CH32V003 und Arduino

#8015771
Lesenswert?

Okay, Ihr könnt meine folgende Frage gleich mit "Ja, du bist zu dämlich" beantworten.

Frage: Bin ich zu dämlich mit Arduino und CH32V003 irgendetwas anderes zu bewerkstelligen als bloß Logikpegel auf einem Pin wackeln zu lassen?

Hintergrund: Ich möchte mein serielles Bootloader-Board, welches ich jetzt überarbeitet habe und dessen Vorgängerschaltung und Firmware ich hier gepostet habe, tatsächlich Arduinotauglich machen (ich arbeite im Normalfall nicht mit Arduino).

Grundsätzlich kann Arduino Codes compilieren und auch ein Upload in mein Board durch patchen von platform.txt und boards.txt funktioniert einwandfrei.

Aber jede etwas erweiterte Funktion scheint nicht zu funktionieren. Ist der Core von hier:

https://github.com/openwch/arduino_core_ch32

wirklich so fehlerhaft und unvollständig wie es sich mir darstellt oder mache ich grundlegend etwas falsch.

Für mich stellt es sich so dar:

  • class Serial kann nur schreiben, lesen funktioniert nicht
  • Interrupthandler funktioniert nicht
  • Wire.h bedient i2c nicht korrekt
  • SPI.h ebensowenig

Gerade versuche ich so etwas einfaches wie analogRead und das funktioniert natürlich genausowenig wie analogWrite.

Für die obigen "Probleme" habe ich jetzt eigenständigen Ersatz geschrieben, der Funktionen bereitstellt, der die Funktionaltät der Hardware herstellt, aber es ist eben etwas ausserhalb der Standardklassen und ich weiß nicht ob das Sinn und Zweck der Übung ist, denn: für jedes SPI-Device, für jedes I2C-Device muß dann eine eigene "Library" geschrieben werden, weil alle Beispiele aus dem Netz dann darauf aufbauen (und eben nicht funktionieren).

Momentan habe ich für CH32V003 dann geschrieben SPI-TFT Display, OLED-Display, TM16xx 7-Segmenttreiber, DS18B20, DHT11, LM75 ... etc.

Irgendwie fühlt sich das an, als ob ich das gesamte Ökosystem neu aufsetze.

Bin ich zu dämlich?

:-) natürlich dürft ihr das mit "ja" beantworten

#8015862
Lesenswert?

Ralph S. schrieb:

Gerade versuche ich so etwas einfaches wie analogRead und das funktioniert natürlich genausowenig wie analogWrite.

analogRead scheint zumindest implementiert zu sein:

https://github.com/openwch/arduino_core_ch32/blob/main/cores/arduino/ch32/analog.cpp

Vielleicht geht es ja trotzdem nicht, weil es auf einem anderen Prozessor probiert wurde.

Ich werfe jetzt einfach mal eine Vermutung den Raum: Wahrscheinlich ist eines der #defines nicht aktiv

1
#if (defined(CH32V20x) || defined(CH32V30x) || defined(CH32V30x_C) || defined(CH32V10x) || defined(CH32L10x) || defined(CH32VM00X) )
: Bearbeitet durch User
#8015869
Lesenswert?

Christoph M. schrieb:

Vielleicht geht es ja trotzdem nicht, weil es auf einem anderen Prozessor probiert wurde.

Ich werfe jetzt einfach mal eine Vermutung den Raum: Wahrscheinlich ist eines der #defines nicht aktiv #if (defined(CH32V20x) || defined(CH32V30x) || defined(CH32V30x_C) || defined(CH32V10x) || defined(CH32L10x) || defined(CH32VM00X) )

... sagen wir es einmal so: Der Core ist grundsätzlich irgendwie höchst unvollständig und höchst buggy. Aus diesem Grund, allerdings erst am Entstehen: siehe Anhang.

Daraus werde ich dann am We eine weitere, rein spezielle Library für den CH32V003 machen!

Angehängte Dateien:
#8016143
Lesenswert?

Hallo,

wenn ich mir den Header anschaue https://github.com/openwch/arduino_core_ch32/blob/main/variants/CH32V00x/PinAF_CH32V00x.h stimmt etwas mit dem Include Guard nicht. Vermutlich copy paste und nicht zu Ende abgeändert oder nur erstmal kopiert und dann stehen gelassen. Ich habe noch keinen Core geschrieben, ich würde bei anderen schauen jedoch für den eigenen Core bei Null anfangen. Man wird bei dem Umfang sonst nicht fertig mit debuggen. Vielleicht hilft dir das weiter. https://www.elektronik-labor.de/Projekte/CH32V2.html

#8016417
Lesenswert?

Harald K. schrieb:

Veit D. schrieb:

stimmt etwas mit dem Include Guard nicht.

Was soll daran nicht stimmen?

1
> #ifndef _PINAF_CH32V20X_H
2
> #define _PINAF_CH32V20X_H
3
> 
4
> ... diverser Pofel
5
> 
6
> #endif /* _PINAF_CH32V20X_H */
7
>

Das ist vollkommen korrekt.

Bitte genau hinschauen. Ein CH32V003 ist kein CH32V20X. Der Ordnername steht für CH32V003 und drin der Header für CH32V20X. Das kann nicht richtig sein. Passt für mich nicht. Den Ordner für CH32V20X gibt es ja extra noch.

#8016554
Lesenswert?

Das praktische ist ja, daß vor lauter Platz, den die enthaltene Lizenz wegnimmt, keinerlei Kommentar in so einer Datei drinstehen darf, wofür sie genau da ist und welche Einschränkungen sie hat.

Und niemand wundert sich, daß da "Copyright (c) 2017, STMicroelectronics" drinsteht, obwohl die Datei doch für einen µC von WCH ist ...

Es ist jedenfalls nicht komplett auszuschließen, daß derjenige, der sie geschrieben hat, sie aus einer Portierung für CH32V20x kopiert und einfach vergessen hat, sie nach dem umbenennen anzupassen.

Ob das, was da in den beiden Funktionen pinV32_DisconnectDebug und pin_SetV32AFPin geschieht, irgendwas macht, was spezifisch für CH32V20x, aber nicht für CH32V00x ist, müsste sich jemand ansehen, der die Reference Manuals vorliegen hat und weiß, was der ganze Kram überhaupt soll.

Ich hab' mit Arduino und dem zugehörigen Schichtkuchen weniger zu tun, aber ich beschäftige mich unter anderem schon mehrere Jahrzehnte damit, C-Code von verschiedenen Leuten anzugucken. Es gibt wirkklich viele Schlampen. Nach der Phase "zurechtgedengelt, bis es fehlerfrei compiliert und bei einfachen Tests funktionier" entfällt meistens die Phase "aufräumen", denn das ist ja mühsam ...

#8016571
Lesenswert?

Harald K. schrieb:

Ich hab' mit Arduino und dem zugehörigen Schichtkuchen weniger zu tun, aber ich beschäftige mich unter anderem schon mehrere Jahrzehnte damit, C-Code von verschiedenen Leuten anzugucken. Es gibt wirkklich viele Schlampen. Nach der Phase "zurechtgedengelt, bis es fehlerfrei compiliert und bei einfachen Tests funktionier" entfällt meistens die Phase "aufräumen", denn das ist ja mühsam ...

Ja, das passiert öfters. Im obigen Fall
Beitrag "Re: CH32V003 und Arduino"
wäre es vielleicht eine gute Übung, die gezeigte ADC-Funktion einfach mal unterhalb des Komaptibilitätslayers anzuhängen.

Noch eine kleine Randbemerkung: In den ursprünglichen Arduino-API Funktionen ist analogRead nicht in einer Klasse implementiert.

: Bearbeitet durch User
#8016661
Lesenswert?

Christoph M. schrieb:

Noch eine kleine Randbemerkung: In den ursprünglichen Arduino-API Funktionen ist analogRead nicht in einer Klasse implementiert.

tja, dann habe ich das jetzt anderst gemacht und das analoge Einlesen in eine Klasse verpackt. Das ganze schön in Arduino-Häppchen, für jeden xyz eine eigene "Lib".

Hier dann meine im Anhang.

Klasse ADC, aus der für jeden analogen Eingang ein Objekt instanziiert wird. Es gibt dann nur 2 öffentliche Methoden: read() und calc_spg(advalue, refwert).

Ich sollte irgendwann mal "in die Pötte" kommen und alle Dinge die für Arduino und CH32V003 von mir gemacht worden sind, in einer Doku zusammenschreiben. Hier also "meine Methode", analoges in Arduino mit CH32V003 einzulesen.

Nächstes wird sein, "analog zu schreiben" (um das in Arduino-Sprech) zu formulieren, in Wirklichkeit ist das ja eine PWM.

Angehängte Dateien:
#8016688
Lesenswert?

Hallo Ralph,

gehe bitte mit einem besseren Beispiel voran. Zeiger zerfallen als Parameter, die Länge ist weg. Hier klappt das zufällig, weil print() bis zum Nullpointer liest. Ansonsten ist sowas gefährlich. Lieber Referenzen statt Zeiger.

So wäre das besser.

1
Stream &cout {Serial};
2

3
void textnvalue(Stream &out, const char (&s1)[], const int16_t value, const char (&s2)[], const bool mode)
4
{
5
  out.print(s1);
6
  out.print(' ');
7

8
  if (mode)
9
  {
10
    out.print(value / 100);
11
    out.print(".");
12
    out.print(value % 100);
13
  }
14
  else
15
  {
16
    out.print(value);
17
  }
18

19
  out.print(' ');
20
  out.println(s2);
21
}
22

