Ads

Get STM32 tutorial using HAL at $10 for a limited time!

Sunday, July 12, 2015

AVR ATmega Tutorial - Millis Function on AVR Microcontrollers

In this tutorial, I will make tutorial for making millis() function that will return number of millisecond since AVR microcontrollers began executing program. This function is like millis() function on Arduino. I will use ATmega16 and CodeVisionAVR for this tutorial. First, you have to make a variable that will hold the value of millisecond. I declared this variable as volatile because the value of this variable will be changed inside ISR.
// Store value of millisecond since uC started
volatile unsigned long millis_value;
Next, Setup timer 0 (or another timer if you wish) to generate interrupt every 1 ms. I am using timer 0 on CTC mode to count up from 0 to the value of OCR0 register. The prescaler that I use is 64 with 16 MHz CPU clock. To calculate the OCR0 register for 1ms compare match, we can use this formula OCRx = ((T x Fcpu) / N) - 1. Where T is the desired compare match value in second (1ms = 0.001s), Fcpu in Hz is 16,000,000 and N is prescaler (64). The OCR0 value will be 0xF9. To generate code for this settings we will use CodeWizardAVR. This is the settings for timer 0:

 

Copy this lines of code from CodeWidardAVR preview to main function. This codes is used for initializing timer 0 and timer 0 interrupt.
void main(void)
{
    /* Set timer 0 on CTC mode that will compare match every 1ms */    
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: 250.000 kHz
    // Mode: CTC top=OCR0
    // OC0 output: Disconnected
    TCCR0 = 0x0B;
    TCNT0 = 0x00;
    OCR0 = 0xF9;

    /* Enable compare match interrupt for timer 0 */
    // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK = 0x02;
    
    /* Enable global interrupt */
    #asm("sei")

    while (1);
}
After that, add this ISR code from CodeWizardAVR preview. This code will increment millis_value every 1ms.
// Timer 0 output compare interrupt service routine
interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
    // Increment millisecond every 1ms
    millis_value++;  
}
To get the millis_value we can make a function like this:
// This function is used to get millis_value
unsigned long millis()
{
    unsigned long m;
       
    // Disable interrupts while we read millis_value or we might get an
    // inconsistent value (e.g. in the middle of a write to millis_value) 
    #asm("cli")
    m = millis_value;
    #asm("sei")
     
    return m;
}
We need to disable interrupt while read millis_value to avoid inconsistent value (in case when in the middle of a write to millis_value).

6 comments :