Sari la conținut
ELFORUM - Forumul electronistilor

Unde-i greseala ??


Bird

Postări Recomandate

Va salut ...si La multi ani !

 

Folosesc codul de mai jos pentru a afisa pe un display LCD rezultatul masurarii presiunii atmosferice si spre exemplu : daca

'volti " = 3998 mV presiunea din calcul ar fi una iar cea afisata e alta ??In loc de 757.1 / 750.0 . Nu stiu ce gresesc si unde . Aveti vreo idee ? (Folosesc "unitati " pentru zecimala ).

 

 

 

Presiune var word ' variabila de stocare a valorii presiunii

 

Volti var word ' valoarea tensiuni echivalente cu intrarea ADC de la senzor

 

mmHG var word

 

'MASURARE PRESIUNE

 

ADCON0=%11000001

 

PAUSE 100

 

ADCON0.2 = 1 ' Start Conversion

 

PAUSE 100

 

NU_I_GATA:

 

PAUSE 550

 

If ADCON0.2 = 1 Then

goto NU_I_GATA

else ' Wait for low on bit-2 of ADCON0, conversion finished

Presiune = ADRESH ' Move high byte of result to Presiune

endif

 

Volti = (Presiune*196)/10

PAUSE 100

 

mmHG = ((77+(((Volti-3000)*24)/1000))*75)

 

PAUSE 150

 