23
textnvalue(cout, 

oder

1
void textnvalue(Stream &out, const char (&s1)[], const int16_t value, const char (&s2)[], const bool mode)
2
{
3
   char buffer[32];  // anpassen
4

5
  if (mode) {
6
    snprintf(buffer, sizeof(buffer), "%s %d.%02d %s", s1, (value/100), (value%100), s2);
7
  }
8
  else {
9
    snprintf(buffer, sizeof(buffer), "%s %d %s", s1, value, s2);
10
  }
11

12
  out.println(buffer);
13
}
#8016689
Lesenswert?

Christoph M. schrieb:

Ralph S. schrieb:

tja, dann habe ich das jetzt anderst gemacht und das analoge Einlesen in eine Klasse verpackt. Das ganze schön in Arduino-Häppchen, für jeden xyz eine eigene "Lib".

Wo wäre es laut Standard-API: https://docs.arduino.cc/language-reference/en/functions/analog-io/analogRead/

Ist hier zu finden oder 1:1 auf dem Rechner. https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/wiring_analog.c

: Bearbeitet durch User
#8016700
Lesenswert?

Christoph M. schrieb:

Ralph S. schrieb:

tja, dann habe ich das jetzt anderst gemacht und das analoge Einlesen in eine Klasse verpackt. Das ganze schön in Arduino-Häppchen, für jeden xyz eine eigene "Lib".

Wo wäre es laut Standard-API: https://docs.arduino.cc/language-reference/en/functions/analog-io/analogRead/

Nur mal so am Rande: Ich mache zwar im Normalfall so gar nichts mit Arduino und vor ein paar Monaten hatte ich mich genau wegen DIR damit einmal auseinandergesetzt, meinen Bootloader und mein passendes Board dazu, unter Arduino gangbar zu machen.

Allerdings muß man mir, und so dämlich und blöd bin ich dann doch nicht, nicht aufzeigen, wie ein analogRead in Arduino definiert ist.

Man muß nicht 1000 Klimmzüge machen, um ums Verrecken genau den gleichen Mist zu haben, dann Arduino standardmäßig vorgibt. Man muß / sollte hier nicht am Core herumfrickeln, wenn da 1000 Köche den Brei verderben.

Hier setze ich lieber auf das, was garantiert funktioniert und garantieren funktioniert erst mal nur eines wirklich: Linkerscript, Compiler und Linker (und so wie es aussieht digitalRead / write und Serial (hier aber nur schreibend).

Also alles andere was man haben will selbst aufsetzen (was so gar nicht wirklich Arduino-Style ist, weil: dann kann man es gleich anderst machen).

Von daher schreibe ich jetzt erstmal alles auf was ich so habe und werde dann alles "veröffentlichen": Allerdings wird dann zwar die Handhabung Arduino-Style sein, aber mit vorhandenen Programmen nicht kompatibel sein.

Vorhanden sind:

  • adc (eigene Klasse, hier im Anhang)

  • serial als eigene Klasse v003_serial (schreibend und lesend, erbt Stream von daher funktioniert print und println)

  • i2c (eigene Klasse als Ersatz für wire)

  • my_printf (abgespecktes sehr kleines, printf, keine klasse)

  • colpos farbige Textausgaben und Cursorpositionierung bei Terminalausgaben

  • v003_oled (Klasse für i2c-OLED mit SSD1306 / SSD1315 Controller)

  • hx1838 (Infrarotempfänger, keine eigene Klasse, weil Benutzung Timer2 - und auch Timerinterruptbehandlung ist im Core unvollständig) usgaben und textcursorpositionierung

  • ds18b20 (Klasse fürs auslesen eines einzelnen Temperatursensors, evtl. werd ich das für mehrere Sensoren erweitern)

  • BMP280 (eigene Klasse, ein bereits initialisierter i2c wird vorrausgesetzt)

  • charlie20 (Library für 20 charliegeplexte LED's, keine eigene Klasse, weil wieder Timerinterrupt)

  • dht11 (eigene Klasse für diesen -schlechten- Sensor)

  • Schieberegister 74HC595 (eigene Klasse)

  • HD44780 (unglaublich: nicht einmal das originale Demo funktioniert, weil das Timing scheinbar komlett daneben ist. Deshalb auch hier eigene Library mit eigener Klasse. Erbt Stream und von daher funktioniert auch print und println)

  • rtc (für ds3231 / ds1305, eigene Klasse, ein bereits initialisierter I2C Bus wird vorrausgesetzt).

  • SPI-tftdisplay mit st7735 oder st7789 grafikcontroller, Displays von 160x80 bis 320x240 Pixel (eigene Klasse)

  • tm16xx (7-Segment Anzeigetreiber, eigene Klasse)

  • ws2812 (eigene Klasse)

Demos für LM75 I2C-Temperatursensor, I2C-EEprom, interruptgesteuertem Blinken, Timernutzung generell.


Das nächste ist PWM und Servos.


Für den Fall, dass irgendjemand vorab von dem oben genannten "Zeugs" etwas brauchen kann, sagt bescheid, ich werde das hier posten.

Aber bitte verschont mich damit, welche Syntax Arduino im Originalen macht. Es nutzt hier nix, etwas kompatibel zu machen, das eher schlecht als recht funktioniert, nur damit auf jeder Plattform einheitlich die selbe Syntax herscht, nur um dann festzustellen: Funktioniert nur auf einer Plattform fehlerfrei: Arduino Uno / Nano mit ATmega328.... bei allen anderen Dingen zickt es immer irgendwo rum.

Egal was man ausprobiert, sogar mit originalen Uno r4 Platinen.

Aus diesem Grunde gleich eigene Klassen, Methoden und Funktionen... allerdings dokumentieren muß man es auch (und damit tu ich mich dann schwer).


Wie gesagt, wenn jemand etwas von obiger Liste benötigt: schreiben, ich poste das hier dann.

Wochenendlicher Gruß, Ralph

#8016793
Lesenswert?

Ralph S. schrieb:

Allerdings muß man mir, und so dämlich und blöd bin ich dann doch nicht, nicht aufzeigen, wie ein analogRead in Arduino definiert ist.

Ich finde es ja gut, dass du etwas arduinoartiges machst. Vor langer Zeit habe ich einmal ähnlich angefangen, eine vereinfachte API arduinoähnlich für eine MCU zu machen. Mit der Zeit habe ich aber gemerkt, dass der Sinn eines "Kompatibilitätslayers" die Kompatibilität ist. Bei analogRead ist das noch relativ überschaubar, aber sobald man die I2C Funktionen implementiert, wird das schon schwieriger.

#8016869
Lesenswert?

Veit D. schrieb:

So wäre das besser.

Stream &cout {Serial}; void textnvalue(Stream &out, const char (&s1)[], const int16_t value, const char (&s2)[], const bool mode) { out.print(s1); out.print(' '); if (mode) { out.print(value / 100); out.print("."); out.print(value % 100); } else { out.print(value); } out.print(' '); out.println(s2); } textnvalue(cout, … odervoid textnvalue(Stream &out, const char (&s1)[], const int16_t value, const char (&s2)[], const bool mode) { char buffer[32]; // anpassen if (mode) { snprintf(buffer, sizeof(buffer), "%s %d.%02d %s", s1, (value/100), (value%100), s2); } else { snprintf(buffer, sizeof(buffer), "%s %d %s", s1, value, s2); } out.println(buffer); }

Okay, die erste Variante kann ich einsehen (und finde ich auch recht "elegant"), die zweite Variante ist genau das, was ich auf einem ch32v003 vermeiden möchte: snprintf schluckt für die Verhältnisse eines ch32v003 (nur 16384 Byte Flash insgesamt) ungehörige Mengen Flash. Zu diesem Zweck habe ich ja auch extra ein abgespecktes printf, in den Demos vollte ich mein eigenes printf vermeiden und deshalb die Krücke mit textnvalue.

Die Frage ist, ob ein "üblicher" Arduino Nerd das hier:

1
Stream &cout {Serial};

versteht.

Aber im Grunde gehts ja um den ADC .... und nicht um die Ausgabe!

#8016963
Lesenswert?

Christoph M. schrieb:

Ralph S. schrieb:

Die Frage ist, ob ein "üblicher" Arduino Nerd das hier:Stream &cout {Serial};

Das Ziel des Arduino-Frameworks ist maximale Verständlichkeit und einfachste Benutzbarkeit. Der gezeigte Code erfüllt diese Bedingungen nicht und ist deshalb ungeeignet.

Was ist das denn für eine schwachsinnige Aussage? Sowas bringt mich von 0 auf 100 auf die Palme. Überlege einmal was du da schreibst. Das passt vorn und hinten nicht zusammen. Frage dich einmal was der normale Arduino User davon sieht. Der guckt nicht einmal den Header an. Und das soll dann laut deiner Meinung Grund genug sein schlechten bzw. problematischen Code von einem selbst zu schreiben? Ich bitte dich. Das kann nur Unsinn werden. Ich hoffe du regst dich nie über Arduino im allgemeinen auf, sonst schmiere ich dir das jeden Tag aufs Brot.

Im Gegenteil, man könnte noch ein Funktion-Template daraus machen um die Länge für irgendwas verarbeiten zu können. Zum Bsp. falls man snprintf verwendet die optimale lokale Buffergröße anzulegen. Auch das würde der normale Arduino User der diese Funktion einfach nur verwendet nicht bemerken, aber dem Programmierer der Funktion schreibt, gibt es alle Möglichkeiten in die Hand. Letzteres hat immer Vorrang. Immer!

Und wenn es dann interessierte Arduino User gibt, die mehr machen wollen wie nur das Framework benutzen, die sehen dann wie es andere richtig bzw. richtiger (bin auch nicht perfekt) geschrieben haben und können dann selbst nachforschen oder Bücher lesen oder was auch immer um in die Programmierung einzusteigen.

Es jedenfalls kein einziger Grund dabei diesen Leuten guten Code vorzuenthalten bzw. umgekehrt schlechten Code zu servieren. Kein Einziger!

Falls du der Christian bist mit dem ich schon im Biergarten saß, dann müssten wir dieses Jahr darüber reden. :-)

Das war mein Sonntag-Plädoyer.

#8016967
Lesenswert?

Ralph S. schrieb:

... die zweite Variante ist genau das, was ich auf einem ch32v003 vermeiden möchte: snprintf schluckt für die Verhältnisse eines ch32v003 (nur 16384 Byte Flash insgesamt) ungehörige Mengen Flash.

Kann ich nachvollziehen. Das Problem kenne ich mit dem ATtiny412. Für das Programm ist Platz genug. Zum bequemen Debuggen ist alles zu wenig.

: Bearbeitet durch User
#8017449
Lesenswert?

Veit D. schrieb:

Ralph S. schrieb:

... die zweite Variante ist genau das, was ich auf einem ch32v003 vermeiden möchte: snprintf schluckt für die Verhältnisse eines ch32v003 (nur 16384 Byte Flash insgesamt) ungehörige Mengen Flash.

Kann ich nachvollziehen. Das Problem kenne ich mit dem ATtiny412. Für das Programm ist Platz genug. Zum bequemen Debuggen ist alles zu wenig.

:-) jetzt bin ich etwas "abgelenkt" von den eigentlichen Dingen, die ich machen möchte.

Dein Vorschlag mittels stream etwas auszugeben ist natürlich absolut berechtigt, andererseits liest print nun halt wirklich bis zum Zerobyte.

Mir war/ist die Ausgabe mittels print / println viel zu "dämlich" und zu "Zeilenintensiv", vor allem geht da Übersicht verloren von dem, was man eigentlich zeigen möchte.

Abgesehen davon dass ich Arduino immer nur für andere verwende, habe ich deshalb ma mein eigenes, sehr abgepecktes printf, innerhalb Arduino (sehr sehr kleiner Flashbedarf).

Da ich das nun aber in einem Demo zu bspw. ADC nicht verwenden möchte - es erfordert dann eben das Einbinden meiner printf-Library (ich tu mich immer noch schwer mit dem Begriff "Library" hinsichtlich den Arduino-Libraries), was ich vermeiden möchte.

Hm, jetzt bin ich am überlegen, ob man so etwas wie textnvalues dann, um das instanziieren eines Streams zu vermeiden, vllt. besser in ein Makro packt (und den originalen Aufruf von mir dan beibehält) ?!?

Aber.... :-) ich werde mir das mit dem Stream zu Herzen nehmen und für meine zu erstellende Dokumentation zu dem ganzen Sermon (den ich hoffentlich wirklich mache) mit aufnehmen. Zumindest ist das mal auf meiner ToDo Liste

#8017504
Lesenswert?

Hallo Ralph,

die Funktion mit Deklaration

1
void textnvalue(Stream &out, const String &s1, const int16_t value, const String &s2, const bool mode)

belegt bei mir 30kB weniger Flash bei gleichen RAM im Vergleich zu

1
void textnvalue(const String &s1, const int16_t value, const String &s2, const bool mode)

ich hätte vermutet es bleibt gleich, weil der Parameter out nur durchgereicht wird. Stream ist hierbei der Datentyp.

Die vielen print Zeilen nerven manchmal nicht nur dich. Deswegen gibt es eine gern verwendete Streaming Klasse. https://github.com/janelia-arduino/Streaming

Wegen deiner Print Klasse. Du kannst gern deine Printklasse verwenden, ist kein Problem, du solltest nur, ich nenne es einmal "Funktionskompatibel" bleiben mit dem Interface. Wenn es nicht alles "drucken" kann was möglich wäre, geht das laut meiner Meinung nach auch, muss dann eben in der Doku erwähnt werden, dass auf Grund von zu wenig Flash nicht alles möglich ist. Wenn du eine Möglichkeit siehst Flash einzusparen und musst deswegen die "Funktionskompatibilität" verlassen, dann ist das eben so.

Thema Makros. Die sparen bestimmt durch Präprozessor Ersetzung Flash ein. Nur wird man an einen Punkt kommen ab dem man nicht mehr durchblickt und Fehler nicht mehr sieht. Man hat auch in C++ viele Möglichkeiten allein schon mit constexpr. Für eine Funktion verwendet kann alles zur Compile-Time ausgewertet werden, muss es jedoch nicht. Man muss zusehen das alle Parameter Compile Time konstant sind. Ähnlich wie mit Makros, nur das bei Makros weniger Prüfungen durchlaufen werden.

Das sind alles so viele Grundsatzentscheidungen, da sollte man sich Zeit nehmen. :-)

Nochwas, weil ich das gerade sehen.

1
void loop()
2
{
3
  uint16_t count = 0;
4
  uint16_t temp;
5
  while(1)
6
  {
7
    temp= ntc_gettemp(ntc1.read());
8
    textnvalue("\rCounter: ", count, "  |  ", 0);
9
    textnvalue("Temp.: ", temp, " oC", 1);
10
    count++;
11
    delay(1000);
12
  }
13
}

loop() ist in Arduino die while() Schleife. setup() ist das in der main() bis zur while().

count und temp entweder lokal static machen oder noch besser global. temp ist in deinem Fall in der loop lokal und nicht initialisiert. Vermutlich nur vergessen. ;-)

#8017608
Lesenswert?

Hallo Ralph,

ich möchte dir nicht auf den Keks gehen oder klugsch. oder so. Habe nochmal genauer hingeschaut und mir gehts wirklich darum mit besseren Bsp. voranzugehen, weil in den Arduino IDE Bsp. schlummern mir nicht gefallende zu viele #defines etc. rum und wir sagen das auch im Arduino Forum fast wöchentlich jeden Neuling der zu uns findet. :-)

Nochmal zu deinem Bsp. count global machen (ohne = 0;) uint16_t count; und dann

1
void loop()
2
{
3
    const uint16_t temp = ntc_gettemp(ntc1.read());
4
    textnvalue("\rCounter: ", count, "  |  ", 0);
5
    textnvalue("Temp.: ", temp, " oC", 1);
6
    count++;
7
    delay(1000);
8
}

und wenn man so richtig gut sein möchte, schreibt man die erste Zeile

1
const uint16_t temp {ntc_gettemp(ntc1.read())};

Dann finden noch Datentyp- und Bereichsüberlaufprüfungen statt. Ist wirklich nur gut gemeint. Ist dein Code, kannst schreiben wie du möchtest. Falls temp noch weiter Verwendung finden soll, dann natürlich global.

#8018168
Lesenswert?

Grüß dich Veit,

nein, du gehst mir nicht auf den Keks. Grundsätzlich bin ich dankbar für die Arduino-Sichtweise (und ich überdenke meine Ansätze, auch wenn ich deine Meinung oder Sichtweise nur teilweise teile).

Man merkt mir auch an, dass ich bisweilen sehr "oldschool" unterwegs bin und mich manchen Dingen (leider) hartnäckig verschließe, auch wenn sie ihre Gründe haben und bisweilen besser sind.

Globale Variable lassen sich nicht immer vermeiden, aber dennoch versuche ich sie so wenig wie möglich zu verwenden.

Was ich im Moment mit Arduino mache, mache ich für mich (sorry, wenn ich das so sage, aber ich würde für mich oder auch dienstlich Arduino nicht einsetzen). Auch wenn viele jetzt die Nase rümpfen werden, bei Arduino (mit ATmega8, später ATmega328) hat mir vor allem der Bootloader und die günstige Hardware gefallen, die aber auch nativ mit AVR-GCC, AVRDUDE und Makefiles zu bedienen war / ist. Mehr aber ehrlich gesagt nicht.

Also habe ich für den CH32V003 eben auch einen seriellen Bootloader geschrieben. Die Hardware siehst du im Bild im Anhang. Das ganze ist vorrangig für meine Lehrlinge gedacht, die in der Schule mit Arduino (und ganz schlimm mit Blockly) umgehen müssen und dafür zu je 5 Personen sich eine SenseBox teilen müssen. Als Ausbildungsprojekt lernen sie hier dann auch das SMD löten und "basteln" sich ein Nano-Board mit CH32V003 zusammen, für die ich jetzt die Libraries schreibe.

Natürlich verstehe ich das Anlegen lokaler Variable innerhalb des Codes, bspw.

1
for (int i = 0; i< 10; i++)

Weil hier der Compiler selbst entscheiden kann, ob er die Variable im Ram anlegt oder ob ein Register frei ist, die er als Laufvariable nutzen kann.

Dennoch mag ich das nicht (warum auch immer) und habe in einer Funktion / Methode lieber ein für die gesamte Funktion gültige Variable i.

