Vous êtes sur la page 1sur 13

Arhitecturi cu microprocesor

Curs 7
7.1. Interfaa de programare (IDE) n MikroC Microcontrolerele execut programele ncrcate n memoria Flash. Aceste programe sunt numite cod executabil i sunt o secven de 0 i 1 care sunt interpretate direct de microcontroler. Acest cod este organizat pe cuvinte de 12, 14 sau 16 bii depinznd de tipul de microcontroler i arhitectura lui. Fiecare cuvnt este considerat de ctre CPU ca o comand care va fi executat de ctre microcontroler. Din raiuni practice, este mai uor de lucrat cu secvene de numere n hexazecimal, i adeseori, codul executabil este reprezentat ca o secven de numere hexazecimale nuimit cod Hex. Microcontrolere PIC 16F887 au cuvinte pe 14 bii, iar setul de instruciuni n limbaj de asamblare are 35 de instruciuni diferite. Programarea n limbajul de asamblare, limbajul direct al microcontrolerului este dificil i mare consumatoare de timp. Ca atare se prefer utilizarea unor limbaje de nivel mai nalt, cel mai adesea limbajul C. Similar limbajului de asamblare, exist compilatoare specializate pentru microcontrolere care produc cod in asamblare i apoi n final cod executabil care poate fi ncarct pe microcontroler.

Un exemplu simplu de program scris n C i secvena i rezultatele operaiilor de compilare ale compilatorului MikroC sun n Figura de mai jos.

7.1. Limbajul C pentru microcontrolere PIC - MikroC Compilatorul mikroC recunoate 33 cuvinte cheie:
Cuvinte cheie mikroC
absolute asm at auto bit bool break case catch char class code const continue data default delete do double else enum explicit extern false float for friend goto if inline int io long mutable namespace operator org pascal private protected public register return rx sfr short signed sizeof static struct switch template this throw true try typedef typeid typename union unsigned using virtual void volatile while

Standardul ANSI C conine 24 de biblioteci cu funciile corespunztoare. Aceste funcii sunt n mod obinuit furnizate cu orice compilator i cele mai multe din opraiile uzuale n programe sunt efectuate folosind aceste biblioteci.
<assert.h> <errno.h> <inttypes.h> <locale.h> <signal.h> <stdint.h> <stdlib.h> <time.h> <complex.h> <fenv.h> <iso646.h> <math.h> <stdarg.h> <stddef.h> <string.h> <wchar.h> <ctype.h> <float.h> <limits.h> <setjmp.h> <stdbool.h> <stdio.h> <tgmath.h> <wctype.h>

n cele ce urmeaz vom detalia aspecte din limbajul MikroC pentru microcontrolere PIC, insistnd pe elemente diferite de ANSI C. Mikro C are un set de cuvinte adiionale care nu sunt suportate de standardul ANSI C:
code data rx at sbit bit sfr

Pentru a facilita programarea MCU a PIC, MikroC are un numr de variabile globale i constate predefinite. Toate registrele PIC i biii lor sunt declarate ca variabile globale. Aceti indentificatori au un caracter global i sunt vizibili n ntregul proiect. La crearea unui proiect MikroC pentru PIC va include fiierele corespunztoare variantei de microcontroler PIC din directorul defs care conine declaraiile corespunztoare registrelor SFR i constantelor. mikroC PRO for PIC permite accesarea biilor individuali din variabilele pe 8 bii care suport tipurile de date bit i sbit. Dac vrem s accesm un cmp particular dintr-o variabil global de la un MCU ales (de exemplu PIC16F887), putem s le accesm prin numele cmpului sau folosind semnul deselector pentru variabile (.):
GIE_bit = 0; INTCON.B0 = 0; ADCON0.F5 = 1; // stergere bit intreruperi globale // stergere bit 0 in registrul INTCON // setare bit 5 in registru ADCON0

Tipurile de date sbit sunt pentru date SFR adresabile la nivel de bit. Tipurile de date bit sunt pentru date utilizate ca declaraii de variabile. Nu se poate folosi o definiie pentru o arie de bii i nu se pot aloca pointeri la variabile de tip bit. Varibilele de tip bit nu pot fi iniializate i nu pot fi membre de structuri sau union.
sbit LEDA at PORTA.B0; sbit bit_name at sfr-name.B<bit-position>; sbit TRISC0 at TRISC0_bit; bit bf; // variabla bit bit arr[5]; // invalid

