wolfei Postat Decembrie 31, 2010 Partajează Postat Decembrie 31, 2010 Am de facut un proiect pt fac cu uC si in acelasi timp un prieten m-a rugat sa ii fac un incubator automatizat intr-un frigider vechi, asa ca am decis sa impusc 2 iepuri dintr-o lovitura. O sa ii ridic temp cu o rez cu nichelina iar temp cu un ventilator care va sufla intr-un recipient cu apa. Temp o masor cu LM35 iar umid prin metoda psihometrului, adik inca un LM35 care masoara temp din recipientul cu apa. Am ajuns intr-un impas acum..ouale trebuiesc intoarse odata la 8 ore..si pentru cele 8 ore vreau sa folosesc un timer, timer 0 de exemplu.Am gasit un tutorial aici: http://www.microcontrollerboard.com/pic ... orial.html Conform formulei de acolo am facut urmatoarele calcule: 8ore=28800sec=T f=1/T=3.472*10^-5 Hz=0,000347Hz Clock 20MHz, folosind cllock extern nu se imparte la 4 Folosind formula:f=(20*10^9)/(256*256*count)=0,000347=> count=(20*10^12)/22740992=>count=879469 Asadar ar tr sa numar de 879469 ori ca sa obtin 8 ore folosind codul de acolo. E corect? Va multumesc in avans pentru ajutor! Link spre comentariu
puiu Postat Decembrie 31, 2010 Partajează Postat Decembrie 31, 2010 1. Cred ca mai bine ai face un calendar adica un ceas real si fata de el s-a faci rotirea oulelor. Deci un ceas in care sa ai secunda, minutele, ora si data. Link spre comentariu
wolfei Postat Decembrie 31, 2010 Autor Partajează Postat Decembrie 31, 2010 Multumesc pentru raspuns dar proiectul imi impune sa folosesc timere si intreruperi.Eu joi tr sa predau proiectul si mai am de facut si comanda motoarelor BDLC si stepper in asm...lucru care mi se pare cel mai greu...deoarece in asm nu am lucrat deloc.. Link spre comentariu
puiu Postat Decembrie 31, 2010 Partajează Postat Decembrie 31, 2010 1. Ce PIC folosesti? Link spre comentariu
Eugen_B Postat Decembrie 31, 2010 Partajează Postat Decembrie 31, 2010 Atentie, clock ul nu se imparte la 4 cand e selectat timer-ul sa numere impulsuri externe , tu folosesti clock-ul pic-ului, deci trebuie sa il imparti la 4. Daca ii dai impulsuri separat pe pin-ul de input pentru timer , atunci nu mai trebuie impartit (vezi pagina 47 din datasheet la pic16f877).Oricum , eu as calcula altcumva cat trebuie sa numar.Presupun ca folosesti pic16f877 ( am vazut asta in alt thread).Avand in vedere ca iti trebuie un interval mare de timp , selectezi cel mai mare prescaler posibil.Astfel , tu ai 20Mhz clock , deci o sa ai impulsuri la timer la 5Mhz , adica la 1/5 us (200 ns , asta fara prescaler).Cu prescaler pe maxim (in registrul OPTION_REG, PS2:PS0 =111) , vei avea 1:256 impulsuri de clock , deci 200ns *256= 51.2 us pentru un impuls de clock dupa prescaler.Cum TM0 are 8 biti , vei avea o intrerupere generata la overflow la 256*51.2us adica la 13.3632 ms.Ca sa numeri 8 ore , va trabui sa numeri 8*3600*1000 /13.3632 , adica aproximat 2155172.Avand in vedere ca pentru a reprezenta 2155172 ai nevoie de 17 biti , sa ai grija cu ce numeri , sa fie de 24 sau 32 biti (short long sau long ,nu stiam ca exista short long , dar se pare ca e in manualul de la HI-TECH c). Link spre comentariu
wolfei Postat Decembrie 31, 2010 Autor Partajează Postat Decembrie 31, 2010 Da folosesc pic16f877A..multumesc pt lamuriri eugen..deci orice frecventa as folosi toate se impart la 4...Si acum o intrebare de incepator...in timp ce eu numar de cate ori overflows TIMER0...pot sa fac celelate task-uri?...adica controlul a doua ventilatoare +umiditate si temperatura si transmisie seriala? Link spre comentariu
Eugen_B Postat Decembrie 31, 2010 Partajează Postat Decembrie 31, 2010 Da , setezi timer-ul sa-ti genereze intrerupere la overlow.Astfel o sa-ti apeleze functia definita ca intrerupt handler la fiecare 13 ms. Tu in functia asta doar incrementezi acel numar , si verifici daca a ajuns la valoarea maxima, si daca da il dai la zero si semnalizezi faptul asta. Asta o sa ia cateva instructiuni, cam 2 us la fiecare 13 ms , deci restul timpului poti sa faci altceva. Link spre comentariu
wolfei Postat Decembrie 31, 2010 Autor Partajează Postat Decembrie 31, 2010 Multumesc mult pentru ajutorul acordat...dar am auns la cea mai grea parte...scrisul in assembler..aici sunt chir in plop.. Trebuie sa fac comanda a 2 ventilatoare si un motor stepper... Am gasit un cod pe net care se pare ca functioneaza in Proteus..si vreau sa il incadrez in programul meu dupa ce numar 8 ore sa intorc ouale.. Am folosit #asm si #endasm...dar am o gramada de erori...am cautat pe net sa le rezolv dar scap de unele si dau in altele.. Atasez codul intreg al programului meu..inclusiv partea cu asm... #include <pic.h>__CONFIG(HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGEN & UNPROTECT);#include "delay.h"#include "stdlib.h"#include "delay.c"void initialize(void) { GIE=1; // disable interrupts INTE = 1; ADCS1 = 0; //select Fosc/8 ADCS0 = 1; ADCON1=0; // A/D port configuration 0 ADFM = 1; //right justified result ADON=1; // turn on the AD conversion module }/* return a 10-bit result */unsigned int read_adc(unsigned char channel){ channel&=0x07; // truncate channel to 3 bits ADCON0&=0xC5; // clear current channel select ADCON0|=(channel<<3); // apply the new channel select DelayMs(10); ADGO=1; // initiate conversion on the selected channel while(ADGO)continue; return(((ADRESH&0x03)<<8)+ADRESL); // return the 10-bit result}float temp_usf(void){ int i; float temp_an, temp, temp1; temp_an=0; for(i=0; i<4; i++) { temp_an =temp_an+read_adc(0); DelayMs(5); } temp_an=temp_an/4; temp =temp_an*((5.0*100.0)/1023.0); temp1=temp*100; return(temp1);}float temp_umf(void){ int i; float temp_an, temp, temp2; temp_an=0; for(i=0; i<4; i++) { temp_an =temp_an+read_adc(1); DelayMs(5); } temp_an=temp_an/4; temp =temp_an*((5.0*100.0)/1023.0); temp2=temp*100; return(temp2);}float umiditate(void){ float dif,tempus,tempum; tempus=temp_usf(); tempum=temp_umf(); dif=tempus-tempum;return(dif);}void InitUSART() //rutina de setare si initializare a modulului USART{ //SPBRG=64; //19200 baud la 20 MHz SPBRG=25; //9600 baud la 4 MHz BRGH=1; //high speed SYNC=0; //modul asincron SPEN=1; //activare port serial TXIE=0; //dezactivare intrerupere USART la transmisie TX9=0; //transmisie pe 8 biti TXEN=1; //activare transmisie RCIE=0; //dezactivare intrerupere USART la receptie RX9=0; //receptie pe 8 biti CREN=1; //activare receptie}void TransmitUSART(unsigned char c) //Rutina de transmitere a unui octet la portul serial{ while(!TXIF); //asteapta sa se termine transmisia precedenta TXREG=c; //incarca si transmite noua valoare}void TransmitUSARTC(const char* c){ int i =0; while(c[i]!=0x0 && c[i]!=0xd) { TransmitUSART(c[i]); i++; }// TransmitUSART(0xd);}unsigned char ReceiveUSART() //Rutina pt receptia unui octet de la portul serial{ unsigned char c; while(!RCIF); //asteapta pana se incheie receptia c=RCREG; //octetul receptionat este preluat din RCREG return c; }void afisare_usart(unsigned int i) { int zeci,unitati; zeci = i/10 + 48; unitati = i%10 + 48; while(!TXIF); TXREG = zeci; DelayMs(5); while(!TXIF); TXREG = unitati; }void afisfloat(long i){ int nr1, nr2;nr1=i/100;nr2=i%100; if (nr2>0) { afisare_usart(nr1); TransmitUSARTC(","); afisare_usart(nr2); TransmitUSART(0xd); DelayUs(250); } else { afisare_usart(nr1); TransmitUSART(0xd); DelayUs(250); } }void main(void){float temp_uscat,temp_umed,umid,dif;int temp;long count; initialize(); DelayUs(20); InitUSART(); TRISB = 0x01; TRISC = 0x80; TRISD = 0; TMR0=0; //initiere TMR0 T0CS=0; //clock intern T0SE=0; //numarare pe front crescator PSA=0; //utilizare prescaler PS0=1; PS1=1; //prescaler de 256 PS2=1; while(1){ while (!T0IF); //asteapta pana T0IF=1 T0IF=0; //resetare flag overflow count++; //incrementare if (count==15) { count=0; //aici trebuie sa pun motorul de intoarcere oua #asm CBLOCK 0x10 // ; Temporary storage pos dc1 dc2 ENDC LIST p=16F84 //; PIC16F844 is the target processor // #include "P16F84.INC" ; Include header file CBLOCK 0x10 //; Temporary storage ENDC ORG 0entrypoint goto start ORG 4intvector goto intvector start clrw //; Zero. movwf PORTB //; Ensure PORTB is zero before we enable it. bsf STATUS,RP0 //; Select Bank 1 movlw 0xF0 //; Set port B bits 0-3 as outputs movwf TRISB //; Set TRISB register. bcf STATUS,RP0 //; Select Bank 0 movlw 3 //; Initialize the motor position movwf pos movwf PORTB call delay clrf PORTB //; Motor drive off //;Main loop loop btfss PORTA,0 //; Test clockwise button call stepcw btfss PORTA,1 //; Test anti-clockwise button call stepccw goto loop //;Rotate one step clockwise stepcw bcf STATUS,C //; Clear the carry flag btfsc pos,3 //; Set carry if this bit set bsf STATUS,C rlf pos,W //; Pick up and rotate the motor's current position andlw 0x0F // ; Mask to lower nibble movwf pos movwf PORTB //; Drive the outputs call delay //; Wait clrf PORTB // ; Clear the output return//;Rotate one step counter clockwise stepccw bcf STATUS,C //; Clear the carry flag btfsc pos,0 bsf pos,4 rrf pos,W //; Pick up and rotate the motor's current position andlw 0x0F // ; Mask to lower nibble movwf pos movwf PORTB //; Drive the outputs call delay //; Wait clrf PORTB // ; Clear the output return//; This routine implements the delay between steps,//; and thus controls the motor speed.delay movlw 18 //; Outer loop iteration count movwf dc1 dl1 clrf dc2 //; Initialize inner loopdl2 nop nop decfsz dc2,F goto dl2 decfsz dc1,F goto dl1 return END #endasm } temp_umed=temp_umf(); DelayUs(250); temp_uscat=temp_usf(); DelayUs(250); dif=umiditate(); DelayUs(250); temp=temp_uscat/100; if (temp < 38) //daca temperatura scade sub 38 grade RD6=1; // pornesc rezistenta de nichelina else RD6=0; TransmitUSARTC(" 1.Temperatura uscata este : "); afisfloat(temp_uscat); DelayUs(250); TransmitUSARTC(" 2.Temperatura umeda este : "); afisfloat(temp_umed); DelayUs(250); if ((dif >= 5) & (dif < 5.5)) umid=70; // umiditatea se alege in functie else if ((dif >= 5.5) & (dif < 6 )) umid=65; // de diferenta dintre cele doua temperaturi else if((dif >= 6 ) & (dif < 6.5)) umid=62; // else if((dif >= 6.5) & (dif < 7)) umid=60; // else umid=0; TransmitUSARTC(" 3.Umiditatea este : "); afisfloat(dif); // afisare_usart(dif); DelayUs(250); DelayMs(1000); DelayMs(1000); DelayMs(1000); } } Astept un raspuns! Va multumesc! Link spre comentariu
Eugen_B Postat Decembrie 31, 2010 Partajează Postat Decembrie 31, 2010 Nu ai facut partea cu intreruperea corect. In functia initialize, INTE e pentru intrerupere generata prin semnal pe pin extern ca sa activezi intreruperea la timer overflow trebuie la initializare sa setezi timer-ul , apoi T0IE=1; si apoi GIE=1; dai drumu la general intrerupts dupa ce ai setat restul. Apoi adaugi functia: void intrerupt isr(void) //este apelata cand este generata o intrerupere{ if(T0IF)//intreruperea este generata de timer0 ? { count++; if(count==790){ //de test , ar trebui sa seteze "intoarce" la 10 sec intoarce=1; count=0; } T0IF=0;//am procesat intreruperea, resetam flag-ul pentru a se putea apela din nou }} in main ai trebui sa ai cam asa while(1){ CitestiTemperatura(); AfiseziTemperatura(); ComuniciSerial(); FaciCeMaiTrebuie(); if(intoarce){ intoarce=0; IntoarceOua(); }} cred ca variabila intoarce ar trebui declarata cu volatile, de ex volatile int intoarce; pentru ca compilatorul o sa observe ca nu se schimba in loop-ul principal , si o sa optimizeze codul ceva de genul: if(0) . Daca tot ai facut o functie initialize , de ce nu ai pus in ea si setarile pentru timer? Nu prea inteleg ce e cu atatea delay-uri in loop-ul principal. Daca de exemplu nu vrei sa citesti temperatura de prea multe ori pe secunda, baga si citirea temperaturii ca si intoarcerea oualelor. La asembly nu ma pricep. Link spre comentariu
puiu Postat Ianuarie 1, 2011 Partajează Postat Ianuarie 1, 2011 1. Nu prea este program in ASM. Link spre comentariu
wolfei Postat Ianuarie 2, 2011 Autor Partajează Postat Ianuarie 2, 2011 Pai codul in principal e in C...dar trebuie sa am si bucati de asm...asa ca am vrut sa pun pt motoare codul in assembler..eu am cunostinte minime de assembler dar mie mi s-a parut ca acel cod pentru controlul motorului stepper e in asm. Multumesc pentru sfaturi eugen...am sa fac modificarile necesare...un lucru care nu prea inteleg de ce nu merge este si umiditatea...eu am facut o functie care sa imi trimita diferenta dintre cei 2 senzori de temperatura...si in functie de intervalul in care se afla diferenta...calculez umiditatea..si nu inteleg de ce nu merge sa afisez umiditatea.Este vorba despre bucatica asta de cod, e asa de simplu ca nici nu inteleg ce poate fi gresit... TransmitUSARTC(" 2.Temperatura umeda este : "); afisfloat(temp_umed); DelayUs(250); if ((dif >= 5) & (dif < 5.5)) umid=70; // umiditatea se alege in functie else if ((dif >= 5.5) & (dif < 6 )) umid=65; // de diferenta dintre cele doua temperaturi else if((dif >= 6 ) & (dif < 6.5)) umid=62; // else if((dif >= 6.5) & (dif < 7)) umid=60; // else umid=0; TransmitUSARTC(" 3.Umiditatea este : "); afisfloat(dif); // afisare_usart(dif); DelayUs(250); Link spre comentariu
Eugen_B Postat Ianuarie 2, 2011 Partajează Postat Ianuarie 2, 2011 AND logic este && , & este AND pe biti, la acele if-uri trebuie sa pui &&(desi cred ca ar trebui sa mearga si cu & , pentru ca este intre 2 expresii care dau ori 0 ori 1). Tu afisezi dif in loc de umid. Asta vroiai sa faci ? sau doar ai uitat sa pui umid ? O alta chestie care am observat-o , tu citesti de 2 ori temperatura (umeda si uscata) , a doua oara pentru umiditate, mi se pare inutil , poti sa folosesti valorile citite anterior , adica in loc de : temp_umed=temp_umf(); DelayUs(250); temp_uscat=temp_usf(); DelayUs(250); dif=umiditate(); temp_umed=temp_umf(); DelayUs(250); temp_uscat=temp_usf(); DelayUs(250); dif=temp_uscat-temp_umed; Link spre comentariu
wolfei Postat Ianuarie 2, 2011 Autor Partajează Postat Ianuarie 2, 2011 A ramas asa in codul pe care l-am pus deoarece utima oara am afisat doar dif...sa vad daca e bine calculata si daca e ok afisarea..eu vreau sa afisez umid..Thanks! Link spre comentariu
wolfei Postat Ianuarie 5, 2011 Autor Partajează Postat Ianuarie 5, 2011 Am facut toate modificarile sugerate de eugen...dar nu prea iese... Inca nu reusesc sa inteleg de ce nu merg if-urile alea imbricate...am incercat sa fac cu un sw...dar nu reusesc sa ii dau de cap...am separat primul if sa vad daca merge pe bucatisi imi evalueaza daca dif >5, dar nu vrea sa evalueze daca dif<=5.5..am pus si un alt if: if dif<5.5 sw=1 else sw=2...si sta mereu in sw=2... Deasemenea nu reusesc sa fac intreruprea inca...mai era ceva ce ar fi trebuit sa fac? Multumesc pentru ajutor! #include <pic.h>__CONFIG(HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGEN & UNPROTECT);#include "delay.h"#include "stdlib.h"#include "delay.c"void initialize(void) { GIE=1; // disable interrupts INTE = 1; ADCS1 = 0; //select Fosc/8 ADCS0 = 1; ADCON1=0; // A/D port configuration 0 ADFM = 1; //right justified result ADON=1; // turn on the AD conversion module T0IE=1; TMR0=0; //initiere TMR0 T0CS=0; //clock intern T0SE=0; //numarare pe front crescator PSA=0; //utilizare prescaler PS0=1; PS1=1; //prescaler de 256 PS2=1; }unsigned int read_adc(unsigned char channel){ channel&=0x07; // truncate channel to 3 bits ADCON0&=0xC5; // clear current channel select ADCON0|=(channel<<3); // apply the new channel select DelayMs(10); ADGO=1; // initiate conversion on the selected channel while(ADGO)continue; return(((ADRESH&0x03)<<8)+ADRESL); // return the 10-bit result}float temp_usf(void){ int i; float temp_an, temp, temp1; temp_an=0; for(i=0; i<4; i++) { temp_an =temp_an+read_adc(0); DelayMs(5); } temp_an=temp_an/4; temp =temp_an*((5.0*100.0)/1023.0); temp1=temp*100; return(temp1);}float temp_umf(void){ int i; float temp_an, temp, temp2; temp_an=0; for(i=0; i<4; i++) { temp_an =temp_an+read_adc(1); DelayMs(5); } temp_an=temp_an/4; temp =temp_an*((5.0*100.0)/1023.0); temp2=temp*100; return(temp2);}void InitUSART() //rutina de setare si initializare a modulului USART{ //SPBRG=64; //19200 baud la 20 MHz SPBRG=25; //9600 baud la 4 MHz BRGH=1; //high speed SYNC=0; //modul asincron SPEN=1; //activare port serial TXIE=0; //dezactivare intrerupere USART la transmisie TX9=0; //transmisie pe 8 biti TXEN=1; //activare transmisie RCIE=0; //dezactivare intrerupere USART la receptie RX9=0; //receptie pe 8 biti CREN=1; //activare receptie}void TransmitUSART(unsigned char c) //Rutina de transmitere a unui octet la portul serial{ while(!TXIF); //asteapta sa se termine transmisia precedenta TXREG=c; //incarca si transmite noua valoare}void TransmitUSARTC(const char* c){ int i =0; while(c[i]!=0x0 && c[i]!=0xd) { TransmitUSART(c[i]); i++; }// TransmitUSART(0xd);}unsigned char ReceiveUSART() //Rutina pt receptia unui octet de la portul serial{ unsigned char c; while(!RCIF); //asteapta pana se incheie receptia c=RCREG; //octetul receptionat este preluat din RCREG return c; }void afisare_usart(unsigned int i) { int zeci,unitati; zeci = i/10 + 48; unitati = i%10 + 48; while(!TXIF); TXREG = zeci; DelayMs(5); while(!TXIF); TXREG = unitati; }void afisfloat(long i){ int nr1, nr2;nr1=i/100;nr2=i%100; if (nr2>0) { afisare_usart(nr1); TransmitUSARTC(","); afisare_usart(nr2); TransmitUSART(0xd); DelayUs(250); } else { afisare_usart(nr1); TransmitUSART(0xd); DelayUs(250); } }void interrupt isr(void) //este apelata cand este generata o intrerupere{ int count, intoarce; if(T0IF)//intreruperea este generata de timer0 ? { count++; if(count==790){ //de test , ar trebui sa seteze "intoarce" la 10 sec intoarce=1; count=0; } T0IF=0;//am procesat intreruperea, resetam flag-ul pentru a se putea apela din nou }}volatile int intoarce;void main(void){float temp_uscat,temp_umed,umid;int temp,dif,sw;long count; initialize(); DelayUs(20); InitUSART(); TRISB = 0x01; TRISC = 0x80; TRISD = 0;while(1){ temp_umed=temp_umf(); DelayUs(250); temp_uscat=temp_usf(); DelayUs(250); dif=temp_uscat-temp_umed; DelayUs(250); temp=temp_uscat/100; if (temp < 38) //daca temperatura scade sub 38 grade RD6=1; // pornesc rezistenta de nichelina else RD6=0; TransmitUSARTC(" 1.Temperatura uscata este : "); afisfloat(temp_uscat); DelayUs(250); TransmitUSARTC(" 2.Temperatura umeda este : "); afisfloat(temp_umed); DelayUs(250); if ((dif >= 5) && (dif < 5.5)) umid=70; // umiditatea se alege in functie else if ((dif >= 5.5) && (dif < 6 )) umid=65; // de diferenta dintre cele doua temperaturi else if((dif >= 6 ) && (dif < 6.5)) umid=62; // else if((dif >= 6.5) && (dif < 7)) umid=60; // else umid=0; /* if ((dif >= 5) && (dif < 5.5)) sw =1; // umiditatea se alege in functie else if ((dif >= 5.5) && (dif < 6 )) sw=2; // de diferenta dintre cele doua temperaturi else if((dif >= 6 ) && (dif < 6.5)) sw=3; // else if((dif >= 6.5) && (dif < 7)) sw=4; // else sw=0;switch ( sw ) {case 1: umid=75; break;case 2: umid=65; break;case 3: umid=62; break;case 4: umid=60; break;default: {umid=0;TransmitUSARTC(" eroare ");TransmitUSART(0xd);} break;}*/ TransmitUSARTC(" 3.Diferenta este : "); afisfloat(dif); DelayUs(250); TransmitUSARTC(" 3.Umiditatea este : "); afisare_usart(umid); TransmitUSART(0xd); DelayUs(250); RD5=0; if(intoarce) { intoarce=0; RD5=1; DelayMs(1000); DelayMs(1000); DelayMs(1000); } DelayMs(1000); DelayMs(1000); DelayMs(1000); } } Link spre comentariu
Liviu M Postat Ianuarie 5, 2011 Partajează Postat Ianuarie 5, 2011 Poate din cauza ca ai declarat dif integer (asa ca ((dif>5) && (dif<=5.5)) n-o sa fie niciodata adevarat)?LE Incearca sa actualizezi comentariile din cod, ca te induci singur in eroare (sau ma induci pe mine ). De ex., GIE=1 e activare intreruperi globale, nu deactivare ca la tine in comentariu. 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