Sida 1 av 2
C-program som fastnar i avbrottsrutinen? PIC16F870
Postat: 6 februari 2008, 12:12:50
av StRob
Jag får inte programmet att gå in i while(1)-loopen i main. Avbrotten fungerar fint. Både för 10ms avbrott och tangenttryck. och 20ms efter tangenttrycket togglar den pinnen på PORTA igen som den ska. Då borde den även sätta flaggan och således gå till ReadKeyboard()?!?
Jag har en ICD2 och när jag lägger in breakpoint där ReadButtonFlag sätts och stegar där ifrån så fungerar det. Skumt! Nån som vet vad jag gör fel? JAg har bara med avbrottsrutinen och main för att spara plats. Vill ni se nåt annat så säg bara till.
Kod: Markera allt
/***************************************************************************************
* Avbrottsrutin *
***************************************************************************************/
#pragma origin 4
extern interrupt isr (void)
{
clrwdt ();
char save_FSR;
int_save_registers //Spara viktiga register
save_FSR = FSR;
byte temp;
if(RBIF && RBIE) //Avbrott för knapptryck
{
ButtonDelay = DEBOUNCE_TIME; //Ladda knappstudstimern.
ButtonFlag = 1; //Flagga för knapptryckning.
temp = PORTB; //Läs PORTB för att nollställa missmatch-villkoret.
RBIF = 0; //Nollställ avbrottsflaggan.
RA1 = !RA1; //TEST TEST TEST TEST TEST TEST TEST TEST TEST !!!!!!!!!!!!!!!!
}
if(CCP1IF && CCP1IE) //Interrupt varje ms.
{
CCP1IF = 0; //Viktig! Annars genereras avbrott så fort den kommer ur avbrottsrutinen.
ms--; //Nollställs och disablas efter DCF
RA0 = !RA0; //10ms-TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST !!!!!!!!!!!!!!!!
if(ms <= 0)
{
ms = 1000;
sekund++;
if(sekund >= 60)
{
sekund = 0;
}
}
if(ButtonFlag)
{
ButtonDelay--;
if(ButtonDelay <= 0) //Har knappstudsdelayen räknat färdigt?
{
nop();
ButtonFlag = 0; //Nollställ knapptryckningen.
ReadButtonFlag = 1; //Ja, Flagga för läsning av tangentbordet.
RA1 = !RA1; //TEST TEST TEST TEST TEST TEST TEST TEST TEST !!!!!!!!!!!!!!!!
}
}
}
end:
FSR = save_FSR;
int_restore_registers //Hämta sparade register
}
/***************************************************************
* Main program starts here. (Also RESET entry point) *
**************************************************************/
void main (void)
{
GIE = 0;
vFirstInit(); //Initiera µP
UARTinit(); //Initiera UART
timer1init(); //Initiera Timer1
ms = 0x01; //Sätter ms till 1 för att sekund ska börja på 0.
sekund = 0;
PORTB = 0b00000000; //Aktrivera tangentbordet. Nollar egentligen bara RB0-RB3
temp1 = PORTB; //Sätt normalläge för tangentbordet.
ButtonFlag = 0;
ReadButtonFlag = 0;
RBIF = 0;
RBIE = 1;
TMR1ON = 1; //Starta timer1
PEIE = 1;
GIE = 1;
while(1) //Evighetsloop. Ligger och väntar på avbrott.
{
RA0 = !RA0; //TEST TEST TEST TEST TEST TEST TEST TEST TEST !!!!!!!!!!!!!!!!
if(ReadButtonFlag) //kollar flaggan för tangentbordsavkodning.
{
ReadKeyboard(); //Läs av tangentbordet.
// PWRDown(); //Sleep till nästa tangenttryck
}
}
}
Postat: 6 februari 2008, 13:34:44
av StRob
Jag provade att toggla en pinne varje gång jag kommer in i avbrottsrutinen och det visade sig att programmet genererar avbrott var 22:a µs.. Därför kommer den aldrig ur avbrottsrutinen.. Ska gräva vidare och se vad det är som genererar avbrott. slänger in mina initieringar så kanske nån är vaksam på vad det är..
Kod: Markera allt
/*******************************************************
* Power-up init *
*******************************************************/
void vFirstInit(void)
{
int W = 0;
// Set up I/O pins
PORTA = 0;
PORTB = 0b00001111; //Sätter utgångarna höga för att inaktivera tangentbordet.
PORTC = 0;
// RB<0-3> as outputs.
// RA<0-7> as outputs.
TRISA = 0b00000000; //Outputs
TRISB = 0b11110000; //0-3=Outputs, 4-7=Inputs. Keyboard
TRISC = 0b10000000; //Outputs. RC6 = TX = 0, RC7 = RX = 1.
// Set up the OPTION register
// Bit 7 = /RBPU = 0, internal pull-ups enabled
// Bit 6 = INTEDG = 0, interupt on falling edge of RB0/INT pin
// Bit 5 = T0CS = 0, internal TMR0 clock (Fxtal/4)
// Bit 4 = T0SE = 0, rising edge on T0CKI increments TMR0
// Bit 3 = PSA = 0, prescaler assigned to TMR0
// Bit 2..0 = PS2..PS0 = 111, prescaler = 1:256
ADCON1 = 0x06; //PORTA är digitala in och utgångar, inga analoga ingångar.
OPTION = 0b00000111; //Pull-up på PORTB, 1:256 prescaler på TIMER0.
CCP1CON = 0b00001011; // CCPR1 == TMR1 resets timer1 and set CCP1IF.
// Set up the PIE1 register (Avbrottsregister)
//
// Bit 7 = EEIE = 0, EE Write complete Interrupt Enable bit
// Bit 6 = CMIE = 0, CMIE Comparator Interrupt Enable
// Bit 5 = RCIE = 0, USART Recieve Interrupt Enable bit
// Bit 4 = TXIE = 0, USART Transmitt Interrupt Enable bit
// Bit 3 = Unimplemented, read as 0
// Bit 2 = CCP1IE = 0, CCP1 Interrupt Enable
// Bit 1 = TMR2IE = 1, TMR2 to PR2 Match Interrupt Enable bit
// Bit 0 = TMR1IE = 1, TMR1 Overflow Inerrupt Enable bit
PIE1 = 0b00010100; //Enabla UART Recieve interrupt, CCP1, Timer2, Timer1 overflow
PIR1 = 0b00000000; //Nollställ alla avbrottsflaggor (TMR1IF flagga OF bit 0)
CCPR1H = 0x2F; //Sätter tiden för CCP1-interrupt på 10ms. (CCPR1H = 0x04; CCPR1L = 0xCC; för 1ms)
CCPR1L = 0xF8;
//Set up
ButtonFlag = 0; //Indikerar knapptryckning.
ReadButtonFlag = 0; //Indikerar att debounce-timern räknat klart och det är dags för avläsning av tangentbordet.
}
/************************************************************
* Initiering av Timer1 *
***********************************************************/
// T1CON: Set up the TIMER1 control register.
// Bit 7..6 = U = 00, Unimplemented, Read as '0'
// Bit 5..4 = T1CKPS1..T1CKPS0 = 10, Prescaler = 1:4 ( (Fosc/4)/prescaler ) = 1.25MHz
// Bit 3 = T1OSCEN = 0, TIMER1 Oscillator Enable Control bit
// Bit 2 = /T1SYNC = 0, TIMER1 External Clock Input Synchronization Control bit
// Bit 1 = TMR1CS = 0, TIMER1 Clock Source Select bit, 0 = internal CK (Fosc/4), (Timer mode)
// Bit 0 = TMR1ON = 0, TIMER1 On bit, Enables TIMER1
// INTCON: Set up the Interrupt control register.
// Bit 7 = GIE = 0 Global Interrupt Enable bit
// Bit 6 = PEIE = 0, Peripheral Interrupt Enable bit
// Bit 5 = T0IE = 0, Timer0 Overflow Interupt Enable bit
// Bit 4 = INTE = 0, RB0/INT External Interrupt Eable bit
// Bit 3 = RBIE = 1, RB port change Interrupt Enable bit
// Bit 2 = T0IF = 0, Timer0 Overflow Flag bit
// Bit 1 = INTF = 0, RB0/INT Interrupt Flag bit
// Bit 0 = RBIF = 0, RB Port change Flag bit
void timer1init(void)
{ //Starta timer1 när STX mottagits och stoppa och preset timern när DCF är klar.
INTCON = 0b00000000; //Enable interrupts on port change - PORTB
TMR1L = 0x00;
TMR1H = 0x00;
TMR1L = 0x00;
T1CON = 0b00000100; //Initiering av TIMER1. Bit0 On/off. Ingen Prescaler (Fosc/4)
//TIMER2 Init:
T2CON = 0b01111111; //Postscaler = 1/16, Prescaler = 1/16 ==> T2OF = 3,33ms
}
/**********************************************************
* Initiering av UART *
**********************************************************/
// Set up the TXSTA register
//
// Bit 7 = CSRC = 0, Clock Source Select bit, Asynchronous = Don´t care
// Bit 6 = TX9 = 0, 9-bit Transmit Enable bit, 8-bit = 0
// Bit 5 = TXEN = 1, Transmit Enable bit
// Bit 4 = SYNC = 0, USART Mode Select bit. Asynchronous mode = 0
// Bit 3 = Unimplemented, Read as ´0´
// Bit 2 = BRGH = 0, High Boud Rate Select bit. High speed = 1
// Bit 1 = TRMT = 1, Transmit Shift Register Status bit (Read only). 1 = TSR Empty
// Bit 0 = TX9D = 0, 9th bit of transmit data. Can be parity bit
// Set up the RCSTA register
//
// Bit 7 = SPEN = 1, Serial Port Enable bit. 1 = enable
// Bit 6 = TX9 = 0, 9-bit Receive Enable bit, 8-bit = 0
// Bit 5 = SREN = 0, Single Receive Enable bit. Asynchronous mode: Don´t care
// Bit 4 = CREN = 1, Continuous Receive Enable bit. Asynchronous mode: 1 = Enable Cont. Receive
// Bit 3 = ADEN = 0, Address Detect Enable bit. Unused in 8-bit Asynchronous mode.
// Bit 2 = FERR = 0, Framing Error Bit. 0 = No Framing Error
// Bit 1 = OERR = 0, Overrun Error Bit. 0 = No overrun eror
// Bit 0 = RX9D = 0, 9th bit of receive data. Can be parity bit
void UARTinit(void)
{
SPBRG = 31; //SPBRG = 31. Baud rate = 9600, 63 = 4800, 255 = 1200.
TXSTA = 0b00100110;
RCSTA = 0b10010000; //Enable RX.
}
//*****************************************************************
Postat: 6 februari 2008, 13:45:05
av maha
Nu är jag inte så insatt just PIC-programmering men på vissa platformar måste man väl manuellt nollställa interrupt-flaggan för att inte hamna in igen, vet som sagt inte hur det är i PIC-världen dock.
Postat: 6 februari 2008, 13:50:53
av SmourF
de e helt rätt

