MicroC PIC pitanja

Rasprava o PIC mikrokontrolerima, PIC projekti i drugo vezano za PIC-eve...

Moderators: pedja089, stojke369, [eDo], trax

Post Reply
User avatar
rajac
Napredujem
Napredujem
Posts: 129
Joined: 11-03-2009, 19:01

MicroC PIC pitanja

Post by rajac »

Evo počeo malo proučavat gore navedeno(šteta šta nema kurs za mikroC kao za PBP),došo do interapta(konkretno Timer0),i tu mi ne radi dio koda.Na PIC16F877A(na 4 Mhz) na portu B i D spojeni su (bez multipleksa dakle) po jedan 7seg display(zajednička katoda,anode na pinovima 0-7).Na portu C na pinovima 2 i 3 spojeni tasteri sa pulldown otpornicima.Nakon paljenja "uređaja" na displayu(jedan prikazuje desetice,drugi jedinice) se pokaže nula.Jedan od tastera glumi start/stop tipku,drugi taster glumi reset tipku. Pritiskom na prvi taster broj na displeyu se svake sekunde uveća za 1 dok ne dođe do 99 pa opet kreće od nule. Pritiskom na start/stop taster u svakom trenutku se može zaustaviti i ponovo nastaviti uvećavanje broja.Pritiskom na reset tipku displey se postavi u nulu i ostaje sve dok se ponovo ne stisne start/stop tipka. Vrijeme od 1 sekunde se generira pomoću timera0 i interapta tako da timer svakih 200us radi interapt koji onda uveća brojač br,dok ne dođe do 5000 (5000*200us=1s).
Kod:

Code: Select all

const unsigned short znamenka[]={63,6,91,79,102,109,125,7,127,111};
unsigned short i=0;
unsigned int br=0;
bit  stanje1,stanje2,dozvola;


void main() {
       PORTB=0;
       PORTD=0;
       PORTC=0;
       TRISB=0;
       TRISC=0xFF;
       TRISD=0;
       PORTB=0; //ništa na displayu desetica
       PORTD=znamenka[0];
       stanje1=1;
       stanje2=1;   
       dozvola=0;
       
       OPTION_REG=0b11001111;
       GIE_bit=1;
       PEIE_bit=0;
       TMR0IE_bit=1;
       TMR0=56;
       
    while(1){

      if(PORTC.B2==1&&stanje1==1){  //start/stop tipka
       dozvola=~dozvola;
       stanje1=0;
      }


      if(PORTC.B2==0){
       stanje1=1;
      }

      if(PORTC.B3==1&&stanje2==1){ //reset tipka
       i=0;
       br=0;
       dozvola=0;
       stanje2=0;
      }

      if(PORTC.B3==0){
       stanje2=1;
      }

      /*if(br==5000){                 //generiranje 1 sekunde-svaki put kad br
       br=0;                        //dostigne vrijednost 5000, i se uveća za 1
        if(i>=99){                  //ukoliko i prijeđe 99 vraća se na nulu.
         i=0;                       //program radi sa uvjetom if(br>=5000),ali
        }                           //ne radi sa br==5000
        else{
         i++;
        }
      }*/



      if(i<10){
       PORTB=0; //kad je brojač <10,na displayu desetica se ne prikazuje ništa
      }
      else{
       PORTB=znamenka[i/10]; //izvlačenje 1. znamenke brojača (i)
      }

       PORTD=znamenka[i%10]; //izvlačenje 2. znamenke brojača (i)

    }
}

void interrupt(){
  if(TMR0IF_bit){    //nije portebno ako je samo TMR0 izvor inerrupta
    if(dozvola==1){
     br++;
      if(br==5000){      //isti kod za generiranje sekunde kao gore,ali u
       br=0;                //u interaptu.U ovom slučaju program radi.
        if(i>=99){        //
         i=0;               //
        }                    //
        else{              //
         i++;              //
        }                   //
      }                     // Zašto ovaj dio koda mora biti u interaptu?
    }
   TMR0=56;
   TMR0IF_bit=0;
  }
}


Problem je što mi nije jasno zašto program ne radi dobro kad dio koda za provjeru stanja brojača br nije u interaptu(u proteusu i na protobordu u tom slučaju ispravno broji do 10-13,svaki put drukčije,a nakon toga jedno 2 minute mu treba da skoči na 14,i onda opet dugo vremena stoji tako itd.).
Kako odrediti koji dio programa treba biti u interaptu a koji ne(znam da treba što manje ,pa sam zato mislio da mi u interaptu bude samo br++ i setovanje tmr bitova)?
abc
Pravo uznapredovao :)
Pravo uznapredovao :)
Posts: 498
Joined: 08-03-2007, 20:19
Location: Hrvatska

