Forum: Compiler & IDEs INT0 und Timer2 - kann die Impulslänge nicht messen...


von Stanislav S. (lau)


Lesenswert?

Hallo liebe Community,

ich versuche mit einem atmega162 die Tastendrücke, die ein VW-Radio an 
CD-Wechsler meldet, auszuwerten. Laut Protocol-Beschreibung (und das 
sehe ich auch mit dem LA) kommt erst 9 ms-langer high-Impuls, dass 4,5 
ms low, und dann kommen 32 bits von Command, die als (0,550 ms high + 
0,550ms low) für 0 und (0,550 ms high + 1,7 ms low) für 1 kodiert sind. 
Stimmt alles, abgeguckt mit LA direkt am Pin 12 des atmega's; Pegeln vom 
Radio sind 0V-5V, Ausgang des Radios ist über zwei 74HC14-Elemente an 
INT0 angeschlossen.
Als erstes wollte ich einfach die Längen der Impulse zwischen steigender 
und fallender Flanken messen, mit denen ein Array von 32 Stellen füllen 
und das Ergebnis mit UART auszugeben nur irgendwie klappt es bei mir 
nicht. Device reagiert auf die Sendung vom Radio und gibt das Array über 
UART aus, nur die gemessenen Längen stimmen überhaupt nicht: alle Werte 
im Array sind dann entwender 00 oder 01 :(

Was mache ich event. falsch in dem untenstehenden Code? (kompiliert mit 
der letzten WinAVR-Version) :

void main(void) {
  SBI(MCUCR, ISC01);SBI(MCUCR, ISC00); //rising edge by start
  while (1) {
  }
}

void start_T2() {
  TCNT2 = 0x00;
  //clock period = 128 us
  SBI(TCCR2, CS22);SBI(TCCR2, CS21);SBI(TCCR2, CS20);
}
void stop_T2() {
  CBI(TCCR2, CS22);CBI(TCCR2, CS21);CBI(TCCR2, CS20);//clear bits
}
volatile int   count = 0;
volatile int   state = 0;
volatile uint8 lengthes[32];

SIGNAL(SIG_INTERRUPT0) {
  if (state==0) {
    //set from rising to falling edge
    SBI(MCUCR, ISC01);CBI(MCUCR, ISC00);
    start_T2();
    state = 1;
  }
  if (state==1) {
    //set back to rising edge
    SBI(MCUCR, ISC01);SBI(MCUCR, ISC00);
    lengthes[count]  = TCNT2;
    stop_T2();
    state = 0;
    ++count;
    if (count>31) {
      for (int i=0;i<32;++i) {
        UART_Printfu08(lengthes[i]);
        EOL();
      }
      count = 0;
    }
  }

}

von johnny.m (Gast)


Lesenswert?

SIGNAL, SBI, CBI... sind längst veraltet (und was CBI und SBI angeht, 
die werden afaik gar nicht mehr unterstützt). Du müsstest eigentlich 
beim Compilieren eine ganze Latte Warnungen und Fehlermeldungen 
bekommen... Außerdem: Der obige Code ist mit Sicherheit unvollständig. 
Warum schickst Du kein vollständiges Programm?
Und noch was: Impulslängenmessung macht man mit Input Capture und nicht 
über externe Interrupts.
Und: Serielle Ausgaben haben in Interrupt-Handlern nichts verloren. Da 
brauchste Dich nicht zu wundern, wenn es Timing-Probleme gibt.

von Stanislav S. (lau)


Lesenswert?

Der Compiler bringt keine Warnungen aus, ausser
cdc.c:30: warning: function declaration isn't a prototype
cdc.c:34: warning: function declaration isn't a prototype

SBI/CBI/SIGNAL benutze ich an anderen Stellen des Projektes und die 
funktionieren einwandfrei; wegen serieller Ausgabe hast du formal Recht, 
das ist aber nur ein Versuch, die Längen zu messen; die Ausgabe erfolgt 
erst nachdem die ersten 32 Impulse gemessen sind und damit dürfte 
keinerlei Timing-Probleme zumindest für die ersten 32 Messungen 
herrvorrufen; ich habe schon versucht das Array beim Empfangen eines 
bestimmten Charakters mit SIGNAL(SIG_USART0_RECV) in uart.c auszugeben - 
mit gleichem Endergebnis; der Unterschied zu ICP liegt m.E. nur daran, 
dass ich da Noise unterdrucken kann  :/ - nur ich habe hier keinen 
Noise, sonst würde INTO auch beim Noise ausgelöst.

Den Quellcode komplett poste ich gleich.

von johnny.m (Gast)


Lesenswert?

Tja, mit den Warnungen kann man herzlich wenig anfangen, wenn man nicht 
weiß, auf was sich die Zeilennummern beziehen...

von Stanislav S. (lau)


Angehängte Dateien:

Lesenswert?

anbei das Projekt

von Stanislav S. (lau)


Lesenswert?

habe gestern dem Rat von johny.m gefolgt und ICP benutzt - mit dem geht 
es auf einmal :)
Code:

int count = 0;
u08 lengthes[32];
u16 lengthes_16[72];

void cdc_init(void)
{
  SBI(TCCR1B, ICNC1);
  CBI(TCCR1B, ICES1); //falling
  SBI(TIMSK , TICIE1);
  SBI(TCCR1B, CS12);CBI(TCCR1B, CS11);CBI(TCCR1B, CS10);
}

SIGNAL(SIG_INPUT_CAPTURE1) {
  uint16 length = ICR1;
  lengthes_16[count] = length;
  TCNT1 = 0x0000;
  ++count;
  if (count>71) count = 0;

}
void printL() {
  for (int i=0;i<72;++i) {
   UART_Printfu16(lengthes_16[i]);
   EOL();
   lengthes_16[i] = 0x0000;
        }
}

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wenn du jetzt noch SIGNAL durch ISR ersetzt und TIMER1_CAPT_vect für
den Namen des Vektors, bist du auf dem aktuellen Stand.

Außerdem ist deine Benutzung der CBI- und SBI-Makros der beste
Beweis, warum man solche Makros wirklich nicht haben will.  All deine
umständlichen und codeintensiven Aktionen (die noch dazu kurzzeitig
den Timer mit einem nicht gewollten Prescaler betreiben) lassen sich
einfach durch:
1
TCCR1B = _BV(ICNC1) | _BV(CS12);
ersetzen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.