ntreruperi ntreruperile sunt tratate prin folosirea cuvntului rezervat interrupt. Prototipul funciei este void interrupt(void) iar pentru P18 piroritile de nivel sczut cu void interrupt_low(void). Se presupune ca utilizatorul va scrie propria definiie (funcie) pentru tratarea intreruperilor n aplicaie. Registrele SFR salvate n stiv la intrarea n ntrerupere su restaurate la revenire din rutinele de ntrerupere sunt:
familia PIC12: W, STATUS, FSR, PCLATH familia PIC16: W, STATUS, FSR, PCLATH familia PIC18: FSR (fast context folosit pentru salvare WREG, STATUS, BSR)

Funciile cu numele interrupt vor fi legate ca ISR (interrupt service routine). Dac se dorete salvarea de ctre utilizator a regitrilor i nu o salvare automat, atunci se folosete directiva pragma:
#pragma disablecontexsaving

Directiva pragma este utilizat de compilator pentru operaii specifice ale compilatorului. Exemple de utilizare rutine ntreruperi simple (primul exemplu) i posibilitate ntreruperi multiple (al doilea exemplu):
// exemplu 1 void interrupt() { contor++; TMR0 = 96; INTCON = $20; } // exemplu 2 void interrupt() { if (INTCON.TMR0IF) { contor++; TMR0 = 96; INTCON.TMR0F = 0; } else if (INTCON.RBIF) { contor++; TMR0 = 96; INTCON.RBIF = 0; } }

Directive de link-editare Pentru alocarea obiectelor n memorie, mikroC foloseste un algoritm intern. Dac dorim stocarea unei variabile sau a unei rutine la o adres predefinit, se folosesc directive de link-editare absolute i org. Directiva absolute specifica adresa de start pentru variabil n memoria RAM. Trebuie avut grij ns s nu supra-scriem n locaia de memorie.
// Variabla x va ocupa 1 octet la adresa 0x42 short x absolute 0x42; // Variabla z va ocupa 2 octeti la adresele 0x33 si 0x34 int y absolute 0x23;

Directiva org specific o adres de start din ROM. Directiva org se poate utiliza cu funcii definite extern, cum ar fi funcii de bibliotec. Directiva org se poate aplica oricrei funcii cu excepia ntreruperilor.
void UART_Write1(char data) org 0x200;

Dac utilizatorul dorete ca s specifice o anumit adres n ROM pentru propria rutina, atunci va trebui s foloseasc directiva orgall.
#pragma orgall 0x200

Pentru a spcifica o adresa anumt de start a unei rutine in ROM foloisnd numai numele rutinei se folosete directiva #pragma funcorg <func_name> <starting_address>. Rutine built-in Compilatorul mikroC PRO for PIC furnizeaz un set de funcii built-in. Aceste funcii nu au nevoie de includere fiier header cu prototipuri. Fiind implementate ca funcii inline, nu exist limitri de imbricare pn la un anumit nivel cu excepia Vdelay_ms, Delay_Cyc i Get_Fosc_kHz care sunt n actualul compilator rutine C. Pentru aceste funcii trebui sa includem n proiect built_in.h.
Lo (returneaz 8 bii al unui numr, biii 07) Hi (returneaz 8 bii al unui numr parte high, biii 815) Higher (returneaz 8 bii al unui numr, biii 1623) Highest (returneaz 8 bii al unui numr, biii 2431) Delay_us (creeaz o ntrziere de un numr constant de microsecunde) Delay_ms (creeaz o ntrziere de un numr constant de milisecunde) Vdelay_ms (creeaz o ntrziere de un numr variabil de milisecunde) Delay_Cyc (creeaz o ntrziere bazat pe ceasul MCU) Clock_Khz (returneaz dispozitiv ceas in KHz rotunjit la cel mai apropiat ntreg) Clock_Mhz (returneaz dispozitiv ceas in MHz rotunjit la cel mai apropiat ntreg) Get_Fosc_kHz (returneaz dispozitiv ceas in KHz rotunjit la cel mai apropiat ntreg)

Specificaii PIC Limitrile de apeluri ibricate (apeluri recursive) sunt n numr de 8 pentru familiile PIC 12, PIC 16 i 31 pentru familiile PIC 18. Datorit limitrilor de memorie i stiv, apelurile de funcii recursive nu pot conine nici un parametru al funciilor, nici variabile locale. Depirea numrului de apeluri va genera de ctre compilator eroare depaire stiv. n aplicaiile cu procesorul PIC16 nu este permis ca o rutin s aiba mai mult de o pagine (2.000 instruciuni). mikroC pentru PIC permite inserare cod de asamblare in codul surs n C folosind declaraia asm. Numeralele nu pot utiliza adresa absolut a variabilelor SFR sau GPR n cadrul instruciunilor asm. Sunt permise formele asm, _asm sau _.
asm { bloc de instructiuni in limbaj asamblare }