mii = 48+(mmHG//10000/1000)

sute = 48+(mmHG // 1000/100)

zeci = 48+(mmHG//100/10)

unitati = 48+(mmHG // 10)

 

PAUSE 100

 

adr = 129

 

PAUSE 100

 

i2cwrite I2CDAT, I2CCLK, $A0, adr,[mii,sute,zeci,",",unitati]

 

PAUSE 100

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

Top autori în acest subiect

  • Bird

    9

  • Liviu M

    2

  • deep-blue

    2

Top autori în acest subiect

spre exemplu : daca'volti " = 3998 mV presiunea din calcul ar fi una iar cea afisata e alta ??In loc de 757.1 / 750.0 . Nu stiu ce gresesc si unde . Aveti vreo idee ? (Folosesc "unitati " pentru zecimala )

Mai intai de toate un sfat calduros: nu lasati microcontrolerul sa faca nici un calcul mai mult decat minimul necesar. Teoria calcului numeric poate umple singura zeci de volume, dar ca regula generala: cu cat controllerul face mai putine calcule cu atat mai putine posibile "anomalii" vor aparea in rezultat.

Volti = (Presiune*196)/10PAUSE 100mmHG = ((77+(((Volti-3000)*24)/1000))*75)
se poate simplifica pana la
mmHG=Presiune*35.28-375
Calculul (bine ar fi daca l-ar mai verifica cineva) e aici [attachment=0]calcul_presiune.pdf[/attachment]Nici inmultirea aceeia nu trebuie sa o faca controlerul asa cum e acolo. Inmultind totul cu 100 scapam de virgula:
mmHG*100=Presiune*3528-37500
Inmultirea se poate reduce acum la shift-ari si adunari succesive:
Presiune*3528 = Presiune*2048 + Presiune*1024 + Presiune*256 + Presiune*128 + Presiune*64 + Presiune*8
(Inmultirea s-a descompus exact dupa termenii de mai sus). Memo: sa nu uitam si de scadere!
mmHG = (Presiune<<11) + (Presiune<<10) + (Presiune<<8) + (Presiune<<7) + (Presiune<<6) + (Presiune<<3) - 37500;/* In sfarsit ultima parte, pregatirea pentru afisare: */mii = 0;sute = 0;zeci = 0;unitati = 0;x=mmHG;while (x >= 100000){    x -= 10000;    mii++;}while (x >= 10000){    x -= 1000;    sute++;}/* s.a.m.d. ... *//*  */
Nu cunosc limbajul in care s-a programat initial formula, dar in C - daca se poate folosi - se poate impune un control foarte bun al preciziei.Am facut un mic program ca sa vad daca un algoritm de tipul celui de mai sus da rezultate mai bune. In urma rezultatelor pot sa presupun cu destul de multa siguranta ca problema vine de la o optimizare a formulei lui mmHG.
# gcc -o pressure pressure_numeric_calc.c# ./pressure Volti = 3990 mmHG = 75570	mmHg (mcu) = 7 5 5 7 	mmHg (pc float) = 7557.0000Volti = 3991 mmHG = 75588	mmHg (mcu) = 7 5 5 8 	mmHg (pc float) = 7558.8000Volti = 3992 mmHG = 75606	mmHg (mcu) = 7 5 6 0 	mmHg (pc float) = 7560.6000Volti = 3993 mmHG = 75624	mmHg (mcu) = 7 5 6 2 	mmHg (pc float) = 7562.4000Volti = 3994 mmHG = 75642	mmHg (mcu) = 7 5 6 4 	mmHg (pc float) = 7564.2000Volti = 3995 mmHG = 75660	mmHg (mcu) = 7 5 6 6 	mmHg (pc float) = 7566.0000Volti = 3996 mmHG = 75678	mmHg (mcu) = 7 5 6 7 	mmHg (pc float) = 7567.8000Volti = 3997 mmHG = 75696	mmHg (mcu) = 7 5 6 9 	mmHg (pc float) = 7569.6000Volti = 3998 mmHG = 75714	mmHg (mcu) = 7 5 7 1 	mmHg (pc float) = 7571.4000Volti = 3999 mmHG = 75732	mmHg (mcu) = 7 5 7 3 	mmHg (pc float) = 7573.2000Volti = 4000 mmHG = 75750	mmHg (mcu) = 7 5 7 5 	mmHg (pc float) = 7575.0000
Programul:
#include <stdio.h>int main (){	unsigned short i, j, k ,l, m;	unsigned int x = 0;	unsigned int mmHG = 0; // 32 bit    unsigned char mii = 0, sute = 0, zeci = 0, unitati = 0;		for (i = 3950; i <= 4000; i++)	{		x = i;		mii = 0; 		sute = 0; 		zeci = 0; 		unitati = 0; 		/* mmHG = 1.8*Volti + 375		 * i = Volti		 * multiplicam cu 10 ca sa scapam de virgula		 *      = 18*Volti + 3750		 *      = Volti*16 + Volti*2 + 3750		 */		mmHG = (i<<4) + (i<<1) + 3750;		x = mmHG;		while (x >= 10000)		{			x -= 10000;			mii++;		}				while (x >= 1000)		{			x -= 1000;			sute++;		}				while (x >= 100)		{			x -= 100;			zeci++;		}				while (x >= 10)		{			x -= 10;			unitati++;		}						k = k*100 + l*10 + m;				printf("Volti = %d mmHG = %d\tmmHg (mcu) = %d %d %d %d \tmmHg (pc float) = %4.4f\n", i, mmHG, mii, sute, zeci, unitati, i*1.8+375);	}	return 0;}
Link spre comentariu

................. ce compilator folosesti si cat de "eficient" e implemantat printf?

Eu folosesc MicroCodeStudio Plus cu PicBasicPro 2.43 . Nu stiu sa folosesc "C " or "C++" . :jytuiyu Va multumesc pentru ideea de a restrange formula ! O sa incerc . Ma gandeam ca poate nu folosesc cotrect intarzierile . Cu toate ca am incecat si mai mici si mai mari......
Link spre comentariu

...........Am incercat sa folosesc si formula data de fabricantul senzorului de presiune "MPX4151" :

 

Vout=Vs *(0.009*P-0.095)+/- Eroare

 

Vout = Volti

Vs = tensiunea de alimentare - 4.95 V-

P = KPascali

Dar.....tot aparea diferenta intre cacul si display avand masurati si afisati pe display "Volti " care corespundeau cu masurarea efectiva cu instrumentul , la intrarea in pinul ADC

Link spre comentariu

In programul de test de mai sus au ramas vreo 2 linii de cod orfane - sper sa nu incomedeze. In plus, programul l-am facut ca sa testez doar a 2-a formula (mmHG = ((77+(((Volti-3000)*24)/1000))*75)) deoarece am presupus ca acolo e problema.

 

ce compilator folosesti si cat de "eficient" e implemantat printf?

 

Pentru PIC-uri folosesc SDCC dar nu am avut ocazia pana acum sa folosesc (nici nu stiu daca are) stdio.

 

Prefer Atmel-urile, mai ales ca din cand in cand mai gaseam controlere "not recomended for new designs" chiar si la 2-3 lei.

Am un toolset AVR (avr-gcc v4.3, libc v1.62., binutils v2.19) destul de nou. Nu folosesc printf-ul din libc ci rutine adaptate dintr-un demo de stdio, in primul rand pentru ca printf() ocupa mult prea mult flash si in al doilea rand pentru ca nu se impaca cu LCD-urile Hitachi 2x16. Totusi folosesc din cand in cand sprintf() ... care, recunosc, nu stiu cat e de eficient, dar am mare grija sa nu-l servesc cu float.

 

Stiu ca apar diferente intre ce se afiseaza pe PC respectiv pe un microcontroler, dar nu si daca-i dai "mura-n gura" lui printf ce sa afiseze.

 

Ma gandeam ca poate nu folosesc cotrect intarzierile . Cu toate ca am incecat si mai mici si mai mari......

Ma indoiesc ca acele intarzieri folosesc la ceva (cand sint folosite dupa un calcul matematic bineinteles). Cum am mai spus, nu cunosc compilatorul, dar presupun ca acesta nu lucreaza "in paralel" la formula si in acelasi timp asteapta dupa rezultat. Mai degraba va proceda secvential: calculeaza si apoi executa rutina de pauza.

Intervalele de pauza cand se lucreaza (seteaza, citeste rezultat) cu convertorul A/D sint, insa, esentiale si timpii minimi se gasesc in foaia de catalog a controlerului. Presupun ca aceste intervale au fost corecte din moment ce rezultatul e destul de apropiat de cel real (deobicei daca aceste intervale nu sint suficient de mari rezultatele conversiei sint puternic eronate).

 

Dar.....tot aparea diferenta intre cacul si display avand masurati si afisati pe display "Volti " care corespundeau cu masurarea efectiva cu instrumentul , la intrarea in pinul ADC

Raman la ideea ca trebuie optimizata formula de calcul.

Link spre comentariu

Nu folosesc printf-ul din libc ci rutine adaptate dintr-un demo de stdio, in primul rand pentru ca printf() ocupa mult prea mult flash

OK, de fapt printf ma interesa. Tot din cauza ca am auzit ca ar consuma multe resurse, nici macar n-am incercat sa-l folosesc, mi-am scris rutinele proprii (probabil la fel de ineficiente).

 

@Bird: daca m-am prins corect cum it functioneaza programul, se pare ca problemele vin de la

unitati = 48+(mmHG // 10)

Esti sigur ca operatia e facuta bine?
Link spre comentariu

unitati = 48+(mmHG // 10)Esti sigur ca operatia e facuta bine?

Operatia de mai sus este corecta , functionand pentru afisarea in ASCII a unitatilor . Imparte numarul cu 10 si ia "restul" de-l afiseaza . O folosesc sa subrutina pentru mai multe date , pe care le afisej pe display . Acesta fiind cu leduri , nu LCD !
Link spre comentariu

Am schimbat formula . Am vazut ca se da in caracteristicile senzorului ~46mV/KPa , si am impartit "Volti"la 40( ca sa acoper eroarea ce apare la calcul intre presiunea de la INMH si cea rezultata la mine ) si am inmultit cu 75 sa obtin mmHG .(7.5 ar trebui dar il las asa ca sa folosesc "unitati " pe post de zecimala ). Dar tot apar diferente intre afisare si calcul . Ex: 753,3 din calcul , "Volti " fiind 4018 , si pe display indica 750.0 . Afisez pe display si presiunea in mmHG si "Volti " pe care-i compar cu valoarea masurata cu un instrument la intrarea ADC-ului . Cu stiama ! Unii se pregatesc de revelion , iar eu imi bat capul cu "prostioare " :rade:

Link spre comentariu
Vizitator thenoble66

Salut,

Am vazut ca se da in caracteristicile senzorului ~46mV/KPa , si am impartit "Volti"la 40( ca sa acoper eroarea ce apare la calcul intre presiunea de la INMH si cea rezultata la mine ) si am inmultit cu 75 sa obtin mmHG .(7.5 ar trebui dar il las asa ca sa folosesc "unitati " pe post de zecimala ). Dar tot apar diferente intre afisare si calcul . Ex: 753,3 din calcul , "Volti " fiind 4018 , si pe display indica 750.0

Hai sa vedem cum face PIC-ul calculele:Volti = 4018 ' tip WORD, ATENTIEmmHg = Volti / 40 ' = 100 ATENTIE! SE TRUNCHIAZA! 100.45 <> 100mmHg = mmHg * 75 ' = 750, deci rezultat afisat corectDaca vrei rezultate corecte, foloseste tip float, sau long, cu precautiile de rigoare.Toate bune,thenoble66
Link spre comentariu

Salut,...........................................................Daca vrei rezultate corecte, foloseste tip float, sau long, cu precautiile de rigoare.Toate bune,thenoble66

Sa traiesti ! Fi bun si detaliaza ..." precautiile de rigoare " si poate imi spui concret care sunt modificarile ce trebiesc facute . Valabil pentru toate variabilile ? Cu stima si multumiri ,
Link spre comentariu

Salut,Hai sa vedem cum face PIC-ul calculele:Volti = 4018 ' tip WORD, ATENTIEmmHg = Volti / 40 ' = 100 ATENTIE! SE TRUNCHIAZA! 100.45 <> 100mmHg = mmHg * 75 ' = 750, deci rezultat afisat corectthenoble66

Am inversat calculele :Volti fiind = 4037...mmHG = Volti *75/40 =......101.5 !!!?? in loc de 7569.375=> 756.9 Daca la primul exemplu am inteles ce se intampla , acum nu prea am inteles .
Link spre comentariu
Vizitator thenoble66

Scuze,Am gresit o virgula in exemplu. Iata exemplul corectat:

Volti = 4018 ' tip WORD, ATENTIEmmHg = Volti / 40 ' = 100 ATENTIE! SE TRUNCHIAZA! 100.45 <> 100mmHg = mmHg * 75 ' = 7500, deci rezultat afisat corect

Cu valorile noi:

Am inversat calculele :Volti fiind = 4037...mmHG = Volti *75/40 =......101.5 !!!?? in loc de 7569.375=> 756.9

PIC face in felul urmator:4037 * 75 = 302775, dar saracul WORD nu retine decat ultimele 16 biti, adica 4063140631 / 40 = 1015.775 dar WORD nu retine decat 1015AICI E PROBLEMA!Daca ai declara variabile de 4 octeti (LONG sau cum s-ar numi in BASIC folosit de tine), rezultatele s-ar apropia de cele asteptate:4037 * 75 = 302775 ' fara trunchiere302775 / 40 = 7569.375 ' adica 7569 trunchiat la 32 de bitiTe rog sa observi, ca nu pot da reteta directa in limbajul folosit de tine, pentru ca eu nu il folosesc.Am atasat in schimb un .pdf cu niste calcule, poate utile.Toate bune,thenoble66
Link spre comentariu

Scuze,

 

Te rog sa observi, ca nu pot da reteta directa in limbajul folosit de tine, pentru ca eu nu il folosesc.

 

 

Toate bune,

thenoble66

"Variables are where temporary data is stored in a PicBasic Pro program. They are created using the VAR keyword. Variables may be bits, bytes or words. Space for each variable is automatically allocated in the microcontrollers RAM by PBP. The format for creating a variable is as follows:.................................

 

:cry: O sa caut la calcule matematice ...( nu sunt un profesionist in programare....sunt un programator de "ocazie " de asta si folosesc un program mai "mura'n gura ").

 

Iti multumesc pentru ajutorul dat . Daca rezolv ceva revin cu solutia .

Link spre comentariu
Vizitator thenoble66

Observ din manualul PicBasic muuuulte limitari privind aritmetica folosita.

Ciudat e faptul ca, desi calculele matematice pe 4 octeti (32 de biti) nu sunt un punct tare al PIC-urilor 12FXXX, 16FXXX, DAR NU SUNT IMPOSIBILE, ele nu se pot compila cu PicBasicPro.

 

Eu folosesc cat-de-cat regulat urmatorul compilator.

http://www.mikroe.com/en/compilers/mikrobasic/pro/pic/

Deocamdata limitarile sunt date doar de eventualele lipsuri ale mele.

Chiar cu varianta demo poti compila cod hex pana la 2k.

 

Merita incercat. :da

 

Toate bune,

thenoble66

 

PS: :vezi urmatorul calcul:

 

Presiune = Volti * 15 / 8

===================

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