1

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

Ali El-Boghdady
  • 145
  • 1
  • 11

1 Answers1

2

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
Ibram Reda
  • 1,882
  • 2
  • 7
  • 18
  • thank you for your great and explanatory answer it worked after i increased the delay , i already have the proteus atmega at 1MHZ , what i need to do is to have a better understanding of how clock works in these calculations if you can explain this to me or refer me to a link would be great – Ali El-Boghdady Nov 16 '20 at 11:54
  • @AliEl-Boghdady You are welcome, I have updated the post and put some info about the delay – Ibram Reda Nov 17 '20 at 00:05