16
1 7.4. Oheisrautaa. LCD-näyttö, Liquid Crystal Display 10.01.2008 pva, kuvat jma ”Useat niistä, jotka ovat pyrkineet maailman valoksi, ovat löytäneet itsensä lyhtypylväästä.” - tuntematon Sisältö Yleistä LCD-näytön toiminta LCD-näytön ohjelmointi Mitä on tiedettävä lcd-raudasta ennen ohjelmointiin ryhtymistä: Katsotaan mitä lcd_tat.h sisältää lcd_1.c, esimerkki Toinen esimerkki printf()-funktio Merkkijono Merkkijonon esittely fdevopen ja sen käyttö lcd-näytön kanssa Yleistä Kuten PC-ympäristössä, myös pienissä sulautetuissa järjestelmissä tarvitaan numeroiden ja kirjaimien (merkkijonojen) käsittelyä. Tosin paljon harvemmin ja pienemmissä mittasuhteissa. Miten muuten voidaan tulostaa lämpömittaritietoja, kellonaika, varoituksia, jne.? LCD-näyttö on tyypillinen sulautetun systeemin näyttö. Sillä voidaan tulostaa ASCII- merkkejä, siis tavallisia numeroita ja kirjaimia sekä erilaisia yksinkertaisia graafisia kuvioita. Varsinaisten kuvien tulostukseen tarvitaan erityinen graafinen lcd-näyttö. Tässä käsitellään vain alfanumeerisen eli merkkinäytön perustekniikkaa.

7.4. Oheisrautaa. LCD

Embed Size (px)

Citation preview

Page 1: 7.4. Oheisrautaa. LCD

1

7.4. Oheisrautaa. LCD-näyttö, Liquid Crystal Display 10.01.2008 pva, kuvat jma ”Useat niistä, jotka ovat pyrkineet maailman valoksi, ovat löytäneet itsensä lyhtypylväästä.” - tuntematon Sisältö Yleistä LCD-näytön toiminta LCD-näytön ohjelmointi Mitä on tiedettävä lcd-raudasta ennen ohjelmointiin ryhtymistä: Katsotaan mitä lcd_tat.h sisältää lcd_1.c, esimerkki Toinen esimerkki printf()-funktio Merkkijono Merkkijonon esittely fdevopen ja sen käyttö lcd-näytön kanssa Yleistä

Kuten PC-ympäristössä, myös pienissä sulautetuissa järjestelmissä tarvitaan numeroiden ja kirjaimien (merkkijonojen) käsittelyä. Tosin paljon harvemmin ja pienemmissä mittasuhteissa. Miten muuten voidaan tulostaa lämpömittaritietoja, kellonaika, varoituksia, jne.? LCD-näyttö on tyypillinen sulautetun systeemin näyttö. Sillä voidaan tulostaa ASCII-merkkejä, siis tavallisia numeroita ja kirjaimia sekä erilaisia yksinkertaisia graafisia kuvioita. Varsinaisten kuvien tulostukseen tarvitaan erityinen graafinen lcd-näyttö. Tässä käsitellään vain alfanumeerisen eli merkkinäytön perustekniikkaa.

Page 2: 7.4. Oheisrautaa. LCD

2

Toiminta Nestekide on eräitten orgaanisten yhdisteiden nestemäisen ja kiinteän olomuodon välivaihe. Se on kuin neste, mutta sähköisesti ja optisesti kiteen kaltainen. Sähkökentän avulla nestekiteen molekyylien asentoon voidaan vaikuttaa ja asento taas vaikuttaa valon läpäisyyn. LCD-näyttötekniikoita on toiminnaltaan useita erilaisia. Yksinkertaisin toiminnaltaan ja ohjaukseltaan on sulautetuissa yleisimmin käytetty mustavalkoinen merkkinäyttö. Siinä kahden lasilevyn väliin on pantu ohut, noin 10 um:n nestekidekalvo. Lasilevyjen pintaan, siis kumpaankin, tehdään näkymättömillä hyvin ohuilla johtimilla ruudutus, pistematriisi tai segmenttejä. Johtimiin tuodaan jännite, joilla saadaan aikaan levyjen välille sähkökenttä. Ohjaamalla sähkökenttää, vaikutetaan nestekidemolekyylien asentoon. Asento vaikuttaa valon läpäisyyn, yhdessä asennossa valo pääsee läpi, toisessa ei. Jos panemme näytön takareunaan peilin, niin valoa läpäisevä piste näkyy kirkkaana ja läpäisemätön tummana. Parempi kontrasti saadaan aikaan, jos peilin tilalle asennetaan valolähde, pieni loisteputki tai LED-diodeita. Ilman taustavaloa, tehontarve on vähäinen. Rakenneidea on yksinkertaisen nerokas. Monimutkainen siitä tulee, jos halutaan saada aikaan värejä. Vaikeudet kasvavat edelleen, jos näytöistä halutaan tehdä suurikokoisia. Paremmat laatuisissa lcd-näytöissä käytetään polarisoituja laseja estämään tai päästämään valonsäteet eteenpäin. Segmenttien valonläpäisyä ohjataan sähkökenttien avulla. Ohjauksesta huolehtii näytön sisäinen CPU ja sen elektroniikka. Merkkinäytön ohjaus Merkkinäytöt tehdään tänä päivänä pääasiassa Hitachin 44780 normin mukaiseksi. Kaikki sen liitäntänastat ovat aina samannumeroisia ja toimintaperiaate on siis sama riippumatta valmistajasta tai liittimen/liitännän mekaanisesta muodosta.

Kuva 7.4.1. Hitachi 44780 lohkotasolla.

Page 3: 7.4. Oheisrautaa. LCD

3

44780-normin näyttö sisältää: - lcd-moduulin - mikro-ohjaimen, joka ohjaa itse näyttötapahtumaa - RAM-muisti, johon tulostettavat merkit tallennetaan ja - ROM-merkkimuistin, josta etsitään ASCII-merkkiä vastaavat ohjaussignaalit

Näytön dataväylä on 8-bittinen ja sen kautta näytölle menevät merkit ovat joko käskyjä tai dataa. Ohjauspulssien avulla käskyt (esim. kertoo merkin paikan) menevät käskyrekistereihin ja näytettävä data (ASCII-koodi) datarekisterin kautta näyttömuistiin ja edelleen näyttöön. Merkit voivat olla kirjaimia, numeroita tai erikoismerkkejä. Niitä voi tehdä itsekin. ASCII-koodia vastaava bittikuvio löytyy merkki-ROMmista ja näytön sisäinen CPU hoitaa sen näytöllä oikeaan riviin ja sarakkeeseen. LCD-näytön ohjaussignaalit LCD:n pinninumero

Nimitys Merkitys

1 Vss Power Supply, GND 2 Vcc Power Supply, +5 V 3 Vee GND tai pot. liuku, Kontrasti 4 RS Register Select.

0 = Instruction input 1 = Data input

5 RW Read/Write, 0 = Write to LCD 1 = Read from LCD

6 E Enable, 1>>0 7 DB0 GND, jos 4-bitin ohjaus, LSB 8 DB1 GND, jos 4-bitin ohjaus 9 DB2 GND, jos 4-bitin ohjaus 10 DB3 GND, jos 4-bitin ohjaus 11 DB4 Data 4 12 DB5 Data 5 13 DB6 Data 6 14 DB7 Data 7, MSB 15 Anode Taustavalo +V, 16 Cathode Taustavalo GND Taulukko 7.4.1. 44780-normin mukaisen LCD-näytön liitäntä. Mikro-ohjain lähettää lcd-näytölle 8-bittisen ohjaus- tai datatavun. Tavallisimmin kuitenkin käytetään 4-bittistä toimintomoodia, jolloin voidaan samasta portista (8 bittiä) hoitaa komennot ja datan siirto. Silloin ohjauskoodista tulee hieman monimutkaisempi koska data pitää lähettää kahdessa osassa (nibble). Ohjauskomentojen ja datan siirtäminen on ajoituksen kannalta vaativaa puuhaa, koska lcd:n ohjaus vaatii aikaa. Se on hidas. Siksi komentojen välillä on käytettävä viivesilmukoita. Jos näytössä on taustavalo, sitä ohjataan pinneistä 15 = anodi ja 16 = katodi.

Page 4: 7.4. Oheisrautaa. LCD

4

LCD-näytön liittäminen AVR-mikro-ohjaimeen Japanilaisen Hitachin LCD-näytön ohjaustapa HD44780 on vallitseva normi sulautettuihin soveltuvissa merkkinäytöissä. Valmistaja saa olla kuka tahansa, sen ohjaus tapahtuu aina samalla tavalla.

Kuva 7.4.2. Hitachi 44780-lcd-näytön 4-bitin liitäntä LCD-näytön käyttöönotto Kun käyttöjännite on kytketty LCD-näyttöön, niin ensimmäinen tehtävä on näytön kontrastin säätäminen. Se on tarpeen tehdä vain kerran. Säädä trimmeripotentio-metrillä kontrastijännite sellaiseen arvoon, että näyttöön tulee (vähintään) yksi rivi (tai osa siitä) grafiikkapisteistä muodostuneita tummia suorakaiteita. Nämä näkyvät ilman datan ohjaustakin. Kun ajat toimivaa ohjelmaa, niin säädä uudelleen kontrastia - nyt sellaiseen arvoon, jossa merkit näkyvät parhaiten. Tämän jälkeen ei säätöön enää tarvitse koskea. LCD-näytön ohjaaminen on hyvin monimutkaista. Siksi aluksi kannattaa tyytyä valmiisiin malleihin ja taitojen kehittyessä, tehdä omia sovelluksia. LCD-näytön ohjelmointi Tommi Tilli on tehnyt mainion LCD-näytön (Hitachi 44780) ohjausohjelman. Ja mikä parasta, hän on luovuttanut kaiken vapaaseen opetuskäyttöön. Kiitos. Tiedostot ovat, versiopäivitys 15.8.2007: lcd_tat.h lcd_tat.c Header-tiedosto sisältää tarvittavat näyttöön ja porttiin liittyvät määritykset ja funktioiden esittelyt. Funktioiden määritykset (sisällöt) löytyvät lcd_tat.c tiedostosta. Tee työkansio lcd-näytön harjoituksille ja kopioi sinne lcd_tat.c ja lcd_tat.h tiedostot. Ne hoitavat lcd-näytön tarvitsemat ajurikoodit, näin oma työmme helpottuu. Jos teet projektin, joka käyttää LCD-näyttöä, on projektikansioon kopioitava molemmat ajurit.

Page 5: 7.4. Oheisrautaa. LCD

5

PV-EMOssa on (kun siihen on liitetty PV-M32-kortti) A-porttiin kytkettynä 2*16 merkin LCD-näyttö. LCD:n taustavaloa ohjataan ON/EI C-portin PC.0-bitillä. Mitä on tiedettävä lcd-raudasta ennen ohjelmointiin ryhtymistä?

- portti johon lcd-näyttö on asennettu - miten lcd-näyttö on liitetty porttiin, 4/8-bittinen, pinnit - millainen näyttö, rivien määrä ja merkkien määrä rivillä

Nämä tiedot on koottu erityiseen header-tiedostoon, tässä tapauksessa lcd_tat.h. Kaikki tämän dokumentin koodit on tehty tuon headerin oletuksella, eli: 2*16 merkin näyttö A-portissa. Katsotaan mitä lcd_tat.h sisältää LCD:n liittäminen mikro-ohjaimen porttiin: Comments: LCD (Hitachi HD44780 -based) control fun ctions. An LCD must be connected like the table below shows : PORT Bit 0 -> LCD-4 (RS) Bit 1 -> LCD-5 (RW) Bit 2 -> LCD-6 (EN) Bit 4 -> LCD-11 (D4) Bit 5 -> LCD-12 (D5) Bit 6 -> LCD-13 (D6) Bit 7 -> LCD-14 (D7)

LCD-näytön käyttöönottoa varten on seuraava funktio: LCD_init(_Bool fCharfix, _Bool fCursor, _Bool fBlin k) -function initializes the LCD for operation. First argument tells whether the character fix will be enabled or not. Character fix is needed to display some charac ters (ASCII > 127) properly. If second argument is true (1), a cursor will be shown on the LCD. If third argument is true, the cursor will blink if it is enabled.

Koodiin tulee esim. LCD_init(1, 0, 0); Korjattu (mukana myös erikoismerkit) näyttömoodi, ei kursoria, eikä se vilku. Portin, johon lcd-näyttö asennetaan, määrittely: /*A PORT where the LCD is connected and the Data Di rection Register * of that PORT.*/ #define LCD_PORT PORTA #define LCD_PIN PINA #define DIRECTION_REGISTER DDRA

Jos lcd-näyttö asennetaan johonkin muuhun kuin A-porttiin, on ylläoleva määritys päivitettävä. Siis esim. B-portin kyseessä ollen: PORTB, PINB, DDRB.

Page 6: 7.4. Oheisrautaa. LCD

6

Näytön liittäminen AVR:n porttiin: /** * Bit connections between the LCD and the PORT */ #define LCD_4_RS 0x01 // Bit 0, Register Select l ine #define LCD_5_RW 0x02 // Bit 1, ReadWrite control line #define LCD_6_EN 0x04 // Bit 2, Enable //#define LCD_11_D4 0x10 // Bit 4 //#define LCD_12_D5 0x20 // Bit 5 //#define LCD_13_D6 0x40 // Bit 6 #define LCD_14_D7 0x80 // Bit 7

Seuraavaksi tulee erilaisia määrityksiä. LCD:n ongelma on hitaus, siksi ohjainohjelmassa tarvitaan erilaisia viiveitä. //** Delays needed to use the LCD **// /** * A delay between commands. The delay should be ab out 450ns (might vary * a little between different LCDs). */ #define COMMAND_DELAY_US 1 // The delay should be at least 120us. #define SHORT_DELAY_US 128 // Delay should be at least 15ms. #define STARTDELAY_MS 16 // Second delay used in the initialization of the L CD. // Delay should be about 5ms. #define STARTDELAY_SHORT_MS 5

