Sida 1 av 1
Interrupt i mikroC / Extern interrupt?
Postat: 9 februari 2008, 18:58:41
av gustavn
Jag har en quadrature encoder med 3600 pulser/varv som jag vill läsa av med en PIC 16f877A @ 20Mhz. Jag vill räkna pulserna och visa dom på en display, detta har jag fått att fungera genom att sätta A och B pinnen från encodern till två vanliga digitala ingångar. Problemet är att under den tid det tar att skriva ut antalet pulser på displayen så missar räknaren pulser.
Så till frågan, hur ska man lösa detta på effektivast sätt?
Edit: Glömde skriva att jag använder mikroC.
Postat: 9 februari 2008, 19:20:30
av Icecap
Man löser det vid att ha 1 interrupt!
Den sitter på ena pulståget och vid interrupt kollar den fasen på andra pulsen, då vet den om det är + eller -.
En variabel (X) räknas då upp eller ner enl. detta.
Sedan gör ISR inget mer!
I mainloopen har du en annan variabel (Y):
Kod: Markera allt
if(X != Y)
{
Y = X;
printf(Display,Y); // Nåja, du fattar nog...
}
På det sätt är ISR'n snabb och utläsningen tar den tid den tar.
Postat: 9 februari 2008, 19:30:49
av gustavn
Tack Icecap!
Hur löser man det praktiskt med själva interrupt-inkopplingen? Jag har läst i databladet att det finns en pinne RB0/INT, är det den som man ska koppla in pulståget på?
Postat: 9 februari 2008, 19:35:21
av Icecap
Det kan vara ett sätt, sedan väljer man rätt interrupt-enable och kör.
Postat: 9 februari 2008, 19:51:03
av gustavn
Tack, för snabbt svar, nu fungerar det! Men en konstig sak är att det bara verkar vara 1800 pulser / varv. Har provat att vrida motor axeln precis ett varv och den visar då ca 1800. Vad kan det bero på? Om det är av intresse så ser min kod ut så här:
Kod: Markera allt
char *siffra[7];
int i=0;
void interrupt(){
INTCON.INTE = 0;
if(PORTD.F3==0){
i++;
}
else{
i--;
}
INTCON.INTE = 1;
INTCON.INTF = 0;
}
void main(){
INTCON.INTE = 1;
INTCON.PEIE = 1;
INTCON.GIE = 1;
OPTION_REG.INTEDG = 1;
PORTB = 0;
TRISB = 1;
PORTD = 0;
TRISD = 8;
Lcd_Config(&PORTB,2,3,0,7,6,5,4);
Lcd_Init(&PORTB);
Lcd_Cmd(LCD_CURSOR_OFF);
while(1){
IntToStr(i,siffra);
Lcd_Out(2,4,siffra);
}
}
Postat: 9 februari 2008, 19:55:21
av sodjan
Du får bara positiva *eller* negativa flanker. Sannolikt så räknar
tillverkaren med båda. Du kan vid varje interrupt ställa om INTEDG
dynamiskt så att du fångar båda flankerna, om det nu spelar någon roll...
Postat: 9 februari 2008, 20:01:49
av Icecap
Kod: Markera allt
void interrupt(VOID)
{
INTCON.INTE = 0; // VARFÖR?
if(!PORTD.F3)
{
i++;
}
else
{
i--;
}
INTCON.INTE = 1; // VARFÖR?
INTCON.INTF = 0; // VARFÖR? Edit: Därför!!!
}
Varför har du med dessa INTCON-grejer?
Du har 3600 pulser om du räknar alla fram (eller bak) flankor på båda pulstågen. Du kan åstadkomma det vid att ha 2 interrupt som räknar på ovanstående sätt.
Postat: 9 februari 2008, 20:08:08
av gustavn
INTCON.INTE = 0; och INTCON.INTE = 1;
Har jag med för att det inte ska kunna bli en interrupt till innan den aktuella interrupten har räknats. Vet inte om det är nödvändigt.
INTCON.INTF = 0; Har jag med efter att ha läst detta i databladet:
INTF: RB0/INT External Interrupt Flag bit
1 = The RB0/INT external interrupt occurred (must be cleared in software)
0 = The RB0/INT external interrupt did not occur
Postat: 9 februari 2008, 20:22:12
av Icecap
.INTF-flaggan ska nollas av mjukvaran, mitt fel.
Men låt bli .INTE i interrupten, den ställer man i initialiseringen och sedan får det räcka.
Postat: 9 februari 2008, 20:27:51
av gustavn
Ok Tack!, då ändrar jag det.
Finns det fler interrupt-pinnar än RB0/INT jag kan använda?
Jag har sett att det står i databladet att det finns 15 interrupts på 16f877A men vet inte vilka som dom menar förutom RB0/INT?
Postat: 10 februari 2008, 01:04:26
av sodjan
> Jag har sett att det står i databladet att det finns 15 interrupts på 16f877A
> men vet inte vilka som dom menar förutom RB0/INT?
Figure 14-10. (*SÅ* svart var det väl inte att se...

)
> Finns det fler interrupt-pinnar än RB0/INT jag kan använda?
Se kapitel 14.11.3. Vet dock inte om det passar in på ditt fall. Kanske...