Need help with timer - c

For last 2 weeks am trying to learn timer & interrupt & wrote a program (with my understanding) to blink LEDs on ATMEGA2560 but no matter what I do TCNT0 never increments & ISR() function never gets called. Where am I going wrong and how can I fix it? Here is my code:
#include<avr/io.h>
#include<avr/interrupt.h>
#define READ_ATMEGA(ADDR) *((P_CHAR)(BASE_ADDR + ((ADDR) * ADDR_MULTIPLIER)))
#define WRITE_ATMEGA(ADDR, DATA) *((P_CHAR)(BASE_ADDR + ((ADDR) * ADDR_MULTIPLIER))) = DATA
#define BASE_ADDR 0x20
void init_timer0_ovf_interrupt(void);
void timer0_interrupt_isr(void);
void initialize_ports(void);
void delay(unsigned int no_65_5ms_interrupts);
void __attribute__((ISR)) timer0_interrupt_isr(void);
//#pragma interrupt_handler timer0_interrupt_isr:24
unsigned int delay_timer;
int main(void)
{
initialize_ports();
init_timer0_ovf_interrupt();
delay(46);
return 0;
}
void initialize_ports(void)
{
READ_ATMEGA(4) = 0xff;
WRITE_ATMEGA(5, 0x00);
}
void delay(unsigned int no_65_5ms_interrupts)
{
TCNT0 = 0x00;
delay_timer = 0;
while(delay_timer <= no_65_5ms_interrupts)
{
;
}
}
void init_timer0_ovf_interrupt(void)
{
TCCR0A = 0X00;
TCCR0B = 0x02;
TIMSK0 = 0x01;
TIFR0 = 1<<0;
OCR0A = 25;
sei();
}
void timer0_interrupt_isr(void)
{
delay_timer++;
if(delay_timer >= OCR0A)
{
PORTB = ~(PORTB);
delay_timer = 0;
}
}

The global variable delay_timer is shared between interrupt and non-interrupt code. It should be declared as volatile as the value can change outside of delay().
If you look at the generated code for delay() you'll probably see that the value of delay_timer isn't being re-read while spinning in the while loop.
Also, volatile isn't enough. You've got non-interrupt code and interrupt code both writing to the same variable (delay_timer). You need to protect writes to the variable in non-interrupt code, there's a race-condition there. The easy/lazy way is to disable interrupts & restore them in the non-interrupt code.
(As for setting up your interrupts & starting your timer, that info should be in the chip's datasheet. Usually that's the part that's easier to get right, it's the shared data stuff that bites people.)

3-4 days ago, I wrote the same program a little differently & got LEDs blinking but still not sure whether it is the correct way of using timer & interrupt. Could anyone please see this & tell me whether it's the correct or not? I managed to write this program by reading programs of timers, interrupts.
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t intrs;
ISR(TIMER0_OVF_vect) {
/* this ISR is called when TIMER0 overflows */
intrs++;
/* strobe PORTB.5 - the LED on arduino boards */
if (intrs >= 61){
PORTB = ~PORTB;
intrs = 0;
}
}
int main(void) {
TCCR0B = 0x02;
/* Enable Timer Overflow Interrupts */
TIMSK0 = 0x01;
/* other set up */
DDRB = 0xff;
TCNT0 = 0;
intrs = 0;
/* Enable Interrupts */
sei();
while (1)
; /* empty loop */
}
If it's the correct way then I can start working on next step.
Thanks

If could be that your while loop in the delay function doesn't do anything and will not increment delay_timer so you are stuck in an endless loop:
void delay(unsigned int no_65_5ms_interrupts)
{
TCNT0 = 0x00;
delay_timer = 0;
while(delay_timer <= no_65_5ms_interrupts)
{
; //Nothing is happening here!!
}
}

Related

Can someone explain what does the interrupt "Trap" do in the micro controller

I am using stm8l - discovery board and I am curious about the functionality of trap in the micro controller. My program stops instead of running continously in the while loop, Is the functionality of trap interrupt that if it occurs, it does not execute (similar to reset)?
#include <iostm8l.h>
#include <stdio.h>
#include <stdint.h>
void Cus_delay(uint32_t ntime)
{
while(ntime!=0)
{
ntime--;
}
}
main()
{
CLK_DIVR = 0x00; // Set the frequency to 16Mhz
PC_DDR = 0x80; // direction output for led
PC_CR1 = 0x80; // fast push pull mode
int a = 10;
while(1)
{
Cus_delay(400000);
Cus_delay(400000);
PC_ODR ^= 0x80;
a = a/0;
}
}

init External Interrupt on LPC213x/4x

