0

这是一个带有按钮的简单 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++;
            }
        }
    }
}

在此处输入图像描述

4

1 回答 1

2

F_CPU应该与 proteus 中的硬件熔断器配置相同,您可以通过双击 atmega 16 更改它们并更改 CKSEL 熔断器,如下所示

在此处输入图像描述

一些信息可能会有所帮助

  1. _delay_ms()它仅西一些 CPU 周期取决于在F_CPU计算中使用所需的时间
  2. 您需要增加此延迟以300ms确保程序不会多次处理相同的单击,并且如果您按住键,它将以视觉方式增加

错误行为分析

25ms时间很短......正常的人工点击会发生,200-300ms所以在每次点击时,微控制器都会认为它不止一次

当我使用 8 MHZ 时钟时,它工作正常

当您更改F_CPU8MHZ时,_delay_ms()它会根据此速度进行计算,并且会向西更多周期...而实际速度为1MHZ

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

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

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

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

微控制器的频率由硬件保险丝决定,因此您需要告诉软件您使用哪个频率来定义F_CPU,以便软件知道每个周期将花费时间 = 1/F_cpu

当您需要延迟时,软件已经知道每个时钟所花费的时间,因此它将计算达到所需延迟时间的周期数(如果您需要延迟 1ms 延迟并且每个时钟 tack 1 us 那么您需要等待1000 个周期来实现这些延迟

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

以下代码不正确,但编译器_delay_ms()在汇编中翻译时会产生类似的情况

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

这段代码将产生 50nop个周期并浪费 50 个周期(实际上超过 50 个,因为访问和递增变量“ i ”会消耗一些周期,但忽略它来展示这个想法

阅读更多

  1. AVR 延迟功能是否使用计时器?
  2. 如何延迟 AVR 组装
于 2020-11-15T17:44:49.963 回答