Im Falle von Arduino finde ich (sorry) void loop() fürchterlich, wird diese doch in einer function main eben in der Schleife aufgerufen. Inhalte lokaler Variablen gehen hier logischerweise verloren und sie müssen alle static gemacht werden oder sind global.

Aus diesem Grund, wenn du dir das erste Demo genau ansiehst, mache in in void loop genau das, was ich mit .c oder .cpp Sourcen auch mache, meine "loop" ist in eine Endlosschleife while(1) { code } eingebunden so dass die void loop niemals verlassen wird. Genau so, wie ich das im Embedded-Bereich eben mache, wenn ich das ausserhalb von Arduino mache.

Deine Einwände habe ich "in mich aufgenommen" und werde das so überdenken. Ein

1
const uint16_t temp = ntc_gettemp(ntc1.read());

funktioniert in deiner void loop() nur deshalb, weil diese Funktion vom Arduino-Framework permanent neu aufgerufen wird und in die loop immer wieder neu eingetreten wird. Ich werde das so, den Auszubildenden auch mitteilen. Dieses Vorgehen ist aber AUCH eines der Gründe, weshalb mir Arduino nicht soooo sonderlich gut gefällt und ich verwende dann Dinge, wie ich sie auch in reinem C oder C++ verwende.

Im Falle des textnvalues habe ich mich entschlossen das ganz fallen zu lassen und in den Beispielprogrammen zu den Libraries, an denen Ausgaben gemacht werden, egal ob auf Displays oder auf UART, mein abgespecktes printf .... namentlich my_printf einzusetzen. Die Demos müssen demnach einen Zugriff auf diese Library my_printf haben (auch wenn ich weiß, dass man unter C++ - Arduino ist ja nichts anderes - eigentlich cout verwendet).

Grundsätzlich bin ich der Meinung, dass C++ auf Leistungsschwachen Mikrocontrollern wie bspw. AVR oder in meinem Falle jetzt CH32V003 ein C++ zu viel Overhead hat und deshalb diese Chips doch besser mit C bedient sind. C++ setze ich auf PC (in Verbindung mit QT5 ein) oder auf leistungsstarken Mikrocontrollern ab STM32F4 oder auch H7.... ein- zweimal auch auf einem STM32F030CCt (hat aber wenig RAM) und einem STM32F103CCT (schon eher, aber alt). Die haben dann wenigstens 256 kByte Flash und der Overhead von C++ ist hier zu verkraften.

Wahrscheinlich treffe ich Deine Meinung nicht, aber ich denke, man darf auch unterschiedlicher Meinung sein. 2 hochinteressierten Lehrlingen (aber noch nicht weit fortgeschritten) habe ich die unterschiedlichen Realisierungsweisen gezeigt und deine - zugegeben sehr profesionellen - Äußerungen haben sie nicht auf Anhieb verstanden.

Zur Schaltung, weil hier auch manche (nicht in diesem Forum) angemerkt haben, dass die Resetschaltung hierfür "befremdlich" aussieht:

Der CH32V003 hat eine eigene Bootloader-Section, die NICHT in den Firmwareflashbereich hereinragt. Somit sind die vollen 16384 Byte Flash für die Firmware verfügbar. Die Bootloader-Section ist 1920 Byte groß und wird, wenn die Optionbytes gesetzt sind, bei einem PowerOn angesprungen. Und nur bei einem PowerOn. Für meine Schaltung ist das "dämlich", weil ein Resetimpuls an nrst zwar das Userprogramm neu startet, aber NICHT in den Bootloader springt. Aus diesem Grund habe ich ein einfaches PushPull-Register gebaut, das dem V003 kurzfristig die Spannung wegnimmt und somit den gesamten Chip neu startet und in den Bootloader springt (wenn ein Impuls auf rts des CH340 Chips kommt).

Ursprünglich hatte ich hierfür einen einzelnen PNP vorgesehen gehabt. Dieses hatte den Nachteil, sollte die Betriebsspannung hierüber abgeschaltet werdeb, aber eine Peripherieelektronik an den Chip angeschlossen sein, es vorkommen kann, dass der V003 über einen GPIO mit Spannung fremdversorgt wird und der gesamte Chip nicht neu gestartet wird.

Im Anhang auch mein (sehr) abgespecktes printf, das ich hier auch mit dem Arduino verwende und mir die (unsägliche) Sache mit langen Reihen von Serial.print erspart

Angehängte Dateien:
#8018184
Lesenswert?

Hallo Ralph,

sehr schön das du sowas mit Lehrlingen machst. :-) Eine kurze Nachfrage bevor ich darauf antworten möchte.

2 hochinteressierten Lehrlingen (aber noch nicht weit fortgeschritten) habe ich die unterschiedlichen Realisierungsweisen gezeigt und deine - zugegeben sehr professionellen - Äußerungen haben sie nicht auf Anhieb verstanden.

Ging es dabei um die Funktionsparameter oder wegen der loop() / while(1)?

#8018234
Lesenswert?

die Funktionsparameter haben sie nicht verstanden, die loop nach Erklärung, dass diese Funktion in einer nicht sichtbaren funktion main in einer endlosschleife aufgerufen wird:

1
int main(void)
2
{
3
  loop();
4
}

und dass hier loop nur eine normale Funktion aus Sicht von C++ ist, die eben lokale Variable wieder "vergißt" wenn sie nicht static sind.

:-) hier war dann "Erklärungsbedarf", dass es außerhalb von Arduino ohne eigenes zutun keine Funktion loop gibt und dass die Funktion, die in einem Programm beim Start des Programms "main" heißt.

Auch wenn dich das vielleicht ärgert, einer meinte in der Art: "wozu braucht man dann noch Arduino" (ich habe meine Toolchain gezeigt).

Meine Antwort war, dass es für Arduino eine Unmenge an fertigen Beispielen gibt und der Einstieg sehr schnell ist und ein installieren einer Toolchain nicht notwendig ist. Einstecken und geht!

Für Funktionsparameter: Ich bin erst einmal froh, dass, zumindest einige, den Unterschied zwischen call by reference und call by value verstehen!

#8018251
Lesenswert?

aus lauter Jux und Dollerei habe ich jetzt mein my_printf und v003colpos auf avr losgelassen und prompt funktioniert es nicht, weil ich type int verwende (und die auch als 32-bit behandle), die aber auf avr nur 16 bit lang sind. eine explizite angabe von int32_t für alle bisher int angaben macht my_printf und v003colpos auch mit avr kompatibel.

Angehängte Dateien:
#8018498
Lesenswert?

Ralph S. schrieb:

Grundsätzlich bin ich dankbar für die Arduino-Sichtweise (und ich überdenke meine Ansätze, auch wenn ich deine Meinung oder Sichtweise nur teilweise teile).

Man merkt mir auch an, dass ich bisweilen sehr "oldschool" unterwegs bin und mich manchen Dingen (leider) hartnäckig verschließe, auch wenn sie ihre Gründe haben und bisweilen besser sind.

Globale Variable lassen sich nicht immer vermeiden, aber dennoch versuche ich sie so wenig wie möglich zu verwenden.

Übrigens: Ein paar der syntaktischen Eigenheiten der Arduino-API sind der Kompatibilität mit Processing geschuldet. Mit Processing kann man z.B. Daten vom Arduino Visuallisieren oder eine einfache GUI erzeugen, mit der man die Arduinos steuern kann. Processing ist eigentlich Java und nur bedingt kompatibel mit der C++ Seite von Arduino. Aber man hat eine gewisse Kompatibilität wie z.B.

1
 boolean

eingeführt, obwohl es in C++ eigentlich

1
 bool

ist

https://www.arduino.cc/education/visualization-with-arduino-and-processing/

#8018594
Lesenswert?

Hallo Ralph,

Lokale vs. globale Variablen. Ja man sollte wenn immer möglich lokale vorziehen. Nur in der Mainloop macht das für mich keinen Sinn, wenn sie static sein müssen. Dann kann man sie auch gleich global machen.

Natürlich verstehe ich das Anlegen lokaler Variable innerhalb des Codes, bspw.

1
> for (int i = 0; i< 10; i++)
2
>

Weil hier der Compiler selbst entscheiden kann, ob er die Variable im Ram anlegt oder ob ein Register frei ist, die er als Laufvariable nutzen kann.

Hier verstehe ich dann wiederum nicht, warum du i nicht immer lokal für for() machst. Das ist sehr fehlerträchtig. Gut, die Marotte wirst du wohl nicht mehr rausbekommen. :-) :-)

Kommen wir zur Arduino loop. Ich denke hier liegt ein großes Missverständnis vor.

Die Bedeutung von setup() und loop() ist eigentlich, für mich, mehr eindeutig wie der klassische Aufbau mit main und while. Aber gut, ist Ansichtssache. Geschenkt. Kommen wir zum Kern.

In deiner demo.ino gehört alles zwischen loop() { und while(1) in setup(). Dann ist die überflüssige while(1) in der loop weg. Ansonsten ist deine loop-while Programmierweise kurz gesagt wirklich etwas eigenartig und würde ich Lehrlingen auch so nicht zeigen, weil es nirgends so steht und ehrlich gesagt auch keinen Sinn macht.

Lehrlinge:

und dass hier loop nur eine normale Funktion aus Sicht von C++ ist, die eben lokale Variable wieder "vergißt" wenn sie nicht static sind.

Eine non static lokale Variable in while(1) wird von der Wirkungsweise genauso vergessen wie in loop. Entweder wird sie immer neu initialisiert oder bekommt einen Zufallswert zugewiesen. Das heißt auch in while(1) muss man static verwenden, wenn der Wert erhalten bleiben soll.

Wenn sie call by reference vs. call by value verstanden haben, dann sind sie doch schon einen großen Schritt weiter.

Wenn dich setup() und loop() stören, dann musst du diese nicht verwenden. Du kannst in der Arduino IDE genauso gut

1
int main() {
2
  ...
3
  while(1) 
4
  {
5
   ...
6
  }
7
}

verwenden. Und wenn du sowieso eigene Libs schreibst, dann fällt damit auch der gesamte Basis Overhead vom Framework weg. Du bist damit auf dich mit allen allein gestellt und nutzt die IDE nur noch zum einfacheren flashen des Controllers.

Auch wenn dich das vielleicht ärgert, einer meinte in der Art: "wozu braucht man dann noch Arduino" (ich habe meine Toolchain gezeigt).

Keine Sorge, dass ärgert mich nicht. Ich kann mit und ohne Arduino IDE programmieren.

Genau das meinte ich mit #defines

1
// Farbzuordnungen der EGA-Farben zu den Farbnummern
2
  #define black           0
3
  #define blue            1
4
  #define green           2
5
  #define cyan            3

Das ist in C++ alles Datentyp sicher zur Compile Time mit constexpr uint8_t farbe {1}; Oder du hast dich noch nicht entschieden ob du C oder C++ programmierst. :-)

Deine #define Konstanten cnt_speed bis yofs wären bei mir auch constexpr … Compile Time Konstanten mit Datentyp. Irgendwo hatte ich noch gesehen das du bool selbst definierst. Muss du nicht, bringt die Toolchain schon mit.

Damit höre ich auch auf an der Stelle. Sonst schreiben wir Ellenlange Seiten über jedes Detail und hilft niemanden weiter. Ich wünsche dir auf jeden Fall jederzeit interessierte Lehrlinge, weil das ist etwas schönes wenn jemand zuhören möchte und auch mit Fragen bohrt wo man erstmal überlegen muss. In diesem Sinne, bleib so nett.

#8018660
Lesenswert?

Grüß Dich Veit,

erstmal Danke für den Kommentar. Nur um evtl. Mißverständnisse auszuräumen, ich mache mit Arduino eigentlich (und nicht nur eigentlich) nichts.

Ich bin - gebe ich zu - schon ein Verfechter von klassisch C oder C++. Mit Arduino bin ich derzeit nur deshalb beschäftigt, um zum einen aufzuzeigen, dass mit meinem Bootloaderboard Arduino genauso gut umgehen kann, wie mir "normalem" C oder auch C++.

Von daher bin ich "nur" damit beschäftigt, die Dinge, die in meiner Toolchain funktionieren nach Arduino zu portieren, weil der Core für den V003 aus meiner Hinsicht unzureichend ist.

Hier ist es dann etwas mühselig, die hardwarenahen Dinge mittels Arduino zu realisieren. Was "state of the art" in und unter Arduino ist, weiß ich zugegebenermaßen nicht.

Ich weiß nicht mehr wer es war (könntest sogar Du gewesen sein), müßte ich nachlesen im Thread, der anmerkte, dass bei einer eigenen seriellen Klasse ein Arduinoanwender erwarten würde, dass diese Klasse den Stream von Arduino erbt (und somit auch print, println, write etc.).

Also habe ich den Stream in dieser Klasse geerbt. Mache ich dann auch mit den Displays dann so.

Deine Anmerkungen zu setup und loop ... und wie das in Arduino gewollt ist werde ich dann tatsächlich so auch dann in den Demos übernehmen:

Veit D. schrieb:

In deiner demo.ino gehört alles zwischen loop() { und while(1) in setup(). Dann ist die überflüssige while(1) in der loop weg. Ansonsten ist deine loop-while Programmierweise kurz gesagt wirklich etwas eigenartig und würde ich Lehrlingen auch so nicht zeigen, weil es nirgends so steht und ehrlich gesagt auch keinen Sinn macht.

Die loop also für das verwenden, für das sie gedacht ist, alles vor "meiner" while ins setup setzen und ein while in der loop nicht verwenden. Variable dann eben static oder tatsächlich global.

Das reißt mir kein Arm (und auch kein Bein aus).

Veit D. schrieb:

Und wenn du sowieso eigene Libs schreibst, dann fällt damit auch der gesamte Basis Overhead vom Framework weg.

dass die eigenen Libs geschrieben werden ist leider eine Notwendigkeit, weil ansonsten bestimmt Dinge mit V003 und Arduino sonst nicht funktionieren, leider!

Hier dann einfach mal die Frage: Hast du mit V003 unter Arduino schon gewerkelt? Wenn ja :-) hätte ich ja glatt einen Ansprechpartner, wie man etwas zum Laufen bekommt OHNE etwas neu schreiben zu müssen, das Rad muß ja nicht immer wieder neue erfunden werden.

Veit D. schrieb:

Genau das meinte ich mit #defines// Farbzuordnungen der EGA-Farben zu den Farbnummern #define black 0 #define blue 1 #define green 2 #define cyan 3 Das ist in C++ alles Datentyp sicher zur Compile Time mit constexpr uint8_t farbe {1};

Das hier ist natürlich eine gute Anmerkung. Im Sinne der Farbzuordnung hatte ich mir tatsächlich ein constexpr überlegt, auch wegen der wie du absolut richtig anmerkst, der Datentypsicherheit wegen. Hier sieht man auch sehr deutlich an, dass das Original tatächlich ein C-code (und kein C++) ist. Ich habe noch nicht evaluiert, ob ein constexpr uint8_t farbe zusätzlichen Speicherplatz wegnimmt oder nicht und werde das einfach einmal testen. Für den Fall dieser Farbzuordnungen schätze ich jedoch die Gefahr eines falschen Datentyps eher als gering ein, testen werde ich des dennoch.

Veit D. schrieb:

Oder du hast dich noch nicht entschieden ob du C oder C++ programmierst. :-)

Veit D. schrieb:

Oder du hast dich noch nicht entschieden ob du C oder C++ programmierst. :-)

Veit D. schrieb:

Oder du hast dich noch nicht entschieden ob du C oder C++ programmierst. :-)

Na ja, ich habe mich schon entschieden und die Antwort ist: beides. Ich mache das vom Target abhängig, normalerweise würde ich jedoch für einen so kleinen Controller wie den V003 eben C bevorzugt nehmen (genauso wie für AVR) und für die größeren dann eben C++ oder vorzugsweise für PC-Anwendungsprogramme.

Ich tu mich immer noch schwer damit, das die vor Jahrzehnten schmerzhaft gelernten C++ (damals unter Borland C++) Dinge auch auf Mikrocontroller anzuwenden (mit meinem ersten Controller MCS-48 wäre das undenkbar gewesen), einfach des größeren Resourcenbedarfs wegen.

Bei größeren Controllern, STM32F4 aufwärts habe ich dann dieses Problem nicht mehr, weil da dann genug von allem da ist.

Man möge mir meine Ansichten verzeihen.

Aber dennoch ein großes Dankeschön für die Anmerkungen - und wie du hoffentlich gelesen hast - werde ich dann eben ein paar Dinge doch so machen wie du da gesagt hast, einfach weil ich in der "Arduino-Welt" nicht wirklich zu Hause bin (die Demos zu den Hardware-Libraries werden es dir danken).

Veit D. schrieb:

In diesem Sinne, bleib so nett.

Schmunzeln muß, du weißt doch: "Nett ist die kleine Schwester von sch****" , nein ich gehe mal davon aus, das das so gemeint war, wie du das geschrieben hast.

Einen Gruß an Dich, Ralph

#8019018
Lesenswert?

Hallo Ralph,

alles gut und schön das es keine Missverständnisse gibt. :-)

Wegen deiner Frage ob ich einen CH32V003 habe, da muss ich leider passen. Bestimmt ein interessantes Teil, würde dann aber zu viel für mich mit allen anderen Dingen. Ich bewundere daran, an so einem völlig anderen fremden Controller, dein Durchhaltevermögen. Ehrlich. Bei allen anderen bspw. neuen AVRs gibt es immer hier und da jemanden der helfen könnte. Mit kleinen STM32 wollte ich einmal anfangen, dazu kam es aber nie.

Eine constexpr Variable wird auf jeden Fall zur Compile Time "ersetzt" und belegt keine zusätzlichen Ressourcen. Kann auch ein Rückgabewert einer constexpr Funktion sein, allerdings nur, wenn dabei auch alles zur Compile Time konstant ist und nicht nur "gefühlt" konstant. Zur Laufzeit berechnet und mit const deklariert zählt nicht dazu. Die constexpr Funktion funktioniert dennoch, man spart damit jedoch keine Ressourcen, wenn nicht alles richtig konstant ist. Das findet man durch testen heraus. Ich möchte dich jedoch nicht in die C++ Ecke drängen. Das entscheidest du. Es sollte einem nur bewusst sein, dass Arduino C++ ist. Ob man das alles nutzt steht auf einem anderen Blatt. Mach das worin du dich wohl fühlst, dann profitieren auch deine Lehrlinge davon.

Auf eines kannste dich bei mir verlassen. Ich meine alles so wie schreibe. Auch wenn manchmal hier und da meine Leidenschaft der Überzeugungsarbeit mit mir durch gehen sollte. :-) Gute nachvollziehbare begründete Gegenargumente können mich allerdings stoppen.

In diesem Sinne Grüße zurück, Veit

#8019139
Lesenswert?

https://copilot.microsoft.com/shares/m3DxodnxxTu8k9eSLDAcL

Da hat die Microsoft KI was unterschlagen. "serialEventRun" in der loop kann schon wichtig sein.

Auf meiner Platte findet sich in .arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino

1
#include <Arduino.h>
2

3
// Declared weak in Arduino.h to allow user redefinitions.
4
int atexit(void (* /*func*/ )()) { return 0; }
5

6
// Weak empty variant initialization function.
7
// May be redefined by variant files.
8
void initVariant() __attribute__((weak));
9
void initVariant() { }
10

11
void setupUSB() __attribute__((weak));
12
void setupUSB() { }
13

14
int main(void)
15
{
16
  init();
17

18
  initVariant();
19

20
#if defined(USBCON)
21
  USBDevice.attach();
22
#endif
23
  
24
  setup();
25
    
26
  for (;;) {
27
    loop();
28
    if (serialEventRun) serialEventRun();
29
  }
30
        
31
  return 0;
32
}

Bei den "Cören" für den ESP32 oder dem RP2040 wird das dann noch aufwändiger. Dort ist oft noch die Funktion "yield" eingebaut, die von manchen Treibern als zyklischer Aufruf benötigt wird.

#8019190
Lesenswert?

Veit D. schrieb:

Eine constexpr Variable wird auf jeden Fall zur Compile Time "ersetzt" und belegt keine zusätzlichen Ressourcen. Kann auch ein Rückgabewert einer constexpr Funktion sein, allerdings nur, wenn dabei auch alles zur Compile Time konstant ist und nicht nur "gefühlt" konstant. Zur Laufzeit berechnet und mit const deklariert zählt nicht dazu. Die constexpr Funktion funktioniert dennoch, man spart damit jedoch keine Ressourcen, wenn nicht alles richtig konstant ist. Das findet man durch testen heraus. Ich möchte dich jedoch nicht in die C++ Ecke drängen.

:-) du drängst mich nicht in die Ecke... da bin ich schon (zumindest immer wieder). Allerdings lernt man nie aus, dass gcc constexpr "wegoptiomiert" wenn alles tatsächlich konstant ist, wußte ich, dass das unter Arduino mit avr-g++ auch so ist wußte ich nicht zu 100% ... Ich habe es ausprobiert und es ist tatsächlich wie du sagst (unter riscv-gcc auch), ergo, werde ich versuchen, bei Portierungen von C nach C++ etwas "sorgfältiger" zu sein, was solche Dinge angeht.

Veit D. schrieb:

Auch wenn manchmal hier und da meine Leidenschaft der Überzeugungsarbeit mit mir durch gehen sollte. :-)

lachen muß (sorry), dann überzeuge mich einmal, anstelle von C oder C++ bei Microcontrollern Arduino zu verwenden anstelle einer Toolchain (wie bspw. eine eigen eingerichtete oder auch einfach nur avr-gcc, libopencm3 bei stm32 oder das ch32fun framework).

Mein Gegenargument für bspw. ch32v003 (weil ich das hier gerade belegen kann) ist, dass ein Programm, welches im Code identisch ist (einfach C-Code ins Arduino Sketch kopiert) mit dem Framework 3192 Byte belegt, mit Arduino 9178 Byte!

Die Codegröße schreckt mich häufig ab (Verarbeitungsgeschwindigkeit manchmal auch).

Okay, ich habe mittlerweile - auch durch Azubis - gelernt, dass die Einstiegshürde niedrig ist, dass es etwas braucht, was schnell funktioniert. Es kein Setup benötigt. Spricht dafür.

Aber wenn man auch anderst kann?

#8019302
Lesenswert?

Hallo Ralph,

ich denke ich muss nochmal darauf eingehen. Auch auf die Gefahr das du es doch schon weißt. :-) Oder für andere Mitleser. "Arduino" ist keine eigene Sprache oder sowas wie man mancher Ortens traurigerweise lesen muss. Das Framework ist ganz normales C/C++ und stellt viele Funktionen bereit, damit die Nutzbarkeit und damit die Einstiegshürde niedrig wird. Das haben deine Lehrlinge schon richtig erkannt. Arduino nutzt auch keine eigens geschriebene Toolchain, sie nutzen einen ganz normalen avr-gcc 7.3.0 mit eingestellten Sprachstandard C++11. Den kann man locker auf C++14 und auch auf C++17 einstellen. Man darf nur keine komplette C++17 Unterstützung erwarten. Den 'auto' Datentyp in Range-based for loop verwenden zu können ist nett. Mit C++11 ist das noch nicht möglich. https://www.gnu.org/software/gcc/projects/cxx-status.html Worin sich die Gimmicks eines avr-gcc von anderen xyz-gcc unterscheiden ist die avr-LibC. Da hat man Dinge wie Range für switch-case, was man in anderen Toolchains nicht hat. Das sind dann allgemeine Unterschiede der Toolchains, die nichts mit Arduino zu tun haben, was auch gut so ist. ;-)

lachen muß (sorry), dann überzeuge mich einmal, anstelle von C oder C++ bei Microcontrollern Arduino zu verwenden anstelle einer Toolchain (wie bspw. eine eigen eingerichtete oder auch einfach nur avr-gcc, libopencm3 bei stm32 oder das ch32fun framework).

:-) Ich muss und möchte dich nicht überzeugen. Mir ging es vorwiegend darum, wenn man Arduino verwendet, dass man es richtig verwendet. Also nicht die loop() verschandelt und setup() ungenutzt lässt. :-)

Mein Gegenargument für bspw. ch32v003 (weil ich das hier gerade belegen kann) ist, dass ein Programm, welches im Code identisch ist (einfach C-Code ins Arduino Sketch kopiert) mit dem Framework 3192 Byte belegt, mit Arduino 9178 Byte!

Das ist ein berechtigtes Argument. Das ist vermutlich dem Framework geschuldet. Also der Anpassung an alle Cores ohne Code Kompatibilität zu verlieren. Was ja auch der Sinn von Arduino ist. Ein nacktes setup + loop belegt schon Speicher, kommt noch Serial dazu, steigt es schon stark an. Das rührt daher das unter der Haube schon viel Code ausgeführt wird um Grundeinstellungen der Hardware vorzunehmen. Bsp. werden Timer voreingestellt für millis, delay und analogWrite, damit dann zur Laufzeit nichts/wenig umkonfiguriert werden muss. Der Komfort kostet dann Speicher. Jetzt kann man das speziell für seine Hardware natürlich auf ein Minimum reduzieren. Muss dann aber bspw. zusätzliche init/begin Funktionen zur Verfügung stellen. Bei Serial kommt noch die Vererbung dazu, die da scheinbar nicht so optimal ist. Allerdings hat wohl damals von Arduino.cc niemand geahnt, dass Arduino für Controller-Speicher-Miniaturen verwendet wird. :-) Arduino fing zwar laut meines Wissens mit einem ATmega168P an, der Durchbruch begann jedoch mit dem ATmega328P auf dem bekannten UNO R3.

Aber wenn man auch anders kann?

Wenn man anders kann, dann kann man es anders machen. Ich sage einmal so. Was du unter Haube wie in deinem Core programmierst ist deine Sache. Für den Arduino User ist nur wichtig, wenn man den Anspruch hat kompatibel zu bleiben, dass das Interface deiner Funktionen/Methoden dem entspricht, was in der Arduino Doku steht. Was anderes interessiert den gemeinen Arduino User nicht. :-) Alle anderen schauen ggf. unter die Haube die mehr wissen wollen.

Betrachten wir es einmal anders. Auf der Welt schreiben bestimmt Millionen Programmierer immer wieder fast den gleichen Code für USART zum Bsp.. Ist das nicht vergeudete Zeit? Jetzt kann man bestimmt Arduino in einem anderen Licht betrachten, die es geschafft haben vieles, trotz unterschiedlichster Hardware, auf einen gemeinsamen Nenner zusammenzuführen, damit eben nicht jeder bei Null anfangen muss. Dabei bleiben fast unweigerlich Ressourcen liegen. Tja, ist eben so. Ich meine, wenn man die Entwicklung von Arduino sieht, wieviele Leute ihren eigenen Core beitragen usw., dann ist das schon eine Nummer. Wenn man aus heutiger Sicht das Framework programmieren würde, würde es bestimmt anders aussehen, weil paar Aspekte anders einfließen würden, wie zum Bsp. Speicher sparen. Ich muss Arduino.cc nicht schön reden, da läuft auch nicht alles rund, möchte jedoch einen Grund erkennen warum das so ist wie es ist.

Was du noch machen könntest, SpenceKonde (https://github.com/SpenceKonde) unterstützt mit seinen Cores ATtinys die wenig Speicher haben. Hier könntest du einmal reinschauen wie er das gemacht hat um Ressourcen zu sparen. Er arbeitet viel mit Makros und C und Assembler und lehnt C++ regelrecht ab, was Schade ist.

Habe ich schon wieder zu viel getippt. ;-)

Ruhiges Wochenende wünsche ich …

#8019311
Lesenswert?

Veit D. schrieb:

Controller-Speicher-Miniaturen verwendet wird. :-) Arduino fing zwar laut meines Wissens mit einem ATmega168P an

