Interrupt on Pin Change

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ATMEGA644, GCC Compiler. I can't get this test program working. The Interrupt does not appear to be firing. The value of NumChanges is alway equal to 0x00.

I have a function generator and scope on PA0 so I know the pin is physically changing.

I may be setting up the interrupt wrong? Any help would be greatly appreciate. Thanks.

// THIS CODE *DOES NOT* WORK PROPERLY
#include  
#include 

#define F_CPU 20000000UL

volatile unsigned int NumChanges;



ISR(PCINT0_vect)
{
	NumChanges = NumChanges + 1;
}

int main (void) 
{ 


	// PORTA
	// Pin40, PA0: Input, 
	// Pin39, PA1: Output, 
	// Pins:   76543210
	// Values: 00000010  0x02

	DDRA = 0x02;

	
	// PORTB
	// Pin1, PB0: Output, LED
	// Pins:   76543210
	// Values: 00000001  0x01
	
	DDRB = 0x01;

	//Enable Pin Change Interrupt on TxIn Pin PA1
	PCMSK0 |= (PCMSK0 << PCINT0);
	PCICR |= (PCICR << PCIE0);
	sei();


	while(NumChanges < 50)
	{
		//Collect Data
	}

	cli();

	NumChanges = NumChanges;  //For Testing and Debugging.


} //end main

Below is the revised code that DOES work properly per JS's post below.

// THIS CODE *DOES* WORK PROPERLY
#include  
#include 

#define F_CPU 20000000UL

volatile unsigned int NumChanges;



ISR(PCINT0_vect)
{
	NumChanges = NumChanges + 1;
}

int main (void) 
{ 


	// PORTA
	// Pin40, PA0: Input, 
	// Pin39, PA1: Output, 
	// Pins:   76543210
	// Values: 00000010  0x02

	DDRA = 0x02;

	
	// PORTB
	// Pin1, PB0: Output, LED
	// Pins:   76543210
	// Values: 00000001  0x01
	
	DDRB = 0x01;

	//Enable Pin Change Interrupt on TxIn Pin PA1
	PCMSK0 |= (1 << PCINT0);  //Fixed/Revised This Line
	PCICR |= (1 << PCIE0); //Fixed/Revised This Line
	sei();


	while(NumChanges < 50)
	{
		//Collect Data
	}

	cli();

	NumChanges = NumChanges;  //For Testing and Debugging.


} //end main
Last Edited: Sun. Nov 9, 2008 - 06:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
   PCMSK0 |= (PCMSK0 << PCINT0); 
   PCICR |= (PCICR << PCIE0); 

try

   PCMSK0 |= (1 << PCINT0); 
   PCICR |= (1 << PCIE0); 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
   PCMSK0 |= (1 << PCINT0); 
   PCICR |= (1 << PCIE0);

Yup. That was it. I don't know why I did that. :oops:
Thanks so much!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And remember that you WILL GET 2 interrupts, one going up and one going down, therefore a Pin CHANGE interrupt. If you just want one of the edges you will need to ignore the unwanted edge in software.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In addition to what js wrote, in general you should be sure to clear an interrupt flag before enabling the corresponding interrupt. It is less important (actually not necessary) in your test code because the flag will never be on due to the fact that the code just began running from a reset.

   PCIFR |=  (1 << PCIF0);
   PCMSK0 |= (1 << PCINT0);
   PCICR |= (1 << PCIE0);

Personally, my preference is to use the _BV() macro as shown in the functionally equivalent code below.

   PCIFR |=  _BV(PCIF0);
   PCMSK0 |= _BV(PCINT0);
   PCICR |= _BV(PCIE0);

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
my preference is to use the _BV() macro
But that's fostering non portable C code, maybe ok for people selling BASIC though. :lol:

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

And remember that you WILL GET 2 interrupts, one going up and one going down, therefore a Pin CHANGE interrupt.

This is what I want. I am measuring an incoming PWM data stream. I figure that I can time stamp each transition and then decode the 1's and 0's after the data stream is over.

Is there a better more direct way to do this instead of using the Interrupt on Pin Change?

Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
But that's fostering non portable C code
No more so than using PCINT0. Neither are part of standard C, they are simply macros defined in an include file and easily replicated if your particular C compiler doesn't happen to have them defined.

This is the AVR GCC forum, by the way.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

immo wrote:
Is there a better more direct way to do this instead of using the Interrupt on Pin Change?
Using the Input Capture facility will be more accurate. This is because it takes a snapshot of the associated timer exactly at the time when the capture event occurs.

Your method will work, of course, but there is a latency that will exist between the time the signal edge occurs and when the timer can be read. The latency has two parts; one fixed and one variable. The fixed part is due to the overhead required to invoke the ISR, save the necessary registers, and, finally, read the timer value. The variable part is due to the fact that interrupts might be disabled at the time when the signal transition occurs. Interrupts could be disabled for an unknown and variable amount of time with respect to the event. Moreover, a higher priority interrupt might be asserted during that period so that when interrupts are re-enabled, other ISRs may be executed first.

It may be that your method will produce entirely satisfactory results; much depends on your requirements and the nature of the signal involved.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

It may be that your method will produce entirely satisfactory results; much depends on your requirements and the nature of the signal involved.

I think the On Pin Change will work for this project. I'll try Input Capture on the next one. Thanks for the info though.

One side question: Is it OK to turn off an Interrupt inside it's ISR Routine? For instance in the On Pin Change ISR, it is OK to turn off the On Pin Change Interrupt after so many Interrupts have occured? Or is that just bad practice? Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
No more so than using PCINT0. Neither are part of standard C,
While we said pretty much all that there is to be said about _BV here:
https://www.avrfreaks.net/index.p...
PCINTO and other registers/bit names are processor specific, however bitwise operators ARE part of the C standard
6.5.7 Bitwise shift operators
Syntax
1 shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression

so why confuse a newbee with something that can be used in just 1 compiler type instead of using something that can be used across other brands of compilers and/or processors?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly