Sari la conținut
ELFORUM - Forumul electronistilor

Exemple si notiuni de baza => Incepator


Postări Recomandate

Salutari.

 

In intentia de a evolua si de a extinde putin jucaria de mai sus am zis sa adaug mai multe functii devreme ce tot are uC-ul ala atatea porturi si canale la dispozitie, acuma, evident ca unde citesti tensiune, pui si de-o citeala de corenti, si aici analizand codul sursa pe care mi l-a scris @Vlad Mihai la topicul cu voltampermetru de AICI, in principiu as sti ce am de facut, dar asta ar presupune sa modific niste linii mecanic, fara a intelege mare lucru despre unele principii, asta nu ma satisface astfel incat apelez din nou la bunavointa si timpul vostru pentru a-mi lamuri cateva chestii. Inainte de toate achizitia ADC pentru curent din acel cod:

//Curent          curent1=ADC_read(1);                // get ADC value for U from channel 1          Delay_ms(50);          curent2=ADC_read(1);                // get ADC value for U from channel 1          Delay_ms(50);          curent3=ADC_read(1);                // get ADC value for U from channel 1          Delay_ms(50);          curent4=ADC_read(1);                // get ADC value for U from channel 1          Delay_ms(50);          curent5=ADC_read(1);                // get ADC value for U from channel 1          Delay_ms(50);          curent6=ADC_read(1);                // get ADC value for U from channel 1          Delay_ms(50);          curent_medie=(curent1+curent2+curent3+curent4+curent5+curent6)/6;

Observ ca se fac mai multe citiri cu o anumita pauza intre ele si se extrage o medie, in cazul de fata 6 citiri cu 50mS intre ele, am observat ca @thunderer recomanda AICI chiar mai multe citiri ( 200 ), acuma inteleg ca asta se face pentru o afisare mai precisa a curentului pe ecran si pentru variatii mai mici ale valorii afisate, am dreptate? si daca da atunci gandesc ca totusi acest numar de citiri nu poate fi unul pur subiectiv, adica spre exemplu cazului cu pauza dintre citiri, nu cred ca pot fi prea multe pentru ca s-ar pierde din timpul de raspuns al afisarii, s-ar intarzia actualizarile ( sau s-ar rari, sau cum se mai zice... intelegeti sper la ce ma refer ) deci gandesc ca tre sa fie o logica aici, un soi de regula sau asa ceva, si eu nu o stiu... ma puteti lamuri cum este mai bine de facut?

 

Apoi avand in vedere faptul ca citiri multe ocupa si spatiu mult, am analizat putin propunerea lui @thunderer cu bucla for:

curent = 0 for i = 1 to 200 (de exemplu citesti 200 valori, nu te limitezi doar la 6)     curent = curent + adc_read(1)next icurent = curent / 200

Dar marturisesc ca nu am inteles prea bine ce-i de facut, adica stiu sintaxta acestei bucle pentru limbajul C, dar nu sunt sigur despre cum se poate aplica si solicit din nou ceva lamuriri.

 

Multumesc anticipat si o zi buna va doresc.

Link spre comentariu
  • Răspunsuri 102
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

Top autori în acest subiect

acuma inteleg ca asta se face pentru o afisare mai precisa a curentului pe ecran si pentru variatii mai mici ale valorii afisate, am dreptate?

Nu afisarea e principalul motiv al medierii, ci valoarea masurata. Cu cat mediezi mai multe valori, cu atat ai o masuratoare mai stabila (ne referim la masurari statice, in care prin medierea mai multor masuratori reduci influentele zgomotului). Stabilitatea afisarii e bonus.

si daca da atunci gandesc ca totusi acest numar de citiri nu poate fi unul pur subiectiv,

Ba de cele mai multe ori chiar asta e - un compromis intre viteza de masurare si stabilitate. Pe care compromis il asezi unde-ti ti se potriveste mai bine. Avantajul "lucrului facut de tine". :rade:

 

dar nu sunt sigur despre cum se poate aplica si solicit din nou ceva lamuriri.

 

Folosind o bucla for, codul de la Vlad poate fi transcris in:

   unsigned char ucIdx;   unsigned int iCurrent;      iCurrent=0;   for(ucIdx=0; ucIdx<6; ucIdx++) {           iCurrent +=ADC_read(1);   // get ADC value for U from channel 1          Delay_ms(50);  }    iCurrent = iCurrent / ucIdx;
Dupa cum vezi, am renuntat la variabilele curent2..curent6 nenecesare in cazul de fata si m-am asigurat ca iCurrent e suficient de mare sa incapa 6 masuratori in el (pentru cele 200 de masuratori ale lui thunderer ti-ar fi trebuit o variabila pe 32 de biti).

Cu alte cuvinte, buclele (for/while) sunt bune cand ai de facut operatii repetitive (sau usor de facut repetitive cu ajutorul unor algoritmi simpli).

Link spre comentariu

Mii de multumiri pentru timpul acordat si pentru informatii.Acum am inteles ideea... totusi constat ca sunt la ani lumina fata de tine la capitolul asta... pana la urma abea m-am apucat de asa ceva, am de munca pana o sa ma pot baza pe propriile cunostinte in proportie de 100% in scrierea unui cod eficient, dar am rabdare.Acuma imi cer scuze pentru ignoranta insa desi pe cuvant ca am studiat totusi acum aud prima data de ideea de variabile de 'x' biti, adica ai zis ca 'ICurrent' este suficient de mare sa incapa in ea 6 masuratori, sa inteleg ca numarul de caractere al variabilei decide cantitatea de informatii posibil a fi stocate in ea, sau sunt eu total pe langa subiect?... poti te rog sa detaliezi?

Link spre comentariu

In documentatia compilerului folosit, ar trebui sa gasesti informatii despre tipul de date suportate de compilerul respectiv.

Copy/paste din manualul de la XC8 - compilatorul de la uChip.

bit                         1signed char            8unsigned char         8signed short           16unsigned short        16signed int               16unsigned int            16signed short long     24unsigned short long  24signed long              32unsigned long           32signed long long        32unsigned long long     32
Dupa cum vezi, exist variabila bit - pe 1 bit, valori 0/1, exista (signed) char pe 8 biti (-128..127), unsigned char tot pe 8 biti, dar ia numai valori pozitive - 0..255...

thunderer a propus un for pana la 200 si in corpul for-ului a adunat rezultatele conversiei ADC pe 10 biti. Asta inseamana valori de pana la 1023 (2^10). Inmultite cu 200, ies valori mai mari de 200000.

Cum o variabila (fara semn) reprezentata pe 16 biti (unsigned int/unsigned short) "poate" maxim 65535 (2^16) => pentru cei 200000 e nevoie nu de 32 biti cum eronat am zis mai sus, ci de un short long (24 biti).

Link spre comentariu

...sa inteleg ca numarul de caractere al variabilei decide cantitatea de informatii posibil a fi stocate in ea...

Pfff, o perla cat mine de mare...parca am fi la bac :rade: Rau e sa nu stii unele chestii, debitezi niste aberatii demne de generic asa cum am facut eu... deh asta e, trec eu de stagiul asta candva....Multumesc mult, acuma am inteles, si sa-mi fie rusine ca am citit despre chestia asta si abea acum mi-am amintit dupa ce ai postat lista aia, dar la momentul respectiv nu stiam la ce se refera... pana la urma autodidactica este valabila pana la un punct, anumite chestii doar lovindu-te de ele si discutandu-le cu altii le poti depasi. Eu am folosit mikroC si in manualul sau este tabelul asta:Acuma stiu ce am de facut si pot alege atatea citiri cate doresc in cunostinta de cauza, poate ca n-ar strica o scurta bucla din asta si pentru tensiune... in fine inca o data mii de multumiri. :aplauze
Link spre comentariu

Testand sugestiile lui @Liviu M am evoluat putin proiectul educativ de pe pagina anterioara, i-am adaugat masurare curent si avertizari vizuale si sonore asupra atingerii pragurilor maxime V/A. Iata codul sursa:

/* Proiect Volt/Amper-Metru test * Descriere   Voltmetru 0-50V, Ampermetru 0-10A cu LCD 2x16 * Configuratie   Microcontroller PIC16F887   Oscilator XT 8.0000Mhz * Autor   marian@Elforum */// Conexiuni LCDsbit 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;//Declarare variabileunsigned char ch, I, U;unsigned int Tensiune, Curent, ProtU, ProtI;unsigned long V, A;//Functie principalavoid main() {    INTCON = 0;                      // Dezactivare intreruperi    ANSEL = 0x06;                    // Pini AN1 si AN2 setat pe mod analogic    TRISA = 0x06;                    // Pini RA1 si RA2 setati ca intrari    ANSELH = 0;                      // Restul canalelor setate pe mod digital    PORTA.F5 = 0;                    // Resetare pin RA5    PORTA.F4 = 0;                    // Resetare pin RA4        Lcd_Init();                      // Initializare LCD    Lcd_Cmd(_LCD_CURSOR_OFF);        // Comanda dezactivare cursor    Lcd_Cmd(_LCD_CLEAR);             // Comanda stergere ecran    Delay_ms(1000);    Lcd_Out(1,1,"Volt/Amper-Metru"); // Mesajul initial => prima linie    Lcd_Out(2,5,"*Marian*");         // Mesajul initial => linia a 2-a    ADCON1 = 0x82;                   // Referinta este Vcc    Delay_ms(3000);                  // 3 secunde delay    Lcd_Cmd(_LCD_CLEAR);             // Comanda stergere ecran    Lcd_Out(1,1,"U:0-50V");          // Mesaj principal => Prima linie,    Lcd_Out(1,9,"I:0-10A");          // "U.." coloana 1; "I..." coloana 9    while (1) {        //Tensiune        Tensiune = 0;        for (U=0; U<10; U++) {        Tensiune += ADC_Read(2);     // Achizitie ADC pentru tensiune        Delay_ms(10);        }        Tensiune = Tensiune/U;        V = (long)Tensiune*5000;     // Convertire rezultat in milivolti        V = V/1023;                  // 0..1023 => 0-5000mV                ch = V/1000;                 // Extragere zecimale        Lcd_Chr(2,1,48+ch);          // Scrie rezultatul in format ASCII        ch = (V/100) % 10;           // Extragere unitati        Lcd_Chr_CP(48+ch);           // Scrie rezultatul in format ASCII        Lcd_Chr_CP('.');        ch = (V/10) % 10;            // Extragere sutimi        Lcd_Chr_CP(48+ch);        ch = V % 10;                 // Extragere zecimi        Lcd_Chr_CP(48+ch);        LCD_Chr_CP('V');             // Afisare caracter 'V' la final        Delay_ms(10);                //Curent        Curent = 0;        for(I=0; I<10; I++) {        Curent += ADC_Read(1);       // Extragere ADC pentru curent        Delay_ms(10);        }        Curent = Curent/I;        A = (long)Curent*1000;       // Convertire rezultat in milivolti        A = A/1023;                  // 0..1023 => 0-1000mV                ch = A/1000;                 // Extragere zecimale        Lcd_Chr(2,9,48+ch);          // Scrie rezultatul in format ASCII        ch = (A/100) % 10;           // Extragere unitati        Lcd_Chr_CP(48+ch);           // Scrie rezultatul in format ASCII        Lcd_Chr_CP('.');        ch = (A/10) %10;             // Extragere sutimi        Lcd_Chr_CP(48+ch);           // Scrie rezultatul in format ASCII        ch = A % 10;                 // Extragere zecimi        Lcd_Chr_CP(48+ch);        Lcd_Chr_CP('A');             // Afisare caracter 'A' la final        Delay_ms(10);                //Protectii        ProtU = ADC_Read(2);         // Achizitie ADC pentru protectie Tensiune        if (ProtU == 1023) {        PORTA.F4 = 1;                // Aprinde LED daca tensiunea este 50V        Delay_ms(100);        Sound_Init(&PORTA, 0);       // Initializare buzzer,        Sound_Play(1000, 1000);      // si activare avertisment 1Khz, 1 secunda                }        else {        PORTA.F4 = 0;                // Resetare RA4        }        ProtI = ADC_Read(1);         // Ahizitie ADC pentru protectie Curent        if (ProtI == 1023) {        PORTA.F5 = 1;                // Aprinde LED daca curentul este 10A        Delay_ms(100);        Sound_Init(&PORTA, 0);       // Initializare buzzer,        Sound_Play(500, 1000);       // si activare avertisment 500Hz, 1 secunda        }        else {        PORTA.F5 = 0;                // Resetare RA5        }    }}

Si aici un clip cu simularea:

 

Cred ca ar fi ok, si mai cred ca in virtutea celor asimilate cu aceste teste educative voi mai finisa putin proiectul V/A la care lucrez, cel al carui cod a fost scris de @Vlad Mihai, inca nu l-am finalizat tocmai deoarece vroiam intai sa studiez putin programarea, display-ul mare si uC-ul cu destule porturi ofera frau liber imaginatiei. :da

 

PS: Accept orice comentarii si/sau critici.

Link spre comentariu

Nu am studiat codul chiar in profunzime, da' as avea doua observatii:- nu ai nevoie de bucle separate pentru curent si tensiune- testul pentru protectii il poti face folosind aceleasi masuratori de curent/tensiune folosite pentru afisaj (in interiorul buclei/buclelor).In rest, felicitari pentru rezultatele de pana acum si perserverenta.

Link spre comentariu

Referitor la posibilitatea unei singure bucle atat pentru tensiune cat si pentru curent, ar putea arata cam asa?:

declarare variabila pentru incrementare in bucla;Tensiune = o;Curent = 0;for ( setare valoare variabila; verificare stare; incrementare ) {  Tensiune += ADC_Read(2);  //trebuie delay intre ele aici?  Curent += ADC_Read(1);  // sau pun un singur delay aici?}

E ok asa? Si daca da atunci restul poate ramane asa cum este nu? adica listez intai partea de tensiune care ramane de la bucla, si apoi cea de curent... ori asa ori n-am inteles eu ideea...

 

PS: Multumesc mult pentru apreciere.

Link spre comentariu

La ceva in genul asta ma gandeam, da.Intre citiri curent/tensiune nu cred ca-ti trebuie delay, dar nu stiu exact cum e implementata functia ADC_read.Eventual poti imparti delay(50) in doua delay(25), dupa fiecare ADC_read cate doua.Partea de afisare ramane cum e. Cum ziceam si mai devreme, poti renunta la citirile pentru protectii si folosi citirile deja facute.

Link spre comentariu

Am testat varianta cu o singura bucla pentru achizitia ADC la tensiune si curent si vad ca merge ok, am pus doar un singur delay mic dupa achizitii, cam asa arata codul cu afisaj cu tot:

         unsigned char ch, ADCx;         unsigned int Tensiune, Curent;         unsigned long V, A;                //Achizitie ADC        Tensiune = 0;        Curent = 0;        for (ADCx=0; ADCx<10; ADCx++) {        Tensiune += ADC_Read(2);     // Achizitie ADC pentru tensiune        Curent += ADC_Read(1);       // Extragere ADC pentru curent        Delay_ms(10);        }        //Tensiune        Tensiune = Tensiune/ADCx;        V = (long)Tensiune*5000;     // Convertire rezultat in milivolti        V = V/1023;                  // 0..1023 => 0-5000mV        ch = V/1000;                 // Extragere zecimale        Lcd_Chr(2,1,48+ch);          // Scrie rezultatul in format ASCII        ch = (V/100) % 10;           // Extragere unitati        Lcd_Chr_CP(48+ch);           // Scrie rezultatul in format ASCII        Lcd_Chr_CP('.');        ch = (V/10) % 10;            // Extragere sutimi        Lcd_Chr_CP(48+ch);        ch = V % 10;                 // Extragere zecimi        Lcd_Chr_CP(48+ch);        LCD_Chr_CP('V');             // Afisare caracter 'V' la final        Delay_ms(10);                //Curent        Curent = Curent/ADCx;        A = (long)Curent*1000;       // Convertire rezultat in milivolti        A = A/1023;                  // 0..1023 => 0-1000mV        ch = A/1000;                 // Extragere zecimale        Lcd_Chr(2,9,48+ch);          // Scrie rezultatul in format ASCII        ch = (A/100) % 10;           // Extragere unitati        Lcd_Chr_CP(48+ch);           // Scrie rezultatul in format ASCII        Lcd_Chr_CP('.');        ch = (A/10) %10;             // Extragere sutimi        Lcd_Chr_CP(48+ch);           // Scrie rezultatul in format ASCII        ch = A % 10;                 // Extragere zecimi        Lcd_Chr_CP(48+ch);        Lcd_Chr_CP('A');             // Afisare caracter 'A' la final        Delay_ms(10);

Partea de protectii nu am inclus-o pentru ca spre rusinea mea nu am inteles prea bine cum s-ar putea include in acea bucla... as aprecia mult daca ai putea veni cu ceva sugestii.

Link spre comentariu

La partea de protectii ma gandeam la ceva de genul (numai partea de tensiune, partea de curent e similara):

unsigned char ch, ADCx;unsigned int Tensiune, Curent;unsigned int ProtU;unsigned long V, A;sBit OverVoltage;       //Achizitie ADCTensiune = 0;Curent = 0;for (ADCx=0; ADCx<10; ADCx++) {   ProtU = ADC_Read(2);         // Achizitie ADC pentru protectie Tensiune   if (ProtU == 1023) {     OverVoltage = 1;     Tensiune=ProtU;      break; // pericol, intrerupi prelucrarea normala si activezi alarma   }   Tensiune +=ProtU;     // Achizitie ADC pentru tensiune   Curent += ADC_Read(1);       // Extragere ADC pentru curent   Delay_ms(10);}   if(OverVoltage){   PORTA.F4 = 1;                // Aprinde LED daca tensiunea este 50V//   Delay_ms(100);  //dupa parerea mea, neinteresanta   Sound_Init(&PORTA, 0);       // Initializare buzzer,   Sound_Play(1000, 1000);      // si activare avertisment 1Khz, 1 secunda     OverVoltage = 0;  }  else {   PORTA.F4 = 0;                // Resetare RA4   Tensiune = Tensiune / ADCx;}
Nu e neaparat o varianta finala (nu e nevoie sa intrerupi masuratorile cu break, de exemplu), poate ca e chiar o idee proasta in cazul de fata, dar e o idee de genul "se mai poate face si asta".

Poti lasa linistit varianta pe care o aveai tu deja implementata, bineinteles.

Link spre comentariu

In conditiile in care avem la dispozitie cativa kb, orice byte e pretios.In cazul ultimei modificari avantajul principal (dupa parerea mea) e siguranta - detectezi eventualele probleme mult mai repede decat in varianta anterioara.In varianta initiala, testele le faceai dupa ce masurai de 5 ori, mediai, afisai...In varianta mea, detectezi problemele la fiecare masuratoare.

Link spre comentariu

Ai dreptate, se obtine o viteza de reactie din partea protectiilor, in acest sens cred ca se pot implementa si ceva actiuni fizice, spre exemplu alimentarea intregului montaj PIC sa se faca din sursa separata ( un alt traf micut ), si la detectarea supratensiunii un releu sa decupleze alimentarea trafului de putere care alimenteaza sursa principala, si genul protectiei sa fie implementat astfel incat sa se mentina releul aclansat pana la o resetare cu un buton sau comutator ceva, sau un tiristor dupa portul PIC care sa fie amorsat de uC si apoi sa mentina releul aclansat. Apoi la detectarea suprasarcinii ( scurtcircuitul inclus evident ) sa se actioneze un alt port care sa aclanseze un alt releu ce va decupla iesirile sursei principale de panoul frontal unde se fac conexiunile cu sarcina, ori asa ori se comuta acelasi releu care intrerupe alimentarea, desi as tinde spre varianta 2 desi ar necesita un pin in plus si un releu mai solid cu 2 perechi de contacte... in fine posibilitati sunt multe cred. :daPS: O protectie suplimentara pentru intrarile PIC ar putea fi acele zennere de 5V inseriate cu o eventuala rezistenta, evident nu orice zenner, rezultate foarte bune am obtinut testand practic BZX55C5V1, influenta este foarte mica chiar si la limita superioara.

Link spre comentariu

@Liviu ma gandeam la o chestie, cred ca ar fi momentul sa pun in practica cele asimilate pana acum cu un microcontroller pe care il am si care era destinat proiectului de AICI, devreme ce mare parte din cod va fi asta de aici voi continua discutia aici.

 

Asadar ma gandeam asa, folosesc LCD 2x24 ca de asta am si as afisa pe el 4 masuratori: tensiune, curent, putere si temperatura radiator, partea cu temperatura din lipsa de senzor ma voi folosi de un termistor, am gasit unul PTC cu posibilitate de montare pe surub, am si cateva NTC pe la 10k dar acelea sunt sub forma de disc deci greu de fixat pe radiator... vad ca asta PTC are cam 150 Ohm la temperatura aproximativa a camerei, probabil voi folosi un AO ( al 2-lea AO de la capsula celui cu care fac monitorizarea curentului ) pentru asigurarea variatiei de 0-5V in functie de variatia rezistentei sale si calibrarea as putea-o face cu ajutorul unui multimetru cu sonda de temperatura... evident nu ma astept la precizie dar macar aproximativ si tot ar fi ceva...

 

Apoi tensiunea, curentul si puterea sunt simplu de rezolvat, acuma referitor la protectii, eu ma gandeam ca atunci cand unul din praguri este atins, pe langa aprinderea ledurilor si avertizare sonora sa se faca asa cum ziceam si comanda unor relee, si devreme ce deja am ledurile care se aprind la atingerea limitelor, tot de acolo as lua si semnalul pentru releu cu un bipolar mic/mediu, acuma eu ma gandisem ca atunci cand oricare din praguri este atins microcontroller-ul sa opreasca rularea normala a codului si sa afiseze pe ecran un avertisment, spre exemplu "Protectie", si sa se mentina ledurile aprinse, am testat asta cu comanda "break" in simulator si vad ca ar fi ok, avertizarea sonora ruleaza o singura data ( i-am lungit durata la 3 sec ) apoi se afiseaza mesajul pe LCD si se opreste rularea normala, ledul ramane aprins, banuiesc ca asa este si normal devreme ce nu s-a primit comanda de resetare, cam asa arata codul descris pentru partea de tensiune:

        //Protectii        ProtU = ADC_Read(2);         // Achizitie ADC pentru protectie Tensiune        if (ProtU == 1023) {        PORTA.F4 = 1;                // Aprinde LED daca tensiunea este 50V        Sound_Init(&PORTA, 0);       // Initializare buzzer,        Sound_Play(1000, 3000);      // si activare avertisment 1Khz, 3 secunde        Lcd_Cmd(_LCD_CLEAR);         // Comanda stergere ecran        Lcd_Out(1,1,"Protectie");    // Mesaj de avertizare        break;                       // Oprirea rularii programului        }

Sub el este acel "else" care reseteaza portul respectiv in cazul in care comanda "if" nu este 'adevarata' dar asta oricum se face la inceputul codului, deci banuiesc ca se poate renunta la else, nu?

 

Ce spui e ok?

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