Atmega8

1
 In 2005, Massimo Banzi, along with David Mellis (an IDII student at the time) and David Cuartielles, added support for the cheaper ATmega8 microcontroller to Wiring. Then they forked (or copied) the Wiring source code and started running it as a separate project, called Arduino.

https://arduinohistory.github.io/#the-formation-of-arduino

#8019322
Lesenswert?

Veit D. schrieb:

ch denke ich muss nochmal darauf eingehen. Auch auf die Gefahr das du es doch schon weißt. :-) Oder für andere Mitleser. "Arduino" ist keine eigene Sprache oder sowas wie man mancher Ortens traurigerweise lesen muss. Das Framework ist ganz normales C/C++

Das wußte ich natürlich schon, wie in vergangenen Threads bereits geschrieben, bin ich ja gerade dabei, Arduino-Libraries für CH32V003 zu schreiben und dann sieht man in den .c und .cpp Dateien schon deutlich, was das ist ( :-) und ganz Blinde könnten das schon ander Dateiextension .cpp erkennen). In den Libraries dich speziell für den V003 mache bin ich permanent am überlegen, ob ich daraus eine Klasse mache oder nicht und ob das eine eigenständige Library wird oder nicht.

Bsp. Auszubildende sollen / müssen Textdisplay in Betrieb nehmen (HD44780) und stellen fest: Originaldemo funktioniert leider (wegen Timingsachen am Clock) nicht. Also schreibe ich eine extra Library mit denen die auch sofort umgehen konnten.

Gehen wir einen Schritt weiter, weil in einem anderen Thread scheinbar schon der Unterschied zwischen einem OLED (Grafik) Display und einem Textdisplay nicht sofort klar war, dass es Displayadapter für HD44780 mit I2C Anschluß gibt. Also bin ich momentan dabei, einen I2C Displayadapter für Arduino CH32V003 zu machen. Ehrlichkeitshalber muß ich sagen, dass ich die Funktionalität erst einmal in reinem C gemacht habe und jetzt portiere ich das nach C++ / Arduino. Hier stellt sich dann schon die triviale Frage: Packe ich das in eine kompakte Library mit evtl. unterschiedlichen Klassen, die zum einen ein Display parallel anfährt und die andere Klasse das mit I2C macht. Packe ich das in eine Klasse, bei der über den Konstruktor entschieden wird, welche Schnittstelle das Display hat? Prinzipiel: Nutze ich meine bereits erstellte I2C auf Hardware-Basis (weil der Core von V003 fehlerhaft ist) oder verwende ich lieber ein Software - Bitbanging um das an anderen Pins als den I2C Hardwarepins zu legen ... oder mache ich beides und untescheide wieder mit dem Konstruktor? Ganz "schräg" könnte ich noch sagen: Hey, ich mache das als Demo für den I2C-Bus.

Hier habe ich so überhaupt keine Ahnung davon, was ein Arduino User gerne hätte. Meine eigene "Strategie" ist, für jedes "Problem" seine eigene Source zu haben (zumindest mal im Embeddedbereich). Auf PC oder großen System packt man das in eine Datei, vllt. sogar in eine sehr mächtige Klasse, weil man eh genügend Resourcen hat.

Veit D. schrieb:

was in der Arduino Doku steht.

Es ist nicht nur wichtig was in der Arduino Doku steht, sondern grundsätzlich (und da muß ich mich daran machen) muß man seine Funktionen dokumentieren, damit andere und man selbst später damit umgehen kann.

Veit D. schrieb:

Jetzt kann man bestimmt Arduino in einem anderen Licht betrachten, die es geschafft haben vieles, trotz unterschiedlichster Hardware, auf einen gemeinsamen Nenner zusammenzuführen, damit eben nicht jeder bei Null anfangen muss.

Das größere Problem ist doch eher, dass man versucht, alles irgendwie "Arduino-kompatibel" zu machen, auf biegen und brechen. Für jede neue Plattform oder für jede neue Controllerfamilie wird ein neuer Core erstellt.... und dieser ist erst einmal unvollständig und häufig auch noch buggy (leider). Aber das Produkt muß ja schnell auf den Markt.

Im Falle von AVR ist das im Laufe der Jahre gewachsen, aber man sieht diesem Teil deutlich an, dass es ursprünglich eben für ATmega gemacht war.

Für mich als Elektroniker sieht Arduino in manchen Dingen "befremdlich" aus, ein "digitalWrite" ... herjeh... und dann auch noch eine Angabe von "HIGH" und "LOW"... anstelle von 1 und 0 (ich weiß, dass ich auch 1 und 0 angeben kann).

Aber das ist eben der Lauf der Dinge, wie heute Sachen verstanden werden (das ist jetzt keine Wertung von positiv oder negativ). Tatsache ist aber auch, dass mit Arduino grundsätzlich fast kein Hardwareverständnis gefördert wird (leider)

Herjeh, :-) ich wollte mich nicht darüber auslassen über ein für und wider von Arduino... (und hab hier schon zu viel geschrieben).

Veit D. schrieb:

Arduino fing zwar laut meines Wissens mit einem ATmega168P an, der Durchbruch begann jedoch mit dem ATmega328P auf dem bekannten UNO R3.

Arduino fing mit einem Board namens "Arduino Board Serial" an, das noch mit einer RS232 (anstelle von USB) ausgestattet war und einen ATmega8 als Controller hatte (das war im Jahr 2005). Diesem folgen Diecimila 2007 mit ATmega168 und USB... und dann gab es einige Platinen im r3 Format.

Veit D. schrieb:

Was du noch machen könntest, SpenceKonde (https://github.com/SpenceKonde) unterstützt mit seinen Cores ATtinys die wenig Speicher haben. Hier könntest du einmal reinschauen wie er das gemacht hat um Ressourcen zu sparen.

Da habe ich vor Jahren schon reingesehen gehabt. Ehrlich erschließt es sich mir nicht, auf solch kleinen Controllern Arduino machen zu wollen. Für die neueren ATtiny 0/1/2 series gilt das nicht, die sind ja oft min. so leistungsstark wie ein Mega... :-) den ATtiny1612 finde ich bspw. gar nicht so schlecht.

Veit D. schrieb:

Habe ich schon wieder zu viel getippt. ;-)

Ich habe auch zu viel geschrieben... und wünsche dir ebenfalls ein schönes Wocheende

PS: und ich ... bastel jetzt an einer anderen Baustelle die mir am Herzen liegt und die lange brach lag: meine Webseite ... und damit ich es nicht ganz verlerne, Seite mit JavaScript: NTC - LookUp Table Generator entsteht ... ähnlich wie es vor einiger Zeit sebulli gemacht hat ... er online und ich als konsolenprogramm ... :-) beim generierten Code der Tabelle kommen wir zur gleichen Tabelle, was nicht wundert, weil die benutzten Mechanismen sind dieselben. Bei der Interpolation habe ich dort etwas "gespickelt", gebe ich zu ... und habe diese Interpolation übernommen, weil sie effizienter ist als meine. Jetzt... habe ich mich entschlossen, meine Webseite um eben auch einen NTC-LookUp-Table Generator zu erweitern, die erste Version siehst man hier ... und wenn man sich den JavaScript Code anschaut, sieht man bei mir dann sehr deutlich, dass das einmal C war : https://www.jjflash.de/ntc_table_v2.html

#8019325
Lesenswert?

Veit D. schrieb:

Du kannst in der Arduino IDE genauso gut ... verwenden.

Nein, kann er nicht. Weil damit die unsichtbare Initialisierung des Frameworks verloren geht.

Dir ist das klar, aber anderen womöglich nicht. Außeredem wir sind ja gerade dabei, den ordentlichen Weg zu lehren. Wenn schon Arduino, dann richtig.

: Bearbeitet durch User
#8019327
Lesenswert?

Veit D. schrieb:

Geschenkt. :-)

Übrigens, die Arduino-API hieß ursprünglich "Wiring". Es lohnt sich, hier mal die ersten zwei Seiten zu lesen.

1
Have you ever wondered where those commands come from?
2

3
Probably one of the most distinctive things, that is widely known and used today by Arduino users in their sketches, is the set of commands I created as the language definition for Wiring.
4

5
    pinMode()
6
    digitalRead()
7
    digitalWrite()
8
    analogRead()
9
    analogWrite()
10
    delay()
11
    millis()
12
    etc

https://arduinohistory.github.io

: Bearbeitet durch User
#8019346
Lesenswert?

Alexander schrieb:

Veit D. schrieb:

Du sprichst ganz klar für dich. Nicht alle sind wie du.

Dito. Du bist bist extrem drin. Und ich kann ruhigen Gewissens behaupten ich bin schon überdurchschnittlich tief ins Framework eingetaucht, verglichen mit dem gemeinen Arduino Nutzer.

Dann schreib nicht laufend solchen Unsinn, welche absolut unnötige Gegenreaktion hervorrufen. Mir macht das keinen Spass.

#8019353
Lesenswert?

Nemopuk schrieb:

Veit D. schrieb:

Du kannst in der Arduino IDE genauso gut ... verwenden.

Nein, kann er nicht. Weil damit die unsichtbare Initialisierung des Frameworks verloren geht.

Dir ist das klar, aber anderen womöglich nicht. Außeredem wir sind ja gerade dabei, den ordentlichen Weg zu lehren. Wenn schon Arduino, dann richtig.

Ich habe es rausgesucht. Du meinst

Du kannst in der Arduino IDE genauso gut

1
int main() {
2
  ...
3
  while(1) 
4
  {
5
   ...
6
  }
7
}

Dazu musst du den gesamten Kontext der Unterhaltung zwischen Ralph und mir betrachten.

#8019358
Lesenswert?

Hallo Nemupuk,

kleine Ergänzung. Das alleine für sich aus dem gesamten Kontext zu ziehen macht wirklich keinen Sinn. In der Unterhaltung ging es an dem Punkt darum, ob man sich generell entscheidet konform für Arduino zu programmieren oder die IDE nur als Programmierwerkzeug verwendet und ohne Framework sein eigenes Ding macht.

#8019371
Lesenswert?

Hallo Ralph,

wegen Display Lib. Ja so eine Grundsatzentscheidung ist schwierig. Meistens wird das mittels Konstruktor Überladung gelöst. Dafür muss man die Parameterreihenfolge gut überlegt wählen und man kann mit Defaultwerten arbeiten. Die Vorliebe muss man gedanklich durchspielen.

Eine beliebte Lib für grafische Displays ist die von Oli Kraus. https://github.com/olikraus/u8g2 https://github.com/olikraus/u8g2/wiki Dich wird es erschlagen wenn du die anschaust. Er erschlägt alles mit Konstruktor überladen. Ist bestimmt einen Blick wert. Nur ein Bsp. wegen Konstruktor.

Man kann auch eine gemeinsame Basisklasse schreiben die dann an die verwendete spezifische Interface Klasse vererbt wird. Dann hätte man unterschiedliche Konstruktoren und mehr Parameterfreiheiten. Da gibt es keine Vorgabe. Beim Standard HD44780 Display vielleicht nur, dass wie erwähnt, sowas wie lcd.print() nutzbar ist.

Wenn man zwischendurch die "Baustelle" wechselt, deine Webseite, wird das helfen aus dem Gedankenwald herauszukommen. Danach kommen meistens bessere Ideen. Glaub mir. :-)

#8019447
Lesenswert?

Bisher,bin ja ebenfalls Arduino nutzer, kam ich nach kurzer Einarbeitung auch mit fremden "Codeschnipseln" ganz gut zurecht und habe diese entsprechend "Arduino gerecht" für meine PY32 zurechtgebastelt.

Drehgeber zb. https://www.mikrocontroller.net/articles/Drehgeber#Solide_L%C3%B6sung:_Beispielcode_in_C

War am Ende nicht wirklich schwer das umzustricken, weil Arduino eben für die Interrupts/Timer ect. definierte Funktionen hat. Es ist leichter als die Einstellungen in die entsprechenden Register zu Schreiben, was das verstehen das Code angeht. Was fehlt ist der Bezug zum Hintergrund, das kommt aber mit den ersten Problemen die sich nicht mit Hilfe eines Tutorial lösen lassen. Wenn der core beim Einstellen des Takt fehlerhaft ist, bleibt das schnellste workaround es selbst zu lernen und was eigenes dafür zu schreiben. Man bleibt halt leichter am Ball wenn wenigstens zwischendurch mal was ohne basteln läuft.

Codegröße ist echt ein Faktor, schon die Optimierungsoptionen ergeben teils einige KB Unterschied.

#8019477
Lesenswert?

Moin Veit,

die u8g2 Library und auch die Displaytreiber von Adafruit (egal ob monochrome oder farbig) habe ich mir natürlich schon vor längerer Zeit angesehen und genau diese Librarys schrecken mich ab.

Der größte Vorteil dieser Treiber ist aus meiner Sicht der Dinge auch ihr größter Nachteil. Sie sind derart umfangreich, dass dich die Libraries schier erschlagen und ohne das Wiki kann man intuitiv zum Einstieg erst einmal gar nichts machen leider.

Natürlich ist es sehr super, wenn man ultra viele Displays unterstützt, aber das Inbetriebnehmen wird dadurch nicht so wirklich leichter.

Beispielsweise habe ich versucht, allerdings in C, mehrere Displays (farbige TFT's) in einer Source unterzubringen, was ich auch getan habe. Die Source ist in ihrern Einstellmöglichkeiten mittlerweile hart an der Grenze, was ich mir antun möchte (und ich habe das selbst geschrieben). Unterschiede in Farbreihenfolgen, Adressräumen (sogar bei Displays mit dem gleichen Displaycontroller, Serien, die eine Verdrahtung wie ein 160x128 haben, aber ein nur ein Glas 128x128 montiert haben), Initialisierungssequenzen und dann möchte man das ganze ja universell haben in den Anschlussmöglichkeiten. Zu guter letzt dann noch SPI oder paralleles Interface war / ist nicht so richtig übersichtlich und zu guter letzt (im Falle von STM32) das ganze noch mittels DMA betreibbar bewegt mich dann, das ganze (auch eine meiner Baustellen) auf C++ umzustellen und ich erhoffe mir davon eine einfachere Handhabung.

Aber wie gesagt ist das auch eine weitere Baustelle, :-) mit dem CH32V003 dachte ich eigentlich, ich mache etwas mit einem schönen Anfang und einem schönen Ende und bin da dran kleben geblieben (egal ob Arduino oder Plain-C) und werkel daran schon länger als ich es mir so gedacht hatte.

