NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Interrupts

March 26, 2011
by hariharan
hariharan's Avatar

Normally, hardware interrupts are programmed by using the isr() notation. In the crystal time project, signal() notation is used. What's the difference? And also, how do we program hardware interrupts to do something first time, second time, and third time?

March 26, 2011
by bretm
bretm's Avatar

In older versions of avr-gcc SIGNAL was the only way to do it, so you'll see this more often in older code. The difference is that interrupts are disabled inside an ISR but are enabled inside a SIGNAL. That means SIGNAL code has to support re-entrancy in many cases (because another interrupt can happen while you're processing the first one) which makes the code harder to write correctly, so ISR is recommended over SIGNAL for new code.

volatile int whichTime;

ISR(something_vect)
{
    whichTime++;

    switch(whichTime)
    {
        case 1:
            // first time
            break;

        case 2:
            // second time
            break;

        case 3:
            // third time
            break;
    }
}

int main()
{
    whichTime = 0;
    // other stuff
}
March 26, 2011
by hariharan
hariharan's Avatar

Then, will this code work?

#define F_CPU 14745600 
#include <stdio.h>

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

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h
int main() {
  DDRC &= ~(1<<PC4);
volatile int whichTime;   
ISR(_vect) {     
whichTime++;     
if (PINC & (1<<PC4){
  switch(whichTime)    {       
  case 1:             
  // first time
printf_P(PSTR(" first medicine taken\r\n"));             
  break;        
   case 2:           
  // second time     
  printf_P(PSTR(" second medicine taken\r\n")); 
        break;         
  case 3:           
  // third time           
 printf_P(PSTR(" third medicine taken\r\n")); 
  break;     
  } 
  } else {
  printf_P(PSTR("medicine not taken! \r\n")); 
  }
return 0; 
  }
March 26, 2011
by Ralphxyz
Ralphxyz's Avatar

Short answer NO!!

Now look up:

ISR(_vect)

What interrupt vector do you want to use?

Then you should limit what is going on while handling your interrupt, what would happen while your interrupt was attempting to do the printfs another interrupt was called?

Things like doing prints should be done in your main() function probable in a while loop.

Back to the books.

Ralph

March 26, 2011
by hariharan
hariharan's Avatar

will this work?

#define F_CPU 14745600 
#include <stdio.h>

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

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h
int main() {
  DDRC &= ~(1<<PC4);
volatile int whichTime;   
ISR(PCINT1_vect) {

medicineTime++;     
while (1){

if (PINC & (1<<PC4){
  switch(medicineTime)    {       
  case 1:             
  // first time
printf_P(PSTR(" first medicine taken\r\n"));             
  break;        
   case 2:           
  // second time     
  printf_P(PSTR("second medicine taken\r\n")); 
        break;         
  case 3:           
  // third time           
 printf_P(PSTR(" third medicine taken\r\n")); 
  break;     
  } 
  }
  return 0;
  } 
}
March 26, 2011
by Ralphxyz
Ralphxyz's Avatar

Well did you try it?

For one thing the ISR goes outside of your main() function like you had it originally. When I said to do your prints in your main() functions you would set a variable in the ISR and then print that variable in the main().

Does asking if a code set works really make much sense? What do expect us to do load it and try it out for you?

You get much better answers if you were to ask "Why doesn't this code work".

Ralph

March 26, 2011
by hariharan
hariharan's Avatar

My Bad!

March 26, 2011
by hariharan
hariharan's Avatar

I tried a simpler code for getting to know interrupts. I made a code that will make a led blink at a slower rate than before when there is a interrupt. this code has the isr outside the main(). But why is'nt it working?

// led_blink.c
// for NerdKits with ATmega168
// hevans@nerdkits.edu

#define F_CPU 14745600

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

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

// PIN DEFINITIONS:
//
// PC4 -- LED anode

int main() {
  // LED as output
  DDRC |= (1<<PC4);
  DDRC &= ~(1<<PC5);

  // loop keeps looking forever
  while(1) {
    // turn on LED
    PORTC |= (1<<PC4);

    //delay for 500 milliseconds to let the light stay on
    delay_ms(500);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(500);

  }
  }
 ISR(PCINT1_vect){
 sei();
 if (PINC&(1<<PC5){
 PORTC |= (1<<PC4);

    //delay for 500 milliseconds to let the light stay on
    delay_ms(1000);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(1000);
    //delay for 500 milliseconds to let the light stay on
    PORTC |= (1<<PC4);

    delay_ms(1000);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(1000);

}
return 0;

}
March 26, 2011
by leedawg
leedawg's Avatar

Your code does not work because you have not set up the interrupts yet. You need to define what type of interuptt is going to happen. As your code reads right now, the AVR has no way of knowing that when you push a button to fire the interrupt that you have defined. So it looks as though you have defined the interrupt fine but you need to tell the avr what is going to make the interrupt fire and you set that up in your int main routine, per the data sheet for the avr.

Let me see if I can dig up some code to show you in a bit.

Lee

March 26, 2011
by leedawg
leedawg's Avatar

Alrighty here it is you need to add something like this to your main routine to set up the interrupts for the avr

PCICR |= (1<<PCIE1); //set up interrupt values  This will pcint values 23-16 to fire the interrupt.

PCMSK1 |= (1<<PCINT13); //This will mask the other pins so that only PC4 fires the interrupt.

That ought to do it so your code should read something more like this..

// led_blink.c
// for NerdKits with ATmega168
// hevans@nerdkits.edu

#define F_CPU 14745600

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

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

// PIN DEFINITIONS:
//
// PC4 -- LED anode

void init_interrupt(){
 PCICR |= (1<<PCIE1); //set up interrupt values  This will pcint values 23-16 to fire the interrupt.

PCMSK1 |= (1<<PCINT13); //This will mask the other pins so that only PC4 fires the interrupt.
}

int main() {
  // LED as output
  DDRC |= (1<<PC4);
  DDRC &= ~(1<<PC5);
init_interrupt(); 
  // loop keeps looking forever
  while(1) {
    // turn on LED
    PORTC |= (1<<PC4);

    //delay for 500 milliseconds to let the light stay on
    delay_ms(500);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(500);

  }
  }
 ISR(PCINT1_vect){
 sei();
 if (PINC&(1<<PC5){
 PORTC |= (1<<PC4);

    //delay for 500 milliseconds to let the light stay on
    delay_ms(1000);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(1000);
    //delay for 500 milliseconds to let the light stay on
    PORTC |= (1<<PC4);

    delay_ms(1000);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(1000);

}
return 0;

}

Good luck it might not run because I may have made an error somewhere you compiler will tell you when you try to compile the code but the principle is what you need. Go read the data sheet on page 70 in the PDF file and it will tell you all about the pin change interrupt register and mask register that is where I got all the info on it.

Let us know how it went.

Lee

March 26, 2011
by leedawg
leedawg's Avatar

I made an error that I just saw in my code in the comments where I wrote PC4 I meant PC5 which is the pin you defined as your input pin.

Good luck

March 26, 2011
by hariharan
hariharan's Avatar

Even though, it gives an error message. Like: in function _vector_4, expected '>' before '{'token, expected expression before '}' token

March 26, 2011
by hariharan
hariharan's Avatar

srry, Expected ')' before '{' token

March 26, 2011
by hariharan
hariharan's Avatar

I found the error! in line 47, there should be another ')' before '{' thanks every one for helping me! i have another question. how do you program a timer interrupt? in the crystal clock program, they use a signal() notation. can u do that with a ISR() notation?

March 26, 2011
by leedawg
leedawg's Avatar

Yes just look up the library its under your start menu and will tell you all the things you can use in the interrupt library. ISR will work fine and you can use another command for the timer interrupt. And im sorry I missed a brace like I said I was just typing it into the forum here and did not run it through my compiler which usually always tells me I have an error and have to track it down. Glad to hear it is working for you now though.

Lee

March 26, 2011
by Ralphxyz
Ralphxyz's Avatar

And once again go back to the specsheet and search the Nerdkits forum for Timer Interrupts, you will find lots of examples in the forum and the specifics in the specsheet.

It don't come easy there is certain steps you just gotta do, like reading the specsheet and seeing what has been said before.

You are not the first to ask these questions, you rarely will be.

I am glad you have made good progress.

Ralph

March 27, 2011
by hariharan
hariharan's Avatar

i wanted to modify the crystal time code to display hours and minutes. so, i looked at the libc document and modified the code. But it does not work. why?

// realtimeclock1.c
// for NerdKits with ATmega168
// mrobbins@mit.edu

#define F_CPU 14745600

#include <stdio.h>
#include <stdlib.h>

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

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

// PIN DEFINITIONS:

void realtimeclock_setup() {
  // setup Timer0:
  // CTC (Clear Timer on Compare Match mode)
  // TOP set by OCR0A register
  TCCR0A |= (1<<WGM01);
  // clocked from CLK/1024
  // which is 14745600/1024, or 14400 increments per second
  TCCR0B |= (1<<CS02) | (1<<CS00);
  // set TOP to 143
  // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...
  // so 0 through 143 equals 144 events
  OCR0A = 143;
  // enable interrupt on compare event
  // (14400 / 144 = 100 per second)
  TIMSK0 |= (1<<OCIE0A);
}

// the_time will store the elapsed time
// in hundredths of a second.
// (100 = 1 second)
// 
// note that this will overflow in approximately 248 days!
//
// This variable is marked "volatile" because it is modified
// by an interrupt handler.  Without the "volatile" marking,
// the compiler might just assume that it doesn't change in 
// the flow of any given function (if the compiler doesn't
// see any code in that function modifying it -- sounds 
// reasonable, normally!).
//
// But with "volatile", it will always read it from memory 
// instead of making that assumption.
volatile int32_t the_time;
int main (){
int8_t h, m;
m <60;
h < 24;

SIGNAL(SIG_OUTPUT_COMPARE0A) {
  // when Timer0 gets to its Output Compare value,
  // one one-hundredth of a second has elapsed (0.01 seconds).
  the_time++;
}
#pragma vector=TIMER0_OVF_vect
__interrupt void MotorPWMBottom()
{
 if ( the_time = 60) {
m +=1
}
if ( m = 59) { 
h +=1
}
}

int main() {
  realtimeclock_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("%d :%d :%16.2f sec"),h(double) the_time / 100.0);
  }

  return 0;
}

i think it does not work since #pragma vector=TIMER0_OVF_vect __interrupt void MotorPWMBottom() the right way. if so, how should i use it?
March 28, 2011
by hariharan
hariharan's Avatar

i figured out that i shouldn't have used #pragma vector=TIMER0_OVF_vect __interrupt void MotorPWMBottom(). but how do i program that m+=1 when the_time = 60 and h+=1 when m = 60? i want to fire a interrupt when the_time= 60, but can i do it without using any pin change interrupt or timer interrupt?

Post a Reply

Please log in to post a reply.

Did you know that there are Power MOSFETs for switching big loads on and off? Learn more...