Operatorul () poate fi utilizat n lista de prototipuri de funcii pentru a indica un numr variabil de argumente sau argumente de tipuri variabile.
void func_test (int n, float v, ...);

Directive Preprocesor mikroC PRO pentru PIC suport urmtoarele directive preprocesor standard:
#(null directive) #define #elif #else #endif #error #if #ifdef #ifndef #include #line #undef

Biblioteci mikroC PRO pentru PIC furnizeaz un set de biblioteci care simplific iniializarea i folosirea microcontrolerelor PIC i a modulelelor acestora. Pentru includerea bibliotecilor mikroC PRO n proiect se folosete Library manager. Bibliotecile specifice hardware pentru PIC sunt:
ADC CAN CANSPI Compact Flash EEPROM Ethernet PIC18FxxJ60 Flash Memory Graphic LCD I2C Keypad LCD Manchester Code Multi Media Card OneWire Port Expander PrintOut PS/2 PWM RS-485 Software I2C Software SPI Software UART Sound SPI SPI Ethernet SPI Graphic LCD SPI LCD SPI LCD8 SPI T6963C Graphic LCD T6963C Graphic LCD UART USB HID

Bibliotecile standard ANSI:


ANSI ANSI ANSI ANSI C C C C Ctype Math Stdlib String

Biblioteci diverse
Button Conversions Sprint Setjmp Time Trigonometry

Anumite biblioteci utilizeaza funcii, variabile sau constate definite n alte biblioteci. De exemplu, SPI_Glcd Glcd_Fonts i Port_Expander care utilizeaz biblioteca SPI. Asta nseamn ca un utilizator care folosete un din biblioteci trebuie sa utilizeze i dependenele de aceste biblioteci, adic celelalte biblioteci.

Exemplu de program care utilizeaz ntreruperi i temporizatoare Temporizatorul TMR0 este folosit ca un numrator. Cnd numrul de tac-turi de ceas ajunge la numrul memorat n registrul TEST, un 1 logic (5 V) apare la pinul PORTD.3. Aceast tesniune activeaz automat un releu electromecanic, i vom numi acest bit in programul in C, RELAY. n exemplu, registrul test va memora numrul 5.

/*Header******************************************************/ void main() { char TEST = 5; // Constant TEST = 5 enum outputs {RELAY = 3}; // Constant RELAY = 3 ANSEL = 0; ANSELH = 0; PORTA = 0; TRISA = 0xFF; PORTD = 0; TRISD = 0b11110111; // All I/O pins are configured as digital // // // // // Reset port A All portA pins are configured as inputs Reset port D Pin RD3 is configured as an output, while the rest are configured as inputs

OPTION_REG.F5 = 1; OPTION_REG.F3 = 1; TMR0 = 0; do { if (TMR0 == TEST) (PORTD.RELAY = 1); } while (1); }

// Counter TMR0 receives pulses through the RA4 pin // Prescaler rate is 1:1 // Reset timer/counter TMR0

// Does the number in timer match constant TEST? // Numbers match. Set the RD3 bit (output RELAY) // Remain in endless loop

Asignarea prin enumearare se face ndat ce variabila este declarat.


enum outputs {RELAY = 3}; // Constant RELAY = 3

Dac mai muli pini ai portului D sunt conectai la relele, expresia de mai sus poate fi scris ca n cele ce urmeaz:
enum outputs {RELE = 3, HEATER, MOTOR = 6, PUMP};

Toate constantele sunt asignate n felul urmtor: RELE =4, HEATHER = 5, MOTOR = 6, PUMP = 7. Dac ne uitm cu atenie n acest exemplu, vom vedea unul din dezavantaje n utilizarea buclei de ateptare do-whilw peantru a se finaliza un eveniment. n aceast perioada microprocesorul este practic pus n ateptare i poate efectua nici o operaie, ceea ce este un mare dezavantaj. O alt metod mai eficient este cea a utilizrii temporizatoarelor i ntreruperilor. Temporizatorul TMR0 cu prescalare asignat se va utiliza pentru a genera o ntrerupere ori de cte ori registrul timer depete o valoare (overflow) , i incrementeaz variabila cnt cu 1.Cnd valoarea aceste variabile devine 400, portul B este incrementat cu 1. ntreaga procesdura are loc n timp ce microcontrolerul poate face alte operaii la nivel de ntreruperi.

