proteus中7段显示的时钟问题

clock problems with 7-segment display in proteus

这是一个带有按钮的简单 7 段显示,问题是每当我将时钟设置为 1 MHZ 时,显示并不像预期的那样 运行,但是当我使用 8 MHZ 时钟时,它工作正常。 这是代码:

#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++;
            }
        }
    }
}

F_CPU应该和proteus中的硬件保险丝配置一样你可以通过双击atmega 16来改变它们并改变CKSEL保险丝如下

一些信息可能有帮助

  1. _delay_ms()只需要CPU个周期就可以了F_CPU计算需要的时间
  2. 您需要将此延迟增加到 300ms 以确保程序不会多次处理相同的点击,如果您按住该键,它会以视觉方式增加

错误行为分析

25ms 是一个非常短的时间...正常的人类点击大约需要 200-300ms 所以在每次点击中微控制器都会认为它不止一次

when I use 8 MHZ clock it works fine

当您将 F_CPU 更改为 8MHZ 时,_delay_ms() 会根据此速度进行计算,并将向西移动更多周期...而实际速度是 1MHZ

这种速度差异(在 F_CPU 和实际速度之间)导致延迟慢 8 倍 ='25ms' *8 ='200 ms'

简单的解决方案将 _delay_ms(25) 增加到 _delay_ms(200) 以达到相同的效果

更新(有关延迟如何工作的信息)

_delay_ms 只是浪费 CPU 周期的循环,它会阻止 CPU 工作

微控制器的频率由硬件保险丝决定,所以你需要告诉软件你使用哪个频率 throw define F_CPU 这样软件就会知道每个周期需要时间 = 1/F_cpu

当你需要延迟时,软件已经知道每个时钟所花费的时间,因此它会计算周期数以达到所需的延迟时间(如果你需要延迟1ms延迟和每个时钟调整 1 us 然后你需要等待 1000 个周期来实现这些延迟)

在 Assembly 中有一条指令叫做 nop 只需要 1 个周期来执行并且什么都不做

下面的代码不正确,但当编译器在汇编

中翻译_delay_ms()时,它会产生类似的东西
for(int i=0;i<50;i++)nop;

此代码将生成 50 个 nop 并浪费 50 个周期(实际上超过 50 个,因为访问和递增变量 'i' 将消耗一些循环但忽略它以显示想法)

阅读更多

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