att man man mste nollställa i mjukvaran
hade gärna läst genom proget men blir så förvirrad då du verkar använda en annan typ av compilator, vilken använder du btw ?
MVH
Postat: 6 februari 2008, 13:51:46
av StRob
Så är det även här. Och jag har 2 st (väntade) avbrott och de nollställs direkt i delen för vardera avbrott i avbrottsrutinen.. (lite knepig mening men hoppas du förstår)
RBIF = 0; och CCP1IF = 0;
Postat: 6 februari 2008, 13:53:29
av StRob
SmourF skrev:de e helt rätt

att man man mste nollställa i mjukvaran
hade gärna läst genom proget men blir så förvirrad då du verkar använda en annan typ av compilator, vilken använder du btw ?
MVH
Jag använder CC5X i MPLAB
Postat: 6 februari 2008, 13:57:21
av SmourF
ok, nu orkade jag kika igenom lite din while sats, som sagt ja använder inte den compilatorn och kan inte hur man skriver interrupt i den, men första bilden jag får av det hela är i while satsens if sats, där du skriver
if(ReadButtonFlag)
samtidigt som du nollställer "ReadButtonFlag = 0" i början, så den går ju aldrig in i den, eller är det jag som tänker fel ?
för ReadButtonFlag verkar vara en "variabel" ej "port"
tack i förhand
MVH
EDIT: vid närmare titt, så som jag förstår det går den in i interrupt varje ms, sålänge inte den andra interrupt utlöses, och om ButtonFlag är hög så sätter den "ReadButtonFlag" ? och med det så läser den av tangentbordet, så förstår jag det...
Postat: 6 februari 2008, 14:01:57
av StRob
ReadButtonFlag är en flagga (en global variabel på endast en bit) som sätts i avbrottsrutinen. Tanken är alltså att den ska ligga och polla den flaggan i evighetsloopen i main. Men den kommer aldrig dit för något genererar avbrott som aldrig nollställs.
Postat: 6 februari 2008, 14:08:33
av StRob
Ja då har du greppat det helt rätt.. Knapptryckningen genererar avbrott, men pga knappstudsar vill jag inte läsa tangentbordet förrän efter 20ms. därav alla flaggor

