Sari la conținut
ELFORUM - Forumul electronistilor

Termometru PIC16F690 afisaj 7SEG+LM35


Postări Recomandate

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

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 de bratueduard
Link spre comentariu

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

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

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

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

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

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

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 de danpin
Link spre comentariu
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

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