Witam,
Jakiś czas temu pytałem o sprawy związane z pomiarem częstotliwości sinusoidy o częstotliwości od 2 do 150Hz oraz zmiennej amplitudzie (od kilku V do 400V). Mam już układ elektroniczny przekształcający sinusoidę na prostokąt (brana jest pod uwagę tylko dodatnia połówka, a ujemna jest usuwana). Jest tu kilka rezystorów, mostek, tranzystor, dioda oraz transformatorek. (Może działanie tego układu da się jeszcze ulepszyć, ale to w sumie nie jest teraz tematem). Uzyskany z dodatniej połówki sinusoidy prostokąt jest podawany na nóżkę PE7(INT7) mikrokontrolera ATmega128 (kwarc
16MHz). Dokładność pomiaru, którą chciałbym osiągnąć to 0,2Hz przy częstotliwości 50Hz. Chciałem Was prosić o sprawdzenie mojego kodu, którego zadaniem jest nieustanne mierzenie czasu trwania dodatniej połówki, a następnie wypisywanie tej wartości na wyświetlacz. Kod, który napisałem wygląda na działający, ale może ma jakiś ukryty błąd.volatile unsigned long int timer = 100000; volatile short actualTime;
./* procedura wywoływana 100000 razy na sekundę */ SIGNAL (SIG_OUTPUT_COMPARE2) { cli();
if (timer < 100000) timer++;
sei(); }
/* wyzwalane zboczem narastającym i opadającym */ SIGNAL (SIG_INTERRUPT7) { cli();
if (PINE & PINE7) { timer = 0; TCCR2 = 0; // stop timera TCNT2 = 0; // zerowanie licznika TCCR2 = _BV(WGM21) | // start timera _BV(C21); // (prescaler 8) } else { actualTime = timer; }
sei(); }
int main(void) { char s[16];
initLCD();
cli();
EICRB |= _BV(ISC70); EIMSK |= _BV(INT7);
TCCR2 = 0; OCR2 = 19; TIFR |= _BV(OCF2); TIMSK |= _BV(OCIE2); while (ASSR & _BV(OCR2UB)) ;
sei();
while (1) {
if (timer == 100000) LCDshowString("---"); else { sprintf(s, "%d ", actualTime); LCDshowString(s); } }
return 0; }
*** Jak to się sprawuje: Jako źródło sygnału podłączyłem po prostu zasilanie sieciowe 230V/50Hz. Wczoraj wieczorem przed godziną 22 liczba na wyświetlaczu wynosiła 996 (ostatnia cyfra niekiedy migała na "5"). Potem zaczęło to rosnąć... 997/8. O godzinie 22 było jakieś 999. Potem zaczęło spadać do 996. Teraz (godzina 13:40) mam 996/7. ***W szczególności chciałem zapytać o to, czy poprawnie zastosowałem cli() i sei() w procedurach obsługi przerwań. Ponadto chciałem zapytać, czy kod wewnątrz while(1) jest poprawny i czy nie lepiej byłoby zapisać to tak:
while (1) { unsigned long int timerLatch; short actualTimeLatch;
cli(); timerLatch = timer; actualTimeLatch = actualTime; sei();
if (timerLatch == 100000) LCDshowString("---"); else { sprintf(s, "%d ", actualTimeLatch); LCDshowString(s); } }
Chodzi o sytuację, w której w pętli głównej jest przetwarzana wartość zmiennej timer albo actualTime (np. został odczytany pierwszy bajt) i w trakcie nastąpi przerwanie, zmieni wartość zmiennej, obsługa przerwania się skończy, zostanie dokończone przetwarzanie zmiennej timer albo actualTime -- wartość chyba będzie błędna (jeden bajt z poprzedniej wartości, reszta bajtów po aktualizacji w przerwaniu).
Z góry dziękuję za rady.
Robbo