Hi ich will mithilfe eines Protokolls daten über usart an meinen mega32 übermitteln. aufbau: { = start comand data } = end die daten werden immer in bytes übermittelt. ich bäuchte jetz noch eine ctoi funktion so das ich bis zu 254 zahlen im data feld übermitteln kann. ich hab mal den code angehangen er ist nicht sehr schön ... für verbesserungen und vorschläge semtlicher art bin ich sehr dankbar ( = grüße #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #define SYSCLK 16000000 #define BAUD 38400UL #define UBRR_BAUD ((SYSCLK/(16*BAUD))-1) /* USART initialisieren */ void uart_init(void); unsigned char buffer; int sequ=0; int speed=0; int stat=0; int main(void) { /* USART initialisieren */ uart_init(); sei(); /* Nichts tun. Die Interrupts erledigten den Rest */ do { if (speed) { } } while (1) ; } void uart_init(void) { /* Baudrate einstellen ( Normaler Modus ) */ UBRRH = (unsigned char) (UBRR_BAUD>>8); UBRRL = (unsigned char) UBRR_BAUD; /* Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts */ UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN); /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */ UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); } /* Interrupt wird ausgelöst sobald neue Daten im USART-Empfangspuffer liegen */ ISR(USART_RXC_vect) { /* Daten aus dem Puffer lesen ... */ buffer = UDR; if (buffer == '{') sequ=1; else { if(sequ==1) { if(buffer=='}') sequ=0; if(buffer=='s') stat=1; else { if (stat == 1) { stat=0; speed=buffer; while ( !( UCSRA & (1<<UDRE)) ) ; UDR = speed; } } } } /* ... warten bis der Sendepuffer leer ist ... */ //while ( !( UCSRA & (1<<UDRE)) ) ; /* ... und gleich wieder zurück schicken */ //UDR = buffer; }
Was soll ctoi() machen? Du nimmst das Byte, das du ja hoffentlich (habs jetzt nicht in deinem Code gesucht) in einem unsigned char empfangen hast und weist das ganz einfach einem int zu. unsigned char data; // data kriegt irgendwie seinen Wert von der UART int i; i = data; Du kannst auch mit data direkt weiterrechnen. Ein char ist in C auch nichts anderes als ein kleiner Integer. Mit dem kann man genauso rechnen wie mit einem int. Nur spielt sich halt alles im Zahlenbereich 0 bis 255 ab (wenn du einen unsigned char hast). Beantwortet das dein Problem?
Das data: Ist das ein einzelnes Byte oder ein String. Die Möglichkeit gibt es auch noch. Im ersten Posting bin ich davon ausgegangen, dass data nur ein einzelnes Byte ist, dass den Wert enthält. Das da also eine binäre Übertragung erfolgt. Das muss aber nicht so sein. Du kannst ja die Zahl auch als Stringrepräsentierung rüberschicken. Bei einer Zahl 123 werden also nacheinander die Zeichen '1', dann '2' und schlieslich '3' übertragen, sodass du auf der Empfangsseite jetzt mit einem String "123" da stehst und daraus wiederrum eine Zahl machen musst. atoi() wäre zb. dafür geeignet.
Ich verstehe nicht, was dein Programm machen soll. Etwas mehr Hintergrundinfo wäre hilfreich. Im Moment sieht es so aus: 1/ Das Hauptprogramm initialisiert UART und dreht dann Däumchen. Ein Anweisungsrumpf für die Abfrage einer Variable speed ist vorhanden. Soll da die Baudrate umgeschaltet werden? 2/ Die Empfangsroutine empfängt Zeichen und setzt unter bestimmten Umständen eine Variable speed. Die Umstände werden durch eine state machine definiert, die eine 4-Byte Kommandosequenz erwartet. An Verbesserungen schlage ich vor: A/ Die state machine aus der Interrupt-Routine rausnehmen. Die ggf. zeitraubende Auswertung sollte im Hauptprogramm gemacht werden. B/ Einen längeren Puffer für die Empfangsroutine einbauen, der mindestens so gross ist wie eine Kommandosequenz. Dieser Puffer wird gemäß A/ ausgewertet. C/ Die Zuweisung an UDR aus der Empfangsroutine rausnehmen. Sie hat logisch dort nichts zu suchen. Sind das Reste einer Echo-Funktion? // Globale Definitionen #define MAXPUFFER 4 char puffer[MAXPUFFER]; unsigned char zeichen_im_puffer = 0; ... // Auswertung im Hauptprogramm if ( zeichen_im_puffer == MAXPUFFER && puffer[0] == '{' && puffer[3] == '}' ) { // Kommando? switch ( puffer[1] ) { // SPEED case 's': speed = puffer[2]; // Nutzdaten // ggf. hier Baudrate umschalten break; // Unbekanntes Kommando default: break; } // Kommando abgearbeitet. zeichen_im_puffer = 0; puffer[0] = 0; puffer[1] = 0; puffer[2] = 0; puffer[3] = 0; } ... // Puffer in der Empfangsroutine ISR(USART_RXC_vect) { unsigned char zeichen = UDR; if (zeichen_im_puffer < MAXPUFFER) puffer[zeichen_im_puffer++] = zeichen; // else = Puffer voll // dann z.B. weitere Zeichen verwerfen }
oh vieln dank für die super mühen erstmal ( = ich hab probiert die state maschine in die main reinzunehem und buffer eben global zu deklarieren ... leider ging dies nicht (wieso weiß ich nciht) ich werde deine veränderungen ausprobieren ...noch mal zu meinem protokoll ja data ist erstmal nur ein byte also am controller kommt {f100} für forwärts oder {b100} for backwards und eventuell ncoh request um den strom abzufragen aber das wird später kommen baudrate werde ich irgendwann mal umstellen ja ( =
Beitrag "Auswertung RS232-Befehle" Einfacher geht es sicherlich einfach zum Schluss das Fifo über den Memcpy Befehl ins struct zu kopieren. Gruß, Dirk
@ Peter Ich weiss es auch nicht. Wenn ich helfen soll, müsstest du Fehlermeldungen, eine Problembeschreibung oder den geänderten Sourcecode angeben. Am besten alles. Wenn du meine Codeschnippsel verwendet hast, kennzeichne die beiden globalen variablen zusätzlich mit volative.
Hi, also sowas wie dirk als link beigelegt hat find ich schon sehr gut und könnte ich auch sicherlich gut als ausgangasposition verwenden. ich schrieb einfach mal wie ich das program verstanden habe. sobalt ich ein zecihen sende wird dies in ein array[0] geschrieben. dann wird die funktion get_data ausgeführt sobalt was reingeschrieben wurde ist der wrx pointer erhöht und nicht mehr gleich dem rx pointer also wird das zeichen in cmd geschrieben sobalt 4 bytes eingelesen worden wird statusbyte = ready gesetzt und auswertung() erlaubt die auswertung der daten dazu wird eine case angelegt um den cmd zu überprüfen .... wenn das so stimmt wieso geht mein programm da unten nciht [ = nochmal danke wusste garnicht das es so ein forum gibt wo soviel mühen reingesteckt werden
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <avr/signal.h> |
4 | //#include "uart.h"
|
5 | |
6 | #define SYSCLK 16000000
|
7 | #define BAUD 38400UL
|
8 | #define UBRR_BAUD ((SYSCLK/(16*BAUD))-1)
|
9 | |
10 | #define BUFLEN 20
|
11 | |
12 | #define COMMAND0 1
|
13 | #define COMMAND1 2
|
14 | #define COMMAND2 3
|
15 | #define COMMAND3 4
|
16 | |
17 | #define READY 0
|
18 | |
19 | |
20 | |
21 | typedef unsigned char u8; |
22 | typedef unsigned short u16; |
23 | typedef unsigned long u32; |
24 | |
25 | typedef struct commands |
26 | {
|
27 | u8 cmd; |
28 | u8 data0; |
29 | u8 data1; |
30 | u8 data2; |
31 | u8 data3; |
32 | }commands; |
33 | |
34 | volatile unsigned char rx_buffer[BUFLEN]; // Receive Buffer |
35 | volatile unsigned char rx_ptr; // uchar pointer |
36 | volatile unsigned char wrx_ptr; // uchar pointer |
37 | volatile unsigned char status_byte; // uchar pointer |
38 | |
39 | enum states {byte0=0, byte1, byte2, byte3, byte4}state; |
40 | |
41 | |
42 | struct commands rs232data,*p; |
43 | |
44 | void uart_init(void); |
45 | |
46 | |
47 | SIGNAL(SIG_UART_RECV) |
48 | {
|
49 | rx_buffer[wrx_ptr] = UDR; // put new byte to buffer |
50 | if (++wrx_ptr >= BUFLEN) { // erhoehe den lese Buffer |
51 | wrx_ptr = 0; |
52 | }
|
53 | }
|
54 | |
55 | |
56 | void get_data(void) |
57 | {
|
58 | if(wrx_ptr != rx_ptr){ |
59 | switch (state) |
60 | {
|
61 | case byte0: p->cmd = rx_buffer[rx_ptr]; |
62 | break; |
63 | |
64 | case byte1: p->data0 = rx_buffer[rx_ptr]; |
65 | break; |
66 | |
67 | case byte2: p->data1 = rx_buffer[rx_ptr]; |
68 | break; |
69 | |
70 | case byte3: p->data2 = rx_buffer[rx_ptr]; |
71 | break; |
72 | |
73 | case byte4: p->data3 = rx_buffer[rx_ptr]; |
74 | status_byte |= (1<<READY); |
75 | break; |
76 | |
77 | }
|
78 | state++; |
79 | if (++rx_ptr>=BUFLEN){ |
80 | rx_ptr = 0; |
81 | }
|
82 | }
|
83 | }
|
84 | |
85 | void auswertung (void) |
86 | {
|
87 | if (status_byte & (1<<READY)){ |
88 | switch (p->cmd) |
89 | {
|
90 | |
91 | case COMMAND0: // do anything |
92 | while ( !( UCSRA & (1<<UDRE)) ) |
93 | ;
|
94 | UDR = 0; |
95 | break; |
96 | |
97 | case COMMAND1: // do anything |
98 | break; |
99 | |
100 | case COMMAND3: // do anything |
101 | break; |
102 | |
103 | }
|
104 | status_byte &= ~(1<<READY); |
105 | state=0; |
106 | }
|
107 | }
|
108 | |
109 | |
110 | |
111 | int main (void) |
112 | {
|
113 | |
114 | p = &rs232data; |
115 | |
116 | get_data(); |
117 | auswertung(); |
118 | |
119 | return 0; |
120 | }
|
121 | |
122 | void uart_init(void) |
123 | {
|
124 | /* Baudrate einstellen ( Normaler Modus ) */
|
125 | UBRRH = (unsigned char) (UBRR_BAUD>>8); |
126 | UBRRL = (unsigned char) UBRR_BAUD; |
127 | |
128 | /* Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts */
|
129 | UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN); |
130 | |
131 | /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
|
132 | UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); |
133 | }
|
Du musst mindestens get_data() und auswertung() in eine Endlosschleife einbauen, sonst wird das nix. Und sehen tust du im Moment auch nix, weil keine Nutzfunktion eingebaut ist. Bau doch mal ein Echo ein (empfangene Zeichen zurückschicken) und schalte mit einem Kommando Echo in Grossschreibung an und mit einem anderen Kommando Echo in Kleinschreibung. Allerdings sollest du dann einfacher eingebare Kommandos benutzen. Also z.B. #define COMMANDO0 "e" // Echo ein #define COMMANDO2 "g" // Grossschrift ein ...
Hallo, vielleicht optimiert der Compiler auch das Struct weg, das koennte vielleicht weiterhelfen. volatile struct commands rs232data,*p; Du möchtest nur ein Byte auswerten und keine komplexen Protokolle übertragen ? dann koennte man alles ein bischen verkleinern indem man sich das Struct spart.
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <avr/signal.h> |
4 | //#include "uart.h"
|
5 | |
6 | #define SYSCLK 16000000
|
7 | #define BAUD 38400UL
|
8 | #define UBRR_BAUD ((SYSCLK/(16*BAUD))-1)
|
9 | |
10 | #define BUFLEN 20
|
11 | |
12 | #define RUN 0
|
13 | #define STOP 1
|
14 | #define BOOM 2
|
15 | |
16 | typedef unsigned char u8; |
17 | typedef unsigned short u16; |
18 | typedef unsigned long u32; |
19 | |
20 | volatile unsigned char rx_buffer[BUFLEN]; // Receive Buffer |
21 | volatile unsigned char rx_ptr; // uchar pointer |
22 | volatile unsigned char wrx_ptr; // uchar pointer |
23 | |
24 | void uart_init(void); |
25 | |
26 | |
27 | SIGNAL(SIG_UART_RECV) |
28 | {
|
29 | rx_buffer[wrx_ptr] = UDR; // put new byte to buffer |
30 | if (++wrx_ptr >= BUFLEN) { // erhoehe den lese Buffer |
31 | wrx_ptr = 0; |
32 | }
|
33 | }
|
34 | |
35 | |
36 | void check_data(void) |
37 | {
|
38 | if(wrx_ptr != rx_ptr){ |
39 | switch (rx_buffer[rx_ptr]) |
40 | {
|
41 | case RUN: //starte |
42 | break; |
43 | |
44 | case STOP: //halte an |
45 | break; |
46 | |
47 | case BOOM: //explodiere |
48 | break; |
49 | |
50 | }
|
51 | if (++rx_ptr>=BUFLEN){ |
52 | rx_ptr = 0; |
53 | }
|
54 | }
|
55 | |
56 | int main (void) |
57 | {
|
58 | uart_init(); |
59 | for(;;){ |
60 | check_data(); |
61 | }
|
62 | }
|
63 | |
64 | void uart_init(void) |
65 | {
|
66 | /* Baudrate einstellen ( Normaler Modus ) */
|
67 | UBRRH = (unsigned char) (UBRR_BAUD>>8); |
68 | UBRRL = (unsigned char) UBRR_BAUD; |
69 | |
70 | /* Aktivieren des Empfängers, des Senders und des "Daten
|
71 | empfangen"-Interrupts */
|
72 | UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN); |
73 | |
74 | /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */
|
75 | UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); |
76 | }
|
Gruß, Dirk
also irgendwie bekomm ich nicht bei jeder 0 etwas zurück sondern nur nach einer wilkürlich anzahl ... ich hab noch ne klammer hinzugefühgt und ne ausgabe ... was haben die zeiger denn für anfangswerte und was macht die if bedingung indem die sie zeiger vergleich ? #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> //#include "uart.h" #define SYSCLK 16000000 #define BAUD 38400UL #define UBRR_BAUD ((SYSCLK/(16*BAUD))-1) #define BUFLEN 5 #define RUN 0 #define STOP 1 #define BOOM 2 volatile unsigned char rx_buffer[BUFLEN]; // Receive Buffer volatile unsigned char rx_ptr; // uchar pointer volatile unsigned char wrx_ptr; // uchar pointer void uart_init(void); SIGNAL(SIG_UART_RECV) { rx_buffer[wrx_ptr] = UDR; // put new byte to buffer if (++wrx_ptr >= BUFLEN) { // erhoehe den lese Buffer wrx_ptr = 0; } } void check_data(void) { if(wrx_ptr != rx_ptr){ switch (rx_buffer[rx_ptr]) { case RUN: while ( !( UCSRA & (1<<UDRE)) ) ; //starte UDR = 'r'; break; case STOP: //halte an break; case BOOM: //explodiere break; } if (++rx_ptr>=BUFLEN){ rx_ptr = 0; } } } int main (void) { uart_init(); for(;;){ check_data(); } } void uart_init(void) { /* Baudrate einstellen ( Normaler Modus ) */ UBRRH = (unsigned char) (UBRR_BAUD>>8); UBRRL = (unsigned char) UBRR_BAUD; /* Aktivieren des Empfängers, des Senders und des "Daten empfangen"-Interrupts */ UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN); /* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit */ UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); }
volatile unsigned char rx_ptr; // uchar pointer volatile unsigned char wrx_ptr; // uchar pointer ... sind mistverständlich von der Benennung her oder falsch von der Definition her, denn es sind keine Zeiger. Es sind Zähler. Und die sollten am Programmanfang auf 0 initialisiert werden, wenn man sicher gehen will und sich nicht auf den C-Startupcode verlassen will.
mh dann müsste ich aber doch beim ersten gesendeten byte (0) schon was zurückbekommen
Angenommen du machst die Initialisierung mit 0 volatile unsigned char rx_ptr = 0; volatile unsigned char wrx_ptr = 0; Und das erste Byte kommt über diese Interruptroutine. SIGNAL(SIG_UART_RECV) { rx_buffer[wrx_ptr] = UDR; // put new byte to buffer if (++wrx_ptr >= BUFLEN) { // erhoehe den lese Buffer wrx_ptr = 0; } } Dann ist wrx_ptr == 1 rx_ptr == 0 rx_buffer[0] == 0 Wenn das Byte eine binäre (!!!) 0 ist. Die Ziffer 0 wäre ein '0'. Nur zum Verständnis. In in deinem Programm geht es vielleicht (!) als erstes nach check_data(). Vielelicht, weil wir nicht wissen, wo der Interrupt aufgetreten ist. void check_data(void) { if(wrx_ptr != rx_ptr){ switch (rx_buffer[rx_ptr]) { case RUN: while ( !( UCSRA & (1<<UDRE)) ) ; //starte UDR = 'r'; break; case STOP: //halte an break; case BOOM: //explodiere break; } if (++rx_ptr>=BUFLEN){ rx_ptr = 0; } } } Die aktuellen Werte sind: wrx_ptr == 1 rx_ptr == 0 rx_buffer[0] == 0 Der if-Fall ist wahr (1 != 0), rx_buffer[0] == 0 == RUN, also geht es in den case RUN. Hier wird gewartet bis der Sendepuffer leer ist und dann wird ein 'r' gesendet. D.h. deine Annahme ist richtig. Empfängt der µC eine binäre 0, sollte ein 'r' zurückgeschickt werden. Wenn nix kommt, könnte es an der Verwechselung von binärer 0 mit Ziffer 0 liegen. Oder das Senden über UART funktioniert nicht.
Hallo, >In in deinem Programm geht es vielleicht (!) als erstes nach >check_data(). Vielelicht, weil wir nicht wissen, wo der Interrupt >aufgetreten ist. Es ist egal wann der Interrupt ausgeloest wird das Fifo Buffer wird weiterhin gefuellt. In deinen Programm hattest du den Buffer verkleinert auf 5 Bytes, wenn deine Mainapplikation zulange braucht um die empfangenden Daten auszuwerten werden deine alten Daten überschrieben. In einigen anderen Mikrocontrollern befinden sich einige Kbyte Ringbuffer als Hardware, manchmal kann in dem Fall auf ein Software Fifo Buffer verzichtet werden.
also die hardware funktioniert ich bekomme mit dem programm: http://www.kreatives-chaos.com/index.php?seite=c_uart auch die buchstaben die ich sende zurück
also wenn ich dein help.c nehme ... bekomme ich wilkürlich Zeichen sobalt ich eine 0 schicke. modifiere ich das programm mit einer anderen uart_init() bekomme ich (nicht bei jedem 0 byte was ich sende) start, stop ect zurück ...
Hallo, dann liegt es höchstwahrscheinlich an deiner F_CPU (Quarz), CPU Einstellung im Makefile. Anbei ein Screenshot, ich sende ein paar Bytes jeweils (00) Hexdezimal und bekomme als Rückantwort ein Ascii String (RUN).
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.