Postat: 6 februari 2008, 14:17:12
av sodjan
Är du säker på att alla xxIE flaggor för *andra* interruptkällor är nollade ?
D.v.s så du inte av misstag får in interrupt för något annat än de två
källorna som du faktiskt tar hand om. I så fall kommer du att ha en
xxIF flagga som kommer att starta om interruptrutinen hela tiden.
Postat: 6 februari 2008, 14:21:15
av StRob
Ja det var det jag också tänkte på så jag började med att sätta PEIE = 0 och då försvann det. så det bör ju vara nåt av dom avbrotten. Så nu sitter jag och testar att stänga av en efter en, men det ser mörkt ut.. Om IE är nollad så sätts inte motsvarande IF eller? Hur som så ska den ju inte generera avbrott för den iaf...
Postat: 6 februari 2008, 14:28:14
av sodjan
> Om IE är nollad så sätts inte motsvarande IF eller?
Var har du läst det ??? Det är i alla fall helt fel.
> Hur som så ska den ju inte generera avbrott för den iaf...
Om xxIE är = "0" så får du inget avbrott, men du kan aldrig stänga av
att xxIF sätt till "1" om/när själva avbrottsvilkoret är uppfyllt.
Det betyder att man bl.a kan :
- Polla xxIF flaggorna istället för att ha en ISR, om man vill det.
- Kan "fördröja" avbrottet genom att stänga av xxIE under en tid, om man vill det.
Så snart xxIE sätts till "1" igen (och xxIF under tidenhar satts till "1") så får du
avbrottet då istället...
Postat: 6 februari 2008, 14:36:46
av StRob
okej. tack. Jag var inte säker så därför kollar jag både IE och IF i avbrottet.
Men såg just att "CCP1IF = 0;" inte fungerar enligt debuggern. Men enligt min togglade pinne så fungerar det ju utmärkt. Det är lite skumt. Men det känns ändå inte som om det är den som ställer till det för då skulle ju inte togglingen fungera så fint på 10ms..
Postat: 6 februari 2008, 14:54:35
av sodjan
> så därför kollar jag både IE och IF i avbrottet.
Och det är helt rätt att göra det !
Om du har stängt av interrupt från en viss källa, så vill du ju inte att
de ska köras "bakvägen" genom att ett annat interrupt triggar ISR'en.
Därför ska man alltid kolla *både* IF och IE flaggan i koden.
Snabbast är att kolla IE först, då behöver man inte kolla IF i onödan.
Om man inte kollar båda flaggorna så skulle man inte kunna stänga
av eller fördröja ett interrupt samtidigt som de andra kör på som vanligt.
ICD och debuggning vet jag inget om, mer än att jag har hört/läst
att det finns vissa begränsningar i vissa funktioner när man debuggar.
Postat: 6 februari 2008, 15:02:55
av StRob
>ICD och debuggning vet jag inget om, mer än att jag har hört/läst
att det finns vissa begränsningar i vissa funktioner när man debuggar.
Oj, skulle jag inte ha debuggern skulle det gå ÄNNU sämre.. Hur kan man överleva utan den???