Hi I write code below for initial External Interrupt for LPC2138 in KEIL 4.7 Compiler and when run code in proteus software , code dosent Work. I double check VIC and EXTINT registers seems correct. thanks
Project Picture on Proteus
one Switch on EXTINT2 (P0.15) and one LED on P1.25
#include <LPC213x.h>
void delay(int count);
void init_ext_interrupt(void);
__irq void Ext_ISR(void);
int main (void)
{
init_ext_interrupt(); // initialize the external interrupt
while (1)
{
}
}
void init_ext_interrupt(void) //Initialize Interrupt
{
EXTMODE = (1<<2); //Edge sensitive mode on EINT2
EXTPOLAR &= ~(1<<2); //Falling Edge Sensitive
PINSEL0 = 0x80000000; //Select Pin function P0.15 as EINT2
/* initialize the interrupt vector */
VICIntSelect &= ~(1<<16); // EINT2 selected as IRQ 16
VICVectAddr5 = (unsigned)Ext_ISR; // address of the ISR
VICVectCntl5 = (1<<5) | 16;
VICIntEnable = (1<<16); // EINT2 interrupt enabled
EXTINT &= ~(1<<2); //Set interrupt
}
__irq void Ext_ISR(void) // Interrupt Service Routine-ISR
{
IO1DIR |= (1<<25);
IO1SET |= (1<<25); // Turn ON LED
delay(100000);
IO1CLR |= (1<<25); // Turn OFF LED
EXTINT |= (1<<2); //clear interrupt
VICVectAddr = 0; // End of interrupt execution
}
void delay(int count)
{
int j=0,i=0;
for(j=0;j<count;j++)
{
for(i=0;i<35;i++);
}
}
You should correct the line:
(VICVectCntl5 = (1<<5) | 16;)
to:
(VICVectCntl5 = 0x20 | 16;)
as datasheet said.

MSP430 Function Call Being Skipped

I am programming an MSP430 microcontroller with the MSP430 LaunchPad Dev Kit and I am running into some problems on this simple code.
#include <msp430.h>
void Delay(void);
#define LED1 BIT0 //define LED1 as bit 0 (0x00)
#define LED2 BIT6 //define LED2 as bit 6 (0x40)
#define delayTime 20000 //define iTime as 20000
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; //stop watchdog timer
P1DIR |= (LED1|LED2); //set P1.0 and P1.6 to output direction (P1.3 is naturally an input)
P1OUT |= LED1; //set P1.0 high so the LEDs will blink alternatively
while(1)
{
Delay();
P1OUT ^= (LED1|LED2); //toggle P1.0 using exclusive-OR
}
}
void Delay(void)
{
int i = 0;
while(delayTime > i)
{
i++;
}
}
This code compiles fine, but when debugging the code, the function call 'Delay()' is skipped entirely and the function is never entered. However, when I give the function a return type of 'unsigned int' like this:
unsigned int Delay(void)
{
int i = 0;
while(delayTime > i)
{
i++;
}
return 1;
}
I can call the Delay function in an if statement like the one below and the debugger will enter the function.
if(Delay() == 1)
{
P1OUT ^= (LED1|LED2); //toggle P1.0 using exclusive-OR
}
I'm sure there is some simple oversight that I'm making. I can't for the life of me figure out why the debugger is skipping my first void function call. Any wisdom?
swineone has responded with the following correct solution in a comment:
"Try changing the declaration int i = 0; to volatile int i = 0; in the
Delay() function. This tells the optimizer not to touch that variable,
and may be the difference between the optimizer optimizing the code
away or not."
Thanks for the help!
It's recommended to work with interrupts. Such a task goes to this:
#include "io430.h"
#define ON 1
#define OFF 0
#define LED1 P1OUT_bit.P0
#define LED2 P1OUT_bit.P6
void init(void)
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
P1OUT = 0x00;
P1DIR = 0xFF;
// initialize Timer0_A
TA0CCR0 = 62500; // set up terminal count
TA0CTL = TASSEL_2 + ID_3 + MC_1; // configure and start timer
// enable interrupts
TA0CCTL0_bit.CCIE = 1; // enable timer interrupts
__enable_interrupt(); // set GIE in SR
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void myTimerISR(void)
{
LED1 = ~LED1;
}

Interrupt handling with 8051 C using Keil uVision