Näytön ohjaamiseen tarvittavien funktioiden esittelyt, prototyypit, on listattu seuraavaksi. Itse funktiot löytytävät lcd_tat.c-tiedostosta. //***********************// //* Function prototypes *// //***********************//

Sitten koodin tekoon. lcd_1.c, esimerkki /************************************************** ******** Project : lcd_1.c Hardware: PV-M32, (4 MHz) + PV-EMO eli LCD on PORTA Software : WinAVR-20071221 Date : 26.9.2007 + 10.1.2008 Author : pva Comments: tulostaa tekstiä ja numeroita lcd-näyttöö n Kopioi lcd_tat.c ja lcd_tat.h tiedostot projektin k ansioon.

Page 7: 7.4. Oheisrautaa. LCD

7

Klikkaa hiiren oikealla (vasemmalla olevan hakemist opuun) Source Files, Add Existing Source Files, lisää lcd_ tat.c - tällä kerrotaan C-kääntimelle, että sen pitää kääntää myös lcd_tat.c *************************************************** *******/ #include <avr/io.h> #include <util/delay.h> #include "lcd_tat.h" #define RIVI 0 #define SARAKE 0 // prototyyppi void wait(uint16_t time); int main(void) { LCD_init(1, 0, 0); // lcd ON, kursori EI, kursori EI VILKU uint16_t numero = 0; while(1) { LCD_Clear(); // näytön tyhjennys ja kursori "ko tiin" LCD_WriteString("AVR MCU"); LCD_SetCursorXY(SARAKE, RIVI+1); LCD_WriteUINT(numero); wait(200); numero++; } } // *** Primitive wait() *** void wait(uint16_t time) { volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); } Analysointi Ensin pitää kopioida lcd_tat.c ja lcd_tat.h tiedostot projektikansioon, kuten kommenteissa kerrotaan. AVRStudiossa lcd_tat.c tiedosto otetaan mukaan painamalla hiiren oikealla napilla Source Files ja sitten Add Existing Source Files... (editorissa vasemmalla tiedostoikkunassa). Sitten pääohjelmalle kerrotaan, että otamme lcd-näytön käyttöön, se tapahtuu kirjoittamalla koodiin rivi LCD_init(1, 0, 0); // lcd ON, kursori EI, kursori E I VILKU Tämän koodi toimii kuten kommentissa on kerrottu. Sen tarkempi sisältö löytyy tiedostosta lcd_tat.c. Seuraava rivi tekee kuten jo funktion nimestä selviää ja kommentti vielä vahvistaa. LCD_Clear(); // näytön tyhjennys ja kursori "kotiin " LCD_WriteString("AVR MCU");

Page 8: 7.4. Oheisrautaa. LCD

8

Sitten näyttöön kirjoitetaan merkkijono. Lainausmerkkien väliin voi laittaa kaikkia näyttömme osaavia merkkejä. Tekstin pituus on riippuvainen näytöstä. LCD_SetCursorXY(SARAKE, RIVI+1); LCD_Write_UINT(numero);

Ja sitten siirretään kursori seuraavalle riville ja kirjoitetaan näyttöön numero-muuttujan arvo. Tommin tekemän ajuriohjelmiston hyvä puoli on se, että hän on käyttänyt funktoiden nimenä hyvin toimintaa kuvaavia nimiä. Otetaan mallia! Ei tarvitse välttämättä paljon kommenttia kirjoittaa, kun itse koodi kertoo mitä tehdään. Toinen esimerkki /************************************************** ******** Project : lcd_yksitellen_m32.c Hardware: PV-M32, (4 MHz) + PV-EMO eli LCD on PORTA Software : WinAVR-20071221 Date : 10.1.2008 Author : pva Comments: tulostaa tekstiä lcd-näyttöön merkki kerr allaan Kopioi lcd_tat.c ja lcd_tat.h tiedostot projektin k ansioon. Klikkaa hiiren oikealla (vasemmalla olevan hakemist opuun) Source Files, Add Existing Source Files, lisää lcd_ tat.c - tällä kerrotaan C-kääntimelle, että sen pitää kääntää myös lcd_tat.c *************************************************** *******/ #include <avr/io.h> #include <util/delay.h> #include "lcd_tat.h" #define RIVI 0 #define SARAKE 0 // *** Primitive wait() *** void wait(uint16_t time) { volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); } int main(void) { uint8_t i; uint8_t merkkijono[] = "Upotettu_AVR"; LCD_init(1, 0, 0); while(1) { LCD_Clear(); // näytön tyhjennys ja kursori "ko tiin" for(i=0; i<12; i++) { LCD_SetCursorXY(SARAKE+i, RIVI); LCD_WriteChar(merkkijono[i]); // merkkitaulukon kirjaimet yksi kerrallaan - >lcd wait(200); } } }

