Problem med interrupt

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Björne
Inlägg: 19
Blev medlem: 18 april 2008, 19:38:11

Problem med interrupt

Inlägg av Björne »

Tjena, sitter och leker med en PWM styrning för RGB lysdioder, inget märkvärdigt.Men har fastnat vid interrupt funktionen.
När jag trycker på en knapp ändras det mellan olika färger och till sist startas en while loop som dimmar mellan olika färger. Allt funkar bra ända tills att jag startar while loopen, sen slutar interrupt funktionen att funka.
Säkert ett lätt fel att fixa, är rätt ny med programmering. :)

edit*
Så där e hela koden och jag använder en PIC16F777

Kod: Markera allt

#include <htc.h>
#define XTAL_FREQ 8MHZ 
#include "delay.c"

__CONFIG(0x382A);
__CONFIG(0x3EBC);
	int i = 0, j = 0, status0 = 0, status1 = 0,status2 = 0,status3 = 0;
	#define red CCPR2L
	#define green CCPR1L
	#define blue CCPR3L
	#define indikering RA0
void init_setup(void)
{

	ADCON1 = 0x0F; 
	TRISA = 0x00;		
	TRISD = 0x00;
	TRISB = 0x1F;		//RB1 till RB4 knappar
	TRISC = 0x00 ;       
		//Spesifikationer för PWM
	CCP1CON = 0x0C; 	//set CCP1 as PWM		
 	CCP2CON = 0x0C;		//set CCP2 as PWM
	CCP3CON = 0x0C;		//set CCP3 as PWM
	PR2	= 0xFF;				
	T2CON = 0xF8;		//set prescaler to 16, postscaler to 1
	red = 0x00;		// nollställ PWM vid uppstart
    green = 0x00;		// nollställ PWM vid uppstart
	blue = 0x00;		// nollställ PWM vid uppstart
	TMR2ON = 1;			//Starta timer2
		//Interrupt
	GIE = 1;
	RBIE = 0;
	INTEDG = 0;		    //	0 = Interrupt on falling edge of RB0/INT pin
	INT0IE = 1;			// RB0/INT External Interrupt Enable bit
	INT0IF = 0;			// RB0/INT External Interrupt Flag bit
	//indekerings lampa
	indikering = 0;
} 
void Delay(void)
{
DelayMs(200);
}
void puase (int antal)
{
for(j = 0; j<antal; j++)
DelayMs(5);
}

void sequence(int infade, int instop, int inred, int ingreen, int inblue)
{
//while(red != inred && green != ingreen && blue != inblue) ???
while(status3 !=1)
	{
		if(red - inred < 0 )
		red++;
		if(red - inred > 0 )
		red--;
		if(red - inred == 0 )
		status0 = 1;

		if(green - ingreen < 0)
		green++;
		if(green - ingreen > 0 )
		green--;
		if(green - ingreen == 0 )
		status1 = 1;

		if(blue - inblue < 0 )
		blue++;
		if(blue - inblue > 0 )
		blue--;
		if(blue - inblue == 0 )
 		status2 = 1;
			if(status0 == 1 && status1 == 1 && status2 == 1)
			{
			status0 = 0;
			status1 = 0;
			status2 = 0;
			status3 = 1;
			}
		puase(infade);   // fade x 50 ms puase
	}
		status3 = 0;
		indikering = 1;
		puase(instop);   // fade x 50 ms puase
		indikering = 0;
}

void farger(void) //knapp 2	
{
	Delay();
	INT0IF = 0;   //reset interrupt flag
	if( i == 0)
	{
	red = 255;
	green = 0;
	blue = 0;	
	i++;
	}
	else if( i == 1)
	{
	red = 0;
	green = 255;
	blue = 0;	
	i++;	
	}
	else if( i == 2){
	red = 0;
	green = 0;
	blue = 255;
	i++;				
	}
	else if( i == 3){
	red = 0;
	green = 0;
	blue = 0;
	i = 0;
		while(INT0IF==0) // loopar till ny interrupt kommer
		{ 
		sequence(2,0,255,0,0);
		sequence(2,0,255,255,0);
		sequence(2,0,0,255,0);
		sequence(2,0,0,255,255);
		sequence(2,0,0,0,255);	
		sequence(2,0,255,0,255); 
		}		
	}
}
interrupt isr()
{  
	if(RB2 == 0) //knapp 2
 	 farger();
}

void main()
{
init_setup();
	while(1)
	{
	}
}



All hjälp uppskattas!
Senast redigerad av Björne 26 augusti 2008, 17:38:50, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Gör ett litet test-case som visar ditt problem.
Men å andra sidan, du talar ju inte ens om vad det är du kör det på.
Och varför är det uppdelat på två code-taggar ?
Lägg in hela koden (eller ditt test-case) som en komplett kod.
bearing
Inlägg: 11677
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

Det är inte bra att i interruptet vänta in nästa interrupt som du gör i while-loopen. Interruptrutiner ska exekveras snabbt. Gör istället så att du sätter en flagga i interruptet som senare kollas i mainloopen. Anropa sedan sequence() från mainloopen.

INT0 interruptet sker vid påverkan på RB0. Varför kollas RB2?

Ett problem är att du inte nollställer INT0-flaggan efter while-loopen i interruptet vilket gör att interruptrutinen loopas. Möjligtvis är ett annat problem att alla sequence-anrop tar jättelång tid så att while-loopen går runt för sällan.

Tillägg:
Försök minimera antalet globala variabler. Variabeln j kan du t.ex. ha lokal i sin funktion.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Det är knappast det minsta möjliga test-case som visar det aktuella
problemet.

Bearing är sannolikt på rätt spår. Du verkar "köra" dina interrupt
ganska märkligt. Generellt ska man aldrig vänta på någonting inne
i sina ISR'er. Huvudproblemet är nog en galen struktur på det hela.

Du får också förklara RB0/INT resp RB2. Vilket interrupt är det du använder ?

Om du dessutom aldrig returnerar från din ISR så kommer stacken
att gå i taket efter ett tag. Men det borde synas vid körning i MPSIM.

Sen nägra mer generella synpunkter som inte direkt har med det
aktuella problemet att göra...

> __CONFIG(0x382A);
> __CONFIG(0x3EBC);

Finns det inget sätt att ange CONFIG så att det är läsbart vad du gör ?
Sen finns det 2 CONFIG register, tar den där koden automatiskt
hänsyn till det ?

> TRISB = 0x1F;

Använd gärna binära konstanter när du sätter register med individuella bitar.
Samma sak med T2CON lite längre ner.
Björne
Inlägg: 19
Blev medlem: 18 april 2008, 19:38:11

Inlägg av Björne »

INT0 interruptet sker vid påverkan på RB0. Varför kollas RB2?
På min koppling har jag 4 knappar som går till RB1,2,3 och 4, samt alla knapparna är även kopplade till RB0/INT via dioder så de inte påverkar varandra. Så jag får en interrupt på alla knapparna. Har läst nu att det finns någon "interrupt on change" på portB som kanske hade varit bättre men men det funkar bra med.
De andra knapparna ska jag har för fada snabbare/långsammare m.m.

Har försökt att ta till mig de ni har kommenterat, har ändrat i koden så den kör metoderna från main-loopen och inte i interrupten. Tror interrupten funkar som de ska nu, programmet går runt utan att fastna. Men de är lite tråkigt att vänta på att hela while-loopen i farger() ska köras igenom innan den kollar interrupt variablen. Man kanske kan göra någon array med alla sequence värdena, sen skicka man bara en i taget och kollar interrupt variablen efter varje. men jag vet inte :) Är på lite okänt vatten.

Här är den nya koden.

Kod: Markera allt

// PIC16F777
#include <htc.h>
#define XTAL_FREQ 8MHZ 
#include "delay.c"
__CONFIG(UNPROTECT & CCPRC1 & DEBUGDIS & BORDIS & MCLREN & PWRTDIS & WDTDIS & HS); 
__CONFIG(IESODIS & FCMDIS);

int i = 0;
#define red CCPR2L
#define green CCPR1L
#define blue CCPR3L
#define indikering RA0

void init_setup(void)
{
	ADCON1 = 0b00001111; 
	TRISA = 0x00;		
	TRISD = 0x00;		
	TRISB = 0b00011111;  //RB1 till RB4 knappar
	TRISC = 0x00 ;       
		//Spesifikationer för PWM
	CCP1CON = 0x0C; 	//set CCP1 as PWM		
 	CCP2CON = 0x0C;		//set CCP2 as PWM
	CCP3CON = 0x0C;		//set CCP3 as PWM
	PR2	= 0xFF;					
	T2CON = 0b11111000;	//set prescaler to 16, postscaler to 1
	red = 0x00;		// nollställ PWM vid uppstart
    green = 0x00;		// nollställ PWM vid uppstart
	blue = 0x00;		// nollställ PWM vid uppstart
	TMR2ON = 1;			//Starta timer2
		//Interrupt
	GIE = 1;
	RBIE = 0;
	INTEDG = 0;		    //	0 = Interrupt on falling edge of RB0/INT pin
	INT0IE = 1;			// RB0/INT External Interrupt Enable bit
	INT0IF = 0;			// RB0/INT External Interrupt Flag bit
	//indekerings lampa
	indikering = 0;
} 
void Delay(void)
{
DelayMs(200);
}
void puase(int antal)
{
int j;
for(j = 0; j<antal; j++)
DelayMs(5);
}

