Astabil cu led-uri folosind microcontroller PIC16F876 si ARDUINO
In urma unor discutii cu un client mi-am propus sa caut o schema pentru programarea microcontroller-elor PIC din familia 16Fxxx pentru cei care construiesc montaje cu microcontrollere PIC16Fxxx si nu au cu ce sa le programeze.
Pentru a putea construi un programator pentru uC PIC avem nevoie de circuitul integrat MAX232 sau echivalent ce asigura interfatarea dintre portul serial al PC-ului si microcontroller.
Pe langa MAX 232 avem nevoie de urmatoarele tensiuni ( alimentari ) pentru a aduce uC-ul in starea de programare:
Cu ajutorul acestei aplicatii ( proiect ) vom utiliza convertorul analog-digital al microcontroller-ului PIC16F887 ( in general al oricarui tip de microcontroller ).
Ca senzor de temperatura folosesc LM35 ( ieftin si se gasesc oriunde ) ( datasheet ). Acest senzor va scoate pe iesire o tensiune proportionala cu temperatura, iar gama de masurare a temperaturii este: -55 – 150 grade Celsius. Pentru mai multe detalii consultati datasheet-ul .
Pentru afisearea temperaturii vom folosi un display LCD 2×16 ( doua randuri a cate 16 caractere ).
Inainte de a incepe trebuie sa facem o scurta ( foarte scurta ) introducere in ceea ce inseamna convertorul analog-digital ( ADC ).
-un ADC este un circuit electronic care converteste o marime analogica ( tensiune, curent,…etc ) de intrare intr-o marime digitala de iesire.
O caracteristica importanta a unui ADC este rezolutia acestuia, adica numarul de valori pe care poate sa-l furnizeze convertorul la iesirea sa in intervalul de masura. Lucrand cu date binare , rezolutia se va masura in biti.
Ex: daca rezolutia ADC-ului este pe 10 biti, convertorul poate furniza 1024 valori diferite la iesire.
Sa facem cateva calcule pe exemplul nostru:
Consideram temperatura ambientala 25,5 grade C si stim ca iesirea lui LM35 se modifica cu 10mV /grad C, in aceste conditii va rezulta ca pentru o temperatura de 25,5 tensiunea pe iesirea senzorului ( LM35 ) va fi:
25,5 * 10mV = 255mV=0,255V.
Cunoscand aceasta tensiune putem sa calculam ce valoare va avea ADC-ul la iesire astfel:
VALadc = 0,255 V / 0,004882 V = 52,22950.
Dupa ce am calculat VALadc putem sa calculam si tempratura :
Temp = VALadc *ADCrez (V) / 10 (mV/C ) = 52,22950 * 0,004882 (V) / 0,01 ( V/C ) = 25,5 C
Stiind toate acestea formula Temp va fi folosita si in programul nostru pentru microcontroller.
Schema proiectului :
Codul sursa:
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;
char message1[] = „Temperatura:”;
char tempC[15];
unsigned int tempinC;
float temp_value=0;
void main()
{
ANSEL = 0x04; // Selectare port AN2 ca fiind analog
ADCON1=0X80;
TRISA = 0x04;
ANSELH=0;
Lcd_Init();
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
Lcd_Out(1,1,message1);
Lcd_Chr(2,6,223);
Lcd_Chr(2,15,223);
Lcd_Chr(2,7,’C’);
do {
tempinC = ADC_Read(2);
temp_value = tempinC*0.4882; // formula de calcul a temperaturii
FloatToStr(temp_value,tempC); // conversia in char a valorii lui temp_value
Lcd_Out(2, 1, tempC);
Delay_ms(1000);
} while(1);
}
Un mic filmulet demonstrativ:
In articolul „Aplicatii cu led-uri folosind PIC16F877 partea I” v-am explicat cum putem sa ne jucam cu led-urile implicit si cu porturile microcontroller-ului. In articolul de azi vom vedea cum ne „jucam” cu butoane si anume vom conecta 3 butoane la microcontoler si cate 8 led-uri la porturile B, C, D. Butoanele vor fi conectate la portul A pinii RA1, RA2, RA3.
La apasarea butonului conecat la pinul RA1 se vor aplrinde led-urile de la portul B, la apasarea butonului conectat la pinul RA2 se vor aprinde led-urile de la portul C si la apasarea butonului conectat la pinul RA3 se vor aprinde led-urile de la portul C.
Mai jos va prezint schema electronica realizata in proteus, unde am facut si simularea:
Pe schema: butonul B1 este conectat la pinul RA1 –- la apasarea lui se vor aprinde ledurile de la portul B
butornul B2 este conectat la pinul RA2 –- la apasarea lui se vor aprinde led-urile de la portul C;
butonul B3 este conecat la pinul RA3 –- la apasarea lui se vor aprinde led-urile de la portul D.
In continuare va afisez codul sursa a programului:
bit stareB,stareC,stareD;
void main() {
ANSEL = 0; // Configureaza pinii AN ca fiind digitali
ANSELH = 0;
C1ON_bit = 0; // Dezactiveaza comparatoarele
C2ON_bit = 0;
TRISA1_bit=1;
TRISA2_bit=1; // seteaza pinii RA1,RA2,RA3 ca fiind de intrare
TRISA3_bit=1;
TRISB = 0;
TRISC = 0;
TRISD = 0; // Configurare PORTC ca iesire
PORTB = 0;
PORTC = 0;
PORTD = 0; // valoarea Initiala a PORTx
stareB = 0;
stareC = 0;
stareD=0;
while(1) {
if (Button(&PORTA,1,0,1)) { PORTB=0xFF;
stareB = 1;
}
if (stareB&&Button(&PORTA, 1, 0, 0)) {
PORTB=0x00;
stareB=0;
}
if (Button(&PORTA,2,0,1)) {
PORTC=0xFF;
stareC=1;
}
if (stareC&&Button(&PORTA, 2, 0, 0)) {
PORTC =0x00;
stareC=0;
}
if (Button(&PORTA,3,1,1)) {
PORTD=0xFF;
stareD=1;
}
if (stareD&&Button(&PORTA,3,1,0)) {
PORTD=0x00;
stareD=0;
}
}
}
In program a aparut functia Button() care are urmatoarea structura:
unsigned short Button(unsigned short *port, unsigned short pin, unsigned short time, unsigned short active_state);
unde: unsigned short *port : portul la care este conectat butonul;
unsigned short pin : pinul la care este conectat butonul;
unsigned short time : intarzierea la apasarea butonului in milisecunde;
unsigned shortactive_state : starea butonului apasat/neapasat ( 1/0 );
if(Button(&PORTA,1,0,1)) : daca butonul conecat la portul a ( PORTA ) pinul 1 (RA1) cu intarzierea 0 este apsat (1) executa ceva.
Desi pe tot internetul gasim aceleasi aplicatii cu led-uri ( aprinderea unui led, led-ul care palpaie,etc….) si eu voi prezenta in continuare cateva aplicatii cu led-uri.
Cu ajutorul acestor aplicatii un INCEPATOR invata sa foloseasca microcontroller-ul, sa inteleaga cum se folosec porturile lui, cum ne ‘jucam” cu ele, etc…, de aceea cine stie deja lucrurile acestea il rog sa nu ma „injure” si sa aiba rabdare ca voi posta si proiecte mai complicate.
Pornind de la schema urmatoare:
dorim sa facem ca ledurile D1,D2,..D8 sa se aprinda pe rand ( adica D1–D2–D3–D4–….–D8 api D8–D7–D6–….–D1).
Vom lucra in mediul „MikroC for PIC” produs de mikroelektronika, iar ca placa de dezvoltare folosesc un EasyPIC6 produs tot de mikroelektronika.
Scrieu mai jos programul apoi il voi explica:
void main()
{
int i;
ANSEL=0; //configuram pinii microcontrollerului ca fiind digitali
ANSELH=0;
TRISB=0x00; //configuram portul B ca fiind un port de iesire
PORTB=0x00000001; // ii dam pinului RB0 de la portul B valoarea 1
while(1)
{
for(i=0;i<7;i–>
{
PORTB=PORTB<<1 // mutam la stanga cu o pozitie acel 1 din valoarea initiala a lui PORTB
Delay_ms(1000); // pana ajunge la pinul RB7
}
for(i=6;i>=0;i–)
{
PORTB=PORTB>>1;
Delay_ms(1000);
}
}
}
TRISB : cu ajutorul acestui registru facem ca pinii de la portul B sa fiie pini de iesire sau de intrare. Daca ii facem de iesire atuncii microcontrollerul va scoate semnal din microntroller catre ceva iar daca este de intrare atunci microcontrollerul asteapta sa primeasca semnale de la ceva. In cazul nostru TRISB=0x00 adica de iesire.
PORTB: acest registru ne ajuta sa dam la fiecare pin al portului ce semnal vrem noi sa iasa. In cazul nostru PORTB=0x00000001, pinul RB0=1,RB1=0,RB2=0,….,RB7=0 adica pe pinul RB0 va iesi 1 logic (5v) si va cauza aprinderea led-ului D1.
PORTB=PORTB<<1 : semnul „<<” inseamna shift la stanga cu o unitate (casuta). Spre exemplu avem cazul nostru ,unde initial PORTB=0x00000001 iar apopi noi il shift-am (mutam) pe 1 de la sfarsit cu o casuta catre stanga de sase (6) ori: pt. i =0 avem PORTB=0x00000010; pt i=1 avem PORTB=00000100; si asa mai departe pana cand PORTB=0x10000000. Binenteles ca intre aceste mutari se executa si instructiunea Delay_ms(1000) care inseamna : asteapta ( intarzie continuarea executarii ) o secunda. Cand PORTB=0x10000000 atunci programul va executa urmatoul for ( for(i=6;i>=0;i–) ) si va shift-a ( muta ) pe 1 spre dreapta cu o unitate ( casuta ) pana cand PORTB=0x00000001, si apoi se reia de la inceput ( de la primul for. Aceste doua for-uri fiind incluse intr-o intructiune WHILE(1) se vor executa la infinit.
Acestea fiind spuse in continuare voi pune un filmulet in care este explicat si exemplificat practic
Filmulet prezentare aplicatie + simulare in Proteus: