question about interrupts [codevision]

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

hi

i know that there are lots of theads about interrupts, but mostly they go about other c-compilers, then codevision.

i have these codes:

  // interrupt on INT0 pin falling edge (sensor triggered) 
  MCUCR = (1<<0) | (1<<1);

  // turn on interrupts!
  GICR  |= (1<<6);

i don't know how to go further, i have seen things like 'SIGNAL' and otherstuff, but codevision, doesn't reconise it.

is it possible to create an interrupt when i push a button on the STK500.

i use an ATmega16L on the STK500.

hopefully you guys can help me, thanks

Robbin

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

Provak wrote:

i don't know how to go further, i have seen things like 'SIGNAL' and otherstuff, but codevision, doesn't reconise it.

It sounds unbelievably for me, that there is no example directory inside your codevision installation. :roll:

Absolute every Compiler, which I have installed, create also an example directory.
Typically there are UART and interrupt examples inside.

Provak wrote:

is it possible to create an interrupt when i push a button on the STK500.

This is definitely the worst approach to read a key.

Peter

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

what do you mean with "definitely the worst approach to read a key"

i just want to know how to create and use interrupts and this was the first thing that came up in my head.

anyway,

i use the code generator to help me,

interrupt [EXT_INT0] void ext_int0_isr(void)
{
PORTA.0 = 0;

}

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Low level
// INT1: Off
// INT2: Off
GICR|=0x40;
MCUCR=0x00;
MCUCSR=0x00;
GIFR=0x40;

// Global enable interrupts
#asm("sei")

how can i write down, that when i push button (PIND.0) that the interrupt wakes up??

Robbin

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

Quote:

what do you mean with "definitely the worst approach to read a key"

Search for "switch bounce". Short answer: When a switch makes contact it does not go from open to closed in one clean transition. Instead it closes and opens several times in a short period before coming to rest in the closed position. Thus, if you are using an interrupt to capture the changing of switch state you will see what looks like maybe ten presses of the switch.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Robbin,

Look in the \cvavr\examples directory for some example projects. Start with using an IRQ to flash an LED.

You can use the CodeWizard to create the IRQ initialisation code and skeleton ISR (interrupt service routine) code. You have to write the actual code inside the ISR.

Alternatively you write everything by hand (which I do). The CodeVision help will show you the syntax and give advice on interrupts. You can find lots of example code on AvrFreaks although much is avr-gcc. The only difference is syntax and constants from header files.

#include       //CV cpu specific header for TIM1_OVF value
//#include         //you could use this instead
interrupt [TIM1_OVF] void timer1_overflow(void) //CV 

#include       //GCC cpu for SIG_xxx values
#include    //GCC ISR macro
ISR(SIG_TIMER1_OVERFLOW) //GCC check spelling

As danni has suggested, there may be better ways of scanning a key. (ie use a timer IRQ)

HTH David.

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

i know, i have read about that, but that is not a priority now, i need first that i can activate the interrupt.

how can i do that, thanks

Robbin

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

Robbin,

1. you write the ISR. It is identified by the signal number value. These vary for each chip and the syntax as I have shown. The cpu will automagically go to the correct ISR for each type of interrupt.
2. you set the specific interrupt enable bits in MCUCR
3. you turn on interrupts in GICR
4. you execute #asm("sei") to enable the cpu

5. at times you will need a sei/cli pair in your main routines to alter a volatile variable. You could do this with GICR if you wanted.

6. in general ISRs are short and sweet. So you do not need to re-enable IRQs from within an ISR unless strictly necessary.

7. both CV and GCC will look after register saves etc for the ISR. But it is always worthwhile to read the datasheet and the compiler manuals if you are doing hairy things.

David.

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

hi david, thanks for the help. i can almost dream the datasheet, but it isn't really helping me.

i have this code:

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
if(PIND.0 == 1){
PORTA.0 = 0; }
}

GICR|=0x40;                 
MCUCR = (1 << 1) | (1 << 0);   
MCUCSR=0x00;

// Global enable interrupts
#asm("sei")

