[C] Interrupt om verschillende led patronen te kiezen werkt niet

Hallo, ik heb hieronder een code geschreven waarmee je in principe met een druk op de knop een ander led patroon kan laten zien. Per druk op de knop wordt status met 1 verhoogd waardoor er een ander patroon te zien is. Die doet het niet.

Mijn situatie:
Een STK500 waarbij de INT pin hoog is. Op het moment dat de schakelaar wordt ingedrukt, vind er een interrupt plaats omdat hij laag wordt gemaakt. Ik heb de interrupt zelf getest, die werkt. Ik vermoed dat het te maken heeft met mijn C code. Iets met de scope van status.

Heeft iemand een idee waar het aanligt en heeft iemand eventueel een efficientere code voor deze situatie. Eventueel kan ik meerdere while statements gebruiken of for, maar dat moet in dit geval niet uitmaken.



	#include <avr/io.h>     // avr header file for IO ports 
	#define F_CPU 1000000LU
	#include <avr/interrupt.h>

unsigned int status = 0;

ISR(INT0_vect) 	// when an interrupt is enabled
{
status++;		// increment status
}

int main(void){ 

  DDRB = 0xFF;		// output
  PORTD = (1<<PD2); // int pin is high
  PORTB = 0xFF;	// all leds off

  GICR = 0x40;
  MCUCR = (0<<ISC00) | (0<<ISC01);	// low level int

  sei();


 while(1){

  if( status == 1 ) // after first int
  PORTB = 0xFE;
  
  if( status == 2 ) // after second int
  PORTB = 0xFD;

  if( status == 3 ) // after third int
  PORTB = 0xFB;

  if( status == 4 ) // ..
  PORTB = 0xF7;
  
  if( status == 5 )
  PORTB = 0xEF;  

  if( status == 6 )
  PORTB = 0xDF;

  if( status == 7 )
  PORTB = 0xBF;  

  if( status == 8 )
  {
    PORTB = 0x7F;  
    status = 0;
  }
  
}

  return 1;  
} 

Gaat inderdaad om status. Doe eens dit:


volatile unsigned int status = 0;

Maak status eens volatile. Nu word het kapot ge-optimized.

[edit]Ow.. Nummer 3... Nou ja, zal wel duidelijk zijn zo :)[/edit]

[Bericht gewijzigd door Marco69 op (38%)]

Het is zo! Nu nog even bekijken waarom het zo is.

Ik had nu een softwarematige oplossing bedacht voor het contactdender. Het werkt niet, maar zit ik in de goede richting?


ISR(INT0_vect) 	// when an interrupt is enabled
{
_delay_ms(100);
if( (PORTD&0x04) == 0x00)
++status;		// increment status

}

ongeveer, eerst wachten tot het knopje omhoog gaat en dan een aantal milliseconden wachten.

delayloop uit je ISR halen. Beter helemaal geen (externe) functies aanroepen uit je ISR. Je kan ook in je ISR een flag setten voor 'ingedrukt' en dan in je mainloop een

while (flag);

dan blijft hij daarin hangen tot je loslaat. afhankelijk van de rest van je programma nog een _delay_ms(100); erna

[Bericht gewijzigd door Adhy op (16%)]

Op 21 januari 2009 21:33:04 schreef UneXisted:
Het is zo! Nu nog even bekijken waarom het zo is.

In het kort: je source wordt function voor function gecompileerd. Da's handig, want zo heb je feitelijk geen verschil tussen functions in hetzelfde file of functions uit verschillende files.
Die compiler doet wat optimization. Concreet worden niet alle variables als zodanig gebruikt. Waar mogelijk worden waarden in registers gehouden (snelheid).
Daar er geen relatie tussen je functions is, gaat dat dus 'stuk'. Je ISR zal vast het memory wel updaten, echter je main heeft daar geen weet van en houdt het ding lekker in een register.
Met volatile vertel je de compiler dat er onder water nog wel eens aan dat ding getrokken kan worden. In dit geval door een ISR, maar je kunt dezelfde situatie hebben als je bijvoorbeeld memory mapped I/O hebt en daar variablen op gemapped hebt. Concreet wordt deze variable dus consequent uit memory gehaald in plaats van optimized in een register gefrut.

Optimization uit zetten zou hetzelfde effect gehad hebben - fout blijft dat het dan geen correcte code is die toevallig wel werkt.

Overigens is het de taak van de linker om ervoor te zorgen dat de 'references' die in je gecompileerde code naar bijvoorbeeld deze variable verwijzen resolved worden. Welnu: dat gaat lukken want het symbol is er. Bouwen doet het dus ook zonder volatile prima.

Op 21 januari 2009 21:42:58 schreef Adhy:
delayloop uit je ISR halen. Beter helemaal geen (externe) functies aanroepen uit je ISR. Je kan ook in je ISR een flag setten voor 'ingedrukt' en dan in je mainloop een

while (flag);

dan blijft hij daarin hangen tot je loslaat. afhankelijk van de rest van je programma nog een _delay_ms(100); erna

Persoonlijk zou ik het nog anders doen. Laat ergens een timer interrupt lopen en handel daar je patroontjes af. Heb je je hele main voor andere dingen.