pin change interrupt ATmega

Iemand die ervaring heeft met het werken met PCINT's bij Atmel controllers?
Ik heb een stukje code om te werken met vier drukknoppen. De 'naam' van de knop die wordt ingedrukt zou op het LCD scherm moeten verschijnen, maar dit heeft niet het gewenste resultaat...

code:


#include <avr/interrupt.h>   
#include <avr/io.h>
#include "lcd.h"

#define PIJLBENEDEN		 PINC4  //PCINT4
#define PIJLBOVEN	         PINC5  //PCINT5
#define ENTER			 PINC6  //PCINT6 
#define ESCAPE			 PINC7  //PCINT7

#define PINC_MASK  (1<<PCINT20) | (1<<PCINT21)  | (1<<PCINT22) | (1<<PCINT23);


ISR (PCINT2_vect) {    //Interruptroutine

lcd_init(LCD_DISP_ON_CURSOR_BLINK);

   if (PIJLBOVEN != 0 && PIJLBENEDEN != 0 && ENTER != 0 && ESCAPE != 0) {  //Indrukken van een knop geeft een "1".

      if (PIJLBENEDEN == 1) {

      lcd_puts("PIJLBENEDEN\n");

      }

      if (PIJLBOVEN == 1) {

      lcd_puts("PIJLBOVEN\n");

      }

      if (ENTER == 1) {

      lcd_puts("ENTER\n");

      }

      if (ESCAPE == 1) {

      lcd_puts("ESCAPE\n");

      }

   }

}



int main (void) {

sei();

//Opstarten van de LCD module

lcd_init(LCD_DISP_ON);
  
lcd_clrscr();

lcd_puts("\n");
lcd_puts("  xxxxxxxxxx\n");

PCMSK2 = PINC_MASK;	

PCICR = (1<<PCIE2);

}

Alvast bedankt voor een eventuele reactie!!

Groeten, Gilles

Zijn die PINCx dingen niet gewoon defines van de input pinnen van port C? Nou zijn die vast niet allemaal 0, maar de kans dat er eentje 1 is acht ik ook niet zo groot (gezien de nummers die je gebruikt).

Wat je naar mijn idee wilt is kijken of een bepaalde bit in PINC geset is. Ofwel: PINC lezen en kijken welke bitjes geset zijn. Zoiets dus:

code:

unsigned char a=0;
a=PINC;

if (0!=(a & PIJLBENEDEN))
{
  ...
}

Ik ben ook niet zo dol op dit soort forse handling in een ISR. Doe dat lekker in je mainloop en laat de ISR alleen wat semaphores zetten (en ja, het kan vast wel, en het gaat ook vast wel goed...).

Verder is het enablen van je global interrupts voordat je het spul geconfiged hebt ook niet zo netjes. Het zal echter bij een AVR wel loslopen.

[edit]Typo gecorrigeerd

Zorg dat je NOOIT, NOOIT, NOOIT wat met Versatel Tele2 te maken krijgt!

code:


#define    PINC4    4

Dat zegt genoeg, denk ik. Wellicht is er verwarring met andere compilers die iets als "PINC.4" wel vertalen naar hetgeen uiteindelijk bedoeld wordt?

Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)

Je bent de "while (1);" vergeten. Zo loopt je programma het end van "main" uit, en de avr-gcc compiler weet dan niks anders te verzinnen dan de AVR maar opnieuw op te starten. Zo staat ie dus constant te rebooten.

Ik zou wel de lcd_init () uit de interrupt routine weghalen.

90% van de problemen bij interrupts in microcontrollers komt doordat je vergeten bent ergens de interrupts te enabelen. Volgens mij mis ik nog een globaal interrupt enable bitje wat gezet moet worden. Of SEI dat voor je doet, betwijfel ik.

P.S. En marco heeft gelijk: Zet de sei achter het aanzetten van de PCINT dingen, net voor de while (1); .

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Heel erg bedankt voor de reacties, maar ik heb nog altijd niet het gewenste resultaat. Ik heb het programma als volgt verandert:

code:


#include <avr/interrupt.h>   
#include <avr/io.h>
#include "lcd.h"

#define PIJLBENEDEN		 PINC0  //PCINT4
#define PIJLBOVEN	         PINC1  //PCINT5
#define ENTER			 PINC2  //PCINT6 
#define ESCAPE			 PINC3  //PCINT7

#define PINC_MASK  (1<<PCINT16) | (1<<PCINT17)  | (1<<PCINT18) | (1<<PCINT19);

ISR (PCINT2_vect) {

   if ((PINC & 00000001) == 1) {

      lcd_puts("PIJLBENEDEN\n");

   }

   if ((PINC & 00000010) == 1) {

   lcd_puts("PIJLBOVEN\n");

   }


   if ((PINC & 00000100) == 1) {

   lcd_puts("ENTER\n");

   }


   if ((PINC & 00001000) == 1) {

   lcd_puts("ESCAPE\n");

   }

}



int main (void) {

//Opstarten van de LCD module

lcd_init(LCD_DISP_ON);
  
lcd_clrscr();

lcd_puts("\n");
lcd_puts("  xxxxxxxxxx\n");

PCMSK2 = PINC_MASK;	

PCICR = (1<<PCIE2);

SREG = (1<<SREG_I);

while (1);

}

