March 26, 2011
by hariharan
|
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
|
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
|
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
|
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
|
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
|
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
|
My Bad! |
March 26, 2011
by hariharan
|
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
|
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
|
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
|
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
|
Even though, it gives an error message. Like: in function _vector_4, expected '>' before '{'token, expected expression before '}' token |
March 26, 2011
by hariharan
|
srry, Expected ')' before '{' token |
March 26, 2011
by hariharan
|
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
|
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
|
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
|
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
|
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? |