Search code examples
cavratmelstudioproteus

clock problems with 7-segment display in proteus


here is a simple 7-segment display with a pushbutton the problem is whenever I make the clock 1 MHZ the display doesn't run as expected but when I use 8 MHZ clock it works fine. here is the code:

#define  F_CPU 1000000L

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    DDRD &= ~(1<<PD4);
    DDRC |= (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3);
    PORTC = 0;
    while (1) 
    {
        if(PIND & (1<<PD4)){
            _delay_ms(25);
            if(PIND & (1<<PD4)){
                PORTC++;
            }
        }
    }
}

enter image description here


Solution

  • F_CPU Should be the same as the hardware fuses configuration in proteus you could change them by double-click on atmega 16 and change CKSEL Fuses as following

    enter image description here

    some info maybe help

    1. _delay_ms() It only west some CPU cycles depend on the required time by using F_CPU in the calculation
    2. You need to increase this delay to 300ms to make sure that program does not process the same click more than one and if you hold the key down it will increase in visual manner

    analysis of the wrong behavior

    25ms is a very short time ... a normal human click will take around 200-300ms so in every click the microcontroller will consider it more than one

    when I use 8 MHZ clock it works fine

    when you change F_CPU to 8MHZ the _delay_ms() it make the calculation on this speed and will west more cycles ... while the actual speed is 1MHZ

    this differance in speed (between F_CPU and the actual speed) led to make 8 times slower delay ='25ms' *8 ='200 ms'

    simple solution increase the _delay_ms(25) to _delay_ms(200) to make the same effect

    update (info about how delay work)

    _delay_ms Is just LOOP to waste CPU cycles and it blocks the CPU from work

    the frequency of the microcontroller is determined by the hardware fuses so you need to tell the software which frequency you use throw define F_CPU so the software will know each cycle will take time = 1/F_cpu

    when you need a delay, the software already know the amount of time taken by each clock so it will calculate the number of cycle to achieve the required delay time(if you need delay 1ms delay and each clock tack 1 us then you need to wait for 1000 cycles to achieve these delay)

    in Assembly there is instruction called nop take only 1 cycle to execute and do nothing

    the following code is not correct but it makes something similar when the compiler translate _delay_ms() in Assembly

    for(int i=0;i<50;i++)nop;
    

    this code will make 50 nop and wast 50 cycles(actually more than 50 because access and increment variable 'i' will consume some cycles but neglect it to show the idea)

    read more

    1. Do AVR delay functions use timers?
    2. how to make delay in AVR Assembly