Aktykuły które nie zmieściły się w żadnej kategorii

0102 /03
04Procesor w stanie sleep budzony co 8 sekund. Pobór prądu 1 uA.06
070809
  1. // wartość podajemy z uwzględniem "0" jako pozycji czyli 15 - 1 = 14
  2. // 14 * 8 = 112s + dla zerowej pozycji 8 = 120 czyli 2 minuty 
  3. // 149 daje 20 minut
  4. #define WAKE_PrescalerX8  1   // co daje 15 * 8s = 120 sekund 
  5. volatile uint8_t wake_up;
  6. #if __AVR_ATmega328P__ == 1
  7. #define MS      PB0
  8. #define RST69   PB1
  9. #define SS      PB2 // PB2 to domyślny CS który 
  10.                     // musi być wyjściem inaczej się zwiesza SPI
  11. #define MOSI    PB3
  12. #define MISO    PB4 
  13. #define SCK     PB5
  14. #define _INT0   PD2 // port przerwania 
  15. #endif
  16. //..................
  17. ISR(TIMER2_OVF_vect)
  18. {      
  19.   static uint16_t counter = 0;
  20.   if( ++counter > WAKE_PrescalerX8 ) 
  21.    {
  22.      counter = 0;
  23.      wake_up = 1;
  24.    }
  25.    sekund++;
  26. }   
  27. //....................
  28. void initTimer2(void)
  29. {
  30.    TIMSK2  = 0; // wyłączenie przerwań Timer2
  31.    ASSR  &= ~(1 << EXCLK);
  32.    ASSR  |= (1<<AS2);  //Włącz tryb asynchroniczny
  33.    TCNT2=0;  //początkową wartość licznika
  34.    TCCR2B |= (1<<CS22) | (1<<CS21) | (1<<CS20);  //ustaw prescaller na podział 1024
  35.                                              //  co daje 8 sekund
  36.    while (ASSR & ((1<<TCN2UB)|(1<<TCR2BUB)));  // poczekać na aktualizację rejestru
  37.    TIFR2  = (1<<TOV2);  // kasowanie flagi przerwań
  38.    TIMSK2  = (1<<TOIE2);  // włączenie przerwania , TOV2 
  39. }
  40. //...................
  41.    initTimer2();
  42.    sei();
  43.    rsPrintLn(" > Wejscie w sleep");
  44.    power_all_disable(); //wyłączenie TWI TIM2 TIM0 TIM1 SPI USART0 and ADC
  45.    power_timer2_enable();
  46.    set_sleep_mode(SLEEP_MODE_PWR_SAVE);
  47.    wake_up = 0;
  48.    while (1) 
  49.     {
  50.      sleep_mode(); // wejście w stan uśpienia
  51.      TCCR2B |= (1<<CS22) | (1<<CS21) | (1<<CS20);  // zabezpieczenie przed 
  52.                                                   // powtórzeniem przerwania 
  53.      while (ASSR & (1<<TCR2BUB));  //poczekać na aktualizację 
  54.                                    //rejestru 2 linia zabezpieczenia
  55.      if ( wake_up == 1 ) 
  56.       { 
  57.         power_all_enable();
  58.         rsPrintLn(" > Wyscie z sleep");
  59.         WriteDane();  // wysyłanie danych do odbiornika
  60.         power_all_disable(); //wyłączenie TWI TIM2 TIM0 TIM1 SPI USART0 and ADC
  61.         power_timer2_enable();
  62.         set_sleep_mode(SLEEP_MODE_PWR_SAVE); // usypianie procesora poza Timerem
  63.         wake_up = 0;
  64.      }  
  65.     }

Uruchomienie trybu asynchronicznego niesie za sobą pewien problem.
Przy szybkim zegarze wewnętrznym np. 8MHz w przedstawionym przykładzie, gdzie w pętli głównej jest tylko jeden warunek i następuje ponowne wejście w tryb sleep procesor może wywołać przerwanie ponownie zanim zdążą się zmienić ustawienia w rejestrze timera2.

Czas jednego cyklu zegara 32768Hz wynosi 1 / 32768 = 0,000030517578125 sekundy podnosząc to przez preskaler * 1024 = 0,03125 sekundy * licznik wewnętrzny timera 256 uzyskujemy 8 sekund. Odstęp czasu między kolejnymi przerwaniami. Czas jednego cyklu Timera2 wynosi 31,25 ms zanim nastąpi zmiana. Procesor taktowany zegarem 8MHz swoje obliczenia wykona szybciej i stwierdzi że nastąpiło ponowne wywołanie przerwania mimo że nie zmieniły się stany w Timer2 o czym przy pracy asynchronicznej jednostka centralna jeszcze niewie.

Dlatego stosujmy następujący wybieg :

  1.    TCCR2B |= (1<<CS22) | (1<<CS21) | (1<<CS20);  
  2.    while (ASSR & (1<<TCR2BUB));
lub
  1.    _delay_ms(35);
Atmega328 i 32kHz

Opóźnienie dłuższe niż zmiana stanu oscylatora pomnożonego przez preskaler.
Można to pominąć jeżeli procesor będzie miał dużo do wykonania i czas tych wszystkich operacji będzie ponad 31 ms.


Dasej (C) 2019 : 5096