Mikrokontrollerin suorittama koodi ei usein näy käyttäjälleen fyysisesti, minkä vuoksi esimerkiksi ledejä käytetään ilmaisemaan, että laite toimii oikein. Monesti on kuitenkin hyödyllisempää ilmaista laitteen toimintaa visuaalisemmin, esimerkiksi 7-segmenttinäytön avulla. PC-maailmasta joillekin voi tällaiset näytöt olla tuttuja PC:n emolevyltä, missä vikakoodeja ilmaisemaan on käytetty yhtä tai useampaa 7-segmenttinäyttöä. Mikäli 7-segmenttinäyttö tuntuu vielä oudolta käsitteeltä, voit lukea siitä lisää 7-segmentin elektroniikkasivulta.
Tässä osassa otetaan selvää, kuinka Launchpadin avulla saadaan näytölle tulostumaan numeroita. Sitä varten tarvitaan hieman muuta elektroniikkaa.
Tarvittavat osat
Jotta näyttö saataisiin pelaamaan niinkuin haluamme, tarvitaan tätä kytkentää varten vastuksia, johtimia, koekytkentä alusta ja näytönohjainpiiri sekä itse näyttö. Alla näet osalistan kokonaisuudessaan:
- 7-segmenttinäyttö (GL8E040)
- HCF4511 (BE) BCD-7segmentti dekooderi
- 7 kpl 220 ohmin vastuksia
- Johtimia
- Launchpad + MSP430G2231 mikrokontrolleri
- Koekytkentäalusta
Näytönohjaimen kytkeminen mikrokontrolleriin
Alla olevasta kuvasta nähdään tässä esimerkissä käytetty kytkentä.
Ja alla olevasta kuvasta nähdään kytkentä käytännössä:
Ulkopuolisen piirin käyttö voi hieman ihmetyttää, sillä 7-segmenttinäytön pystyisi toki kytkemään suoraan mikrokontrollerin IO-pinneihin. Tämä ratkaisu söisi kuitenkin kaikki käytettävissä olevat IO:t ainakin MSP430G2231 ohjaimelta (LE + 7-segmenttiä = 8 pin). Lisäksi ohjelma olisi monimutkaisempi kuin mitä se on nyt. Tällä tavalla kytkettynä mikrokontrollerilta "syödään" 5-pinniä ja tästäkin on vielä vara nipistää poistamalla LE-pinni käytöstä (ja kytkemällä se kiinteästi "0" tilaan).
Mikäli näytönohjainpiiri ei ole ennestään tuttu, niin kannattaa tarkastaa sen toiminta piirin datalehdestä (linkki). Piiriä ohjataan BCD formaatilla. BCD tulee sanoista "Binary Coded Decimal" ja se yksinkertaisesti tarkoittaa desimaalilukuja, mitkä on esitetty binäärisessä muodossa. Tässä tarvitaan vain 4 ohjaussignaalia ja kun kukin ohjaussignaali voi olla vain kahdessa eri tilassa, niin mahdollisia vaihtoehtoja pinnien tiloille on 24 = 16. Wikipedia tarjoilee tästäkin aiheesta lisää tietoa (linkki).
LE-pinniä ("Latch Enable") voidaan käyttää jos halutaan säilyttää syötetty numero näytöllä. Jos esimerkiksi kirjoitetaan luku 7 BCD-dekooderille ja aktivoidaan LE, niin ohjauspinnien tilat pysyvät samana jolloin luku 7 voidaan myös lukea HCF4511-piiriltä.
Esimerkki 1: Numerot 0 - 9 näyttöön
Aivan ensimmäiseksi täytyy tehdä ohjelma, minkä avulla saadaan tulostettua numeroita näytölle. Lisäksi hyödynnetään ohjelmassa jo aiemmin esille tulleita funktioita ja makroja. Ohjelman lähdekoodi löytyy alta.
#include <msp430g2231.h> // Ohjelmamuistin koko tavuina (byte) Flash/RAM = 238/2 #define LED_RED (BIT0) #define LED_GREEN (BIT6) #define INIT_LAUNCHPAD_LEDS (P1DIR |= LED_RED+LED_GREEN) #define LED_OFF (P1OUT &= ~(LED_RED + LED_GREEN)) // jos nämä on kytketty muihin, niin nämä voidaan muuttaa. // Jos LE-pinni on kytketty kiinteäksi, kaikki LE_ alkuiset // definet voidaan poistaa #define LE_PIN (BIT3) #define LE_PORT (P1OUT) #define LE_SET (LE_PORT |= LE_PIN) #define LE_CLEAR (LE_PORT &= ~LE_PIN) #define SEGMENTPORT (P1OUT) #define SEGMENTDIR (P1DIR) // Jos alla olevan muuttaa, niin SetSegmentNumber funktio // ei toimi... Paitsi tietenkin jos laitat sen toimimaan ;) #define SEGMENTPINS (BIT7 + BIT6 + BIT5 + BIT4) // Launchpad funktiot inline void InitLaunchpad(); // 7-Segmenttifunktiot void InitSegmentDriver(); void SetSegmentNumber(unsigned char n); void main(void) { unsigned char i=0; WDTCTL = WDTPW + WDTHOLD; // watchdog pysäytys InitLaunchpad(); InitSegmentDriver(); while(1) { // Tulostetaan numerot 0 ... 9 SetSegmentNumber(i++); __delay_cycles(1000000); if(i > 9) { i = 0; } __no_operation(); // aseta breakpoint tähän } } inline void InitLaunchpad() { INIT_LAUNCHPAD_LEDS; // Ledien alustus LED_OFF; // LED1 ja LED2 pois päältä // S2 (P1.3) kytkin tuloksi ylösvetovastuksella P1DIR &= ~BIT3; P1IE |= BIT3; P1IES |= BIT3; P1REN |= BIT3; P1OUT |= BIT3; // alustetaan CPU:n kello 1 Mhz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; // BCSCTL3 = XCAP_3; // kiteen alustus on kommentoitu koska sitä ei nyt tarvita } void InitSegmentDriver() { // asetetaan pinnit lähdöksi ja nollataan kaikki SEGMENTDIR |= SEGMENTPINS + LE_PIN; LE_CLEAR; // asetetaan segmenttipinnit "1" tilaan, jolloin näytössä // ei näy mitään. Jos porttipinnit on "0" niin 0 näkyy näytössä. SEGMENTPORT |= SEGMENTPINS; LE_SET; } void SetSegmentNumber(unsigned char n) { // siirretään numero (joka mahdollisesti on 0 - 9) // ylempään 4 bittiin n <<= 4; LE_CLEAR; // Latch Enable pinnin asetus nollaan SEGMENTPORT = 0xF0 & n; // maskaus ja porttibittien asetus LE_SET; // Latchaus jotta numerot jäävät näytölle }
Lataa tämän esimerkin CCSv5 projekti tästä.
Ohjelman toiminta
Ohjelmassa alustetaan ensin mikrokontrolleri toimimaan launchpadilla 1 MHz:n nopeudella. Tämän jälkeen alustetaan 7-segmenttinäytön ohjainpiiriä ohjaavat porttipinnit. Pääohjelmassa tulostetaan numerot 0 ... 9 7-segmenttinäytölle niin, että noin sekunnin välein uusi numero tulostuu entisen tilalle. Luvun "ylimenon" tarkistus tapahtuu ehtolauseessa if ja kun ehto on tosi, niin luku nollataan. __no_operation() funktion kohdalle voit asettaa breakpointin ja tutkia, kuinka ohjelma toimii.
SetSegmentNumber(..) funktiolle annetaan parametrina näytettävä luku. Funktio yksinkertaisesti asettaa porttipinnit vastaavaan binääriseen tilaan, kuin mikä sille on desimaalina annettu (no okei, binääriähän tämä kaikki loppupeleissä on, mutta ymmärtänet pointin).
Ainoa erikoisuus, mikä aiemmin ei ole esimerkeissä vielä tullut esille on bittien siirto. Bittejä voidaan C-kielessä siirtää operaattorilla << ja >>. Ensimmäisenä toimintona SetSegmentNumber(..) funktiossa siirretään muuttujan n bittejä 4 kertaa vasemmalle ja sijoitetaan saatu arvo takaisin muuttujaan n (siitä syystä operaattori <<=, joka on 'suomennettuna' siirto ja sijoitus). Siirto tehdään siksi, koska 7-segmenttinäyttö on kytketty portin P1 ylempään puolikkaaseen tavuun (P1.4 - P1.7).
Näin ollen esimerkiksi luvusta 1 (0b00000001) tuleekin oikeasti luku 32 (0b00010000). Asiaa on havainnollistettu alla olevissa taulukoissa.
Esimerkiksi luku 1 ennen siirtoa:
n = 1 | ||||||||
Bitti | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
Portti | P1.7 | P1.6 | P1.5 | P1.4 | P1.3 | P1.2 | P1.1 | P1.0 |
Tila | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Ja luku 1 siirron jälkeen:
n <<= 4; | ||||||||
Bitti | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
Portti | P1.7 | P1.6 | P1.5 | P1.4 | P1.3 | P1.2 | P1.1 | P1.0 |
Tila | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
Ja koska porttipinni P1.4 on kytketty 7-segmenttiohjaimen A-tuloon (nasta 7), niin näytölle tulostuu numero 1, koska HCF4511 piirin tuloissa näkyy luku 1.
Alla olevassa kuvassa on esitettynä miten esimerkiksi numero 4 näkyy 7-segmenttinäytöllä. Kuvan alla on lisäksi esitetty taulukolla, kuinka porttipinnien nastat ovat numeron 4 asetuksen jälkeen.
Bitti | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
Portti | P1.7 | P1.6 | P1.5 | P1.4 | P1.3 | P1.2 | P1.1 | P1.0 |
Tila | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
Huomannet, että porttipinni P1.3 on asetettu myös "1" tilaan. Tämä johtuu siitä, että porttipinni P1.3 ohjaa Latch Enable pinniä. Itse numeron arvoon sillä ei ole siis merkitystä. LE-pinnin voi tästä piiristä toki kytkeä maahan, jolloin vapautuu käyttöön P1.3. Tällöin kirjoitettua lukua ei kuitenkaan voi enää lukea takaisin, vaan numero häviää mikäli portin 1 tilaa vaihdetaan.
Mikäli asia ei täysin auennut, niin suosittelen tutkimaan näytön toimintaa debuggerin avulla ja mahdollisesti lukemaan yllä olevat selitykset uudestaan. Mikrokontrollerin porttipinnien (P1OUT, P1DIR) rekisterien tiloja voit tarkastella ja muutella debuggerin Registers -ikkunasta:
Tässäpä kaikki tällä kertaa. Edellisiä osia yhdistelemällä saat tästäkin sovelluksesta mielenkiintoisemman. Esimerkiksi tietokoneohjatun 7-segmenttinäytön tekeminen ei pitäisi olla kovin suuri työ - täytyy vain hieman soveltaa.