6.7. rauta USART-Ohjelmointia

22
1 6.7. AVR_rauta. USART ohjelmointi 7.1.2008. pva ”Nuorempana muistin mitä tahansa – olipa se tapahtunut tai ei.” - Mark Twain Sisältö Yleistä RS-232 USART ja sen rekisterit Vastaanoton pollaus, mallikoodi. Pollattu USART Keskeytysohjattu USART Ensimmäinen sarjaliikenneohjelma Terminaaliohjelma Merkkijonon tulostaminen printf-funktio fdevopen (USART_Transmit, NULL); Käytännön esimerkki ToinenASCII-harjoitus Printf()-funktion käyttämät ei-tulostuvat merkit The default printf library does not handle floats. Ohjelmallinen UART Yleistä Jos tietoa siirretään rinnakkaismuodossa tavu kerrallaan, tarvitaan 8 johdinta (ja yhdeksäs eli referenssimaa). Jos siirretään bittejä sarjamuodossa paikasta toiseen, selvitään kahdella johtimella. Tiedonsiirtonopeus luonnollisesti kärsii. Siirtotapahtuma voi olla: - Synkroninen o jolloin käytössä on yhteinen kello, CLK - Asynkroninen o jolloin yhteistä kelloa ei ole Full-duplex - lähtö- ja tulopuskurit (ja kellolinjat) erikseen - samanaikainen lähetys ja vastaanotto Half-duplex - voi lähettää ja vastaanottaa - tosin ei samaan aikaan

Transcript of 6.7. rauta USART-Ohjelmointia

Page 1: 6.7. rauta USART-Ohjelmointia

1

6.7. AVR_rauta. USART ohjelmointi 7.1.2008. pva ”Nuorempana muistin mitä tahansa – olipa se tapahtunut tai ei.” - Mark Twain Sisältö Yleistä RS-232 USART ja sen rekisterit Vastaanoton pollaus, mallikoodi. Pollattu USART Keskeytysohjattu USART Ensimmäinen sarjaliikenneohjelma Terminaaliohjelma Merkkijonon tulostaminen printf-funktio fdevopen (USART_Transmit, NULL); Käytännön esimerkki ToinenASCII-harjoitus Printf()-funktion käyttämät ei-tulostuvat merkit The default printf library does not handle floats. Ohjelmallinen UART Yleistä Jos tietoa siirretään rinnakkaismuodossa tavu kerrallaan, tarvitaan 8 johdinta (ja yhdeksäs eli referenssimaa). Jos siirretään bittejä sarjamuodossa paikasta toiseen, selvitään kahdella johtimella. Tiedonsiirtonopeus luonnollisesti kärsii. Siirtotapahtuma voi olla:

- Synkroninen o jolloin käytössä on yhteinen kello, CLK

- Asynkroninen o jolloin yhteistä kelloa ei ole

Full-duplex

- lähtö- ja tulopuskurit (ja kellolinjat) erikseen - samanaikainen lähetys ja vastaanotto

Half-duplex

- voi lähettää ja vastaanottaa - tosin ei samaan aikaan

Page 2: 6.7. rauta USART-Ohjelmointia

2

RS-232 Tietokoneympäristössä jo 1960-luvulta lähtien on ollut käytössä yleisimpänä sarjaliikennesysteeminä RS-232-normi (Recommended Standard). Se on edelleen varsin käyttökelpoinen menetelmä datan siirtoon mikro-ohjaimen ja oheislaitteiden välillä. Siinä on käytössä kaksi datajohdinta, tuleva ja menevä ja referenssinä maajohto. Liittimenä käytetään tavallisimmin 9-napaista D-liitintä. Laitekättelyt lisäävät johtimien määrää. Nopeus Sarjamuotoinen tiedon siirto tapahtuu tietyllä nopeudella, jotta vastaanottaja tietää odottaa ja vastaanottaa samalla nopeudella, millä lähettäjä lähettää. Muuten tulee ongelmia. Bittien siirtonopeus on normioitu ja määritetään UBRR-rekisterissä, Baud Rate Register. Nopeuden määräämät pulssit generoidaan systeemin kellosta. Nopeus lasketaan kaavasta: UBRR = (System Clock/(16 * baud rate)) –1 Älä käytä siirtonopeutta joka poikkeaa normista enemmän kuin ±0.5%. bps, bits per second, bittiä sekunnissa kbps, kilo bits per second, kilobittiä sekunnissa

Tasot RS-232-liitäntä käyttää +12 V ja –12 V jännitetasoja, (threshold levels +3 V ... –3 V, max +/-15 V). AVR toimii +5 V jännitteellä, joten väliin tarvitaan tasomuunnin. Sen hoitaa kortilla oleva MAX232-piiri. Siirrettävä merkki

Yksittäiset siirrettävät ASCII-merkit varustetaan start- ja stop-biteillä, jolloin synkronointi, tahdistus, on merkkikohtaista. Merkin lähetys alkaa aina start-bitillä. Databittien määrä voi olla 5-8, tavallisimmin 8 ja stop-bittien 1, 2 tai 1,5. Yleisin sarjasiirtomuoto on 8N1. Se tarkoittaa, että databittejä on 8 kpl, pariteettitarkistusta ei ole käytössä ja stop-bittejä on vain yksi. Lähetys- ja vastaanottopäiden erilaiset määritykset aiheuttavat enimmät ongelmat. Pariteettitarkistus

Parillinen pariteetti, Even Parity Pariteettibitti saa arvon 0, jos tavussa on parillinen määrä ykkösbittejä, saa arvon 1, jos bittejä on pariton määrä. Pariton pariteetti, Odd Parity Päinvastoin.

Page 3: 6.7. rauta USART-Ohjelmointia

3

USART AVR käsittelee dataa rinnakkaismuodossa. Sarjasiirtoa varten pitää tehdä rinnakkais-sarja-muunnos ja vastaanotossa päinvastoin. Jos emme käytä synkronista siirtoa,

- vastaanottajalle pitää kertoa milloin tuleva merkki alkaa, - montako databittiä tulee, - milloin merkki loppuu, - ja tietysti tiedonsiirtonopeus,

