Hi Kann mir jemand sagen was für Flags gesetzt werden, wenn auf der seriellen Schnittstelle Daten daherkommen? Ich möchte in einer while(1) schleife Strings einlesen. (Aber nur dann einlesen wenn welche daherkommen). Kann mir jemand ein Teilfragment vom einlesen eines Strings posten? mfg
>Kann mir jemand ein Teilfragment vom einlesen eines Strings posten?
Siehe Datenblatt, Kapitel U(S)ART- Data Reception
Atmega 64. Hier meine Problembeschreibung: Ich möchte mit dem Atmega64 SMS lesen und versenden können. Dafür würde ich ja wie immer uart_gets() benutzen um etwas vom modem einzulesen. Jedoch weiß ich ja nicht wann eine sms eintrifft und um dies zu erkennen müsste der µC ja permanent an der seriellen Schnittstelle auf text warten. Dies wäre mit dem aufruf von uart_gets() erledigt, da die funktion erst beendet wird wenn die max string länge erreicht wurde oder ein string endzeichen erkannt wird. eine ausgabe vom modem wäre z.B. +CMTI:"SM",3 diese zeile sagt mir das eine neue sms im speicherbereich 3 gespeichert wurde. die darauf folgende antwort vom µC wäre dann (öffne SMS 3)-->AT+CMGR=3. folglich wird der inhalt der sms ausgegeben mit dem sich dann arbeiten ließe. mein problem ist nun: nach dem aufruf der funktion uart_gets() wartet der µC auf zeichen. falls aber keine sms eintrifft, empfängt der µC keine zeichen vom modem, wartet bis ins nächste jahrhundert und beendet die uart_gets() funktion nicht um mit dem programm fortzufahren. kurz gesagt in zwei fällen soll reagiert werden: wenn sich pinX verändert und wenn eine sms mit befehl eintrifft. wie löse ich dieses problem?
Hallo, schau mal ins Datenblatt vom ATMega64. In einem UART-Register UCSRA gibt's ein Flag, das heißt RXC. Es wird auf 1 gesetzt, wenn ein Zeichen empfangen wurde. Es reicht also wenn du vor dem Aufruf von uart_gets() überprüfst ob dieses Bit gesetzt ist. Wenn nein kannst den PinX abfragen, oder sonstige Aktionen durchführen. Gruß, Florian
Wenn du mit
>uart_gets()
nichts anfangen kannst, dann ist das die falsche Funktion für dich.
In eine Hauptprogrammschleife vom Typ
while(1){}
gehört nichts, was die Ausführung der Schleife grundsätzlich verhindern
kann.
Mein Tipp:
1) sieh nach, ob ein Zeichen gekommen ist z.B. über uart_getc()
2) falls nein: mach weiter mit der Schleife 4)
3) falls ja: füge es zu deinem String dazu,
ist es ein CR oder LF dann ersetze es durch \0 und
werte dann den so erhaltenen String aus
4) Tu den Rest der Schleife (Pinabfrage....)
5) Weiter bei 1)
@Florian Pfanner Werde ich später ausprobieren! Wird aber warscheinlich zur Lösung führen. Danke!
Kann mir jemand sagen wo da der Fehler liegen könnte. Der Atmega bleibt in der While(1) schleife hängen.
1 | unsigned char neu[10]; |
2 | |
3 | while (1) |
4 | {
|
5 | if((UCSR0A & (1<<RXC))) |
6 | {
|
7 | printf("Hallo\n"); //Gibt Hallo an die Serielle Schnittstelle aus. |
8 | gets(neu); //Speichert den String auf neu ab. |
9 | }
|
10 | }
|
Wie gesagt will ich einen String einlesen, sobald ich was auf der seriellen Schnittstelle empfang, sonst soll das Programm andere Tätigkeiten ablaufen lassen.
Ist printf schon auf STDOUT gerichtet und gets auf STDIN? Siehe http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html "The standard streams stdin, stdout, and stderr are provided, but contrary to the C standard, since avr-libc has no knowledge about applicable devices, these streams are not already pre-initialized at application startup..." Und wie man die Zuordnung mit Hilfe von FDEV_SETUP_STREAM macht (http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gea2b6be92ead4673bc487b271b7227fb und Democode in http://www.nongnu.org/avr-libc/user-manual/group__stdiodemo.html) EDIT: Siehe auch http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_Nutzung_von_printf
ist drauf gerichtet und funtkioniert auch, aber irgenwas hats mit der abfrage von der seriellen schnittstelle glaube ich.
schurli wrote: > Kann mir jemand sagen wo da der Fehler liegen könnte. > Der Atmega bleibt in der While(1) schleife hängen. warum eigentlich nicht über den RXC interrupt? >
1 | > unsigned char neu[10]; |
2 | >
|
3 | > while (1) |
4 | > { |
5 | > if((UCSR0A & (1<<RXC))) |
^^^ RXC0 muss es heißen
1 | > { |
2 | > printf("Hallo\n"); //Gibt Hallo an die Serielle Schnittstelle aus. |
3 | > gets(neu); //Speichert den String auf neu ab. |
4 | > } |
5 | > } |
6 | >
|
> > Wie gesagt will ich einen String einlesen, sobald ich was auf der > seriellen Schnittstelle empfang, sonst soll das Programm andere > Tätigkeiten ablaufen lassen. klingt wie gemacht für interrupts
1 | //Installation der Seriellen Schnittstelle
|
2 | void Handy_Init (void){ |
3 | |
4 | //Enable TXEN im Register UCR TX-Data Enable
|
5 | UCR=(1 << TXEN | 1<<RXEN); |
6 | //Teiler wird gesetzt
|
7 | UBRR=(SYSCLK / (BAUD_RATE * 16L) - 1); |
8 | |
9 | //öffnet einen Kanal für printf (STDOUT)
|
10 | fdevopen (uart_putchar, uart_getchar); |
11 | };
|
12 | |
13 | |
14 | //Routine für die Serielle Ausgabe
|
15 | int uart_putchar (char c){ |
16 | |
17 | if (c == '\n') |
18 | uart_putchar('\r'); |
19 | //Warten solange bis Zeichen gesendet wurde
|
20 | while(!(USR & (1<<UDRE))); |
21 | //Ausgabe des Zeichens
|
22 | UDR = c; |
23 | return (0); |
24 | };
|
25 | |
26 | //Routine für die Serielle Ausgabe
|
27 | int uart_getchar (void){ |
28 | |
29 | while(!(USR & (1<<RXC))); |
30 | return(UDR); |
31 | };
|
Hier der Codeausschnitt. Wie kann man es über den RXC interrupt machen?
schurli wrote: > ist drauf gerichtet und funtkioniert auch, aber irgenwas hats mit der > abfrage von der seriellen schnittstelle glaube ich. Dan erläutere bitte, was genau du mit "bleibt in der While(1) schleife hängen" meinst. Im Moment besteht dein Codeschnippsel nämlich aus einer Endlosschleife; das Programm MUSS in der while(1) Schleife bleiben. Wenn du andere Tätigkeiten abzuarbeiten hast, könntest du die hier unterbringen: unsigned char neu[10]; while (1) { // Auf UART-Eingabe prüfen if((UCSR0A & (1<<RXC))) { printf("Hallo\n"); //Gibt Hallo an die Serielle Schnittstelle aus. gets(neu); //Speichert den String auf neu ab. } // ggf. Eingabe auswerten und // sonstigen Code ausführen }
deine register stimmen nicht. die routinen wurden wohl für einen andren µc geschrieben. lies dir einfach mal das datenblatt und das tutorial hier jeweils zum thema uart durch
Sorry hab vergessen das die mit dem Präprozessor definiert wurden.
1 | #if defined (__AVR_ATmega64__)
|
2 | # define USR UCSR0A
|
3 | # define UCR UCSR0B
|
4 | # define UDR UDR0
|
5 | # define UBRR UBRR0L
|
6 | # define EICR EICRB
|
7 | #endif
|
ahja. dann stimmt aber trotzdem RXC noch nicht. muss RXC0 heißen. die sind nicht an der gleichen stelle bei anderen typen.
und noch hinterher: > int uart_putchar (char c){ warum denn int? void tuts doch. > if (c == '\n') > uart_putchar('\r'); rekursion? > ... > };
Hat zwar schon anstandslos mit RXC statt RXC0 funktioniert obwohl es definitiv falsch ist. Trotzdem hängt das Programm beim Einlesen des Strings. "Hallo" wird mir auf der Seriellen ausgegeben, aber dann steht alles.
Die Funtkion stammt von Ulrich Radig und ist auf Siemens Handys zugeschnitten.
1 | unsigned char neu; |
2 | |
3 | while (1) |
4 | {
|
5 | if((UCSR0A & (1<<RXC0))) |
6 | {
|
7 | printf("Hallo\n"); //Gibt Hallo an die Serielle Schnittstelle aus. |
8 | neu=uart_getchar(); |
9 | }
|
10 | }
|
Komischerweise funktioniert das einlesen eines Zeichens wunderbar. Wenn ich im Hyperterminal irgenwas eingebe, schickt mir der AVR "Hallo" zurück und das Programm läuft in der while(1) weiter. 10mal irgendwas drücken ergibt 10mal "Hallo" also funktiniert es. Warum funktioniert gets() nicht? mfg
Welches Zeichen ist den das Zeilenendezeichen in gets? Tipp, dies ist der Code von gets() aus avr-libc 1,6.2:
1 | #include <stdio.h> |
2 | |
3 | #include "stdio_private.h" |
4 | |
5 | char * |
6 | gets(char *str) |
7 | {
|
8 | char *cp; |
9 | int c; |
10 | |
11 | if ((stdin->flags & __SRD) == 0) |
12 | return NULL; |
13 | |
14 | for (c = 0, cp = str; c != '\n'; cp++) { |
15 | if ((c = getchar()) == EOF) |
16 | return NULL; |
17 | *cp = (char)c; |
18 | }
|
19 | *--cp = '\0'; |
20 | |
21 | return str; |
22 | }
|
Und welches Zeichen schickt dein UART-Sender (Terminalprogramm?, Handy?) am Ende einer Zeile?
Stefan "stefb" B. wrote: > Wenn du andere Tätigkeiten abzuarbeiten hast, könntest du die hier > unterbringen: > > unsigned char neu[10]; > > while (1) > { > > // Auf UART-Eingabe prüfen > if((UCSR0A & (1<<RXC))) > { > printf("Hallo\n"); //Gibt Hallo an die Serielle Schnittstelle aus. > gets(neu); //Speichert den String auf neu ab. > } > > // ggf. Eingabe auswerten und > // sonstigen Code ausführen > > } Das setzt allerdings voraus, dass der restliche Code nicht zu viel Zeit braucht (abh. von F_CPU und BAUDRATE). Der Hardware-UART-Puffer ist derzeit nur 2 Zeichen gross und es besteht grosse Gefahr, dass Zeichen verloren gehen. Ein grösserer Empfangspuffer und eine vom Userprogramm unabhängig laufende RX-Interruptroutine wären sicher die geschicktere Lösung.
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.