23. 7-segmenttinäytön ohjaus

Julkaistu: sunnuntai 12.2.2017

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 bittejä 4 kertaa vasemmalle ja sijoitetaan saatu arvo takaisin muuttujaan (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.