Low Power Forth MCU-programming met ByteForth voorbeeld RF afstandbediening


Mogelijke maatregelen om stroom te besparen op microcontrollers en 
in dit voorbeeld de AVR en wel de AT90S2313/ATtiny2313. De functionaliteit
van het programma mag natuurlijk niet veranderen.
Waar moeten we verder op letten:

a) Vermijden van wachtlussen ofwel hoe zetten we de MCU zo kort mogelijk aan.
b) Welke (on)mogelijkheden biedt de gebruikte processor (handige hardware).
c) Zoveel mogelijk ongebruikte interne MCU-hardware uitschakelen.
d) Goed nadenken over het stroomverbruik van de diverse I/O-pinnen.
e) Werkfrequentie MCU

Voor dit voorbeeld zijn belangrijk:
   I/O-pins, Interne H/W uitschakelen, Sleepmode, Actieftijd


In vier stappen naar een LowPower versie:

1) Uitschakelen zender
2) Ingaan slaapmodus en gebruik watchdog
3) Pinchange interrupt
4) Toets herhaal functie en finetuning


Hoe bereken je de geschatte levensduur, ik ga hier uit
van een geschatte gebruiksduur van ongeveer 3 minuten per dag.
Meestal zal dat wat minder zijn want met een kachel zullen 
we niet gaan zappen als met een TV.

Er wordt een CR2032 lithium batterij gebruikt met een opgegeven
capaciteit van 220 mAh en een spanning van 2,0V tot 3,4V.
Dat betekent dat de zender 0,2% van de dag actief is, de formule wordt dan:

   /(499xIrust)+Iactief
1 /-------------------- x Accu capaciteit in mAh = Aantal gebruiksuren
 /         500

Aantal gebruiksdagen is uren/24
Aantal gebruiksjaren is dagen/365



1) Alleen de RF-zender uitschakelen
    MCU = AT90S2313, kristal 4 MHz, Irust=3mA, Iactief=3,6mA
    Een verhouding van 99/1 betekent dat de afstandbediening
    elke dag ongeveer 14 minuten actief gebruikt wordt.
    Geschatte levensduur de CR2032 batterij bij 499/1 is 73,3 uren (3 dagen)


\ Zender aan voordat het karakter verzonden wordt, daarna weer uit.
: EMIT              ( char -- )
    CLEAR UIT  (EMIT  SET UIT
    ;
    
\ Flag is true als er een toets wordt ingedrukt?
: TOETS?            ( -- flag )
    FROM OMHOOG 0=
    FROM OMLAAG 0=  OR
    FROM START1 0=
    FROM START2 0=  AND  OR
    ;

\ Variabel herhalings tempo voor toetsen. Wacht de eerste keer 
\ 250 millisec. als een toets ingedrukt is, daarna 30 ms.
FLAG VERSNEL        ( -- flag )
: WACHT             ( -- )
    VERSNEL IF  30 MS EXIT  THEN  250 MS  SET VERSNEL
    ;

\ Wacht tot een toets ingedrukt is
: TOETS             ( -- )
    BEGIN  TOETS? UNTIL         ( Toets los? )
    CLEAR VERSNEL               ( Reset toetsvertraging )
    ;

: ZENDER            ( -- )
    SETUP  BEGIN  TOETS  ZEND  WACHT  AGAIN
    ;  MAIN





2) Watchdog als toets-scan interrupt
    MCU = AT90S2313, kristal 4 MHz, Irust=4,4uA, Itoets=3mA, Iactief=3,6mA
    Geschatte levensduur de CR2032 batterij bij 499/1 is 18980 uren
    Dat is ruim een 2 jaar.


\ Laat de zender slapen als er geen toets meer  ingedrukt is.
: TOETS             ( -- )
    BEGIN
    TOETS? 0= WHILE             ( Toets los? )
        CLEAR VERSNEL           ( Reset toetsvertraging )
        POWERDOWN               ( MCU in slaap )
    REPEAT
    CLEAR VERSNEL    
    ;

