Pin change interrupt

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

Hello all!

I have an atmega168, and I want to count the time with a timer the time that one of my pins went high or low.
How do I do this?

I came up with the idea of a pin change interrupt, but I don't know how to do that.

I wrote the following code, but it is not working. It compile fine, but my idea does not works as I want.

#define F_CPU 14745600

#include 
#include 

#include 
#include 
#include 
#include 

#include "../delay.h"
#include "../lcd.h"
#include "../uart.h"

// PIN DEFINITIONS:
void setup() {
EICRA = (1<<ISC11);
  PCMSK0 |= (1<<PC5);

  // turn on interrupts!
  EIMSK  |= (1<<INT0);
}

volatile int32_t the_time;

SIGNAL (SIG_INT0)
{
   the_time++;
}


int main() {
 setup();

  // init lcd
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

  // init serial port
  uart_init();
  FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
  stdin = stdout = &uart_stream;

  // turn on interrupt handler
  sei();

  while(1) {
    lcd_home();
    fprintf_P(&lcd_stream, PSTR("%16.2f sec"), (double) the_time / 100.0);
  }


  return 0;
}

Any ideas???

Thanks!!!

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

Where is the interrupt code ?

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

sparrow2 wrote:
Where is the interrupt code ?

Isn't it this one?
SIGNAL (SIG_INT0)
{
the_time++;
}

??? I am not good at interrupts. I don't really know how to do it. This is what I did by looking at my atmega168 datasheet.

Please help :(

Thanks in advance :)

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

I'm confused about what you are trying to. Are you trying to COUNT the number of times a pin goes high (or low)? Or are you trying to TIME the time that a pin is high (or low)? Your code seems to be trying to do both.

Tell us what you are trying to do in more detail and then we can help.

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

lcruz007 wrote:

Isn't it this one?
SIGNAL (SIG_INT0)
{
the_time++;
}

??? I am not good at interrupts. I don't really know how to do it. This is what I did by looking at my atmega168 datasheet.

Please help :(

Thanks in advance :)

SIG_INT0 identifies an interrupt vector, yes; it's just not the pin-change interrupt that you mentioned in your original post. That would be PCINT0_vect or PCINT1_vect, or PCINT2_vect, depending on which port(s) you're interested in changes on. Your code doesn't enable a consistent set of interrupts; as far as I can tell, you set up to enable interrupts only for external interrupt 0 (Port D, bit 2), and then you set the interrupt behavior for external interrupt #1 (Port D, bit 3), whose interrupt vector is not defined, and whose interrupt isn't enabled. The behavior for interrupt 0 (the one you did enable and for which you DO have a service routine installed) is left at its default (active-low) behavior.

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

Well, I think I could work with both methods. But I was trying to read the time that the pin was high or low.
Because, what I really need is to know how much does a digital signal changes from high to low.

I am working with an accelerometer, it is high at 0g in a 50% duty cycle. When I move it, it changes proportionally to acceleration.

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

Connect the signal you want to measure the duty factor of to the Timer1 "input capture" pin. You don't say what the frequency of the signal you need to measure is, and it would be possible for the frequency to be too high for this method to work, but generally, the scheme is as follows:

* Allow Timer1 to free-run at some suitable frequency (for best resolution,
one at which it's able to count nearly to fullscale
during one cycle of the input signal)
* Enable the Timer1 capture interrupt
* Provide an ISR for the timer1 capture event that
   a) Copies the latched, captured timer count into
      either of two slots of a two-element array,
      depending on which edge the capture occurred on
   b) Flip the selected "active edge"  that
      determines when the next capture occurs
   c) On one of the edge types (the falling one, say)
      set some signal that your main() code can
      watch for one.  For true slickness, you could
      use two sets of two-element "high" and "low"
      measurements, and allow main() to see which one
      the ISR is currently accumulating.  Or you could
      reenable interrupts at this point while you
      recompute the ratio of high-to-low (just get
      comfortably done during one cycle of the signal)

Or you could run your signal through an RC filter and use the onboard A/D converter to digitize the value.

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

Hi,
Thanks to all for your replies.

OK, I have this in my code just to see if my pin change interrupt is working, and want to try to light up an LED.

void setup() {
    //TIMSK1 |= (1<<ICIE1);



  EICRA |= (1<<ISC00);
  PCMSK0 |= (1<<PB0);
  PCICR |= (1<<PCIE0);
  PCIFR |= (1<<PCIF0);
  // turn on interrupts!
  EIMSK  = (1<<INT0);
  EIFR |= (1<<INTF0);
}

ISR (PCINT0_vect)
{
   DDRB |= (1<<PB3);
}

What am I doing wrong here? Like I said before I am a newbie in the part of interrupts, I guess that my code above is lame.

Thanks in advance. :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ISR (PCINT0_vect)
{
   DDRB |= (1<<PB3);
}

You want to change the direction of the pin B3 when you get an interrupt?!? Nope, in fact what I think you want is:

void setup () {
. . .
    DDRB = | (1 << PB3);
    PORTB = 0;
. . .
}

ISR (PCINT0_vect)
{
   PORTB |= (1<<PB3);
}

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!