Avtor: mag. Vladimir Mitrović
E-pošta: vmitrovic12@gmail.com
2018_265_46
Ko sem preučeval ponudbe LED&KEY modulov s TM1638 čipom (njegove izvedbe in ustrezne Bascom-AVR knjižnice so opisane v predhodnih dveh nadaljevanjih), sem ugotovil, da obstaja modul, ki uporablja krmilni čip, ki ima že podobne oznake: TM1637. Gre predvsem za module s štirimi 7-segmentnimi displeji, primernimi za uporabo v digitalnih urah (slika 36), med katerimi se je znašel tudi en LED&KEY modul enostavnejše izvedbe (slika 37).
Ta vsebina je samo za naročnike
Moduli s čipom TM1637
Isti namen, isti proizvajalec, minimalna razlika v oznaki… TM1637 čipu sem zato najprej pristopil kot “mlajšemu bratu” TM1638 čipa in ga poizkusil integrirati v isto knjižnico. Vendar pa se je hitro pokazalo, da med temi čipi obstajajo pomembne razlike, tako v organizaciji internega spomina, kot tudi v komunikacijskem protokolu. Zato sem se odločil, da bom čipu TM1637 in modulom za prikaz časa posvetil lastne knjižnice, ki bodo olajšale njihovo uporabo iz programskega jezika Bascom-AVR in seveda, njihovo povezovanje z našimi MiniPin in MegaPin razvojnimi orodji. Tudi tukaj sem predvidel dve knjižnici: TM1637$SE.sub, ki pokriva osnovne funkcije samega integriranega vezja, in LED_clock$SE.sub, ki poenostavlja izpis na modulih za prikaz časa, ki so bili zasnovani na njemu.
Osnovno o integriranem vezju TM1637
Vse, kar morate vedeti o integriranem vezju TM1637, je prikazano na sliki 38. Čip podpira dve matrici: vhodno 8×2 (na sliki modro) in izhodno, 8×6 (na sliki rumeno). Na presečišča linij K1-K2 in KS1-KS8 vhodne matrice se vežejo tipke ali stikala, katerih stanja bere TM1637 v multipleksiranem načinu dela. Na presečiščni liniji SEG1-8 in GRID1-6 izhodne matrice se vežejo LEDice. To so lahko posamezne enobarvne ali večbarvne LEDice, diodne matrice ali pač 7-segmentni displeji. V vsakem primeru, anode LEDic se morajo spojiti na GRID, katode pa na SEG linije – obratno od načina povezovanja, kakor ga podpira TM1638. Ker ima TM1637 samo 6 GRID priključkov, ne more podpreti 7-segmentnih displejev s skupno katodo!
Takšen način povezovanja LEDic hkrati vključuje multipleksirani način dela, za kar “skrbi” sam TM1637. Če želite vključiti eno od LEDic, je dovolj, da postavite ustrezen bit v 6-bajtnem displej registru integriranega vezja. Povezava med položajem LEDice v matrici in naslovom bita v displej registru je prikazana v “rumeni” tabeli v zgornjem desnem delu slike 38. Naslovne lokacije so napisane znotraj oklepajev v heksadecimalnem zapisu in se gibljejo v razponu od (00h) do (05h). Če želite, npr, vključiti LEDico vezano na presečišču linij SEG5 in GRID2, je potrebno postaviti bit B4 na naslovni lokaciji (01h). V vsakem trenutku je lahko postavljeno poljubno število bitov v kateri koli kombinaciji.
Poleg vklapljanja in izklapljanja LEDic, lahko TM1637 krmili tudi z intenziteto njihove svetilnosti. Eden od 8 razpoložljivih nivojev intenzitete se postavlja s pomočjo Display Control ukazov in se nanaša na vse LEDice sočasno (ni možno postavljati intenzitete vsake posamezne LEDice). Z Display Control ukazi je tudi možno ugasniti in ponovno vklopiti celotno diodno matrico.
TM1637 ima en vhodni register, katerega vsebina je odvisna od tega, katero stikalo v vhodni matrici je sklenjeno. Če ni sklenjeno niti eno stikalo oziroma če niti ena K linija ni povezana z niti eno KS linijo, bodo v vhodnem registru postavljeni vsi biti (FFh). Ko s sklenjenim stikalom povežemo eno od K linij z eno od KS linij, se bo v vhodnem registru en ali več bitov postavilo v stanje “0”. Možne kombinacije so prikazane v “modri” tabeli na sliki 38 spodaj desno. Če sklenemo npr., stikalo med linijama KS1 in K1, bo vsebina vhodnega registra F7h. Opazili boste da TM1637 čip ne more pravilno prebrati stanja stikal, če hkrati sklenemo dva ali več stikal; če to naredimo, bo vsebina vhodnega registra nestabilna, oziroma bo zavzela kombinacijo ki ustreza samo enemu od sklenjenih stikal.
TM1637 podpira serijsko komunikacijo preko svojih DIO in CLK priključkov. Komunikacijo popolnoma krmili mikrokontroler, ki generira taktne impulze (CLK) in preko DIO linije vodila pošilja in sprejema podatke. Po podatkih proizvajalca gre za “poenostavljen I2C protokol”, v katerem je izpuščeno naslavljanje čipa. To sem preizkusil in s TM1637 čipom je zares možno komunicirati z uporabo standardnega Bascom-AVR I2C ukaza. Z dodatkom zelo važne pripombe: TM1637 pričakuje, da se mu najprej pošlje najmanj pomemben bit (LSB), medtem ko I2C protokol najprej pošlje najpomembnejši bit (MSB). To pomeni, da morate vse ukaze in podatke, ki jih želite poslati TM1637 čipu s pomočjo standardnih I2C ukazov, najprej pripraviti tako, da zamenjate vrstni red bitov (bit_7 <> bit_0, bit_6 <> bit_1 itd.). Napisal sem enostavno asemblersko rutino, ki vam bo olajšala to delo:
Dim Tm1637_byte As Byte ... Tm1637_flip: Loadadr Tm1637_byte , X ld r24,x ldi r23,8 Flip$$_1: ror r24 rol r25 dec r23 brne flip$$_1 st x,r25 Return
Ukaz ali podatek ki ga želite poslati TM1637 čipu najprej vpišite v spremenljivko Tm1637_byte, pokličite Tm1637_flip podprogram:
Gosub Tm1637_flip
in v spremenljivki Tm1637_byte vas bo pričakal “preobrnjen” ukaz ali podatek, ki ga sedaj lahko TM1637 čipu pošljete z uporabo standardnih Bascom-AVR I2C ukazov. Nikakršne dodatne knjižnice vam za to niso potrebne, vendar pa morate dobro spoznati interno organizacijo TM1637 čipa in njegove ukaze. Izpuščanje naslavljanja čipa v I2C protokolu ima še eno nesrečno posledico: če povežete več modulov s TM1637 čipi na I2C vodilo, bodo vsi prikazovali isto vsebino in branje stanja tipk (za module, ki jih imajo) ne bo možno. Prav tako na I2C vodilo ne bo možno povezati niti en čip, ki uporablja standardni (polni) I2C protokol, ker ga ne bo možno naslavljati: TM1637 se bo odzval na vsak poslan naslov in ga bo poizkušal interpretirati kot svoj ukaz ali podatek.
Zaradi tega razloga sem odstopil od uporabe Bascomovih I2C ukazov za komuniciranje s TM1637 čipi in v TM1637$SE.sub knjižnici sem predvidel lastne komunikacijske rutine za iste namene. Rutine podpirajo neodvisno komunikacijo z do šest TM1637 moduli. Da bi to bilo možno, mora vsak modul imeti svojo lastno DIO linijo, medtem ko je CLK linija skupna. Na ta način je možno vsakemu posameznemu TM1637 čipu poslati START in STOP signal in s tem z njim vzpostaviti in prekiniti komunikacijo. Shema na sliki 39 prikazuje eno takšno konfiguracijo s tremi TM1637 moduli; vsak modul prikazuje lastno vsebino in možno je brati stanje tipk (če jih moduli imajo). TM1637 moduli se lahko povežejo tudi paralelno, po shemi na sliki 40. V takšnem vezju se vsi moduli nahajajo na istem vodilu, (imajo skupni DIO in CLK liniji), prikazujejo isto vsebino, branje stanja tipk (če jih moduli imajo) ni možno. Paralelno spojene module v programu obravnavamo, kot da gre za samo en modul.
Knjižnica TM1637$SE.sub
Knjižnica TM1637$SE.sub podpira mreže od enega do maksimalno 6 TM1637 čipov oziroma modulov v neodvisni povezavi (število čipov/modulov je lahko večje, ker se vsi paralelno spojeni čipi/moduli štejejo kot eden).
Moduli so oštevilčeni od 1 do 6, številčenje mora biti narejeno po vrsti (če uporabljamo 3 module, morajo biti njihove številke 1, 2 in 3). Da bi podprogrami iz knjižnice znali korektno komunicirati s TM1637 čipi moramo v glavnem programu definirati število modulov na vodilu in tudi priključke mikrokontrolerja, ki krmilijo vodilo.
Knjižnica dimenzionira in uporablja naslednje globalne spremenljivke:
Dim Tm1637$current As Byte
Spremenljivka Tm1637$current vsebuje redno številko trenutno izbranega (aktivnega) TM1637 čipa (1-6). Njena vsebina se postavlja iz glavnega programa, preverjajo ga vsi komunikacijski ukazi in podprogrami iz knjižnice, zato da bi pred pošiljanjem ali prejemanjem podatkov aktivirali pravi čip.
Dim Tm1637$keys As Byte
Spremenljivka Tm1637$keys vsebuje kopijo vhodnih registrov TM1637 čipa v trenutku, ko je zadnjič izvršen ukaz za branje, Tm1637$read_keys.
Sledi opis ukazov iz knjižnice:
Ukaz Tm1637$write_command
Tm1637$write_command par1
Parametri: | par1 | Konstanta ali ime byte spremenljivke, ki vsebuje veljaven data ukaz |
Namen: | Pošlje ukaz Data Command tipa TM1637 čipu. | |
Opomba: | Dovoljene vrednosti parametra par1 so &B0000-&B1111, ukaz ignorira bite par1.7-par1.4. |
Ukaz Tm1637$write_control
Tm1637$write_control par1
Parametri: | par1 | Konstanta ali ime byte spremenljivke, ki vsebuje veljaven kontrolni ukaz |
Namen: | Pošlje ukaz Display Control tipa TM1637 čipu. | |
Opomba: | Dovoljene vrednosti parametra par1 so &B0000-&B1111, ukaz ignorira bite par1.7-par1.4. |
Ukaz Tm1637$write_byte
Tm1637$write_byte par1, par2
Parametri: | par1 | Konstanta ali ime byte spremenljivke, ki vsebuje veljaven naslov displej registra (0-5) |
par2 | Konstanta ali ime byte spremenljivke, ki vsebuje podatek (0-255), ki ga je treba vpisati na naslov dan s parametrom par1 | |
Namen: | Vpisuje byte podatek par2 v displej register, na naslov določen z vrednostjo parametra par1. | |
Opombe: | Dovoljene vrednosti parametra par1 so &B0000-&B0101, ukaz ignorira večje vrednosti.
Ukaz postavlja Data Command parametre normal mode, fixed address, write data. |
Ukaz Tm1637$write_block
Tm1637$write_block par1
Parametri: | par1 | Konstanta ali ime byte spremenljivke, ki vsebuje veljaven naslov displej registra (0-5) |
Namen: | Začetni ukaz z zaporednim vpisom; pošlje naslov bajta iz displej registra TM1637 čipu. | |
Opombe: | Dovoljene vrednosti parametra par1 so &B0000-&B0101; če se podajo večje vrednosti, lahko ukaz povzroči neželeno spremembo vsebine drugih spominskih lokacij displej registra.
Ukaz postavlja Data Command parametre normal mode, auto increment, write data. |
Ukaz Tm1637$write_data
Tm1637$write_data par1
Parametri: | par1 | Konstanta ali ime byte spremenljivke, ki vsebuje podatek za vpis (0-255) |
Namen: | Vpisuje podatek v predhodno naslovljen bajt displej registra TM1637 čipu. | |
Opombe: | Ukaz se uporablja med zaporednim vpisom podatkov.
Če je število bajtov, ki se jih poizkuša vpisati v enem bloku večje od razpoložljivega naslovnega prostora, lahko ukaz povzroči neželeno spremembo vsebine drugih spominskih lokacij displej registra. |
Ukaz Tm1637$write_block_end
Tm1637$write_block_end
Parametri: | nima |
Namen: | Zaključni ukaz z zaporednim vpisom. |
Ukaz Tm1637$read_keys
Tm1637$read_keys
Parametri: | Nima |
Namen: | Bere vsebino vhodnega registra TM1637 čipa in jo shrani v spremenljivko Tm1637$keys. |
Opomba: | Ukaz postavlja Data Command parameter read key scan data. |
Ukaz Tm1637$flip
Tm1637$flip par1
Parametri: | par1 | Ime byte spremenljivke, ki vsebuje podatek |
Namen: | Zamenjuje vrstni red bitov v spremenljivki (bit_0 <> bit_7, bit_1 <> bit_6 itd.). |
Poleg navedenih ukazov, knjižnica vsebuje še nekaj deset podprogramov, ki kličejo ukaze iz knjižnice. Te podprogrami imajo prefiks Tm1637$$ in priporočam, da se jih ne uporablja direktno iz uporabniškega programa.
Potem ko smo spoznali koncept in ukaze iz knjižnice TM1637$SE.sub, bomo način njihove uporabe ilustrirali s pomočjo enega primera. Naj poudarimo še enkrat, da so ukazi iz knjižnice orientirani na TM1637 čip in ne na modul, v katerem je vgrajen, in bo za rešitev neke konkretne naloge potrebno poznati shemo samega modula, tj. način na katerega so LEDice, 7-segmentni displeji, stikala in tipke povezani s čipom. Primer ki ga bomo analizirali nam lahko v tem pomaga.
Primer je napisan za razvojno orodje v katerem se nahajajo trije moduli s TM1637 čipom, povezani z mikrokontrolerjem ATtiny4313 po shemi na sliki 39. Krmilno vezje z mikrokontrolerjem se nahaja v razvojnem sistemu MiniPin, MegaPin, ali v nekem drugem podobnih možnosti. Tukaj bomo analizirali samo dele programa, ki se nanašajo na ukaze iz knjižnice; za popolno razumevanje dela je potrebno pogledati celoten program.
Program TM1637_test.bas
Namen programa je preverjanje vseh ukazov iz knjižnice TM1637$SE.sub. Program je razdeljen na 5 celot, od katerih se prva izvrši med inicializacijo (po resetu mikrokontrolerja), tri s pritiski na tipke TP1-TP3, zadnja pa znotraj glavne Do-Loop zanke.
Inicializacijska rutina zapolnjuje displej spomin TM1637 čipa z binarnimi enicami (&Hff) od najnižje do najvišje lokacije, menja intenziteto osvetlitve od najmanjše do največje, dvakrat ugasne in ponovno vklopi displej, nato zapolnjuje displej spomin z binarnimi ničlami (&H00); preverjajo se ukazi Tm1637$write_block, Tm1637$write_data, Tm1637$write_block_end in Tm1637$write_control. Postopek se ponavlja na vseh treh modulih, nakar ostaja izbran prvi modul.
- TP1: Začenši od lokacije 0, zapolnjuje displej spomin TM1637 čipa z vsebino &B00000001 do &B00111111; nato, ponovo začenši od lokacije 0, zapolnjuje displej spomin z vsebino &B10000001 do &B10111111; nato začenši od lokacije 5, nazaj zapolnjuje displej spomin z vsebino &B00000000 (preverja ukaz Tm1637$write_byte). Cilj je ugotoviti kako so številke in segmenti 7-segmentnega displeja povezani s TM1637 čipom. Ko spustimo tipko, na displeju ostane “zamrznjen” zadnji izpisan prikaz.
- TP2: Podobno kot TP1, samo da se tukaj uporabljajo ukazi Tm1637$write_block, Tm1637$write_data, Tm1637$write_block_end. Ko spustimo tipko, na displeju ostane “zamrznjen” zadnji izpisani prikaz.
- TP3: Menja izbrani modul (1->2->3->1…). Dokler je tipka pritisnjena, je število trenutno izbranega modula prikazano na LEDicah LED0 in LED1 (slika 39).
Znotraj glavne Do-Loop zanke se večkrat bere vsebina vhodnega registra TM1637 čipa trenutno izbranega modula in se ga prikazuje LEDicah LED0 – LED7.
Poglejmo kako je to realizirano v programu! Na začetku programa definiramo koliko TM1637 čipov bomo uporabljali koristiti (v tem primeru 3)
Const Tm1637_number = 3
in takoj nato definiramo komunikacijske priključke CLK, DO in DI:
Tm1637_clk Alias Portd.6 Tm1637_do Alias Portd.5 Tm1637_di Alias Pind.5
Opazili boste kako DO in DI delita en fizični priključek mikrokontrolerja, prvi ga uporablja kot izhodnega, drugi kot vhodnega. Ker je program napisan za tri TM1637 čipe, moramo še definirati tudi DO/DI priključka za preostala dva čipa:
Tm1637_do1 Alias Portd.4 Tm1637_di1 Alias Pind.4 Tm1637_do2 Alias Portd.3 Tm1637_di2 Alias Pind.3
Te definicije je nujno napisati preden pokličemo TM1637$SE knjižnice, zato jo v svoj program vključujemo šele sedaj:
$include "TM1637$SE.sub"
Z vključitvijo knjižnice bodo v programu postale dostopne vse njene globalne spremenljivke in ukazi, vendar bodo sestavni del programa postali samo tisti ukazi, ki se jih bo uporabljalo. V program se bo avtomatsko vključil samo inicializacijski podprogram, ki bo konfiguriral predhodno definirane CLK in DO priključke kot izhodne, postavil jih bo v ustrezno začetno stanje (STOP) in izbral bo prvi TM1637 čip. Opomba: Knjižnica uporablja novi način definiranja podprograma (Config Submode = New) zato je to treba upoštevati v kolikor se v programu uporabljajo podprogrami iz nekih drugih knjižnic ali lastni podprogrami.
Zdaj bomo z Display Control ukazom definirali želeni nivo osvetlitve, npr. 4/16:
Tm1637$write_control &B1010
Če želimo vključiti vse LEDice (ali vse segmente vseh displejev), je to najlažje narediti v blok-modu, ki ga pričnemo z Write_block ukazom:
Tm1637$write_block &B0000
Tukaj smo definirali kako displej registre TM1637 čipa zapolnjujemo od začetnega naslova, 0. Vseh 6 bajtov displej registra bomo zapolnili z vrednostjo &B11111111 s pomočjo Write_data ukaza: For I = 1 To 6 Tm1637$write_data &B11111111 Waitms 100 Next
Waitms 100 znotraj zanke upočasnjuje vklop LEDic/segmentov, da bi lahko spremljali zaporedje, po katerem se vključujejo in da bi lahko zaključili, kateremu naslovu displej registra ustreza katera skupina LEDic (ali kateri 7-segmentni displej).
Blok-mod vpisa moramo zaključiti z Write_block_end ukazom:
Tm1637$write_block_end
Isti učinek bi lahko dosegli z uporabo Write_byte ukaza:
For I = 0 To 5 Tm1637$write_byte I , &B11111111 Waitms 100 Next
Write_byte ukaz ima direkten pristop vsaki naslovni lokaciji displej registra, zato ga uporabljamo kadar želimo vpisati specifično vsebino na nek določen naslov:
Tm1637$write_byte 2 , &B00000111
če želimo zapolnjevati displej register s spremenljivo vsebino in pri tem preskočiti nekatere naslovne lokacije ali pač če želimo zbrisati vsebino vseh lokacij nazaj: For I = 5 To 0 Step -1 Tm1637$write_byte I , &B00000000 Waitms 250 Next
Z uporabo Write_control ukaza vpisujemo vrednosti v Display control register in s tem vplivamo na intenzivnost svetilnosti LEDic. Npr., zanka
For I = &B1000 To &B1111 Tm1637$write_control I Waitms 200 Next
bo menjala intenzivnost svetilnosti vključenih LEDic od najmanjše (&B1000) do največje (&B1111), dokler se zanka
For I = 1 To 2 Tm1637$write_control &B0000 Waitms 200 Tm1637$write_control &B1010 Waitms 200 Next
2 krat ne ugasne (&B0000) in ponovno vklopi (&B1010) vse LEDice (seveda, to se nanaša samo na diode, ki smo jih predhodno vključili; ukaz ne menja vsebine displej registra).
Če želimo prebrati vsebino vhodnega registra, bomo uporabili ukaz Read_keys:
Tm1637$read_keys
Ta ukaz bo prebral vsebino vhodnega registra TM1637 čipa in jo bo prenesel v globalno spremenljivko TM1637keys znotraj same knjižnice. Ker vsebina vhodnega registra TM1637 čipa ustreza trenutnemu stanju tipk/stikal, moramo pogosto brati in analizirati njegovo vsebino; zato je v testnem programu ta procedura vpisana znotraj glavne Do-Loop zanke. Namesto analize v testnem programu zgolj prikazujemo prebrano vsebino na LEDicah LED7-LED0 (slika 39):
Portb = Tm1637$keys
Ko na priključenem modulu gledamo učinke, ki jih povzročajo posamezni deli testnega programa, ne preverjamo samo načina, s katerim delajo in kako se uporabljajo ukazi iz knjižnice, pač pa lahko spoznamo tudi, kako so posamezne komponente nepoznanega modula povezane s TM1637 čipom. Tako sem prišel do sheme enostavnega LED&KEY modula s slike 41. Spotoma sem ugotovil, da so oznake v verziji modula, ki sem ga imel na razpolago napačno natisnjene: prvi priključek z leve, označen kot SG1, je pravzaprav K2, za njim pa sledijo SG1-SG8, tako da je priključek označen kot K2 pravzaprav SG8.
Opomba: V praksi se je pokazalo, da posamezni moduli ne podpirajo od proizvajalca deklarirane hitrosti branja vhodnega registra TM1637 čipa. Nejasno je, ali se vzrok za to skriva v samem čipu ali v komponentah na modulu. Napako sem kompenziral z zmanjševanjem hitrosti prenosa med izvrševanjem ukaza Tm1637$read_keys na približno 20 kbs, kar je podaljšalo čas branja na še vedno zanemarljivih 0,5 ms. S takšno hitrostjo sem uspešno bral vse TM1637 čipe, ki so mi bili dostopni. Če naletite na čip, ki se ga ne da pravilno brati niti pri tako zmanjšani hitrosti komunikacije, potem poizkušajte na DIO vhod vezati dodatni pull-up upor 4,7 kΩ ali 2,2 kΩ (proizvajalci modula sledijo priporočilom proizvajalca in zato na CLK in DIO vhode postavljajo “filtre za odpravo motenj” ki so sestavljeni iz pull-up upora 10 kΩ in kondenzatorja kapacitete 100 pF spojenega proti masi, če pogledate sliko 41).
Vsi primeri, ki smo jih do sedaj navedli, so se nanašali na prvi TM1637 modul, ker je selektiran v trenutku, ko smo vključili TM1637$SE knjižnico. Če si želimo komunicirati s nekim drugim modulom, je dovolj spremeniti vrednost globalne spremenljivke Tm1637$current:
Tm1637$current = 3
Knjižnica bo sedaj izbrala tretji TM1637 modul, in zato bodo vsi ukazi in podatki po tem posredovani njemu.
Knjižnica TM1637$SE.sub omogoča pristop vsakemu, na TM1637 čipu baziranemu modulu, vendar ne nudi končne rešitve. Če želite elegantno uporabljati takšen modul, so potrebni podprogrami “višjega nivoja”, ki že imajo v sebi vgrajene posebnosti posameznega modula. Eno takšno nadgradnjo bomo predstaviti v naslednjem nadaljevanju. Gre o knjižnici LED_clock$SE.sub, ki je prilagojena modulom za prikaz časa; z uporabo ukazov iz te knjižnice, delo s navedenimi moduli ne bo zahtevnejše od uporabe običajnega LCD modula!