Hi, und zwar ist mir gestern Abend an meinem ATMEGA8535 mit T6963 Display folgendes aufgefallen In meinem Hauptprogramm verwende ich diesen Code: while() { if(tasten() == 3) tagesprofil(); } Wenn ich meinen Hex Code in meinen ATMEGA8535 lade dann wird auch alles auf meinem Display angezeigt. Nur meine Uhr bleibt komischerweise stehe. Ich vermute dass es an dem "getchar()" liegt. Denn wenn ich diese if Anweisung entferne, dann funzt auch alles super. Ich Verwende den sende und empfangs Interrupt der UART den AD Wandler und den "TIM1_COMPA" Interrupt. Was könnte da falsch sein? interrupt [USART_RXC] void uart_rx_isr(void) { uart_recieve = UDR; } interrupt [USART_TXC] void uart_tx_isr(void) { } void tagesprofil (void) { unsigned char n, m; for (n=0; n<24; ++n) { if (n == 0) { putchar('T'); } sprintf (printbuf,"%4d %2d.%2d.%2d ",2006,(int)12,(int)16,(int)n); sprintf (printbuf+15,"%4d%3d",1014,(int)23); *(printbuf+24) = 0x0d; *(printbuf+25) = 0x0a; for (m=0; m<26; ++m) { putchar(*(printbuf + m)); } {unsigned int i; for (i=1000; i>0; --i);} } putchar('E'); } unsigned int readADC_10BIT(unsigned char channel) { unsigned char m; unsigned int result; ADCSRA = 0x86; // Frequenzvorteiler // setzen auf 64 (1) und ADC aktivieren (1) ADMUX = channel; // Kanal waehlen ADMUX |= 0x40; // AVCC als Referenzspannung nutzen /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */ ADCSRA |= 0x40; // eine ADC-Wandlung while(!(ADCSRA & 0x10)); // auf Abschluss der Konvertierung warten (ADIF-bit) result = 0; /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */ for(m=0;m<4;m++) { ADCSRA |= 0x40; // eine Wandlung "single conversion" while(!(ADCSRA & 0x10)); // auf Abschluss der Konvertierung warten (ADIF-bit) result += (ADCL + (ADCH<<8)); // mit uint16_t x //result += ADC; // Wandlungsergebnisse aufaddieren } ADCSRA &= ~0x80; // ADC deaktivieren (2) result >>= 2; // Summe durch vier teilen = arithm. Mittelwert return result; } interrupt [TIM1_COMPA] void timer1_compa_isr(void) { #if XTAL % DEBOUNCE // bei rest OCR1A = XTAL / DEBOUNCE - 1; // compare DEBOUNCE - 1 times #endif if( --prescaler == 0 ) { prescaler = DEBOUNCE; sekunde++; // exact one second over Uhrzeit(sekunde); tasten(); #if XTAL % DEBOUNCE // handle remainder OCR1A = XTAL / DEBOUNCE + XTAL % DEBOUNCE - 1; // compare once per second #endif } }
Shit ich habe mich da oben vertan ich habe den Code benutzt. while() { if(getchar() == 'h') tagesprofil(); } Wenn ich in dem Hauptprogramm dies hier vewende: while() { if(tasten() == 3) tagesprofil(); } Dann tut es auch korrekt. Also die Uhr bleibt dann in der Anzeige(Display) nicht sethen
Ich kenn mich nicht so damit aus, aber von C++ kenne ich ein getch() - welches auf die Tasteneingabe wartet. Mit if prüfst du einen Wert - hier ist es egal, ob der Wert übergeben wurde.
Ja ich ich weiss da nicht weiter. Wie gesagt meine Uhr auf dem Display läuft da nicht mehr. Nur wenn ich eine Anforderung sende, dass das Tagesprofil gesendet werden soll, dann läuft die Uhr kurz weiter. Ich glaube schon dass der Timer da ganz normal arbeitet. Es hängt möglicherweise mit dem Display zusammen. Hmmmm...
kommt getchar() nicht erst zurück, wenn ein Zeichen empfangen wurde ? Damit würde Dein System stehen.
Hmmm...ich habe halt deswegen die Funktion getchar() verwendet, weil ich von der UART auf ein bestimmtes Zeichen warte und dann soll die entsprechende Aktion ausgeführt werden. In diesem Falle wird das Tagesprofil gesendet. Welche Funktion müsste ich dann verwenden um ein Zeichen von der UART zu empfangen(Controller)?
einfach einen neue Function schreiben. char rec_char(void) { if((UCSRA & (1<<RXC))); return UDR; else return 0x00; }
Die Funktion hab ich mal getestet. Funzt nicht! Wenn ich die Funktion uart_recieve() ausführe und ich sende vom PC aus ein Zeichen dann hört die UART nicht mehr auf zu empfangen. Kann ich überhaupt die UART Interrupt so verwenden? interrupt [USART_RXC] void uart_rx_isr(void) { uart_recieve = UDR; } interrupt [USART_TXC] void uart_tx_isr(void) { } unsigned char uart_recieve(void) { while(!(UCSRA & 0x80)) return UDR; }
Wenn ich es so mache wie Steffen beschrieben hat, dann tut sich gar nix. char rec_char(void) { if((UCSRA & (1<<RXC))); return UDR; else return 0x00; } Stimmt der Code wirklich?
Also das mit der UART klappt nach nicht so richtig. Ich habe mich entschlossen das ganze ohne UART Interrupt zu machen. unsigned char uart_recieve(void) { while(!(UCSRA & 0x80)) return UDR; } unsigned char uart_transmit(void) { while(!(UCSRA & 0x20)) UDR = data; } Die uart_transmit Funktion tut soweit. Die andere Funktion funktioniert noch nicht. Die UART tue ich im Hauptprogramm so initialisieren: UCSRB = 0x18; //ohne Interrupt //für Interrupt 0xD8 verwenden: UBRRH = 0; UBRRL = 0x33; Was ist in meiner Empfangfunktion falsch?
solltest Du nicht auch noch mitteilen, dass das Zeichen abgeholt wurde? interrupt [USART_RXC] void uart_rx_isr(void) { uart_recieve = UDR; lösche_IRQ_Flag(); } kenn mich mit Atmel wenig aus. Steffen löst es mit Polling, es gilt: entweder pollen oder mit Interrupt
Ich verwende keinen Interrupt. Ich habe zwei Funktionen. unsigned char uart_recieve(void) { while(!(UCSRA & 0x80)) return UDR; } unsigned char uart_transmit(void) { while(!(UCSRA & 0x20)) UDR = data; } Nur die uart_recieve Funktion tut gar nicht.
warum lässt du die uhr nicht per interrupt aktualisieren? dann kann das hauptprogramm auf ungestört auf deine anfragen reagieren und deine uhr läuft ordentlich. wenn das display ein busy flag hat, dann ist das mit dem schreiben auf das display auch nicht schlimm. das hauptprogramm muss halt vor jedem schreiben auf das fertigstellen des kommandos im display warten. in der isr brauchst du nur auf das display schreiben und eigentlich nicht warten, bis es fertig ist.
Hmmm..wei meinst du das genau? Wie müsste die uart_recieve() FUnktion korrekt aussehen?
Ich lasse doch bei mir die Uhr per Interrupt aktualisieren. Ich verwende den Timer Compare. Und da wird meine Uhrzeit aktualisiert. Deshalb verstehe ich das nicht was hans dieter da geschrieben hat. Ich hab ein Problem mit dem Empfangen von der UART. Die uart_recieve Funktion tut nicht. Senden funktioniert ja. Muss ich bei der uart_recieve Funktion irgend ein Bit löschen? Als Controller verwende ich den ATMEGA8535 unsigned char uart_recieve(void) { while(!(UCSRA & 0x80)) return UDR; } unsigned char uart_transmit(void) { while(!(UCSRA & 0x20)) UDR = data; }
Bei Deiner uart_receive-Funktion kommt ein unbekannter Wert zurück, falls nichts im UDR drinnen ist. Ich verwende in solchen Fällen zwei Funktionen für den Empfang: uint8_t get_serial_status(void) { if (bit_is_set(UCSRA,RXC)) return 1; else return 0; } uint8_t get_serial(void) { return UDR; } Im Hauptprogramm frage ich dann erstmal den Status ab. Falls der Status = 0, muss das Hauptprogramm einfach weitermachen, ohne etwas von der seriellen Schnittstelle abzuholen. <-- Das ist wichig. Wenn Du auf die serielle Schnittstelle wartest, wird währenddessen das LCD nicht mehr aktualisiert. Ist der Status = 1, lese ich die serielle Schnittstelle aus und verarbeite die Daten. Noch ein kleiner Tipp am Rande: Man verwendet sinnvollerweise keine Konstanten bei dem Setzen von Bits, sondern die Bezeichnungen aus dem Datenblatt. Das macht den Code lesbarer.
schau mal im Datenblatt, ob das Lesen des UDR das Bit7 (RXC) im UCSRA wieder zurücksetzt, oder ob Du das selbst machen musst.
Super! Ich kann jetzt von der UART senden und empfangen. Leider funzt es noch als nicht zu 100% korrekt. Ich habe in meiner Main in der while Schleife drei if Bedingungen eingebaut. if(uart_recieve() == 'A') { test(); } if(uart_recieve() == 'B') { uart_transmit('E'); } if(uart_recieve() == 'C') { tagesprofil(); } Wenn ich das Zeichen 'A' an den Controller sende dann sendet der Controller auch --> test(); Wenn ich das Zeichen 'B' oder 'C' sende dann sendet der Controller da nix.Überhaupt kein Zeichen. nur wenn ich wieder das Zeichen 'A' sende dann tut es. Wenn ich das Zeichen'B' sende warum tut sich da nichts? Ich habe mal das Register UCSRA in der while Schleife ausgelesen. Am Anfang steht dort 0x20 wenn ich das Zeichen 'A' drücke dann erscheint der HEX Wert 0x60. Warscheinlich muss man das TxC Register wieder löschen oder? Wie kann ich denn von dem UCSRA Register das 7Bit löschen? //Funktionen zur UART void uart_transmit(unsigned char data) { while(!(UCSRA & 0x20)); UDR = data; } unsigned char uart_recieve(void) { while((UCSRA & 0x80)) return UDR; }
> if(uart_recieve() == 'A') > { > test(); > } > if(uart_recieve() == 'B') > { > uart_transmit('E'); > } > if(uart_recieve() == 'C') > { > tagesprofil(); > } Der Code versucht insgesammt 3 mal zu lesen. D.h. Wenn Du B tippst und die Code Sequenz ganz am Anfang steht, so wird das nicht ausgewertet (da ja kein 'A'). In den Zweig fuer 'B' kommt er aber auch nicht rein, da Du ja wieder uart_receive() aufrufst und da kommt dann nichts mehr (das 'B' das du ueber die Serielle geschickt hast wurde ja bereits vom vorhergehenden if weggefressen). Machs mal so: char Zeichen; ... zeichen = uart_receive(); if( zeichen == 'A' ) { } else if( zeichen == 'B' ) { } else if( zeichen == 'C' ) { }
Oder: switch (uart_receive()) { case 'A': mach irgendwas break; case 'B': .... break; case 'C': .... break; usw. usw. }
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.