-
Data: 2011-02-10 20:56:55
Temat: Re: AVR ATmega, pomiar częstotliwości przebiegu, prośba o sprawdzenie kodu
Od: "Robbo" <y...@m...com> szukaj wiadomości tego autora
[ pokaż wszystkie nagłówki ]Dziękuję bardzo za ten kod. Przykład z wykorzystaniem union oraz struct
również bardzo cenny!
Twój kod, tak na szybko, bez union i struct (chodzi o samą ideę):
SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;
if (ETIFR & _BV(TOV3)) {
overflow++;
ETIFR |= _BV(TOV3);
ff++; // licznik zdarzeń tego typu
}
actualDuration = ((unsigned long)icr + overflow * 65536UL) - pp;
pp = (unsigned long)icr + overflow * 65536UL;
}
SIGNAL (SIG_OVERFLOW3)
{
overflow++;
}
Wyświetlam sobie na LCD wartość ff. Na ogół ma wartość "1" i tak już
zostaje. Wynika z tego, że bardzo rzadko mam sytuację z jednoczesnymi
przerwaniami.
Wydaje mi się, że możliwe jest jeszcze pewne uproszczenie -- w praktyce mi
ono zdaje egzamin (a przynajmniej tak mi się wydaje na podstawie
obserwacji). Chodzi o to, że u Ciebie "overflow" inkrementowany jest
nieustannie. To nie jest błąd -- wszystko działa jak należy. Niemniej ja
chciałem mieć "overflow" zerowany, gdyż zależnie od jego wartości chciałem
zrobić odcinanie niskich częstotliwości mierzonego sygnału. Oto przeróbka:
*** KROK 1
SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;
if (ETIFR & _BV(TOV3)) {
overflow++;
ETIFR |= _BV(TOV3);
}
actualDuration = ((unsigned long)icr + overflow * 65536UL) - pp;
pp = (unsigned long)icr + overflow * 65536UL;
pp -= overflow * 65536UL;
overflow = 0;
}
powyższe można uprościć do takiej postaci:
*** KROK 2
SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;
if (ETIFR & _BV(TOV3)) {
overflow++;
ETIFR |= _BV(TOV3);
}
actualDuration = ((unsigned long)icr + overflow * 65536UL) - pp;
pp = (unsigned long)icr;
overflow = 0;
}
Zatem wydaje mi się (może się mylę, ale w praktyce działa i wygląda OK), że
w "pp" nie musimy trzymać wartości licznika software'owego, a wystarczy
trzymać ICR.
Co o tym myślisz?
A oto kompletny kod -- odcinamy poniżej ok. 2Hz (w szczególności, gdy sygnał
w ogóle jest zerowy).
SIGNAL (SIG_INPUT_CAPTURE3)
{
icr = ICR3;
if (ETIFR & _BV(TOV3)) {
overflow++;
ETIFR |= _BV(TOV3);
}
actualDuration = ((unsigned long)icr + overflow * 65536UL) - pp;
pp = (unsigned long)icr;
overflow = 0;
}
SIGNAL (SIG_OVERFLOW3)
{
overflow++;
}
int main(void)
{
char buf[16];
unsigned long actualDurationLatch;
TCCR3A = 0;
TCCR3B |= _BV(ICES3) | _BV(ICNC3) |
_BV(CS32) | _BV(30); // prescaler 64
ETIMSK |= _BV(TICIE3) | _BV(TOIE3);
sei();
while (1) {
cli();
actualDurationLatch = actualDuration;
sei();
if ((overflow >= 5) || (actualDurationLatch > 150000)) {
LCDwriteString("-------------");
} else {
sprintf(s, "%ld ", actualDurationLatch);
LCDwriteString(s);
}
}
}
W moim pierwotnym liście podałem kod z wykorzystaniem SIG_OUTPUT_COMPARE2
oraz SIG_INTERRUPT7. Kod tamten miał (w porównaniu do tego z wykorzystaniem
input capture) tę wadę, że zwiększanie zmiennej "timer" 100000 razy na
sekundę obciążąło procesor. Niemniej miał on też pewną zaletę -- chodzi o
to, że dla niskich częstotliwości "odcinanie" miałem zawsze w określonym
czasie (np. gdy timer osiągnął wartość 100000; timer był resetowany po
każdym zboczu narastającym -- zatem wartość 100000 mówiła, że minęło 100000
ticków zegara od ostatniego zbocza narastającego sygnału mierzonego). Tu
(chodzi o kod z input capture) niestety jest problem. Gdy sygnał zaniknie
nagle, to "overflow" musi doliczyć do 5 (taką wartość sobie przyjąłem), ale
przecież ICR może mieć różną wartość i czas, w którym "overflow" doliczy do
5 może być różny (gdy ICR było bliskie 0, to będzie to czas prawie pięciu
przepełnień ICR; gdy ICR było prawie 65000, to będzie to czas nieco ponad
czterech przepełnień ICR). Aby mieć dokładne odcinanie (po upływie dokładnie
określonego czasu), musiałbym zrobić dodatkowy timer (np. dający impuls co 1
sekundę), resetowany w SIG_INPUT_CAPTURE3. Jeśli timer da impuls (czyli nie
został zresetowany w ciągu ostatniej sekundy), to znaczy, że sygnał jest
poniżej 1Hz i robimy odcinanie.
R.
Następne wpisy z tego wątku
- 10.02.11 21:31 Michoo
- 11.02.11 07:36 Zbych
- 11.02.11 11:05 Robbo
- 11.02.11 11:43 Michoo
- 11.02.11 12:15 Zbych
- 11.02.11 12:22 Robbo
- 11.02.11 12:24 Zbych
- 11.02.11 12:33 Zbych
- 11.02.11 12:58 Robbo
- 11.02.11 13:09 Robbo
Najnowsze wątki z tej grupy
- 8080
- Portowanie CP/M
- radyjko
- Re: Basen i chłodzenie w w wentylacji mechanicznej
- Akumulatory VRLA
- ładowarka zmarła
- Podstawa bezpiecznikowa jako rozłącznik DC
- Napięcie akumulatora wyłączające UPS / jakie nowe akumulatory do UPS?
- nawigacja satelitarna
- SmartLife/Tuya i osuszanie -- mordowanie z zimną krwią...
- Głośnik piezoelektryczny
- Mala autonomiczna kamera monitoringu
- czas na emeryturę i EB
- Generowanie sumy kontrolnej z fragmentu pliku bin
- Re: Mala autonomiczna kamera monitoringu
Najnowsze wątki
- 2024-07-13 256 świadków nie ma racji
- 2024-07-11 Tokarze CNC czyli ciężkie życie prototypiarza
- 2024-07-12 Zgody na przetwarzanie danych
- 2024-07-13 IObit Uninstaller Pro 13.6.0.5 Multilingual: Installation Guide
- 2024-07-12 stare graty młode kozy
- 2024-07-11 8080
- 2024-07-13 Przyłącze dolne grzejnika
- 2024-07-13 IObit Uninstaller Pro 13.6.0.5 Multilingual Overview
- 2024-07-12 Czym wykonać otwór fi 100 w betonie komórkowym?
- 2024-07-12 Warszawa => Senior Rust Software Engineer <=
- 2024-07-12 Warszawa => Business Unit Manager (Recruitment Business) <=
- 2024-07-12 Warszawa => Head of WMS Competence Center for IT&D Contract Logistics
- 2024-07-12 Warszawa => Head od WMS Competence Center dla IT&D (Blue Yonder) <=
- 2024-07-12 Kraków => Ruby Backend Developer <=
- 2024-07-12 Warszawa => UX/UI Designer <=