Interrupts- simple program

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

Hi everybody. I am trying to understand how interrupts works, but i'm get stuck.

I wrote a simple code:

\\atmega8 is used
#include 
#include "util\delay.h"
#include
#define LED 0
#define F_CPU 8000000UL

ISR(INT0_vect)
{
	PORTD=0xFF;
	_delay_ms(1000);
	
}

int main(void)
{
	      \\The low level of INT0 generate an interrupt, so ISC01 and ISC00 are both 0, in MCUCR.
         
	GICR |=(1<<INT0);//Enable INT0 interrupt
	
	sei();           //Enable Global interrupts
	
	DDRD=(1<<LED);//LED Pin as an output
    while(1)
    {            // Just flashing a LED
		PORTD |=(1<<LED);
		_delay_ms(200);
		PORTD &=~(1<<LED);
		_delay_ms(200);
       
    }
}

Well, basically, I want my LED to flash, but when I press the buton (witch is INT0 , pulled to ground), the led should stop flashing, for a second.

The problem is, when I am pressing the button, the LED just stop's flashing(but stays on), while I am holding the button, in order to stay for a second. When I am releasing it, it's starts flashing again.

What I am doing wrong? I will really apreciate your help.

edit.
I modified MCUCR, so now is enabling on transitions H-L. And it seems to work, but after reset (the MCU with reset pin) first it is executing the interrupt code ( it stay's on for a second, then start flashing).

But, i have modified the interrupt code like this

ISR(INT0_vect)
{
	PORTD=0x00; // I want the led to go off
	_delay_ms(1000);
	
}

and now it just stay's off from the beginning, and nothing is affecting that (actually, i see a very short spark at the beginning, the led goes on for 1ms or so, then go off.

Last Edited: Mon. Jan 9, 2012 - 06:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you have set DDRD to ff that is all the pin are high so every time you press the botton it goes high and doesn't flash. To make it stop glowing make it to 0x00

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

rudr_p wrote:
you have set DDRD to ff that is all the pin are high so every time you press the botton it goes high and doesn't flash. To make it stop glowing make it to 0x00

I understand that, but anyway, it's not flashing only while I am holding down the button.

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

u said you don't want to flash when the botton is pressed

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

Quote:

What I am doing wrong?

Quote:

\\The low level of INT0 generate an interrupt, so ISC01 and ISC00 are both 0, in MCUCR.

The interrupt is continually firing when you are "holding down the button" so not much useful is getting done.

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.

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

Also, with the LOW Level interrupt, the interrupt will continually fire as long as you hold the interrupt pin low. You want falling edge to run the interrupt only once. Also, buttons bounce, so you will get multiple interrupts on every button press (though with the _delay_ms(1000) in the interrupt, you will end up only responding to two of them).

Regards,
Steve A.

The Board helps those that help themselves.

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

Ok, thanks for responses. However, I did the changes for H-L transition and it seems to work ( but the delay i think is about 2 seconds, instead of 1), but I modified a little the code.

ISR(INT0_vect) 
{ 
   PORTD=0x00; 
   _delay_ms(1000); 
    
} 

So now I wan't to turn off the led for a second. But the led stay's off from the beginning.
i just can't understand why?

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

Quote:

i just can't understand why?

Perhaps/probably the interrupt flag is set at startup, and then fires when you enable interrupts.

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.

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

theusch wrote:
Quote:

i just can't understand why?

Perhaps/probably the interrupt flag is set at startup, and then fires when you enable interrupts.

i tried to clear the interrupt flag ( from datasheet it say's that I have to write "1" to it, if I want to clear the flag) but still it is not working.

If somebody is so kind, can he write a simple code, that is flashing a led, then on an external interrupt, say turn off the led for a wile. It is just so frustrating to write something that logically should work, but on the ground ( i mean on the breadboard ) is not working :D

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

I guess no one will write codes for you . You need to figure it out yourself . Forums only offer help and try seeing code again you might just find it .use stimulator

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

I guess no one will write codes for you . You need to figure it out yourself . Forums only offer help and try seeing code again you might just find it .use stimulator

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

Quote:
but the delay i think is about 2 seconds, instead of 1
I already answered that: your switch is bouncing.

Regards,
Steve A.

The Board helps those that help themselves.

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

and i guess the max second for delay is 262.14ms / F_CPU
for delay_ms. and are you sure your chip is running at 8mhz?

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

I did't use a switch, I used a push button, and bouncing time is very short ( i think ms or so, but in any case not 1 second).

Hovever, I found the problem. I used internal pull up resistor, and for some reason, the interrupt was over and over called. Now I am using an external pull up resistor ( for making the transition possible, from high to low), and everything is working as expected (still a little too much for the interrupt delay, but i will take this as bouncing time).
THANK'S to ALL of YOU for your help!

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

rudr_p wrote:
and i guess the max second for delay is 262.14ms / F_CPU
for delay_ms. and are you sure your chip is running at 8mhz?

Now is running at 1Mhz, but I changed F_CPU.
And i can use _delay_ms(50000) (50 seconds), and is still doing it's job.

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

Quote:

Hovever, I found the problem. I used internal pull up resistor, and for some reason, the interrupt was over and over called. Now I am using an external pull up resistor ( for making the transition possible, from high to low), and everything is working as expected

Your code showed no indication of that. How are you supposed to help when you don't show the actual code you are using?

Quote:

I did't use a switch, I used a push button, and bouncing time is very short ( i think ms or so, but in any case not 1 second).

The bouncing time won't be a millisecond http://www.ganssle.com/debouncin... but it doesn't have to be a second for you to see your symptom--it just has to bounce while you are in your ISR and doing your delay.

Quote:

i tried to clear the interrupt flag ( from datasheet it say's that I have to write "1" to it, if I want to clear the flag) but still it is not working.


Show the code.

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.

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

Quote:
and i guess the max second for delay is 262.14ms / F_CPU
for delay_ms.
You guess incorrectly. Current versions of avr-gcc extend beyond this limitation (though with reduced accuracy).

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
Quote:
and i guess the max second for delay is 262.14ms / F_CPU
for delay_ms.
You guess incorrectly. Current versions of avr-gcc extend beyond this limitation (though with reduced accuracy).

thanks for clearing that misconception :D

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

@theusch
sorry for incomplete code.
I was using also there

PORTD|=(1<<PD3) //witch is INT0 pin

but I was doing magician stuff, when i put my hand above the circuit, the interrupt was called ( i didn't touch anything!) So now I am using an external pull up resistor ( although, it should work fine with internal...).

For clearing flag, I used this code ( just before sei() in the main)

GIFR|=(1<<INTF0);

quote from datasheet :The flag is cleared when the interrupt routine is executed. Alternatively, the flag
can be cleared by writing a logical one to it.

But why is not working, when I set up MCUCR, for enable interrupt at low level of INT0?
I understand that the interrupt will be called over, and over while my button is bouncing, but at the end of bouncing, it should just do my delay, then step over it.

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

Quote:

\\atmega8 is used

Quote:

I was using also there
Code:
PORTD|=(1<<PD3) //witch is INT0 pin

Quote:
(INT0) PD2

No, PD3 is not INT0 on a Mega8.

How do you expect a switch/button to work as expected as an input when you are setting the entire port as output, and forcing the entire port low/high? At the worst, you are shorting an AVR high output to ground--not a good strategy.

Internal pull-ups work fine in the vast majority of button/switch pull-up situations.

-- Clean up your code.
-- Show it all.
-- Manipulate only the pin(s) with the LED(s) connected.
-- Tell whether LEDs are high and low.

Quote:

But why is not working, when I set up MCUCR, for enable interrupt at low level of INT0?

"then step over it", and then re-enter the interrupt because the flag is set and do it all again.

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.

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

sorry for confusing you, i was confused myself. It is pin number 4 on the Atmega8, and I did PD3 (i forgot about pin nr 1 Reset...).
now i have changed the code, and it is working as intended. thanks again.

#include 
#include "util\delay.h"
#include
#define LED 0
#define F_CPU 1000000UL

ISR(INT0_vect)
{
	PORTD&=~(1<<LED);     //turn led off
	_delay_ms(1000);
}



int main(void)
{
    DDRD|=(1<<LED);     //led as an output
    PORTD|=(1<<PD2);    //pull up on button pin (int0)
	MCUCR|=(1<<ISC01);  //interrupt on H-L transittion
	GICR |=(1<<INT0);   //enable INT0 interrupt
	GIFR|=(1<<INTF0);   //clear interrupt flag 
	sei(); 
	
	
    while(1)
    {
		PORTD |=(1<<LED);
		_delay_ms(500);
		PORTD &=~(1<<LED);
		_delay_ms(500);
       
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And actually, I also tried the interrupt on INT0 low (just leaved MCUCR untouched ), and is working as well.

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

Clearing INTF0 where you are clearing it does no good. The problem is that it is getting set while you are in the ISR because of bounce.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:

Clearing INTF0 where you are clearing it does no good.

Well, it addresses the "delay at startup" symptom. But indeed, buttons bounce.

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.

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

I don't believe anybody else has raised this serious concern, which is, never put a delay in an ISR. This defeats the main benefits of having interrupts.

I know, you're just experimenting with the interrupt concept now, but I'm telling you this so you don't get into a very bad habit.

Here is a bare bones pseudo-code version of how to do what you want using timers and no delay statements. This is a much more typical approach to timing problems.

volatile u8 tick_flag = 0;
volatile u16 count = 1; // so first --count -> 0

timer_isr() // set to tick every 10ms
{
  tick_flag = 1;
}

// better to check buttons in timer_isr
// but I'll do it your way for this example
button_isr()
{
  count = 100; // 1 second delay
}

main()
{
..init stuff..
  sei();
  while (1)
  {
    if (tick_flag)
    {
      cli():
      if (--count == 0)
      {
        PORTD ^= (1<<LED);
        count = 50; // 0.5 second delay
      }
      sei();
      tick_flag = 0;
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
Clearing INTF0 where you are clearing it does no good. The problem is that it is getting set while you are in the ISR because of bounce.

I cleared it, just in case it's getting set somehow ( i know, it sound weird, but the interrupt was activated at the beginning of the program, so I decided that that flag was set from the beginning).

@kk6gm Thanks a lot! But i decided to do software delays, because i might need those timers, who knows... But you are right, because while i am in the interrupt delay loop, no other interrupt can occur. So this is making my software delay useless.

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

That suggests that you wrongly believe that a timer can only be used for one thing at a time?

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

andrianu wrote:
@kk6gm Thanks a lot! But i decided to do software delays, because i might need those timers, who knows... But you are right, because while i am in the interrupt delay loop, no other interrupt can occur. So this is making my software delay useless.

Software delays beyond a very small fraction of a second are evil, IMHO. Real applications (as opposed to educational, etc) need to juggle many balls at once, and so you need to learn how to use timers to their fullest capability. I commonly use one timer to (a) generate a fixed system tick interrupt and (b) generate longish interval interrupts unrelated to the system tick and (c) do input capture and (d) do short software delays such as the 50us needed for character LCD commands.

As an embedded programmer, timers are your friends. :)

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

Quote:
I cleared it, just in case it's getting set somehow ( i know, it sound weird, but the interrupt was activated at the beginning of the program, so I decided that that flag was set from the beginning).
BUT YOU ALSO HAVE TO CLEAR IT AT THE END OF THE ISR SINCE THE FLAG IS BEING SET MULTIPLE TIMES WHILE YOU ARE IN THE INTERRUPT BECAUSE OF SWITCH BOUNCE. Switch bounce has been brought up by me and others several times, yet you refuse to acknowledge that this is a problem. It will even be more of a problem the minute you remove the ridiculous delay in the ISR.

Regards,
Steve A.

The Board helps those that help themselves.

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

@Koshchi
Let me try to understand that.
When the interrupt event occur, the flag is set (INTF0 for external interrupt, in GIFR). Let say, that my bounce will produce 10 more interrupt conditions,( I mean here that it will trigger the interrupt 10 more times) so every time, the flag will be set over and over, causing the interrupt to start 10 timmes, so if the interrupt code, is very short ( in meaning of time), it will execute that code 10 times. (no good).

let say:

ISR(INT0_vect)
{   
	i+=50;
}	

it will add not 50 to i, but 100, 150... because of the bounce.

so i tried to write like this:

ISR(INT0_vect)
{   
     GIFR|=(1<<INT0); //clear the interrupt flag
     i+=50;
}	

but i don't think i did it right, because I am clearing that flag, but my bounce it will set it again!
The simplest solution I think is to add a small software delay in the code, like 100 ms , witch is longer than the switch bounce.(simplest yet not the best one)
sorry for being a pain in the ass, but i really want to understand how everything is working.
Thanks again!

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

Quote:

but i don't think i did it right, because I am clearing that flag, but my bounce it will set it again!

Exactly.
Quote:

The simplest solution I think is to add a small software delay in the code, like 100 ms , witch is longer than the switch bounce.(simplest yet not the best one)

In a trivial app, whatever works. In a real app, use a proper debounce mechanism. Have you looked at the range of bounce times that Ganssle found? Also, in a real app it is likely that there is a bank of switches/buttons for the user interface. Debounce them in parallel; it takes a few microseconds every few milliseconds. The output will be the current debounced state, and new edges. Remember in a real app with n buttons one can't afford to just sit there for 100ms for each button--subsequent presses may be lost; there may be button-held code; there may be button combinations; other things need to be done.

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.