0

I'm trying to learn how to program a MC, so maybe I didn't know much about a MC. I tried to test interrupt pin of ATtiny85 with this simple code

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

void setup()
{
  GIMSK = 0b00100000;
  PCMSK = 0b00000001;
  sei();
  DDRB = 0b00010000;
}

void loop()
{
  PORTB = 0b00010000;
  _delay_ms(500);
  PORTB = 0b00000000;
  _delay_ms(500);
}

ISR(PCINT0_vect)
{
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);
  PORTB = 0b00010000;
  _delay_ms(100);
  PORTB = 0b00000000;
  _delay_ms(100);

}

This is just a blink code with an interrupt to make the LED blink faster 10 times. My question is why sometimes the LED blink faster many times with the interrupt pin is not connected to anything (open)? Didn't it have internal pull up or should I use external pull up in my circuit?

Thank you

  • You only get an internal pullup if you actively turn that internal pullup on. – Majenko May 4 '18 at 19:24
  • @Majenko so how to enabling internal pullup with use it as interrupt pin too? is it possible? – juliussin May 4 '18 at 19:26
  • The interrupt functionality is completely separate to the IO functionality. Make sure the pin is an INPUT and set it HIGH will turn on the pullup. You need to know which DDR and PORT for the pin you're using as an interrupt of course. – Majenko May 4 '18 at 19:28
  • You really shouldn’t have interrupts that take multiple seconds to finish executing. Interrupts should finish quickly so your main program can get back to its processing. – RubberDuck May 5 '18 at 3:13
1

More than an answer, these are some comments and suggestions on your program, that I hope will help you write cleaner code:

  1. Since you seem to be avoiding using the Arduino core library, you may as well write your own main() instead of relying on the one from the core. This way you have a plain C program that can be compiled either within or outside of the Arduino framework.

  2. Instead of opaque constants, like 0b00100000, use the bit names. These names are defined in the datasheet and are provided by the avr-libc. They are normally used with the _BV() macro, which expands to (1<<(x)).

  3. For those of us who do not have the full datasheet in our head, a comment or two stating what each bit does is helpful.

  4. To change only one bit from a port, use the syntax PORTB |= ...; or PORTB &= .... The compiler is smart enough to turn this into single assembly instructions, namely sbi and cbi.

  5. Rather than repeating ten times the same lines, use a loop.

Applying these suggestions, your program would like like;

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

ISR(PCINT0_vect)
{
    for (int i = 0; i < 10; i++) {
        PORTB |= _BV(PB4);
        _delay_ms(100);
        PORTB &= ~_BV(PB4);
        _delay_ms(100);
    }
}

int main(void)
{
    PORTB = _BV(PB0);     // internal pullup on PB0
    GIMSK = _BV(PCIE);    // enable pin change interrupt
    PCMSK = _BV(PCINT0);  // sense pin change on PCINT0 = PB0
    DDRB  = _BV(PB4);     // pin PB4 as output
    for (;;) {
        PORTB |= _BV(PB4);
        _delay_ms(500);
        PORTB &= ~_BV(PB4);
        _delay_ms(500);
    }
}
  • Wow thank you very much this is very helpful. This is very useful for beginners. And what's the double semicolon for? Is it like while(1)? Since there are so many tutorials with Arduino library, it's pretty difficult to find some code examples with plain C program (or not?) – juliussin May 5 '18 at 11:49
  • The for(;;) is an infinite loop, just like while(1). – chrisl May 5 '18 at 13:44
  • Did this code solve your problem with the double execution, that you mentioned below? – chrisl May 5 '18 at 13:44
  • @juliussin: As stated by @chrisl, for (;;) introduces an infinite loop. I prefer it over while (true) because it feels natural to me to read it like “for (ever)”. – Edgar Bonet May 5 '18 at 16:47
  • @chrisl I just tried this code, and this code didn't solve the double ISR if I connect the interrupt pin to the ground with a jumper (I use breadboard to place my ATtiny85) and the repeated ISR if I touch the jumper pin. And unfortunately I doesn't have scope to check the signal of the interrupt pin :( – juliussin May 5 '18 at 18:25
2

The internal pullup is only activated, if you activate it in your code. To so, you have to write a 1 to the corresponding bit in the PORTB register, while the DDRB register is set for the pin to be an input.

So you the interrupt gets triggered randomly, because the pin was floating.

Since you are currently always write to the whole PORTB, you have to change the last bit to 1 on every PORTB write. Or you can write a 1 to it in setup() and only change the one output bit in PORTB by using

PORTB ^= 0b00010000;

This will toggle only your output pin.

  • Wow thank you, I'm using PORTB because I want to learn how register work and avoid to depend on library. So based on your suggestion I changed the last bit to 1 on every PORTB I wrote. I think this is worked pretty good. But if I touch the interrupt pin with my hand, the ISR run repeated. Is this because the trigger is unstable if I touch it? – juliussin May 4 '18 at 19:47
  • This should not happen, if you activated the internal pullup resistor. I tried this with my ATTiny85 and it works perfectly. – chrisl May 4 '18 at 20:06
  • I activated the internal pullup as you said by changed the last bit to 1 on every PORTB I wrote. But with the human touch, it's still unstable. And another problem, If i connect the interrupt pin to VCC, nothing happened (because it is pulled up right?) but if i connect it to GND, it run ISR twice, and then I release it, it run ISR once. – juliussin May 4 '18 at 20:21
  • Odd behavior (that with the double execution). I couldn't reproduce that on my hardware. Maybe there is something odd with your wiring. – chrisl May 4 '18 at 20:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.