Digitalni V-m. Merjenje napetosti na fotouporu in prikaz na LCD-ju

Izdelali bomo digitalni voltmeter, ki bo meril napetost na fotouporu LDR. Napetost na fotouporu, ta je odvisna od svetlobe, ki ji je fotoupor izpostavljen, naj se prikazuje na LCD displayu. Če je napetost na fotouporu večja od 2,5 V, se mora vklopiti razsvetljava, v našem primeru LED dioda.

Za izdelavo naloge bomo uporabili ADC - analogno digitalni pretvornik mikrokontrolerja PIC16f877a.

Slika 1: Mikrokontroler PIC16f877a, priključki (vir: https://www.theengineeringprojects.com/wp-content/uploads/2017/06/PIC16F877a.jpg)


Napetost ki se bo spreminjala na fotouporu, se bo spreminjala tudi na pinu RA0/AN0. Ostale elemente, LCD zaslon, tipko reset, kristalni oscilator (4 MHz) in druge elemente pa bomo priključili na mikrokontroler PIC16f877a kot prikazuje načrt (slika 2).

Slika 2: Priklop elementov na mikrokontroler PIC16f877a

ADC oziroma analogno digitalna pretvorba je opisana v prejšnjem poglavju in je tukaj ne bomo ponavljali. Izbrali bomo taki način delovanja, da bo spodnja vrednost referenčne analogne napetosti 0 V (Vss), zgornja vrednost referenčne analogne napetosti pa 5 V (Vdd), to je napetost napajanja mikrokontrolerja. Ker želimo dokaj točne rezultate, izmerimo kakšna je ta napetost. Vezje napetostno napajamo prek USB priključka s programatorjem PICkit 2. Z meritvijo sem ugotovil, da v mojem primeru napetost znaša Vdd = 4,68 V.

Mikrokontroler PIC16f877a vsebuje 10-bitni, 8 kanalni ADC. To pomeni, da bo imela izhodna vrednost ADC ločljivost od 0 - 1023 (210 – 1 = 1023). Najmanjša vrednost spremembe analogne napetosti, ki jo 10-bitni ADC zazna je v mojem primeru 4,68 V/1023 = 0,0045747 V oz. 4,5747 mV.

Program za digitalni V-m:

 /*

  Merjenje napetosti na fotouporu LDR in prikaz na LCD zaslonu.

  Vklop razsvetljave (LED diode), če je napetost na fotouporu večja od 2,5 V.

  Okolje MPLAB IDE v8.92, HI_TECH compiler for PIC10/12/16 MCUs V9.82, oscilator 4 MHz.

  Avtor: Milan Ivič, jan. 2018.

*/

    #include <htc.h>

    #include <pic.h>

    #include <math.h>

 //Definiranje priključnih pinov za LCD:

    #define RS RB1

    #define EN RB3

    #define D4 RB4

    #define D5 RB5

    #define D6 RB6

    #define D7 RB7

    #define _XTAL_FREQ 4000000

    __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_ON & CP_OFF & BOREN_ON & LVP_OFF);

    #include "lcd.h"           //Vključitev header (zaglavne) datoteke lcd.h

    unsigned int ADC_vrednost=0;        //V spremenljivko se bo shranjeval rezultat AD pretvorbe

    unsigned int digit1, digit2, digit3;      //Spremenljivke tipa int za prikaz napetosti na dve decimalki natančno

 void ADC_Init()

 {

    ADCON0 = 0b10000001;                //AD pretvorba je omogočena, časovni takt za pretvorbo je 32*Tosc

    ADCON1 = 0b10001110;                 //RA0/AN0 je analogni, vsi ostali so digitalni. Vref+ = Vdd, Vref- = Vss

 }

 unsigned int ADC_beri(unsigned char kanal)

 {

    if(kanal > 0)                            //Zanima nas signal na AN0 (na kanalu 0)

    {

        return 0;

    }

    ADCON0 &= 0b11000101;                //Nastavitev ustreznih bitov registra ADCON0

    ADCON1 = 0b10001110;                 //Izbira analognega vhoda AN0 in izbira desne poravnave rezultata 

    __delay_ms(3);                       //Čas potreben za polnjenje kondenzatorja (dokumentacija za PIC16f877a)

    GO_nDONE = 1;

    while(GO_nDONE);

    return ((ADRESH<<8)|ADRESL);       //Vrni se iz funkcije z rezultatom AD pretvorbe (10-bitni rezultat)

 }

 void main()

 {

    TRISB = 0x00;                        //Vsi pini na PORTB so izkodni

    TRISA = 0xFF;                        //Vsi pini na PORTA so vhodni

    TRISD = 0x00;                        //Vsi pini na PORTD so izkodni

    LCD4bitni_Init();                    //Za komunikacijo z LCD-jem uporabimo zaglavno datoteko (header file) lcd.h

    LCD4bitni_Clear();

    LCD4bitni_Set_Cursor(1,0);

    LCD4bitni_Pisi_niz("Napetost na LDR:");

    LCD4bitni_Set_Cursor(2,7);

    LCD4bitni_Pisi_niz("V");

    ADC_Init();                   //Klicanje funkcije za inicializacijo AD pretvorbe

    do

    {        

        ADC_vrednost = ADC_beri(0);                    //Klicanje funkcije za branje in AD pretvorbo signala na AN0 (RA1/AN0)

 //Pretvorba 10-bitnega podatka v napetost na dve decimalki natančno:

        ADC_vrednost = (ADC_vrednost*4.68/1024)*100;

        digit1 = (ADC_vrednost/100);

        digit2 = ((ADC_vrednost - digit1*100)/10);

        digit3 = (ADC_vrednost - (digit1*100+digit2*10));

        if(ADC_vrednost > 249)                  //Ali je napetost na fotouporu (RA0/AN0) večja od 2,5 V?

            RD0=1;

        else

            RD0=0;

        LCD4bitni_Set_Cursor(2,2);

        LCD4bitni_Pisi_znak(digit1+48);               //48 ASCII => znak 0 => Piši znak od številke 0 naprej.

        LCD4bitni_Pisi_znak(0x2E);                      //Izpis decimalne pike. ASCII hex. koda za decimalno piko.

        LCD4bitni_Pisi_znak(digit2+48);

        LCD4bitni_Pisi_znak(digit3+48);

        __delay_ms(500);

    }

    while(1);

 }