: ZENDER            ( -- )
    SETUP  3 WATCHDOG-ON        ( Reset MCU om de 0,4 sec bij 3 Volt )
    BEGIN  TOETS  ZEND  WACHT  AGAIN
    ;  MAIN





3) Pinchange interrupt maakt MCU wakker
    MCU = ATtiny2313, kristal 2 MHz, Irust=400nA, Iactief=1,45mA
    Geschatte levensduur de CR2032 batterij bij 499/1 = 66683 uren
    Ofwel ruim zeven en een half jaar.
    

\ Wakker worden na een toetsaanslag
CODE TOETSAANSLAG   ( -- )
    R16 PUSH,
    R16 0 LDI,                  ( Interrupt gelijk weer uit )
    ADR INTERRUPT-MASKER R16 OUT,
    R16 POP,
    RETI,
END-CODE  PIN-CHANGE

: TOETS             ( -- )
    BEGIN
    TOETS? 0= WHILE
        CLEAR VERSNEL
        SET LED
        $20 TO EXT-INT-FLAG     ( Reset pinchange interrupt )
        $20 TO INTERRUPT-MASKER ( Pinchange interrupt aan )
        POWERDOWN
    REPEAT
    SET LED
    ;




4) Pinchange aan, Werkfrequentie naar 0,5 MHz, Watchdog als toetsvertraging
    MCU = ATtiny2313, kristal 0,5 MHz, Irust=400nA, Iactief=1,25mA
    Geschatte levensduur de CR2032 batterij bij 499/1 = 75883 uren
    Dat betekent dat de batterij een ruime acht en een half jaar mee gaat.


\ Watchdog is een NOOP, wordt alleen gebruikt om MCU wakker te maken
CODE WATCH          ( -- )
    RETI,
END-CODE  WD-TIMEOUT

: 30MS              ( -- )      $41 (MS) ;
: 250MS             ( -- )      $44 (MS) ;

\ Variabel herhalings tempo voor toetsen. Wacht de eerste keer 
\ 250 millisec. als een toets ingedrukt is, daarna 30 ms.
FLAG VERSNEL        ( -- flag )
: WACHT             ( -- )
    VERSNEL IF  30MS EXIT  THEN  250MS  SET VERSNEL
    ;




\ ----------------------------------------------------------------------
\ LANGUAGE    : AVR ByteForth vsn 2.00
\ PROJECT     : Zender voor branderautomaat
\ DESCRIPTION : 433 of 900 MHz zender voor branderautomaat
\ CATEGORY    : Applicatie, afmeting: 522 bytes.
\ AUTHOR      : Willem Ouwerkerk, Februari 04, 2005
\ LAST CHANGE : Willem Ouwerkerk, November 04, 2013
\ ----------------------------------------------------------------------

\ Read low fuse:  00 00 50 AVR> .HEX  ( Default = 64 )
\ Write low fuse: FA 00 A0 AC >AVR

TINY2313                                \ Selecteer target
NEEDS TARGET.FRT                        \ Laad cpu specifiek deel
  5 SET-CRYSTAL                         \ Er wordt een .5 MHz xt gebruikt

INCLUDE MS.FRT                          \ Correcte MS erbij
INCLUDE AVR-EEP.FRT                     \ EEPROM

\ Lezen van 16-bits data in EEPROM
: DEE@              ( addr -- dx )
    2>R  2R@ 1 M+ EE@  2R> EE@
    ;

PORTB SFR INGANG                        \ Gebruikte I/O poorten
PORTD SFR UITGANG

\ pin 14 = RO = PB2 - Hoog
\ pin 15 = RB = PB3 - Aan/Uit
\ pin 16 = LB = PB4 - Functie
\ pin 17 = LO = PB5 - Laag

PORTB 1 BIT-SFR VOEDING                 \ Gebruikte ingangen             
PORTB 2 BIT-SFR OMHOOG
PORTB 3 BIT-SFR START1
PORTB 4 BIT-SFR START2
PORTB 5 BIT-SFR OMLAAG                  \ Laatste ingang, nu de uitgangen
PORTB 6 BIT-SFR MOSI
PORTB 7 BIT-SFR MISO

PORTD 6 BIT-SFR TXD                     \ RS232 uitgang
PORTD 5 BIT-SFR UIT                     \ De zender en de LED aan/uit (0 = aan)
PORTD 4 BIT-SFR LED

\ Software RS232 op 2400 baud
  #066 CONSTANT BITRATE#                \ 2400 Baud .5 MHz
  #01 CONSTANT STOPBITS#                \ Aantal stopbits

CODE WACHT-BIT  ( -- )                  \ Wacht een halve bit tijd
    R18 BITRATE# LDI,
    DO,  R18 LOOP,
    NOP,                                \ Extra vertraging
    RET,
END-CODE

\ Verzend het karakter 'char' via software RS232.
CODE EMIT      ( char -- )             \ RS232s char naar RS232
    ADR UIT CBI,                        \ Zender aan
    R16 X+ LD,
    R17 9 STOPBITS# + LDI,              \ 1 + 8 + S bits
    R16 COM,                            \ Inverteer char
    SEC,                                \ Start-bit is false
    DO,
        CS IF,
            ADR TXD SBI,                \ Zend nul
        ELSE,
            ADR TXD CBI,                \ Zend een
            NOP,
        THEN,
        ' WACHT-BIT GCALL,              \ Wacht halve bittijd
        R16 LSR,                        \ Pak volgende bit
    R17 LOOP,                           \ Zend alle bits
    ADR TXD CBI,                        \ Eindig altijd laag
    ADR UIT SBI,                        \ Zender uit
    RET,
END-CODE

\G Initialiseer de I/O-bits voor RS232.
MACRO: SETUP-RS232   ( -- )             \ RS232s Initialiseer RS232
    -1 SETDIR TXD                       \ TXD is uitgang
    CLEAR TXD                           \ Begin met TXD laag
    ;

\ Codes veranderd in ASCII om een prototype van monteursoftware
\ eenvoudig te kunnen demonstreren.
&U CONSTANT AAN/UIT                     \ De zes toetscodes
&O CONSTANT OP
&N CONSTANT NEER
&R CONSTANT REBOOT
&H CONSTANT HO/LA
&M CONSTANT MONTEUR                     \ Naar monteurs menu

1. EEALLOT                              \ Positie nul niet gebruiken!
EEHERE 2CONSTANT SLEUTEL    2. EEALLOT  \ Communicatie sleutel

\ Gebruik pinchange interrupt om AVR wakker te maken.
GIMSK   SFR INTERRUPT-MASKER            \ Gebruikte hardware registers
PCMSK   SFR CHANGE-MASKER
EIFR    SFR EXT-INT-FLAG

\ Wakker worden na een toetsaanslag
CODE TOETSAANSLAG   ( -- )
    R16 PUSH,
    R16 0 LDI,                          \ Interrupt gelijk weer uit
    ADR INTERRUPT-MASKER R16 OUT,
    R16 POP,
    RETI,
END-CODE  PIN-CHANGE


\ Watchdog interrupt
WDTCR   SFR WATCHDOG
CLKPR   SFR KLOKDELER  \ Klokdeler init code verbeteren !!!!!

CODE WATCH          ( -- )
    RETI,
END-CODE  WD-TIMEOUT

\ Stroomverbruik omlaag halen
PRR     SFR POWERREDUCTIE
ACSR    SFR COMPARATOR

\ Initialisatie van de zender
: SETUP-ZENDER      ( -- )
    $00 SETDIR VOEDING      \ PB 1 t/m 5 ingangen
