danpin Postat Octombrie 5, 2014 Partajează Postat Octombrie 5, 2014 Salutari! Vreau sa fac un termometru cu PIC16F690 care sa-mi afiseze temperatura pe trei digiti LED 7 seg. anod comun si intre anumite valori ale temp. sa-mi porneasca/opreasca un ventilator. Asa de amorul artei, am zis sa fac comanda ventilatorului in PWM cu factor de umplere proportional cu temperatura. Cum nu ma pricep prea mult la programare, nu-mi prea iese treaba... Software-ul l-am scris inspirandu-ma de pe forum si din alte surse de pe net. In simulare merge bine pana pornesc PWM-ul dupa care imi afiseaza cu intermitenta cifrele, adica se vede "baleierea" celor trei digiti. Atasez fisierele, daca cineva e dispus sa ma ajute un pic. Termometrul vreau sa-l folosesc pt. afisarea temp. radiatorului unei surse pe care vreau sa o construiesc, schema sursei fiind luata de aici: http://www.rmitaly.com/index.php/en/products/obsoleti/item/940-lps-130-d/940-lps-130-d Am construit termometrul pe placa de test dar nu a functionat de nici un fel, afisa total aiurea, posibil sa fi avut probleme la programarea PIC-ului. Ori de cate ori incercam sa-l programez imi dadea eroare, trebuia sa sterg Pic-ul intai si pe urma mergea programat, adica nu mai dadea eroare la scriere, dar pe afisaj se aprindeau segmentele aiurea. Ca programator folosesc o clona K8076-Velleman cu care am programat alte Pic-uri fara probleme. Iesirea senzorului LM35 trebuie amplificata sau merge legata direct la Pic? Pun si aici codul, poate cineva vede direct ce e gresit sau mai trebuie completat fara sa mai deschida arhiva rar sau similarea. unsigned short mask(int num){ switch (num) { case 0 : return 0xC0; case 1 : return 0xF9; case 2 : return 0xA4; case 3 : return 0xB0; case 4 : return 0x99; case 5 : return 0x92; case 6 : return 0x82; case 7 : return 0xF8; case 8 : return 0x80; case 9 : return 0x90; case 10 : return 0xFF; }}unsigned char ADCx;unsigned short portb_index;unsigned int digit, number, ColCount;unsigned short portb_array[4];unsigned short portc_arry[8];unsigned int adc_rd0, tlong, temperature;unsigned short current_duty, current_duty1; void anods () { PORTA.F2 = 0; PORTA.F4 = 0; PORTA.F5 = 0; ColCount++; if (ColCount>3) ColCount=0; switch (ColCount) { case 1: PORTA.F2 = 1; break; case 2: PORTA.F4 = 1; break; case 3: PORTA.F5 = 1; break; } } void my_port(int ValueToSend) { RB4_bit = (ValueToSend); //lsb RB5_bit = (ValueToSend>>=1); RB6_bit = (ValueToSend>>=1); RB7_bit = (ValueToSend>>=1); RC0_bit = (ValueToSend>>=1); RC1_bit = (ValueToSend>>=1); RC2_bit = (ValueToSend>>=1); RC3_bit = (ValueToSend>>=1); //msb }void interrupt(){ if(T0IF) { INTCON.GIE = 0; anods (); my_port( portb_array[portb_index]); portb_index ++; if (portb_index > 3u) portb_index = 0; TMR0 = 100; INTCON.T0IF = 0; // Clear timer0 interrupt flag INTCON.GIE = 1; }}void temp_ADC() // Reading the analog inputs (ADC){ Temperature = 0; for (ADCx=0; ADCx<5; ADCx++) { Temperature += ADC_Read(9); // Reading voltage values from channel 9 //Delay_us(50); } Temperature = (Temperature/ADCx); // Temperature (Voltage) calculation tlong = (long)Temperature*1.5; // Millivolts conversion number = (tlong/1.023); // 0...1023 => 0...1500mV //Delay_us(50);}void display(){ if (number<1000) { digit = (number / 100u); if(digit<1) { digit=10; portb_array[0]= mask(digit); } else portb_array[0]= mask(digit); digit = (number / 10u) % 10u; portb_array[1] = mask(digit)&0x7F; digit = ((number)% 10u); portb_array[2] = mask(digit); } else { digit = (number / 1000u)%10u; portb_array[0]= mask(digit); digit = (number / 100u) % 10u; portb_array[1] = mask(digit); digit = (number/10)% 10u; portb_array[2] = mask(digit); }}void overtemp(){ if (number >=350) { PWM1_Start(); //PORTC.F4=1; //Init PWM for Single Output current_duty=number ; // Set the PWM Duty Cycle PWM1_Set_Duty(number*0.28); // Start with Max Duty Cycle if (number >=900) PWM1_Set_Duty(255); } if (number <800) PORTC.F6=1; else PORTC.F6=0; if (number <300) PWM1_Stop(); //PORTC.F4=0;} void main(){ OPTION_REG = 0b11000101; INTCON = 0b10100000; OSCCON = 0b01110111; ADCON0 = 0b11100111; ADCON1 = 0b00110000; T2CON=0b00000101; PR2=0x65; // Frequency: 4.90 kHz TMR2=0; // Start with zero Counter PSTRCON=0b00000001; // Enable Pulse Steering on P1D (RB4) CM1CON0=0; CM2CON0=0; CCP1CON= 0b00001100; // port initialization... //INTCON.T0IE = 1; // Enable interrupt on TMR0 overflow TRISB = 0x00; // Set PORTB direction to be output PORTB = 0x00; // Turn OFF LEDs on PORTB TRISC = 0x20; // Set PORTC direction to be output PORTC = 0x00; // Turn OFF PORTC TRISA = 0x02; PORTA = 0x02; ANSEL = 0x02; ANSELH = 0x02; digit = 0; portb_index = 0; ColCount=0; number = 0; //initial value; PIR1.TMR2IF=0; TMR0 = 100; // Set timer TMR0 initial value; PWM1_Init(20000); // Initialize PWM1 module at 20KHz current_duty = 64; // initial value for current_duty while(1) //Endless loop; { temp_ADC(); overtemp(); display(); //Delay_us(1000); }} Termometru 7SEG+LM35.rar Link spre comentariu
bratueduard Postat Octombrie 5, 2014 Partajează Postat Octombrie 5, 2014 (editat) Pune te rog si schema pe care o folosesti. Momentan modul de lucru PWM nu este in regula. eu as proceda altfel: 1. scos tot ce contine "void overtemp" si deasupra de la "While(1) "PWM1_Init(20000); current_duty = 64;" 2. la unsigned short mai adaugat si "pwm=0" 3. initializez pwm cam asa (in void main) PWM1_Init(1000); // incercam cu 1KHz si vedem cum se comporta ventilatorul PWM1_Start(); 4. si comanda pwm mai jos de "while(1);": if (number >=350 && number<=450) {pwm==64;} if (number >=451 && number<=551) {pwm==96;} if (number >=552 && number<=651) {pwm==128;} // asa stabilesti limite de temperatura si umplere de pwm // la sfarsit: if (number<249) {pwm=0;} PWM1_Set_Duty(pwm); O alta metoda este stabilirea "number" intre 350 - 900 (parca) si asa poate comanda PWM proportional cu temperatura. Initial incearca ce am scris mai sus si mai vedem. Daca postezi si o schema as putea face o simulare.L.E. scuze! nu am vazut initial atasamentul cu schema. Editat Octombrie 5, 2014 de bratueduard Link spre comentariu
sofian Postat Octombrie 5, 2014 Partajează Postat Octombrie 5, 2014 aici este gresit void anods (){PORTA.F2 = 0;PORTA.F4 = 0;PORTA.F5 = 0;ColCount++;if (ColCount>3)ColCount=0;switch (ColCount){case 1: PORTA.F2 = 1;break;case 2: PORTA.F4 = 1;break;case 3: PORTA.F5 = 1; // nu exista ColCount=3break;}} trebuie asa void anods (){ColCount++;if (ColCount>3)ColCount=0;PORTA.F2 = 0; // aici sting digitPORTA.F4 = 0; // trebuie sa fie cit mai aproape de aprindere digitPORTA.F5 = 0;switch (ColCount) // aprindere digit ColCount 0..2{case 0: PORTA.F2 = 1;break;case 1: PORTA.F4 = 1;break;case 2: PORTA.F5 = 1;break;}} Link spre comentariu
Mircea Postat Octombrie 5, 2014 Partajează Postat Octombrie 5, 2014 Nu lucrez in C (doar in Basic) deci nu pot comenta ce este postat, fiind departe de a intelege perfect sintaxa utilizata. 2 comentarii: 1. Daca vrei DC proportional cu temperatura, atunci folosesti o interpolare liniara. N-as folosi secvente de IF-uri (care mananca din memoria program). http://en.wikipedia.org/wiki/Linear_interpolation 2. Folosirea ADC_Read(x) este de fapt succesiunea lui ADC_Init() si ADC_Get_Sample(x). Sa zicem ca nu ai probleme acum cu ADC_Read(x), dar poate mai tarziu vrei ceva optimizare. Stiu ca exemplele din Help sunt cu ADC_Read(x), si asta face pe multi sa foloseasca aceasta functie mai curand decat ADC_Get_Sample(x). Spor la treaba! Link spre comentariu
danpin Postat Octombrie 5, 2014 Autor Partajează Postat Octombrie 5, 2014 Multumesc tuturor pt. sfaturi si implicare! - Sofian - Am facut modificarea dar nu schimba situatia, tot sacadat imi afiseaza in simulare atunci cand am PWM-ul pornit, in plus daca schimb case 1,2,3 cu case 0,1,2 imi schimba ordinea de afisare a digitilor adica am D3, D1, D2 - thunderer - Am schimbat ADC_Read(x) cu ADC_Init() si ADC_Get_Sample(x), cu interpolarea mai studiez.... - bratueduard - Am facut modificarile sugerate dar nu merge.... Pornind PWM-ul in MAIN imi afiseaza sacadat cifrele si atunci cand ventilatorul este oprit, adica sub 35 grade. In schimb am modificat in programul initial PWM1_Init(500); // Initialize PWM1 module at 0,5KHz si cel putin in simulare s-a ameliorat treaba, indicatia cu PWM-ul pornit este suficient de stabila. Intrebasem in primul post: trebuie amplificat semnalul de la LM35 inainte de intrarea in PIC? Link spre comentariu
Mircea Postat Octombrie 5, 2014 Partajează Postat Octombrie 5, 2014 Resursa asta o stii? http://www.mikroe.com/chapters/view/17/chapter-4-examples/#c4v11 Intrebasem in primul post: trebuie amplificat semnalul de la LM35 inainte de intrarea in PIC? Depinde de valoarea iesirii LM35. De regula ajustezi iesirea ca sa folosesti toata plaja de la 0 la 5V, ca sa folosesti cei 10biti ai ADC-ului. Link spre comentariu
danpin Postat Octombrie 5, 2014 Autor Partajează Postat Octombrie 5, 2014 Multumesc thunderer! Da, de prin cartile si exemplele lor am inceput sa invat cate ceva. Programele si aplicatiile lor le fac doar asa ca hobby, nu "activez" in domeniul electronicii. Incerc sa invat cate ceva cand am timp. Link spre comentariu
fratello Postat Octombrie 6, 2014 Partajează Postat Octombrie 6, 2014 Multe aplicatii software (in care generam o purtatoare de 38 KHz sau un PWM variabil) imi mergeau sacadat IN SIMULARE, dar perfect in realitate !!! Ai incercat macar pe un breadboard montajul ?! Link spre comentariu
danpin Postat Octombrie 6, 2014 Autor Partajează Postat Octombrie 6, 2014 Fratello, in primul post am scris: "Am construit termometrul pe placa de test dar nu a functionat de nici un fel, afisa total aiurea, posibil sa fi avut probleme la programarea PIC-ului. Ori de cate ori incercam sa-l programez imi dadea eroare, trebuia sa sterg Pic-ul intai si pe urma mergea programat, adica nu mai dadea eroare la scriere, dar pe afisaj se aprindeau segmentele aiurea. Ca programator folosesc o clona K8076-Velleman cu care am programat alte Pic-uri fara probleme." Am sa mai incerc sa reprogramez PIC-ul, am dat comanda de alte doua bucati, poate asta pe care-l am acum are probleme...nu stiu... Link spre comentariu
fratello Postat Octombrie 6, 2014 Partajează Postat Octombrie 6, 2014 Scuze ... sunt 2 lucruri diferite, cred ca le-am amestecat ... Am citit asta : "- Sofian - Am facut modificarea dar nu schimba situatia, tot sacadat imi afiseaza in simulare atunci cand am PWM-ul pornit" si am crezut ca DOAR in simulare sunt probleme. Link spre comentariu
Vezi Muti Postat Octombrie 6, 2014 Partajează Postat Octombrie 6, 2014 unsigned short portb_array[4]; adica ai declarat un array cu elemetele [0][1][2][3]. portb_array[0]= mask(digit);portb_array[1] = mask(digit)&0x7F;portb_array[2] = mask(digit); port_array[3] = ? ... iar in intrerupere ai: my_port( portb_array[portb_index]);portb_index ++;if (portb_index > 3u)portb_index = 0; trimiti functiei my_port si valoare portb_index=3 desi in matricea portb_array ai valori utile numai pentru elementele [0][1][2] cred ca de aici apare problema. te las sa te chinui sa vezi cum se resolva Link spre comentariu
sofian Postat Octombrie 6, 2014 Partajează Postat Octombrie 6, 2014 functia asta nu este buna void display(){ if (number<1000){digit = (number / 100u);if(digit<1){digit=10;portb_array[0]= mask(digit);}elseportb_array[0]= mask(digit);digit = (number / 10u) % 10u;portb_array[1] = mask(digit)&0x7F;digit = ((number)% 10u);portb_array[2] = mask(digit);}else{digit = (number / 1000u)%10u;portb_array[0]= mask(digit);digit = (number / 100u) % 10u;portb_array[1] = mask(digit);digit = (number/10)% 10u;portb_array[2] = mask(digit);}} poti face asa void display(){// afisarea este pe trei digiti, dar tu faci calcule pentru 4 digiti 0..1500mVunsigned int temp;temp = number;digit = (temp % 10);portb_array[0]= mask(digit); // LSBtemp /= 10;digit = (temp % 10);portb_array[1]= mask(digit);temp /= 10;digit = (temp % 10);portb_array[2]= mask(digit);temp /= 10;digit = (temp % 10);portb_array[3]= mask(digit); // MSB} Link spre comentariu
danpin Postat Octombrie 8, 2014 Autor Partajează Postat Octombrie 8, 2014 (editat) Vezi Muti Da, acel 4 in unsigned short portb_array[4]; ramasese pierdut de la incercarile pe care le facusem inainte, am schimbat cu 3 sofian Se poate face si cum ai propus tu, dar trebuie sa modific sa nu-mi afiseze zero in fata unitatilor cand temperatura e <10 grade, sa mai modific sa afiseze punctul zecimal si temperaturi >99 grade. Pot sa fac cu if sau cu switch, pt. zero am facut, mai urmeaza sa modific sa-mi afiseze corect T>99. Oricum, cu toate modificarile sugerate in simulare tot sacadat arata cifrele, posibil si din cauza simulatorului cum a spus fratello. Editat Octombrie 8, 2014 de danpin Link spre comentariu
sofian Postat Octombrie 8, 2014 Partajează Postat Octombrie 8, 2014 Sa nu mai apara sacadat trebuie: in simulator setat frecventa procesorului 8Mhz cum este la tine intrerupere timer0 de 1mS OPTION_REG = 0b11000011; // clockout/16 (2Mhz/16=125000Hz)TMR0 = 256-125; // INT la fiecare 1mS(1000Hz) Link spre comentariu
danpin Postat Octombrie 10, 2014 Autor Partajează Postat Octombrie 10, 2014 void display(){ if (number<1000) { digit = (number / 100u); if(digit<1) { digit=10; portb_array[0]= mask(digit); } else portb_array[0]= mask(digit); digit = (number / 10u) % 10u; portb_array[1] = mask(digit)&0x7F; digit = ((number)% 10u); portb_array[2] = mask(digit); } else { digit = (number / 1000u)%10u; portb_array[0]= mask(digit); digit = (number / 100u) % 10u; portb_array[1] = mask(digit); digit = (number/10)% 10u; portb_array[2] = mask(digit); }} void display(){ unsigned int temp, x, y; temp = number; x=temp/1000; switch (x){ case 0: digit = (temp % 10); portb_array[2]= mask(digit); temp /= 10; digit = (temp % 10); portb_array[1]= mask(digit)&0x7F; temp /= 10; y=temp/10; switch (y) { case 1: digit = 10; portb_array[0]= mask(digit); break; case 0: digit = (temp % 10); portb_array[0]= mask(digit); break; } break; case 1: temp /= 10; digit = (temp % 10); portb_array[2]= mask(digit); temp /= 10; digit = (temp % 10); portb_array[1]= mask(digit); temp /= 10; digit = (temp % 10); portb_array[0]= mask(digit); break; }} Care din cele doua variante pt. functia display ar fi mai buna/corecta? 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