/*Header******************************************************/ unsigned cnt; void interrupt() { cnt++; TMR0 = 96; INTCON = 0x20; } void main() { OPTION_REG = 0x84; ANSEL = 0; ANSELH = 0; TRISB = 0; PORTB = 0x0; TMR0 = 96; INTCON = 0xA0; cnt = 0; // Define variable cnt

// Interrupt causes cnt to be incremented by 1 // Timer TMR0 is returned its initial value // Bit T0IE is set, bit T0IF is cleared

// Prescaler is assigned to timer TMR0 // All I/O pins are configured as digital // // // // // All port B pins are configured as outputs Reset port B Timer T0 counts from 96 to 255 Enable interrupt TMR0 Variable cnt is assigned a 0

do { if (cnt == 400) { PORTB = PORTB++; cnt = 0; } } while(1); }

// // // //

Endless loop Increment port B after 400 interrupts Increment number on port B by 1 Reset variable cnt

Exemplu de program folosind senzorul de temperatura Se utilizeaz senzorul de temperatur DS1820, cu domeniul de msurare -55 C pn la 125 C, cu o precizie de 0.5 C. Se va utiliza un tip special de comunicaie serial, numit 1-wire (biblioteca One_Wire)

Biblioteca conine 3 funcii:


Ow_Reset utilizat pentru resetare senzor; Ow_Read recepionare date de la senzor; Ow_Write trimite comenzi la senzor.

/*Header******************************************************/ // LCD module connections sbit LCD_RS at RB4_bit; sbit LCD_EN at RB5_bit; sbit LCD_D4 at RB0_bit; sbit LCD_D5 at RB1_bit; sbit LCD_D6 at RB2_bit; sbit LCD_D7 at RB3_bit; sbit LCD_RS_Direction at TRISB4_bit; sbit LCD_EN_Direction at TRISB5_bit; sbit LCD_D4_Direction at TRISB0_bit; sbit LCD_D5_Direction at TRISB1_bit; sbit LCD_D6_Direction at TRISB2_bit; sbit LCD_D7_Direction at TRISB3_bit; // End LCD module connections const unsigned short TEMP_RESOLUTION = 9; char *text = "000.0000"; unsigned temp; void Display_Temperature(unsigned int temp2write) { const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8; char temp_whole; unsigned int temp_fraction; // check if temperature is negative if (temp2write & 0x8000) { text[0] = '-'; temp2write = ~temp2write + 1; } // extract temp_whole temp_whole = temp2write >> RES_SHIFT ; // convert temp_whole to characters if (temp_whole/100) text[0] = temp_whole/100 + 48; else text[0] = '0'; text[1] = (temp_whole/10)%10 + 48; // Extract tens digit text[2] = temp_whole%10 + 48; // Extract ones digit // extract temp_fraction and convert it to unsigned int temp_fraction = temp2write << (4-RES_SHIFT); temp_fraction &= 0x000F; temp_fraction *= 625; // convert temp_fraction to characters text[4] = temp_fraction/1000 + 48; text[5] = (temp_fraction/100)%10 + 48; text[6] = (temp_fraction/10)%10 + 48; text[7] = temp_fraction%10 + 48; // Display temperature on LCD Lcd_Out(2, 5, text); } void main() { ANSEL = 0; // Configure AN pins as digital I/O ANSELH = 0; C1ON_bit = 0; // Disable comparators C2ON_bit = 0; Lcd_Init(); // Initialize LCD Lcd_Cmd(_LCD_CLEAR); // Clear LCD

// // // //

Extract Extract Extract Extract

thousands digit hundreds digit tens digit ones digit

Lcd_Cmd(_LCD_CURSOR_OFF); // Turn the cursor off Lcd_Out(1, 1, " Temperature: "); // Print degree character, 'C' for Centigrades Lcd_Chr(2,13,223); // different LCD displays have different char code for // degree // if you see greek alpha letter try typing 178 instead of 223 Lcd_Chr(2,14,'C'); //--- main loop do { //--- perform temperature reading Ow_Reset(&PORTE, 2); // Onewire reset Ow_Write(&PORTE, 2, 0xCC); // Issue command Ow_Write(&PORTE, 2, 0x44); // Issue command Delay_us(120); Ow_Reset(&PORTE, 2); Ow_Write(&PORTE, 2, 0xCC); // Issue command Ow_Write(&PORTE, 2, 0xBE); // Issue command temp = Ow_Read(&PORTE, 2); temp = (Ow_Read(&PORTE, 2) << 8) + temp; //--- Format and display result on Lcd Display_Temperature(temp); Delay_ms(500); } while (1); }

signal SKIP_ROM CONVERT_T

SKIP_ROM READ_SCRATCHPAD

Vous aimerez peut-être aussi