Sari la conținut
ELFORUM - Forumul electronistilor

Incubator full-option!


wolfei

Postări Recomandate

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
  • Răspunsuri 40
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • wolfei

    18

  • Liviu M

    10

  • puiu

    6

  • Eugen_B

    5

Top autori în acest subiect

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

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

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

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

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

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

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

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

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

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

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