USART - järjestikühenduse liides
USART'i (Universal Synchronous/Asynchronous Receiver Transmitter) kasutatakse mikrokontrollerite omavaheliseks andmesideks ja ühenduseks muude väliste seadmetega (näiteks arvutiga). Side võib olla sünkroonne (USRT - Universal Synchronous Receiver Transmitter) või asünkroonne (UART - Universal Asynchronous Receiver Transmitter). Kogu USART'i funktsionaalsus on kogutud namespace'i AVRCpp::USART, mis asub päisefailis „USART.h“. Mõnel mikrokontrolleril on mitu USART porti - nendele vastavad staatiliste liikmetega klassid on nimetatud USART0, USART1, USART2 jne. Juhul, kui seadmel on üks USART'i port, siis on see seotud klassiga USART0.
Ühenduse ülesseadmine
Seaded
- Paarsusbitt - paarsuskontroll tegemaks kindlaks, kas andmed on jõudnud kohale rikkumata kujul. Soovitav on alati paarsusbitti kasutada. Paarsusbitt ei taga, et viga alati kindlaks tehakse: töötab alati vaid juhul, kui vaid üks bitt kaadrist võetakse vastu valesti.
enum ParityCheck { // Paarsusbitt kaadris puudub. NoParityCheck, // Paarsusbitt on kaadris olemas. Väärtusega üks, kui andmebittide summa // annab tulemuseks paaris arvu. EvenParity, // Paarsusbitt on kaadris olemas. Väärtusega üks, kui andmebittide summa // annab tulemuseks paaritu arvu. OddParity };
- Stopbitt - määrab ära lõpubiti pikkuse. Võib olla saatjal ja vastuvõtjal erinevalt seadistatud. Sümbolite edastuskiirus väheneb, kui valida DoubledStopBit, aga see tagab usaldusväärsema andmeühenduse.
enum StopBit { // Kaadris on ühekordne lõpubitt NormalStopBit, // Kaadris on kahekordne lõpubitt DoubledStopBit };
- Sümboli pikkus - Selleks, et ühe kaadriga terve bait üle kanda (binary mode), peab sümboli pikkus olema 8 bitti. ASCII teksti ülekandmiseks (ASCII mode) on mõistlik kasutada 7-bitilist andmeosa. Üheksabitine andmeosa on mõeldud esmajoones mitme mikrokontrolleri ühendamisks ühe liini peale (andmesiin - data bus).
enum CharacterSize { // Kaadri andmeosa on 5 bitti. CharacterSize5, // Kaadri andmeosa on 6 bitti. CharacterSize6, // Kaadri andmeosa on 7 bitti. CharacterSize7, // Kaadri andmeosa on 8 bitti. CharacterSize8, // Kaadri andmeosa on 9 bitti. CharacterSize9 };
- Sünkronisatsiooni front - Määrab ära, kas biti väärtus loetakse sisse sünkronisatsioonisignaali (clock) tõusval või langeval küljel.
enum SynchroEdge { // Vastuvõtt tagafrondil ReceiveOnFall, // Vastuvõtt esifrondil ReceiveOnRise };
- Andmesiin või lihtne andmeliin - andmesiini kasutatakse juhul, kui ühe ja sama liini peale on ühendatud mitu kontrollerit. Lihtsa andmeliini korral ühendusel on alati täpselt kaks poolt.
enum CommunicationMode { // Lihtne andmeliin SingleProcessor, // Andmesiin MultiProcessor };
- Andmeliin kasutuses või mitte - saab määrata kommunikatsiooni suunda: simpleks ehk andmeliiklus käib vaid ühtepidi (üks pool saadab ja teine võtab vastu) või täis/pool-dupleks ehk andmeliiklus on mõlemasuunaline. Andmeliini väljalülitamisel saab kasutada vastavat väljaviiku alternatiivseteks tegevuseks (näiteks teha tavaliseks digitaalseks sisendiks).
- Saatjaliin
enum Transmitter { // Saatjaliin on kasutuses TransmitterEnable, // Saatjaliini väljaviik on muuks otstarbeks TransmitterDisable };
- Vastuvõtuliin
enum Receiver { // Vastuvõtuliin on kasutuses ReceiverEnable, // Vastuvõtuliini väljaviik on muuks otstarbeks ReceiverDisable };
- Andmeedastuskiirus (baud rate) - bitikiirus (bitti sekundis), kusjuures sümboli edastuse kiirus = andmeedastuskiirus / bittide arv kaadris. Andmeedastuskiiruste seadmseks on mõistlik kasutada ühte järgnevatest makrodest (failist „USART.h“):
// Asünkroonse ühekordse kiirusega andmeühenduse korral #define AsyncNormBaudCalc(BaudRate) F_CPU / 16 / BaudRate - 1 // Asünkroonse kahekordse kiirusega andmeühenduse korral #define AsyncDblBaudCalc(BaudRate) F_CPU / 8 / BaudRate - 1 // Sünkroonse andmeühenduse korral halduri poolel #define SyncMasterBaudCalc(BaudRate) F_CPU / 2 / BaudRate - 1
Järgnevates koodinäidetes on ära näidatud, millal ja kus neid makrosid kasutatakse.
Asünkroonne ühendus
Asünkroonsel ühendusel on kasutuses väljaviigud TXn ja RXn. Mõlemad ühenduse pooled peavad olema ühesuguselt seadistatud.
Klassi USARTn'i staatiline funktsioon asünkroonse ühenduse seadistamiseks on:
void SetupAsynchronous ( uint16_t baudRate, Receiver, Transmitter, ParityCheck, StopBit, CharacterSize, Speed, CommunicationMode );
Näide:
#include "USART.h" using namespace USART; typedef USART0 MyUART; void Initialize() { MyUART::SetupAsynchronous ( AsyncDblBaudCalc(9600), /* baudRate */ ReceiverEnable, /* Receiver */ TransmitterEnable, /* Transmitter */ EvenParity, /* ParitiCheck */ NormalStopBit, /* StopBit */ CharacterSize8, /* CharacterSize */ DoubleSpeed, /* Speed */ SingleProcessor /* CommunicationMode */ ); }
Kui parameeter speed on määratud väärtusele NormalSpeed, siis tuleb andmeedastuskiiruse parameetri edastamisel kasutada makrot AsyncNormBaudCalc, vastasel korral AsyncDblBaudCalc.
Sünkroonne ühendus
Sünkroonse ühenduse korral on üheks pooleks haldur (master) ja teiseks pooleks alluv (slave). Alluvaid võib olla seejuures mitu, haldureid aga alati üks. Sünkroonne ühendus kasutab kolme liini: TXn, RXn ja XCKn.
Halduri seadistamine
SetupMasterSync ( uint16_t baudRate, Receiver, Transmitter, ParityCheck, StopBit, CharacterSize, SynchroEdge, CommunicationMode );
Näide:
#include "USART.h" using namespace USART; typedef USART0 MyMasterUSRT; void Initialize() { MyMasterUSRT::SetupMasterSync ( SyncMasterBaudCalc(9600) /* baudRate */ ReceiverEnable, /* Receiver */ TransmitterEnable, /* Transmitter */ EvenParity, /* ParitiCheck */ NormalStopBit, /* StopBit */ CharacterSize8, /* CharacterSize */ ReceiveOnFall, /* SynchroEdge */ SingleProcessor /* CommunicationMode */ ); }
Alluva seadistamine
Klassi USARTn'i staatiline funktsioon alluva seadistamiseks on:
void SetupSlaveSync ( Receiver, Transmitter, ParityCheck, StopBit, CharacterSize, SynchroEdge, CommunicationMode );
Näide:
#include "USART.h" using namespace USART; typedef USART0 MySlaveUSRT; void Initialize() { MySlaveUSRT::SetupSlaveSync ( ReceiverEnable, /* Receiver */ TransmitterEnable, /* Transmitter */ EvenParity, /* ParitiCheck */ NormalStopBit, /* StopBit */ CharacterSize8, /* CharacterSize */ ReceiveOnFall, /* SynchroEdge */ SingleProcessor /* CommunicationMode */ ); }
Andmeside pidamine
Saatmisfunktsioonid
static void Write (uint8_t data) static void Write (uint8_t data, bool ninth) static void WriteNinthSet (uint8_t data) static void WriteNinthCleared (uint8_t data)
Kõik need funktsioonid täidavad riistvaralise saatmispuhvri baidi. Kui see bait on juba eelnevalt täidetud, siis programmijärg on funktsioonis kinni senikaua, kuni eelmine bait on ära saadetud.
Teksti saatmiseks on mõistlik kasutada:
void SendText (char *text, uint16_t size);
SendText saadab parameetriga size määratud arv baite sõltumata parameetriga text viidatud nullsümboliga lõppeva sõne pikkusest. „Puudu jäävad baidid“ täidetakse nullsümbolitega. Sobib ideaalselt konstantse pikkusega pakettide saatmiseks.
Universaalsed funktsioonid:
template <typename Type> void Send (Type &data); template <typename Type> void SendArray (Type *data, uint16_t size);
Funktsioonid Send ja SendArray pöörduvad tagasi alles siis, kui kogu andmehulk on saadetud.
Näide:
#include "USART." using namespace AVRCpp::USART; typedef USART0 MyUSART; struct Packet { uint8_t version : 2; uint8_t function : 2; uint8_t length : 4; uint16_t address; int32_t data[16]; }; // struct Packet void InitializeUSART(); void FillBuffer(uint8_t *buffer); int main() { Packet packet; uint8_t additionalData[32]; InitializeUSART(); packet.version = 1; packet.function = 0; packet.length = 0; packet.address = 43; packet.data[0] = 0; FillBuffer(additionalData); MyUSART::Send(packet); MyUSART::SendArray(additionalData, 32); /* ... */ } // main
Vastuvõtufunktsioonid
bool Read (uint8_t &data); bool Read (uint8_t &data, bool &ninth); bool SimpleRead (uint8_t &data); bool SimpleRead (uint8_t &data, bool &ninth); ReadResult DetailedRead (uint8_t &data); ReadResult DetailedRead (uint8_t &data, bool &ninth); ReadResult DetailedSimpleRead (uint8_t &data); ReadResult DetailedSimpleRead (uint8_t &data, bool &ninth);
- Eesliide Simple tähistab kõige optimaalsemat võimalikku lugemist - tarkvaraline lugemise katkestamine ei ole võimaldatud, kuid see-eest programmi maht on väikseim võimalik.
- Eesliide Detailed tähistab võimalust funktsiooni tagastatava väärtuse abil teada saada lugemise õnnestumise kohta üksikasjalikku infot, kusjuures ReadResult on defineeritud:
enum ReadResult { // Vastuvõtt oli edukas Success, // Tarkvaraliselt katkestatud Canceled, // Vähemalt üks kaader jäi vahele - osa sümboleid jäi õigel ajal // tarkvara poolt välja lugemata DataOverRun, // Vastuvõetud kaadri formaat ei vasta seadistustele või on tugevasti moondunud FrameError, // Paarsuskontroll andis negatiivse tulemuse ParityError };
- Ilma eeslii(de)teta funktsioon Read võimaldab tarkvaralist vastuvõtu katkestamist ja tagastatava väärtuse põhjal saab programmis kindlaks teha, kas vastuvõtt õnnestus (true) või mitte (false).
Universaalsed funktsioonid:
template <typename Type> bool Receive (Type &data); template <typename Type> bool ReceiveArray (Type *data, uint16_t size); template <typename Type> ReadResult DetailedReceive (Type &data); template <typename Type> ReadResult DetailedReceiveArray (Type *data, uint16_t size);
Näide:
#include "USART." using namespace AVRCpp::USART; typedef USART0 MyUSART; struct Packet { uint8_t version : 2; uint8_t function : 2; uint8_t length : 4; uint16_t address; int32_t data[16]; }; // struct Packet void InitializeUSART(); int main() { Packet packet; uint8_t additionalData[32]; InitializeUSART(); if (MyUSART::Receive(packet) ) { if (packet.version == 1) switch (packet.function) { case 0: if (MyUSART::DetailedReceiveArray(additionalData, 32) == Success) { /* ... */ } else { /* FAILED ! */ } break; case 1: /* ... */ } } else { /* FAILED ! */ } } // main
Vastuvõtu katkestamine
Vastuvõtu katkestamist kasutatakse juhul, kui Read või Receive funktsioon on vaja blokeerivast olekust välja tuua ilma, et peaks teiselt seadmelt andmeid saabuma. Tüüpiliseks juhtumiks on maksimaalse ooteaja (time out period) kehtestamine: seadmele, kellega suhtlus käib, antakse teatud aeg, mille vältel on tal võimalik vastus saata. Kui vastus ei jõua määratud aja vältel kohale, siis taimeri katkestuse alamprogramm katkestab lugemise ja Read funktsioon pöördub tagasi väärtusega false või Cancelled. Ehk siis C++'s:
#include "USART.h" #include "Interrupt.h" using namespace AVRCpp; using namespace USART; typedef USART0 MyUSART; #define PLEASE_SEND_SOMETHING 0 #define THANK_YOU 1 #define TOO_LATE 2 INTERRUPT_HANDLER(TIMER0_OVF) { // Maksimaalne ooteaeg on läbi MyUSART::CancelReading(); } void InitializeMyUSART(); void InitializeTimer(); void ActivateTimerOverflowInterrupt(); int main() { uint8_t data = 0; InitializeMyUSART(); MyUSART::Write(PLEASE_SEND_SOMETHING); InitializeTimer(); ActivateTimerOverflowInterrupt(); GlobalInterrupts::Enable(); if (Read(data) ) { // Korras, soovitav bait sai sisseloetud MyUSART::Write(THANK_YOU); } else { // Ühendus on katkenud või teine seade jäi saatmisega liiga hiljaks // või vastuvõtmisel esines viga MyUSART::Write(TOO_LATE); } return 0; }
USART'i kasutamine siinina
USART'i liidesega Atmeli mikrokontrolleritele on riistvaraliselt sisse ehitatud võimalus kasutada seda porti siinina. Lihtsaim viis on toimida järgnevalt:
- Luua sünkroonne võrk ühe halduri ja mitme alluvaga
- Kasutada üheksabitist sümbolit ühes kaadris, kusjuures üheksas bitt tähistab paketi algust.
- Kasutada mitmeprotsessorilist režiimi (CommunicationMode = Multiproccessor)
- Paketi esimese baidi vastuvõtul (üheksas bitt on loogiline 1):
MyUSART::EnterSingleProcessorMode();
- Esimesel võimalusel, kui on kindlaks tehtud, et addressaat on keegi teine, või kui pakett on lõpuni loetud:
MyUSART::EnterMultiProcessorMode();