void sequence(int infade, int instop, int inred, int ingreen, int inblue)
{
int status0 = 0, status1 = 0,status2 = 0,status3 = 0;
//while(red != inred && green != ingreen && blue != inblue) ???
while(status3 !=1)
	{
		if(red - inred < 0 )
		red++;
		if(red - inred > 0 )
		red--;
		if(red - inred == 0 )
		status0 = 1;

		if(green - ingreen < 0)
		green++;
		if(green - ingreen > 0 )
		green--;
		if(green - ingreen == 0 )
		status1 = 1;

		if(blue - inblue < 0 )
		blue++;
		if(blue - inblue > 0 )
		blue--;
		if(blue - inblue == 0 )
 		status2 = 1;
	
		if(status0 == 1 && status1 == 1 && status2 == 1)
		status3 = 1;

		puase(infade);   // fade x 50 ms puase
	}
		status3 = 0;
		indikering = 1;
		puase(instop);   // fade x 50 ms puase
		indikering = 0;
}
void farger(void) //knapp 2	
{
	Delay();  
	if( i == 1)
	{
	red = 255;
	green = 0;
	blue = 0;	
	}
	else if( i == 2)
	{
	red = 0;
	green = 255;
	blue = 0;		
	}
	else if( i == 3){
	red = 0;
	green = 0;
	blue = 255;				
	}
	else if( i == 4){
	red = 0;
	green = 0;
	blue = 0;
		while(i==4) // loopar till ny interrupt kommer
		{ 
		sequence(1,0,255,0,0);
		sequence(1,0,255,255,0);
		sequence(1,0,0,255,0);
		sequence(1,0,0,255,255);
		sequence(1,0,0,0,255);	
		sequence(1,0,255,0,255); 
		}
	}
} 		
interrupt isr()
{  
DelayMs(5);
	if(RB2 == 0)//knapp 2
	{
	i++;
		if(i == 5)
		i= 1;
	}
	INT0IF=0;		//reset interrupt flag
}

void main()
{
init_setup();

	while(1)
	{
	if( i <= 4)
	farger();
	}
}
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Vad är "interrupt variablen" ?
"i" ?

Sen är ju också frågan *vad* som igentligen ska hända
då man trycker på knappen...

Man ska/bör aldrig ha en delay i ISR'en. Det tyder i så fall
på att något är feldesignat. Men det är svårt att säga något om
utan att veta vad som igentligen ska hända...

> Men de är lite tråkigt att vänta på att hela while-loopen i farger()
> ska köras igenom innan den kollar interrupt variablen.

Varför inte kolla den inne i while loopen ?
Och göra det du vill göra direkt ?
Björne
Inlägg: 19
Blev medlem: 18 april 2008, 19:38:11

Inlägg av Björne »

Vad är "interrupt variablen" ?
det är tänkt att vara i ja
Sen är ju också frågan *vad* som igentligen ska hända
då man trycker på knappen...
När jag trycker på knappen är tanken att man ska bytta "program" t.ex. från fast röd till fast grön o.s.v.
Man ska/bör aldrig ha en delay i ISR'en. Det tyder i så fall
på att något är feldesignat. Men det är svårt att säga något om
utan att veta vad som igentligen ska hända...
Delayen kan jag nog ändra på, tanken med den var att när man trycker så ska man hinna släppa så den inte registrerar fler än en knapp tryckning.
Varför inte kolla den inne i while loopen ?
sant sant.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> När jag trycker på knappen är tanken att man ska bytta "program" t.ex.

OK.
Bara att låta ISR'en göra det den ska (ändra "program")
samt att se till att "program" kollas regelbundet i main()
eller i någon av de funktioner som main() anropar. D.v.s
tillräckligt regelbundet för att det inte ska uppfattas som "segt"...
bearing
Inlägg: 11677
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Inlägg av bearing »

En snygg lösning vore att göra om koden så att allt sker i interrupt. Istället för delay-funktionerna används timerinterrupt. Då kommer programmet inte fastna någonstans.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Ja visst, det vore absolut bäst.
Plocka bort alla delay() helt och hållet...

Jag har också undrat lite över vad "puase" är för något... :-)
Björne
Inlägg: 19
Blev medlem: 18 april 2008, 19:38:11

Inlägg av Björne »

Hmm, varför tänkte jag inte på en timerinterrupt, skulle nog bli rätt bra, får kanske testa det. tack bearing!
Jag har också undrat lite över vad "puase" är för något...
om du menar puase() metoden så är den för att dimma ljuset snabbare/långsammare mellan olika färger.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Ah, hm, ja, det var inte så jag menade...

Jag vet vad funmktionen gör, men jag hade kallat den pause()...
Björne
Inlägg: 19
Blev medlem: 18 april 2008, 19:38:11

Inlägg av Björne »

oj, såg inte ens att de var felstavat. haha
Skriv svar