I've been doing a project about home automation in which I have to use timer interrupts with 8051 microcontroller. I've constructed the following code, however I couldn't manage to get interrupt working. It seems that the program does not go into timer ISR at all. I use a buton to simulate PIR input, therefore lampControl is triggered, no worries there. I use as a library.
Any ideas or help will be greately appreciated:
void timer0_isr(void) interrupt 1 //Timer 0 Interrupt
{
TH0 = 0xDC;
TL0 = 0x00;
TR0 = 1;
if (++lamp_interrupt_count == 6000)
{
sendCharacterShowAsHex(0x8F);
lamp_interrupt_count = 0;
TR0 = 0;
}
}
void main()
{
unsigned char chr;
IE = 0x93;
while(1)
{
serialInput();
if (getPIRInput() == 0x00)
{
lampControl(0x80);
}
....
....
....
}
void lampControl(unsigned char serial_data_in)
{
if (serial_data_in == 0x80)
{
sendCharacterShowAsHex(0x80);
//enable interrupts
IE = 0x93;
device_interrupt = 2; //Lamp
TMOD = 0x21; // Timer0 Gate=0, Mode 1, 16bit timer
TH0 = 0xDC;
TL0 = 0x00;
TR0 = 1;
}
else if(serial_data_in == 0x8F)
{
sendCharacterShowAsHex(0x8F);
}
}
You need to configure the timer and interrupts before you can use them.
In main() you need at least the following configuration bits set in order to be able to turn
the timer on with "TR0 = 1;" :
Set those bits first thing in main() and this should do the trick:
TMOD = 0x01; // 16-bit no auto reload
TH0 = 0xDC; //Set high and low bits to count 0xFFFF - 0xDC00 = 0x23FF counts
TL0 = 0x00;
ET0 = 1; // Enable timer0 interrupt
EA = 1; // Enable all interrupts
//TR0 = 1; //Enable Timer0 immediately
The rest of your code should run fine.
Note: you could change your interrupt function definition to:
"void timer0_isr(void) interrupt 1 using 1" to force it to use register bank 1 for the interrupt function operation.

Changing a global variable in C

I am running a C program on an AVR chip. Whenever a serial signal is heard, it runs the serial interrupt ISR (USART_RX_vect). In this method it should turn on change to = 1;. Then in my main while loop, it should clear the LCD and display it and then set change = 0 again.
This is to stop it continually doing the calulations, and displaying the result on the LCD a million times a minute..
However, when the interrupt method changes the change variable to 1, it does not seem to change it "globally" and in the main method it is always 0..
There is a bit of stuff in here that is for debugging purposes.
/* LCD DEFINES */
#define LED PB5
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
/* UART SERIAL DEFINES */
#define F_CPU 16000000UL
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1
#define STARTCHAR 'R'
#define ENDCHAR 'E'
char reading;
char inputBuffer[12];
char readStatus;
uint8_t position;
int change;
char output;
int result;
struct Axis
{
uint8_t axisNumber;
uint16_t position;
uint16_t oldPosition;
} axis1, axis2, axis3;
/* SETUP UART */
void USART_Init( unsigned int ubrr)
{
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void USART_Transmit( unsigned char data )
{
UDR0 = data;
}
unsigned char USART_Receive( void )
{
return UDR0;
}
/*****************************************************************/
int main(void)
{
/* INITALISE SERIAL */
USART_Init(MYUBRR);
/* Turn on Receive Complete Interrupt */
UCSR0B |= (1 << RXCIE0);
/* Turn On GLobal Interrupts */
sei();
position = 0;
change = 0;
/* Initialise LCD */
lcd_init(LCD_DISP_ON); /* Initialize display, cursor off. */
lcd_clrscr();
lcd_puts("READY");
//Turn on LED 13
set_output(PORTB,LED);
output_low(PORTB,LED);
while (1) /* Loop forever */
{
if (change == 1)
{
//If not reading, display the result on the LCD display.
axis1.position = (inputBuffer[0]<< 8) | inputBuffer[1];
axis2.position = (inputBuffer[2]<< 8) | inputBuffer[3];
axis3.position = (inputBuffer[4]<< 8) | inputBuffer[5];
char axis1Printout[12];
char axis2Printout[12];
char axis3Printout[12];
sprintf(axis1Printout,"%u ", axis1.position);
sprintf(axis2Printout,"%u ", axis2.position);
sprintf(axis3Printout,"%u ", axis3.position);
char output[40] = "";
strcat(output, axis1Printout);
strcat(output, axis2Printout);
//strcat(output, axis3Printout);
lcd_clrscr(); /* Clear the screen*/
lcd_puts(output);
_delay_ms(300);
change = 0;
}
}
}
/* INTERRUPTS */
ISR (USART_RX_vect)
{
change = 1;
unsigned char input = USART_Receive();
if (input == 'R')
{
readStatus = 0; //Reading
position = 0;
}
else if ((input != 'E') && (position < 12) && (position > -1))
{
inputBuffer[position] = input;
position++;
}
else if (input == 'E')
{
readStatus = 1; //Stop Reading
position = -1;
output_high(PORTB,LED);
}
}
You need to declare change using the volatile keyword:
volatile int change;
This tells the two 'threads' (main execution loop and your ISR code) to not 'cache' the value in a register, but always retrieve it from memory.
Edit: There's another problem with the code - in your main loop, by the time you set changed to 0, you may have already had another interrupt which should have triggered your loop to run again. The easy-but-not-guaranteed fix is to immediately set changed to 0 straight after you check it. The proper way would be to use a lock - but depending on your situation, the first option might do.
Make the variable declaration volatile to ensure that a changed value is written imediately to the variable in memory.
An object shared by an interrupt handler and the application code should be qualified as volatile in the declaration.
Without the qualifier, the implementation can assume the object cannot change unexpectedly in the application code and can cache the variable (in a register for example) for optimizations while executing the application code.

Resources