Folgendes Programm für ATmega48pa @ 1.5 MHz schaltet den TXD im sleep
mode power-down auf low:
1 | #include <stdint.h>
|
2 | #include <stdbool.h>
|
3 | #include <avr/io.h>
|
4 | #include <avr/wdt.h>
|
5 | #include <avr/sleep.h>
|
6 | #ifdef sleep_mode
|
7 | #undef sleep_mode
|
8 | #define sleep_mode()\
|
9 | cli();\
|
10 | MCUCR |= 1<<SE;\
|
11 | sei();\
|
12 | asm volatile("sleep");\
|
13 | cli();\
|
14 | MCUCR &= ~(1<<SE);\
|
15 | sei();
|
16 | #endif
|
17 | #include <avr/interrupt.h>
|
18 |
|
19 | void uart_putchar( char c )
|
20 | {
|
21 | while ( !( UCSR0A & (1<<UDRE0)) );
|
22 | UDR0 = c;
|
23 | return;
|
24 | }
|
25 |
|
26 | int main(void)
|
27 | {
|
28 | wdt_disable();
|
29 | ACSR = (1<<ACD);
|
30 | MCUCR |= (1<<BODS);
|
31 |
|
32 | #define BAUD 9600UL // Baudrate
|
33 | #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // clever runden
|
34 | #define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) // Reale Baudrate
|
35 | #define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
|
36 | #if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
|
37 | #warning Fehler der Baudrate ist groesser als 1% !
|
38 | #endif
|
39 | UBRR0 = UBRR_VAL;
|
40 | UCSR0B = (1<<TXEN0);
|
41 | UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
|
42 |
|
43 | uart_putchar( 'H' );
|
44 | uart_putchar( 'E' );
|
45 | uart_putchar( 'L' );
|
46 | uart_putchar( 'L' );
|
47 | uart_putchar( 'O' );
|
48 | uart_putchar( '\n' );
|
49 |
|
50 | TCNT1 = 0;
|
51 | OCR1A = 2047;
|
52 | OCR1B = 0;
|
53 | TCCR1A = 0;
|
54 | TCCR1B = (1<<CS12)| (1<<CS10);
|
55 | TIMSK1 = (1<<OCIE1A);
|
56 |
|
57 | set_sleep_mode(SLEEP_MODE_IDLE);
|
58 | sei();
|
59 | while(1)
|
60 | {
|
61 | uart_putchar( 'S' );
|
62 |
|
63 | //sleep_mode();
|
64 | cli();
|
65 | sleep_enable();
|
66 | sei();
|
67 |
|
68 | sleep_cpu();
|
69 |
|
70 | cli();
|
71 | sleep_disable();
|
72 | sei();
|
73 |
|
74 | uart_putchar( 'W' );
|
75 | }
|
76 | }
|
77 |
|
78 | ISR( TIMER1_COMPA_vect )
|
79 | {
|
80 | uart_putchar( 'T' );
|
81 | set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
82 | }
|
Was dazu führt, dass die Gegenseite eine 0 empfängt:
Wenn man den USART nach Initialisierung gleich wieder mit PRR =
(1<<PRUSART0); abschaltet, passiert dies auch:
In der Doku finde ich nur folgendes:
> The Transmitter will override normal port operation for the TxDn pin when
enabled.
> When disabled, the Transmitter will no longer override the TxDn pin.
Also selbst, wenn, wie im letzten Fall, der USART mitten in der
Übertragung abgeschaltet wird, sollte der Pin doch eigentlich wieder zum
Eingang (high-Z) werden!?
Auch das Deaktivieren ändert daran nichts:
1 | ...
|
2 | UBRR0 = UBRR_VAL;
|
3 | UCSR0B = (1<<TXEN0);
|
4 | UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
|
5 | uart_putchar( 'H' );
|
6 | PRR = (1<<PRUSART0);
|
7 | UCSR0B = 0;
|
8 | while(1);
|
Auch das Warten auf Übertragungsende mit while ( !( UCSR0A & (1<<UDRE0))
); ändert nichts.
Reihenfolge ändern (PRR nach UCSR0B) bringt auch nichts -> Power-Down
und PRR schalten TX low!
Ausnahme offenbar: UCSR0B = 0; vor Power-down.
Soll das so sein, wo ist es dokumentiert?