Page 9: 7.4. Oheisrautaa. LCD

9

Analysointi Edellisen koodin toiminnan kun ymmärtää, niin tämäkin on ”selvää tekstiä”. Muotoileva tulostus printf()-funktio PC-koneissa tulostus ohjataan ulostulo-tiedostoon, joka on yleensä menee näyttöön. Kaikkien C-kielikurssien ensimmäinen opittava ohjelma tulostaa PC-näytölle printf-funktiolla ”Hello World!”. Mutta miksi se on ongelma sulautettujen C-kielessä? Koska sitä on vaikea saada mahdutettua mukaan. Sulautettujen näyttönä on tavallisimmin pieni, 1- tai useampirivinen lcd-merkkinäyttö. Toisinaan on tarve ohjata tulostus sarjaporttiin ja sitä kautta eteenpäin vaikka PC:n terminaaliohjelmaan tai muulle oheislaitteelle (modeemi, Nokian kännykkä, jne.). Silloin suppeastakin printf-funktiosta on hyötyä, koska se kykenee muotoilemaan tulostettavaa dataa käyttäjän haluamalla tavalla. Printf on ns. formatoitu tulostuskomento, jossa c-käännin hoitaa kaiken:

- tulostuksen - tulostuksen muotoilun - tyyppimuunnokset, jne.

Kaupallisissa AVR-C-kääntimissä on printf()-funktio ja löytyy se avr-gcc:stäkin. Valitettavasti se on tehtävä hyvin suppealla ja epästandardilla ’virityksellä’, sillä oikea printf()-funktio vaatii muistitilaa toteutuksesta riippuen 4 – 30 kB. Ja kun meidän käyttämissä mikro-ohjaimissa on muistia yleensä niin vähän, ettei sinne ’oikea’ printf() mahdu. Siksi yleensä päädytään ratkaisuun, jolla hoidetaan merkkijonot muilla keinoin. Toisaalta kuitenkin on hyvä tietää, että AVR-GCC-yhteisön tuottamana yleisessä jakelussa on printf:n lisäksi hyvin monenlaisia merkkijonon tulostukseen käytettäviä funktioita. Joten, jos välttämättä sellaista kaipaa, se vaatii tutustumista kääntimen kirjaston dokumenttiin, tai nettisurffailua, tai kääntymistä kavereitten puoleen.

Jos ’lainaat’ koodia jostain PC-ympäristöön tarkoitetusta C-kielen oppikirjasta, niin sulautetuissa järjestelmissä muutkin funktiot kuin printf esiintyvät yleensä hyvin rajoitetuin ominaisuuksin (koska käytössä on hyvin vähän muistia ja prosessori on pienitehoinen). Sulautetun järjestelmän C-käännin (muukin kuin avr-gcc) ei välttämättä ’ymmärrä’ kaikkea ANSI C:n mukaista koodia.

Ennen LCD-printf-tulostukseen tutustumista perehdytään merkkijonoihin. Sen jälkeen tulostus lcd-näyttöön tai myöhemmin RS-232-sarjaporttiin, ei tuota ongelmia.

Anyway, we do not recommend the printf() family for small devices (at least not the version in the library -- feel free to use the source code, and cut down your own customized version). Instead, there are simpler conversion functions available as well.

Page 10: 7.4. Oheisrautaa. LCD

10

Merkkijono Lisää merkkijonoista (mm. kirjastofunktiot) sarjaportin (USART) yhteydessä. C-kielessä merkkijono ei ole oma tietotyyppi, vaan on käytettävä taulukkoa. Se on yhden tai useamman merkin muodostama jono, joka talletetaan peräkkäisiin muistipaikkoihin. Peräkkäiset muistipaikat (kuten edellä opit) muodostavat vektorin, eli yksiuloitteisen taulukon. Merkkijono on taulukon erikoistapaus ja sen alkiotyyppi on 8-bittinen char. Jonon päättyminen ilmaistaan nollamerkillä, joka merkitään '\0', eli NULL, eli null, character. Se ei ole numero nolla, vaan tulostumaton merkki. Sen ASCII-arvo on 0. Desimaalinollan ASCII-merkkihän on 0x30. Ilman lopettavaa nollamerkkiä, kirjaimia sisältävä taulukko on merkkitaulukko, ei merkkijono. Siitä C-käännin tietää mihin merkkijono loppuu. Käännin laittaa NULL-merkin automaattisesti merkkijonon loppuun. Taulukoita käytetään nimellä, samoin siis myös merkkijonoja. Merkkijonon nimi on osoite merkkijonon ensimmäiseen merkkiin. Jos merkkijonoa käytetään funktioiden kanssa, esim. printf-funktio, merkkijono kokonaisuudessaan ei välity funktion kutsussa, vaan kutsussa välittyy ainoastaan merkkijonon osoite. Siis kutsuva funktio välittää kutsuttavalle funktiolle paikan muistissa, johon voi kirjoittaa, tai josta voidaan lukea.

Vektori on samantyyppisten muuttujien kokoelma jolla on yhteinen nimi. Merkkitaulukko on char-tyyppisten alkioiden muodostama taulukko. Merkkijono on char-tyyppisten alkioiden muodostama taulukko, joka päättyy ’\0’-merkkiin.

Merkkijonon esittely char-tyyppinen muuttuja voi tallentaa vain yksittäisen merkin. Koska merkkijonolle ei ole erityistä tietotyyppiä, muodostetaan merkeistä taulukko. char jono[6] = {'A', 't', 'm', 'e', ’l’, '\0'}; tai char jono[6 ] = "Atmel"; // parempi tapa char sana[] = {'j', 'o', 'n', 'o', '\0'}; char motor[] = "Moottori ON”;

Lainausmerkit eivät sisälly jonoon, niitä käytetään jonon rajojen merkitsemiseen. Heittomerkkejä käytetään yksittäisten merkkien erottamiseen. C-kielen standardi-kirjastossa on runsaasti valmiita funktioita merkkien ja merkkijonojen käsittelyyn. Jos ne eivät riitä, niin osaava tekee tarpeisiinsa sopivan itse.

Page 11: 7.4. Oheisrautaa. LCD

11

”jono tekstiä” ”” // nollajono ” ” // tyhjää ”a-b+c;” // ei tehdä mitään ”/* ei kommenttia */” ”jono \” juu” ”abc” // merkkitaulukko, koko on 4, koska lopussa on \0 ’a’ ja ”a” ovat eri asioita, jälkimmäisessä a ja \0

Merkkijonon esittelyssä SRAM-muistista varattu alue ei tyhjene, vaan sinne jää aikaisempi sisältö.

Ongelma on vain siinä miten printf()-funktio saadaan käyttöön avr-gcc:n kanssa. Sitä varten on opittava C-kielen tiedostojen käsittelyfunktio fopen.

fdevopen ja sen käyttö lcd-näytön kanssa

Yleistä

Kaikki ohjelmiemme käsittelemä data katoaa bittien taivaaseen heti kun ohjelman ajo loppuu. Näin käy ellemme talleta sitä ennen johonkin pysyvään muistiin kuten esim. kiintolevylle. Tallentamista varten meidän on luotava tiedosto, file. Lukemista ja kirjoittamista varten tiedosto on ensin avattava (ja käytön jälkeen suljettava). Se tehdään standardikirjaston (stdio.h) funktiolla fopen() ja tiedosto-osoittimella (file or stream-pointer), jonka ko. funktio palauttaa. Tiedoston käyttöönotto tapahtuu fopen-funktiolla, jonka muoto-formaatti on: FILE *fopen(char *name, char *mode);

Funktion fopen - ensimmäinen argumentti on osoitin

o (ulkoiseen, käsiteltävänä olevaan) tiedostoon - ja toinen argumentti, mode,

o mitä tiedostolle aiotaan tehdä (w – kirjoitus, r – luku, a – lisäys). - funktion nimi kuvastaa sen osoitetta.

o tätä osoitetta kutsutaan funktion osoittimeksi, file pointer. Tähän kaikkeen tarvitaan käyttäjärjestelmän apua. Mutta kun meillä ei ole käyttöjärjestelmää (vielä), eikä edes kiintolevyä, niin toimitaan seuraavasti: Fdevopen() on tarkoitettu tietovuon siirtämisen jollekin laitteelle. Se avaa datavirran laitteeseen (kirjoitus tai luku tai molemmat), joten se tarvitsee funktion yksittäisen merkin siirtämiseen. Sillä ei ole väliä siirretäänkö tekstiä tai binääridataa (inside avr-libc).

Page 12: 7.4. Oheisrautaa. LCD

12

Funktiolla on kaksi argumenttia - eka: mihin merkki kirjoitetaan - toinen: on osoitin tiedostoon avr-libc-kirjastossa tuo fopen() on korvattu fdevopen()-funktiolla. kts. avr-libc user manual. ( FILE_ fdevopen (int(_)(char, FILE _) put, int(_)(FILE _) get) ) • FILE _ fdevopen (int(_put)(char, FILE _), int(_get)(FILE _)) stdio.h FILE_ fdevopen (int(_)(char, FILE _) put, int(_)(FILE _) get) Kun ohjataan data esim. LCD-näytölle korvataan ed. funktio tällä: // Otetaan prinft()-funktio käyttöön siten, että se n tulostus // ohjataan LCD_kirjoitaMerkki()-funktioon, eli LCD -näytölle. fdevopen((void *) LCD_WriteChar, NULL);

Näin saadaan prinf()-funktio käyttöön. Funktio on ”iso” ja sillä on laaja tulostuksen muotoilua ohjaava argumenttilista. printf("Hello: %s %d=%c", data, luku, luku); The 3rd argument of fdevopen has been removed since a few avr-

libc versions, it was unused anyway. Funktion nimi kuvastaa osoitetta, jossa funktio sijaitsee. Tähän osoitteeseen osoittaa funktion osoitin-pointer. Fdevopen() mahdollistaa funktion osoittimen käytön parametrina kun kutsutaan itse funktiota ja lähetetään argumentteja sille. Fdevopen()-funktio ohjaa laitteeseen ( UART, LCD, tms.) kirjoittavan tai sieltä lukevan funktion tietovirtaa. Ei ole eroa onko data tekstivirtaa tai binäärivirtaa. Sarjaportin käsittelyyn printf() löytyy valmiina, mutta LCD-näytölle on kirjoitettava oma. Jos osaat kirjoittaa funktion, joka kirjoittaa merkin suoraan UARTin datarekisteriin (tai lcd-näyttöön), puolet hommasta on hoidossa. Sitten kirjoitetaan funktio, joka ottaa argumenttina merkin (ja palauttaa integerin = always nolla). Käytä tuon funktion nimeä argumenttina kirjoittavaan funktioon, nyt kaikki merkit ohjataan suoraan läpi funktion. Initialisoi UART ja/tai lcd ensiksi. Käytännön esimerkki /************************************************** ******** Project : printf_to_lcd.c Hardware: PV-M32, (4 MHz) + PV-EMO eli LCD on PORTA Software : WinAVR-20071221 Date : 10.1.2008 Author : Tomi Tilli & pva Comments: tulostaa tekstiä lcd-näyttöön merkki kerr allaan Opiskele fdevopen-dokumentti. Kopioi lcd_tat.c ja lcd_tat.h tiedostot projektin k ansioon.

Page 13: 7.4. Oheisrautaa. LCD

13

Klikkaa hiiren oikealla (vasemmalla olevan hakemist opuun) Source Files, Add Existing Source Files, lisää lcd_ tat.c - tällä kerrotaan C-kääntimelle, että sen pitää kääntää myös lcd_tat.c *************************************************** *******/ #include <avr/io.h> #include <util/delay.h> #include "lcd_tat.h" // *** Primitive wait() *** void wait(uint16_t time) { volatile uint16_t i; for(i=0;i<2000;i++) _delay_loop_2(time); } int main(void) { uint16_t pieni = 123; uint32_t iso = 123456789; // Otetaan LCD käyttöön merkinkorjauksella ja ilman kursoria LCD_init(1, 0, 0); // Otetaan prinft()-funktio käyttöön siten, että tu lostus // ohjataan LCD_WriteChar()-funktioon = LCD-näytöll e. fdevopen((void *) LCD_WriteChar, 0); printf("Hello AVR-World!"); while (1) { // Kirjoitetaan 16-bittinen luku 2.riville LCD_SetCursorXY(0, 1); printf("min: %d ", pieni); wait(500); // Standard C89/C99 feature: // long integers require a `l' (letter `ell') // specifier in integer formats. LCD_SetCursorXY(0, 1); // Kirjoitetaan 32-bittinen luku 2.riville printf("max: %li",iso); // <--- did the trick!! wait(500); } }

Analysointi Miten saadaan printf-funktio käyttöön ja tulostettava data ohjattua lcd-näyttöön? // Otetaan prinft()-funktio käyttöön siten, että tu lostus // ohjataan LCD_WriteChar()-funktioon = LCD-näytöll e. fdevopen((void *) LCD_WriteChar, NULL);

Sen suurin hyöty on erilaisten (char, int, hex, des...) numeroiden tulostuksessa. Toinen huomioitava asia on suurten kokonaislukujen tulostus. // Standard C89/C99 feature: // long integers require a `l' (letter `ell') // specifier in integer formats.

Page 14: 7.4. Oheisrautaa. LCD

14

LCD_SetCursorXY(0, 1); // Kirjoitetaan 32-bittinen luku 2.riville printf("max: %li",iso); // <--- did the trick!!

LCD-näyttö ja liukulukutulostus Vaikka liukulukujen, floating point, käyttö pienissä mikro-ohjaimissa ei ole suositeltavaa (liian pienet resurssit), annetaan seuraavassa mallikoodi sen käytöstä. Ihan vaan oppimisen iloksi. Mallikoodi /************************************************** ******** Project : adc_floatingpoint.c Hardware: PV-M32 (4 MHz) + PV-EMO Software: WinAVR-20071221 Date : 10.01.2008 Author : pva Comments: mittaa ADC-3-trimmerin liu'un jännitteen ja tulostaa sen A-porttiin kytkettyyn LCD-näyttöön. Laita 10 kohmin trim_potikka GND ja +5 V väliin, liulle noin 100 kohmia ja se ADC3-inputtiin, eli PA.3 Säädä potikkaa, seuraa lcd-näyttöä. Kopioi lcd_tat.c ja lcd_tat.h tiedostot projektin k ansioon. Klikkaa hiiren oikealla (vasemmalla olevan hakemist opuun) Source Files, Add Existing Source Files, lisää lcd_ tat.c - tällä kerrotaan C-kääntimelle, että sen pitää kääntää myös lcd_tat.c *************************************************** *******/ #include <avr/io.h> #include <stdio.h> #include <avr/interrupt.h> #include <util/delay.h> #include "lcd_tat.h" #define AIKA 600 #define WAIT(time) for(uint16_t i=0;i<2000;i++)_del ay_loop_2(time); #define TAUSTAVALO 1<<0 uint8_t lippu = 0; uint16_t adc_data = 0; // hypätään tänne, kun muunnos valmis ISR(ADC_vect) { lippu = 1; adc_data = ADCW; // luetaan muunnostulos muuttujaan (10 bittia >> 0-1023) }

Page 15: 7.4. Oheisrautaa. LCD

15

void Tulosta(uint16_t jannite) { cli(); // kielletään keskeytykset LCD_Clear(); double luku =0; // float luku = 0; luku = jannite*5000/1023; // skaalataan muunnostulos 'volteiksi' printf("%.2f", luku); LCD_WriteString(" Volttia" ); LCD_SetCursorXY(0, 1); LCD_WriteString("V-mittari"); lippu = 0; WAIT(1000); sei(); // globaali keskeytys sallittu } void ADC_init(void) { ADMUX |= 1<<REFS0; // (1<<REFS0) AVCC=5V with external capacitor at AREF pin ADMUX |= (1<<MUX1) | (1<<MUX0); // valitaan ADC.3 -input ADCSRA |= (1<<ADPS2) | (1<<ADPS0); // jakoluku 32 // 4000000/32 = 125 kHz // oltava välillä 50 kHz ... 200 kHz ADCSRA |= (1<<ADIE) | (1<< ADEN); // adc ON ja ke skeytys ON } int main(void) { DDRC |= TAUSTAVALO; PORTC |= TAUSTAVALO; // Otetaan LCD käyttöön merkinkorjauksella ja ilman kursoria LCD_init(1, 0, 0); // Otetaan prinft()-funktio käyttöön siten, että se n tulostus // ohjataan LCD_kirjoitaMerkki()-funktioon, eli LCD -näytölle. fdevopen((void *) LCD_WriteChar, NULL); ADC_init(); DDRA &= ~(1<<3); // ADC.3 input sei(); // globaali keskeytys sallittu while(1) // jatkuva mittaus { DDRA &= ~(1<<3); // ADC.3 input // oltava tässä, koska "lcd sekoittaa asetukse t" ADCSRA |= (1<<ADSC); // (1<< ADEN) ADC ON // (1<<ADSC) Start conversion WAIT(AIKA); if(lippu==1) Tulosta(adc_data); } } /* Oletuksena avr-libc-kirjaston printf-funktio ei osa a tulostaa liukulukuja, desimaalilukuja. Kun et käytä liukuluja, säästät muistia melkoisesti .

Page 16: 7.4. Oheisrautaa. LCD

16

Jos kuitenkin haluat käyttää liukulukuja, meidän on maipuloitava linkkeriä. 1) Avaa AVRStudion "Project -> Configuration Option s" 2) Avaa "Libraries"-välilehti 3) Available Link Objects: - Add Library: math library (libm.a) - ja the floating-point printf library (libprintf_f lt.a) libprintf_flt.a täytyy olla ylin ja libm.a täytyy o lla alin 4) Avaa "Custom Options" välilehti. 5) Maalaa-Highlight [Linker Options]. 6) Kirjoita (copypastaa tästä) "Add" laatikkoon: -Wl,-u,vfprintf -lprintf_flt -lm 7) Klikkaa "Add" ja OK */