Hallo Gemeinde,
es geht leider schon wieder um das Thema der Impulslängenauswertung,
hier im Beispiel bei einem Empfänger aus dem Modellbaubereich. Ich weiß,
dass es dazu schon einige Beiträge gibt, welche ich auch gelesen habe
aber mir bisher noch nicht den entscheidenden Hinweis zur Fehlerquelle
in meinem Code gebracht haben.
Nachfolgend erstmal der Programmcode:
1
#include<inttypes.h>
2
#include<avr/interrupt.h>
3
#include<avr/io.h>
4
#include<util/delay.h>
5
6
7
volatileuint16_tsignal_1st,signal_2nd;
8
volatileuint16_timpuls;
9
volatileuint8_tkanal=255;
10
volatileuint8_tsetMode=0;
11
volatileuint8_tsignalEnd=0;
12
13
uint16_tsignalLength=0;
14
15
16
ISR(TIMER1_CAPT_vect)
17
{
18
19
switch(setMode)
20
{
21
case0:
22
23
signal_1st=ICR1;
24
25
TCCR1B^=(1<<ICES1);// Capture-Flanke umschalten
26
setMode=1;// Modus "fallende Flanke"
27
break;
28
case1:
29
30
signal_2nd=ICR1;
31
TCCR1B^=(1<<ICES1);// Capture-Flanke umschalten
32
setMode=0;// Modus "steigende Flanke"
33
signalEnd=1;// Variable zum Beginn der Berechnung für die Impulslänge
34
cli();
35
break;
36
}
37
}
38
39
40
intmain(void)
41
{
42
DDRB=0x00;// Port B als Input (inkl. PB0 = ICP1)
43
DDRC=0xff;// Port C als Ausgang
44
45
46
TIMSK|=(1<<TICIE1);// Capture Interrupt enable
47
TCCR1B|=(1<<CS12)|(1<<ICES1);// Prescaler 256 Timer 1, Capture bei steigender Flanke
48
49
sei();// Globale Interruptfreigabe
50
51
52
for(;;)
53
{
54
55
if(signalEnd)
56
{
57
impuls=(signal_2nd-signal_1st);// Differenzwert zwischen steigender und fallender Flanke
58
59
60
61
if(impuls<47)// Vergleichswert für 1,5ms bei 8MHz und TimerPrescaler 256
62
63
PORTC=~0x00;
64
65
else
66
67
PORTC=~0x01;
68
69
70
signalEnd=0;
71
sei();
72
73
}
74
75
}
76
}
Zur Funktion:
Eigentlich ist die Geschichte recht simpel und wird bisher auf einem
STK500 getestet. Die Impulslänge eines Empfängerkanals wird mittels
Timer und "Input Capture" auf eine bestimmte Länge überprüft und damit
einfach zwei Ausgänge geschalten.
In der ISR schalte ich die Flankenerkennung von zuerst "steigend" auf
"fallend" um und berechne aus der Differenz der beiden Werte im ICR1 die
vergangene Zeit.
Jetzt ist das Problem, dass ich praktisch immer (unabhängig von der
Impulslänge) in die erste IF-Anweisung reinlaufe und ich vom errechneten
Wert anscheinend immer unter den 47 bin. Die Impulslängenänderung beim
Bewegen des Knüppels passt (lt. Oszi) und liegt auch am ICP1 an.
Ich sehe jetzt keinen Fehler und kann mir das auch nicht wirklich
erklären. Wäre super, wenn jemand einmal über den Code sehen könnte,
vielleicht bin ich ja einfach nur blind :) Bin für jeden Tipp dankbar.
Gruß
Stefan
schaut doch eigentlich ganz gut aus.
ich bin mir nur nicht so sicher, ob signalEnd nicht immer true ist..
(weil das ja sicherlich existiert)
- ich meine mein avr gcc hätte mir da mal was entsprechendes gesagt..
- kann aber auch sein das das in nem java code war...
geh doch auf nummer sicher und schreib
hmm, "signalEnd" setze ich ja bei der Definition der Variable und in der
IF-Anweisung auf Null. Von daher müsste es eigentlich stimmen.
Ich hab jetzt aus lauter Verzweiflung (weil ich keine Fehler gefunden
habe) am Vergleichswert rumgespielt und siehe da... !
Wenn ich einen VGL-Wert von 6 einstelle, schaltet meine LED um,
allerdings nicht von aus -> ein, sondern sie wird PWM-mäßig getaktet (je
nach Knüppelposition am Sender) bis sie dann bei Vollauschlag dauerhaft
leuchtet. Das dürfte aber doch bei einem Vergleich auf "größer" bzw.
"kleiner" nicht der Fall sein, da ich eine eindeutige Grenze definiere.
Nun stellt sich mir noch die Frage, ob meine Überlegungen zur Berechnung
des Vergleichswertes richtig waren. Bin hier folgendermaßen vorgegangen:
FCPU = 3.69MHZ
Prescaler Timer = 256 --> 1/(3.69MHZ/256) = ~0.07ms
Der Timer wird also alle 0.07ms angetaktet. Für einen Mittelpunktswert
von 1,5ms sollten die beiden Werte im ICR1-Register eine Differenz von
1,5ms/0.07ms = ~22 aufweisen, was meinen Vergleichwert bildet. Ist die
Impulslänge kürzer oder länger bin ich jeweils unter bzw. über diesem
Wert.
Jetzt irritiert mich der Wert von 6 aber, bei dem es funktioniert!? Wo
ist mein Denkfehler? :/
Hier nochmal der Code bei dem es geht:
1
ISR(TIMER1_CAPT_vect)
2
{
3
4
if(setMode==0)
5
{
6
signal_1st=ICR1;
7
8
TCCR1B^=(1<<ICES1);// Capture-Flanke umschalten
9
setMode=1;// Modus "fallende Flanke"
10
}
11
12
elseif(setMode==1)
13
{
14
signal_2nd=ICR1;
15
signalEnd=1;
16
}
17
18
}
19
20
intmain(void)
21
{
22
23
24
DDRB=0x00;// Port B als Input (inkl. PB0 = ICP1)
25
DDRC=0xff;// Port C als Ausgang
26
PORTC=0xff;
27
28
29
TIMSK|=(1<<TICIE1);// Capture Interrupt enable
30
TCCR1B|=(1<<CS12)|(1<<ICES1);// Prescaler 256 Timer 1, Capture bei steigender Flanke
Hallo Stefan,
wenn ich die 8MHz aus dem Quellcode einsetze, erhalte 32µs Timer-Takt.
Das sind dann für 1,5ms 47 Takte. Im zweiten Posting schreibst Du was
von 3,69MHz? Die 6 als Vergleichswert würde bei 1MHz Takt passen. Fuses
falsch?
Du setzt in Deinem Programm an keiner Stelle den Timer auf 0. Somit
wirst Du hin und wieder statt einer sauberen Differenz der Zeitpunkte
aus dem Capture einen negativen Wert erhalten. Ich würde nach der
fallenden Flanke den Timer auf 0 setzen. Er zählt dann in den ca. 20ms
Wiederholzeit bis ca. 625, also noch locker im Bereich für 16 Bit.
Welchen Sinn haben die cli in der ISR und der zweite sei im
Hauptprogramm?
Grüße, Kurt
Hallo Kurt,
das Wort "Fuses" löst gerade ein komisches Gefühl bei mir aus... Ich
glaub, ich hab das total verpennt :/ Kaum umgstellt, geht das Ganze
arg!
Anfangs habe ich einen 8MHz Quarz auf dem STK500 getestet, deswegen
bezog sich der Wert auf 8 MHz. Standardmäßig werde ich aber mit den
3,69MHz vom STK500 arbeiten, zumindestens bis alles läuft. Die Info hab
ich euch verschwiegen :) Aber wenn natürlich in den Fuses keine
Taktquelle eingstellt ist......
Mit cli() und sei() hatte ich vor die Interruptanforderungen während der
Berechnung zu sperren, was aber völliger Blödsinn ist, da die Impulse in
einem Abstand von ca. 20ms kommen und das dem Controller ja locker
ausreicht die Berechnung durchzuführen.
Bezüglich der negativen Werte hatte ich vor das Overflow-Flag
auszuwerten und dann entsprechend einen Offsetwert zu den beiden
ICR1-Werten hinzuzurechnen. Den Timer einfach zu nullen wäre natürlich
auch eine simple Idee. Ich werd mal sehen, wie ich das schlussendlich
lösen werde.
Danke dir Kurt, manchmal denkt man an die simpelsten Sachen nicht mehr
... :/
Viele Grüße
Stefan
Stefan S. schrieb:> Bezüglich der negativen Werte hatte ich vor das Overflow-Flag> auszuwerten
Das überlass mal den ASM-Leuten... ^^
> und dann entsprechend einen Offsetwert zu den beiden> ICR1-Werten hinzuzurechnen.
Außerdem gibt es da (zumindes in ASM) keine negativen Werte. Man
subtrahiert den Zeitstempel des Impulsbeginns (der älter und daher
kleiner ist) vom Zeitstempel des Impulsendes (der ja neuer ist) und
erhält die Impulsbreite. Da beide 16-Bit-Werte als Ring (also kein
Zahlenstrahl) zu verstehen sind, heben sich die Überträge auf.
> Den Timer einfach zu nullen wäre natürlich> auch eine simple Idee.
Dachte ich zu Tiny12/15-Zeiten auch mal. Doch meist bietet es sich an,
neben dem ICP-Interrupt noch eine oder beide Compare-Spuren zu nutzen,
und da muss man den Timer frei durchlaufen lassen.
> Ich werd mal sehen, wie ich das schlussendlich> lösen werde.
Mach' wie Du denkst, ich will Dir da nichts vorschreiben, lediglich
Denkanstöße geben...
...