ATMEGA 164A PCINT Issue

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

HI all,  I am new to programming, Now I am going to use button for ATMEGA164A using PINCINT0 for PA0,

The interrupt working only once. Where I am missing?

 

Please help me.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

ISR(PCINT0_vect)
{

	PORTB |= 0x01;
	_delay_ms(500);
	PORTB &= ~0x01;
}

int main(void)
{

	DDRB |= 0x01;
	DDRA &= ~0x01;
	cli();
	PCICR|= (1<<PCIE0);		// Enable pin interrupt PCINT0
	PCMSK0|=(1<<PCINT0);
	EICRA|=(1<<ISC10)|(1<<ISC11);

	sei();

	while(1)
	{

		

	}
}

Using led at PortB 0Pin. I am using Proteus simulation, When I press switch the interrupt pin gets High and Led will blink, But after Interrupt pin should come Low state in this case its not happening. The Int pin remains high after leaving switch also.

This topic has a solution.
Last Edited: Tue. Apr 18, 2017 - 03:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please see http://www.avrfreaks.net/forum/p...

 

I'll move the thread.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
EICRA|=(1<<ISC10)|(1<<ISC11);

Why are you doing this? It has nothing to do with PCINTs? The ISC bits are when you use INTn interrupts, not pin changes.

 

For PCINT you don't get to set any kind of high/low/rising/falling condition. They interrupt for one reason and one reason only - that there has been a "pin change" on the input.

 

I would expect to see your ISR called when the input makes a low-high or high-low transition. One may occur on button "make" and one on button "break" but ONLY if the electronics are configured in such a way as to achieve this.

 

Because AVRs have internal pull-up resistors the "simple" electronics are to set the pin to be an INPUT (DDR bit  = 0), turn on the internal pull up (PORT bit = 1) and then have the external circuitry so that the connection to the pin is normally open but it connects to Ground when the switch is closed.

 

I then looked at you code expecting to see you setting it up in this way and, instead see...

	DDRA &= ~0x01;

So yes that has made PA0 an input (it was anyway) but there's nothing here to do:

       PORTA |= 0x01;

so you are not switching on the pull up.

 

So in your simulated circuit do you have external pull up or pull down resistors?

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

Thank you for your help,

 

Here I making Pin 0 High.

PORTB |= 0x01;

 

Yes I have external pull ups. and what should I do if I have to work with only falling edge? I am reading external 5Volts.

Last Edited: Mon. Apr 3, 2017 - 11:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Gangusa wrote:
Here I making Pin 0 High.

But that is your LED output ??!? I'm not talking about that.

 

Your switch is apparently connected to PCINT0.0 that is:

 

I am trying to get some idea of what it is you have on the outside of the AVR and attached to that pin. Now maybe it is just a switch to Gnd....

but if it is, then "inside" the AVR, you would need to turn on the pull-up resistor for that pin so that while the switch remains open the PA0 signal (PCINT0 bit 0) remains weakly connected to Vcc.

 

Surely you can just take a picture of the Proteus screen and show us what you have connected to that pin?

Last Edited: Mon. Apr 3, 2017 - 12:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi  clawson, The code is working fine if I connect PINA0 to ground. But what I need is if I get 5volt to the pin I should blink the led.

 

First time when I press button it blinks, and the input pin becomes high all the time itself so It is not working for second time. (Sorry for my english).

 

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

Try

 

ISR(PCINT0_vect)
{
    if(bit_is_set(PINA,0));   // rising edge, do nothing
    
    else
    {
       PORTB |=  (1<<PB0);
       _delay_ms(500);
       PORTB &= ~(1<<PB0);
    }
}

int main(void)
{

	DDRB  |=  (1<<PB0);       // output, Led
	DDRA  &= ~(1<<PA0);       // input, (button against GND)
	PORTA |=  (1<<PA0);       // pull-up on button  

	PCICR|= (1<<PCIE0);		  // Enable pin interrupt PCINT0
	PCMSK0|=(1<<PCINT0);

	sei();

	while(1)
	{

	}
}

 

Last Edited: Tue. Apr 4, 2017 - 05:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Visovian wrote:

 


	PORTA |=  (1<<PA0);       // pull-up on button  

 

 

Again you making PINA0 as high. Actually as schematic I am reading pin for 5V. But we make it high before only the pin cannot recognize the pin change state. 

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

Actually as schematic I am reading pin for 5V

Sorry, I have overlooked it.

 

Simply change code to

if(bit_is_clear(PINA,0));   // falling edge, do nothing

 But your pin PA0 is in the air when the button is released. This will cause random level changes.

You need a pull-down resistor on PA0.

 

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

Yes it is ok noow, I it is working only one time and I dont have external Pull down resisters in my project board, What can i do inside the code? 

 

 

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

FIRST add the pull-down resistor!!

 

My code works here on my board.

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

Pull (down or up) resistor is CONDITIO SINE QUA NON when using a plain button.

Otherwise the pin chages its state quickly and causes one interrupt after another.

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

Thank you for you followup, Now it is working. Now I want to toggle the Bit PORTB 0 when I get interrupt.

 

 

 

The same code I modified for the above requirement.

 

ISR(PCINT0_vect)    

{
	
	if(PINA & 0x00);   //clear edge, do nothing
	
	else
	{
	      PORTB ^= 0x01;
	}
	
}

 

But When I press switch o/p bit getting toggle both the cases (While pressing and while leaving switch).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
if(PINA & 0x00);   //clear edge, do nothing

should be

 

if(PINA & 0x01);

or

 

if(PINA & (1<<0));
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you sure about this:

	if(PINA & 0x00);

It kinda always fall into the else branch.
 

And if you have mechanical switch - it'll bounce a lot! And it'll look like it changes state randomly.

Computers don't make errors - What they do they do on purpose.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all, Thank You for your help. The problem is solved. The final code is:

ISR(PCINT0_vect)
{
	if (raising)
	{
		raising = 0;

		if(PORTC & 0x04)
		{
			PORTC &= ~(0x04);
	
		}
		else
		{
			PORTC |= (0x04);

		}
		return;
	}
	raising = 1;
}

 

The above code for ISR for PIN CHANGE INTERRUPT executes only for falling edge.

 

Thank you all for your help.

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

Gangusa wrote:
The above code for ISR for PIN CHANGE INTERRUPT executes only for falling edge.

Well, it works for one edge.  Depending on your starting conditions, it may be rising or falling.

 

As mentioned, for falling edge on that selected pin (PA0), one would usually write:

 

ISR(PCINT0_vect)
{
    if ((PINA & 0x01) == 0) // PA0 is low, so it must have fallen
    {
        PINC = 0x04;    // toggle PC2
    }
}

 

So there is no tracking variable needed (looking at the PIN register directly), and no conditional logic needed for the toggle.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.