Hallo zusammen, ich habe folgendes Problem (ATMEGA164P): Es wird alle 5ms eine Messung (Dauer ca 70µs) mittels externem AD-Wandler über die SPI - Schnittstelle durchgeführt. Dies habe ich mittels Timer (Compare Modus) gelöst. Die Messung funktioniert einwandfrei. Sie wird mittels Terminal-Programm vom PC aus gestartet. Nur mit dem Stoppen klappt es nicht so ganz... Start und Stop - Befehl bestehen jeweils aus 5 Bytes. Die Bytes werden im USART-Register des Controllers mittels Interrupt-Routine empfangen. Durch Debuggen habe ich festgestellt, dass die Daten des Stop-Befehls nicht immer vollständig ankommen. Der Start Befehl funktioniert immer. Deshalb gehe ich davon aus, dass es etwas mit der Messung zu tun hat. Folgende Dinge sind mir noch nicht ganz klar: 1. Wenn die Interruptroutine des Timers ausgeführt wird, was passiert mit dem Interrupt des USARTs? 2. Was passiert mit dem Daten die von dem Terminal-Programm des PCs gesendet werden, wenn das USART-Register noch nicht gelesen wurde. Weitere Informationen: AVRSTUDIO v4.13 AVRGCC v4.1.1
zu 2. Wenn Du nicht mit Handshake-Signalen arbeitest, landen die zuviel gesendeten Signale vom PC im Nirvana. Du musst sie allerdings abholen. Bei 9600Bd hast Du dafür aber ca. 1ms Zeit. Der ATmega88 (Deinen kenne ich nicht, vermute aber, sie sind einigermaßen identisch) kann noch ein zusätzliches Byte puffern. Da sollten die 70us Deiner Wandlung nicht stören. Aber: Welches PC-Programm setzt Du ein? Wir hatte große Schwierigkeiten mit dem Hyperterminal. Das lieber nicht verwenden, es gibt andere gute zum kostenlosen Download (ich habe "Hercules", kann noch einiges mehr, funktioniert aber sicher). Allgemein: Wenn Du nicht besondere Maßnahmen triffst, kann ein Interrupt nicht von einem anderen (wie prior auch immer) unterbrochen werden. Das liegt daran, dass beim Einsprung in den Interrup das Globale Interruptflag gelöscht wird und erst am Ende des Interrupt wird es wieder gesetzt (RETI). Wenn Du es zu Beginn ( oder wo auch immer ) Deines Interrupt setzt (SEI), dann können andere Interrupts den aktuell laufenden unterbrechen (wie prior auch immer). Aber Vorsicht! Da kann man viel kaputt machen! Deinen Wandlungs-Interrupt (ich gehe hierbei davon aus, dass Du im Interurpt auf das Ende der Wandlung wartest) könntest Du wahrscheinlich unterbrechen lassen, NACHDEM die Wandlung gestartet wurde. Du wartest ja ohnehin nur, etwas länger warten stört Deine Wandlung nicht. Eine andere Alternative könnte sein, einen Interrupt am Ende der Wandlung zu generieren. Das scheint mir eine bessere Lösung zu sein. Schöne Pfingsten noch Willi Wacker
Hallo Willi, danke für deine schnelle Antwort. Ich verwende HTERM als Terminal-Programm, weil das binär, hex, dezimal und ASCII anzeigen kann. > Wenn Du nicht mit Handshake-Signalen arbeitest, landen die zuviel > gesendeten Signale vom PC im Nirvana. Ich arbeite nicht mit Handshake-Signalen. Aber das Start-Signal kommt ja ordnungsgemäß an. Nachdem das Start-Signal gesendet wurde, wird der Interrupt des TIMERS für die Messung aktiviert. Das Stop Signal kommt dann meistens nicht mehr richtig an. Wie sieht es denn aus, wenn die Interruptroutine von der Messung noch läuft, alle weiteren Interrupts gesperrt sind und dann der Interrupt des USARTs ausgelöst wird? Wird das Zeichen dann nach Beenden der Routine des TIMERS abgearbeitet? Oder geht das Zeichen dann verloren? > Eine andere Alternative könnte sein, einen Interrupt am Ende der > Wandlung zu generieren. Das scheint mir eine bessere Lösung zu sein. Wie macht man das?
> Es wird alle 5ms eine Messung (Dauer ca 70µs) mittels externem > AD-Wandler über die SPI - Schnittstelle durchgeführt. Auch der SPI-Bus kann im Hintergrund laufen und einen Interrupt auslösen, wenn ein Byte fertig ist. Ich würde zur Realisierung folgenden Ansatz machen (in ASM gedacht): - Timer-Interrupt startet alle 5ms die SPI-Sequenz und kehrt sofort zur Mainloop zurück. - SPI-Interrupt führt diese SPI-Sequenz weiter (State-machine), sendet ggf. Ergebnis über UART-TX oder legt Ergebnis in Buffer und kehrt unverzüglich zur Mainloop zurück. - UART-RX-Interrupt empfängt ein Byte, legt es in RX-Buffer, setzt Semaphore für Mainloop und kehrt unverzüglich zur Mainloop zurück. - Mainloop parst Befehle im Buffer, falls Semaphore gesetzt war und führt Befehl aus, falls er gültig war. Geht dann ggf. in Sleep. - Mainloop kann jederzeit durch Interrupt unterbrochen werden, wobei sich jeder Interrupt extrem kurz fasst, um anderen Interrupts auch eine Chance zu geben. ...
@MarcB Der Fehler liegt vermutlich daran, daß der Timerinterrupt dauernd aktiv wird und damit dem Rx Interrupt keine Chance zur Abarbeitung läßt. Tx funktioniert, weil da der Timerinterrupt noch nicht aktiv ist. @hannes Lux - SPI-Interrupt führt diese SPI-Sequenz weiter (State-machine), sendet ggf. Ergebnis über UART-TX oder legt Ergebnis in Buffer und kehrt unverzüglich zur Mainloop zurück. Ich habe bisher den 486er in assembler programmiert und darum denke ich in ns statt in µs, wie es beim AVR notwendig ist. Und weil ich beim 486 hauptsächlich mit Berechnungen zu tun habe, fallen dort keine Wartezeiten an. Oder kaum. Wenn Ergebnis über Uart gesendet werden soll, muß erst geprüft werden, ob der Sendepuffer leer ist. Da entsteht ggf. eine Wartezeit. Der Buffer ist aber recht aufwendig, unabhängig von der Größe. Bei einem Byte Puffer könnte man vielleicht noch 1 Register nehmen. Aber schon ab 2 Byte muß man den Puffer im RAM haben. 2 Zeiger für Tx und 2 Zeiger für Rx. 3 Zeiger stehen nur zur Verfügung und werden vielleicht auch noch anders gebraucht, daher müssen die Zeiger auch im Ram stehen. Mindestens die 2 Zeigerregister im Interrupt müssen gepusht und gepopt werden. Ggf. muß festgestellt werden, ob der Puffer voll ist und was dann zu tun ist und ob der Puffer leer ist. Wegen des Ringpuffers muß auch das Ende des Pufferspeichers abgefragt werden. Um da ein Byte abzulegen und wieder zu lesen, ist das ein ganz schön großer Aufwand. Beim Rx entsteht der gleiche Aufwand. Dabei muß auch noch berücksichtigt werden, daß schnellere Abläufe durch einen Buffer nicht an langsamere angepaßt werden, sondern es werden damit nur unregelmäßige Zeiten ausgeglichen. Dies könnte auch ein Timer überbrücken, jedoch entstehen dann zwangsweise Pausen, die evtl. unerwünscht sind.
Wolfram, ich weiß, wie Ringbuffer in AVR-ASM funktionieren. Das Arbeiten damit ist aber allemal effizienter als das Verweilen in einer Timer-ISR während einer kompletten externen ADC-Wandlung incl. SPI-Datenübertragung. Eine andere Vorgehensweise könnte bei Nutzung externer OWI-Chips sinnvoll sein, während des (relativ schnellen) Auslesens darf man keine Interrupts zulassen, da diese das Timing stören. Allerdings kann man den Zeitpunkt des Auslesens so organisieren, dass er am wenigsten stört. Meine Hinweise richteten sich aber auf einen externen Chip, der über SPI angesprochen wird. Und dies ist beim AVR recht effizient per Hardware-SPI möglich. ...
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.