0,00 €

V košarici ni izdelkov.

0,00 €

V košarici ni izdelkov.

More
    DomovDownloadBASCOM programiBascom-AVR knjižnice za Arduino module (2)

    Bascom-AVR knjižnice za Arduino module (2)

    eestecAvtor: Mag. Vladimir Mitrović
    2017_256_40

    V preteklem delu smo spoznali ZS-042 modul in pojasnili koncept ter vsebino programske knjižnice DS3231$SE.sub. Če jo pridružimo k našim BascomAVR programom bodo ukazi iz knjižnice omogočili enostavno delo z integriranim vezjem DS3231 bodisi da ga uporabimo kot del ZS-042 modula ali v nekem drugem vezju. Sledijo primeri, ki bodo pokazali kako pravilno uporabiti ukaze iz te knjižnice in kako povezati ZS-042 modul z Mini in MegaPinom.

    Program DS3231_1.bas

    Slika 4: Shema mikrokontrolerskega vezja za katerega je napisan program DS3231_1.bas

    Program je napisan za vezje po shemi na sliki 4. To je pravzaprav poenostavljena shema razvojnega sistema MiniPin, zato se vezje lahko realizira z njegovo pomočjo, s pomočjo razvojnega sistema MegaPin ali na neki drugi platformi, ki ima dostopne ustrezne priključke mikrokontrolerja. ZS-042 modul se veže na istoimenske priključke na levi strani slike 4; neizkoriščene priključke modula (32K in SQW) pustimo nepovezane.

    Analizirali bomo samo dele programa, ki uporabljajo RTC; za popolno razumevanje dela je potrebno pogledati celoten program.

    Na začetku programa je potrebno vključiti programsko knjižnico:

    $include "DS3231$SE.sub"

    S tem so v programu definirane vse DS3231$ spremenljivke in dostopni postanejo vsi ukazi iz knjižnice. Sestavni del programa bodo postali samo tisti ukazi, ki jih bomo uporabljali. Opomba: DS3231 knjižnica uporablja novi način definiranja podprograma (Config Submode = New), zato je s tem potrebno računati, v kolikor se v programu uporabljajo podprogrami iz nekaterih drugih knjižnic ali lastni podprogrami.

    Sledi konfiguracija displeja,

    Config Lcdpin = Pin ...

    vhodnih pinov (Pind.0 – Pind.4), katerim so dodeljena alternativna imena v skladu s shemo(Pind.0 = Tp1, Pind.1 = Tp2, itd.)

    Tp1 Alias Pind.0
    Config Tp1 = Input
    Portd.0 = 1
    ...

    in I2C vodila, preko katere mikrokontroler komunicira z RTC-jem:

    Config I2cdelay = 5
    Config Sda = Portd.4 'SDA
    Config Scl = Portd.5 'SCL
    I2cinit

    Glede na moje izkušnje navedeni I2cdelay omogoča največjo hitrost I2C komunikacije (okoli 75 kHz), v primeru ko se uporablja softverska emulacija in 8 MHz takt.

    Komunikacijo z RTC-jem pričnemo z njegovo konfiguracijo:

    Ds3231$write_control &B00000000

    V tem primeru so vsi biti kontrolnega registra postavljeni v stanje “0”. S tem je zagotovljeno, da RTC dela na način ki nam ustreza:
    oscilator bo nadaljeval z delom tudi takrat, ko RTC ostane na rezervnem baterijskem napajanju,
    RTC generira pravokotni signal frekvence 1 Hz na SQW priključku (v tem primeru tega signala ne bomo uporabili),
    izključene so vse prekinitve vezane za pojav alarma.

    Četudi to s konfiguracijskim ukazom ni izrecno konfigurirano, bodo časovni ukazi iz programske knjižnice predpostavljali zapis in prikaz časa v 24-urnem formatu, datumski ukazi predpostavljajo, da se datum nahaja v 21. stoletju.

    Po konfiguraciji RTC nadaljuje z delom na nastavljeni način in bo delal tako, dokler je spojen na osnovno (Vcc) ali rezervno baterijsko (Vbat) napajanje. Iz programa moramo samo periodično prebrati njegove časovne in datumske registre in jih nato na prikladen način izpisati na LCD-ju:

    Do
     Ds3231$read
     Gosub Disp_time
     Gosub Disp_date
    ...
     Waitms 100
    Loop
    Slika 5: Fotografija ure realizirane z razvojnim sistemom MiniPin

    Kot smo pokazali v predhodnem nadaljevanju, Ds3231$read prenaša vsebino časovnih in datumskih registrov iz RTC-ja v ustrezne globalne spremenljivke. Zdaj so te vrednosti dostopne drugim ukazom znotraj programa. V našem primeru v zgornji vrstici displeja prikazujemo trenutni čas:

    Disp_time:
     Home U
     Lcd_hh_mm_ss
    Return

    v spodnji vrstici pa datum in dan v tednu:

    Disp_date:
     Home L
     Lcd_dd_mm_20yy
     Lcd " "
     Lcd_dan_slo
    Return

    Za prikaz na displeju so uporabljeni ukazi Lcd_hh_mm_ss, Lcd_dd_mm_20yy in Lcd_dan_slo iz programske knjižnice DS3231$SE.sub.

    Opomba: integrirano vezje DS3231 si dneve v tednu zapomni kot številke v razponu od 1 do 7, zato so na isti način zapisani tudi v globalni spremenljivki DS3231$day. DS3231 nima vpisanega algoritma izračuna dneva v tednu iz datuma, ampak samo inkrementira dan v tednu kadar ura preskoči iz 24h na 00h. Ukazi za prikaz dneva v tednu iz DS3231.sub knjižnice v tem primeru Lcd_dan_slo, pretvarjajo številčno oznako dneva v tednu v trištevilčno kratico imena, s predpostavko, da je prvi dan v tednu ponedeljek.

    Kako to izgleda resnici prikazuje fotografija na sliki 5. Da bi bil prikaz časa in datuma točen, bo te podatke potrebno najprej vpisati v RTC DS3231. To delamo v podprogramih T2, T3 i T4 z ustreznimi tipkami Tp1, Tp2 i Tp3. Program znotraj Do…Loop zanke redno preverja stanje teh tipk, katerih namen je sledeč:

    Če tipka Tp1 ni pritisnjena,

    • s tipko Tp2 nastavljamo ure,
    • s tipko Tp3 nastavljamo minute,
    • tipko Tp4 nastavljamo dneve v tednu.

    Če je tipka Tp1 pritisnjena,

    • s tipko Tp2 nastavljamo dneve v mesecu,
    • s tipko Tp3 nastavljamo mesece in
    • s tipko Tp4 nastavljamo leta.

    Vsak pritisk na neko tipko pomeni povečanje ustrezne vrednosti za 1. Vsaka sprememba minut hkrati resetira sekunde. Program preverja vpisane vrednosti in ne dovoljuje vnos izven dopustnega obsega. Na primeru ur (dopustni obseg je 00 – 23 v BCD formatu) to izgleda tako:

    ...
     Incr_bcd Ds3231$hour
     If Ds3231$hour > &H23 Then
     Ds3231$hour = &H00
     End If
     Ds3231$write_hour
    ...

    Za vsako spremembo datuma je potrebno bolj zahtevno preverjanje številke dneva v mesecu, odvisno od tekočega meseca in tega, ali je leto prestopno ali ne. Preverjanje se odvija v podprogramu Check_dte, ki se ne nahaja v programski knjižnici, ampak je sestavni del programa:

    ...
     Incr_bcd Ds3231$dte
     Gosub Check_dte
     Ds3231$write_date
    ...

    Podprograma Check_dte tukaj ne bomo analizirali, poglejte ga v programu. Potrebno je samo vedeti, da je spremembo datuma potrebno vpisovati po vrsti leto, mesec, dan; v nasprotnem primeru Check_dte ne bo delal korektno. Bodite pozorni na to, da je po vsaki spremembi vrednosti neke globalne spremenljivke potrebno vpisati to novo vrednost v ustrezen register RTC-ja (Ds3231$write_hour, Ds3231$write_date).

    Program DS3231_2.bas

    Slika 6: Shema mikrokontrolerskega vezja za katero je napisan program DS3231_2.bas

    Program DS3231_2.bas je napisan za vezje po shemi na sliki 6, ki se od vezja s slike 4 razlikuje samo po tem, da je sedaj izkoriščen tudi priključek SQW RTC-ja. Vezje se lahko realizira s pomočjo razvojnih sistemov MiniPin in MegaPin ali na neki drugi platformi ki ima pristopne ustrezne priključke mikrokontrolerja. Neizkoriščeni priključek 32K ZS-042 modula je nepovezan.

    S povezovanjem priključka SQW z mikrokontrolerjem smo načelno dobili možnost uporabe alarmnega vezja RTC-ja, ker RTC javlja alarmni dogodek s postavljanjem SQW pina v stanje logične “0”. Za to je potrebno v RTC vpisati želena časovna alarma, postaviti A1IE in A2IE bita v kontrolnem registru in konfigurirati SQW pin kot izhodni pin alarmnega vezja s postavljanjem INTCN bita kontrolnega registra.

    Zdaj se ne bomo ukvarjali z alarmnim vezjem RTC-ja, smo pa to omenili zgolj informativno. Program DS3231_2.bas, ki ga analiziramo, je funkcionalno zelo podoben prejšnjemu programu DS3231_1.bas. Njegov osnovni namen je prikaz časa in datuma, dodane pa so mu nekatere nove funkcionalnosti, ki jih bomo zdaj podrobno pogledali. Ker program ne uporablja alarmnega vezja RTC-ja, je kontrolni register konfiguriran na isti način kot prej:
    Ds3231$write_control &B00000000

    Tako je alarmno vezje RTC-ja onemogočeno, na SQW pinu pa se pojavlja pravokotni signal frekvence 1 Hz. Ta signal bomo izkoristili zato, da bi zmanjšali pogostost komunikacije mikrokontrolerja z RTC-jem na enkrat v sekundi. Pin, na katerega je spojen SQW signal, je konfiguriran kot vhodni:

    Sqw Alias Pind.6
    Config Sqw = Input
    Portd.6 = 0

    Stanje tega pina se stalno preverja v Do…Loop zanki, ki sedaj vsebuje samo Debounce ukaze:

    Do
     Debounce Sqw , 0 , New_second , Sub
     Debounce Tp2 , 0 , T2 , Sub
     Debounce Tp3 , 0 , T3 , Sub
     Debounce Tp4 , 0 , T4 , Sub
    Loop

    Tipke Tp2, Tp3 in Tp4 imajo isto funkcijo kot v prvem primeru in njim pridruženi podprogrami so zelo podobni predhodnim. Branje časovnih in datumskih registrov RTC-ja in njihov prikaz na displeju so sedaj premeščeni v podprogram New_second, ki se izvršuje ko SQW pin spremeni stanje iz “1” u “0”, torej, enkrat v sekundi:

    New_second:
     Ds3231$read
     Gosub Check_holiday_slo
     Gosub Check_dst
     Gosub Disp_time
     Gosub Disp_date
    Return

    Opazili bomo dva podprograma, Check_holiday_slo in Check_dst. Check_dst avtomatsko popravlja prehod iz zimskega v letno računanje časa in obratno. Te korekcije niso rešene v integriranem vezju DS3231 in sem jih zato moral implementirati programsko. Prehod iz zimskega v letno računanje časa se dogaja v 2 urah (Ds3231$hour = &H02) zadnjo nedeljo (Ds3231$day = 7) v tretjem mesecu (Ds3231$mth = &H03). Ta zadnja nedelja nastopa po 24. dnevu tretjega meseca (Ds3231$dte >= &H25), zato je samo potrebno počakati, da se pokrijejo vsi pogoji in izvršiti premik za 1 uro vnaprej:

    Check_dst:
     If Ds3231$day = 7 Then
     If Ds3231$mth = &H03 Then
     If Ds3231$dte >= &H25 Then
     If Ds3231$hour = &H02 Then
     Ds3231$hour = &H03
     Ds3231$write_hour
     End If
     End If
     End If
    ...

    Prehod iz letnega v zimsko računanje časa se dogaja zadnjo nedeljo (Ds3231$day = 7) desetega meseca (Ds3231$mth = &H10), ki nastopa po 24. dnevu v mesecu (Ds3231$dte >= &H25). To je programsko najbolj zahteven podvig: vračamo se eno uro nazaj, zato je potrebno vgraditi zaščito, da se skok nazaj ne bi v nedogled ponavljal. Zaščito smo dosegli z zastavico Flag_s. Najprej bomo počakali prvo uro (Ds3231$hour = &H01) v dnevu, v katerem nastopa sprememba in postavili zastavico (Flag_s = 1):

    If Ds3231$mth = &H10 Then
     If Ds3231$dte >= &H25 Then
     If Ds3231$hour = &H01 Then
     Flag_s = 1
     End If

    Zdaj čakamo tretjo uro (Ds3231$hour = &H03) in opravljamo korekcijo časa samo, če je zastavica postavljena:

    If Ds3231$hour = &H03 Then
     If Flag_s = 1 Then
     Ds3231$hour = &H02
     Flag_s = 0
     Ds3231$write_hour
     End If
     End If
     End If
     End If
     End If
    Return

    Sočasno brišemo zastavico zato, da se proces ne bi ponavljal. Opazili boste še, kako smo vsako korekcijo z ukazom Ds3231$write_hour morali vpisati v ustrezen register RTC-ja.

    Da bi se te časovne korekcije pravilno odvile, je nujno da je program v mikrokontrolerju aktiven v trenutku, ko je potrebno prestaviti računanje časa z zimskega na poletno in celo uro pred prehodom z letnega na zimsko računanje. Če RTC v teh kritičnih obdobjih ni povezan z mikrokontrolerjem, se avtomatska korekcija ne bo dogodila in jo bo potrebno opraviti ročno.

    Druga nadgradnja programa je preverjanje državnih praznikov. To sem potreboval v enem projektu, ko je program moral med delovnimi dnevi delovati na en način, med vikendom drugače in spet drugače med prazniki. Ker gre za zanimivo programsko rešitev, sem se jo odločil vgraditi v ta program.

    Preverjanje dneva vikenda je enostavna: v sobotu je Ds3231$day = 6, v nedeljo Ds3231$day = 7. Preverjanje državnih praznikov je precej bolj zahtevno; to rutino preverbe sem namestil v podprogram Check_holiday_slo. Če ugotovi, da gre za državni praznik, bo podprogram postavil zastavico Flag_h. V glavnem delu programa lahko to informacijo izkoristimo, kakor želimo. V našem primeru, če gre za državni praznik, bo podprogram za izpis datuma v zgornji vrstici displeja dodatno izpisal oznako DP:

    Disp_date:
     Locate 1 , 13
     If Flag_h = 1 Then
     Lcd "DP"
     Else
     Lcd " "
     End If
     Home L
     Lcd_dd_mm_yyyy
     Lcd " "
     Lcd_dan_slo
    Return

    Zdaj pa poglejmo, kako v podprogramu Check_holiday_slo preverjamo, če gre za praznik ali ne. Obstajata vrsti državnih praznikov: tisti, ki dogajajo vsako leto na isti datum in tisti, pri katerih je datum »premičen«. Datumi “fiksnih” praznikov v Sloveniji so vpisani v tabelo Dp_slo:

    Dp_slo: 'Državni prazniki SLO
    Data &H01 , &H01 'Novo leto
    Data &H02 , &H01 'Novo leto
    Data &H08 , &H02 'Prešernov dan
    Data &H27 , &H04 'Dan upora
    Data &H01 , &H05 'Praznik dela
    Data &H02 , &H05 'Praznik dela
    Data &H25 , &H06 'Dan državnosti
    Data &H15 , &H08 'Marijino vnebovzetje
    Data &H31 , &H10 'Dan reformacije
    Data &H01 , &H11 'Dan spomina na mrtve
    Data &H25 , &H12 'Božič
    Data &H26 , &H12 'Dan samostojnosti
    Data &H00 , &H00

    Podatke iz tabele beremo enega za drugim v pomožno spremenljivko vrste word z imenom Hol_dtemth, primerjamo s tekočim datumom iz RTC-ja in, če sta se obe spremenljivki pokrili, postavljamo Flag_h:

    Flag_h = 0
     Restore Dp_slo
     Do
     Read Hol_dtemth
     Gosub Check_holiday_date
     Loop Until Hol_dtemth = &H0000
    ...
    Check_holiday_date:
     If Hol_dtemth = Ds3231$date Then
     Flag_h = 1
     End If
    Return

    Program vsebuje tudi tabelo datumov fiksnih državnih praznikov v Hrvaški, Dp_hr. Na isti način se lahko preverjajo tudi prazniki na Hrvaškem. Po potrebi se naredi podobna tabela za neko drugo državo ali za nek drug namen. Če delate svojo tabelo, jo obvezno zaključite z lažnim datumom 00.00 (Data &H00 , &H00); v nasprotnem bo podprogram preverjanja nadaljeval z uporabo datumov izven tabele.

    Med premične praznike v Sloveniji spadajo tudi Velika noč, Velikonočni ponedeljek in Binkošti. Čeprav se na internetu lahko poiščejo kalkulatorji za izračun datuma Velike noči za vsako leto posebej, sem se odločil za drugačen pristop in v tabelo vpisal datume Velike noči do leta 2050:

    Uskrs: 'Velika noc
    Data &H16 , &H04 '2017
    Data &H01 , &H04 '2018
    Data &H21 , &H04 '2019
    ...
    ...
    Data &H05 , &H04 '2048
    Data &H18 , &H04 '2049
    Data &H10 , &H04 '2050

    Z malo truda je tabelo možno podaljšati za še več let. V programu se tekoče leto preračunava v indeks za iskanje v tabeli:

    Hol_pom = Makedec(ds3231$yr)
     Hol_pom = Hol_pom - 17

    S tem računom leto 2017 (Ds3231$yr = 17h) dobi indeks 0 in tako po vrsti do leta 2050 (Ds3231$yr = 50h), pri katerem je indeks 33. Podprogram najprej preverja, ali je indeks v dovoljenem razponu, nato odčitava datum Velike noči iz tabele in preverja, ali je enak tekočem datumu:

    If Hol_pom < 34 Then
     Hol_dtemth = Lookup(hol_pom , Uskrs)
     Gosub Check_holiday_date

    Datum drugega dne Velike noči dobimo tako, da datum iz tabele povečamo za 1, datum za Binkošti pa tako, da datum Velike noči povečamo za 49. Pri tem moramo upoštevati, da so datumi zapisani v BCD formatu in paziti na dolžine posameznih mesecev; postopek izračuna poglejte v programu. (Na Hrvaškem je državni praznik Telovo, ki pride 60 dni po Veliki noči. Ta datum lahko izračunamo na podoben način, kot smo v slovenski verziji računali datum Binkošti). Vsak dobljen datum primerjamo s tekočim datumom s pomočjo podprograma Check_holiday_date ki bo, če je katera koli od teh primerjav pozitivna, postavil Flag-h. To bo glavnemu programu signaliziralo, da je aktualni datum državni praznik. Kot smo predhodno rekli, v programu DS3231_2.bas to informacijo uporabljamo za prikaz oznake DP na displeju.

    Program DS3231_3.bas

    Slika 7: Shema mikrokontrolerskega vezja za katerega je napisan program DS3231_3.bas

    Program DS3231_3.bas je napisan za mikrokontroler ATmega328P, ki ga lahko naložimo v razvojne sisteme MiniPin II ali MegaPin. Program je funkcionalno identičen programu DS3231_2.bas, zato tega dela ne bomo analizirali; posvetili se bomo samo posebnostim, ki jih prinaša ATmega328P. Čeprav je ATmega328P večji in zmogljivejši mikrokontroler kot ATtiny4313, žal nima razpoložljivih vseh pinov porta B. Če bi torej želeli uporabiti LCD adapter iz naše ponudbe, moramo LCD “premestiti” na port D. Zato so tipke Tp1 – Tp4 premeščene na pine 0 – 3 porta B, SQW, SDA in SCL pa na pine 3, 4 in 5 porta C. Vse te spremembe so prikazane na shemi na sliki 7, v programu so tudi prikladno zamenjani konfiguracijski ukazi posameznih pinov.
    Za razliko od ATtiny4313, ima ATmega328P hardversko rešeno I2C (TWI) komunikacijo, kjer sta SDA in SCL liniji povezani na pine 4 in 5 porta C. Zato so ravno te pini konfigurirani kot I2C priključki. Da bomo lahko uporabljali TWI, je v programu potrebno uporabiti alternativno knjižnico i2c_twi.lbx. Tako je možno doseči večje hitrosti komunikacije. V našem primeru uporabljamo 400 kHz:

    'use TWI instead SW emulated I2C:
    $lib "i2c_twi.lbx" 
    Config Twi = 400000

    Ostanek programa je identičen programu DS3231_2.bas.

    V teh primerih smo pokrili osnovne funkcije RTC-ja DS3231 in ilustrirali uporabo ukazov iz knjižnice DS3231$SE.sub. Delo z alarmi bomo pustili za neko drugo priložnost, čaka nas še veliko dela…

    Opomba: DS3231$SE.sub knjižnico in vse navedene programske primere v tem članku lahko brezplačno dobite v uredništvu revije Svet elektronike.
    www.svet-el.si
    Mitrovic_Barduino2

    Bascom-AVR knjižnice za Arduino module (1)