Hallo lieben Mitleser,
kurz zu meinem Vorhaben:
Ich möchte mittels Handy-Mega8-Uart einen Interrupt auslösen.
Also wenn das Handy über die Tx-Leitung ein String mit "RING\c\r" sendet
(sprich angerufen wird) soll der Controller mit dem Signal aus dem
"Schlaf" geholt werden. Nun habe ich einiges über Interrupts gelesen
(auch das Datenblatt dahingehend befragt) allerdings sind mir einige
Dinge noch unklar. Wird ein Interrupt bei jedem Empfangen eines
"RING"-Strings ausgelöst, oder wie habe ich mir das vorzustellen?
Welchen Interrupt-Vektor würdet ihr für so einen Fall verwenden? Wie
würdet ihr das realisieren, dass der mega8 bei einer empfangenen
"aktivität" auf der Rx-Leitung, nur ein einziges mal in die
Interrupt-Routine springt, diese abarbeitet (Zeitunkritisch, kann länger
dauern, wegen Anruf Eingabeaufforderung etc) und dann wieder schläft?
Muss die Interrupt-Routine eigentlich in einer bestimmten Zeit
abgearbeitet werden, oder ist das dem Controller egal, solange es mir
egal ist? :-)
Welcher "Schlaf"-Modus bietet sich hier an? (so, dass auf
Uart-Aktivitäten der Controller geweckt wird und was könnten da die
Energieeinsparungen sein gegenüber Dauerbetrieb und Polling?)
ich würd mich über jede Hilfe und für jeden Bruchteil einer Antwort auf
meine ca1000 Fragen sehr freuen...
MFG Elko
Ein Interrupt wird durch ein >einzelnes< Ereignis ausgelöst, meist eine
positive oder negative Flanke eines Signals oder ein komplett an der
UART eingetroffenens Zeichen.
Wenn die UART eingesetzt wird, kann diese nach jedem Zeichen einen
UART-Int
auslösen. In der Int-Routine wird die Folge der Zeichen kontrolliert
(aufgesammelt), und wenn dann die richtige Zeichenfolge z. B nach dem
zehnten Zeichen (bzw.Int)erkannt ist, kann der Kontroller zu weiteren
Aktionen schreiten.
Ich hab' das Datenblatt nicht im Kopf, aber wahrscheinlich kann man nach
der Interrupt-Routine den Kontroller jedesmal schlafen schicken und
durch den nächsten UART-Int wieder aufwecken.
Eventuell muss man auch durch die erste Signalflanke den Kontroller
aufwecken und ihn für einige Zeit, vom Timer-Int gesteuert, wach lassen.
Wenn dann nicht der richtige String eingetroffen ist,
rücksetzen,schlafen legen und auf neuen String warten.
Ich bin da selbst Anfänger und habe mich selbst kürzlich mit Sleep Mode
und Aufwecken beschäftigt. Daher hier eine Spekulation dazu:
Du könntest die RX Leitung (TTL vom Handy direkt oder TTL-Seite des
RS232-TTL) zusätzlich auf den INT0 vom AVR geben und dadurch den AVR
sogar aus dem Sleep Mode Power Down wecken.
Das Aufwachen per INT0 wird ausgelöst, wenn an INT0 ein LOW Pegel
anliegt. Es ist also sicher zu stellen, dass im Ruhezustand (Spezialfall
Handy ist aus beachten!) ein HIGH Pegel anliegt.
Der AVR wacht dann beim Startbit auf. Ob die Aufwachzeit noch ausreicht,
um das erste "RING" teilweise zu detektieren, muss man testen (ich
spekuliere: es reicht nicht). Beim zweiten RING sollte der AVR wach
sein. Wesentlich schneller als der Power Down Mode ist der Stand By Mode
wach.
Die mehrfache Abarbeitung des INT0 beim Empfangen kann man ignorieren
oder du kannst den INT0 nach dem Aufwachen abschalten. Das Abschalten
benutze ich im Beispiel Suppentimer [[Pollin
Funk-AVR-Evaluationsboard]].
Beim externen Interrupt an sich muss man, habe ich gelesen, beachten,
dass das sehr empfindlich gegen elektromagnetische Störungen sein kann
und dass der AVR ggf. öfters durch Fehlalarme aufgeweckt wird. Also wäre
die Software so zu schreiben, dass der AVR nach dem Aufwachen das RING
prüft und bei Fehlalarm schnellstens wieder pennen geht.
Vielen vielen Dank für die Antworten...
@stefan: das hört sich schon sehr interessant an...
Meinst du die Rx Leitung vom Handy oder vom uC? Warscheinlich meinst du
den Tx des Handys zusätzlich auf int0 legen?
allerdings stehe ich noch ein wenig auf dem schlauch was die
implementierung der prüfung betrifft.
wie könnte ich das (am einfachsten) realisieren, dass nach dem RING
geprüft wird? programmiere übrigens in C...
wäre für jede Hilfe dankbar...
MFG Elko
Freie Auswahl TX vom Handy oder RX vom AVR. Die beiden sind ja irgendwo
verbunden.
Dazwischen kann sich ein Pegelwandler RS232-TTL befinden. Aber: Handys
haben eigentlich nie echte RS232-Pegel (ausser ein entsprechendes
Handykabel für PC_Anschluss wird benutzt, dann ist der Pegelwandler im
Kabel), so dass man einen Pegelwandler vergeblich sucht. Aufpassen mit
welchen Pegeln das Handy arbeitet 0V/5V oder 0/3.3V oder...
Bei einem Pegelwandler ist es im Prinzip Geschmackssache, wo die TX/RX
Kreuzung gemacht wird - auf der Handyseite oder auf der AVR-Seite.
Beim Programmieren gehe ich gerne schrittweise vor, anstatt alles auf
einmal stemmen zu wollen.
Hier würde das bedeuten, zuerst ein UART Programm zu schreiben, das in
einer Hauptschleife ein "RING" auswerten kann. Das würde ich auch
erstmal mit einem PC und Terminalprogramm simulieren statt mit einem
Handy.
Dann eine INT0-Funktion dazu zu packen. Dann ein Sleep dazu zu packen.
Wie eine UART abgeprüft wird, wird im AVR GCC Tutorial beschrieben. Und
der Rest auch ;-)
Vielleicht helfen dir auch meine Beispiele s. Link o. weiter. Beim 8-Bit
Z#hler und der Uhr ist UART (Polling) drin und im Suppentimer ist
INT0/Sleep drin.
Danke nochmal...
Das mit den Pegeln etc ist alles klar, auch jetzt die hardwaremäßige
umsetzung und Uarts habe ich auch schon aufgebaut, allerdings habe ich
konkrete probleme bei der Prüfung selbst, ob die Zeichenkette RING
empfangen wurde oder nicht. Da der Controller ja wahrscheinlich die
ersten paar zeichen wegen dem aufwachen verwerfen wird. Würdest du die
empfangenen zeichen in ein Array übertragen und dann auf die
Zeichenfolge "RING" prüfen (wenn ja wie gross sollte der array sein?)
Wenn ich das volle RING erfassen möchte, bietet sich doch ein größeres
array an, oder (vielleicht doppelt so lang wie das "RING\c\r"?)
Vielen Dank für die Mühe...
LG Elko
noch was, wäre es sinnvoll, dass in der Rx-Int-Routine das empfangene
Zeichen überprüft wird und sobald ein "R" empfangen wird, das R in
Array[0] übertragen wird... sobald ein "I" empfangen, das I in Array[1]
übertragen wird etc. und in der Rx-Int-Routine wird dann geprüft ob das
Array == "RING" entspricht.
Verstehe ich das richtig, dass ich den INT0-interrupt nur für das
aufwachen benutze und danach ausschalte und dass das empfangen der
zeichen über den Uart-Rx-INT läuft?
LG Elko
Bei dem Puffer (Array ist OK) würde ich erstmal nicht geizen. 2*RING
plus Nullbyte (!) hört sich zweckdienlich an.
Empfangene Zeichen unter Beachtung der Grösse reinschreiben dabei \r
verwerfen. Jedesmal den Puffer hinter dem aktuellen Zeichen mit Nullbyte
abschliesse. Bei einem \c auswerten und anschliessend die Füllposition
auf den Pufferanfang zurücksetzen. Ebenso zurücksetzen beim Erreichen
des Puffergrösse. Auswertung mit strncmpi ggf. mit Vorauswahl, ob die
mitgezählte Zahl der Zeichen im Puffer genau 4 ist.
EDIT:
> noch was...
Das ist mir zu kompliziert gedacht.
Die Empfangsroutine würde ich universell gestalten. Sie soll eine Zeile
per UART in einen Puffer schreiben. Wie gross der Puffer ist, kann
konfiguriert werden. Danach kümmert sich der Rest des Programms um die
Auswertung der Zeile.
Dadurch bekommt man eine universelle UART-Zeileneinleseroutine und nicht
nur eine RING-Einleseroutine. BZW. gibt es bereits fertige Libraries für
ersteres.
Ich habe vor ein paar Jahren eine Freisprecheinrichtung für ein
Mobiltelefon entwickelt.
Ich hatte mich für zwei Interruptlevel (per Software, da AVR sowas nicht
in Hardware unterstützt) entschieden.
USART-IRQs im hohen Level über Ringpuffer.
Den Parser im niedrigen Level per Timer-Interrupt. Das ganze habe ich
per State-Machine gemacht. Einfach Zeichen aus dem Ringpuffer holen bis
zum Zeilenende-Zeichen, danach dann Stringvergleich mit den erwarteten
Strings - hier nur "RING". Flag setzen und die Arbeit wird in der
Hauptroutine erledigt.