External Interrupt ATtiny85

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

Hi,

 

I'm new in ATMEL world, and I'm a little bit lost in the registers. I'm trying to activate a simple external interrupt, in order to stop the blink of my LED, but nothing happend. It should be very simple, can you help me ?

 

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

#define LEDDEUXCINQ    4   // Leds 2 et 5 sur pin4

int diode=0;

ISR(INT0_vect){
  diode = 1 - diode;
}

void init_ISR(){
  MCUCR |= 0x3;  // Rising EDGE
  GIMSK |= 1<<6;  // Activate the INT0
  SREG  |= 1<<7;  // Activate the general interrupt
}

void init_GPIO(){
  DDRB |= 1<<LEDDEUXCINQ; // LED as output
}

int main() {
  init_GPIO();
  init_ISR();
  init_general();

  while(1){
   if(diode){
      PINB&=~(1<<LEDDEUXCINQ);
   }
      PINB|=1<<LEDDEUXCINQ;
      _delay_ms  (200);
      PINB&=~(1<<LEDDEUXCINQ);
      _delay_ms  (200);
  }

  return 0;
}

Thanks in advance :)

This topic has a solution.
Last Edited: Sun. Jun 3, 2018 - 05:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please check whether this movement will be the movement you thought with this code.

 

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

#define LEDDEUXCINQ    4   // Leds 2 et 5 sur pin4

volatile int diode = 0;        //<<<<<<<<<<<<<<<<<<<<<<<<<

ISR(INT0_vect){
    diode = 1 - diode;
}

void init_ISR(){
    MCUCR |= 0x3;  // Rising EDGE
    GIMSK |= 1<<6;  // Activate the INT0
//    SREG  |= 1<<7;  // Activate the general interrupt
    sei();        //<<<<<<<<<<<<<<<<<<<<<<<<<
}

void init_GPIO(){
    DDRB |= 1<<LEDDEUXCINQ; // LED as output
}

