1

I'm trying to make a function to make a delay in ATmega32 using Timer0 but I can't get the delay right and when I used debugging I found that the variable T_tick is not changing value from 0 but other operations depend on its value so nothing is working right. I don't know what's wrong with this variable and I've been stuck here for while so please help. My code is as follows in a single page:

#include <math.h>
#include "registers.h"

#define CPU_frequency 1000000
#define set_bit(x,Bit_num) x|=(1<<Bit_num)
#define clr_bit(x,Bit_num) x&=~(1<<Bit_num)
#define tolge(x,Bit_num) x^=(1<<Bit_num)

//timer configuration
#define Normal 'N'
#define PWM_paseCorrect 'O'
#define PWM_fast 'p'
#define CTC 'Q'

double T_tick = 0,T_maxDelay = 0;
uint32_t overflowsNumber = 0, T_initValue = 0, overflowCounter = 0;

// set the timer mood
void timer0_init(uint8_t timerMood)
{
    switch(timerMood)
    {
        case Normal:
        TCCR0 = 0x00;
        break;
        case PWM_paseCorrect:
        TCCR0 = 0x40;
        break;
        case CTC:
        TCCR0 = 0x08;
        break;
        case PWM_fast:
        TCCR0 = 0x48;
        break;
    }

}

void delayT0(double delay)
{
    //convert delay to Ms
    delay= delay/1000;
    
    //calculate tick time
    T_tick = 1/CPU_frequency;
    
    //calculate max delay time
    T_maxDelay = 256*T_tick;
    
    //calculate overflow flag count
    overflowsNumber = ceil(delay/T_maxDelay);
    
    //calculate the timer initial value
    T_initValue = 256 - (delay/T_tick)/overflowsNumber;
    
    //set timer initial value
    TCNT0 = T_initValue;
    
    //start timer in no prescaling mood
    set_bit(TCCR0,0);
    //Make a loop to count the overflows
    overflowCounter = 0;
    while (overflowCounter < overflowsNumber)
    {
        
        //wait until overflow flag =1
        while ((TIFR &(1<<0)) == 0)
        
        //clear overflow flag
        set_bit(TIFR,0);
        
        overflowCounter++;
    }
    overflowCounter = 0;
    TCCR0 = 0x00;
    
}

void LED_init(uint8_t pinNumber)
{
    set_bit(DDRA,pinNumber);

}
void LED_TOGLE(uint8_t pinNumber)
{
    tolge(PORTA,pinNumber);
}

int main(void)
{
    LED_init(0);
    timer0_init(Normal);
    while (1)
    {
        LED_TOGLE(0);
        delayT0(512);
    }
}

The delay is supposed to be 512ms but it's only 1ms because of the variable T_tich that i don't know what's its problem; or that's what i think. if any one can help please do; i've been stuck in there for too long

abdo Salm
  • 1,678
  • 4
  • 12
  • 22
Ahmed Hal
  • 11
  • 3
  • 3
    `1/CPU_frequency` is an integer division, resulting in zero. I suggest to get rid of all the floating point calculations though, it can be done by rearranging the calculations appropriately. – Eugene Sh. Sep 12 '22 at 18:48
  • even when i replaced CPU_frequency with its value "1000000" it still didn't work – Ahmed Hal Sep 12 '22 at 18:50
  • 1
    You have `while ((TIFR &(1<<0)) == 0)` [_no_ semicolon!] followed by `set_bit(TIFR,0);`. Is this your real code??? Because it's the equivalent of: `while ((TIFR &(1<<0)) == 0) set_bit(TIFR,0);` and you are clearing the overflow flag on each iteration instead of _after_ the loop. – Craig Estey Sep 12 '22 at 18:52
  • If you need `T_tick` to remain a `double` then use: `T_tick = 1.0/CPU_frequency;` (see @EugeneSh.'s comment) – sj95126 Sep 12 '22 at 18:53
  • All that said you _really_ do not want to use floating point on an 8 bit processor with no FPU. It is a complete waste of limited resources and entirely unnecessary. in this case. The resulting code will be significantly larger and significantly slower. That is a different question though - if you want to know post it. – Clifford Sep 12 '22 at 19:48

1 Answers1

3

your problem is so simple : in the line T_tick = 1 / CPU_frequency;. after preprocessing , it's expanded to be equivalent to : T_tick = 1 / 1000000; which will always result in zero.

even my compiler gives me this warning in this line :

Clang-Tidy: Result of integer division used in a floating point context; possible loss of precision

as the right hand side is integer division as 1 / 1000000 = 0

so T_tick = 0; , that's why T_tick will be always zero.

so either write T_tick = 1.0 / CPU_frequency; or T_tick = (double)1 / CPU_frequency;.

also don't forget to turn on all your compiler warnings using compiler flags as it will really help.

abdo Salm
  • 1,678
  • 4
  • 12
  • 22