Enkel bij het hoog maken van PINC0 (=PIJLBENEDEN), komt op het schermpje "PIJLBENEDEN". Soms komt bij het hoog maken van PINC1 ook "PIJLBENEDEN" op het scherm...

if ((PINC & 00000010) == 1) {

Ik vrees dat je compiler die "00000010" als een decimaal (10) of octaal (8) getal beschouwt.
Met

if ((PINC & 0x20) == 1) {

zal het beter gaan...

Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)

Ik zie een paar foutjes in je programma.

binaire getallen moeten vooraf gegaan worden door 0b

dus 00000100 moet 0b00000100 worden

Wanneer je een bitwise AND doet zullen alle bits waar de mask 0 voor is op 0 gezet worden.
BV: 0b11011100 & 0b00000100 wordt 0b00000100

In jouw if-clausules gebruik je deze code:
(PINC & 00000100) == 1
Stel dat de 3e input hoog is van poort C dan zal het resultaat van
PINC & 0b00000100
gelijk zijn aan 0b00000100 (4) en niet aan 1.

Je zult de check dus moeten veranderen naar:
(PINC & 0b00000100) != 0

Verder zie ik ook een punt-komma staan bij je laatste #define die daar niet thuis hoort.

Als laatste opmerking zou ik je willen aanraden om heel strikt tabs te gebruiken in je programma's. Op die manier is het veel makkelijker later je progamma opnieuw te lezen en te debuggen.

Ik heb de veranderingen al aangebracht zoals door jullie aangegeven, maar nog geen resultaat. Ik heb nu een stukje code waarvan ik echt niet kan denken wat er fout is...

code:


#include <avr/interrupt.h>   
#include <avr/io.h>
#include "lcd.h"

#define PIJLBENEDEN		 PINC0  //PCINT4
#define PIJLBOVEN	         PINC1  //PCINT5
#define ENTER			 PINC2  //PCINT6 
#define ESCAPE			 PINC3  //PCINT7

#define PINC_MASK  (1<<PCINT16) | (1<<PCINT17)  | (1<<PCINT18) | (1<<PCINT19);

ISR (PCINT2_vect) {  

   if ((PINC & 0b00000001) == 0b00000001) {

   lcd_clrscr();

   lcd_puts("PIJLBENEDEN\n");

   }


   if ((PINC & 0b00000010) == 0b00000010) {

   lcd_clrscr();

   lcd_puts("PIJLBOVEN\n");

   }


   if ((PINC & 0b00000100) == 0b00000100) {

   lcd_clrscr();

   lcd_puts("ENTER\n");

   }


   if ((PINC & 0b00001000) == 0b00001000) {

   lcd_clrscr();

   lcd_puts("ESCAPE\n");

   }

}


int main (void) {

lcd_init(LCD_DISP_ON);
  
lcd_clrscr();

lcd_puts("\n");
lcd_puts("  xxxxxxxxxx\n");

PCMSK2 = PINC_MASK;	

PCICR = (1<<PCIE2);

SREG = (1<<SREG_I);

while (1);

}

PIJLBOVEN en PIJLONDER komen soms goed op het scherm. ENTER en ESCAPE daarentegen geven geen teken van leven, ook niet als ik andere poorten gebruik...

Is er iemand die het probleem ziet?

Alvast bedankt!!

#define PINC_MASK (1<<PCINT16) | (1<<PCINT17) | (1<<PCINT18) | (1<<PCINT19)

de ; had ik ook gewist na de define - lijn

Heb je externe pull-down weerstanden aan de interrupt-pinnen hangen? Als dat niet zo is, loop je het risico dat de pinnen (of sommige pinnen) gewoon altijd als hoog gelezen worden en dus nooit een pin-change interrupt zullen veroorzaken.

In dat verband: is het niet eenvoudiger de interne pull-up weerstanden te activeren, de pinnen te sturen door ze met GND te verbinden en in de ISR te testen welke pin laag is?

Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)

waar is de sei () gebleven?

Doe me een lol en doe:

code:


lcd_puts ("int");
if (PINC & 0x80)  lcd_puts ("7");
if (PINC & 0x40)  lcd_puts ("6");
if (PINC & 0x20)  lcd_puts ("5");
if (PINC & 0x10)  lcd_puts ("4");
if (PINC & 0x08)  lcd_puts ("3");
if (PINC & 0x04)  lcd_puts ("2");
if (PINC & 0x02)  lcd_puts ("1");
if (PINC & 0x01)  lcd_puts ("0");
lcd_puts("!");

in je interrupt routine. Verder ga ik in dit soort gevallen niet meer op DEFINES vertrouwen, dus wordt de initializatie bijvoorbeeld: PCMSK2 = 0x0f;

straks als het allemaal werkt, ga je dat mooi maken. Nu heb je NET de manual gelezen, en weet je zelf waar de bitjes zitten, en wil je niet het kleine gevaar lopen dat de compiler door iets raars even wat anders had begrepen dan je bedoelde.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/