Hallo zusammen,
ich "spiel" gerade mit dem Sleep-Modes des AVR um in einem kleinen
Hobby-Projekt Strom zu sparen. Im Sleep-Mode "Idle" läuft alles schön,
d.h. er versendet das Zeichen, Antwortet auf empfangene Zeichen und
lässt LEDs blinken.
Nun habe ich aber das Problem das der UART nach dem Sleep-Mode PowerDown
oder ADC nicht mehr richtig sendet, d.h. es kommen falsche Zeichen
"raus".
Die LEDs blinken aber und empfangen wird auch ab und an was.
Meine erste Vermutungen war, das die internen Clock noch nicht richtig
laufen, aber selbst eine Verzögerung von 100ms hat nix gebracht.
Der Controller läuft mit 8Mhz internal RC und der Fuse Clk/8, also mit 1
Mhz. Zum Wecken aus dem Sleep-Mode wird hier der Timer2 als CTC
verwendet
Anbei mein Test-Code in der Hoffnung - das jemand hier sofort "Dödel"
schreit ;)
1 | /* Test Sleep-Modes
|
2 | hardware: AVR Mega168
|
3 | Clock 1Mhz
|
4 | */
|
5 |
|
6 | #define BAUD 4800L // Baudrate/2!
|
7 |
|
8 | // Berechnungen
|
9 | #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // clever runden
|
10 | #define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) // Reale Baudrate
|
11 | #define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) // Fehler in Promille
|
12 |
|
13 | #include <avr/io.h>
|
14 | #include <avr/sleep.h>
|
15 | #include <avr/interrupt.h>
|
16 | #include <util/delay.h>
|
17 |
|
18 | // globale Variablen
|
19 | volatile uint8_t uart_flag;
|
20 | volatile uint8_t uart_data;
|
21 |
|
22 | // funktionen
|
23 | void init_t2(void);
|
24 | void init_uart(void);
|
25 |
|
26 | int main (void) {
|
27 |
|
28 | // IO konfigurieren
|
29 | //DDRA = 0xFF;
|
30 | DDRB = 0xFF;
|
31 | DDRC = 0xFF;
|
32 | DDRD = 0xFF;
|
33 | // UART konfigurieren
|
34 | init_uart();
|
35 | // Timer 2
|
36 | init_t2();
|
37 | // Interrupts freigeben
|
38 | sei();
|
39 | // Endlose Hauptschleife
|
40 | while(1) {
|
41 | //set_sleep_mode(SLEEP_MODE_IDLE);
|
42 | //set_sleep_mode(SLEEP_MODE_ADC);
|
43 | set_sleep_mode(SLEEP_MODE_PWR_SAVE);
|
44 | sleep_mode(); // in den Schlafmodus wechseln
|
45 | // init_uart();
|
46 | _delay_ms(10);
|
47 | // hier wachen wir wieder auf
|
48 | if (uart_flag==1) {
|
49 | uart_flag =0;
|
50 | PORTB ^= (1 << PB0); // LED an/aus wenn zeichen Empfangen
|
51 | while ((UCSR0A & 1<<UDRE0) == 0);
|
52 | UDR0 = uart_data;
|
53 | }
|
54 | // Sende Zeichen '_'
|
55 | while ((UCSR0A & 1<<UDRE0) == 0);
|
56 | UDR0 = 95;
|
57 | }
|
58 | } // Ende Main
|
59 | /****************************************************************************/
|
60 | /* Timer/Counter2 Compare Match A */
|
61 | ISR (TIMER2_COMPA_vect) {
|
62 | PORTB ^= 1<<PB1; // Toggle bit
|
63 | }
|
64 |
|
65 | // UART RX complete interrupt
|
66 |
|
67 | ISR(USART_RX_vect) {
|
68 | uart_flag = 1; // signalisiere neue Daten
|
69 | uart_data = UDR0; // Daten auslesen, dadurch wird auch der Interrupt gelöscht
|
70 | PORTB ^= 1<<PB2; // Toggle bit
|
71 | }
|
72 |
|
73 | void init_t2(void){
|
74 | TCCR2A = 0x00;
|
75 | TCCR2A |= (1<<WGM21)|(0<<WGM20) // Waveform Generation Mode: CTC -WGM22=0
|
76 | | (0<<COM2A1)|(0<<COM2A0); // Compare Output Mode, Non-PWM Mode - disconnect OC2
|
77 | TCCR2B = 0x00;
|
78 | TCCR2B &= ~(1<<WGM22); // Waveform Generation Mode: CTC
|
79 | TCCR2B |= (1<<CS22) |(1<<CS21) |(1<<CS20); // Prescaler 1024
|
80 | OCR2A = 0xFF;
|
81 | ASSR &= ~(1<<AS2); // AS2=0 - clock from internal clock
|
82 | TIMSK2 |= (1<<OCIE2A); //Timer/Counter2 Output Compare Match Interrupt Enable
|
83 | };
|
84 |
|
85 | void init_uart(void){
|
86 | UBRR0H = UBRR_VAL >> 8;
|
87 | UBRR0L = UBRR_VAL & 0xFF;
|
88 | UCSR0B = (1<<RXCIE0) | (1<<RXEN0);
|
89 | UCSR0B |= ( 1 << TXEN0 ) ;
|
90 | UCSR0A |= (1<<U2X0); // double transmission speed
|
91 | }
|