Im Falle eines Textdisplays mit I2C Adapter denke ich, ich mache eine extra Lib dafür.

Veit D. schrieb:

Wenn man zwischendurch die "Baustelle" wechselt, deine Webseite, wird das helfen aus dem Gedankenwald herauszukommen. Danach kommen meistens bessere Ideen. Glaub mir. :-)

:-), ich weiß !

#8019538
Lesenswert?

Ralph S. schrieb:

Aber wie gesagt ist das auch eine weitere Baustelle, :-) mit dem CH32V003 dachte ich eigentlich, ich mache etwas mit einem schönen Anfang und einem schönen Ende und bin da dran kleben geblieben (egal ob Arduino oder Plain-C) und werkel daran schon länger als ich es mir so gedacht hatte.

Das dürfte jedem bei jedem Projekt so gehen. Selbst in Firmen mit Geld und viel Druck ist das so.

#8019544
Lesenswert?

Behalte immer im Hinterkopf, daß die Chinesen erheblich weniger Hemmungen haben, unausgereifte Sachen in den Massenmarkt zu bringen. Da könnte man erwägen, für ordentliche Doku und vollständige Software aus Europa 30 Cent mehr aus zu geben. Der CH32V003 war mal ein extremes Schnäppchen, aber andere haben inzwischen nach gezogen.

: Bearbeitet durch User
#8019564
Lesenswert?

Arduino Arduino Arduino Arduino

Erstens, es gibt dedizierte Arduino-Foren. Zweitens, Mikrocontroller sind sehr unterschiedlich, weil ihre Komponenten sehr unterschiedlich sind. Und weder C, noch C++, noch C+++, noch Python, noch Kobra, noch Anakonda beschreiben die konkreten Komponenten konkreter Mikrocontroller. Und auch Arduino hilft nicht. Z.B., der kleine ATtiny412 enthält • 16-bit Timer/Counter type A (TCA) • 16-bit Timer/Counter type B (TCB) • 12-bit Timer/Counter type D (TCD) • 16-bit Real-Time Counter (RTC) Alle Zähler sind für unterschiedliche Aufgaben konzipiert, nicht für Arduino.

Angehängte Dateien:
#8019568
Lesenswert?

Hallo Georg,

hast du dich im Thread vertan? Hat irgendjemand etwas anderes behauptet? Deine Antwort, weil als Gegenargument formuliert, passt irgendwie nicht zu den geschriebenen Antworten. Ich weiß nicht worauf deine Antwort eine Antwort ist. Manual Screenshots ohne Bezug. Ich finde das komisch.

#8019594
Lesenswert?

... jetzt muß ich schmunzeln zwecks des Posts von Georg M. der mich doch am Anfang verwirrt hat, ob ich hier richtig bin.

Okay.... ich war zwar auf einer anderen Baustelle unterwegs (meine Webseite), aber da funktioniert etwas zumindest funktional und ich muß "nur" noch einen Beschreibungstext da einstellen. Dann läßt mich das Thema hier nicht so wirklich los und das, obwohl ich ja "eigentlich" kein Arduino mache (aber wie es jetzt ausschaut eben doch ein bisschen).

Zudem ist da (negative Charaktereigenschaft) mein Ego (aber nur ein kleines bisschen) angekratzt, weil es dann irgendwie so ausschaut, als ob ich ein blutiger Anfänger bin (hmm, unter Arduino stimmt das vllt. sogar, Arduino ist unter der Motorhaube dann doch so ziemlich vielschichtig).

Also habe ich mich noch einmal hingesetzt und mich der "Problematik" gewidmet, wie man diesem für mich unsäglichen "Serial.print" Herr werden kann und - zu Veit schiel - das dann mal so überlegt, wie denn das unter C++ aussehen sollte / würde und für mich erst einmal etwas "hingebogen".

Und ich bin wirklich sehr gespannt, was Veit und andere dazu sagen (und Veit, du siehst, ich habe die loop nicht kastriert und die counter variable brav static gemacht).

Die nächste Frage hier ist dann, ob ein typischer Arduino-User oder auch Anfänger damit etwas anfangen kann.... und ob das legitim ist, das für Demonstration anderer Arduino-Libraries zu verwenden (bspw. Auswertung NTC-Sensor).

Weil es so kurz ist, der Demo-Sketch ausnahmsweise auch hier zu lesen:

1
/* --------------------------------------------------------
2
                         cout_demo.cpp
3

4
     demonstriert die Verwendung eines abgepeckten cout
5
     mit Arduino
6
     
7
     07.03.2026 R. Seelig
8
   -------------------------------------------------------- */
9

10
#include <Arduino.h>
11
#include "cout_light.h"
12

13
// Objektinstanz fuer cout_light
14

15
cout_light<HardwareSerial> cout_serial(Serial);
16

17
// und Umleiten auf den Namen "cout" ... :-) nicht ganz die feine Art
18
#define cout  cout_serial
19

20
/* --------------------------------------------------------
21
                         setup
22
   -------------------------------------------------------- */
23
void setup() 
24
{
25
  Serial.begin(115200);
26

27
  cout << F("\n\r Hallo Welt,\n\r ein cout-Demo mit Arduino,hier Zaehlerausgabe auf Serial\n\n\r");
28
}
29

30
/* --------------------------------------------------------
31
                         loop
32
   -------------------------------------------------------- */
33
void loop() 
34
{
35
  static int counter = 0;
36
  
37
  cout << F("\r Counter: ") << Dec << counter;
38
  delay(1000);
39
  counter++;
40
}
Angehängte Dateien:
#8019596
Lesenswert?

Ich fand schon vor 30 Jahren, dass dieses

cout << irgendwas

syntaktisch nicht zum Rest der Sprache passt. Da hat man meiner Meinung nach gleich zu Anfang demonstriert, wie man die Sprache nicht missbrauchen sollte.

Seit dem habe ich viele andere Programmiersprachen gelernt. Trotz der damit einhergehenden Toleranz für Vielfalt ist das Unbehagen gegen cout bis heute geblieben. Cout fügt sich wie ein Krebsgeschwür ins Projekt ein.

: Bearbeitet durch User
#8019604
Lesenswert?

Also so als Anfänger, ja, anfangen könnte man was damit.

Allerdings cout gibt's unter Arduino eigentlich nicht standardmäßig, der gemeine Arduino nutzer wird damit erst mal nicht viel anfangen können, verbreiteter ist Streaming.

Das muss zwar auch erst hinzugefügt werden, ist aber scheinbar beliebter als CinCout.

#8019625
Lesenswert?

Hallo,

ich sage einmal so für mich redend. Sobald der gemeine Arduino Nutzer/Programmierer :-) irgendwann ein C/C++ Buch aufschlägt, kommt er mit cin und cout in Berührung. Von daher finde ich es legitim. Wer eine Streaming Lib nutzt muss sowieso umdenken und ohne print klar kommen. Und das geht. ;-) Ansonsten, irgendwas ist doch immer. ;-)

Zum Ralph seinen Code. Ja ja, dass #define sticht mir ins Auge. :-) using funktioniert leider nicht. Dafür kann man C++ like eine Referenz verwenden. Entweder:

1
constexpr auto &cout {cout_serial};

oder

1
constinit auto &cout {cout_serial};

oder

1
cout_light<HardwareSerial> &cout {cout_serial};

Man kann das auch weglassen und gleich die Objektinstanz so benennen.

1
cout_light<HardwareSerial> cout (Serial);

Hier bitte kein '\r' sondern ein '\n'.

1
cout << F("\n Counter: ") << Dec << counter;

Ansonsten sieht das doch gut aus. :-)

#8019679
Lesenswert?

Lach, Hallo Veit,

irgendwie finde ich das grundsätzlich witzig, dieses "hin und her" der Postings.

Und immerhin, die "Anmerkungen" von dir werden kleiner, grundsätzlich wußte ich, dass du das #define monieren würdest, aber die cout - Umsetzung ist doch schon mal so halbwegs C++, oder etwa nicht (und das cout auch).

Allerdings muß ich Nemopuk rechtgeben, so wirklich warm geworden bin ich mit dem cout und cin nicht wirklich und für den Output "liebe" ich das printf, das so viele hassen. Für mich ist der Aufbau von printf alles in allem eher logisch und auch relativ schnell zu sehen, was ausgegeben werden soll und es ist weniger Schreibarbeit (empfinde ich zumindest). Aber, es ging hier um C++ und deshalb auch dieses cout hier.

Grundsätzlich gefällt mir das immer noch besser, als die einzelnen Streamfunktionen print, println, write etc. im Sketch aufzurufen.

Und:

Veit D. schrieb:

Hier bitte kein '\r' sondern ein '\n'.cout << F("\n Counter: ") << Dec << counter;

By the way: Sollte dich - wider erwarten - der CH32V003 interessieren, klebe (okay löte) ich dir gerne einen kleinen Programmer hierfür zusammen und einen Controller auf eine Adapterplatine und schick dir das. Allerdings funktioniert der Programmer zumindest von mir getestet nur unter Linux (würde ich doch sogar glatt unentgeldlich machen, einfach so just for fun). Beim Core des Arduino muß man dann boards.txt plattform.txt und system_ch32v00x.c patchen (aber wem erzähl ich das, das weißt du alles selbst)

Natürlich soll das ein '\r' sein: Mein Terminalprogramm ist so eingestellt, dass \r und \n eben als Carriage return und Newline getrennt interpretiert werden. Damit erreiche ich, dass meine Ausgabe immer in derselben Zeile erfolgt (ohne Zeilensprung) und das ist auch gewollt so.

Angehängte Dateien:
#8019680
Lesenswert?

Hallo Ralph,

kein Problem, ich habe gegen cout nichts einzuwenden. Wenn \r Absicht ist, wusste ich nicht, dann ist das okay, Danke für das Angebot, freut mich, ggf. kommen wir darauf zurück. ;-) Das ist auch lustig, hatte vor kurzem im Arduino Forum jemanden auch ein kleines Geschenk machen wollen. :-)

: Bearbeitet durch User
#8019790
Lesenswert?

Ralph S. schrieb:

Zudem ist da (negative Charaktereigenschaft) mein Ego (aber nur ein kleines bisschen) angekratzt, weil es dann irgendwie so ausschaut, als ob ich ein blutiger Anfänger bin (hmm, unter Arduino stimmt das vllt. sogar, Arduino ist unter der Motorhaube dann doch so ziemlich vielschichtig).

So ist es: Arduino nutzen ist nicht schwer, Arduino machen hingegen sehr.

Ich erwähne es noch mal: Es gibt da gewisse Coding-Guidlines, die man natürlich einfach brechen kann, wenn es einem Spaß macht. Nur sollte man es dann vielleicht nicht mehr "Arduino" nennen.

#8019798
Lesenswert?

Alexander schrieb:

Und warum schreibst Du es dann nicht konsequent durchgängig auch so da wo neue Zeilen gewünscht sind F("\r\nHallo Welt,\r\n"); das muss doch auch am Ego kratzen?

??????

Irgendwie verstehst du wohl das einfachste nicht, um das es geht, oder ? Wenn ich nach "Hallo Welt" eine neue Zeile haben möchte (und die möche ich haben), dann folgt dem eben ein "\n\r".

Und ob ich jetzt (wie von dir vorgeschlagen) \r\n schreibe, oder \n\r ist Jacke wie Hose. Ob ich erst einen Carriage return mache und dann einen Zeilensprung oder umgekehrt macht auf der Ausgabe keinen Unterschied.

Ralph S. schrieb:

cout << F("\n\r Hallo Welt,\n\r ein cout-Demo mit Arduino,hier Zaehlerausgabe auf Serial\n\n\r");

Natürlich hätte ich auch schreiben können:

1
cout << F("\n\r Hallo Welt,");
2
cout << F("\n\r ein cout-Demo mit Arduino, hier Zaehlerausgabe auf Serial");
3
cout << F("\n\n\r);

Hrmpf, ich hätte ja noch als Kommentar hinzufügen können, dass ich hier "Hallo Welt" ausgebe (das.... würde dann wirklich am Ego kratzen)

#8019830
Lesenswert?

Wenn man wie eine Schreibmaschine denkt passieren eben solche Fehler. LFCR ist nicht nur unüblich sondern falsch. Mag auf der "Schreibmaschine" nicht stören, aber spätestens bei utils wie dos2unix wird das spannend (wer's braucht)

Ich wusste übrigens bis gestern nicht dass Arduino gar kein Serial.printf() hat. Auf dem ESP32 funktioniert das. Würde IMHO Sinn machen das aus arduino-esp32/cores/esp32/Print.h zu klauen.

https://forum.arduino.cc/t/serial-print-and-printf/146256

: Bearbeitet durch User
#8019854
Lesenswert?

Alexander schrieb:

aber nur bei Dir, sonst nirgends auf der Welt

wie schräg bist du denn drauf? Erstens, auch wenn ich das nicht wirklich mag, macht das Microsoft so... zweitens darf man seine Console so einstellen wie es funktional ist. Wenn man also wie ich, es gerne hat, dass die Ausgabe in ein und derselben Zeile erfolgen soll, stellt man das Terminal für getrennte \n \r ein. Einzig mittels ESC-Sequenzen kann man das auch bewerkstelligen, allerdings aufwändiger. Grundsätzlich: was machst du für ein Fass auf, für so etwas triviales wie Steuerzeichen in einem AsciiZ String???

Ich finde dich ganz toll, echt.

Aber immerhin, das meine ich ernst, könnte ich meiner HardwareSerial mein abgespecktes printf vermachen. Grundsätzlich werd ich hier dieses abgespeckte printf mit den entstehenden Bibliotheken hier einstellen. Das kann dann zwar kein float und auch keine Längenangaben, dafür trägt es im Falle von AVR nur mit 350 Byte auf, bei CH32V003 419 Byte... aber du darfst dann gerne auch wegsehen, weil in den Demos dann wieder \n\r zu sehen ist.

Auch würde ich gerne von dir lernen, zeig mal, was du da an Arduino-Klassen schon produziert hast (anstelle dich über den Stil anderer zu echaufieren)

#8019930
Lesenswert?

Ralph S. schrieb:

Und ob ich jetzt (wie von dir vorgeschlagen) \r\n schreibe, oder \n\r ist Jacke wie Hose.

Ist es nicht. Wenn ich meine Jacke als Hose anziehe fällt da was raus.

Ralph S. schrieb:

Erstens, auch wenn ich das nicht wirklich mag, macht das Microsoft so...

Nein macht es nicht. Du meinst:

Nemopuk schrieb:

Üblicherweise ist die Reihenfolge \r\n.

Ralph S. schrieb:

Grundsätzlich: was machst du für ein Fass auf

Mach ich nicht. Ich hab Dich nur auf den (trivialen) Typo hingewiesen, der sich bei Dir durchzog (und zu solchen Mißverständnissen wie mit Veit führen kann). Sieht halt schlampig aus so, wäre schade wenn das so ins Repo wandert.

Ralph S. schrieb:

zeig mal, was du da an Arduino-Klassen schon produziert hast

Da gibt es nichts. Ich nutze was da ist und erfinde nicht das Rad neu. Das ist ja das schöne an Arduino. Ich /muss/ gar nichts können.

: Bearbeitet durch User
#8019987
Lesenswert?

Moin,

Ich bin eigentlich der Meinung, wenn etwas mehr Komfort gewünscht ist, daß man dann besser eine etwas üppiger ausgestatteten uC wählen sollte. Beim ATMEGA1284 mit 16K z.B., spielt die Unterstützung von printf eine geringere Rolle als beim 328P oder noch kleiner. Beim STM32L496 denke ich überhaupt nicht daran. Ausser Sportlichkeit lohnt es sich nicht mehr frugal den uC zu wählen. 32-bit uC kosten heutzutage weniger als die älteren 8-Bitter und braucht nicht abgespeckte Bibliotheken. Beim STM habe ich auch noch einen schnell und gut funktionierenden Debugger. Da ist das Arduino Konzept klar im Nachteil. Andrerseits kann man bei Erfahrung auch gut ohne Debugger auskommen und mit cleverer Ausnützung von printf und Oszi Unterstützung Probleme verfolgen. Aber manchmal hat natürlich der Debugger schon den Tag gerettet.

Trotzdem arbeite ich noch gerne mit den kleineren Exemplaren, weil es einfach erzieherisch ist, mit geringen uC Ressourcen Probleme effizient in funktionierende HW umzusetzen und diszipliniert zu planen and programmieren. Viele Realwelt Steuer Anwendungen agieren mit ihrer Umwelt in ms oder s Skala. Und wenn es wirklich nicht langt, skaliert man aufwärts. Für "moderne" kommunizierenden Anwendungen nimmt man ohnehin oft ESP32 oder Vergleichbares.

Gerhard

#8020001
Lesenswert?

Gerhard O. schrieb:

32-bit uC kosten heutzutage weniger als die älteren 8-Bitter und braucht nicht abgespeckte Bibliotheken.

Der CH32V003 /ist/ ein 32-Bit-µC, nur halt einer am unteren Ende der Ausstattung.

Ihm hat sich übrigens ein etwas besser ausgestatteter Nachfolger hinzugesellt, der CH32V002 mit doppelt so viel RAM.

Und wenn man damit leben kann, daß es kein SO-8 bzw. SO-16 als Gehäuse gibt, ist der CH32V006 ein nochmal deutlich besser ausgetatteter Kandidat - 8 kiB RAM und in den meisten Fällen* 62 kiB Flash-ROM. Geben tuts ihn ab TSSOP20/QFN20 bis zu QFN32 (mit dann den meisten I/Os).

Dennoch ist der auch für 5V-Betrieb geeignet, was für viele Bastler den einen oder anderen Pegelkonverterkrampf vermeiden hilft.

*) der CH32V006F4U6 hat aus irgendwelchen Gründen nur 16 kiB Flash und auch nur 4 kiB RAM,

#8020014
Lesenswert?

Anscheinend genug, daß es manchen "Makern" oder Bastlern Probleme bereitet und sie mit Pegelwandlern herummachen müssen, weil sie mit 5V-Peripherie zu tun bekommen.

Die verschiedenen CH32V00x-Modelle laufen aber auch mit weniger als 3 V, die neueren bereits ab 2 V (2.4, wenn ein ADC genutzt werden soll). Beschränkungen bei der Taktfrequenz gibt es wohl nicht.

Insofern ist der 5-V-Betrieb ein /Kann/, kein Muss.

#8020015
Lesenswert?

Alexander schrieb:

Da gibt es nichts. Ich nutze was da ist und erfinde nicht das Rad neu. Das ist ja das schöne an Arduino. Ich /muss/ gar nichts können.

Ich würde an deiner Stelle den Ball flacher halten. Dir muss bewusst sein, wenn du nichts kannst, dann müssen andere etwas können, damit du vorhandenes Nutzen darfst. Das heißt, du bist abhängig von Entwicklern wie Ralph die einen Core schreiben, den du später nutzen kannst. In der Sache hast du Recht, nur kann man es auch netter formulieren.

Es gibt zwischen den Betriebssystemen paar kleine Unterschiede in der Interpretation der Steuerzeichen. Das betrifft jedoch weniger Serial -> Terminalausgabe, sondern Programme welche in eine Textdatei schreiben. Jetzt weiß ich nicht was Ralph für ein Terminal verwendet. Ich hatte es mit dem Seriellen Monitor der Arduino IDE 1.8.19 und 2.3.8 probiert. Eine Einstellung auf CR hilft da nicht. Es wird fortlaufend die Zeile weitergeschrieben, bis es aus den Sichtfeld ist bzw. man den Scrollbalken bewegen muss. hterm kommt mit CR allein zurecht und macht einen Zeilenumbruch. hterm weiß offenbar, dass am COM Port (USB) im Jahre 2026 keine Schreibmaschine angeschlossen ist. :-) Der Serielle Monitor weiß das nicht bzw. gibt es da ein Problem was man adressieren sollte oder es verhält sich Windows konform, was auch nicht sein kann, denn ein Wagenrücklauf erfolgt auch nicht. Könnte man separat besprechen. Ausreichend für einen Zeilenumbruch im Terminal im Jahre 2026 wäre '\n', macht das was die Beschreibung dazu sagt. Mit welchen Terminal '\r' sauber funktioniert weiß ich nicht. Ich kenne keines was an den Anfang der Zeile springt und alles überschreibt.

Unter Windows mit Dateioperationen ist dagegen '\r\n' Standard für EOL. Hiermit gibt es dann wohl die bekannten Problem mit Textdateien bei Austausch zwischen Betriebssystemen.

Jedes Detail habe ich nun nicht studiert, es gibt jedoch Interpretationsunterschiede im OS. https://www.loginradius.com/blog/engineering/eol-end-of-line-or-newline-characters

Nemopuk schrieb:

Was läuft denn heute noch mit 5V, außer uralter Arduino Kram?

Entwicklungen verpasst?

Hier geht es übrigens immer noch um CH32V003. Kein STM oder sonstwas.

: Bearbeitet durch User
#8020035
Lesenswert?

Veit D. schrieb:

Ausreichend für einen Zeilenumbruch im Terminal im Jahre 2026 wäre '\n', macht das was die Beschreibung dazu sagt. Mit welchen Terminal '\r' sauber funktioniert weiß ich nicht. Ich kenne keines was an den Anfang der Zeile springt und alles überschreibt.

Alles was sich VT52,VT100,VT220, … nennt. Und wahrscheinlich ein ganzer Sack voller korrekt implementierter Terminal Emulationen. Selbst minicom, rudimentär in Python programmiert, macht das.

Als newline/neue Zeile: 0x0d CR wird/wurde vom alten Apple genutzt. 0x0d,0x0a CRLF wird von Windows genutzt. 0x0a LF wird von allem Unixodiden genutzt. 0x15 NL wird/wurde von IBM im EBCDIC genutzt.

: Bearbeitet durch User
#8020054
Lesenswert?

Christoph M. schrieb:

Gerhard O. schrieb:

Beim STM habe ich auch noch einen schnell und gut funktionierenden Debugger. Da ist das Arduino Konzept klar im Nachteil.

Wie das?

https://github.com/stm32duino

Danke für den Hinweis. Habe ich bisher ignoriert, weil ich beim STM32 lieber mit ST Werkzeugen und Debugger arbeite. Und bei den 8-bittern stimmt es ja, dass Debugging in der Regel nicht vorgesehen ist.

Wer effizienten Debug mit minimal IO Verlust möchte, ist wahrscheinlich z.B. bei MSP430 und Z!Encore besser aufgehoben. Der MSP430 ist da im Umgang mit CubeMX IDE ohnehin sehr ähnlich. Auch Siliconlabs 8051 Derivate haben ähnlichen Komfort. Über die CH32 Familie kann ich nicht kommentieren, weil ich noch keinen Grund hatte, mich damit zu befassen - stehe da eher neutral dazu. Vermutlich sind die Dokumentationen unserer Hersteller zugänglicher, aber das ist Geschmacksache.

Die einzige chinesische uC Famile die mich peripherell interessiert, sind STCs 8051 uC Flash programmierbare Derivate, die sich über UART Flashen lassen. Und auch nur, weil mir einige zugelaufen sind und der Keil MC51 kompatibel ist. Ob es sich lohnt viel Zeit zu investieren - da bin ich eher skeptisch. Aber es wäre eine Gelegenheit die Tochter einer anderen Mutter näher kennenzulernen.

Seid froh, dass es für die uC eures Herzen, vielfach freie mächtige Entwicklungswerkzeuge gibt, die den Einstieg leicht machen. Arduino ist für viele Sachen auch sehr zweckmässig, wobei dort, wenn man nicht uC übergreifend arbeiten muß, auch dort wie sonst gewohnt, bare Metal Zugang hat. Keiner ist gezwungen immer nur mit Libraries arbeiten zu müssen. Arduino, dank GCC, wo kompatible, lässt da keine Wünsche offen. Übergreifende uC Kompatibilität im Quellcode für Portabilität ist nicht immer unbedingt für alle notwendig noch wichtig.

Gerhard

: Bearbeitet durch User
#8020057
Lesenswert?

Gerhard O. schrieb:

Und bei den 8-bittern stimmt es ja, dass Debugging in der Regel nicht vorgesehen ist.

Hätten sie bestimmt gerne implementiert, wenn der Hersteller (Atmel) das nicht als geheimes Premium Feature für seine eigenen schweineteuren Debugger reserviert hätte. Die Hardware ist inzwischen bezahlbar geworden, aber das Protokoll immer noch geheim.

Gerhard O. schrieb:

Vermutlich sind die Dokumentationen unserer Hersteller zugänglicher, aber das ist Geschmacksache.

Finde ich nicht. Ordentliche Dokumentation ist Grundvoraussetzung für vernünftiges Arbeiten.

: Bearbeitet durch User
#8020067
Lesenswert?

Norbert schrieb:

Alles was sich VT52,VT100,VT220, … nennt. Und wahrscheinlich ein ganzer Sack voller korrekt implementierter Terminal Emulationen. Selbst minicom, rudimentär in Python programmiert, macht das.

Als newline/neue Zeile: 0x0d CR wird/wurde vom alten Apple genutzt. 0x0d,0x0a CRLF wird von Windows genutzt. 0x0a LF wird von allem Unixodiden genutzt. 0x15 NL wird/wurde von IBM im EBCDIC genutzt.

Hallo Norbert,

Danke für den Hinweis. Von VT100 hatte ich schon gehört, da nie benötigt fiel das immer hinten runter. ;-)

#8020129
Lesenswert?

Norbert schrieb:

Alles was sich VT52,VT100,VT220, … nennt.

Nö. Die interpretieren CR als "springe an den Anfang der aktuellen Zeile". Erst in Kombination mit LF gibt es eine neue Zeile.

LF alleine positioniert den Cursor eine Zeile unter seiner bisherigen Position, ändert aber nichts an seiner horizontalen Ausrichtung.

Allerdings nutzen die meisten Terminalemulatoren eine Einstellung, daß sie auch einzelne CR bzw. LF wie eine Kombination aus CR+LF interpretieren.

#8020135
Lesenswert?

Harald K. schrieb:

Norbert schrieb:

Alles was sich VT52,VT100,VT220, … nennt.

Nö. Die interpretieren CR als "springe an den Anfang der aktuellen Zeile". Erst in Kombination mit LF gibt es eine neue Zeile.

Tja Harald, die korrekte Abfolge des Zitats lautet allerdings wie folgt:

Veit D. schrieb:

Mit welchen Terminal '\r' sauber funktioniert weiß ich nicht. Ich kenne keines was an den Anfang der Zeile springt und alles überschreibt.

Worauf ich antwortete:

Norbert schrieb:

Alles was sich VT52,VT100,VT220, … nennt.

#8020142
Lesenswert?

Hallo Norbert,

richtig. Tera Term habe ich ausprobiert und es führt CR korrekt aus. Für einen Zählerwert den Ralph in seinem Demoprogramm zeigt, ist das okay. Funktioniert nur leider nicht mit dem Seriellen Monitor der Arduino IDE und auch nicht mit hterm, welches ich auch sehr gern verwende. Da kann man wie gesagt eine Anfrage stellen. Werde ich machen.

: Bearbeitet durch User
#8020166
Lesenswert?

Veit D. schrieb:

