Hallo,
hab folgendes Problem: möchte mit meinem 90S4433 bei zwei Signalen
jeweils die Abstände zwischen zwei steigenden Flanken "parallel"
erfassen. So parallel ,dass man sie mehr oder weniger gleichzeitig auf
einem LCD Display anzeigen kann.
Jetzt hab ich nur einen Pin für Timer Capture :-( Signal 1 läuft an dem
Port und es klappt bestens.
Ein schnelles Umschalten zwischen den Signalen per Multiplexer klappt
nicht (weiss nicht warum).Jetzt dachte ich mir für das zweite Signal:
lass den Timer0 laufen , löse einen externen Interrupt bei steigender
Flanke von Signal2 aus, sichere den Zählerstand und fertig. Klappt aber
auch nicht :-(
Hat jemand eine Idee wie man die zwei Signale doch messen kann ?
Danke,
Maciek
das klappt schon mit dem externen Int. Auch kannst du dafür Timer1
nehmen, wenn du ihn durchlaufen lässt.
Der externe Int liest den Zählerstand des Timer1 und schreibt den in
eine Variable, beim nächsten wird wieder der Zählerstand gelesen und die
Differenz der beiden Werte ist die Zeit zwischen den Ereignissen.
Genauso verfährst du beim ICP-Int, nur dass nicht der Zählerstand,
sondern das ICP-Register gelesen wird. Differenz bilden, fertig. Solange
der Timer max. 1mal überläuft, brauchst du dich auch darum nicht
kümmern, das Ergebnis stimmt. Für längere Zeiten kannst du auch die
Timer1-OV mitzählen und so aus der 16bit-Zahl eine 24bit-Zahl machen
(oder auch noch mehr bei Bedarf).
Die Zeit, die von EX0 bis zum tatsächlichen Lesen der Zählerstandes
vergeht (Anspringen der ISR, Sichern von Registern/PSW, Lesen des
Zählers) verursacht keinen Fehler, da jedesmal diesselbe Verzögerung
entsteht. Kritisch kann es dann werden, wenn während des EX0-Ereignisses
ein anderer Int läuft, dann wird eine längere Zeit gemessen.
Hallo Maciek,
Welche Zeit vergeht zwischen den Signalflanken,
Ist die Zeit kleiner als 20 Takte kannst du das IMHO vergessen.
ansonsten:
ICP = Signal1 XOR Siganl2
Digitalpin = Signal1
Jetzt kannst du am Digitalpin die Flankenrichtung bestimmen und am ICP
erhälst du einen Impuls.
In der ISR des ICP wertest du einmal die Steigende und einmal die
fallende Flanke aus und bildest die Differenz.
@horse
Der ISR-Aufruf dauert nicht immer gleich lang, durch die
unterschiedliche Ausführungszeit der verschiedenen Befehle entsteht ein
fehler von +-3 Takten.
mfg
werner
vom Aufruf bis zum Lesen dauert es immer gleich lang, ein Fehler kann
entstehen, bis der Aufruf erfolgt, insofern hast du recht, +-3 Takte
stimmt aber nicht, sondern 1-3 Takte.
Aber wollen wir mal keine Erbsen zählen.
@horse
Ich denke die +- 3Takte sind für eine Zeitmessung richtig.
Die AVR-Befehle dauern zwischen 1 und 4 Takten.
folgende Fälle sind möglich:
INT0 INT1 Fehler
1. Flanke +1Takte, 2. Flanke +1Takte Durchschnitt
2. Flanke +4Takte, 2. Flanke +1Takte -3 Takte
3. Flanke +1Takte, 2. Flanke +4Takte +3 Takte
4. Flanke +4Takte, 2. Flanke +4Takte Durchschnitt
Bei der Verwendung von ICP für die eine und einem normalen Interrupt für
die andere Flanke geb ich dir recht: 0-3 Takte
Fehler zwischen verschiedenen Messungen.
Ist natürlich Erbsenzählerei, aber wenn wir schon dabei sind:
Muß man eigentlich nicht sogar noch einen oder gar zwei Takte dazuzählen
weil das Ereignis ja sowohl am Anfang des uC-Taktes als auch am Ende des
uC-Taktes auftreten kann?
uC_clk: 000000000000111111111111111100000000000001111111111
Ereignisübernahme: ^^^^ ^^^^
event1: 000000000011111111111111111111111111111111111111111
event2: 000000000000001111111111111111111111111111111111111
event2 wird erst einen Takt später übernommen, obwohl Die Differenz
zwischen event1 und event2 nahezu null werden kann.
PS: Dieser Fehler tritt auch bei der ICP Methode auf.
mfg
werner
Hallo,
danke für die Antworten ,werde ich gleich ausprobieren. Wenn noch
jemand Lust hat :
Wieso klappt das hier nicht? Es soll bei jedem Interrupt der Zählerstand
gesichert werden.
Die Interrupts kommen abwechselnd von zwei verschiedenen Signalen
(maximal 160Hz).Zwischen den Signalen wird mit einem MUX
gewechselt. Kommt ein Interrupt, so werden die Interrupts erstmal global
abgeschaltet ,eine Berechnung
durchgeführt ,der MUX auf das andere Signal geschaltet und die
Interrupts global wieder angeschaltet.
So immer hin und her.Der Mux arbeitet richtig.
In der Praxis klappt es nicht. Es werden abenteuerliche Werte angezeigt
,die ich mir überhaupt nicht erklären kann.
So ändert die Variable für Signal2 ihre Werte obwohl Signal2 keinen
Interrupt ausgelöst hat. Bin ratlos ,probiere
jetzt mal Eure Tipps.
Grüsse,
Maciek
SIGNAL(SIG_INPUT_CAPTURE1)
{
TIMER_L = TCNT1L; // Unteren
Bits des Zählers retten
TIMER_H = TCNT1H; // Oberen
Bits des Zählers retten
TCNT1H=0; TCNT1L=0; // Zähler
auf Null setzen
interrupt=1;
overflow=0; // Kein
overflow
}
.
.
.
while(1)
{
if(interrupt)
{
asm volatile("cli"); //
Interrupt global aus
if(bit_is_set(PORTB,2)) // MUX
Pin1
{
RPM = (unsigned int)(60*(31250/(float)((TIMER_H*256)+TIMER_L)));
outp (0x03,PORTB); // MUX auf Pin0
schalten
delay50us();
}
else // MUX
Pin0
{
KMH = (unsigned int)(62500/(float)((TIMER_H*256)+TIMER_L));
outp (0x07,PORTB); // MUX auf Pin0
schalten
delay50us();
}
interrupt = 0;
asm volatile("sei"); //
Interrupt global an
}
.
.
.
Hallo nochmal,
habs jetzt mit dem externen interrupt (INT1) versucht.
Geht nicht :-( Hab probeweise an ICP gemessen und dann an INT1
(mit nur einem Signal) Die Interruptroutinen machen in beiden Fällen das
gleiche. Die Messung an ICP klappt an INT1 bekomme ich abwechseln ca
25500 und 9200.
Wenn das an INT1 klappen würde gäbe es doch keinen Unterschied zu pin
ICP. Ist INT1 vielleicht langsamer ?
Tips?
Ich probier jetzt noch den zweiten Tip mit dem XOR. Den Digitalpin
brauche ich am festzustellen welches Signal grade anklopft , oder ? Nur
, wie kann ich mir das merken ,wenn gleichzeitig ein Interrupt kommt und
kurz danach der Impuls wieder weg ist?
Grüsse,
Maciek
Hallo Maciek,
[2 Signale mit 160 Hz]
mir scheint wir haben uns mißverstanden:
Du willst 2 Frequenzen von 2 verschiedenen Signalen messen?
Ich habe verstanden, du willst die Differenz zwischen 2 Signalflanken
messen.
Also Flanke Signal1 bis Flanke Signal2.
Du solltest dir Gedanken über deinen Programmablauf machen. Ich zeichne
das mal auf:
Signal1: _______----------------__________________-----------
Signal2: ____________-----------------_________________-------
Beschr:_________1_2__3_____A______________________4_5__6_____
Der Multiplexer steht auf Signal1.
1.
- Durch die Steigende Flanke wird TCNT1 in die ICR1 Register kopiert.
- In deiner ISR kopierst du TCNT1 in die TIMER-Variable, löschst TCNT1,
interrupt wird gesetzt.
Welcher Wert steht eigentlich in TIMER? TIMER enthält die Zeit die seit
dem letzten
Löschen vergangen ist (steigende Flanke von Signal2 bis steigende Flanke
Signal1).
2.
Wir haben die ISR verlassen und sind jetzt im Hauptprogramm.
- Du deaktivierst alle Interrupts.
- Du berechnest RPM
(bist du sicher das TIMER den Wert enthält den du haben wolltest? s.o.)
- Du schaltest den Mux auf Signal2 um.
- Du aktivierst alle Interrupts
Was würdest du sagen, wieviel Zeit ist seit dem Zeitpunkt 2 vergangen?
Du hast immerhin eine höchst komplizierte Berechnung mit float
durchgeführt.
Sind wir auf der Zeitachse noch for (3) oder schon etwa bei (A)?
Angenommen wir sind bereits bei (A)? Und du hast die Interrupts
reaktiviert.
Das Interrupt Flag ist ist zum Zeitpunkt (3) gesetzt worden und die ISR
Routine
wird zum Zeitpunkt (A) ausgeführt.
Damit enthält TIMER den wert, der zwischen (1) und (A) vergangen ist.
Den Rest kannst du ja selber durchspielen.
uint16_t timer
SIGNAL(SIG_INPUT_CAPTURE1)
{
if (interrupt)
return;
if (ERSTEFLANKE)
timer= ICR1; /* Wert speichern */
ERSTEFLANKE=0;
else {
timer= ICR1-timer /* Zeitdifferenz ermitteln */
interrupt=1
ERSTEFLANKE=1;
}
};
while(1)
{
if(interrupt)
{
INTERRUPT ABSCHALTEN;
if (MUX_AUF_SIGNAL1){
RPM = (uint32_t) 60*31250/timer;
MUX_AUF_SIGNAL2;
}
else {
KMH = (uint32_t) 62500/timer;
AUF_MUX1_UMSCHALTEN;
}
ICP_INTERRUPT LÖSCHEN;
interrupt = 0;
asm volatile("sei"); // Interrupt global an
}
}
Hallo Werner,
vielen Dank ,dass du dir die Mühe gemacht hast :-) Jetzt sehe ich auch
,dass mein Programm nicht laufen konnte. Kommt davon wenn man sich freut
,dass es mit einem Signal funktioniert und nicht merkt ,dass es
eigentlich Zufall war ;-)
Ich hatte den Timer und den Interrupt gar nicht verstanden...
Werde morgen mal meine Signalquelle bemühen (ist ein Auto) und schauen
wie es klappt.
Es sollen zwei Frequenzen gemessen werden. Wenn eine Flanke mal verloren
geht oder die Messung nicht 100% genau ist,ist auch nicht schlimm.
Danke und Grüsse,
Maciek (dersichjetzthoffentlichmehrgedankenmacht)
Na ja, jeder steht mal auf dem Schlauch.
wie kannst du dir sonst erklären, daß ich die Zeit zwischen den
steigenden Flanken der beiden Signale messen wollte obwohl du im
Ursprungsposting deine Anforderungen eigentlich klar angegeben hattest?
mfg
werner
life is stupid