Hallo zusammen, Habe ein kleines Problem. Möchte eine Zahl über ein Terminalprogramm einlesen und diese dann als Integer in einer Variablen speichern. Danach soll die Zahl zur Kontrolle wieder ausgegeben werden. Das funktioniert auch soweit schon recht gut, allerdings soll die Variable bis zur ersten Eingabe schon einen vorbestimmten Wert besitzen und diesen dann erst bei der ersten Eingabe ändern. Habe versucht diesen Wert in den String einzugeben, allerdings bekomme ich bisher immer nur Null zurück. Würde mich freuen wenn mir jemand einen Tip geben könnte. Gruß Andreas #include <avr/io.h> #include <avr/interrupt.h> #include <inttypes.h> #include <string.h> #include <stdlib.h> #define BAUD 9600UL #define UBRR_BAUD ((F_CPU/(8UL*BAUD))-1) #define UART_MAXSTRLEN 5 volatile uint16_t x; volatile uint8_t uart_str_complete = 0; // 1 .. String komplett empfangen volatile uint8_t uart_str_count = 0; char uart_string[6] = "2200"; char s [5]; void uart_init(void) { // Baudrate einstellen (Normaler Modus) UBRR3H = (uint8_t) (UBRR_BAUD>>8); UBRR3L = (uint8_t) (UBRR_BAUD); UCSR3A= (1<<U2X3); // U2X auf LO // Aktivieren von receiver und transmitter UCSR3B = (1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3); // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit UCSR3C = (1<<UCSZ31)|(1<<UCSZ30); } int uart_putc(unsigned char c) { while (!(UCSR3A & (1<<UDRE3))) /* warten bis Senden moeglich */ { } UDR3 = c; /* sende Zeichen */ return 0; } void uart_puts (char *s) { while (*s) { /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */ uart_putc(*s); s++; } } int main(void) { TCCR3B = (1<<CS32) | (1<<CS30); //Timer 3 initalisieren (Prescaler 1024) TIMSK3 |= (1<<TOIE3); //Timer 3 overflow erlauben TCCR4A = (1<<WGM41) | (1<<COM4C1); //PWM Mode 14 TCCR4B = (1<<WGM42) | (1<<WGM43) | (1<<CS41); //PWM Mode 14 und Prescaler 8 ICR4 = 40000; //PWM Frequenz 50Hz (50Hz=16MHz/8*40000) //OCR4C = x; //An-Zeit 1,5ms (16MHz*1,5ms/8) DDRH |= (1<<PH5); //OCR4C auf Ausgang uart_init(); // USART initialisieren sei(); while (1) { char tmp[5]; strcpy ( tmp, uart_string); uint16_t x = atoi( tmp ); OCR4C = x; } } ISR(USART3_RX_vect) { unsigned char nextChar; // Daten aus dem Puffer lesen nextChar = UDR3; if( uart_str_complete == 0 ) { // wenn uart_string gerade in Verwendung, neues Zeichen verwerfen // Daten werden erst in uart_string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird if( nextChar != '\n' && nextChar != '\r' && uart_str_count < UART_MAXSTRLEN - 1 ) { uart_string[uart_str_count] = nextChar; uart_str_count++; } else { uart_string[uart_str_count] = '\0'; uart_str_count = 0; uart_str_complete = 0; } } } ISR (TIMER3_OVF_vect) { itoa (x, s, 10); strcat ( s, " "); uart_puts(s); }
Du schreibst in einer Endlosschleife den Wert aus dem String in ein lokales x, gibst aber in deiner ISR das globale x aus.
Andreas H. schrieb:
1 | ISR (TIMER3_OVF_vect) |
2 | {
|
3 | itoa (x, s, 10); |
4 | strcat ( s, " "); |
5 | uart_puts(s); |
6 | }
|
Mal vorab:
In einer Interruptroutine werden keine String-Operationen und schon
gleich gar keine UART-Zeichenkettensenderoutinen ausgeführt. Eine
Interruptroutine muss so schnell wie möglich beendet werden.
Eine Frage: warum speicherst du den Wert 2x? Einmal als String und
einmal als Zahl? Das ist nämlich dein Problem.
Ich würde den Wert nur als Variable x speichern, und bei Bedarf aus
dieser in einen String (zum Senden) umwandeln. Oder andersrum: sofort
nachdem der String empfangen wurde, wird er in eine Zahl umgewandelt.
Andreas H. schrieb:
1 | volatile uint16_t x; |
2 | :
|
3 | {
|
4 | uint16_t x = atoi( tmp ); |
5 | OCR4C = x; |
6 | }
|
7 | :
|
8 | itoa (x, s, 10); // welches x denn? |
Na toll... Als Tipp: es sind auch andere Variablennamen anstelle von x zulässig. Z.B. auch reloadwert o.ä.
Lothar Miller schrieb: > Ich würde den Wert nur als Variable x speichern, und bei Bedarf aus > dieser in einen String (zum Senden) umwandeln. Oder andersrum: sofort > nachdem der String empfangen wurde, wird er in eine Zahl umgewandelt. Genau das macht er doch. Da der String aber in der Empfangs-ISR Zeichen für Zeichen eintröpfelt, muß er sich ja den bisherigen String irgendwo speichern, bis er komplett ist. Bisher wartet er aber mit der Konvertierung nicht, bis der String komplett angekommen ist, sondern läßt sie ständig laufen.
Andreas H. schrieb: > Würde > mich freuen wenn mir jemand einen Tip geben könnte. Dein ganzes Programm ist seltsam zusammengewürfelt. Wozu den STring vorbelegen? Braucht doch kein Mensch. Du hast eine Variable x (die solltest du wirklich umbenennen). Von der hängt alles weitere ab. Also gibst du der einen Startwert. Und wenn über die UART ein neuer kompletter String reingekommen ist, dann wandelst du den in eine Zahl und weist diesem x diese Zahl zu. Wo ist das Problem?
1 | int main(void) |
2 | {
|
3 | x = 128; |
4 | |
5 | ...
|
6 | |
7 | uart_init(); // USART initialisieren |
8 | |
9 | sei(); |
10 | |
11 | while (1) |
12 | {
|
13 | if( uart_str_complete ) { |
14 | x = atoi( uart_string ); |
15 | uart_str_complete = 0; |
16 | |
17 | OCR4C = x; |
18 | |
19 | itoa( x, s, 10 ); |
20 | strcat( s, " " ); |
21 | uart_puts( s ); |
22 | }
|
23 | }
|
24 | }
|
Und den Timer 3 Overflow legst du klammheimlich ganz schnell wieder still.
Hallo, Kreuzigt mich doch bitte nicht gleich. Beschäftige mich erst seit 3 Wochen mit Mikrokontrollern. Das mit der ISR muss ich mir dann mal überlegen wie ich den String ungefähr alle 4s neu ausgeben kann. Die Ausgabe klappt ja bisher auch. Mein Problem war eigentlich, dass ich bevor ich eine Eingabe mache immer nur Null rausbekomme obwohl in uart_string eigentlich 2200 stehen müsste. Werde mich aber trotzdem mal darum kümmern eure Tipps einzuarbeiten. Gruß Andreas
Andreas H. schrieb: > Das mit der ISR muss ich mir dann mal überlegen wie ich den String > ungefähr alle 4s neu ausgeben kann. Du setzt mit einem Timerinterrupt nach 4 Sekunden ein Flag und fragst das in der Hauptschleife ab. Denn: ob der String nach 4,000000 Sekunden oder z.B. nach 4,000062 Sekunden verschickt wird, das dürfte recht egal sein... Dann könnte das etwa so aussehen:
1 | volatile char Flag_4sec = 0; |
2 | |
3 | TimerISR() // initialisiert so, dass sie z.B. alle 10ms aufgrufen wird |
4 | {
|
5 | :
|
6 | if (++Cnt_4sec == 400) { |
7 | Flag_4sec= 1; |
8 | Cnt_4sec = 0; |
9 | }
|
10 | :
|
11 | :
|
12 | }
|
13 | |
14 | UART_ISR() |
15 | {
|
16 | :
|
17 | :
|
18 | }
|
19 | |
20 | main() |
21 | {
|
22 | |
23 | while(1) { // die ewige Hauptschleife |
24 | :
|
25 | if (Flag_4sec) { |
26 | SendeDenWertMitDemUART(x); |
27 | Flag_4sec = 0; |
28 | }
|
29 | |
30 | if (uart_str_complete) { |
31 | x = StringInDieVariableEinlesen(); |
32 | uart_str_complete = 0; |
33 | }
|
34 | :
|
35 | }
|
36 | }
|
Ok, danke euch allen für die Hilfe. Das Programm funktioniert jetzt so wie es soll mit dem Tipp von Karl Heinz Buchegger. Und, ja, es sieht zusammengewürfelt aus da ich mich durch mehrere Tutorials gewühlt habe und mir den entsprechenden Quellcode zusammengebastelt hab. Werde das nachher mal gründlich aufräumen und ausmisten müssen.
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.