Ich denke, dass der einfache Interrupt-Weg dafür
funktionieren sollte.
1 | volatile uint8_t rx_char, updated;
|
2 |
|
3 | SIGNAL(SIG_UART0_RECV)
|
4 | {
|
5 | uint8_t c;
|
6 |
|
7 | c = UDR0;
|
8 | UDR1 = c;
|
9 | rx_char = c;
|
10 | updated = 1;
|
11 | }
|
12 |
|
13 | int
|
14 | main(void)
|
15 | {
|
16 | uint8_t state = 0, c;
|
17 |
|
18 | init_uarts();
|
19 | sei();
|
20 |
|
21 | for (;;) {
|
22 | if (updated) {
|
23 | updated = 0;
|
24 | c = rx_char;
|
25 | switch (state) {
|
26 | case 0:
|
27 | case 1:
|
28 | if (c == 0) state++;
|
29 | else state = 0;
|
30 | break;
|
31 | case 2:
|
32 | case 3:
|
33 | if (c == 255') state++;
|
34 | else state = 0;
|
35 | if (state == 4) {
|
36 | state = 0;
|
37 | pull_external_reset();
|
38 | }
|
39 | }
|
40 | }
|
41 | }
|
42 |
|
43 | return 0;
|
44 | }
|
Die Interruptverarbeitung sollte bei einem kontinuierlichen Datenstrom
von 9600 Bd selbst bei 1 MHz Takt kein Thema sein. Die Zeichen kommen
dann ca. alle 1 ms, d.h. zwischen den Zeichen verbleiben knapp 1000
Takte für die Verarbeitung. Die ISR selbst braucht 28 Takte (wenn ich
mich nicht verzählt habe), also 28 µs. Die main loop braucht so 20
... 30 Takte pro Umlauf (je nach Zustand).
Eigentlich könnte man am Ende auch noch ein sleep_mode() plus einen
NOP dransetzen, um die restlichen 950 µs lang Strom zu sparen. Der
Zustand kann sich ja ohnehin erst ändern, nachdem es einen neuen
Rx-Interrupt gab. Den NOP braucht man, weil der meiner Erinnerung
nach nach dem Aufwachen abgearbeitet wird, bevor die Rx-ISR
angesprungen wird, diese aber setzt ja erst das "updated"-Flag.
Ggf.
nach dem Aufwachen so lange Kreise laufen, bis "updated" erschienen
ist.