how can i start the interrupt when i press a button. i'm still looking at other threads but i can't find it :(.

Robbin

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

Why are you checking PIND.0 in the ISR? Are you expecting both PD2 (INT0) and PD0 to be activated at the same time? The very fact that control enters ext_int0_isr() is enough to tell you that a pin transition has occurred - you don't need to go reading PINs as well (unless the action of the ISR is REALLY dependent on two different lines activating?)

But as other have said this is the WORST way to learn about using ISRs as your button will bounce and you have to program through hoops to get around the multiple interrupt thing.

You'd be far better off starting a timer and setting it up so that it generates an interrupt. Then have that interrupt handler just toggle (XOR = ^ is good for this!) the state of an LED). If you slow the timer interrupts down enough (high prescale and use overflow interrupts) then you can get the LED to flash at a nice slow rate that the human eye can see. (the 16 bit timers rather than 8 bit can help too as they can reach even longer on/off periods)

Cliff

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

you are right with the last part, with the bouncing and stuff, but first do i need to know how the interrupts gets activated, before i combine it with other things like timer.

i deleted the PIND.0, can you tell me what i need to add to let it work. when it works i will at the timer, and try it the way you said.

many thanks for the advice.

Robbin

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

Both Cliff and I have suggested starting with a timer interrupt. When you are happy with that, go try pin-change IRQs.

The other suggestion is: care about your layout and formatting. Unfortunately CV examples are appalling in this. I find that consistent indentation is incredibly helpful. Also do not be shy of posting your whole code. Strip out some dross but make it compilable. I am as guilty as anyone for silly typos or misplaced braces.

It looks as if your code example will light your LED only when the switch is not made. ie you would not have an IRQ. Just toggle the LED with: PORTA.0 = !PORTA.0 You may get bounce but at least you have a chance of seeing something.

David.

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

i used the codegen again to create the timer interrupt. i have this code:

#include 
#include 
#include 

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTA.0 = !PORTA.0;
delay_ms(100.);

}

// Declare your global variables here

void main(void)
{
// Declare your local variables here


  DDRA = 0xFF;   //  We put port A pins in output mode  
  PORTA = 0xFF;   // put all leds in off state 
  DDRD = 0x00;    // We put port D pins in input mode  
  PORTD = 0xFF; //  we activate the internal pull-up  

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 3680,000 kHz
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x01;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;


// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// Global enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here

      };
}

it works, but i want to control it. which code does the timer start and how can i ajust the timer interval.

Robbin

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

Never put a delay or while loop inside an ISR. You need them to be lean and mean.

You alter the timer IRQ by setting the prescaler bits and the timer values. It is all in the datasheet. The timer will count up to top and then cause an overflow. You can make a timer count up or down, count between a low value and a high value, and a multitude of other modes. You are probably better off with a 16bit counter and a large pre-scale to see an LED flash.

The CodeWizard can set all these values. Just look at the generated code and see what changes. The Wizard writes some comments as well for you. It just does not format the code as I would wish.

Personally I prefer to do things by hand. Print the relevant pages from the datasheet. Everything then becomes clearer.

David.

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

i'm still trying to figure out how to get the time longer, damn for some reason i don't understand it really. lets give it another try.

do i need to create a timer what is not connected to the timer interrupt, or do i need to change the values of the timer interrupt, to make the interval longer and so. i think last, never thought it would be so diffecult.

Robbin

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

Two methods:

1. Use a 16bit timer with prescale will get longer times

2. Use 8 or 16bit timer. The ISR just increments a 16 or 8 bit variable. If the variable overflows then do your thing. eg.

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
    static volatile unsigned int var;
    if (++var >= 20000) {
         var = 0;
         PORTA.0 = !PORTA.0;
    }
    // delay_ms(100.); NEVER EVER use delay inside ISR
}

I quite often use Timer 0 in CTC mode to overflow at say 1 mS. Then the single ISR can do things at 20mS or 100mS or 1000mS. For example a clock would be a sequence of:

if (++ms > 999)
    ms = 0;
    if (++seconds >59) {
        seconds = 0;
        if (++minutes > 59) {
            minutes = 0;
            if (++hours > 23) {
                 hours = 0;
            }
        }
    }
}

The execution time of the ISR even at midnight is measured in uS. Most IRQs are just executing: if (++ms > 999) which is probably less than 10uS.

David

Last Edited: Thu. Sep 27, 2007 - 01:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i see, thanks for the example. i read about the volatile in other threads, why is that ?

Robbin

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

All the variables that can get changed by the ISR need to be qualified with volatile. Your main() routine never seems to change them, so a clever compiler could assume that they never change. If you tell the compiler then it knows not to make this optimisation.

Consider a code sequence in main():

    seconds = 0;
    while (1) {
        if (seconds != 0) do_something();
    }

The compiler would say that do_something() could NEVER execute. But you know that seconds change in the ISR.

David

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

(i have another question, is it possible to run codes in the while at the same time?. to explain it a bit better. when a code is executed will it return to the place were it was when an interrupts came.) figured out myself

hopefully you understand what i mean ^^.

(and.. the interrupts starts right away, is it possible to controle it. that it starts when i do something? ) i figured that out myself ^^
Robbin