int main() {
    init_GPIO();
    init_ISR();
//    init_general();    // ???

    while(1){
        // modified
        if(!diode){
            PINB |= 1<<LEDDEUXCINQ;
            _delay_ms  (200);
            PINB &= ~(1<<LEDDEUXCINQ);
            _delay_ms  (200);
        }
        // modified end
    }

    return 0;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
int diode=0;

should become

volatile byte diode=0;  // volatile : else, optimizer removes variable "diode", thus accelerating/shortening ISR... byte : saves some RAM/cycles
Last Edited: Sat. Jun 2, 2018 - 03:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Open the datasheet. Replace all your magic numbers with the official BIT_NAMEs.
Add whitespace around your operators.
Format the code nicely. An auto-format will indent your code (and add whitespace to operators)
.
All that is cosmetic. But extremely worthwhile.
Your actual problem is that diode must be volatile.
.
David.

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

" It should be very simple"

Things can become ... less simple if you use a button, and if it bounces (typical bouncing time : 10 ms >> ISR response time)  an even number of timeS...

 

edited : read Theush post -> times are sometimes plural.

 

Last Edited: Sat. Jun 2, 2018 - 04:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also, you will soon learn that buttons bounce and it usually is not useful to take action via a button/switch via external interrupt.  For example, imagine that your button bounces an even number of times in less than a millisecond -- it will appear that the code "didn't work".

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

Hi,

 

Here is my code, and aout the button, I don't use it now, I simply disconnect the PIN 7 (PB4), in order to make the interrupt on the falling edge. Here is my coee, and it doesn't work, still... any idea ?
(the LED blink forever), no matter what is happening on PB4.

 

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

#define LEDDEUXCINQ 4   // Leds 2 et 5 sur pin4

volatile byte diode = 1;        

ISR(INT0_vect){
    diode = 1 - diode;
}

void init_ISR(){
    MCUCR |= 1<<ISC01; // Falling EDGE
    GIMSK |= 1<<INT0;  // Activate the INT0
    sei();             //Active General Interrupt
}

void init_GPIO(){
    DDRB |= 1<<DDB4; // LED as output
}

int main() {
    init_GPIO();
    init_ISR();

    while(1){
        if(diode){
            PINB |= 1<<LEDDEUXCINQ;
            _delay_ms  (200);
            PINB &= ~(1<<LEDDEUXCINQ);
            _delay_ms  (200);
        }
        else PINB &= ~(1<<LEDDEUXCINQ);
    }

    return 0;
}

 

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

INT0 is on PB2. The general rule is to enable internal pullup on PB2 and interrupt on falling edge.
XTAL2 is on PB4. I presume that you are using the internal RC. So PB4 can be used as GPIO.
.
David.

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

david.prentice wrote:

INT0 is on PB2. The general rule is to enable internal pullup on PB2 and interrupt on falling edge.
XTAL2 is on PB4. I presume that you are using the internal RC. So PB4 can be used as GPIO.

 

Thanks for your quick answer David. About the the pullup, according to the datasheet, I shoult add this in my init_GPIO() fonction, do you agree : PORTB |= 1<<PB2;

 

About the PB4 in GPIO mode, I thought I'm already in GPIO mode, if not, can you tell me how to do, because I really don't understand the datasheet about this. On ARM (the microprocessor on which I learned), the GPIO was the default setting, is it the case on ATTiny85 ?

 

Video YouTube ici

https://youtu.be/qpVsfJcuIbI

 

Rgds, Charly.

Last Edited: Sat. Jun 2, 2018 - 08:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, PB4 defaults to GPIO. You don't need to do anything.
It only becomes XTAL2 if the clock fuses are set for crystal osc.
.
As mentioned earlier, you will get multiple interrupts from a mechanical switch. If you have an even number of interrupts you will not notice any difference.
.
It is always wise to use a Timer interrupt. Then debounce the mechanical switch.
If your input is a machine generated falling edge, you don't need to worry about bouncing.
.
David.

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

OK, so as you can see on the video on my precedent post, it doesn't work.

 

Actually, interrupt fonction, in my final application, will be fairly long, around 10 secondes. So I don't understand what the problem with the interrupt ?

My Interrupt will be activated by a mercury on/off switch, I cannot do it with a timer.

 

So I thought the ISR will be the more clean method, but maybe should I just check the PIN on the while lopp !?

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

Your yellow wire appears to be connected to VCC.    And you plug the free end into the PB2 pin.

 

If you want an interrupt,  you place the fixed end of the yellow wire in PB2.    And plug  the free end into GND for a falling edge.

 

Using a Timer is much simpler.   Interrupt every 10ms and read PB2.     If the state of PB2 is unchanged for 5 interrupts (50ms) it is debounced.   

 

You can also use the Timer interrupt to blink your LED.    On for 20 ticks on,  off for 20 ticks.

 

David.

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

charlycop wrote:
I simply disconnect the PIN 7 (PB4), in order to make the interrupt on the falling edge.

There are many things to point out with that statement.

 

-- Your "simple" disconnection can bounce.  Perhaps even more than a switch or button.

-- Do you have an external pulldown on that signal line?  If not, then what makes you think the level will drop on a floating pin?

 

(most of us would use the AVR input internally pulled up.  And then a switch/button to ground.

 

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, if diode = 0, then 1-0= 1. Its not going to toggle. Something like diode^=1; might be more effective.
Regardless of whether the external input bounces or not, you would probably want to add some form of filtering to eliminate false signals due to transients,ESD etc. especially if there is a length of wire connecting it. You don’t expect a mercury switch to operate too frequently, so inputs less than ,say 10ms are glitches.

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

diode = 1- diode toggles. It is just a weird way to do exclusive or 1.
Pulled up is high or direct to VCC is high. There is no falling edge.
.
Your yellow wire should be between PB2 and GND. Or the mercury switch should be between PB2 and GND.
.
David.

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

david.prentice wrote:

Your yellow wire appears to be connected to VCC.    And you plug the free end into the PB2 pin.

 

If you want an interrupt,  you place the fixed end of the yellow wire in PB2.    And plug  the free end into GND for a falling edge.

 

Using a Timer is much simpler.   Interrupt every 10ms and read PB2.     If the state of PB2 is unchanged for 5 interrupts (50ms) it is debounced.   

 

You can also use the Timer interrupt to blink your LED.    On for 20 ticks

David.

Thanks David, it seems to work. By the way can you explain the difference between PORTB and PINB in the GPIO context ??

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

theusch wrote:

charlycop wrote:
I simply disconnect the PIN 7 (PB4), in order to make the interrupt on the falling edge.

There are many things to point out with that statement.

 

-- Your "simple" disconnection can bounce.  Perhaps even more than a switch or button.

-- Do you have an external pulldown on that signal line?  If not, then what makes you think the level will drop on a floating pin?

 

(most of us would use the AVR input internally pulled up.  And then a switch/button to ground.

 

Ok got it thanks a lot

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

Yes it toggles of course :)
Thanks

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

charlycop wrote:

 Thanks David, it seems to work. By the way can you explain the difference between PORTB and PINB in the GPIO context ??

 

Go on.   The AVR has different registers for output latch and input port.

 

Reading PORTB reads the output latch i.e. wot you had last written to PORTB.

Reading PINB reads the input pins i.e. what is actually on the pins.

 

If a GPIO pin has been configured as output i.e. with DDRB,   it is very likely to read the same on PINB.# as what value you had left in the PORTB.# latch.

However shorting out a push-pull output pin will cause excess current and probably tell you via PIN.# being different to PORT.#

 

PIC14, PIC18, ... use the same name for input and output.    But at least they make it obvious that LATx is a latch.

 

David.

Last Edited: Sun. Jun 3, 2018 - 09:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, it is not crytal clear for me, but clear enough :)

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

Buy plenty of tea bags.   And a nice packet of biscuits.

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

david.prentice wrote:

Buy plenty of tea bags.   And a nice packet of biscuits.

LOL, very british answer :)

 

Anyway, thanks for a lot your help, here is my project working :

https://www.youtube.com/watch?v=N-6z0r_9GFA

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

Just wanted to thank you guys, my project is finish.

A full description with videos here :

http://fablab.sorbonne-universit...