o jotta vastaanottopäässä osataan tulkita tulevia bittejä oikein. - jos halutaan käyttää virheentarkistussysteemiä, pariteettitarkistusta

tähän tarvitaan ’älykäs’ piiri hoitamaan kaiken ylläolevan. Tuo älypiiri on UART, Universal Asyncronous Receiver Transmitter, ”yleiskäyttöinen tahdistamaton vastaanotin-lähetin”, sarjaliikenteen hoitava erikoispiiri. Sen parannettu versio, USART, Universal Synchronous and Asynchronous Receiver Transmitter. Jälkimmäisessä on samat toiminnot, mutta muutama lisäominaisuus (kuten mm. tahdistettu toiminta). Ensin katsotaan mitä rekistereitä USART sisältää ja mikä on minkin rekisterin ja rekisterin bittien merkitys toiminnan kannalta. Elleivät ne ole selvillä, ohjelmoinnista ei tule mitään. Vanhaan hyvään aikaan UART koostui erillisistä piireistä, nykyään se on integroitu mikro-ohjaimen kanssa samalle chipille.

USART periaatekuva. Seuraavissa taulukoissa on selvitetty kunkin lohkon rekisterit ja niiden ohjausbitit. Baud Rate, eli siirtonopeus, lasketaan järjestelmän kellosta.

Page 4: 6.7. rauta USART-Ohjelmointia

4

AVR ATmega32, USART, Universal Synchronous and Asynchronous serial Receiver Transmitter-rekisterit

UDR, USART I/O Data Register Bitti 7 6 5 4 3 2 1 0 Rekisteri RXB 7 – 0, Read, vain luku Rekisteri TXB 7 – 0, Write, vain kirjoitus

- fyysisesti kaksi rekisteriä, joilla on sama osoite UCSRA, USART Control and Status Register A Bitti 7 6 5 4 3 2 1 0 Nimi RXC TXC UDRE FE DOR PE U2X MPCM

OR over run asetetaan tulee uusi merkki eikä ed ole luettu FE framing error, asetettu jos tulevan stop on nolla

UCSRB, USART Control and Status Register B Bitti 7 6 5 4 3 2 1 0 Nimi RXCIE TXCIE UDRIE RXEN TXEN UCSZ2 RXB8 TXB8

UCSRC, USART Control and Status Register C Bitti 7 6 5 4 3 2 1 0 Nimi URSEL UMSEL UPM1 UPM0 USBS UCSZ1 UCSZ0 UCPOL

Bitti Nimi Merkitys Toiminto 7 RCX Receive Complete, merkki

vastaanotettu 0: kun buffer on tyhjä, 1: kun dataa on bufferissa

6 TXC Transmit Complete, merkki lähetetty

1: kun merkki lähetetty, 0: kun merkki bufferissa

5 UDRE Data Register Empty 1: lähetysbufferi on tyhjä ja valmis ottamaan uuden merkin vastaan

4 FE Framer Error 1: virhe merkkiä vastaanotettaessa 3 DOR Data OverRun 1: kun vastaanottobufferi on täysi (2 merkkiä) ,

tai tuleva merkki odottaa, tai uusi start-bit on havaittu

2 PE Parity Error 1: kun vastaanotossa pariteettivirhe 1 U2X Double the USART Transmission

Speed 0: kun sync toiminto valittu, 1 tuplaa async nopeuden

0 MPCM Multi-processor Communication Mode

1: sallii moni-cpu-toiminnon, lisää s.155

Bitti Nimi Merkitys Toiminto 7 RXCIE RX Complete Interrupt Enable 0: disable, 1: enable eli keskeytysvastaanotto

mahdollinen 6 TXCIE TX Complete Interrupt Enable 0: disable, 1: enable, keskeytyslähetys

mahdollinen 5 UDRIE Data Register Empty Interrupt

Enable 0: disable, 1: enable,

4 RXEN Receiver Enable 0: disable, 1: enable, vastaanotto mahdollinen 3 TXEN Transmitter Enable 0: disable, 1: enable, lähetys mahdollinen 2 UCSZ2 Character Size, bittien määrä

merkissä kts. taulukko edempänä

1 RXB8 Receiver Data bit 8 Databittejä 9 kpl, vastaanotossa 0 TXB8 Transmitter Data bit 8 Databittejä 9 kpl, lähetyksessä

Page 5: 6.7. rauta USART-Ohjelmointia

5

UCSZ2 UCSZ1 UCSZ0 Character Size

0 0 0 5-bit 0 0 1 6-bit 0 1 0 7-bit 0 1 1 8-bit 1 0 0 reserved 1 0 1 Reserved 1 1 0 Reserved 1 1 1 9-bit

UCPOL Transmitted Data changed, output of TxD pin

Received Data changed, input of RxD pin

0 Rising XCK Edge, nouseva reuna Falling XCK Edge, laskeva reuna 1 Falling XCK Edge, laskeva reuna Rising XCK Edge, nouseva reuna UBRRL and UBRRH, Baud Rate Registers, sarjasiirron nopeus Bitti 15/7 14/6 13/5 12/4 11/3 10/2 9/1 8/0 Rekisteri H URSEL - - - UBRR 11 - 8 Rekisteri L UBRR 7 – 0

// sarja_vastaanotto_keskeytys_funktio ISR(USART_RXC_vect) { uint8_t merkki; merkki = UDR; // lue merkki Datarekisteristä // lisää koodia }

Sarjaporttiin ei voida lähettää merkkejä ”miten sattuu”, sillä merkin lähettäminen lähetysrekisteristä ulos vie oman aikansa. Uusi merkki voidaan kirjoittaa lähetysrekisteriin vasta, kun edellisen lähetys on valmis. Siksi sarjaliikenne on huomattavasti hitaampaa kuin rinnakkaisliikenne.

Bitti Nimi Merkitys Toiminto 7 URSEL Register

Select 1: kun kirjoitetaan to UCSRC

6 UMSEL Mode Select 0: async mode, 1: sync mode 5 UPM1 4 UPM0

Parity Mode 00: disabled, 01: reserved 10: even parity, 11: odd parity (pariton pariteetti)

3 USBS Stop Bit Select

0: 1-stop bit, 1: 2-stop bit

2 UCSZ1 Character Size Kts. Taulukko edempänä, merkin bittien määrä 1 UCSZ0 Character Size Kts. Taulukko edempänä, merkin bittien määrä 0 UCPOL Clock Polarity Käytössä vain Sync modessa; 0: kun async mode

Bitti Nimi Merkitys Toiminto 15 URSEL valitaan UBRRH tai UCSRC 0: kun kirjoitetaan/luetaan -

>UBRRH 11-0 UBRR Baud Rate Register, siirtonopeuden valinta

Page 6: 6.7. rauta USART-Ohjelmointia

6

USR-tilarekisterillä on suuri merkitys, kun se kertoo järjestelmälle ’missä mennään’ asettamalla lippubitin, kun merkki on tullut, tai toisen, kun merkki on lähetetty. UDRE-bitti kertoo lähetyksessä, että tavu on siirretty linjalle ja lähetysrekisteri odottaa uutta merkkiä. Tuon bitin tilan selvittäminen, siis milloin lähetysrekisteriin voidaan kirjoittaa, voidaan hoitaa kahdella tavalla:

- keskeytys- tai - pollausperiaatteella.

Lähetys kannattaa hoitaa pollaten ”silloin kun on tarvetta”, mutta vastaanotto keskeytysperiaatteella. Kukin tavu pitää lukea vastaanottorekisteristä ennen kuin voidaan vastaanottaa sinne seuraava merkki. Siksi on viisasta käyttää sarjaliikenne-keskeytystä, jottei prosessorin aika mene sarjaportin tilan kyselyyn, pollaamiseen. RXC- ja TXC-bitti asettuu ykköseksi aina, kun tavu on vastaanotettu tai lähetetty. Niitä käytetään keskeytyslippuina, joilla kerrotaan prosessorille, että nyt tarvitaan uutta lähetettävää tai vastaanotettavaa.

Sarjaliikenteen hoitamiseen meillä on kaksi mahdollisuutta: - pollattu USART - keskeytysohjattu USART

Pollattu USART Tutkitaan UDRE-bittiä, eli onko USART lopettanut edellisen merkin lähettämisen. Vastaanotossa tutkitaan RXC-bittiä, joka kertoo onko merkki (tavu) tullut.

Vastaanoton pollaus, mallikoodi. /************************************************** ******** Project : usart_pollaus.c Hardware: PV-M32+PV-EMO + RS-kaapeli + PV-LEDIT B-p ortissa Software: WinAVR-20070525 Date : 06.11.2007 Author : pva Comments: Liitä RS-kaapeli (käännetty) PC:n ja PV-EMOn väliin . Käynnistä terminaaliohjelma. Lähetä A, B, C, jne, yksi merkki kerrallaan ja tarkkaile LED-pulikkaa *************************************************** *******/ #include <avr/io.h> #include <stdio.h> #include <util/delay.h> #define WAIT(time) for(uint16_t i=0;i<2000;i++)_del ay_loop_2(time); #define XTAL 4000000 #define BAUD 9600 // funktioiden esittelyt eli prototyypit void ReceiveByte(void); void USART_Init(void); int main(void) { DDRB = 0xFF; USART_Init();

Page 7: 6.7. rauta USART-Ohjelmointia

7

while(1) { PORTB = 1<<0; ReceiveByte(); // onko tavu tullut? WAIT(50); PORTB &= ~(1<<0); ReceiveByte(); WAIT(50); } } void ReceiveByte(void) { if(bit_is_set(UCSRA, RXC)) // jos merkki tullut { PORTB = UDR; WAIT(1000); } } // *** sarjaportin asetukset, 8 data, 1 stop bit, 8 N1 ***** void USART_Init(void) { UBRRH = 0x00; // write high register first UBRRL = ((XTAL/16)/BAUD)-1; // baud rate eli nope us UCSRB |= (1<<RXEN); // vain vastaanotto sallittu UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); }

Analysointi

Ennen koodin analysointia on syytä tutkia sarjaliikenteen rautadokumenttia, jotta tiedetään miten bittiliikenne toimii, mitä asioita on otettava huomioon ja miten ne määritetään. Kun raudan toiminta on selvillä, koodin ymmärtäminen on helpompaa. Ensin koodissa määritetään kaksi vakiota, kidetaajuus, josta lasketaan bittien siirtonopeus ja toinen, jolla määritetään bittien siirtonopeus. #define XTAL 4000000 // MCU:n kellotaajuus

#define BAUD 9600 // sarjaportin nopeus 9600 bps

Ikuisessa silmukassa tehdään muun työn ohessa USARTin vastaanottorekisterin pollausta. if(bit_is_set(UCSRA, RXC)) // jos merkki tullut

UCSRA-rekisterin RXC-bitti asettuu ykköseksi, kun merkki on tullut. Jos merkkiä ei heti lueta talteen, seuraava tuleva merkki kirjoitetaan edellisen päälle.

Page 8: 6.7. rauta USART-Ohjelmointia

8

Keskeytysohjattu USART Usein on järkevää että USARTin rekisterit konfiguroidaan generoimaan keskeytyk-sen, kun se on lopettanut merkin (tavun) lähettämisen tai vastaanoton. Koodi voi muun ajan tehdä ”jotain tärkeää”, se siirtyy sarjaliikenteen käsittelyyn vasta merkin tulessa. Ensimmäisessä esimerkissä käytämme keskeytysohjauttua menetelmää, koska se on tehokkain tapa hoitaa liikenne. Se antaa meille mahdollisuuden tehdä ”järkeviä”, eikä aika tuhraannu USARTin tilan pollaamiseen. Data kulkee ensimmäisessä esimerkissä molempiin suuntiin ja mutta vain vastaanotto on keskeytysohjattu. Tavun lähetys tapahtuu silloin kun “koodi käskee”. Sarjaliikenneohjelma, jossa keskeytysvastaanotto /************************************************** ******** Project : USART_tx_rx.c, Hardware: PV-M32 + PV-EMO + RS-232-kaapeli (käännet ty) Software: WinAVR-20070525 + terminal-ohjelma (in PC ) Hyvä: Terminal v1.9b by Br@y++, http://bray.velenje.cx/av r/terminal Date : 03.08.2007 Author : pva Comments: tulostaa terminaaliohjelmaan kirjaimet AV R, rivin vaihto ja telanpalautus, lisäksi lukee painettaessa merkin näppäimistöltä ja tulosta a sen. Käyttää sarjaportin lukemiseen keskeytystä. *************************************************** *******/ #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #define XTAL 4000000 // MCU:n kellotaajuus #define BAUD 9600 // sarjaportin nopeus 9600 bps // prototypes void USART_Transmit(uint8_t data); void USART_Init(void); void wait(uint16_t time); int main(void) { uint8_t merkki = 'A'; uint8_t merki = 'V'; uint8_t mer = 'R'; USART_Init(); sei(); // global interrut ON while(1) { USART_Transmit(merkki); wait(200); USART_Transmit(merki); wait(200); USART_Transmit(mer);

Page 9: 6.7. rauta USART-Ohjelmointia

9

wait(200); USART_Transmit(0x0A); // uusi rivi, new line USART_Transmit(0x0D); // rivin alkuun, CR, ca rridge return wait(200); } } // USART eli sarjaportin asetukset, 8 data, 1 stop bit, 8N1 void USART_Init(void) { // Set baud rate, lasketaan bittien siirtonopeus UBRRH = 0x00; // write high register first UBRRL = ((XTAL/16)/BAUD)-1; UCSRB |= (1<<RXEN)|(1<<TXEN); // 0001 1000 // Bit 4 – RXEN: Receiver Enable, vastaanotto sal littu // Bit 3 – TXEN: Transmitter Enable, lähetys sall ittu UCSRB |= 1<<RXCIE; // rx interrupt enable, 1xx1 1 xxx // sarjavastaanottokeskeytys sallittu // UCSRC = 0x86; // 8 Data, 1 Stop, No Parity 1 xxx x11x UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // Bit 7 – URSEL: Register Select, // must be one when writing the UCSRC. // Bit 6 – UMSEL: USART Mode Select, Asynchronous mode = 0. // Bit 5:4 – UPM1:0: Parity Mode, 00 = no parity // Bit 3 – USBS: Stop Bit Select, 0 = 1 stop bit // Stop Bits to be inserted by the Transmitter. // Bit 2:1 – UCSZ1:0: Character Size, // combined with the UCSZ2 bit in UCSRB sets the number of data bits // in a frame the Receiver and Transmitter use. 0 11 = 8-bit // Bit 0 – UCPOL: Clock Polarity, used for Synchr onous mode only. } // sarja_vastaanotto_keskeytys_funktio ISR(USART_RXC_vect) { uint8_t merkki; merkki = UDR; // lue merkki Datarekiste ristä USART_Transmit(merkki); // lähetä merkki // USART_Transmit(0x0A); // uusi rivi, new line // USART_Transmit(0x0D); // rivin alkuun, CR, ca rridge return } // *** Lähetä merkki USART datarekisteriin ******** ********* void USART_Transmit(uint8_t data) { // Wait for empty transmit buffer, // odota kunnes lähtöpuskuri tyhjä while (!( UCSRA & (1<<UDRE))); // 0010 0000, odota kunnes UDRE == 1 // UDRE on 1, jos puskuri on tyhjä, eli ed. merkk i on lähetetty // Bit 5 – UDRE: USART Data Register Empty, if 1 /* UCSRA xx0x xxxx jos edellistä merkkiä lähetetä än 1<<UDRE 0010 0000 AND & ---------

0000 0000 eli false, ! invertoi, joten tosi-true el i odota */

Page 10: 6.7. rauta USART-Ohjelmointia

10

// Put data into buffer, sends the data UDR = data; // lähtevä merkki datarekisteriin }

Analysointi Itse koodi jakaantuu kolmeen pääfunktioon 1. USART initialisoidaan USART_Init(); funktiolla jolla initialisoidaan sarjaportin asetukset, eli määritetään lähetys- ja vastaanottoparametrit, mikä on siirtonopeus ja miten merkki kehystetään. // USART eli sarjaportin asetukset, 8 data, 1 stop bit, 8N1 void USART_Init(void)

Ensin lasketaan bittien siirtonopeus: // Set baud rate, lasketaan bittien siirtonopeus UBRRH = 0x00; // write high register first UBRRL = ((XTAL/16)/BAUD)-1;

USARTin lähetys ja vastaanotto mahdollistetaan asettamalla TXEN- ja RXEN-bitit. UCSRB |= (1<<RXEN)|(1<<TXEN); // 0001 1000 // Bit 4 – RXEN: Receiver Enable, vastaanotto sal littu // Bit 3 – TXEN: Transmitter Enable, lähetys sall ittu

Sarjaliikenteen vastaanotto hoidetaan keskeytysfunktion avulla asettamalla UCSRB-rekisterissä RXCIE-bitti. UCSRB |= 1<<RXCIE; // rx interrupt enable, 1xx1 1 xxx // sarjavastaanottokeskeytys sallittu

Lopuksi asetetaan vielä bitit joilla määritetään databittien määräksi 8, 1 stop-bitti ja ei oteta käyttöön pariteettitarkistusta // 8 Data, 1 Stop, No Parity 1xxx x11x UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);

Kun lähetys- ja vastaanotto on mahdollistettu, D-portin pinnit PD0 ja PD1 eivät enää ole D-portin käytössä, vaan niitä tulee USARTin lähetys- ja vastaanottopinnejä. Kunnes USART-määritys puretaan. 2. Merkin lähetysfunktio, USART_Transmit(uint8_t data);

Uusi merkki voidaan siirtää lähetyspuskuriin vasta kun edellinen merkki on kokonaisuudessan lähtenyt linjalle. Kun lähetyspuskuri on tyhjä, sen merkiksi USARTissa asetetaan UDRE-bitti. Sen tekee rauta automaattisesti. Siis ohjelma pannaan tarkkailemaan tuon bitin tilaa UCSRA-rekisterissä. while (!( UCSRA & (1<<UDRE)));

Toinen tapa on käyttää tuohon bitin tarkkailuun makroa loop_until_bit_is_set(UCSRA, UDRE); // odota, kunnes datarekisteri on tyhjä

Miksi näin?

Page 11: 6.7. rauta USART-Ohjelmointia

11

Ensin varmistutaan, että lähetyspuskuri on tyhjä. UDRE-bitti kertoo sen ja ohjelma odottaa while- tai makro-silmukassa loop_until_bit_is_set, kunnes bitti on asettunut eli edellinen merkki on varmasti lähetetty. Silloin on UART Data Register Empty, Data rekisteri tyhjä. Kun kirjoitetaan sarjaporttiin, ensimmäinen merkki menee USART:in bufferiin, puskurirekisteriin ja josta se sitten siirtyy automaattisesti siirtorekisteriin. Siirtorekisteri aloittaa merkin siirtämisen bitti bitiltä ulos sarjajohdolle. Tämä on hyvin hidas prosessi, jos sitä vertaa CPU:n toimintaan. Kun ohjelma (yleensä, ei tässä esimerkissä) kirjoittaa uuden merkin välittömästi bufferiin, se ei mitenkään tarkista, ’onko siirtorekisterissä tilaa’. Koska kaikki tämä tapahtuu äärettömän nopeasti, vanha merkki ei ole vielä kokonaan siirtynyt linjalle, joten uusi kirjoitetaan edellisen ’päälle’. Siksi pitää laittaa jokin tarkistussysteemi, joka tutkii, milloin voidaan turvallisesti kirjoittaa uusi merkki. Sitten voidaan siirtää seuraava merkki lähetettäväksi. // Put data into buffer, sends the data UDR = data; // lähtevä merkki datarekisteriin

3. Merkin vastaanottofunktio, ISR(USART_RXC_vect){}

Tässä käytetään keskeytyskirjaston funktiota // sarja_vastaanotto_keskeytys_funktio ISR(USART_RXC_vect)

Kun merkki on saapunut vastaanottoreksiteriin, siitä aiheutuu hyppy keskeytys-ohjelmaan (jos se on mahdollistettu) ja sitten siirretään data-rekisteristä merkki merkki-muuttujaan ja edelleen ohjelman käyttöön. merkki = UDR; // lue merkki Datarekisteristä

Ohjelman toiminta Merkit lähetetään main-funktion while-silmukassa kutsumalla lähetysfunktioata ja antamalla argumenttina lähetettävä merkki. while(1) { USART_Transmit(merkki); wait(200); USART_Transmit(merki); wait(200); USART_Transmit(mer); wait(200); USART_Transmit(0x0A); // uusi rivi, new line USART_Transmit(0x0D); // rivin alkuun, CR, ca rridge return wait(200); }

Kaikki muu selviää tutkimalla koodin kommentteja. Sarjaliikennettä hoitamaan ja indikoimaan on kehitetty lukuisia terminaaliohjelmia.

Page 12: 6.7. rauta USART-Ohjelmointia

12

Terminaaliohjelma Käytämme PC:ssä terminaaliohjelmaa, jolla sarjaliikenne saadaan ”näkyviin”. Windowsissa on Hyperterminal, mutta opiskelussa ja ohjelmien testauksessa se on huono. Paljon parempi, havainnollisempi, on esim.: Terminal v1.9b by Br@y++,

Joka löytyy osoitteesta: http://bray.velenje.cx/avr/terminal

Liitä sarjakaapeli (käännetty, 2-3, 3-2, 5-5) PV-EMOn sarjaporttiin ja toinen pää PC:n sarjaporttiin. Käynnistä terminaaliohjelma.

tämä on hyvä Ohjelman konfigurointiin tässä yhteydessä riittää, kun ohjelman

- Baud Rate, bittien siirtonopeus, - Data bits, merkin databittien määrä, - Parity - pariteetti, - Stop bits, - Handshaking – kättely, none,

asetetaan olemaan samat kuin on asetukset AVR:n USARTin rekistereissä ja siten vielä lopuksi paina Connect. Jos kaikki ok, kuvan mukaisesti AVR merkit lähtevät mikro-ohjaimesta ja tulostuvat PC:n terminaaliohjelmassa. Ellei, jokin on mennyt pieleen ja syytä tarkistaa kaikki alusta alkaen kohta kohdalta. Terminal ohjelma toimii, mutta siinä on pieni ongelma: tabuloinnit, \n, \b, printf(”Viesti \n”); eivät toimi, eivät aiheuta mitään.

Page 13: 6.7. rauta USART-Ohjelmointia

13

Ongelma on siinä, että MS OS = Windows, odottaa 2 merkkiä newlinen kanssa, siis CF + LF. C-kielen newline merkki \n on vain yksi merkki. Se voi olla CR tai LF, riippuu alustasta. Johdonmukaisesti seuraava funktio on Merkkijonon siirtäminen sarjajohdolle /************************************************** ******* Project : usart_merkkitaulukko.c Hardware: PV-M32, 4 MHz CLK, +PV-EMO + käännetty RS-232-kaapeli(2-3, 3-2, 5-5) Software: WinAVR-20070525, Terminal v1.9b http://bray.velenje.cx/avr/terminal/ Date : 06.11.2007 Author : pva Comments: lähettää merkkijonon sarjaporttiin ja tul ostaa sen monitorin terminaaliohjelmaan. *************************************************** ********/ #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #define WAIT(time) for(uint16_t i=0;i<2000;i++)_del ay_loop_2(time); #define XTAL 4000000 // MCU:n kellotaajuus #define BAUD 9600 // sarjaportin nopeus 9600 bps // funktioiden esittely, prototyypit void USART_Transmit(uint8_t data); void USART_Init(void); // *** Lähetä merkki USART datarekisteriin ******** ******** void USART_Transmit(uint8_t data) { while (!( UCSRA & (1<<UDRE))); // odota kunnes UD RE == 1 UDR = data; // lähtevä merkki datarekisteriin } // *** USART asetukset, 8 data, 1 stop bit, 8N1 *** ******** void USART_Init(void) { UBRRH = 0x00; // write high register first UBRRL = ((XTAL/16)/BAUD)-1; UCSRB |= (1<<TXEN); // UCSRC = 0x86; // 8 Data, 1 Stop, No Parity 1xx x x11x UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); } // *** Pääohjelma ********************************* ******** int main(void) { uint8_t i; uint8_t taulu[9] = {'T', 'i', 'e', 't', 'o','k', 'o', 'n', 'e'}; // merkkitaulukko, merkit kehystetään heittomerk eillä USART_Init();

Page 14: 6.7. rauta USART-Ohjelmointia

14

while(1) { for(i = 0; i < 9; i++) { USART_Transmit(taulu[i]); // tulostetaan tau lukon sisältö WAIT(50); } USART_Transmit(0x0A); // LF, Line Feed, rivin vaihto USART_Transmit(0x0D); // CR, Carridge Return, // telan palautus rivin alkuun WAIT(500); } }

Analysointi Alkumääritykset samat kuin edellisissä. Sitten määritämme taulukon nimellä taulu. Siinä on 9 solua, eli char-merkkipaikkaa. Samalla täytetään taulukko yksittäisillä merkeillä. Merkit on kehystettävä heittomerkeillä ja eroteltava toisistaan pilkulla. Nyt ei ole kysymys merkkijonosta, vaan merkkitaulukosta. Main-funktion for-silmukassa tulostetaan taulukon jokainen solu yksi kerrallaan sarjaportin kautta PC:n terminaali-ohjelmaan. Lopuksi lähetetään rivinvaihtomerkki ja telanpalautusmerkki, tai oikeastaan niiden ASCII.-arvot. Toimivat aivan samalla lailla. Pienen viiveen jälkeen sama uudelleen. printf-funktio Kaikkien C-kielikurssien ensimmäinen opittava ohjelma tulostaa printf-funktiolla kuvaruutuun ”Hello World!”. Miksi se on ongelma sulautettujen C-kielessä? Koska sitä on vaikea saada mahdutettua mukaan. GCC kääntimen tekijät pyrkivät pitäytymään tiukasti standardissa. Printf-funktio tekee juuri niin kuin ANSI C normi sanoo, tulostaa konsoliin (monitoriin). Mutta eihän monitoria yleensä ole ’työssä olevan’ sulautetun systeemin lähimaillakaan (vertaa kahvinkeitin, pesukone, kännykkä). Joten printf() on sulautetuissa järjestelmissä sellaisenaan lähes tarpeeton.

Muista, että MCU ei ole PC,

missä käskyllä printf(“Hello”); saadaan käyttöjärjestelmän avulla tulostettua tekstiä monitorin ruutuun.

Mikro-ohjaimen pienten resurssien johdosta joudumme käyttämään ”likaisia temppuja”. Siis ei-ANSI-C-normin mukaista ”puukotettua” koodia.

Page 15: 6.7. rauta USART-Ohjelmointia

15

Joissakin kaupallisissa AVR-kääntimissä on printf-funktio (löytyy se kyllä 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, se kun sisältää monenlaisia muotoilumäärityksiä, jne. Ja kun meidän mikro-ohjaimessamme on käyttömuistia vain 2 kB, niin eihän se ’oikea’ printf millään mahdu mukaan. Siispä on päädyttävä ratkaisuun, jolla hoidetaan merkkijonot ilman sitä ja muilla keinoin. Toisaalta kuitenkin on hyvä tietää, että avr-gcc-yhteisön tuottamana yleisessä jakelussa on hyvin monenlaisia merkkijonon tulostukseen käytettäviä funktioita. Joten, jos välttämättä sellaista kaipaa, se vaatii vähän nettisurffailua, tai kääntymistä kavereitten puoleen.

Huom! 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.

Yleisesti ottaen printf ei ole yksinkertainen asia, vaan AVR runtime kirjaston monimutkaisin toimi. Siinä kaikenlainen, siis kaikki eri datatyypit pitää konvertoida merkkijonoksi, käsitellä muuttujien erilaisia argumenttilistoja, jne.

fdevopen (USART_Transmit, NULL);

Kaikki ohjelmiemme käsittelemä data katoaa bittien taivaaseen heti kun ohjelman ajo loppuu. Ellemme talleta sitä ennen johonkin pysyvään muistiin. Tallentamista varten meidän on luotava tiedosto, file, joka talletetaan nimellä esim. kiintolevylle. 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 (ulkoiseen, käsiteltävänä olevaan) tiedostoon, ja toinen argumentti, mode, mitä tiedostolle aiotaan tehdä (w – kirjoitus, r – luku, a – lisäys). Funktion nimi kuvastaa sen osoitetta. 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: avr-libc-kirjastossa tuo fopen() on korvattu fdevopen()-funktiolla.

Page 16: 6.7. rauta USART-Ohjelmointia

16

kts. avr-libc user manual. ( 6.18.3.3 FILE_ fdevopen (int(_)(char, FILE _) put, int(_)(FILE _) get) ) 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). Funktiolla on kaksi argumenttia - mihin merkki kirjoitetaan - osoitin tiedostoon

(Uudessa kirjastossa funktiosta on kolmas argumentti poistettu, koska sitä ei tarvita).

Käytännön esimerkki Kun ohjataan data esim. UARTin kautta sarjaporttiin korvataan ed. funktio tällä: fdevopen(USART_Transmit, 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);

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. 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 = aina nolla). Käytä tuon funktion nimeä argumenttina kirjoittavaan funktioon, nyt kaikki merkit ohjataan suoraan läpi funktion. Initialisoi UART ja/tai lcd ensiksi. Ohjelma joka kirjoittaa sarjaporttiin printf()-funk tiolla, voisi olla tällainen: /************************************************** ******** Project : printf_1.c, Hardware: PV-M32 + RS-232-cable + PV-EMO Software: WinAVR-20070525 Date : 06.11.2007 Author : pva Comments: tulostaa sarjaporttiin by printf() RS232-kaapeli on ns. käännetty, 2-3, 3-2, 5-5 käytä Tera Term Pro tai jotain muuta terminal-ohjel maa *************************************************** ********/ #include <avr/io.h> #include <stdio.h> #include <util/delay.h> #include <avr/interrupt.h> // keskeytyskirjasto #define WAIT(time) for(uint16_t i=0;i<2000;i++)_del ay_loop_2(time); #define XTAL 4000000 #define BAUD 9600

Page 17: 6.7. rauta USART-Ohjelmointia

17

// *** Lähetä merkki USART datarekisteriin ******** ******** void USART_Transmit(uint8_t data) { // odota kunnes lähtöpuskuri tyhjä while (!( UCSRA & (1<<UDRE))); // 0010 0000, odota kunnes UDRE == 1 // eli ed. merkki lähtenyt UDR = data; // lähtevä merkki datarekisteriin } // *** sarjaportin asetukset, 8 data, 1 stop bit, 8 N1 ***** void USART_Init(void) { // Set baud rate, lasketaan bittien siirtonopeus UBRRH = 0x00; // write high register first UBRRL = ((XTAL/16)/BAUD)-1; // Enable receiver and transmitter, RX ja TX ON UCSRB |= (1<<RXEN)|(1<<TXEN); // 0001 1000 // Bit 4 – RXEN: Receiver Enable, vastaanotto sal littu // Bit 3 – TXEN: Transmitter Enable, lähetys sall ittu UCSRB |= 1<<RXCIE; // rx interrupt enable, 1xx1 1 xxx // vastaanottokeskeytys sallittu // Set frame format // UCSRC = 0x86; // 8 Data, 1 Stop, No Parity 1xx x x11x UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // Bit 7 – URSEL: Register Select, must be one when writing the UCSRC. // Bit 6 – UMSEL: USART Mode Select, Asynchronous m ode = 0. // Bit 5:4 – UPM1:0: Parity Mode, 00 = no parity // Bit 3 – USBS: Stop Bit Select, 0 = 1 stop bit // Stop Bits to be inserted by the Transmitter. // The Receiver ignores this setting. // Bit 2:1 – UCSZ1:0: Character Size, // combined with the UCSZ2 bit in UCSRB sets the nu mber of data bits // in a frame the Receiver and Transmitter use. 011 = 8-bit // Bit 0 – UCPOL: Clock Polarity, used for Synchron ous mode only. } int main(void) { uint8_t i, merkki = 0x41; // ASCII 0x41 (65_des) on A USART_Init(); fdevopen (USART_Transmit, NULL); // ohjataan oletuslaitteeksi USART_Transmit sei(); // global interrupt ON 1xxx xxxx while(1) { for(i=0; i<10; i++) { printf("%d=%c, ", merkki++, merkki); // %d on kokonaisluku // %c merkki WAIT(500); }

Page 18: 6.7. rauta USART-Ohjelmointia

18

USART_Transmit('\n'); // new line, uusi rivi USART_Transmit('\r'); // carriage return, telan palautus WAIT(1000); merkki = 0x41; } }

Analysointi Kommentit kertovat kaiken olennaisen. Toinen printf /************************************************** ******** Project : printf_2.c, Hardware: PV-M32 + RS-232-cable + PV-EMO Software: WinAVR-20070525 Date : 06.11.2007 Author : pva Comments: tulostaa sarjaporttiin by printf() RS232-kaapeli on ns. käännetty, 2-3, 3-2, 5-5 käytä Tera Term Pro tai jotain muuta terminal-ohjel maa *************************************************** ********/ #include <avr/io.h> #include <stdio.h> #include <util/delay.h> #define WAIT(time) for(uint16_t i=0;i<2000;i++)_del ay_loop_2(time); #define XTAL 4000000 #define BAUD 9600 // *** Lähetä merkki USART datarekisteriin ******** ******** void USART_Transmit(uint8_t data) { // odota kunnes lähtöpuskuri tyhjä while (!( UCSRA & (1<<UDRE))); // 0010 0000, odota kunnes UDRE == 1 // eli ed. merkki lähtenyt UDR = data; // lähtevä merkki datarekisteriin } // *** sarjaportin asetukset, 8 data, 1 stop bit, 8 N1 ***** void USART_Init(void) { // Set baud rate, lasketaan bittien siirtonopeus UBRRH = 0x00; // write high register first UBRRL = ((XTAL/16)/BAUD)-1; // Enable receiver and transmitter, RX ja TX ON UCSRB |= (1<<RXEN)|(1<<TXEN); // 0001 1000 // Bit 4 – RXEN: Receiver Enable, vastaanotto sal littu // Bit 3 – TXEN: Transmitter Enable, lähetys sall ittu UCSRB |= 1<<RXCIE; // rx interrupt enable, 1xx1 1 xxx // vastaanottokeskeytys sallittu // Set frame format // UCSRC = 0x86; // 8 Data, 1 Stop, No Parity 1xx x x11x UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // Bit 7 – URSEL: Register Select, must be one when writing the UCSRC. // Bit 6 – UMSEL: USART Mode Select, Asynchronous m ode = 0. // Bit 5:4 – UPM1:0: Parity Mode, 00 = no parity

Page 19: 6.7. rauta USART-Ohjelmointia

19

// Bit 3 – USBS: Stop Bit Select, 0 = 1 stop bit // Stop Bits to be inserted by the Transmitter. // The Receiver ignores this setting. // Bit 2:1 – UCSZ1:0: Character Size, // combined with the UCSZ2 bit in UCSRB sets the nu mber of data bits // in a frame the Receiver and Transmitter use. 011 = 8-bit // Bit 0 – UCPOL: Clock Polarity, used for Synchron ous mode only. } int main(void) { uint8_t data[] = {"Tietokone"}; USART_Init(); fdevopen (USART_Transmit, NULL); // ohjataan oletuslaitteeksi USART_Transmit while(1) { printf("Hello: %s", data); USART_Transmit(0x0A); // LF, Line Feed, rivin vaihto USART_Transmit(0x0D); // CR, Carridge Return, telan palautus rivin alkuun WAIT(1000); } }

ASCII-harjoitus ASCII-merkit kuuluvat ohjelmoijan yleissivistykseen. Ellet tunne niitä, tutki liitteen ASCII-taulukkoa. Jotta ne tulisivat entistä tutuimmiksi tehdään pieni harjoitus. Tutkitaan ensin ASCII-taulukkoa. A on heksalukuna 0x41, eli binäärisenä 0100 0001 a on heksalukuna 0x61, eli binäärisenä 0110 0001 … Z on heksalukuna 0x5A, eli binäärisenä 0101 1010 z on heksalukuna 0x7A, eli binäärisenä 0111 1010 Tutki tarkkaan binäärilukuja. Huomaat, että bitti 5 (vähiten merkitsevä on bitti 0) on erilainen, muuten isot ja pienet ASCII-kirjaimet ovat binäärisenä samanlaiset. Siis pieni kirjain voidaan muuttaa isoksi vain bitti 5 nollaamalla. Sehän hoituu AND-operaatiolla helposti. Tarvitaan maskiksi luku, jossa ko. bitti on 0 ja muut ovat ykkösiä. Maski on siis 1101 1111. a 0110 0001 maski 1101 1111 ----------------------------- AND 0100 0001

Page 20: 6.7. rauta USART-Ohjelmointia

20

Harjoitus 1. Kirjoita edellisen perusteella pieni ohjelma, joka muuttaa pienet aakkoset, vaikka 5 ensimmäistä (a, b, c, d, e, f) isoiksi kirjaimiksi. Tulostus terminal-ohjelmaan. Printf()-funktion käyttämät ei-tulostuvat merkit

Merkki Representation Vastaava heksa-arvo BEL, ääni ‘\a’ ‘\x07’ Backspace, askelpalautin ‘\b’ ‘\x08’ TAB, tabulaattori ‘\t’ ‘\x09’ LF new line, uusi rivi ‘\n’ ‘\x0A’ VT ‘\v’ ‘\x0B’ FF, Form Feed, ‘\f’ ‘\x0C’ CR, Carriage Return, vaunun palautus ‘\r’ ‘\x0D’

Printf-funktion muotoilumerkit %d desimaalikokonaisluku %6d desimaalikokonaisluku, enintään 6 merkkiä leveä %f liukuluku %6f liukuluku, enintään 6 merkkiä leveä %.2f liukuluku, kaksi merkkiä desimaalipisteen jälkeen %6.2f liukuluku, enintään 6 merkkiä leveä ja 2 merkkiä desimaalipisteen jälkeen %o oktaaliluku %x heksaluku %c merkki %s merkkijono %% itse %-luku The default printf library does not handle floats.

Printf()-oletuskirjasto ei osaa käsitellä floats eli liukulukuja. Mukaan tulee ottaa the libprintf_flt library (in Configuration options, under the Libraries tab). Muista myös että avr-gcc:n käyttämät double ja float ovat saman kokoisia. Tehdään pieni koodi jolla asia selviää. /************************************************** ******** Project : printf_ja_floating_point.c, Hardware: PV-M32 + RS-232-cable + PV-EMO Software: WinAVR-20070525 Date : 06.11.2007 Author : pva Comments: tulostaa sarjaporttiin by printf() RS232-kaapeli on ns. käännetty, 2-3, 3-2, 5-5 käytä Tera Term Pro tai jotain muuta terminal-ohjel maa *************************************************** ********/

Page 21: 6.7. rauta USART-Ohjelmointia

21

#include <avr/io.h> #include <stdio.h> #include <util/delay.h> #define WAIT(time) for(uint16_t i=0;i<2000;i++)_del ay_loop_2(time); #define XTAL 4000000 #define BAUD 9600 // *** Lähetä merkki USART datarekisteriin ******** ******** void USART_Transmit(uint8_t data) { // odota kunnes lähtöpuskuri tyhjä while (!( UCSRA & (1<<UDRE))); // 0010 0000, odota kunnes UDRE == 1 // eli ed. merkki lähtenyt UDR = data; // lähtevä merkki datarekisteriin } void USART_init(void) { UBRRH = 0x00; // write high register first UBRRL = ((XTAL/16)/BAUD)-1; // nopeus UCSRB |= (1<<TXEN); // Enable transmitter-lähetys // UCSRC = 0x86; // 8 Data, 1 Stop, No Parity UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); fdevopen(USART_Transmit, NULL); // ohjataan oletuslaitteeksi USART_Transmit } int main(void) { uint8_t laskuri = 10; uint16_t U = 1; double resistanssi, I = 0.015; USART_init(); while (laskuri--) { resistanssi = U++/I; USART_Transmit(0x0A); USART_Transmit(0x0D); printf("Resistanssi: "); printf(" R%d = %6.3f ohmia", laskuri, resistans si); WAIT(1000); } USART_Transmit(0x0A); USART_Transmit(0x0D); printf("Kiitos."); } /* Oletuksena avr-libc-kirjaston printf-funktio ei osa a tulostaa liukulukuja, desimaalilukuja. Kun et käytä liukuluja, säästät muistia melkoisesti . 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

Page 22: 6.7. rauta USART-Ohjelmointia

22

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 */

Analysointi

Ohjelmallinen UART, Full duplex software USART Joissakin AVR-ohjaimissa ei ole USARTia, mm. AT90S1200 on sellainen. Silloin voidaan sarjaliikenteen hoitamiseksi koodata ohjelmallinen USART. Se on viisainta kirjoittaa Full duplex moodiin, sillä half duplex modi voi aiheuttaa datan korruptointia, rikkoontumista/vioittumista. Tähän tulee mallikoodi, kun kerkiää....