\ I/O initialiseren met pullups
    $00 SETDIR START1  
    $00 SETDIR START2  
    $00 SETDIR OMHOOG  
    $00 SETDIR OMLAAG  
    SET START1              \ Pullups op PB 2 t/m 5
    SET START2
    SET OMLAAG
    SET OMHOOG
    SET MISO                \ Pullups op MISO en MOSI
    SET MOSI
\ De led uit
    $FF SETDIR LED
    $FF SETDIR UIT
    SET UIT  SET LED
\ Pinchange initialiseren
    $20 TO INTERRUPT-MASKER
    $3C TO CHANGE-MASKER
    INTERRUPT-ON
    ;

\ Zend sleutel en opdracht via RS232
: COMMANDO          ( char -- )
    SLEUTEL DEE@  SWAP EMIT 1 MS  EMIT 1 MS   EMIT
    ;

MACRO: FUNCTIE?     ( flag1 -- flag2 )  FROM START2 0= AND ;

\ Mogelijk functietoets er uit halen, reageert dan niet als
\ een gewone toets.
\ Is er een toets ingedrukt?
: TOETS?            ( -- flag )
    FROM OMHOOG 0=
    FROM OMLAAG 0=  OR
    FROM START1 0=
    FUNCTIE? OR
    ;

\ Zend sleutel en juiste code na een toetsaanslag
: ZEND              ( -- )
    FROM OMHOOG 0= FROM OMLAAG 0= AND IF   MONTEUR COMMANDO  EXIT  THEN    
    FROM START1 0= FUNCTIE? IF   AAN/UIT COMMANDO  EXIT  THEN
    FROM OMLAAG 0= FUNCTIE? IF   REBOOT  COMMANDO  EXIT  THEN
    FROM OMHOOG 0= FUNCTIE? IF   HO/LA   COMMANDO  EXIT  THEN
    FROM OMHOOG 0= IF  OP   COMMANDO  EXIT               THEN
    FROM OMLAAG 0= IF  NEER COMMANDO  EXIT               THEN
    ;

CODE (MS)   ( u -- )
    R16 X+ LD,          \ Watchdog INTERRUPT aan
    WDTCR R16 OUT,
    R16 MCUCR IN,       \ Power down
    R16 $30 ORI,
    MCUCR R16 OUT,
    SLEEP,
    R16 $18 LDI,        \ Watchdog weer uit     
    WDTCR R16 OUT,
    R16 CLR,
    WDTCR R16 OUT,
    RET,
END-CODE

: 30MS              ( -- )      $41 (MS) ;
: 250MS             ( -- )      $44 (MS) ;

FLAG VERSNEL        ( -- flag )
: WACHT             ( -- )      \ Variabel herhalings tempo voor toetsen.
    VERSNEL IF  30MS EXIT  THEN  250MS  SET VERSNEL
    ;

\ Wacht de eerste keer 250 millisec. als een toets ingedrukt is,
\ daarna 30 ms en laat de zender slapen als er geen toets meer 
\ ingedrukt is.
: TOETS             ( -- )
    BEGIN
    TOETS? 0= WHILE
        CLEAR VERSNEL
        $20 TO EXT-INT-FLAG     ( Reset pinchange interrupt )
        $20 TO INTERRUPT-MASKER ( Pinchange interrupt aan )
        POWERDOWN
    REPEAT
    ;

\ Zend toetscode's via RS232 naar de branderautomaat.
\ Klok 0,5 MHz, Watchdog uit, comparator, T0, T1 en USI ook uit
: ZENDER            ( -- )
    SETUP-BYTEFORTH
    $0E TO POWERREDUCTIE  $80 TO COMPARATOR  ( Schakel onderdelen uit )
    $80 TO KLOKDELER  $02 TO KLOKDELER ( Klok / 4 = 0.5 MHz )
    $18 TO WATCHDOG  CLEAR WATCHDOG    ( Watchdog uit )
    SETUP-RS232  SETUP-ZENDER  CLEAR VERSNEL
    BEGIN  TOETS  ZEND  WACHT  AGAIN
    ;  MAIN

                              ( Einde )
