Forum: Mikrocontroller und Digitale Elektronik Alternative zu Printf in Interrupt


von Benno (Gast)


Lesenswert?

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

von Dirk (Gast)


Lesenswert?

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

von Benno (Gast)


Lesenswert?

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

von Hagen R. (hagen)


Lesenswert?

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

von Tom (Gast)


Lesenswert?

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

von Wolfram (Gast)


Lesenswert?

>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.

von Michi (Gast)


Lesenswert?

"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.

von Rahul (Gast)


Lesenswert?

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.)

von Benno (Gast)


Lesenswert?

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

von Tom (Gast)


Lesenswert?

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

von Christian (Gast)


Lesenswert?

@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
Noch kein Account? Hier anmelden.