Hallo Kann mir bitte jemand helfen. Ich gebe in einer Interruptroutine daten aus (von einem ADC). Momentan mit Printf, das dauert aber zu lange. die Routine sollte nicht länger als 1ms dauern da ich eine Sampelrate von 1000Hz anstrebe. Gibt es eine Alternative?? ich hab was von Flags gelesen. Davon hab ich keinen Plan. Wie geht das?? Ich verwende einen PIC16F777 mit CCS Compiler
Hi, eine alternative waere es deine Daten in einen Ringbuffer zulegen und in der Mainroutine dann auf die USART Schnittstelle zugeben. Die Funktion zur Ausgabe muesstest du selber programmieren. Gruß, Dirk
Hi Dirk, Das klingt kompliziert!! Als schnittstelle verwende ich ein RS232. Geht das damit auch? Hast Du einen Beispielcode für das legen auf den Ringbuffer? Ich hab davon noch nie gehört, bin erst seit ein paar monaten am Programmieren. Vielen dank für Deine schnelle Hilfe!! Gruß Benno
Das problem dürfte hier nichtmal die RS232 Software sein, die meisten arbeiten intern schon mit Ringbuffern. Eher vermute ich das die String-Formatierungen in printf() das zeitliche Problem darstellen. Also entweder ganz darauf verzichten und dein RS232 protokoll auf ein binäres Protokoll ohne Formatierungen umstellen. Dazu benötigst du natürlich auf PC Seite eine eigene Software zum Empfang der Daten. Oder aber die Formatierung deiner Werte ausserhalb der ISR machen und dann senden. Unter Umständen kostet das aber eben soviel Zeit das mehr Daten schneller reinkommen als du formatieren und raussenden kannst. Gruß Hagen
Wieviel du senden kannst hängt natürlich zunächst mal von der Baudrate ab. Bei 9600 Baud ist das gerade mal 1 Zeichen in einer ms. Selbst wenn du auf 115200 Baud gehst, dann kannst du max. 11 Zeichen in dieser Zeit senden. (1 Zeichen = 10 Bit bei 8N1) Somit ist wahrscheinlich die serielle Schnittstelle die Bremse und gar nicht printf(). Gruss
>Gibt es eine Alternative?? ich hab was von Flags gelesen. Davon hab ich >keinen Plan. Wie geht das?? dein Programm sollte so aussehen interruptroutine { lege Wert in Puffer } Hauptprogramm 1.sind werte im Puffer? wenn ja:übernimm Werte und gib sie aus evt. mit printf zu 1. mit Flags regelst du den Zugriff auf den Puffer. Es dürfen nicht beide (Interrupt und Hauptprogramm) auf den Puffer gleichzeitig zugreifen. Das einfachste ist die Interrupts, während deines Zugriffs auf den Puffer aus dem Hauptprogramm zu verbieten. Da der Puffer von 2 unabhängigen routinen benutzt wird mußt du dies dem Compiler mitteilen. In C würdest du dies mit volatile tun.
"Es dürfen nicht beide (Interrupt und Hauptprogramm) auf den Puffer gleichzeitig zugreifen. Das einfachste ist die Interrupts, während deines Zugriffs auf den Puffer aus dem Hauptprogramm zu verbieten. Da der Puffer von 2 unabhängigen routinen benutzt wird mußt du dies dem Compiler mitteilen. In C würdest du dies mit volatile tun." Häh? Wieso muss man den Interrupt im Hauptprogramm sperren? Das ist ja die lausigste Lösung. Das geht auch anders.
Man muß nur einen Ringpuffer aufbauen, auf den zwei Zeiger zeigen: Ein Schreibzeiger und Lesezeiger. Der Schreibzeiger wird in der ISR erhöht und der Lesezeiger in Hauptprogramm. An die Speicherstelle des Schreibzeigers wird der ADC-Wert durch die ISR geschrieben. Im Hauptprogramm werden dann solange die Werte über die RS232 gesendet, bis der Lesezeiger den Schreibzeiger eingeholt hat. Allerdings könnte es nach Toms Berechnung vorkommen, dass eher der Schreibzeiger den Lesezeiger "überrundet". (ich hab die Berechnung nicht weiter nachvollzogen/überprüft.)
Das mit dem Ringpuffer bringt mir glaube ich nichts. die zeit des lesens hängt ja von der übertragung ab. Wenn ich das wieder mit pintf mache wird das ganze ja auch nicht schneller. Ich hab keine Pausen für das Verbieten des Interrupts eingeplant. Ich brauche kontinuierlich einen ADC-Wert pro ms, also muß das interrupt auch jede ms ausgelößt werden. Oder denke ich da falsch? Gruß Benno
Da denkst du richtig. Wenn dein Controller eh nichts anderes macht ausser ADC-Werte einlesen und über die serielle Schnittstelle ausgeben, dann gewinnst du durch einen Ringpuffer gar nichts. Das erzeugt dann eher noch mehr Overhead. Somit musst du dir überlegen wie viele Zeichen du ausgeben kannst, bis der nächste Interrupt kommt. Werden nicht allzu viele sein (s.o.). Vielleicht macht es ja Sinn die Werte direkt zu senden und nicht erst mittels printf() nach ASCII zu wandeln. Dann muss halt ein Programm auf der anderen Seite die Werte in ein lesbares Format bringen. Sollte dich wirklich nur der printf() ausbremsen, musst du eben deine eigene Ausgaberoutine schreiben, einen ADC-Wert nach ASCII zu konvertieren geth mit relativ wenig Aufwand. Gruss
@Benno: Was macht denn das printf? Nur eine Wandlung von einem Wert in desses ASCII-Darstellung mit irgendeinem Radix? Dann solltest Du Dir mal die Funktionen itoa(...) bzw. ltoa(...) ansehen, die sind schneller als printf. Oder eben die Konvertierung eben selber programmieren, z.B. für Radix 16 (Hexadezimalsystem) geht das sehr effizient.
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.