Hab heute ein für ein sehr uniques Vorhaben eine Kleinigkeit gemacht -
Hatte ursprünglich gar nicht vor, das zu Posten, aber ich im Laufe über
zwei kleine Kopfnüsse gestolpert, die ich doch ganz nett fand.
Ich brauchte für ein Vorhaben etwas, das aus 4 Signalen für
Modellbauservos ein serielles - das PPM Signal macht.
Damit es nicht zu einfach wird spuckt die Signalquelle die natürlich
NICHT zeitlich versetzt an ihren Pins aus, sondern mit einem
gleichzeitigen Start. Sonst hätte man es vielleicht einfach mit etwas
Diodenlogik lösen können.
Da ich jetzt nicht für jedes Problem mit BluePills um mich feuern will
weil die so schön viele Timer und CC-Register hat, hab ich es auf einem
Mega8 gemacht, der noch da ist.
>>Mh... okay 4 parallele Signale sampeln, die nicht mega weit von der
Systemgeschwindigkeit weg sind. Na gut - wenn´s schee macht...
Am Ende ist es auf ein abgewandeltes Konzept hinaus gelaufen, wie ich es
auf einem Tiny gemacht habe. .
Hilfreich ist, dass das Einlesen der 4 parallelen Eingangssignale und
das anschließend serielle ausgeben, aus PPM Sicht die Dauer von 5
Kanälen hat, was in das 20ms Fenster passt.
So entstand die Idee den Tiny-Ansatz zu übernehmen, die gesamte Sache
stumpf und ausschließlich in der Mainloop laufen zu lassen und den
Start der Einganssignalperiode als Startschuss für die
Sample-Generate-Loop zu nehmen.
Der Schuss ist, wenn alle Eingangssignale high sind. Gleich kommt was zu
der impliziten Flankenerkennung.
Die Eingangssignale hängen alle an PORTC0:3 und werden einfach durch
Einlesen von PORTC & 15 gemacht. Als ich so am rumdebuggen war, hab ich
die Anzahl der gesampelten Kanäle bis 1 verringert und beim späteren
erhöhen übersehen, dass PORTC0:3 bitstuffed ist und eine Erhöhung von 1
auf 2 nicht der Hinzunahme eines weiteren Kanals entspricht. So kamen
auf dem Oszi originelle Flankenmuster raus.
Sind alle Signale high, werden sie in einer While-Loop gesampelt, bis
alle wieder Low sind. -> Hier ist die Flankenerkennung :)
> Hier war die zweite Kopfnuss fällig.
Natürlich brauchen alle Eingangssignale ein Flag, ob sie schon zu Ende
gesamplet wurden. Sonst werden sie ja laufend überschrieben.
Hatte ich natürlich zu erst nicht dran gedacht, sah auf dem Oszi im
Ausgangssignal nur so aus, als ob alle Eingangssignale "irgendwie
komisch" zusammenhängen.
Die Outputerzeugung läuft im Spaghetti-Style in 4 Blöcken +
Abschluss"höcker" ab. Hab versucht aus zu baldovern, ob sich einer der
PWM Modi eignet. Aber ich war mir ohne längerwieriges Einlesen in die
genauen Details der Modi nicht ausreichend sicher.
Das nicht ausreichend sicher in begrenzter Zeit raus zu kriegen und dem
Gefühl der Restunsicherheit und das sich diese eventuellen Effekte mit
anderen Bugs mischen hat mich zur aktuellen Spaghetti-Lösung kommen
lassen.
1 | #include <avr/io.h>
|
2 | #include <avr/interrupt.h>
|
3 | #include <stdint.h>
|
4 |
|
5 | volatile unsigned int pulseArr[4] = {1000, 1300, 1600, 2000};
|
6 |
|
7 | int main(void)
|
8 | {
|
9 | unsigned int tickCntr = 0;
|
10 | char tmpPin, allDoneFlags = 15;
|
11 | DDRB = 2;
|
12 | TCCR1B = 0b00000010;
|
13 | while(1)
|
14 | {
|
15 | /* */
|
16 |
|
17 | PORTB = 0;
|
18 | pulseArr[0] = 0;
|
19 | pulseArr[1] = 0;
|
20 | pulseArr[2] = 0;
|
21 | pulseArr[3] = 0;
|
22 |
|
23 | while(1)//wait for all Pins to be high
|
24 | {
|
25 | tmpPin = PINC & 2;
|
26 | if(tmpPin == 2)break; //then all Pins are high
|
27 | }
|
28 |
|
29 | TCNT1 = 0;
|
30 | while(TCNT1 < 100)//avoid possible flickers
|
31 | {
|
32 | }
|
33 |
|
34 | allDoneFlags = 15;
|
35 | while(allDoneFlags != 0)//runs as long until all Pins are low again
|
36 | {
|
37 | tmpPin = PINC & 15;
|
38 | allDoneFlags &= tmpPin;
|
39 |
|
40 | //The "(pulseArr['n'] == 0)" checks are used as a flag that the certain channel is measured
|
41 | // Otherwise it gets permanently overwritten
|
42 | if(((tmpPin & 1) == 0) && (pulseArr[0] == 0))pulseArr[0] = TCNT1;
|
43 | if(((tmpPin & 2) == 0) && (pulseArr[1] == 0))pulseArr[1] = TCNT1;
|
44 | if(((tmpPin & 4) == 0) && (pulseArr[2] == 0))pulseArr[2] = TCNT1;
|
45 | if(((tmpPin & 8) == 0) && (pulseArr[3] == 0))pulseArr[3] = TCNT1;
|
46 | // Pssst... (honestly here is (at least technically) some jitter going on)
|
47 | }
|
48 |
|
49 | // subtract the 1ms offset from the 1.5 ms signal
|
50 | if(pulseArr[0] < 1000)pulseArr[0] = 0;
|
51 | else pulseArr[0] -= 1000;
|
52 |
|
53 | if(pulseArr[1] < 1000)pulseArr[1] = 0;
|
54 | else pulseArr[1] -= 1000;
|
55 |
|
56 | if(pulseArr[2] < 1000)pulseArr[2] = 0;
|
57 | else pulseArr[2] -= 1000;
|
58 |
|
59 | if(pulseArr[3] < 1000)pulseArr[3] = 0;
|
60 | else pulseArr[3] -= 1000;
|
61 |
|
62 | //do the pulses of the 4 channels after another
|
63 | PORTB = 2;
|
64 | TCNT1 = 0;
|
65 | OCR1A = 400;
|
66 | TIFR |= 0b00010000;
|
67 | while(!(TIFR & 0b00010000));
|
68 | PORTB = 0;
|
69 | TCNT1 = 0;
|
70 | OCR1A = pulseArr[0]+600;
|
71 | TIFR |= 0b00010000;
|
72 | while(!(TIFR & 0b00010000));
|
73 |
|
74 | PORTB = 2;
|
75 | TCNT1 = 0;
|
76 | OCR1A = 400;
|
77 | TIFR |= 0b00010000;
|
78 | while(!(TIFR & 0b00010000));
|
79 | PORTB = 0;
|
80 | TCNT1 = 0;
|
81 | OCR1A = pulseArr[1]+600;
|
82 | TIFR |= 0b00010000;
|
83 | while(!(TIFR & 0b00010000));
|
84 |
|
85 | PORTB = 2;
|
86 | TCNT1 = 0;
|
87 | OCR1A = 400;
|
88 | TIFR |= 0b00010000;
|
89 | while(!(TIFR & 0b00010000));
|
90 | PORTB = 0;
|
91 | TCNT1 = 0;
|
92 | OCR1A = pulseArr[2]+600;
|
93 | TIFR |= 0b00010000;
|
94 | while(!(TIFR & 0b00010000));
|
95 |
|
96 | PORTB = 2;
|
97 | TCNT1 = 0;
|
98 | OCR1A = 400;
|
99 | TIFR |= 0b00010000;
|
100 | while(!(TIFR & 0b00010000));
|
101 | PORTB = 0;
|
102 | TCNT1 = 0;
|
103 | OCR1A = pulseArr[3]+600;
|
104 | TIFR |= 0b00010000;
|
105 | while(!(TIFR & 0b00010000));
|
106 |
|
107 | // "Stop token"
|
108 | PORTB = 2;
|
109 | TCNT1 = 0;
|
110 | OCR1A = 400;
|
111 | TIFR |= 0b00010000;
|
112 | while(!(TIFR & 0b00010000));
|
113 | PORTB = 0;
|
114 | }
|
115 | }
|