Re: MicroC PIC pitanja

Post by abc »

Nemam vremena da proucavam tvoj problem a i ne sluzim se mikroC.

Ovako:

ako koristis interapte ovakve izjave ZABORAVI if(br==5000){ one su uzrok vecine problema zasto.
Koristi br>5000 ili br>=5000.

Interapt zivi svoj zivot koji je buno brzi od onog sto se dogaca u main while petlji.
Recimo u glavnoj petlji nesto radis i nisi dosao do provjere br==5000 a broj je u stvarnosti 4999 dodje do interapta i broj se poveca na 5000 ali tvoj program jos nije dosao do if(br==5000){ a u medjuvremenu se dogodio jos jedan interapt i broj je sada 5001 i tek sada dolazi do if(br==5000){ ali kako ista ne zadovoljava uslov 5001 je veci od 5000 program ne ulazi u izvrsenje komandi ponistavanja br=0; i uvecavanja sekundi vec uvecava brojac i dalje kako ti je br unsigned int uvecavace ga do 65536 i onda pocine od 0. S tim da moze nekada da pogodi u main petlji da je br==5000 panekada i opali kako treba.

Takodje

if(i<10){
PORTB=0; //kad je brojač <10,na displayu desetica se ne prikazuje ništa

Normalno jer si mu rekao da ako je manje od 10 ne izvrsava komandu PORTB=0;

Prije nego sto pocnes ove if preradi program da ti osvjezi PORTB
PORTB=znamenka[i%1];
PORTB=znamenka[i%10];
PORTB=znamenka[i%100];

Trebalo bi da imaju primjer u mikroC za ovo, zasto izmisljas toplu vodu.
Napravi to u multipleksu kao sto se radi. Daj neki primjer iz mikroC da ti to preradimo.
abc
Pravo uznapredovao :)
Pravo uznapredovao :)
Posts: 498
Joined: 08-03-2007, 20:19
Location: Hrvatska

Re: MicroC PIC pitanja

Post by abc »

Ukratko uzmes pravi C kompajler ;)

pa definises na pocetku

Code: Select all

#define	segments	PORTC
#define common_1 	RB2
#define common_2	RB3
#define common_3 	RB4
#define common_4  	RB5
#define common_5 	RB6
#define common_6        RB7
 
unsigned char	        display_segment_6,
				display_segment_5,
				display_segment_4,	
				display_segment_3,
				display_segment_2,
				display_segment_1,
				mux_common;
Pa onda u interaptu

Code: Select all

if(TMR2IF){
	TMR2IF = 0;			// Clear TMR2 interrupt
	
	mux_common++;			// Move onto to next display

	if(mux_common == 6)		// Reset display selection after the 6-th display
		mux_common = 0;
	segments = 0;			// Turn off all 7 segments and decimal point
	common_1 = 1;
	common_2 = 1;
	common_3 = 1;
	common_4 = 1;
	common_5 = 1;
	common_6 = 1;	
	if(mux_common == 0){		// Turn on Common 1 if first display is selected
		segments = display_segment_1;	// Turn on the segments for display 1
		common_1 = 0;
		}
	if(mux_common == 1){		// Turn on Common 2 if second display is selected
		segments = display_segment_2;	// Turn on the segments for display 2
		common_2 = 0;
		}
	if(mux_common == 2){		// Turn on Common 3 if third display is selected
		segments = display_segment_3;	// Turn on the segments for display 3
		common_3 = 0;
		}
	if(mux_common == 3){		// Turn on Common 4 if third display is selected
		segments = display_segment_4;	// Turn on the segments for display 4
		common_4 = 0;
		}
	if(mux_common == 4){		// Turn on Common 5 if third display is selected
		segments = display_segment_5;	// Turn on the segments for display 5
		common_5 = 0;
		}
	if(mux_common == 5){		// Turn on Common 6 if third display is selected
		segments = display_segment_6;	// Turn on the segments for display 6
		common_6 = 0;
		}

}

I na kraju u main u glavnoj petlji "mrvis" polako broj koji treba da pokazes na displeju

Code: Select all

void  displej(unsigned long display_value){
unsigned char	temp;

	temp = 0;
	while (display_value >99999){
			temp++;
			display_value -= 100000;
			}
		display_segment_6 = segment_decoder[temp];
		temp = 0;

	while (display_value >9999){
			temp++;
			display_value -= 10000;
			}
		display_segment_5 = segment_decoder[temp];
		temp = 0;
	
	while (display_value >999){
			temp++;
			display_value -= 1000;
			}
		display_segment_4 = segment_decoder[temp];
		temp = 0;
	
	while (display_value >99){
			temp++;
			display_value -= 100;
			}
		display_segment_3 = segment_decoder[temp];
		temp = 0;

	while (display_value > 9){
			temp++;
			display_value -= 10;
			}
	display_segment_2 = segment_decoder[temp];
	display_segment_1 = segment_decoder[(unsigned char)display_value];
		
	}
segment_decoder ti je polje iz kojeg ocitava sta ce upucati u tekuci digit 7 displeja.

Da te ne buni toliki kod u interaptu to radi provjereno na 4MHz na piconjama, izvrsava se samo dio koda ostali se preskace. Uostalom prouci malo pa ce ti biti jasnije imas komentare sa strane. Zasto one while petlje za djeljenje zato sto su nekada C kompajleri bili prilicno "glupi" pa se onda tako dobivao kraci i brzi kod.
User avatar
rajac
Napredujem
Napredujem
Posts: 129
Joined: 11-03-2009, 19:01

Re: MicroC PIC pitanja

Post by rajac »

abc wrote:

ako koristis interapte ovakve izjave ZABORAVI if(br==5000){ one su uzrok vecine problema zasto.
Koristi br>5000 ili br>=5000.
Zašto onda u primjeru iz e-knjige sa mikroe stranice
http://www.mikroe.com/eng/chapters/view ... -examples/
ima vrlo sličan primjer za interapt i koristi se ==?

Code: Select all

unsigned cnt;                 // Define variable cnt

void interrupt() {
    cnt++;                    // Interrupt causes cnt to be incremented by 1
    TMR0 = 96;                // Timer TMR0 is returned its initial value
    INTCON = 0x20;            // Bit T0IE is set, bit T0IF is cleared
}

void main() {
    OPTION_REG = 0x84;        // Prescaler is assigned to timer TMR0
    ANSEL = 0;                // All I/O pins are configured as digital
    ANSELH = 0;
    TRISB = 0;                // All port B pins are configured as outputs
    PORTB = 0x0;              // Reset port B
    TMR0 = 96;                // Timer T0 counts from 96 to 255
    INTCON = 0xA0;            // Enable interrupt TMR0
    cnt = 0;                  // Variable cnt is assigned a 0
    
    do {                      // Endless loop
        if (cnt == 400) {     // Increment port B after 400 interrupts
            PORTB = PORTB++;  // Increment number on port B by 1
            cnt = 0;          // Reset variable cnt
        }
    } while(1);
}
abc wrote:
Interapt zivi svoj zivot koji je buno brzi od onog sto se dogaca u main while petlji.
Recimo u glavnoj petlji nesto radis i nisi dosao do provjere br==5000 a broj je u stvarnosti 4999 dodje do interapta i broj se poveca na 5000 ali tvoj program jos nije dosao do if(br==5000){ a u medjuvremenu se dogodio jos jedan interapt i broj je sada 5001 i tek sada dolazi do if(br==5000){ ali kako ista ne zadovoljava uslov 5001 je veci od 5000 program ne ulazi u izvrsenje komandi ponistavanja br=0; i uvecavanja sekundi vec uvecava brojac i dalje kako ti je br unsigned int uvecavace ga do 65536 i onda pocine od 0. S tim da moze nekada da pogodi u main petlji da je br==5000 panekada i opali kako treba.
Sve to sam pretpostavljao i logično je,zato sam i stavio te provjere brojača u interapt i onda radi(radi i sa If(br>=5000) u mainu,ali to bi teoretski moglo nakon dužeg vremena izazvati nepreciznost,da je u pitanju neki 24h timer ili sl.),sad kad razmislim i osvježavanje displeja bi također trebalo biti u interaptu,jer bi se interapt mogao dogoditi između osvježavanja desetica i jedinica u glavnom programu(to bi značilo da brojka na displeju sa npr. 14 skoči na 16).Moje pitanje je bilo koliko koda se smije staviti u interapt.
abc wrote:
Takodje

if(i<10){
PORTB=0; //kad je brojač <10,na displayu desetica se ne prikazuje ništa

Normalno jer si mu rekao da ako je manje od 10 ne izvrsava komandu PORTB=0;
To sam namjerno napravio,nije to greška,to služi da kad je broj manji od 10 ne prikazuje ispred nulu(bez tog bi na displeju za i=5 prikazalo 05,a ovako prikazuje samo 5,čisto vježbe radi sam tako zamislio zadatak).
abc wrote:
Prije nego sto pocnes ove if preradi program da ti osvjezi PORTB
PORTB=znamenka[i%1];
PORTB=znamenka[i%10];
PORTB=znamenka[i%100];

Trebalo bi da imaju primjer u mikroC za ovo, zasto izmisljas toplu vodu.
Napravi to u multipleksu kao sto se radi. Daj neki primjer iz mikroC da ti to preradimo.
NIje sad uopće bitan multipleks,posebno drajvam displeje jer mi je ostalo tako na protobordu spojeno,da sad ne rastavljam.Nisu mi jasna ova tri PORTB-a gore,jel to za trocifreni displej?Ako je (i) npr. 45 i%i=0, i%10=5, i%100=45, to ne izvlači dobro znamenke.
abc
Pravo uznapredovao :)
Pravo uznapredovao :)
Posts: 498
Joined: 08-03-2007, 20:19
Location: Hrvatska

Re: MicroC PIC pitanja

Post by abc »

Evo da ne vodim monolog provuci ovaj kod kroz simulator i usporedi da li su cnt_orig == cnt_contr

Ako ima neka greskica ispravi

Code: Select all

unsigned int cnt=0,cnt_1=0,cnt_orig=0,cnt_contr=0;                 // Define variable cnt
unsigned int br=0, i=0;
void interrupt() {
    cnt++;                    // Interrupt causes cnt to be incremented by 1
    cnt_1++;
    if (cnt_1 == 400) {   
	       cnt_1=0;	   
               cnt_contr++;
        }	
    TMR0 = 96;                // Timer TMR0 is returned its initial value
    INTCON = 0x20;            // Bit T0IE is set, bit T0IF is cleared
}

void main() {
    OPTION_REG = 0x84;        // Prescaler is assigned to timer TMR0
    ANSEL = 0;                // All I/O pins are configured as digital
    ANSELH = 0;
    TRISB = 0;                // All port B pins are configured as outputs
    PORTB = 0x0;              // Reset port B
    TMR0 = 96;                // Timer T0 counts from 96 to 255
    INTCON = 0xA0;            // Enable interrupt TMR0
    cnt = 0;                  // Variable cnt is assigned a 0
   
    do {                      // Endless loop
        if (cnt == 400) {     // Increment port B after 400 interrupts
            PORTB = PORTB++;  // Increment number on port B by 1
            cnt = 0;          // Reset variable cnt
	    cnt_orig++; 	
         }
	//ovdje nafiluj kod
	i++;                 //ovo je samo da pic nesto radi
        br=i/10; 
        br=i%10; 
	br=i%100; 
        br=i%1000; 
	br=i%10000;
        
    } while(1);
}
abc
Pravo uznapredovao :)
Pravo uznapredovao :)
Posts: 498
Joined: 08-03-2007, 20:19
Location: Hrvatska

Re: MicroC PIC pitanja

Post by abc »

Jos malo mog monologa ako te mrzi da napravis simulaciju gornjeg koda(nekoliko linija koda dodano mikroC primeru) onda jos dodaj u petlju da sam pic provjerava da li su oba brojaca ista i upali ledicu.

if(cnt_orig != cnt_contr){
//ovdje kod da upali led
// izvrsava samo ako je tazlika izmedju ove dve varijable
}


Koliko koda moze u interapt, sve zavisi sta radis, moze jako puno ako ti tajmer koji startuje interapt
namesten na nekoliko ms. Ako je kao kod tebe uS(moram reci prilicno smelo za tako slabasan pic) onda relativno malo.

Inace sto se greske mjerenja tice ti si ju napravio vec sto si uzeo TMR0, samo ucitavanje vrednosti ti unosi gresku jer tih nekoliko ciklusa pica dok to uradi mljecni put nece zaustaviti protok vremena;)

Da bi imao najmanju gresku kod mjerenja uzimas 16bitne ili vece tajmere i recimo ocitas ih ako naprave roll off zabiljezis interapt i izracunas ili capture modul ili TMR2 u koji se sam kod inicijalizacije upuca vrednost i dalje sve radi sam.

Zasto radi == kod mikroC primera, zato sto je izvrsavanje programa u glavnoj petlji krace nego u interaptu, a zasto su tako napisali , pretpostavljam imaju forum pa da im korisnici "prave promaju" na forumu kad pocnu da pisu svoj program ,a oni malo zarade od reklama;)
Post Reply