Hi zusammen, ich baue gerade an einer Encoder-Schittstelle fuer LinuxCNC und teste dafuer auch einen Arduino als Konzentrator fuer das Auslesen von Drehwinkelgebern. Diese Teile machen bis zu 2400 Edges/Turn und koennen bis 20kHz arbeiten. http://erste.de/ethraw/readme.de.html Die 20kHz kann ich auch mit einem Arduino in C erfassen. Aber ich muss die Daten ja auch irgendwie loswerden. Das mache ich z.Zt. mit einem Serial.write. Aber dieses Serial.write ist scheinbar noch lahmer als ein digitalRead. Also versuche ich mal, auf direkten IO umzustellen. (ja, ich gebe schon zeichenweise ueber einen Ringbuffer aus) Alternativ koennte ich auch via Ethernet-Shield ausgeben. Das ist aber vermutlich noch langsamer. Oder die Daten ueber ein eigenes 2-Draht-Protokoll rausschieben. Hat jemand hier Erfahrung damit? Oder eine bessere Idee? munter bleiben Wicki
Wicki W. schrieb: > Die 20kHz kann ich auch mit einem Arduino in C erfassen. Mit einem Arduino kannst du bei Programmierung in C problemlos Geber mit 360 Strichen bei 6000 rpm, also 144kHz erfassen - alles eine Frage des passenden Arduinos und der richtigen Nutzung der Hardware.
Wicki W. schrieb: > Hat jemand hier Erfahrung damit? Ein AVR kann 4 Encoder mit bis zu 1 Mio Zusände pro Sekunde auswerten und die Zählerstände (z.B. mit 115kbaud) seriell weiterleiten. Man darf nur nicht in Arduino C++ programmieren, sondern muss Assembler bemühen. http://www.dse-faq.elektronik-kompendium.de/dse-faq.htm#F.29 (man beachte den Begriff loop unroll zum einflechten der Raussendebefehle).
Serial.write muss teilweise darauf warten, dass die Daten abgeschickt werden. Wenn du das oft aufrufst, kann das das Programm bkockieren. Wie hoch ist denn deine Datenrate? Mit C++ hat das natürlich nichts zu tun, auch damit kann man effizie
Womit du die Daten sendest sollte an den Empfänger der Daten angepasst sein. Serielle Schnittstellen kann man problemlos mit 1Mbit (teilweise auch mehr) betreiben. Mit 1Mbit kannst du ca. 25000 Zahlen pro Sekunde übertragen. Wie viele Durchsatz brauchst du denn? Wenn Du deine Anwendung besser beschreibst, können wir Dir vielleicht dabei helfen. Eventuell ist dein Lösungsansatz schlecht und es geht anders sehr viel entspannter.
Mist. ... effiziente Programme schreiben. Man muss aber eben sinnvolle Programm Abläufe bauen, was mit blockierenden Funktionen wie Serial.write kaum geht. Eine ähnlich arbeitende Assembler Funktion hilft da auch nicht wenn sie auf die lahme serielle Schnittstelle warten muss. Das Senden und einlesen der Encoder Signale muss nebenläufig erfolgen.
hey, vielen dank fuer die rueckmeldungen! das hilft mir schon mal weiter, denke ich. Serial.write sollte eigentlich nicht blocken, wenn man nur einzelzeichen nach .avail ausgibt. tut es auch nicht. denn es ist egal, ob ich mit 115200 oder mit 110 baud sende. meine abtastrate bleibt gleich. ich muss gestehen: aus bequemlichkeit (wg. vermeidung zusaetzlicher verkabelung), sende ich mit Serial.write auf der USB-Schnittstelle. (ich weiss, das waere nur eine ader - aber ich brauche auf der anderen seite auch ein empfangsport. und dann sind schon zwei...) ich spiele erst seit einigen wochen mit einem arduino rum und weiss noch nicht, wie er das usb-serial-interface intern handled und ob es ueberhaupt moeglich ist, ein einzelnes zeichen abzusetzen, ohne das die CPU damit laenger als 50usec beschaeftigt ist. ich koennte die frage also abkuerzen auf: kann man mit einem direkten IO den arduino dazu bewegen, dass er ein einzelnes zeichen seriell per usb in einem zeitfenster von 25usec absetzt? (die anderen 25usec brauche ich als "luft" fuer die erfassung der encoder-daten) sicher waere mit ASM noch deutlich schnelleres moeglich. aber zeitkritisch sind die encoder-zaehlerstaende ja nicht. schliesslich muss ich die motoren ja auch beschleunigen und abbremesen. wenn die datentelgramme also im ms-bereich ankommen, dann reicht mir das. alternativ hatte ich auch schon mal dran gedacht, das mit einem PIC zu machen. aber so ein arduino-uno ist einfach "handlicher". (auch wenn ich die IDE/compiler-kombination streckenweise schon aetzend finde und er aus einem sprintf-float einfach kommentar- und fehlermeldunglos nur dreck macht) und wenn das mit usb-seriell geht, dann waere das eine sehr flexible loesung, die mir gut gefallen wuerde.
Wicki W. schrieb: > ich spiele erst seit einigen wochen mit einem arduino rum und > weiss noch nicht, wie er das usb-serial-interface intern handled und > ob es ueberhaupt moeglich ist, ein einzelnes zeichen abzusetzen, > ohne das die CPU damit laenger als 50usec beschaeftigt ist. Mit Einzelzeichenaussendung über USB untergräbst du die vorgesehene Übertragung in Blöcken und erzeugst nur übermäßigen Overhead.
Wolfgang schrieb: > Mit Einzelzeichenaussendung über USB untergräbst du die vorgesehene > Übertragung in Blöcken und erzeugst nur übermäßigen Overhead. Zudem ein PC das einzelne Zeichen nur alle 1ms abholen könnte.
Wicki W. schrieb: > ja, ich gebe schon zeichenweise ueber einen Ringbuffer aus Wie das? Die AVRs (ich nehme an Arduino uno oder nano) haben ein Byte Speicher für den Uart. Bevor das nächste Byte geschrieben wird, muss serial.write warten, bis der Speicher leer ist, sprich das Byte gesendet wird. Normalerweise macht man das mit einem Tx-Interrupt: Alle Daten werden in einen Ringbuffer geschrieben, der Tx-Interrupt wird gestartet. Kommt ein "Uart leer" Interrupt, wird ein Zeichen aus dem Buffer in den Uart gelegt. Der Uart sendet das automatisch raus, ist er fertig kommt wieder ein "Uart leer" Interrupt, nächstes Zeichen aus dem Ringbuffer. Ist der Ringbuffer leer, Interrupt deaktivieren. Das ist wichtig, sonst wird ständig ein "Uart leer" Interrupt ausgelöst. Das dürfte aber nur in C (oder Assembler, oder Pascal), nicht in "Arduinosprache" gehen. Da der Nano / Uno einen ATmega328 ohne USB haben, und die USB Umsetzung durch den FTDI Chip gemacht wird, ist es egal was USB an der Stelle macht. Was Du allerdings vergessen kannst ist Echtzeitfähigkeit über USB: Wann der FTDI das über den Uart empfangene Byte über USB weitersendet ist nicht definiert, und wann Dein OS sagt "Hab da Daten am USB" auch nicht.
Karl K. schrieb: > Da der Nano / Uno einen ATmega328 ohne USB haben, und die USB Umsetzung > durch den FTDI Chip gemacht wird, ist es egal was USB an der Stelle > macht. das war mir nicht klar. macht die sache aber ja eigentlich einfacher. d.h. also: der .write schreibt in jedem fall auf den TX-pin und das arduino-board bastelt das mittel des FTDI in USB um? ich hatte befuerchtet, dass es ein gesondertes handling fuer USB und seriell gibt und es einen unterschied macht, ob ich da oder dort hin schreibe. da ich annehme, dass fuer den ATmega328 der serial-pin auch nur ein register ist, in das man rein schreibt und das umsetzen in ein serielle byte geschieht dann hardwaremaessig, dann frage ich mich, was da bei einem serial.write so lange dauert. aber das habe ich mich bei der digitalRead ja auch gefragt.... ;-) "Zudem ein PC das einzelne Zeichen nur alle 1ms abholen könnte." schreibe zeichenweise, sobald Serial.available ist. um nicht zu bocken. 1x pro 50usec. ein telegramm ist 10 bytes bis 40 lang. also kommen mindestens 500-1000 komplette messungen pro sekunde beim PC an. das reicht mir voellig.
Wicki W. schrieb: > das war mir nicht klar. Aah, dann haat du also keinen Arduino, der sicht per Hardware um die Encoder kümmern kann. Das macht die Sache natürlich mühsamer.
Wicki W. schrieb: > das arduino-board bastelt das mittel des FTDI in USB um? Ja was hast Du denn für ein Board? Uno oder Nano war nur meine Annahme, andere Boards machen das anders. Wicki W. schrieb: > was da bei einem serial.write so lange dauert. Der Pin geht Dich gar nichts an. Wird der Uart aktiviert, übernimmt die Hardware die Steuerung des Pins. Der Uart arbeitet wie ein Fifo. Du schreibst ein Zeichen rein, und sagst senden. Dann übernimmt der Uart das Zeichen aus dem Sendespeicher und schiebt es raus. Sobald das Byte übernommen ist, kannst Du ein zweites Zeichen reinschreiben. Das wird aber erst übernommen, wenn das erste Byte fertig gesendet wurde. Solange ist der Fifo blockiert. Ein drittes Zeichen kannst Du erst in den Fifo schreiben, wenn das erste Zeichen raus ist und das zweite Zeichen übernommen und rausgeschoben wird. Deswegen gehen zwei Zeichen hintereinander schnell, beim dritten hängt es dann. Und da serial.write jetzt warten muss, bis der Fifo wieder frei ist, dauert das so lange. Das bekommst Du nur mit einem Ringbuffer und Interrupt in den Griff. Auch wenns schwerfällt: Hol Dir das Datenblatt vom ATmega328, schau Dir die Sektion USART0 an. Dort wird beschrieben wie das läuft. Wicki W. schrieb: > aber das habe ich mich bei der digitalRead ja auch gefragt Das digital.read prüft auch noch: Ist der Pin Eingang oder Ausgang, und dann kann man den Pin als Variable angeben, die muss für das Abfragen des Registers erst umgerechnet werden (Pinnummer zu Register-Speicherstelle). "Arduinosprache" ist einfach ineffizient, wenn Du es schnell willst, musst Du auf C, Pascal, Assembler zurückgreifen.
leute, ich koennt euch knuddeln ;-) das scheint es gewesen zu sein: statt Serial.write(... schick ich den kram nun mit UDR0 = encs[encoderpointer].out.bts[outpointer-1]; raus. sollte jetzt beliebig viele encoder gleichzeitig mit bis zu 20kHz verarbeiten zu koennen. genug der euphorie... jetzt mal in ruhe testen das ganze. besten dank! und munter bleiben wicki
@Wicki die arduino bibliotheken sind für soetwas unbrauchbar...die ganzen routinen sind auf "einfach" getrimmt und nicht auf performance. mit der hardware ansich ist es realisierbar wenn du bei C oder ASM bleibst... serielle daten schickt man interuptgesteuert über ein fifo raus (asynchron). soetwas können die standard funktionen nicht - diese arbeiten alle blockierend (synchron)
hi karl, danke fuer die infos. dann ist es so, wie ich das erwartete. ist doch prima! (ist ein UNO, uberigens) ich hatte mit schlimmerem gerechnet. Karl K. schrieb: > "Arduinosprache" ist einfach ineffizient, aehhh... was ist eine "Arduinosprache" ? uCs habe ich immer nur in assembler programmiert. dass der arduino C kann, fand ich jetzt nicht so schlecht. auch wenn die implementation etwas gewoehungsbedrueftig ist. ;-) aber wie gesagt: den ersten arduino/atmega hab ich vor rund 4 wochen in die finger bekommen. und soooo tief will ich da auch gar nicht einsteigen, denn so richtig ueberzeugen tut mich das konzept noch nicht.
Wicki W. schrieb: > schick ich den kram nun mit > > UDR0 = encs[encoderpointer].out.bts[outpointer-1]; > > raus. Aba bitte warten bis das voher gesendete Zeichen auch "draussen" ist.
TestX schrieb: > die arduino bibliotheken sind für soetwas unbrauchbar ich glaube, dem kann ich so zustimmen ;-) aber fuer so spielzeugaufgaben (ich drueck n kopf und eine LED geht an) hat er sicher, so wie er ist, eine gewisse daseinsberechtigung.
Wicki W. schrieb: > schreibe zeichenweise, sobald Serial.available ist. um nicht zu > bocken. USB und Serial.Write haben nicht wirklich was miteinander zu tun: USB ist eine blockorientierte Datenübertragung. Es werden also immer Blöcke einer bestimmten Anzahl von Bytes in einem Rutsch übertragen. Auch wenn man also nur ein Byte übertragen will, überträgt USB einen ganzen Block. Und das passiert in einem Zeitraster von 1ms.
Wicki W. schrieb: > was ist eine "Arduinosprache" ? Damit ist der C/C++-"Dialekt" gemeint, der durch die Arduino-Libraries impelementiert wird. Funktionen wie ".write" gibt es in C nicht (in C++ wohl auch nicht). > uCs habe ich immer nur in assembler programmiert. > dass der arduino C kann, fand ich jetzt nicht so schlecht. > auch wenn die implementation etwas gewoehungsbedrueftig ist. ;-) Kann er auch gar nicht. Der Compiler macht aus C Maschinencode, den der Controller dann versteht. > aber wie gesagt: den ersten arduino/atmega hab ich vor rund > 4 wochen in die finger bekommen. > und soooo tief will ich da auch gar nicht einsteigen, denn > so richtig ueberzeugen tut mich das konzept noch nicht. Du kannst auch Arduino-Board per Assembler programmieren. Der verwendete Controller des Boards lässt sich problemlos herausfinden (ist alles dokumentiert). Arduino besteht halt aus einem Gesamtpaket: - Boards, die alle notwendigen Komponenten enthalten, die man für den Btrieb benötigt - eine IDE, die es ermöglicht, die Controller zu programmieren. Es ist eine Astaktionsebene mehr, da man mit diesem System sowohl 8-Bit-AVR, als auch 32-Bit-arm-Controller programmieren kann.
STK500-Besitzer schrieb: >> und soooo tief will ich da auch gar nicht einsteigen, denn >> so richtig ueberzeugen tut mich das konzept noch nicht. > > Du kannst auch Arduino-Board per Assembler programmieren. ja, klar. aber warum mit kanonen auf spatzen schiessen. grundsaetzlich bin ich auch eher fuer ASM statt C. aber es ist halt einfacher zu portieren. und es hing hier ja nur an dem bloeden .write. wenn man die grenzen der hardware nicht ausreizen muss, dann verzichte ich gern aufs anlesen immer wieder neuer register und ASM-dialekte... vor allem, wenn alle paar jahre eine neue CPU rauskommt, die natuerlich viiiiel besser und schneller - und inkompatibel - ist. z80 war geil - aber das waren 6-liter V8-motoren auch mal ;)
STK500-Besitzer schrieb: > Funktionen wie ".write" gibt es in C nicht (in C++ wohl auch nicht). Auch dort kannst du dir eine Funktionen wie ".write" in eine Library packen und benutzen. Das hat Arduino dem Nutzer abgenommen - sonst nichts.
Wolfgang schrieb: > Auch dort kannst du dir eine Funktionen wie ".write" in eine Library > packen und benutzen. Das hat Arduino dem Nutzer abgenommen - sonst > nichts. Sie gehören nicht zum Standard-Sprachumfang von C. Besser?
Wicki W. schrieb: > was ist eine "Arduinosprache" ? Um das jetzt noch mal klar zu sagen: Arduino nutzt ganz normales C++, aber mit einer vordefinierten Bibliothek mit eigenen Funktionen wie eben Serial.write. Arduino in C oder ASM zu programmieren geht mit der Arduino IDE nicht; dazu braucht's z.B. Atmel Studio. Da aber C++ keinen Nachteil gegenüber C hat, kann man auch C++ nehmen. ASM ist für so eine einfache Aufgabe nicht nötig. Wicki W. schrieb: > UDR0 = encs[encoderpointer].out.bts[outpointer-1]; Hoffentlich wartest du vorher/nachher darauf, dass der Puffer auch leer ist, damit du nicht das letzte Byte überschreibst? Dann wird es aber wahrscheinlich genau so langsam wie Serial.write, was ja letztlich genauso funktioniert. Ich nehme mal an, du möchtest dem PC die Anzahl an Schritten oder die aktuelle Position schicken. Als erstes überlegst du dir, wie man das kodiert. Sinnvoll ist es vermutlich, kleine Pakete à 2 Bytes zu schicken, welche entweder die Anzahl an Schritten seit dem letzten Paket, oder die aktuelle Position absenden. Während des Sendevorgangs - d.h. während du darauf wartest, dass der Puffer leer ist - können ja weitere Schritte kommen. Daher solltest du eine Schleife implementieren, in welcher du abfragst ob der Puffer schon leer ist. Wenn ja, sendest du die Anzahl an Schritten seit dem letzten Senden bzw. die aktuelle Position ab. Wenn nicht, prüfst du ob Schritte aufgetreten sind und addierst sie. Das geht vermutlich sogar direkt mit den Serial. -Funktionen. z.B. so in der Art:
1 | int16_t steps = 0; |
2 | while (1) { |
3 | if (Serial.availableForWrite () >= 2) { |
4 | uint8_t buf [2] = { static_cast<uint8_t> (static_cast<uint16_t> (steps) & 0xFF), static_cast<uint8_t> ((static_cast<uint16_t> (steps) >> 8) & 0xFF) }; |
5 | Serial.write (buf, 2); |
6 | steps = 0; // Nur wenn du den Unterschied statt der aktuellen Position schicken möchtest |
7 | }
|
8 | if (... Schritt erkannt ...) { |
9 | if (... rechts ... ) { |
10 | ++steps; |
11 | } else { // links |
12 | --steps; |
13 | }
|
14 | }
|
15 | }
|
So werden beide Aufgaben "gleichzeitig" abgearbeitet, Serial.write sollte schnell genug sein da vorher geprüft wurde ob genug Platz im Puffer ist. Ein Nachteil daran ist, dass eine kleine Latenz entsteht, weil der Puffer wahrscheinlich größer als 2 Bytes ist. Das kann man mit der "Serial" Klasse anscheinend nicht wirklich umgehen. Eine Möglichkeit mit direktem Register-Zugriff wäre:
1 | int16_t steps = 0; |
2 | uint8_t sendState = 0; |
3 | uint8_t nextByte; |
4 | while (1) { |
5 | // Hardware-Puffer leer?
|
6 | if (UCSR0A & (1 << UDRE0)) { |
7 | if (sendState == 0) { |
8 | nextByte = static_cast<uint8_t> ((static_cast<uint16_t> (steps) >> 8) & 0xFF); |
9 | UDR0 = static_cast<uint8_t> (static_cast<uint16_t> (steps) & 0xFF); |
10 | |
11 | steps = 0; // Nur wenn du den Unterschied statt der aktuellen Position schicken möchtest |
12 | sendState = 1; |
13 | } else { |
14 | UDR0 = nextByte; |
15 | sendState = 0; |
16 | }
|
17 | }
|
18 | if (... Schritt erkannt ...) { |
19 | if (... rechts ... ) { |
20 | ++steps; |
21 | } else { // links |
22 | --steps; |
23 | }
|
24 | }
|
25 | }
|
So wird ebenfalls gesendet sobald möglich und die restliche Zeit Schritte gezählt. In nextByte wird das nächste Byte gespeichert, weil ja nach dem Senden des 0. bytes sich der Zähler wieder ändern kann. Das Paketformat ist im Beispiel jeweils Little Endian, das kann man je nach Bedarf ändern. Ist in C++, nicht getestet, sollte aber prinzipiell funktionieren. Schöner wäre es noch mit Interrupts, das ist dann Schritt 2. Können die Timer des AVR's selbständig Encoder einlesen? Manche Controller können das, dann spart man sich die Schleife ganz und kann es komplett in Interrupts machen.
Dr. Sommer schrieb: > Hoffentlich wartest du vorher/nachher darauf, dass der Puffer auch leer > ist, damit du nicht das letzte Byte überschreibst? Dann wird es aber > wahrscheinlich genau so langsam wie Serial.write, was ja letztlich > genauso funktioniert. danke fuer das ausfuehrliche statement. aber natuerlich sehe ich vorher nach ob platz ist. und UDR0 = encs[encoderpointer].out.bts[outpointer-1]; ist um ein vielfaches schneller als Serial.write. ich hab mich nicht bis in die unterste ebene reingewuehlt, aber allein schon die wilde bufferrumschieberei vorher und die vielen calls und jumps kosten zeit. zeit, die ich fuer wichtigere dinge brauche. btw: wie sollen timer einen encoder einlesen koennen? und interrupts: wenn ich das richtig verstanden habe, dann kann ich nicht auf 8 leitungen ISRs einrichten. pollen klappt bislang gut.
:
Bearbeitet durch User
Wicki W. schrieb: > ist um ein vielfaches schneller als Serial.write. Leider kann man ja nicht abfragen ob der Sendepuffer leer ist, sonst ginge das wohl besser. Wicki W. schrieb: > btw: wie sollen timer einen encoder einlesen koennen? Wenn das ein normales "A/B"-Encoder-Signal ist, indem die Input Capture Einheit die Flanken zählt und die beiden Kanäle vergleicht. Die STM32 können das, bei AVR weiß ich nicht. Wicki W. schrieb: > und interrupts: wenn ich das richtig verstanden habe, dann > kann ich nicht auf 8 leitungen ISRs einrichten. Die alten AVR können IIRC nur 2, aber neuere können mehr. Musst du mal selber raussuchen. Man hat dann nur 1 ISR, in der man prüfen muss, auf welchen Kanälen sich was getan hat. Für den UART kann man auf jeden Fall einen Interrupt benutzen.
Wicki W. schrieb: > leute, ich koennt euch knuddeln ;-) > > das scheint es gewesen zu sein: > > statt > > Serial.write(... > > schick ich den kram nun mit > > UDR0 = encs[encoderpointer].out.bts[outpointer-1]; > > raus. > > sollte jetzt beliebig viele encoder gleichzeitig mit bis > zu 20kHz verarbeiten zu koennen. Schwachsinn. Nicht ist beliebige viel! Beitrag "Re: Versetzte Rechtecksignale auswerten, kein drehgeber"
Falk B. schrieb: >> sollte jetzt beliebig viele encoder gleichzeitig mit bis >> zu 20kHz verarbeiten zu koennen. > > Schwachsinn. Nicht ist beliebige viel! > > Beitrag "Re: Versetzte Rechtecksignale auswerten, kein drehgeber" wenn du unbedingt korinthen kacken moechtest: 4 stueck geht zur zeit. 8 sollten auch noch gehen. wieviele genau, muesste ich ausprobieren oder ausrechnen. so viel, wie ich signale in 50(bzw. 25)usec verarbeiten kann. in ASM ginge vermutlich mehr. aber mehr als 4 encoder braucht (m)eine "normale" maschine nicht.
STK500-Besitzer schrieb: > Sie gehören nicht zum Standard-Sprachumfang von C. Besser? Wenn man sich beim Programmieren einzig auf Funktionen aus dem Standard-Sprachumfang von C beschränkt, ist man allerdings wahrlich arm dran. Dr. Sommer schrieb: > Wenn das ein normales "A/B"-Encoder-Signal ist, indem die Input Capture > Einheit die Flanken zählt und die beiden Kanäle vergleicht. Warum überlässt man die Zählerei nicht direkt der Hardware und holt sich bei Bedarf nur den Zählerstand aus dem Counter-Register?
Wolfgang schrieb: > Warum überlässt man die Zählerei nicht direkt der Hardware und holt sich > bei Bedarf nur den Zählerstand aus dem Counter-Register? weil es mit einfachem zaehlen nicht getan ist. man muss auch wissen, ob man vorwaerts oder rueckwaerts zaehlt. und das ergibt sich erst aus dem zeitzversatz von 2 signalen. ich hatte ja auch gedacht, es gibt dafuer schon einen fertigen chip, der das kann - aber scheinbar gibts den nicht oder er ist selten und dann vermutlich exorbitant teuer. jedenfalls kann ich jetzt 2 encoder 1600/2400 flanken/turn mechanisch gekoppelt gemeinsam drehen und lande beim zurueck drehen mit beiden zugleich wieder bei den gleichen werten. mehr wollte ich ja erst mal gar nicht.
Wicki W. schrieb: > Wolfgang schrieb: >> Warum überlässt man die Zählerei nicht direkt der Hardware und holt sich >> bei Bedarf nur den Zählerstand aus dem Counter-Register? > > weil es mit einfachem zaehlen nicht getan ist. > man muss auch wissen, ob man vorwaerts oder rueckwaerts zaehlt. > und das ergibt sich erst aus dem zeitzversatz von 2 signalen. Stimmt, aber es gibt viele Controller, die können das in Hardware. > ich hatte ja auch gedacht, es gibt dafuer schon einen fertigen > chip, der das kann - aber scheinbar gibts den nicht oder > er ist selten und dann vermutlich exorbitant teuer. Nö, die meisten moderneren als STM32, ATXmega und viele andere können das. > mehr wollte ich ja erst mal gar nicht. Gut!
Wolfgang schrieb: > Warum überlässt man die Zählerei nicht direkt der Hardware und holt sich > bei Bedarf nur den Zählerstand aus dem Counter-Register? Genau das kann die Hardware von STM32. Wenn man sich natürlich unbedingt auf einen ollen AVR beschränken will... Wicki W. schrieb: > man muss auch wissen, ob man vorwaerts oder rueckwaerts zaehlt. ... Das auch. Es wird je nach Richtung inkrementiert und dekrementiert. Zitat aus dem RefMan: In this mode, the counter is modified automatically following the speed and the direction of the incremental encoder and its content, therefore, always represents the encoder’s position. The count direction correspond to the rotation direction of the connected sensor. An external incremental encoder can be connected directly to the MCU without external interface logic. Diagramm aus dem Manual im Anhang.
Wolfgang schrieb: > Wenn man sich beim Programmieren einzig auf Funktionen aus dem > Standard-Sprachumfang von C beschränkt, ist man allerdings wahrlich arm > dran. Deswegen ist es die "Arduino-Sprache", die eine Erweiterung von C/C++ ist.
STK500-Besitzer schrieb: > Deswegen ist es die "Arduino-Sprache", die eine Erweiterung von C/C++ > ist. "C/C++" gibt es nicht. Das sind zwei verschiedene Sprachen. Arduino ist C++ und nicht C. Welche Sprachelemente (d.h. nicht einfach nur Bibliotheksfunktionen) wurden denn gegenüber normalem C++ hinzugefügt?
Arduino ist keine Erweiterung von C++, sondern eine
Entwicklungsumgebung+Hardware+Libraries die in C++ geschrieben wurden.
Der Sprachumfang, der auf der Webseite von Arduino beschrieben ist, ist
eine Untermenge von C++ - das ist das Gegenteil einer Erweiterung.
> "C/C++" gibt es nicht.
Ich betrachte C++ als objektorientierten Zusatz zur Sprache C. Für mich
enthält C++ die Sprache C fast vollständig, deswegen halte ich "C/C++"
für einen gültigen Begriff.
Stefanus F. schrieb: > Ich betrachte C++ als objektorientierten Zusatz zur Sprache C. C++ hat halt noch viel mehr als nur ein bisschen OOP. Daher ist das eine sehr einseitige Betrachtung.
Dr. Sommer schrieb: > C++ hat halt noch viel mehr als nur ein bisschen OOP. > Daher ist das eine sehr einseitige Betrachtung. Korrekt, aber Objekte sind der Kern der Sache. Alles kann mehr als seine Hauptaufgabe. Mein Auto kann mehr, als nur zu fahren und mit Messern kann man mehr tun, als nur zu schneiden. Hier alle Funktionen von C und C++ aufzulisten, wäre unpassend.
Stefanus F. schrieb: > Korrekt, aber Objekte sind der Kern der Sache. Keineswegs. Exceptions, templates, "constexpr", Lambdas sind alle unabhängig von OOP. C++ ist eine Multi-Paradigmen-Sprache, und OOP ist nur eins davon, und nicht das Zentrale. Andere Sprachen konzentrieren sich mehr auf OOP und können das teilweise auch besser (z.B. Java).
Wicki W. schrieb: > weil es mit einfachem zaehlen nicht getan ist. > man muss auch wissen, ob man vorwaerts oder rueckwaerts zaehlt. > und das ergibt sich erst aus dem zeitzversatz von 2 signalen. Eben, da ein passender Arduino das per Hardware kann, wäre es doch unsinnig, das per Software zu machen, um die Hardware zu schon.
>> Korrekt, aber Objekte sind der Kern der Sache. Dr. Sommer schrieb: > Keineswegs Schauen wir mal was der Chef (Bjarne Stroustrup) in seinem Buch "The C++ Programming Language" dazu schrieb: "C++ is a general purpose programming language designed to make programming more enjoyable for the serious programmer. Except for minor details, C++ is a superset of the C programming language. In addition to the facilities provided by C, C++ provides flexible and efficient facilities for defining new types...Objects of some user-defined types contain type information...The key concept in C++ is class. A class is a user-defined type." Mit diesen Worten leitet er sein Buch ein, dass die Programmiersprache erklärt. Ich wiederhole mich daher gerne: Objekte sind der Kern der Sache.
Dr. Sommer schrieb: > Genau das kann die Hardware von STM32. Wenn man sich natürlich unbedingt > auf einen ollen AVR beschränken will... Und für wie viele Encoder gleichzeitig?
Stefanus F. schrieb: > Ich wiederhole mich daher gerne: Objekte sind der Kern der Sache. Okay. Stefanus F. schrieb: > Ich betrachte C++ als objektorientierten Zusatz zur Sprache C. Es ist aber eben nicht nur ein Zusatz. Es ist eine neue Sprache. Stefanus F. schrieb: > deswegen halte ich "C/C++" > für einen gültigen Begriff. Wofür überhaupt? Für eine hypothetische Sprache die alles von C und C++ vereint? Für die Summe der Sprachelemente von C und C++? Einfach nur die Menge beider Sprachen? Karl K. schrieb: > Und für wie viele Encoder gleichzeitig? Hängt vom Controller ab. Ohne jetzt detailliert nachzusehen dürften es bei den größeren ca. 10 sein.
Stefanus F. schrieb: > Schauen wir mal was der Chef (Bjarne Stroustrup) in seinem Buch "The C++ > Programming Language" dazu schrieb: Er schreibt da aber auch: I wince when someone characterizes C++ exclusively through one of these styles (e.g., ‘‘C++ is an object-oriented language’’). From its inception, the design of C++ aimed at a synthesis of programming and design styles. Außerdem: http://www.stroustrup.com/bs_faq.html#C-slash What do you think of C/C++? No that's not really a question I often get. In that sense, it is the only "fake FAQ" in this FAQ. However, it ought to be a FAQ because people use "C/C++" as if it meant something specific and as if they knew what it meant, leading to much confusion and misery. People should ask "What is C/C++?" and then on reflection stop using the term. It does harm. There is no language called "C/C++". The phrase is usually used by people who don't have a clue about programming (e.g. HR personnel and poor managers). Alternatively, it's used by people who simple do not know C++ (and often not C either). When used by programmers, it typically indicates a "C++ is C with a few useful and a lot of useless complicated features added" attitude. Often, that is the point of view of people who like to write their own strings and hash tables with little knowledge of the standard library beyond printf and memcpy. There are people who stick to a restricted subset of C++ for perfectly good reasons, but they (as far as I have noticed) are not the people who say "C/C++".
Karl K. schrieb: >> Genau das kann die Hardware von STM32. Wenn man sich natürlich unbedingt >> auf einen ollen AVR beschränken will... > > Und für wie viele Encoder gleichzeitig? ohne nachgesehen zu haben, wuerde ich jetzt erwarten, dass man das mit jedem eingang(spaar) wahlweise machen kann. insgesamt klingt die beschreibung aber schon recht spannend.
Wicki W. schrieb: > ohne nachgesehen zu haben, wuerde ich jetzt erwarten, dass > man das mit jedem eingang(spaar) wahlweise machen kann. Leider nein. Das geht immer nur mit Channel 1+2 eines Timers für die A&B-Eingänge. Bei 4-Kanal-Timern kann man die anderen beiden Channels dann nicht benutzen. Pro Kanal hat man meistens die Wahl zwischen 1-2 damit zu verbindenden Pins. Habe mal nachgesehen; bei den beliebten STM32F407 sind es doch nur 6 Kanäle, denn TIM9-14 haben leider überhaupt keinen Encoder-Modus.
STK500-Besitzer schrieb: > Funktionen wie ".write" gibt es in C nicht (in C++ wohl auch nicht). Das ist eine Methode, keine Funktion. Und dass es in keinen anderen C++ Programmen write() Methoden gibt ist Unfug. Bei Arduino gilt: Serial erbt von Stream, und Stream von Print. So kommt dann auch Serial zu einem ganzen Büschel an verschiedenen write() und print() Methoden. Stefanus F. schrieb: > Ich betrachte C++ als objektorientierten Zusatz zur Sprache C. Für mich > enthält C++ die Sprache C fast vollständig, deswegen halte ich "C/C++" > für einen gültigen Begriff. Kannst du machen... Ist aber Schwachfug. Damit bescheißt du dich nur selber, und andere gleich mit. Sie haben gemeinsame Wurzeln. Sind sich recht ähnlich, bei oberflächlicher Betrachtung. Mehr aber auch nicht. Stefanus F. schrieb: > Der Sprachumfang, der auf der Webseite von Arduino beschrieben ist, ist > eine Untermenge von C++ - das ist das Gegenteil einer Erweiterung. Auch eher unwahr... Ja, in der Arduino Doku findet sich keine Kopie der C++ Doku. Die Arduino Doku kümmert sich eher um die eigenen Libs/Framework. Natürlich kann der AVR-GCC den vollen C++ Sprachumfang. Und dieser steht bis auf Kleinigkeiten wie Exceptions und STL für Arduino AVR zu Verfügung. Für ESP/ARM usw. gehen auch Exceptions und STL Manche C++ Features machen eben auf den kleinen 8Bittern selten Sinn. z.B die dynamische Speicherverwaltung, welche für die STL wohl unerlässlich ist Dr. Sommer schrieb: > Leider kann man ja nicht abfragen ob der Sendepuffer leer ist, sonst > ginge das wohl besser. Natürlich geht das! Zumindest kann man fragen, wieviel Platz noch ist. https://www.arduino.cc/reference/en/language/functions/communication/serial/availableforwrite/ Wicki W. schrieb: > ist um ein vielfaches schneller als Serial.write. Naja... Vermutlich schon... Allerdings füllen Serial.printe und write einen Ringpuffer, welcher dann per ISR geleert wird. Sowas wirst du dann per Hand bauen müssen. Und dann ist der Unterschied schon gar nicht mehr so groß. Wicki W. schrieb: > uCs habe ich immer nur in assembler programmiert. > dass der arduino C kann, fand ich jetzt nicht so schlecht. > auch wenn die implementation etwas gewoehungsbedrueftig ist. ;-) Arduino ist C++, hauptsächlich. Die *.ino ist immer C++. C geht auch, in eigenen Übersetzungseinheiten. Auch Assembler in Librarys ist nicht ganz unüblich. Dr. Sommer schrieb: > was mit blockierenden Funktionen wie > Serial.write kaum geht. Was soll es tun, wenn der Sende Puffer voll ist? Daten verwerfen? Dann doch besser warten/blockieren. Und wem das warten nicht passt, der kann Serial fragen, ob noch Platz im Buffer ist. Dr. Sommer schrieb: > Eine ähnlich arbeitende Assembler Funktion hilft > da auch nicht wenn sie auf die lahme serielle Schnittstelle warten muss. Das ist ein ganz wichtiger und quasi unabwendbarer Punkt. ------------ Anmerkungen: Ich habe nichts dagegen, wenn einer Arduino nicht mag. Werde auch nimmer Werbung dafür machen. Es ist mir echt scheißegal, ob es genutzt wird oder wer es nutzt, und auch wer es nicht nutzen will. Aber liebster "Stefanus F. (stefanus)" was du hier machst, ist ganz klares Arduino Bashing. Und dass andauernd hier im Forum, bei jeder möglichen Gelegenheit. Gespickt mit Unwissen, Täuschungen, ja, ich möchte sagen: Lügen. Und da ich dir das schon mal so, oder so ähnlich gesagt habe, nenne ich das bewusstes lügen. Lügen mit voller Absicht. Was möchtest du damit erreichen? Tipp: Mit deinem fachlichen Wissen, kannst du glänzen. Machst du auch oft. Weiter so! Aber im täuschen/bashen, bist du eher schlecht und offensichtlich.
Arduino Fanboy D. schrieb: > Aber liebster "Stefanus F. (stefanus)" was du hier machst, ist ganz > klares Arduino Bashing. Und dass andauernd hier im Forum, bei jeder > möglichen Gelegenheit. Ich bin sehr erstaunt über diese unzutreffende Schlussfolgerung. Falls es Dir entgangen ist: Ich empfehle Arduino oft und nutze es selbst.
Arduino Fanboy D. schrieb: > Zumindest kann man fragen, wieviel Platz noch ist. > https://www.arduino.cc/reference/en/language/functions/communication/serial/availableforwrite/ Das hab ich schon vorher bemerkt, wie du an meinen Code-Beispielen gesehen hast. Das Ziel war aber, abzufragen, ob der Puffer leer ist und per .write abgeschickte Daten somit sofort abgesendet werden können. Arduino Fanboy D. schrieb: > Und wem das warten nicht passt, der kann Serial fragen, ob noch Platz im > Buffer ist. Genau das sage ich doch... Thread lesen. Statt .write warten zu lassen, den Encoder einlesen, und erst dann .write aufrufen, wenn man weiß, dass es nicht blockiert. Perfekt wäre, es erst dann aufzurufen, wenn man weiß, dass auch sofort abgesendet wird - was nicht zu gehen scheint.
Stefanus F. schrieb: > unzutreffende Schlussfolgerung Dann sage mir doch bitte, warum du so agierst. Vielleicht kann ich ja dann Verständnis für dich entwickeln. So fällt mir das echt schwer. ------------- Dr. Sommer schrieb: > Das hab ich schon vorher bemerkt, wie du an meinen Code-Beispielen > gesehen hast. Ich habe hier keine Code Beispiel gesehen. In diesem Thread habe ich leider nur gesehen, dass du zweimal sagtest dass es nicht geht. Falls ich mich irre, was übersehen habe, bitte ich dich untertänigst um Verzeihung. Dr. Sommer schrieb: > Perfekt wäre, es erst dann aufzurufen, wenn man > weiß, dass auch sofort abgesendet wird - was nicht zu gehen scheint. Serial schreibt in einen Puffer, und dieser wird per ISR geleert. Das ist nicht "direkt", aber meist besser, als "direkt" ohne Buffer. Die Größe des Ringbuffers ist keine Geheimnis. Auch kann man zu Anfang fragen, wie viel Platz ist, so bekommt man einen Vergleichswert, der einem ermöglicht, dafür Sorge zu tragen, dass sofort gesendet wird.
> Dann sage mir doch bitte, warum du so agierst.
Ich agiere nicht so. Du hast da etwas hinein interpretiert, dass ich
nicht aussagen wollte. So etwas passiert, wenn man andere Leute in
falsche Schubladen steckt und dann im Kopf nur noch nach Bestätigungen
dafür sucht.
Wirklich, ich habe hier Arduino überhaupt gar nicht herab gewürdigt. Das
bildest Du Dir nur ein.
Stefanus F. schrieb: > Arduino ist keine Erweiterung von C++, sondern eine > Entwicklungsumgebung+Hardware+Libraries die in C++ geschrieben wurden. Die Entwicklungsumgebung ist in Java geschrieben. Der Größte Teil des Hardwarespezifischen Codes in C Ein winziger Teil in Assembler. Erst die Libraries sind größtenteils in C++. Aber auch viele in C Und wenige Teile in Assembler. Stefanus F. schrieb: > Der Sprachumfang, der auf der Webseite von Arduino beschrieben ist, ist > eine Untermenge von C++ - das ist das Gegenteil einer Erweiterung. Wenn ich etwas missverstanden haben sollte, dann dieses... Denn diese Darstellung des "Gegenteil" halte ich für sehr verdreht, irrational. Arduino nutzt für AVRs die übliche AVR-Gcc Toolchain. Das meiste, was in der Arduino Doku beschrieben wird, sind Erweiterungen/Libraries. Es ist gar nicht Ziel, die C++ Doku zu kopieren. Die muss man sich an anderer Stelle suchen.
Arduino Fanboy D. schrieb: > Wenn ich etwas missverstanden haben sollte, dann dieses... Ok, dann kläre ich Dich auf: Ich halte es für gute Idee, Anfänger nicht gleich mit allen komplexen Details einer Programmiersprache zu konfrontieren. Der Erfolg des Systems bestätigt meiner Meinung nach, dass diese Methode gut ist.
Ja danke, dass ihr den Thread mit euren C/C++ Gelaber zugemüllt habt. Ist jetzt mal wieder gut? Arduino Fanboy D. schrieb: > Allerdings füllen Serial.printe und write einen Ringpuffer, welcher dann > per ISR geleert wird. Das träumst Du. "As of Arduino IDE 1.0, serial transmission is asynchronous. If there is enough empty space in the transmit buffer, Serial.write() will return before any characters are transmitted over serial. If the transmit buffer is full then Serial.write() will block until there is enough space in the buffer." Der "transmit buffer" ist genau der 2-Byte-Fifo, den ich oben beschrieben habe.
Karl K. schrieb: > Der "transmit buffer" ist genau der 2-Byte-Fifo, den ich oben > beschrieben habe. Für die üblichen AVR Arduinos gilt: #define SERIAL_TX_BUFFER_SIZE 64 Siehe: https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/HardwareSerial.h https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/HardwareSerial.cpp https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/HardwareSerial0.cpp Alles da Ringbuffer, ISR ... Karl K. schrieb: > Das träumst Du. Wer träumt?
Arduino Fanboy D. schrieb: > Ich habe hier keine Code Beispiel gesehen. Beitrag "Re: Rotary-Encoder mit Arduino als Konzentrator" > Dr. Sommer schrieb: >> Perfekt wäre, es erst dann aufzurufen, wenn man >> weiß, dass auch sofort abgesendet wird - was nicht zu gehen scheint. > Serial schreibt in einen Puffer, und dieser wird per ISR geleert. > Das ist nicht "direkt", aber meist besser, als "direkt" ohne Buffer. Das erste Byte wird sofort abgesendet. Wenn der Sendepuffer des UART schon leer ist, kommt schließlich keine weitere ISR mehr.
Arduino Fanboy D. schrieb: > Alles da Ringbuffer, ISR ... Ach, Du weisst, dass er die HardwareSerial Lib nimmt? Woher kommen dann die Verzögerungen beim Senden?
Dr. Sommer schrieb: > Arduino Fanboy D. schrieb: >> Ich habe hier keine Code Beispiel gesehen. > > Beitrag "Re: Rotary-Encoder mit Arduino als Konzentrator" Ich bitte untertänigst um Verzeihung. Ja, es steht in deinem Code! Dr. Sommer schrieb: > Das erste Byte wird sofort abgesendet. Ein Byte kommt selten alleine... Sie neigen etwas zur Rudelbildung.. ;-) ------------ Karl K. schrieb: > Ach, Du weisst, dass er die HardwareSerial Lib nimmt? Weil er dieses sagt: Wicki W. schrieb: > Serial.write Oder sollte ich mich auch da irren? Karl K. schrieb: > Woher kommen dann > die Verzögerungen beim Senden? Wenn der Ringbuffer voll ist, dann blockiert write(). Sonst ist es ;-) "rasend" ;-) schnell. Und wie man die Blockade vermeidet, haben wir hier schon geklärt.
Dr. Sommer schrieb: > Perfekt wäre, es erst dann aufzurufen, wenn man > weiß, dass auch sofort abgesendet wird - was nicht zu gehen scheint. doch - das geht. aber das .write ist zu langsam. weil zu grosser overhead. direkter port/register-IO ist um ein vielfaches schneller. und die IDE und die seltsame c-implementation ist schon ein ziemlicher scheiss. (es gibt aber noch viel schlimmere) aber fuer so ein kleines und billiges (preiswertes) teil ist das voll OK. ich fahre ja auch nicht mit ner caterpillar D6 n bruehwuerfel holen ;-) fuer die encoder-erfassung ist ein raspi schon zu fett. und wg. der 3.3v-level auch zu kaputtbar.
Wicki W. schrieb: > aber das .write ist zu langsam. > weil zu grosser overhead. Laut obiger HardwareSerial wird da das Zeichen ein den Fifo gelegt und das Senden angestoßen. Wenn Buffer leer, wird der Interrupt abgegeschaltet. Was anderes mache ich in meiner Routine auch nicht. Also steht zu vermuten, dass "Dein" serial.write nicht die obige HardwareSerial nutzt. Es mag ja für den Anfänger ganz nett sein, sie nicht mit solchen Details zu verwirren, aber wenn man die AVRs wirklich nutzen will, ist die "Obfuskation" beim Arduino eher nervig.
Karl K. schrieb: > Also steht zu > vermuten, dass "Dein" serial.write nicht die obige HardwareSerial nutzt. Viele Alternativen gibts da bei den AVR Arduinos nicht. Serial ist eine "globale" Instanz. Entweder von HardwareSerial, oder USB Serial_ (z.B. beim 32U4). Dann ist Ende. Mehr Möglichkeiten gibts nicht. Serial kann nicht von einem User, einfach so, anders implementiert werden. Nicht ohne tiefe Eingriffe. Karl K. schrieb: > "Obfuskation" Unterstellt eine Absicht. Diese sehe ich nicht. Verwirrung entsteht im Kopf des Betrachters.
Arduino Fanboy D. schrieb: > Viele Alternativen gibts da bei den AVR Arduinos nicht. > Serial ist eine "globale" Instanz. > Entweder von HardwareSerial, oder über USB(z.B. beim 32U4). > Dann ist Ende. > Mehr Möglichkeiten gibts nicht. Serial per HardwareSerial gabs aber "früher" nicht, eine alte Version zu verwenden wäre also eine ganz einfache Möglichkeit, damit auf die Schnauze zu fliegen. Da ich mich aber bei der Versionierung der Arduino-IDE nicht auskenne, weiss ich a) nicht seit wann das auf HardwareSerial umgestellt wurde und b) wo man gerade bei den Versionen ist.
Karl K. schrieb: > Da ich mich aber bei der Versionierung der Arduino-IDE nicht auskenne, > weiss ich a) nicht seit wann das auf HardwareSerial umgestellt wurde und > b) wo man gerade bei den Versionen ist. Faszinierend wie "man" sich da um Kopf und Kragen redet. Bloss um keinen Preis der Welt zugeben dass man vielleicht nicht recht haben könnte .... bis zum letzten Atemzug.
Wicki W. schrieb: > und die IDE und die seltsame c-implementation ist schon ein > ziemlicher scheiss Die Implementation ist der GCC, also neben Clang so ziemlich die beste auf dem Markt. Oder was bist du da normalerweise gewohnt? Der hauptsächliche Overhead von .write dürfte der Funktionsaufruf und das Kopieren sein. Dadurch ist write nicht automatisch schlecht; es kann halt nur etwas was du gar nicht brauchst (Puffer).
Arduino Fanboy D. schrieb: > Viele Alternativen gibts da bei den AVR Arduinos nicht. > Serial ist eine "globale" Instanz. > Entweder von HardwareSerial, oder USB Serial_ (z.B. beim 32U4). > Dann ist Ende. > Mehr Möglichkeiten gibts nicht. > Serial kann nicht von einem User, einfach so, anders implementiert > werden. > Nicht ohne tiefe Eingriffe. entschuldige, aber das ist nicht richtig. wie im verlauf dieses threads zu sehen ist: UDR0 = irgendeinbyte; schreibt direkt in den fifo-buffer und man ist das teil los. 1 maschinenzyklus, wuerde ich sagen. klar muss man sich selbst drum kuemmern, dass man nicht mehr rein schiebt als er in dem zeifenster auch absetzen kann. aber darum ging es ja gar nicht. es ging nur darum, in moeglichst kurzer zeit ein zeichen an den fifo loszuwerden. das ist alles was ich wollte. mission accomplished ;-)
Dr. Sommer schrieb: > Oder was bist du da normalerweise gewohnt? wir treten hier sinnfrei auf der stelle.... aber was ich z.b. gewohnt bin, ist das ein sprintf(x,"%10.3f",val) in x einen druckbaren string liefert. der arduino-compiler liefert aber einen scheiss. und zwar ohne die meldung, dass er so etwas nicht umsetzen kann. ich habe aufgehoert, nach dem fehler zu suchen und zu eruieren, was denn genau im string steht. nachdem ich diese hinweise gefunden habe: ----------- Leider funktioniert die sprintf-Funktion unter Arduino NICHT mit float/double Fließkommazahlen. Man könnte sich behelfen, eine Fließkommazahl erst mit dtostrf in ein char-Array zu packen und danach noch mit sprintf als String auszugeben. ------------ und mir dann nur gedacht: sonst schmeisst einen dieser zeh-compiler inflationaer mit errors und warnings zu - aber sowas erkennt er nicht als fehler? sorry, aber das ist eine scheiss-implementation. vor allem, wenn man das nicht weiss.
OMG schrieb: > Bloss um keinen Preis der Welt zugeben... Du hast eine plausible Erklärung, warum ein Uart mit Ringbuffer und Interrupt das Programm ausbremsen sollte?
Wicki W. schrieb: > Leider funktioniert die sprintf-Funktion unter Arduino NICHT mit > float/double Fließkommazahlen. Das hat aber nichts mit Arduino zu tun sondern mit der verwendeten AVR Toolchain. s.ua.: https://blog.startingelectronics.com/floating-point-numbers-dont-print-sprintf-atmel-studio-avr-c/ "The problem occurs because Atmel Studio 7 uses the minimal version of the function that all the printf family of functions rely on. Using the minimal function reduces code size ..." Ist halt eine andere Bibliothek Funktion, nicht der GCC, nicht Arduino. leo
Wicki W. schrieb: > und mir dann nur gedacht: sonst schmeisst einen dieser zeh-compiler > inflationaer mit errors und warnings zu - aber sowas erkennt er nicht > als fehler? Der Compiler produziert nur einen Funktionsaufruf an die printf-Funktion. Was da drin steht, kann er nicht sehen. Man kann float-printf aber aktivieren: https://www.mikrocontroller.net/articles/FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_bei_WinAVR_bzw_AVR-Studio Hat 1 Minute Google gekostet. wie lange hast du gesucht? Kostet natürlich mehr Speicher. Ob man das wirklich braucht ist noch die Frage. Bei Arduino kann man die Linker-Optionen nicht einstellen, dafür müsste man auf Atmel Studio umstellen. Wicki W. schrieb: > sorry, aber das ist eine scheiss-implementation. > vor allem, wenn man das nicht weiss. Wäre es eine gute Implementation, wenn sie standardmäßig den Programmspeicher mit Funktionalität vollkloppt, die nur selten gebraucht wird? Leider ist es unmöglich, sicher festzustellen, ob nicht irgendwo im Programm printf mit float mit "%f" aufgerufen wird - schließlich kann der Format-String ja auch zur Laufzeit geladen werden.
Dr. Sommer schrieb: > Hat 1 Minute Google gekostet. wie lange hast du gesucht? LOL. Genau das habe ich auch gedacht (weil ebenso lange gesucht). Der TO hat mehr Zeit fuer rummotzen verwendet als fur die Loesung des Problems. leo
wie gesagt: sinnfreie diskussion.... ich habe lediglich beilaeufig erwaehnt, dass ich die ide scheisse finde. und wenn man ein neu entwickeltes numerisches display auf einer neuen hardware mit einer neuen ide mit einem string ansteuert, der nur aus ziffern bestehen sollte, dann sucht den fehler erst mal im eigenen code oder in der hardware. oder sonstwo. (und "neu" heisst in diesem fall: zuvor noch nie in den fingern gehabt) dass ein sprinf undefinierten scheiss liefert, das erwartet man zuletzt. "ja, der elektrische fensterheber in ihrem neuen tesla, der funktioniert so, wie sie es gewohnt sind. wenn sie allerdings bei 3/4-neumond das fenster zu 2 dritteln oeffnen, dann geht der motor aus. steht auf seite 347 im nanual - und bei google" und nun ist die diskussion um dieses thema fuer mich beendet. ich bin raus. munter bleiben wicki
Dr. Sommer schrieb: > Bei Arduino kann man die Linker-Optionen nicht einstellen, dafür > müsste man auf Atmel Studio umstellen. Natürlich kann man das auch mit/in der Arduino IDE Dazu muss man allerdings die Plattform Definition erweitern. Also eine platform.local.txt mit den passenden Einträgen anlegen. Bei diesem Beispiel, die gewünschte Zeile aktivieren
1 | # erlaubt float in sprintf und seinen Brüdern.
|
2 | #compiler.c.elf.extra_flags=-Wl,-u,vfprintf -lprintf_flt -lm
|
3 | |
4 | # erlaubt float in sscanf und seinen Brüdern.
|
5 | #compiler.c.elf.extra_flags=-Wl,-u,vfscanf -lscanf_flt -lm
|
6 | |
7 | # erlaubt float in sscanf,sprintf und ihren Brüdern.
|
8 | #compiler.c.elf.extra_flags=-Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt -lm
|
Arduino Fanboy D. schrieb: > # erlaubt float in sscanf,sprintf und ihren Brüdern. > #compiler.c.elf.extra_flags=-Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf > -lscanf_flt -lm na, das nenne ich doch mal einen konstruktive info! ;-) thx. man muss natuerlich vorher erst mal herausgefunden haben, dass etwas alltaegliches wie sprintf(float) standardmaessig eben nicht geht. das kann schmerzhaft sein.
nochmal wegen deinem angeblichen Buffer Problem. Ich weiß nicht was dich am Serial Ringbuffer stören sollte. Wenn du nur einzelne Bytes sendest werden diese von der USART weiterhin mit voller konfigurierten Baudrate gesendet. Nur eben über den minimalen Umweg durch den Ringbuffer. Dieser Umweg verzögert nur minimalst das Senden. Ändert jedoch nichts an der Geschwindigkeit. Das muss man deutlich trennen. Wenn du wie du sagst nur einzelne Bytes sendest kann dir die kleine Verzögerung aus meiner Sicht herzlich egal sein. Wenn du jedoch Bytes in kurzer Folge sendest, ja dann käme dir der Ringbuffer zur Hilfe, weil er sich selbst um das automatische Senden kümmert. Schneller kommst du zu Fuss dann auch nicht, weil du dann auf den leeren USART Buffer warten müsstest ganz ohne Ringbuffer. Also dein gesamtes gedankliches Problem bezieht sich nur auf eine kleine Verzögerung. Mehr ist das nicht. Und diese Verzögerung tritt auch nur beim ersten Byte auf wenn der Ringbuffer leer sein sollte. Ansonsten spielt er seinen kompletten Vorteil aus. Nun überlege nochmal worüber du dich aufgeregt hast.
Wicki W. schrieb: > aber was ich z.b. gewohnt bin, ist das ein > sprintf(x,"%10.3f",val) > in x einen druckbaren string liefert. > der arduino-compiler liefert aber einen scheiss. In deinem Fall ist der Fehler, dass du %f benutzt hast, obwohl es (in der von Dir verwendeten Version der C Library) nicht implementiert ist. Arduino hat für String Formatierungen allerdings andere Methoden vorgesehen, die (so zumindest die Idee) weniger Fallstricke bieten. > sonst schmeisst einen dieser zeh-compiler inflationaer mit > errors und warnings zu - aber sowas erkennt er nicht als fehler? Der Compiler prüft die Syntax des Quelltextes. Ob die Implementierung alle Buchstaben aus dem String so verarbeitet, wie du es erwartest, kann der Compiler nicht wissen. Ich könnte mir eine Variante von printf() schreiben, die anstelle von %f immer "fuck" ausgibt. Das wäre im Sinne der Programmiersprache völlig korrekt. Dass der Compiler den Inhalt von Kommandos, die in Strings verpackt sind, nicht prüfen kann, ist ein alter Hut. Es ist für mich auch der Hauptgrund, warum ich solche Konstrukte mit Vorsicht einsetze. Noch sind unsere Computer nicht intelligent, das solltest du nie vergessen. Wenn du noch weitere Programmiersprachen lernst, wirst du sehen, dass sich das in den vergangenen 40 Jahren nicht geändert hat. Diesen konkreten Haken hat jede Programmiersprache. Fehlerhafte/Unpassende Inhalte in Strings wirken sich immer erst zur Laufzeit aus. > sorry, aber das ist eine scheiss-implementation. > vor allem, wenn man das nicht weiss. Du weisst es nicht, weil du da etwas benutzt hast, ohne die originale Anleitung zu lesen: https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1 "Since the full implementation of all the mentioned features becomes fairly large, three different flavours of vfprintf() can be selected using linker options..." und so weiter. Wenn du diese 40 jahre alte Funktion scheisse findest, dann nutze sie nicht. Arduino bietet Dir eine objektorientierte Alternative, die für Dich einfacher zu verwenden ist. printf() wird in der Arduino Doku aus gutem Grund gar nicht erwähnt. So viel zum Thema, Arduino sei ein Subset von C/C++. Da du die avr-libc Library benutzt, solltest du die Anleitung dazu lesen. Fang dort an: https://www.nongnu.org/avr-libc/user-manual/pages.html
soifz es mag muessig sein, aber nochmal fuer die, die es nicht verstanden haben: a) das "angeblichen Buffer Problem. Ich weiß nicht was dich am Serial Ringbuffer stören sollte." ringbuffer und sonstiger arduino-overhead sind mir herzlich egal. ich regel das auf unterster ebene selbst. und ich wollte nur wissen: wie bekomme ich ein zeichen in den fifo (weil serial.write eben viel zu langsam ist). glaubt es, oder lasst es. weiss es. b) sprintf und float/double wenn ich eine "standardhardware" mit einem "standardcompiler" einsetze, dann erwarte ich selbstverstaendlich, dass er mir sagt, wenn er eine formatierung eindeutig nicht umsetzen kann. so, wie im beispiel unten. statt es stillschweigend zu fressen und irgendeinen dreck als result zu liefern. (ich spreche jetzt nicht vom sonderfall dynamischer formatierungsstrings) das problem "a" existiert und ist einfach zu loesen "b" ist meine personeliche meinung. nicht mehr und nicht weniger. dennoch war sehr interessant, alle statements hier zu lesen. und das problem ist ja nun auch geloest. besten dank. schoenen sonntag noch wicki ##################### int a; printf("%f",a); : warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=] printf("%f",a);
Wicki W. schrieb: > man muss auch wissen, ob man vorwaerts oder rueckwaerts zaehlt. > und das ergibt sich erst aus dem zeitzversatz von 2 signalen. > > ich hatte ja auch gedacht, es gibt dafuer schon einen fertigen > chip, der das kann - aber scheinbar gibts den nicht oder > er ist selten und dann vermutlich exorbitant teuer. Ein ATtiny25, drei Widerstände und zwei Kondensatoren für <= € 1. Das ist doch nicht teuer? Die 2.Schaltung unter: http://mino-elektronik.de/mt12_iic/mt12_iic.htm Wicki W. schrieb: > sollte jetzt beliebig viele encoder gleichzeitig mit bis > zu 20kHz verarbeiten zu koennen. "Beliebig viele" ist etwas hoch gegriffen. Aber per IIC-Bus >= 10 Controller abzufragen sollte doch kein Problem sein.
Wicki W. schrieb: > aber was ich z.b. gewohnt bin, ist das ein > sprintf(x,"%10.3f",val) > in x einen druckbaren string liefert. > > der arduino-compiler liefert aber einen scheiss. > und zwar ohne die meldung, dass er so etwas nicht > umsetzen kann. Den Compiler geht es einen feuchten Kericht an, was in einem String drin steht, der an eine Funktion übergeben wird. Wenn du den String im Programm erzeugst, kann der Compiler da auch nicht rein gucken. Das ist Sache der Funktion. Und wenn die Laufzeitüberprüfung dann einen Overhead erzeugt, wird auch wieder gemeckert. Man könnte auch erwarten, das bei elementaren Rechenoperationen ein Range Checking statt findet - ist aber nicht so spezifiziert. Also wirst du wohl damit leben müssen, dass du dir die Dokumentation zu der von dir verwendeten Implementation der Funktion zu Gemühte führst.
Wicki W. schrieb: > wenn ich eine "standardhardware" mit einem "standardcompiler" > einsetze Der AVR ist kein Standard-Hardware. Das ist ein winziger Mikrocontroller mit ein paar KiB Programmspeicher. Die wird der Compiler nicht unnötig vollstopfen. Welche AVR-Compiler bist du denn gewohnt, welche float-printf automatisch einbinden nur falls es gebraucht wird? Wicki W. schrieb: > so, wie im beispiel unten. Es wird dich schockieren zu lernen, dass "der Compiler" nicht einfach nur ein monolithischer Software-Block ist. Hier sind schon mal 3 Komponenten betroffen: Compiler, Linker, C-Bibliothek. Der Compiler kann das printf() problemlos umsetzen. Das ist ja schließlich nur ein Funktionsaufruf. In manchen(!) Fällen kann er aus purer Nettigkeit warnen, wenn ein normales Standard-printf vermutlich(!) die Ausgabe nicht korrekt umsetzen kann. Der Compiler kann den Aufruf aber dennoch problemlos umsetzen. Der Compiler weiß aber nicht, welche C-Standard-Bibliothek der Linker später einbinden wird, und was für ein printf() da zum Einsatz kommen wird. Bibliothek und Linker können schließlich sogar von einem anderen Hersteller kommen. Der Compiler kann nicht hellsehen, was da nachgeliefert wird. Der Linker weiß es zwar, aber der weiß wiederum nichts von printf() und kann hier auch nicht warnen. Auf Mikrocontrollern muss man nunmal mit diversen Einschränkungen leben. Wenn dir das nicht passt, verwende keine Mikrocontroller. Was wäre denn dein Vorschlag, wie der Compiler oder Linker feststellen soll, dass hier ein Problem vorliegt und entsprechend warnen können soll?
sagt mal, habt ihr alle zu viel zeit??? das wetter ist herrlich, es ist sonntag, mein problem ist geloest. alles ist gut. und den compiler find ich doof. und es ist mein gutes recht, den doof zu finden. wenn andere den toll finden, dann ist das auch ihr gutes recht. was nichts an der tatsache aendert, dass so ein arduino mehr ein spiel- denn ein werkzeug ist. deswegen nutze ich ihn aber trotzdem, wenn er seinen zweck erfuellt. und nun: auf wiesegehn! wicki
Wicki W. schrieb: > und es ist mein gutes recht, den doof zu finden. Ja. Aber wenn du hier mit unqualifizierten Begründungen herumposaunst dass du ihn doof findest, musst du mit Antworten rechnen. Wicki W. schrieb: > was nichts an der tatsache aendert, dass so ein arduino mehr ein > spiel- denn ein werkzeug ist. Ja. Aber wenn man exakt diesen Compiler in Verbindung mit der Atmel Studio IDE und "professionellen" Platinen verwendet, ist es kein Spielzeug mehr, sondern wird in allen möglichen Produkten verwendet.
Wicki W. schrieb: > was nichts an der tatsache aendert, dass so ein arduino mehr ein > spiel- denn ein werkzeug ist. Du bist jetzt von der "fehlenden" Warnmeldung des Compilers zum Spielzeug gekommen. Alle Compiler verhalten sich in diesem Fall ebenso. Sind jetzt alle Compiler Spielzeug?
Die Küchenpsychologie bietet da einige Ansätze: > Die Erwartungshaltung, ist die Mutter der Enttäuschung. > Der Weg in die Hölle, ist mit falschen Annahmen gepflastert. > In den meisten Fällen brauchen wir nur unseren Blickwinkel zu > ändern, und der Ärger über Kleinigkeiten verschwindet. > Es ist erstaunlich, wie schnell wir uns mit fast jeder > Situation abfinden, wenn wir dazu gezwungen werden. > Es ist offensichtlich, dass uns die Umstände alleine nicht > glücklich oder unglücklich machen. Es ist die Art unserer > Reaktion darauf, die unsere Gefühle bestimmt. > Gott gebe mir Gelassenheit, hinzunehmen, was nicht zu > ändern ist. Mut zu ändern, was ich ändern kann. Und > Weisheit, zwischen beidem zu unterscheiden. > Säge kein Sägemehl. > Weine nie über verschüttete Milch. > Unser Leben ist das Produkt unserer Gedanken. > Das größte Problem, ist die Wahl der richtigen Gedanken. > Ein Mensch, der sich nicht ärgern kann, ist ein Dummkopf. > Ein Mensch, der sich nicht ärgern will, ein Weiser. -- Das grundlegende Problem ist offensichtlich schon Jahrtausende alt, so wie ein Teil dieser Sprüche. Im Grunde halte ich es für etwas überzogen, den Kompiler für die eigene Dokulesehemmung verantwortlich zu machen. Denn der Fehler entsteht im eigenen Kopf. Ihn bei anderen zu suchen blockiert die eigene Entwicklung. Arduino aus diesem Grund zum Spielzeug zu abzuwerten, funktioniert auch nicht, da alle IDEs, oder sonstigen Systeme, welche die AVR Gcc Toolchain nutzen das selbe Verhalten zeigen. Damit möchte ich nicht sagen, dass es falsch ist, mit Arduino zu spielen, nur das Bewertungskriterium ist irrational, und damit fachlich falsch. -------------- Stefanus F. schrieb: > Arduino hat für String Formatierungen allerdings andere Methoden > vorgesehen, die (so zumindest die Idee) weniger Fallstricke bieten. Dem stimme ich ausdrücklich zu. Performance o.ä. steht nicht unbedingt ganz weit üben auf der Arduino Vorgaben Liste. Eher sowas wie Schlichtheit, Naivität. So weit kann es gehen:
1 | #include <Streaming.h> // google findet das schon ;-) |
2 | |
3 | void setup() |
4 | {
|
5 | Serial.begin(9600); |
6 | Serial << F("Start") << endl; |
7 | |
8 | Serial << F("pi: ") << PI << endl |
9 | << F("pi: ") << _FLOAT(PI,6) << endl; |
10 | }
|
11 | |
12 | void loop() |
13 | {
|
14 | |
15 | }
|
Wenn einem Serial nicht schmeckt, aus welchen Gründen auch immer, dann kann/sollte man sich eine eigene Ausgabe bauen. In der Hinsicht ist Arduino offen genug, dass diese Möglichkeit besteht. Aber dann ist man wirklich gezwungen, sich mit den Dokus "rational" auseinander zu setzen. Sonst wird man daran verzweifeln/versagen. Und, wer will das schon.... Man kann also dankbar sein, für die Chance, die Dinge so zu bauen, wie man sie haben möchte. Oder sich darüber ärgern, dass sie nicht so sind, wie man sie sich in der Fantasie ausgemalt hat. > Der Pessimist sieht die Wolken vor der Sonne > Der Optimist sieht die Sonne über den Wolken. Mantra: Die Sonne scheint immer!
moin maedels, es ist faszinierend zu beobachten, ueber welches gigantisches zeitkontingent hier einige verfuegen koennen ;-) > Wenn einem Serial nicht schmeckt, aus welchen Gründen auch immer, dann > kann/sollte man sich eine eigene Ausgabe bauen. genau das war meine intention. problem geloest und alles ist gut. warum man dann seitenweise erguesse ueber eine beilaeufige bemerkung erstellen muss, das erschliesst sich mir nicht. ist vermutlich eine glaubensfrage. aehnlich wie bei bmw- und mercedes- oder harley- und goldwingfahrern. die umsetzung von sprintf, die eine beim compiliervorgang erkennbare nicht-aufloesbarkeit einer formatierung nicht zumindest als warning auswirft, ist scheisse. und ich koennte noch mehr anfuehren, was mir am arduino nicht gefaellt. wenn kritik aber nur zu "mussu halt manual lesen" oder seitenweisen filosofischen erguessen fuehrt: das ist auch in keiner weise konstruktiv. ich find klasse, dass ich mit einer nicht mal 10 eur teuren hardware mehrere encoder gleichzeitig lesen und die ergebnisse ausgeben kann. ohne zusatzhardware. deswegen werde ich aber nicht dem heiligen arduino huldigen und jede kritik wg. des sofortigen verdachts der blasphemie unterlassen. sodele, munter bleiben wicki
Nichts hat es mit glauben oder gar Blasphemie zu tun! Wicki W. schrieb: > die umsetzung von sprintf, die eine beim compiliervorgang erkennbare > nicht-aufloesbarkeit einer formatierung nicht zumindest als warning > auswirft, ist scheisse. > > und ich koennte noch mehr anfuehren, was mir am arduino nicht gefaellt. Und nochmal: Diese deine Kritik hat nichts mit Arduino zu tun! Nichts. Arduino nutzt nur die vorgegebene Toolchain. Und es wurde gar begründet, WARUM diese Toolchain so konstruiert wurde. Es ist einzig deine eigene Einstellung, die dir das eingebrockt hat. Dein Verhalten erscheint mir recht Egozentrisch. Was man auch an deiner Kleinschrift erkennen kann. Das z.B. empfinde ich als Respektlos. Das zeigt, wie wichtig dir deine Individualität ist, und wie sehr du auf die Interessen anderer scheißt. Wie borniert muss man sein, um den Lesern ABSICHTLICH das lesen zu erschweren?
Beitrag #5801025 wurde von einem Moderator gelöscht.
Wicki W. schrieb: > alles Compiler sind Scheiße (sinngemäß) Dann kann es für Dich nur eine Konsequenz geben: Rette die Welt, indem du einen besseren Compiler entwickelst. Viel Glück
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.