Hallo zusammen, ich beschäftige mich seit kurzem mit der Schnittstellenprogrammierung. Also bitte ich zunächst einmal um Entschuldigung, falls diese Frage sich für manch anderen etwas dümmlich anhört. Ich möchte gerne 70 Zeichen lange Strings empfangen ( Gerät--> uC ---> Hyperterminal). Allerdings empfange ich nur jeden zweiten String. Es scheint, dass mein Programm einfach nicht schnell genug ist, diese Strings weiter zu versenden. Ich möchte die Daten gerne ohne Interruptsteuerung empfangen und versenden. Ich habe nun gelesen das ein FIFO-Buffer hierbei Abhilfe schaffen könnte. Sprich der Datendurchsatz wird erhöht und die CPU Last wird verringert. Allerdings versteh ich noch immer nicht ganz wie ich das in das vorhandene Programm integrieren kann. Im Grunde werden die Daten ja in einen globalen Buffer geschrieben und das erste geschriebene Zeichen wird als erstes ausgelesen bzw. zur Verarbeitung weitergegeben. Wäre wirklich klasse, wenn mir hier jemand weiterhelfen könnte. Grüße
Urban schrieb: > die CPU Last wird verringert. Das heißt auf gut Deutsch: es wird nicht unnötig gewartet... Und das passiert jetzt aber in deinem Code immer noch:
1 | void send_char(unsigned char data) |
2 | {
|
3 | while (!(UCSR0A & (1 << UDRE0))); // warten und Däumchen drehen... |
4 | UDR0 = data; |
5 | }
|
6 | |
7 | |
8 | void send_string(char *string) |
9 | {
|
10 | while(*string) // ein while(), das deutet auf Rechenzeitverbrauch hin... |
11 | {
|
12 | send_char(*string); // und jetzt kommts: Warten, warten... |
Hier kann der uC nichts anderes tun, als zu warten, bis das Senden fertig ist. Klar, dass er in der Zwischenzeit keine ankommenden Zeichen verarbeiten kann. Da hilft dein ganzer hübscher Fifo nicht! > Ich möchte die Daten gerne ohne Interruptsteuerung empfangen und > versenden. Warum? Das ist, wie wenn du sagst: ich würde gerne Einparken, aber den Rückwärtsgang nicht verwenden (obwohl du einen hast!!!)... Wenn du mal in dich gegangen bist, such nach P. Fleurys UART-Lib... BTW: #define fosc 16000000 Ich schreibe da immer ein UL hinter die Zahl, weil 16000000 nicht in 16 Bit passen...
Die while - schleifen sind wie mein Vorgänger erwähnt hat, tödlich. Du solltest in der Hauptschleife einen Zustandsautomaten einbauen, der anstatt auf While -(TUE GARNICHTS BIS DIE SCHNITTSTELLE FERTIG IST) eine If-Abfrage einbauen, die nur bei fertiger Schnittstelle ein Datenbyte nachlegt. Wäre das Senden oder Empfangen noch nicht fertig, ist der Prozessor in der Lage an anderer Stelle im Programm weiter zu machen. Phasenprobleme werden so vermieden. ANregung OHNE ANSPRUCH AUF COMPILIERFÄHIGKEIT !!! define MAX_STING 70 uint8_t *SpeicherString[] = "IRGEND_ETWAS_VON_IRGENDWOHER\0" uint8_t SpeicherStringZaehler=0 mode = 0; // Hier noch die Initialisierungen Main { while(1) { switch(mode) { case 0: if(SpeicherStringZaehler++ < MAX_STRING) { /* IF erspart das Sinnlos Warten ...*/ if ((UCSR0A & (1 << UDRE0)) UDR0 = *SpeicherStringe++; } mode ++; break; case 1: Empfangen irgendwie analog wie oben. mode ++; break; default: mode = 0; // tue noch irgendetwas anderres sinnvolles und warte nicht. } } } Ich habe mir von je her angewöhnt, so ein kooperatives Scheduling zu integrieren. Die Statemachines machen zwar die Funktion des Codes unübersichtlich. Aber es lohnt sich. CAN - Grafik-Display und Modem betreiben etc. , lassen sich so quasi parallel betreiben. Und man kann so dem AVRs mit nur 16MHz richtig etwas abverlangen. Viel erfolg.
Hallo zusammen, vielen Dank für die schnellen Antworten. Ich habe es nun mal mit einer ISR probiert und es klappt. Zunächst einmal passen die so, oder muss/sollte ich da etwas anders machen? Ich möchte das Programm so aufbauen, dass beim Auftreten eines bestimmten Zustandes/Zeichenkombination ein Befehl verendet wird. Zudem hätte ich noch folgende Frage: Ich habe zwei UARTS mit UART0 will ich die Daten kontrollieren. Mit dem Zweiten will ich beim Auftreten einer bestimmten Situation, eine SMS versenden. Die GSM-Initialisierung habe ich ebenfalls mittels Polling realisiert. Diese kann ich ja nun einfach durch ISR´s ersetzen. Muss ich dabei auf etwas spezielles achten? Ich weiß nicht inwieweit die dann zueinander im Konflikt stehen. Bin für jeden Hinweis und Tipp dankbar... VG
Hallo, ich bins nochmal. Das Empfangen und Versenden der Daten klappt auf jeden Fall besser, wie mit der while-Schleife. Ich empfange und versende meine 70 Zeichen lange Strings nun nacheinander. Allerdings wird der letzte String der nur 14 Zeichen lang ist nicht versendet. Am obigen Programm hab ich nichts verändert. VG
Das Problem könnte hier liegen
1 | void send_string(char *data) |
2 | {
|
3 | if(uart_tx_flag == 1){ |
4 | strcpy(uart_tx_buffer, data); |
5 | uart_tx_flag = 0; |
6 | UCSR0B |= (1<<UDRIE0); |
7 | }
|
8 | }
|
wenn deine UART nicht sendebereit ist, zb. weil noch eine andere Übertragung läuft, dann .... lässt du den String einfach unter den Tisch fallen und machst gar nichts. Und das ist dann das was du siehst: Ein einzelner String wird nicht gesendet.
Hallo KH, vielen dank für die Antwort! Wenn ich Funktion get_log_data um void get_log_data(void) { if( log_daten == 1 && uart_tx_flag == 1) { send_string(stringbuffer); log_daten = 0; } } uart_tx-flag == 1 erweitere, erhalte ich das gesamte Protokoll. Ich muss also noch festlegen: Wenn letzte Übertragung beendet, dann können neue Daten gesendet werden?! Muss ich also immer, wenn ich ein Befehl senden will, mit uart_tx_flag == 1 die Sendebereitschaft prüfen? Beim Polling habe ich meine Sendefunktion, void send_string(char *string) { while(*string) { send_char(*string); string++; } send_char('\r'); } mit der ich einfach die Befehle innerhalb eines Programms versenden kann. if(log_data == 1) send_string("Log Daten vorhanden"); Bspw. wenn ich nach dem Erreichen eines Counters == 12 einen Befehl versenden will, oder wenn ich auf die Antwort des GSM Moduls reagieren will. Muss ich das dann immer mittels Flags realisieren? Sprich Flag setzen und schauen ob uart_tx_flag auch gesetzt, wenn ja, Senden? if(counter == 12) counter_flag = 1; . . . if(strcmp(stringbuffer, "OK") == 0) gsm_answer_flag = 1; . . . if(counter_flag == 1 && uart_tx_flag == 1) { send_string("Counter = 12"); counter flag = 0; } if(gsm_answer_flag == 1 && uart_tx_flag == 1) { send_string("12345"); gsm_answer_flag = 0; } Ich kapiere das immer noch nicht so richtig. VG
Urban schrieb: > Ich muss also noch festlegen: Wenn letzte Übertragung beendet, > dann können neue Daten gesendet werden?! Nein, eigentlich mußt du nur eine etwas bessere Pufferverwaltung einführen. Ein Ringpuffer wäre da gut geeignet (das ist übrigens ein Fifo). Wenn der ausreichend groß ist, dann kannst du von deinem "Hauptprogramm" einfach Zeichenketten ausgeben, und die ISR (+Pufferverwaltung) sorgt dann schon dafür, dass die Zeichenketten irgendwann nacheinander auf der SIO ausgegeben werden. Die Logik mit den Flags bringt dich irgendwann garantiert zur Verzweiflung.
Lothar Miller schrieb: > Die Logik mit den Flags bringt dich irgendwann garantiert zur > Verzweiflung. Das unterstreiche ich ganz dick und mit roter Farbe!
Hallo, zunächst einmal vielen Dank für eure Antworten. Ich habe mich mal anhand den Anmerkungen von Lothar an die Arbeit gemacht und versucht die Pufferverwaltung zu realisieren. Für mich als Anfänger auf jeden Fall etwas schwieriger als wie beim Einsatz von Polling. Es klappt nicht wirklich. Mit Hilfe meines C-Buches und über das Internet hab ich versucht die Fehler ausfindig zu machen, ohne Erfolg. Es wäre nett, wenn der ein oder andere erfahrenen Programmierer einen Tipp oder Hinweis hätte...Es wäre schon mal gut zu wissen, ob das, was ich gemacht hab in die Richtung geht, die mit Lothar geraten hat. Meine Strings, die ich empfange Enden immer mit '\r', also würde ich dieses Zeichen als Terminator verwenden. In meinem Programm möchte ich die bereits oben erwähnte Flag-Problematik vermeiden um im Haupt- oder Nebenprogramm Befehle zu versenden. Viele Grüße, Urban
Das ist doch kein Ringbuffer, was du da hast. Weder beim Senden noch beim Empfangen > Meine Strings, die ich empfange Enden immer mit '\r', also würde ich > dieses Zeichen als Terminator verwenden. Ein Tip: Halte den Ringbuffer aus jeglicher Dateninterpretation raus. Ein Ringbuffer soll einfach nur ein Zwischenspeicher sein, der Zeichen solange aufnimmt, bis die Verarbeitungseinheit Zeit hat, die zwischengespeicherten Zeichen abzuarbeiten. Mehr nicht. Ein Ringbuffer heißt deswegen so, weil die Speicherfläche logisch gesehen zu einem Ring 'gebogen' wird. Stell dir eine Uhr vor. An jeder Minutenposition ist eine Speicherstelle. Wenn Zeichen in den Ringbuffer gestellt werden, dann werden sie einfach reihum in das nächste Minutenfach gestellt. Wenn es dabei über die Stundengrenze (=60 Minuten) geht, dann wird einfach wieder vorne angefangen. So wie der Minutenzeiger einer Uhr auch einfach nur immer im Kreis läuft und trotzdem immer von 0 bis 59 zählt. Wenn die verarbeitende Einheit Zeit dazu hat, dann holt sie sich ein Zeichen nach dem anderen, solange bis sie entweder genug hat, oder nichts mehr Abzuholendes im Ringbuffer vorliegt. D.h. der Ringbuffer hat 2 ausgezeichnete Positionen: * Wo wird das nächste Zeichen eingefügt, beim Einstellen in den Ringbuffer * Von wo wird das nächste Zeichen gelesen, beim Wiederauslesen aus dem Ringbuffer (Und ja du brauchst 2 Ringbuffer. Einen fürs Senden und einen fürs Empfangen) Schau dir die UART LIb vom Peter Fleury an. Der verwendet Ringbuffer und interrupt gesteuertes Senden/Empfangen. Verblüffend: Wir haben gar keinen Artikel in der Artikelsammlung zum Thema Ringbuffer
Hallo Karl-Heinz, danke für deine Antwort. Ufff,das war wohl ein Griff ins Klo. Ich habe mir die Lib mal angeschaut und bin nicht so richtig durchgestiegen. Dann werde ich mir sie nochmals zu Gemüte führen und hoffen das ich es kapier. Nochmals Danke! VG, Urban
Ist ja kein Beinbruch. Deswegen hat PF die Lib ja veröffentlicht, damit man sie einfach nur benutzen kann, ohne sich um die Details kümmern zu müssen. Es gibt eine Funktion, die ein empfangenes Zeichen holt und es gibt eine Funktion, die ein Zeichen versendet. Mehr braucht man nicht um daraus deine gewünschte Funktionalität hochzuziehen.
Hallo, ich habe nun versucht mit der von KH vorgeschlagenen UART Lib von Peter Fleury einen FIFO zu realisieren. Ich verwende eine Arduino Board Mega mit einer 16MHz Taktfequenz. Die Daten die ich empfange werden mit 9600bps 8Bit, keine Parität und einem Stoppbit versendet. Bisher konnte ich mit Polling meine kleine Anlage ansteuern. Zwar seh ich jetzt den versendeten String am Hyperterminal, meine Anlage reagiert allerdings nicht mehr wenn ich die Befehle über den UART versende. Das lies mich vermuten, dass etwas nicht mit der Einstellung des Datenformates(Parität, bps, etc.) stimmt. Allerdings ist soweit alles in Ordnung. Des weiteren wollte ich die empfangenen Zeichen, sofort wieder über die UART versenden (siehe Programm). Allerdings wird nur 0x00 versendet. Ich weiß nicht mehr weiter.
Bevor ich mir einen Wolf suche: Hast du die Fleury Funktionen so gelassen wie sie waren? (Warum hast du sie nicht in ihrem eigenen File unverändert gelassen. Du brauchst dieses C-File doch nur ins Projekt mit aufnehmen und schon hast du die Funktionen zur Verfügung)
In der Fleury Lib ist eine Demo dabei
1 | while( 1 ) |
2 | {
|
3 | |
4 | // uart_putc( uart_getc() ); // empfangene Daten wieder versenden
|
5 | |
6 | |
7 | |
8 | char c = uart_getc(); |
9 | |
10 | if(c == 0x04) |
11 | uart_puts("Hab ich"); |
12 | |
13 | }
|
sieh dir dort an, wie man die uart_getc Funktion richtig verwendet. Achte auch auf den Datentyp der Variablen, die Peter in seiner Demo benutzt hat.
Hallo Karl-Heinz,ich wollte das nicht einfach so übernehmen, sondern versuchen das zu verstehen und selbst zu probieren...Klappt allerdings noch nicht ganz. ich bleib hartnäckig
Urban schrieb: > Hallo Karl-Heinz,ich wollte das nicht einfach so übernehmen, sondern > versuchen das zu verstehen und selbst zu probieren...Klappt allerdings > noch nicht ganz. ich bleib hartnäckig OK. Extra langsam, nur für dich: S i e h d i r d i e b e i g e l e g t e D e m o a n ! Der Fleury Peter macht das nicht zum Spass, dass er eine Demo schreibt, an der man sieht, wie man die einzelnen Funktionen zu verwenden hat! Sein uart_getc ist ein nicht wartendes getc. Das kommt auch dann zurück, wenn es kein Zeichen an der UART vorgefunden hat. Es ist aber so freundlich, dem Aufrufer mitzuteilen, dass genau dieser Fall vorliegt: UART_NO_DATA (Ich hab nichts für dich). Nur MUSST DU DIESE INFORMATION AUCH AUSWERTEN Und damit man sieht wie das geht, hat der Peter Fleury seiner Lib eine Demo beigelegt, in der er unter anderem genau das zeigt. NUR TUN MUSST DU ES!
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.