You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ATmega324PB Xplained Pro调用delays()后部分LED无法点亮问题

问题分析与解决

问题现象

在ATmega324PB Xplained Pro开发板上进行LED闪烁开发时:

  • 未调用自定义delays()函数时,所有目标LED均可正常点亮
  • 调用delays()函数后,主板LED及OLED1 Xplained Pro上的部分LED能正常闪烁,但OLED1 Xplained Pro及IO1 Xplained Pro上的特定LED无法点亮
  • 可运行与不可运行代码的唯一差异就是是否调用delays()函数

问题代码

#define LED0 7
#define LED1 5
#define LED2 4
#define LED3 3
#define LED_IO1 3

void delays(void){
  int delay = 1600000;/*a long integeger that will make the loop longer, cant put higher number so we make a lot of integers*/
  int delay1 = 1600000;
  int delay2 = 1600000;
  int delay3 = 1600000;
  int delay4 = 1600000;
  int delay5 = 1600000;
  int delay6 = 1600000;
  int delay7 = 1600000;
  int delay8 = 1600000;
  int delay9 = 1600000;
  int delay10 = 1600000;
  int delay11 = 1600000;
  
  int delay12 = 1600000;
  int delay13 = 1600000;
  int delay14 = 1600000;
  int delay15 = 1600000;
  int delay16 = 1600000;
  int delay17 = 1600000;
  int delay18 = 1600000;
  int delay19 = 1600000;
  int delay20 = 1600000;
  int delay21 = 1600000;
  int delay22 = 1600000;
  int delay23 = 1600000;
  
  int i = 0;
  int x = 0;
  int y = 0;
  int z = 0;
  
  while(i < delay && i < delay1 && i < delay2 && i < delay3 && i < delay4 && i < delay5 && i < delay6 && i < delay7 && i < delay8 && i < delay9 && i < delay10 && i < delay11 && i < delay12 && i < delay13 && i < delay14 && i < delay15 && i < delay16 && i < delay17 && i < delay17 && i < delay18 && i < delay19 && i < delay20 && i < delay21 && i < delay22 && i < delay23){
    /*a loop that will go through all the integers to compare them to i*/
    i++;
    x = i;
    x = y;
    x = z;/*make the loop do something to make the loop last longer*/
  
  }
}

void delay1s(void){
  /*its complicated to keep adding more integers in the loop so we call the last function twice and put in a function to be called inside the main to have a more clear code*/
  delays();
  delays();
}

int main(void) {
    // Set led1 as output
    // Set led1, LED2, LED3 AND LED_IO1 as output
    DDRD |= (1 << LED1);
    /*DDRD |= (1 << LED2);
    DDRA |= (1 << LED3);
    DDRB |= (1 << LED_IO1);*/
    
    while (1) {
        // Turn on LED1 by driving led1 low
        // Turn on LED1, LED2, LED3 AND LED_IO1 by driving PIN low
        PORTD &= ~(1 << LED1);
        delays();
        PORTD |= (1 << LED1);
        delays();
        /*PORTD &= ~(1 << LED2);
        PORTA &= ~(1 << LED3);
        PORTB &= ~(1 << LED_IO1);*/
    }
}

核心问题原因

  1. 整数溢出:AVR架构中int是16位有符号类型,最大值仅为32767,但代码中delay变量赋值为1600000,远超出范围,会导致变量值溢出为错误数值,让延时循环行为不可预测。
  2. 栈溢出风险:delays()函数定义了27个int类型局部变量(23个delay系列变量+4个循环变量),每个int占2字节,总共占用54字节栈空间。加上函数调用的栈帧开销,可能耗尽栈空间,破坏其他内存区域的数据(比如IO端口配置寄存器),导致扩展板LED无法正常工作。
  3. 冗余逻辑:while循环中重复判断i < delay17,且x = i; x = y; x = z;这类操作无实际意义,编译器可能优化掉这些代码,导致延时时间远小于预期。

修复方案

方案1:修复整数类型与简化延时函数

将延时变量改为unsigned long(32位)避免溢出,同时简化函数结构,减少栈占用:

void delays(void){
  // 使用32位无符号整数避免溢出
  unsigned long delay = 1600000;
  unsigned long i = 0;
  // 简化循环逻辑,加入空操作防止编译器优化
  while(i < delay){
    i++;
    __asm__ __volatile__ ("nop");
  }
}

方案2:使用定时器实现精确延时(推荐)

自定义软件延时精度低且占用CPU,更可靠的方式是利用AVR定时器实现延时:

#include <avr/io.h>

void delay_ms(uint16_t ms){
  // 配置定时器0为普通模式,预分频64(适配8MHz系统时钟)
  TCCR0A = 0;
  TCCR0B = (1 << CS01) | (1 << CS00);
  while(ms--){
    TCNT0 = 0;
    // 计数到250对应约2ms延时,可根据实际时钟调整
    while(TCNT0 < 250);
  }
}

方案3:优化栈空间使用

如果坚持使用原逻辑,将局部变量改为全局变量(存储在RAM全局区,不占用栈空间):

// 将delay变量移到全局区
int delay = 1600000;
int delay1 = 1600000;
int delay2 = 1600000;
// ... 其余delay变量同理

void delays(void){
  int i = 0;
  int x = 0;
  int y = 0;
  int z = 0;
  
  while(i < delay && i < delay1 && /* ... 其余条件 */){
    i++;
    x = i;
    x = y;
    x = z;
  }
}

额外建议

  • 检查扩展板LED的IO配置是否正确,确保DDRx和PORTx寄存器的设置没有被栈溢出破坏
  • 开启编译器的栈溢出警告(如GCC的-Wstack-usage=80),提前发现栈空间问题

内容的提问来源于stack exchange,提问作者mymycroverse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:55:04