Jetzt weiß ich nicht was Ralph für ein Terminal verwendet. Ich hatte es mit dem Seriellen Monitor der Arduino IDE 1.8.19 und 2.3.8 probiert.

Ich verwende 2 Terminals, zum einen PuTTY, das so ziemlich alles kann, was Datenübertragung angeht (auch SSH und Telnet), aber häufiger ein (nur optisch) modifiziertes picocom https://github.com/npat-efault/picocom in der Konsole!

Den seriellen Monitor der Arduino IDE verwende ich gerade wegen der vielen Einschränkungen überhaupt nicht.

Veit D. schrieb:

Das heißt, du bist abhängig von Entwicklern wie Ralph die einen Core schreiben, den du später nutzen kannst.

:-) um Mißverständnissen vorzubeugen, ich entwickle keinen Core, dafür bin ich ein viel zu großer Arduino-Anfänger und werde das wohl auch bleiben. Ich weiß, wie schon erwähnt nicht, was ein typischer Arduino-User sich wünscht.

Ich schreibe nur Funktionalitäten für einen meiner Ansicht nach unvollständigen Core, damit eben ein CH32V003 auch unter Arduino gut verwendbar ist. Hier vordergründig SPI, I2C, ADC und UART (uart funktioniert mit dem Core, allerdings nur schreibend, nicht lesend). Und ich schreibe Demosketche, wie bspw. Timer2 verwendet werden kann. Die Interruptbehandlung des CH32V003 Core ist ebenfalls unvollständig und hier muß ich ein ebenfalls ein Workaround machen, damit man dieses Nutzen kann. Ohne die Arduinofunktionen habe ich es bspw. noch nicht erreicht, einen Interruptvektor aus einer Klasse heraus anszuspringen.

Aber ich lasse mich von Nörglern wie alecxs nicht abschrecken: er muß ja einen CH32V003 nicht nutzen.

Meine "Versuchskanninchen" kommen mit den Funktionen die ich bereits habe sehr gut zurecht, allerdings - geb ich zu - muß ich die Verwendung erklären und es wartet eine Menge Doku auf mich.

Im Moment geht mir durch den Kopf, für den CH32V003 das Streaming um eine Methode printf zu erweitern.

PS: wenn ich gerade so über Unzulänglichkeiten nachdenke, erinnere ich mich noch sehr genau, wie ich mich gewundert habe, wie ein einfaches Arduino-Programm, welches eine 7-Segmentanzeige über einen TM1650 angesteuert hat, unverhältnismäßig groß geworden ist, und mich deshalb in die Tiefen des Cores hinabbegeben habe. Als Übeltäter habe ich dann delayMicroseconds() ausgemacht, welches soviele Dinge mit einbindet, dass der Speicherbedarf bei Verwendung dieser delayMicroseconds um mehr als 5600 Byte angestiegen ist (was bei einem gesamten Flashspeicher von 16 kByte enorm ist).

Also gibt es bei mir, wenn es genauer sein soll, hier eine Verzögerung, die mittels Timer2 realisiert wird und wenn es ungenauer sein darf schlicht über eine for schleife, in der __asm volatile(" nop "); ausgeführt wird (und sicherlich schreien jetzt Arduino-User auf, weil (eine einzige) Assembleranweisung in Arduino auftaucht. Grundsätzlich glaube ich hier jedoch, dass die Speichereinsparung enorm ist und ein Kommentar reicht, was man der Funktion zu übergeben hat. Wie die Funktion dann die Mikrosekunden verzögert sollte dem Anwender dann egal sein.

Angehängte Dateien:
#8020184
Lesenswert?

Ralph S. schrieb:

und ein Kommentar reicht, was man der Funktion zu übergeben hat. Wie die Funktion dann die Mikrosekunden verzögert sollte dem Anwender dann egal sein.

Die interna jucken meistens null, jedenfalls dann nicht wenn die Funktion das macht was man braucht.

Erst wenn's nicht klappt, gehen die meisten erst mal library für library durch bis eine funktionierende gefunden ist, gibt's da nichts, geht's weiter: KI, Foren, Aufgeben..

Ralph S. schrieb:

Ich weiß, wie schon erwähnt nicht, was ein typischer Arduino-User sich wünscht.

Das muss im Prinzip wie PHP sein, der normale "Arduino Nutzer" instbesondere diese die sich an diesen comfort gewohnt haben, will ein analogWrite(Pin, Val) usw. Hochsprache ohne mit Registern, Magic Numbers, bitoperation usw. konfrontiert zu werden.

Wenn du das Benennungsschema nach dem richtest was es bereits gibt, Funktionsnamen, übergabeparameter usw. fragt nicht mal jemand was im Hintergrund abgeht, ob da nun "nop" oder "sackreisumgefallen" in der Funktion steht, nach dem Motto analogWrite ist immer das gleiche analogWrite weil es heißt ja analogWrite. Es guckt keiner genau hin, aber dafür wurde es ja auch so konstruiert, einstiegsfreundlich.

Das war auch mein Anfang. Ein Nano, LCD anstöpseln, library laden und Loslegen. Erst mit dem PY32 kam so richtig Interesse auch "besser" programmieren zu lernen. Gibt wenig librarys, wobei häufig die vom STM32 kompatibel sind. Und wie beim CH32 ein paar unschöne Mankos im core für PY32, also sehr viel weniger, trotzdem doof. (Takt, GPIO usw..)

Das muss gestaltet sein das ein Kind das lernen kann, dann ist es Arduino Nutzer tauglich. ;-)

#8020204
Lesenswert?

Kilo S. schrieb:

library laden und Loslegen.

Das ist genau das Entscheidende: Das Framework muss es ermöglichen, dass Libraries ohne Anpassung einfach laufen.

Außerdem sollten die grundsätzlichen, in der Arduino IDE vorhandenen Beispiel laufen:

blink ( setzt die Definition von LED_BUILTIN voraus )
analogReadSerial ( setzt voraus das analogRead und Serial funktioniert )

Serial.available muss unbedingt für die serielle Steuerung und Datenübertragung funktionieren:
https://docs.arduino.cc/language-reference/de/funktionen/communication/serial/available/

Der I2C-Scanner sollte funktionieren
https://wolles-elektronikkiste.de/en/i2c-scanner

#8020205
Lesenswert?

Kilo S. schrieb:

Das muss im Prinzip wie PHP sein, der normale "Arduino Nutzer" instbesondere diese die sich an diesen comfort gewohnt haben, will ein analogWrite(Pin, Val) usw.

Jetzt habe ich natürlich ein Problem: Ich weiß wie man den Core dazu bringt, dass bspw. analogWrite(Pin, Val); so funktioniert, wie das auch mit einem AVR-Board funktioniert und habe das auch schon gemacht. Es erfordert dann einen Patch des Cores.

Das Problem ist jetzt: Gibt es ein Update des Core's und installiert dieses, ist der Patch dann weg!

Am Beispiel des ADC (analogRead) die Frage, ist folgendes "noch in Ordnung" für einen Arduino-User (die Klasse hat 2 öffentliche Methoden, "read" und "calc_spg") oder sollte tatsächlich der Core gepatcht werden, so dass man nur die analogRead Funktion hat:

1
#include "v003_adc.h"
2

3
// Objekte erzeugen, Konstruktor erwartet GPIO-Pin, auf dem
4
// ein analoger Wert eingelesen wird. Erlaubte Pins sind:
5

6
//                PA2, PA1, PC4, PD2 .. PD6
7
ADC analog1(PD4);
8
ADC analog2(PA1);
9

10
// zum Einlesen einer Spannung (4990 ist die Betriebsspannung in mV als Referenz)dann:
11
  uint16_t val1, val2;
12

13
  val1= analog1.calc_spg(analog1.read(), 4990);
14
  delay(20);
15
  val2= analog1.calc_spg(analog2.read(), 4990);
16
  delay(20);
#8020208
Lesenswert?

Ralph S. schrieb:

Am Beispiel des ADC (analogRead) die Frage, ist folgendes "noch in Ordnung" für einen Arduino-User (die Klasse hat 2 öffentliche Methoden, "read" und "calc_spg") oder sollte tatsächlich der Core gepatcht werden, so dass man nur die analogRead Funktion hat:

1
// PA2, PA1, PC4, PD2 .. PD6
2
ADC analog1(PD4);
3
ADC analog2(PA1);

Hier liegt ein ganz grundlegendes Verständnisproblem vor. Hernando Barragán schreibt auf der zweiten Seite in https://arduinohistory.github.io

1
 Abstracting the microcontroller pins as numbers was, without a doubt, a major decision, possible because the syntax was defined prior to implementation in any hardware platform. All the language command naming and syntax were the result of an exhaustive design process I conducted, which included user testing with students, observation, analysis, adjustment and iteration.

Die Abstrahierten analogen Eingänge heißen bei den Arduino-Boards A0, A1 ..

: Bearbeitet durch User
#8020210
Lesenswert?

Christoph M. schrieb:

blink ( setzt die Definition von LED_BUILTIN voraus ) analogReadSerial ( setzt voraus das analogRead und Serial funktioniert )

Serial.available muss unbedingt für die serielle Steuerung und Datenübertragung funktionieren: https://docs.arduino.cc/language-reference/de/funktionen/communication/serial/available/

Der I2C-Scanner sollte funktionieren https://wolles-elektronikkiste.de/en/i2c-scanner

Genau das alles macht der "offizielle Core" für den CH32V003 nicht, und für LED_BUILTIN muß man wissen, dass Arduino in diesem Core "2" verwendet und dieser als PC0 interpretiert wird. Noch nicht einmal ein Textdisplay unter Verwendung von #include <LiquidCrystal.h> funktioniert (Timingfehler)

#8020213
Lesenswert?

Christoph M. schrieb:

Die Abstrahierten analogen Eingänge heißen bei den Arduino-Boards A0, A1 ..

ich glaube ich werde mich nie daran gewöhnen, bei Arduino die Boardbezeichnungen anstelle der wahren Bezeichnung des Chips zu verwenden. Will man wirklich so weit von der Hardware weg, dass das Teil ein absolut abstraktes Stück Elektronik ist?

Hm, überlege ich, ob meine Library ADC auch um die Arduino-Namen für die GPIO-Pins erweitert wird

#8020234
Lesenswert?

Ralph S. schrieb:

Das Problem ist jetzt: Gibt es ein Update des Core's und installiert dieses, ist der Patch dann weg!

Übermittel die Patches doch per GitHub an WCH bzw. an einen der anderen auf GitHub die einen Core für CH32 bereitstellen. Ich weiß nicht wie weit die den Code pflegen, ob die vorhaben selbst noch was zu machen, so unvollständig kann der aber eigentlich kaum bleiben. Aber letzte Version von WCH direkt ist auch drei Jahre alt. (2023)

#8020249
Lesenswert?

Ralph S. schrieb:

Will man wirklich so weit von der Hardware weg, dass das Teil ein absolut abstraktes Stück Elektronik ist?

Man will:

1
Abstracting the microcontroller pins as numbers was, without a doubt, a major decision, possible because the syntax was defined prior to implementation in any hardware platform.

Das mach sogar STM (wie man im Bild oben für eines der Nucleo-Boards sieht) und es ist auch der Grund warum analogRead(A0) sowohl auf dem Arduinos mit Atmega als auch den STM32 Varianten funktioniert.

Im STM32 Framework selbst gibt es für jede Variante einen eigenen Ordner, in dem die Pins definiert werden:

https://github.com/stm32duino/Arduino_Core_STM32/blob/main/variants/STM32C0xx/C031C(4-6)(T-U)/variant_NUCLEO_C031C6.cpp

Angehängte Dateien:
#8020437
Lesenswert?

Christoph M. schrieb:

Ja, wer schlau ist, will das.

Schade wenn es halt nicht so wirklich klappt.

Ich muss dank Arduino sogar "mehr denken". Das gleiche Problem (Benennung, Parameter, Rückgabewerte) hab ich auch wenn ich Code produzieren möchte der anderen helfen kann.

Beispiel Beitrag "Re: Fumot Tornado 25000 mit LCD -Teardown"

Setzte das dem blutigen Anfänger vor der die IDE vielleicht seit einem Monat benutzt, der wird erst mal Fragezeichen in den Augen haben. Ohne Erklärung kommt der damit vermutlich nicht direkt weiter, schon der Unterschied zwischen der Schreibweise LCD_ (Uppercase!) Zu lcd. (Lowercase) der Standard library. (Hab's getestet! Mein Nachbar, wandelndes Klischee der Arduino Welt. Tutorial kopieren, scheitern, nächstes Tutorial. Das ist ein Loop bis irgendwann der Frust so groß ist das er hin wirft oder zufällig mal ein Versuch klappt.) Das bringt Manche Leute völlig aus dem Konzept.

Lustigerweise, lcd.print, lcd.prinln usw.. kennt der alles! Er war nicht in der Lage aus diesem "Quasistandard" auszubrechen.

Erst als ich ihm erklärt habe das LCD_DrawString theoretisch lcd.println entspricht hat er es halbwegs kapiert.

Klar, ist eines der extremen Beispiele, es gibt in der Arduino Fraktion so viele Facetten, auch Leute die (Guck ich mir ja auch zum Teil so ab) die IDE auch nur als IDE mit kompilerfunktion nutzen. Da wird dann bare Metal oder mit HAL gearbeitet, klappt erstaunlich gut.

Einerseits geiler scheiß, niedriger Einstieg, günstige Hardware, schneller Erfolg.

Andererseits Beihilfe zur aktiven Verdummung!

Alles hat halt gute und schlechte Seiten.

#8021347
Lesenswert?

Veit D. schrieb:

... Da kann man wie gesagt eine Anfrage stellen. Werde ich machen.

Zum Thema Nachfrage wegen der CR Fehlinterpretation der Arduino IDE hat sich ganz schnell geklärt. Dazu gibt es schon "Hunderte" Anfragen, wird alles abgelehnt. Bsp. https://github.com/arduino/arduino-ide/issues/406 Da wird nichts passieren, man muss ein anderes Terminal verwenden. Tera Term und putty funktionieren bspw..

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren