top of page

Pažintis su TI Tiva C mikrokontroleriu

TI Tiva C serijos TM4C123 vaidinamas "LaunchPad'as", su ARM® Cortex™-M4 mikrokontroleriu. Pakankamai galingas daiktas, rimtiems projektams. Tai buvo mano pirmasis mikrokontroleris po Arduino Uno, kuriuo rašiau tikra C kalba.

Būtent šitą pirkau, nes KTU universitete dauguma dirba su TI mikrokontroleriais, be to aš norėjau kažko su skambiu pavadinimu ARM Cortex, tai šitas savo kaina puikiai tiko, 13 dolerių ir po kelių dienų parsiunčia tiesiai į namus iš JAV.

Apibendrinant TI gaminius bei programinę įrangą CCS, man patiko dirbti su CCS programa. Nesunku perprasti, maloni akims aplinka. Tačiau lyginant su Atmel studio 6 funkcionalumu, tai CCS tikrai kur yra dar tobulėti...

Puslapyje www.ti.com uzsiregistravęs gavau tikrai puikų TI supportą, iškilus kokiems nesklandumams programuojant, greitai atrašo, padeda išspręsti problemas. Žinoma, ties "supportu", kitos kompanijos irgi niekuo nenusileidžia.

Pats mikrokontroleris, sakyčiau kiek kaprizingas... Ne kartą yra tekę tą patį kodą kelis kartus perrašyti "per aplinkui", kad pagaliau veiktų, nors visais atvejais sintaksė buvo taisyklinga, na bet peikti man neleidžia mano kompetencija, tai tiek to. :)

Šitame poste, noriu pasidalinti vienu savo parašytu kodu, kuris man buvo bandomoji užduotis - pilotas, norint gauti apmokamą praktiką xxx įmonėje.

Užduotis nebuvo lengva, reikalaujanti panaudoti kuo daugiau "hardwaro": timerius, uart interrupt'ą, DMA kontrolerį, o veikimo metu mikrokontroleris turėjo būti kuo gilesniame miege, sunaudodamas kaip įmanoma mažiau energijos. Man pavyko energijos sąnaudas sumažinti iki 11.5mW (3.5mA * 3.3V) gilaus miego metu. Neblogai.

Duomenų paketai tikrinami bei formuojami išsiųsti CRC-16 (Modbus). Jeigu gautas paketas su blogu CRC, tai paketas ignoruojamas.

MODBUS PROTOKOLAS :

Gaunami duomenys:

Slave Address (1 byte) | Function (1 byte) | Starting Address (2 byte) | No. of Points (2 bytes) | CRC-16 (2 byte)

Įšsiunčiami duomenys:

Slave Address (1 byte) | Function (1 byte) | Byte Count (1 byte) | Data (1 - 251 bytes) | CRC-16 (2 byte)

FUNKCIJOS:

Read Discrete Inputs = 0x02 (nuskaityti kanalo būseną - LED on/off)

Read Holding Registers = 0x03 (nuskaitoma registrų reikšmė - kiek kartų LED buvo įjungtas)

Write Single Coil = 0x05 (ištrinama norimo registro reikšmė)

PAVYDŽIAI:

1. Iš terminalo (naudoju terminal v1.9 programą) siunčiama užklausa apie 2-jų kanalų būseną:

0x01,0x02,0x00,0x00,0x00,0x02,0x39,0xC8;

Atsakymas iš mikrokontrolerio:

0x01,0x02,0x01,0x00,0xA1,0x88 (abu LED išjungti)

2. Iš terminalo siunčiamas užklausimas apie registro 2 reikšmę:

0x01,0x03,0x00,0x00,0x00,0x02,0x39,0xC8;

Atsakymas iš mikrokontrolerio:

0x01,0x03,0x04,0x00,0x04,0x00,0x15,0x96,0x2A; (LED1 buvo įjungtas 4 kartus, LED2 15-ką)

3. Iš terminalo norima ištrinti registro 1 reikšmę:

0x01,0x05,0x00,0x00,0xFF,0x00,0x8C,0x3A;

Atsakymas iš mikrokontrolerio:

0x01,0x05,0x00,0x00,0xFF,0x00,0x8C,0x3A; (Jeigu pavyko ištrinti, atsakymas sugrįžta toks pats)

4. (Klaidos atveju) Iš terminalo siunčiamas užklausimas apie registro 1 reikšmę:

0x01,0x03,0x00,0x00,0x00,0x01,0x35,0xC1;

Mikrokontroleriui nepavyko nugeneruoti atsakymo, įvyko klaida, tokiu atveju siunčiamas modbus error atsakymas:

0x01,0x83,0x00,0x00,0x00,0x01,0x35,0xC1;

Taip pat prie mikrokontrolerio buvo prijungti du “pull-up” mygtukai. Mygtukų “bounce” pašalintas “softwariškai”.

Pridedu visus 3 kodo failus, jeigu kam bus įdomu pažiūrėti kaip kodas buvo parašytas.

"MBus_main.c" bus pagrindinis kodo failas. "Hardware_Configure.c" tai mikrokontrolerio periferijų nustatymai su keliomis DMA funkcijomis. "Hardware_Configure.h" tai "header" failas, kuriame apibrėžtos kode naudojamos reikšmes.

Ką noriu pabrėžti dėl kodo parašymo subtilybių, tai visa esmė užmigdyti kontrolerį ir laukti kol ateis duomenys į uart ISR bei fiksuoti mygtuko paspaudimus, atitinkamai įjungiant/išjungiant LED'us. Nors sumanimas iš pradžių buvo junkti rėles, ką ir nesunku pritaikyti.

Taigi, toliau analizuojant kodą, visas veikimas pagrįstas vadinamų "state" keitimu. Principas toks:

Deklaruoji globalų enum kintamųjų tipą:

typedef enum{ // Deklaruoji globalų enum kintamųjų tipą: st_WaitAddress, st_Function,

... st_Done, }t_Rx_State;

t_Rx_State RxState = st_WaitAddress; // Priskiriu pradinę reikšmę

ISR { // uart Interupto funkcijoje char receive_byte = UART_CharGet(); // Paimu gautą baitą switch(RxState) { case st_WaitAddress: if(receive_byte == MBus_address)) { // MBus_address priskirtas reikšmei 1. MBus_rx_buff[0] = receive_byte; // reikšmę priskiriu globaliam buferiui RxState = st_Function; } break; case st_Function: if(receive_byte == ...) { MBus_rx_buff[1] = receive_byte; RxState = st_Done; } break;

... // Ir t.t ;) }

Pagrindiniame while cikle, tiktais sulaukus st_Done priskirimo, kas įvyksta duomenų paketą pilnai gavus, gali nudoti duomenys pagrindiniame cikle.

Žinoma čia labai supaprastinta, ištiesų laukiu uart ISR dumenų dydžio baito ir gavęs jį, nustatau DMA kontrolerį gauti duomenys. Gavęs duomenys, DMA vėl iškviečia uart ISR, pranešdamas DMA pabaigą ir tuomet pakeičiu stetą į pilnai gautą duomenų paketą.

int main() { while(1) { if(RxState == st_Done) { // vykdyti nurodymus, išsiųsti atsakymą.

switch(MBus_rx_buff[1]) { // Pagal protokolą, 2 baitas nurodo funkciją case 0x02: //

Read_Inputs_status();

break;

...

} RxState = MBus_address; // gražinu pradinį state } } }

Taip pat noriu paminėti, jog Modbus protokolas suprojektuotas taip, kad išsiuntus duomenų paketą vienam iš "slave" modulių (šiuo atveju iš terminalo į mikrokontrolerį), būtinai turi laukti atsakymo ir tik nesulaukus jo 1-3s, registruoti klaidą.

Galėčiau dar aptarti mygtuko "debouncinimą" ar kaip naudotis CRC, bet nesikartosiu, tai aprašęs esu namų termometrų tiklo straipsnyje.

Apibendrinant, tai efektyvus kodas "slave" moduliukams komunikacijai su 'master" moduliu ar kompiuteriu.

Featured Posts
Recent Posts
Search By Tags
Žymių dar nėra.
bottom of page