Sari la conținut
ELFORUM - Forumul electronistilor

Voltmetru/Ampermetru cu PIC 16F877A


Postări Recomandate

Ca sa micsorezi rezolutia, comenteaza linia 74:

//          LCD_Chr_CP(48+ch);               // write ASCII digit at cursor point
Am reusit sa recompilez codul. Mai vedem maine daca mai ai nevoie (da' nu vad de ce nu te-ai descurca singur).
Cum sa comentez linia 74? :nas: NU am habar de programare si termenii folositi, comentarii si alte chestii.Asa cum am spus, programarea este mai grea decat chineza pentru mine, deocamdata. :rade: Incerc totusi ce mi-ai explicat cu delay. Cu comentarea liniei 74, ... nu cred, sunt "praf" la articolul asta [programare]. :jytuiyu
Link spre comentariu

E gata "pregatita" in postul meu anterior. :ras: Te uiti la linia 74 in fisierul Multimetru.c si o faci sa semene cu ce am scrie eu mai sus (ii scrii // la inceput). :da

Ok. Acum am scris hexul compilat, in PIC, cu DELAY activat, fara // in fata. La urma modific si fac si modificarea liniei 74. :da Deocamdata sa testez cu delay activat. Daca nu merge bine, il dezactivez iar cu // in fata ?Mersi.P.S.Nasol este ca nu am prevazut pe cablaj pini pentru ICSP, :bataie trebuie sa lipesc/dezlipesc fire acum. :rade:
Link spre comentariu

S-ar putea ca cele 50 ms sa fie inca prea "scurte" si sa nu vezi mare diferenta.Eu as mai incerca si cu 100..200 ms inainte sa renunt.Si da, daca ti se pare ca n-ajuta la nimic, poti "dezactiva" (comenta) la loc Delay_ms() scriindu-i cele doua slashuri in fata.

Am testat cu 150 , parca este ceva mai multumitor, acum modific la 250 sa vad randamentul.Apoi si cu linia 74 [la mine e pe 73 ce ai scris tu] am sa pun cele // in fata. :da Dupa compilare, scrisurile de la inceput, sursa reglabila si by GeoMar, s-au deplasat cu 2 digiti mai la dreapta, cum fac sa-l dau la loc? NU am umblat la el deloc.Greu cu programarea asta. :sparge:
Link spre comentariu

Daca se mai doreste reprogramare o sa fac un hex cu programul asa cum era la inceput , dar cu o rezolutie de 14-15 biti, daca nici asa nu o sa apara frumos cifrele pe lcd atunci problema se trage de la lcd (are u timp de raspuns mare si refreshul se face greu) sau de la intrare in adc (este galagioasa si variaza tensiunile).Eu cu un amarit de 16F76 am ridicat rezolutia adc de la 8 bit la 12 bit si se afiseaza frumos valorile pe ecran ...

Link spre comentariu

Si mie mi se mai intampla ca dupa reprogramari s-o ia LCDul razna, da' isi revine dupa ce dezalimentez/realimentez montajul.

Si daca n-ai modificat nimic in functia ar2r.h, atunci si la tine LCD-ul a luat-o razna, pentru ca in functia mentionata sunt date pozitiile de inceput pentru cele 2 linii:

Prima linie de text e afisata incepand cu coloana 4

LCD_Out(1,4,text);                       // print string a on LCD, 1st row, 4th column
iar a doua cu coloana 8.

LCD_Out(2,8,text);                       // print string a on LCD, 2nd row, 8th column
Daca dezalimentezi si realimentezi si problema ramane, poti incerca sa modifici cele doua linii in fisierul Ar2r.h (de ex. prima in LCD_Out(1,2,text); ) pana ajungi la rezulattul dorit.

 

Da' m-am uitat acum in poza din primul post si vad ca scrisul incepe din pozitiile 2 si 5 (cred) nu din 4 si 8 cum e scris in programul pe care l-ai postat.

Daca programul cu care te joci acum e cel postat, atunci cumva-cumva ai modificat pozitiile astea de inceput si trebuie sa le faci la loc, asa cum ti-am explicat mai sus (adica nu e LCD-ul de vina, ci programul).

 

@noob64: sunt sanse ca oversampingul pe care-l propui sa ajute in cazul de fata, da' nu din cauza de lipsa de rezolutie, ci din cauza ca esantionarile/citirile repetate ale ADC-ului sunt echivalente unor intarzieri (delayuri) inserate pe parcurs.

Link spre comentariu

Delay_ms(50);                        // Waits 50ms
Am crescut la delay la 1000 :rade: si merge destul de acceptabil.
Delay_ms(1000);                    // Waits 1000ms
Stiu ca este mult 1 sec, timp de refresh mare, dar am timp sa citesc valoarea ultimului digit inainte sa se schimbe. Oscileaza destul de "frumos" intre cele doua valori.Probabil este si LCD-ul cu timp de raspuns mare. :nas: Am rezolvat si problema scrisului de la inceput.Cum as putea, asa cum a scris @nooob64, sa maresc rezolutia? Sa nu mai "sara" in pasi de 0,03, sa mearga cu 0,01 ? Unde trebuie sa modific ?Pe aici cumva?
u=u/1023;                            // 0..1023 -> 0-3500mV
Pentru moment este bine.Mai incerc cate ceva pe ici, pe colo, ca sa ma obisnuiesc si eu cu programarea asta.Oricum multumesc tuturor pentru ajutor. :aplauzeP.S.Sper sa nu-l stric de tot, oricum imi opresc o copie de rezerva a fisierelor din hex-source, asa cum sunt acum.P.P.S.Se poate implementa in program o linie de comanda, care atunci cand iesirea sursei reglabile este in scurt, sau nu este conectata la intrarea voltmetrului [adica voltmetru/ampermetru indica 0,00 la V,A,W si infinit la Ohmi] cifrele de pe LCD sa clipeasaca intr-un ritm de 1-2 sec?Este mai usor de remarcat asa, cand sursa este in scurt.
Link spre comentariu

Felicitari pentru succesele de pana acum! :da

Discutia cu rezolutia e mai lunga, n-am acum prea mult timp, asa ca incerc cateva idei.

1. La tine acel 0.0(0)3 e destul de aproximativ. Ca sa ai chiar 3 mV/LSB, ar trebui ca la "cap de scala" sa ai 3*1023 = 3069mV, nu 3500 cum ai acum. In conditiile de acum, indicatiile ar trebui sa fie mai mici decat tensiunea reala. Adica pe pinul Vref+ ar trebui sa ai 3.069 V. Si pentru ca asta e o valoare teoretica, cu circuite ideale fara tolerante, ar trebui sa masori cateva tensiuni cunoscute si sa ajustezi valoarea asta pana da ce trebuie.

Ca sa ajungi la 1 mV/LSB, ar trebui fie sa pui Vref+ 1023 mV, fie sa amplifici semnalul masurat de 3 ori, da' cred ca se mai schimba si altele prin schema.

2. Ce propune nooob64 pentru a mari rezolutia se cheama oversampling (mai multe in linkul pe care l-am postat mai sus), da' dupa parerea mea el, folosind functiile standard ale mikroC, o implementeaza gresit.

In mod normal ar trebui ca cele 256 de masuratori pe care le face el sa aiba loc in intervalul in care uChip zice ca se face o singura masuratoare completa.

Dupa parerea mea (sau daca as face eu o functie de biblioteca, asa cum e read_ADC-ul ala de la mikroC), functia aia ar trebui sa functioneze conform specificatiilor uChip, adica sa aiba un delay inautru, care delay sa asigure timpul de incarcare al condensatorului hold in functie de oscilatorul folosit. Daca asa e, atunci cele 256 de masuratori ale lui nooob64 nu sunt oversampling (crestere de rezolutie), ci o mediere a 256 de masuratori normale. Se obtine o masuratoare mai stabila (si de-aia la el nu flutura asa tare LCD-ul), da' nu creste rezolutia. Si introduce o intarziere care si ea ajuta LCD sa functioneze normal.

Link spre comentariu

Pentru Liviu M , din cite stiu eu functia de la MikroC face citirile cum trebuie . Aceasta crestere de rezolutie se face prin acele citiri multiple intr-un timp cit mai scurt apoi se face media si rezulta o rezolutie mai mare . Valorile care le obtin sunt stabile iar valorile variaza cu 0.01 V verificat cu multimetrul.

http://i41.tinypic.com/33zfwir.jpg

 

* Copyright:     (c) Ar2r, 2008. * Description:     Uses ADC x2 (A0 & A1) chanels I & U result in range of 0-3500 mV     Vref=3,5V. It calculates Power & Resistance from U & I     and displays results on LCDx2row. Also sends value of U & I on     serial port. * Test configuration:     MCU:             PIC16F877     Oscillator:      HS, 11.059200 MHz     Ext. Modules:    LCD     SW:              mikroC v8.2 * NOTES:     None.*/unsigned char ch;unsigned int Napon_rd, Struja_rd,i=0;long u, power, res,aux;#include "Ar2r.h"void main(){  INTCON = 0;                              // Disable all interrupts  Usart_Init(19200);                       // Initialize USART module (8 bit, 38400 baud rate, no parity)                                           // (I think this is bug in MikroC, Init is on 19200 but it                                           // actualy works at speed 38400)    Lcd_Init(&PORTB);                        // Lcd_Init, see Autocomplete  LCD_Cmd(LCD_CURSOR_OFF);                 // send command to LCD (cursor off)  Ar2r();                                  // Show splash screen   LCD_Cmd(LCD_CLEAR);                      // send command  to LCD (clear LCD)  ADCON1     = 0x88;                       // configure Vref, and analog channels  TRISA      = 0xFF;                       // designate PORTA as input  while (1)    {      while(i<256)    //4x4x4x4 .... se mareste odata cu numarul de biti doriti      {             aux = aux + ADC_read(1);             i++;      }   Napon_rd = aux/16;    //2x2x2x2 .... se mareste odata cu numarul de biti doritiaux=0; // se pune variabila auxiliara pe 0 dupa calcule si atribuiri //     Napon_rd=ADC_read(1);                // nu mai avem nevoie de linia asta .... get ADC value for U from channel 1      u=(long)Napon_rd*3500;               // covert adc reading to milivolts      u=u/16368;                            // daca avem 10 bit adc (nativ) si "marim" cu 4 bit se face calcul:                                                 // 1023 x 2x2x2x2 .... in functie de adc-ul nativ si de cite ori il "marim"      ch=u/1000;                           // extract 10.00 U digit      Usart_Write(48+ch);                  // write ASCII digit on serial port      if (ch==0)        {          LCD_Chr(1,2, 32);                // write empty space if digit is 0        }      else        {          LCD_Chr(1,2,48+ch);              // write ASCII digit at 1st row, 2nd column        }      ch=(u/100) %10;                      // extract 01.00 U digit      Usart_Write(48+ch);                  // write ASCII digit on serial port      LCD_Chr_CP(48+ch);                   // write ASCII digit at cursor point      LCD_Chr_CP('.');                     // write '.' at cursor point      Usart_Write(',');                    // write ',' on serial port      ch=(u/10) %10;                       // extract 00.10 U digit      Usart_Write(48+ch);                  // write ASCII digit on serial port      LCD_Chr_CP(48+ch);                   // write ASCII digit at cursor point      ch=u %10;                            // extract 00.01 U digit      Usart_Write(48+ch);                  // write ASCII digit on serial port      //if (Button(&PORTD, 1, 1, 0))         // read jumper 2 ON/OFF for last digit of U        {          LCD_Chr_CP(48+ch);               // write ASCII digit at cursor point        }      //else        {          //LCD_Chr_CP(32);                  // write empty space at cursor point        }      LCD_Chr_CP('V');                     // write 'V' at cursor point      Usart_Write('V');                    // write 'V' on serial port      Usart_Write('\n');                   // write '\n' on serial port      // Curent      Struja_rd=ADC_read(0);               // get ADC value for I from channel 0      i=(long)Struja_rd*3500;              // covert adc reading to milivolts      i=i/1023;                            // 0..1023 -> 0-3500mV      ch=i/1000;                           // extract 1.000 I digit      Usart_Write(48+ch);                  // write ASCII digit on serial port      LCD_Chr(1,10,48+ch);                 // write ASCII digit at 1st row, 10th column      LCD_Chr_CP('.');                     // write '.' at cursor point      Usart_Write(',');                    // write ',' on serial port      ch=(i/100) %10;                      // extract 0.100 I digit      Usart_Write(48+ch);                  // write ASCII digit on serial port      LCD_Chr_CP(48+ch);                   // write ASCII digit at cursor point      ch=(i/10) %10;                       // extract 0.010 I digit      Usart_Write(48+ch);                  // write ASCII digit on serial port      LCD_Chr_CP(48+ch);                   // write ASCII digit at cursor point      ch=i %10;                            // extract 0.001 I digit      Usart_Write(48+ch);                  // write ASCII digit on serial port      //if (Button(&PORTD, 0, 1, 0))         // read jumper 1 ON/OFF for last digit of I        {          LCD_Chr_CP(48+ch);               // write ASCII digit at cursor point        }      //else        {          //LCD_Chr_CP(32);                  // write empty space at cursor point        }      LCD_Chr_CP('A');                     // write 'A' at cursor point      Usart_Write('A');                    // write 'A' on serial port      Usart_Write('\n');                   // write '\n' on serial port      //Power Calculation      power=u*i/1000;      ch=power/1000;                       // extract 10.00 P digit      if (ch==0)        {          LCD_Chr(2,2, 32);                // write empty space if digit is 0        }      else        {          LCD_Chr(2,2,48+ch);              // write ASCII digit at 2nd row, 2nd column        }      ch=(power/100) %10;                  // extract 01.00 P digit      LCD_Chr_CP(48+ch);                   // write ASCII digit at cursor point      LCD_Chr_CP('.');                     // write '.' at cursor point      ch=(power/10) %10;                   // extract 0.10 P digit      LCD_Chr_CP(48+ch);                   // write ASCII digit at cursor point      ch=power %10;                        // extract 0.01 P digit      LCD_Chr_CP(48+ch);                   // write ASCII digit at cursor point      LCD_Chr_CP('W');                     // write 'W' at cursor point      // Resistance Calculation      if(power==0)        {          LCD_Out(2,10,"  ");              // write empty space          LCD_Chr_CP(243);                 // write 'infinity' at cursor point          LCD_Out(2,13,"  ");              // write empty space          LCD_Chr_CP(244);                 // write 'ohm' at cursor point        }      else        {          res=u*100/i;          if(res>=10000)            {              LCD_Out(2,10," > 1K");       // write " > 1K"              LCD_Chr_CP(244);             // write 'ohm' at cursor point            }          else            {              ch=res/1000;                 // extract 100.0 R digit              if (ch==0)                {                  LCD_Chr(2,10, 32);       // write empty space if digit is 0                }              else                {                  LCD_Chr(2,10,48+ch);     // write ASCII digit at 2nd row, 10th column                }              ch=(res/100) %10;            // extract 010.0 R digit              if (ch==0 && res<=99)                {                  LCD_Chr_CP(32);          // write empty space if digit is 0                }              else                {                  LCD_Chr_CP(48+ch);       // write ASCII digit at cursor point                }              ch=(res/10) %10;             // extract 001.0 R digit              LCD_Chr_CP(48+ch);           // write ASCII digit at cursor point              LCD_Chr_CP('.');             // write '.' at cursor point              ch=res %10;                  // extract 000.1 R digit              LCD_Chr_CP(48+ch);           // write ASCII digit at cursor point              LCD_Chr_CP(244);             // write 'ohm' at cursor point            }        }      //Delay_ms(50);                        // Waits 50ms  }}
Link spre comentariu

Eu n-am zis ca functia din mikroC nu functioneaza corect, am zis ca nu poate fi folosita la oversampling (e prea lenesa pentru un oversamplig "de 4 biti"). Ca sa te convingi ca asa e, vezi in simulator cat dureazao citire din ADC. Daca e mai lunga decat TAD (vezi in data sheet cat e TAD pentru frecventa la care lucrezi), atunci nu poti face oversamplingul. Daca dureaza de 256 de ori mai putin decat TAD, atunci da, poti face oversampling "de 4 biti". Daca e mai mica da' mai putin, poti calcula "de cati biti poti" poti face oversampling (cati biti poti castiga).Referitor la rezolutia ta, comparatia cu masuratorile facute cu un multimetru cu 2 digiti dupa virgula e irelevanta; rezolutia astuia e prea slaba ca sa poata fi luata drept etalon.Nu de alta, da' rezolutia teoretica pe care o obtii tu (daca chiar iti reuseste oversamplingul ala de 4 biti) e 3500 mV/2^14 ~= 213 uV. Pe asta nu poti s-o verifici decat cu un aparat care "poate" si el macar atat si care, in plus, mai e si bine calibrat.Pe de alta parte, rezolutia implicita, folosind ADC-ul pe 10 biti, e de ~ 3 mV. Asta e cam in acelasi domeniu de rezolutie cu un multimetru de buzunar pe scala de 2V; pe astea le poti compara.

Link spre comentariu

Se poate implementa in program o linie de comanda, care atunci cand iesirea sursei reglabile este in scurt, sau nu este conectata la intrarea voltmetrului [adica voltmetru/ampermetru indica 0,00 la V,A,W si infinit la Ohmi] cifrele de pe LCD sa clipeasaca intr-un ritm de 1-2 sec?Este mai usor de remarcat asa, cand sursa este in scurt.

Chestia asta cu clipitul LCD-ului, se poate introduce in program?Daca vreau sa mai introduc un "splash screen" dupa cel cu "Sursa reglabila" ce trebuie sa fac? :scarpin Fac alt fisier cu scrisul ce vreau sa apara?Cum il introduc in program? :nas: Daca tot ce am scris este posibil, explicati, asta ca sa mai invat si eu cate ceva, daca se poate. :pandaci
Link spre comentariu

In general e valabil cum spune Liviu M , dar daca e pina acolo oversampling-ul acesta nu face decit o stabilizare a valorii si o "marire" a rezolutiei cu maxim 3-4 biti , apoi dureaza prea mult si asanumita "rezolutia" nu mai creste decit se stabilizeaza .

Mi-am amintit ca atunci cind am testat eu chestia cu "marirea rezolutiei" vroiam sa maresc plaja de afisare a tensiunii citite dar sa am si o rezolutie mai buna ... cum ar fii fost sa amsor de la 1-30V cu 256 pasi , asa am "marit" rezolutia si am obtinut 4095 pasi , iar microcontrolerul afisa corect.

La inceput credeam ca Liviu M spune prostii , apoi mi-am adus aminte ce am facut mai demult ... :nebunrau:

Link spre comentariu

Am rezolvat cu al 2-lea splash screen si clipitul afisajului.Vreau sa "modernizez" acest proiect prin introducerea in programul PIC-ului, a unor functii care sa protejeze sursa de scurtcircuit [tot mai este "loc" in programul ptr pic]As vrea ca atunci cand este in scurt sursa [0V la iesire si afisat], PIC-ul sa-mi trimita un ton de 1khz [cu pauze de 1 sec] pe pinul 34, unde voi conecta un buzzer piezo, iar dupa 10-15 sec [daca se mentine scurtul] un pin al PIC-ului [33] sa treaca pe nivel 1, sa pot actiona un releu care deconecteaza iesirea sursei [eliminarea scurtului].Vreau sa introduc in codul C, o comanda de sound_init si sound_play si nu ma pricep, apoi si cea de "timer" [cred] care trece pinul 33 in nivel 1.Daca cineva ma poate ajuta sa modific in MicroC codul, adica sa scriu liniile necesare, apoi sa-l compilez sa obtin hexul, eu nu le am cu programarea, dar sub indrumarea cuiva cred ca reusesc.Multumesc anticipat pentru un eventual ajutor.

Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum
×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări