Bird Postat Decembrie 27, 2009 Partajează Postat Decembrie 27, 2009 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
deep-blue Postat Decembrie 28, 2009 Partajează Postat Decembrie 28, 2009 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-375Calculul (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-37500Inmultirea 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.0000Programul:#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
Liviu M Postat Decembrie 28, 2009 Partajează Postat Decembrie 28, 2009 @deep-blue: ce compilator folosesti si cat de "eficient" e implemantat printf? Link spre comentariu
Bird Postat Decembrie 28, 2009 Autor Partajează Postat Decembrie 28, 2009 ................. 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++" . 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
Bird Postat Decembrie 28, 2009 Autor Partajează Postat Decembrie 28, 2009 ...........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
deep-blue Postat Decembrie 28, 2009 Partajează Postat Decembrie 28, 2009 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
Liviu M Postat Decembrie 28, 2009 Partajează Postat Decembrie 28, 2009 Nu folosesc printf-ul din libc ci rutine adaptate dintr-un demo de stdio, in primul rand pentru ca printf() ocupa mult prea mult flashOK, 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
Bird Postat Decembrie 28, 2009 Autor Partajează Postat Decembrie 28, 2009 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
Bird Postat Decembrie 28, 2009 Autor Partajează Postat Decembrie 28, 2009 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 " Link spre comentariu
Vizitator thenoble66 Postat Decembrie 28, 2009 Partajează Postat Decembrie 28, 2009 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.0Hai 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
Bird Postat Decembrie 29, 2009 Autor Partajează Postat Decembrie 29, 2009 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
Bird Postat Decembrie 29, 2009 Autor Partajează Postat Decembrie 29, 2009 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 Postat Decembrie 29, 2009 Partajează Postat Decembrie 29, 2009 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 corectCu valorile noi:Am inversat calculele :Volti fiind = 4037...mmHG = Volti *75/40 =......101.5 !!!?? in loc de 7569.375=> 756.9PIC 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
Bird Postat Decembrie 29, 2009 Autor Partajează Postat Decembrie 29, 2009 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 Postat Decembrie 29, 2009 Partajează Postat Decembrie 29, 2009 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. Toate bune, thenoble66 PS: :vezi urmatorul calcul: Presiune = Volti * 15 / 8 =================== Link spre comentariu
Postări Recomandate
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 contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum