hallo zusammen! ich möchte gerne eine permanente kommunikation zwischen uc (atmega16) und pc aufrecht erhalten. datenaustausch über rs232 funktioniert in beide richtungen - leider nur unter einschränkungen (es können nur 8 bits gesendet werden). in abhängigkeit von bestimmten einflüssen, sollen zwei mototen mit pwm geregelt werden. jeder motor für sich läuft, doch ich weiß nicht wie ich eine unterscheidung der motoren realisieren kann. beispiel: pc sagt: motor 1 -> pwm 255 motor 2 -> pmw 180 wie schaffe ich es, dass der uc beim lesen von udr mehr als 8 bit einliest? hatte gedacht dass ich vom pc aus z.b. 1255 verschicke, wobei die 1 für den ersen motor steht. benutze das avr studio. würde mich über anregungen oder verbesserungsvorschläge freuen. gruß Floyd
Was du brauchst ist ein Protokoll. Denk dir was aus: zb. 1. Byte Kennung des Motors 2. Byte PWM Wert > wie schaffe ich es, dass der uc beim lesen von udr mehr als 8 bit > einliest? Gar nicht. Die Einheit der Übertragung ist ein Byte (8 bit). Wenn dir das nicht reicht, dann benutz halt mehrere Byte, siehe oben.
Alle seriellen Übertragungsarten, die von µCs zur Verfügung gestellt werden, sind zunächst 8-Bit-Interfaces. Wenn Du mehr als 8 Bit übertragen willst, musst Du ein Protokoll vereinbaren und "Frames" aus mehreren Bytes versenden. Das ist eigentlich kein großes Problem. Du schickst also z.B. immer 2 Bytes, von denen das erste die "Adresse" (also z.B. die Nummer) des Motors enthält und das zweite den gewünschten Wert für die Geschwindigkeit.
könnt ihr mir ein bischen starthilfe für die erstellung eines solchen protokolls geben?
Du kannst ja mehrere Bytes nacheinader senden. Ich würde aber keine binären Werte über die RS-232 senden, sondern nur ASCII-Characters. Dies vermeidet allfällige Probleme mit Steuerzeichen. [Carridge Return] [Line-Feed] [Backspace] [Delete] etc... Deine Zahl würde dann als "1255/n" bzw. [0x31,0x32,0x35,0x35,0x13] übermittelt. So kannst Du die Werte auch direkt im via ein Terminalprogramm eingeben oder anzeigen lassen. MfG Peter
Oder noch besser: übermittle die Werte in einer besser lesbaren Form, z.B. mit Kommandos wie zum Beispiel: M1-255 M2-180
vom pc solche kommandos abschicken geht ja, doch ich weiß nicht ganz wie es dann im uc weitergeht. um einen sochen string einzulesen, muss ich doch mehrmals udr auslesen. wie kann ich das machen ohne daten zu verliehren?
Dafür gibts nen Interrupt, der ausgelöst wird, wenn ein Zeichen empfangen wurde. Wenn Deine Strings immer gleich lang sind (was zu empfehlen ist), dann musst Du nur warten, bis ein String komplett ist und ihn dann auswerten. Wenn Du als letztes Zeichen einen Nullterminator sendest, kannst Du auch eine Fehlerüberprüfung machen. Beispiel: 1. Byte: Nummer des Motors 2. bis 4. Byte: Wert für PWM 5. Byte: Nullterminator Du brauchst also nur einen Puffer mit 5 Bytes, in den nacheinander in der Interrupt-Routine die ankommenden Zeichen geschrieben werden und dessen aktuelle Schreibposition durch einen Zähler überwacht wird. Wenn der Puffer voll ist (also der Zähler z.B. in diesem Beispiel den Wert 4 erreicht hat), kann der String ausgewertet werden.
hi johnny.m genau so würde ich das gerne umsetzen wollen! könntest du mir mit entsprechendem c-code auf die sprünge helfen? bis jetzt sieht das ganze bei mir so aus: #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <stdlib.h> #define F_CPU 3686400 #include <util/delay.h> unsigned char buffer1; void uart_init(void) { UBRRH = 0x00; UBRRL = 0x17; UCSRB = 0x98; UCSRC = 0x86; } unsigned char USART_RX(void) { while(!(UCSRA&(1<<RXC))) ; return UDR; } int main(void) { PORTD=0x00; DDRD=0x20; TCCR1A=0x81; TCCR1B=0x05; TCNT1H=0x00; TCNT1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; uart_init(); while(1) { // will sehen was am uc angekommen ist USART_RX(); buffer1 = UDR; // Ende vom while } // Ende der main }
Als erstes würde ich mir mal eine String-Ausgabe machen:
1 | // Sendet ein einzelnes Zeichen
|
2 | void uart_putc( char c ) |
3 | {
|
4 | // Warte bis die Sendeeinheit bereit ist
|
5 | while( !(USR & ( 1<<UDRE) ) ) |
6 | ;
|
7 | UDR = c; |
8 | }
|
9 | |
10 | // Sende einen C-String
|
11 | void uart_puts( const char* str ) |
12 | {
|
13 | while( *str ) { |
14 | uart_putc( *str ); |
15 | str++; |
16 | }
|
17 | }
|
Damit kannst du schon mal solche Dinge machen:
1 | int main() |
2 | {
|
3 | while( 1 ) |
4 | uart_puts( "Hallo du\n" ); |
5 | }
|
oder auch
1 | int main() |
2 | {
|
3 | char Text[] = "Hallo Welt\n"; |
4 | while( 1 ) |
5 | uart_puts( Text ); |
6 | }
|
Dann gehts weiter: Du brauchst eine Funktion, die nicht nur ein einzelnes Zeichen empfängt, sondern eine Zeile davon. Als Zeile definieren wir mal: Alles was bis zum Return Zeichen geht:
1 | unsigned char USART_RX(void) |
2 | {
|
3 | while(!(UCSRA&(1<<RXC))) |
4 | ;
|
5 | return UDR; |
6 | }
|
7 | |
8 | void uart_gets( char* Input ) |
9 | {
|
10 | char c = USART_RX(); |
11 | uart_putc( c ); // und gleich wieder zurückschicken, damit |
12 | // der Benutzer auch was sieht
|
13 | |
14 | while( c != '\n' ) { |
15 | *Input = c; |
16 | Input++; |
17 | c = USART_RX(); |
18 | uart_putc( c ); |
19 | }
|
20 | *Input = '\0'; |
21 | }
|
Damit kann man dann schon so was machen:
1 | #include <string.h> |
2 | |
3 | .... // hier die uart Funktionen |
4 | |
5 | int main() |
6 | {
|
7 | char Buffer[20]; |
8 | |
9 | while( 1 ) { |
10 | uart_gets( Buffer ); // Auf eine Zeile vom Benutzer warten |
11 | |
12 | //
|
13 | // Testweise die komplette Zeile zurückschicken, so wie
|
14 | // sie vom µC empfangen wurde
|
15 | //
|
16 | uart_puts( "Ich habe verstanden : " ); |
17 | uart_puts( Buffer ); |
18 | uart_putc( '\n' ); |
19 | |
20 | // war die Eingabe vom Benutzer der Text 'Floyd'
|
21 | if( strcmp( Buffer, "Floyd" ) == 0 ) { |
22 | // Wenn ja, dann begrüsse ihn
|
23 | uart_puts( "Hallo Floyd\n" ); |
24 | uart_puts( "Wie gehts\n" ); |
25 | }
|
26 | }
|
27 | }
|
Wenn du dich jetzt mit einem Terminalprogramm an den µC klemmst, muss der brav jede Eingabe wieder zurück- schicken. Jedesmal wenn du Return drückst, zeigt er dir die zuletzt gelesene komplette Zeile an. Und so gehts dann weiter: Du vereinbarst mit dir, dass das erste Zeichen in der Übertragung die Motornummer ist, das nächste Zeichen ignorierst du und daran anschliessend kommt der PWM Wert. An das erste Zeichen kommst du ganz einfach mit Buffer[0] ran. Ab Buffer[1] steht dann eine 'Zahl' in ihrer ASCII Form. Die Funktion atoi() kann diese ganz leicht in eine tatsächliche Zahl wandeln.
1 | ....
|
2 | |
3 | int MotorNr; |
4 | |
5 | while( 1 ) { |
6 | |
7 | uart_gets( Buffer ); |
8 | |
9 | // zu testzwecken. Ist immer gut zu kontrollieren
|
10 | // was der µC tatsächlich empfängt
|
11 | uart_puts( "Ihre Eingabe: " ); |
12 | uart_puts( Buffer ); |
13 | uart_putc( '\n' ); |
14 | |
15 | MotorNr = Buffer[0] - '0'; // Die Motornummer nummerisch machen |
16 | PWMWert = atoi( &Buffer[2] ); // Den PWM Wert umrechnen lassen |
17 | |
18 | if( MotorNr == 0 ) |
19 | uart_puts( "Setze Motor 0 auf neuen Wert\n" ); |
20 | |
21 | else if( MotorNr == 1 ) |
22 | uart_puts( "Setze Motor 1 auf neuen Wert\n" ); |
23 | |
24 | else
|
25 | uart_puts( "Diesen Motor gibt es nicht!\n" ); |
26 | }
|
27 | }
|
Verbinde dich wieder mit dem Terminalprogramm zum µC und gib ein: 0 200 (und natürlich Return drücken) Der µC sollte antworten mit: Ihre Eingabe: 0 200 Setze Motor 0 auf neuen Wert 1 154 Ihre Eingabe: 1 154 Setzte Motor 1 auf neuen Wert 2 300 Diesen Motor gibt es nicht!
hallo Karl Heinz! vielen dank für deine ausführlichen beschreibungen und code-auszüge. sie haben mein problem vollständig gelöst. leider kann ich das ergebnis erst in zwei tagen begutachten, da sich mein uc gestern abend verabschiedet hat... vielen dank! gruß, Floyd
Ich hoffe mal, dassich nicht allzuviele Fehler eingebaut habe. Ein Fehler ist beim direkten eintippen in da Forum immer drinnen. Wenn du noch Probleme hast: gerne wieder.
hab gerade noch einen uc gekauft, da ich neugierig geworden bin. ist mir jetzt wirklich schon peinlich, aber ich hab da ein kleines problem mit dem code. definiere ich buffer im uc läuft die identifizierung einwandfrei. lese ich jedoch über den uart den string ein, wird nur "uart_gets(Buffer)" aufgerufen und danach ist schluß. woran liegt es? hab gerade echt ein brett vorm kopf... der code: #include <avr/io.h> #include <stdio.h> #include <string.h> int MotorNr; char Buffer[20]; //char Buffer[]="1 255\n"; // Sendet ein einzelnes Zeichen void uart_putc( char c ) { // Warte bis die Sendeeinheit bereit ist while( !(UCSRA & ( 1<<UDRE) ) ) ; UDR = c; } // Sende einen C-String void uart_puts( const char* str ) { while( *str ) { uart_putc( *str ); str++; } } // Ausgabe mit printf über USART static int uart_putchar(char c, FILE *stream); static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); static int uart_putchar(char c, FILE *stream) { if (c == '\n') uart_putchar('\r', stream); loop_until_bit_is_set(UCSRA, UDRE); UDR = c; return 0; } unsigned char USART_RX(void) { while(!(UCSRA&(1<<RXC))) ; return UDR; } void uart_gets( char* Input ) { char c = USART_RX(); uart_putc( c ); while( c != '\n' ) { *Input = c; Input++; c = USART_RX(); uart_putc( c ); } *Input = '\0'; } void uart_init(void) { UBRRH = 0x00; UBRRL = 0x17; UCSRA = 0x00; UCSRB = 0x18; UCSRC = 0x86; } int main(void) { PORTD=0x00; DDRD=0xB0; TCCR1A=0xA1; TCCR1B=0x0B; TCNT1H=0x00; TCNT1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // USART initialisieren uart_init(); while(1) { uart_gets(Buffer); uart_puts( "Ihre Eingabe: " ); uart_puts( Buffer ); uart_putc( '\n' ); MotorNr = Buffer[0] - '0'; // Die Motornummer nummerisch machen OCR1AL = atoi( &Buffer[2] ); // Den PWM Wert umrechnen lassen if( MotorNr == 0 ) { uart_puts( "Setze Motor 0 auf neuen Wert\n" ); stdout = &mystdout; printf(" Dieser ist: %u\n",OCR1AL); } else if( MotorNr == 1 ) { uart_puts( "Setze Motor 1 auf neuen Wert\n" ); stdout = &mystdout; printf(" Dieser ist: %u\n",OCR1AL); } else uart_puts( "Diesen Motor gibt es nicht!\n" ); // Ende vom while } // Ende der main } vielen dank im voraus. Floyd
Dein uart_gets() liest ein bis ein '\n' (=LINEFEED) kommt. Schickt dein PC Terminalprogramm überhaupt solche Zeichen oder schickt es beim Drücken von RETURN nur '\r' (=CARRIAGE RETURN)?
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.