V projekt moramo vstaviti zaglavno datoteko lcd.h. Shranjena mora biti v mapi projekta. Najdete jo spodaj v prilogi.

Slika 3: Projekt z vključeno zaglavno datoteko lcd.h

Opis programske kode:

Ker ADC poznamo iz prejšnjega poglavja, se osredotočimo na izpis vrednosti napetosti na LCD display.

Za prikaz napetosti na dve decimalki natančno smo deklarirali tri spremenljivke tipa int, digit1 za cela števila, digit2 za desetinke in digit3 za stotinke:

    unsigned int digit1, digit2, digit3;

Iz funkcije ADC_beri(0) dobimo vrnjen rezultat AD pretvorbe analogne napetosti, ki je na pinu RA0/AN0 (napetost na fotouporu). Ta vrnjen rezultat je 10-bitni in je shranjen v spremenljivki ADC_vrednost. Spremeniti ga moramo v tako obliko, da bo na LCD-ju prikazoval vrednost napetosti na fotouporu. Najprej 10-bitni podatek pretvorimo v decimalno število, ki ustreza pretvorjeni analogni napetosti na RA0/AN0 in ga shranimo nazaj v spremenljivko ADC_vrednost:

Vzemimo primer, ko je napetost na fotouporu oz. na pinu RA0/AN0 vrednosti 2,46 V:

    ADC_vrednost = (537*4.68/1024)*100;

4,68 V => 1023

2,46 V =>  537

V spremenljivki ADC_vrednost bo po matematični operaciji shranjena vrednost 245 => (537*4,68/1024*100 = 245).

V spremenljivki ADC_vrednost bo shranjen celoštevilčni rezultat matematične operacije to je 245, saj je spremenljivka tipa int. Iz tega rezultata moramo priti do podatka 2,46 ki bo prikazan na LCD-ju.

    digit1 = (ADC_vrednost/100);

Če vrednost 245 delimo s 100 in rezultat shranimo v spremenljivko digit1 tipa int, dobi spremenljivka digit1 vrednost 2. (245/100 = 2,45. Ker je spremenljivka digit1 tipa int se vanjo shrani samo celoštevilčni rezultat, to je 2).

    digit2 = ((ADC_vrednost - digit1*100)/10);

V spremenljivki digit2 bo shranjen rezultat 4. ((245 - 2*100)/10 = (245 - 200)/10 = 45/10 = 4,5). Ker je spremenljivka digit2 tipa int se vanjo shrani samo celoštevilčni rezultat, to je 4.

    digit3 = (ADC_vrednost - (digit1*100+digit2*10));

V spremenljivki digit3 bo shranjen rezultat 5. ((245 - (2*100 + 4*10)) = (245 - (200 + 40) = 245 - 240 = 5).

V primeru, ko je napetost na fotouporu oz. na pinu RA0/AN0 vrednosti 2,46 V, bodo imele spremenljivke digit1, digit2 in digit3 naslednje vrednosti:

digit1 = 2

digit2 = 4

digit3 = 5

Napetost, prikazana na LCD displayu bo 2,45 V. Napaka med dejansko in prikazano napetostjo znaša 0,01 V.

Pri napetosti večji od 2,5 V se mora vklopiti LED dioda, priključena na pin RD0. Pri napetosti na fotouporu 2,5 V bo imela spremenljivka ADC_vrednost vrednost 249:

     ADC_vrednost = (546*4.68/1024)*100;

4,68 V => 1023

2,5 V   =>  546

ADC_vrednost = (546*4,68/1024*100 = 249) = 249.

Če je napetost na fotouporu oz. pinu RA0/AN0 večja od 2,5 V, bo vklopila LED dioda, če pa je manjša ali enaka 2,5 V bo LED dioda izklopila.