[其他产品] atmega128长期工作后程序异常,求助!!

[复制链接]
 楼主| jcky001 发表于 2025-4-14 16:00 | 显示全部楼层 |阅读模式
写了一个程序,主要是在定时器1中每20ms监控外界端口IO状态,当IO口状态发生变化时,在定时器内把数据存到数组中,然后作标志位,主程序不停查询该标志位,当标志位为1时,通过串口把数组的数据发送出去。但是在长期工作后(不定时,长达几天几个月都可能)发现程序会出问题,本来串口发送数据只会是在定时器监控的IO口发生变化后才会发生,可是出问题后,主程序会一直往串口发送数据,此时还能进入定时器中断,当IO检测状态改变时,串口数据也改变的。出问题后数据可能是不停地重复发数组内的数据,有时候只会发送数组的一部分数据。下面大概写出程序的内容,不是原代码,求分析可能原因。ISR(time1) //忘记是不是这样了
{
       此处重装初值20ms
       if{PORTA!=pastPORTA}
       {
                for(i=0;i<15;i++)
                        table=某逻辑计算后的值;
               mark=1;
        }
}


int main(void)
{
while(1)
{
        if(mark==1)
       {
              mark=0;
             for{i=0;i<15;i++}
             {
                     Uartsend_oneBit(table);//往串口发送数据
              }
        }
}
}
出问题时现象为串口不停发送table[]的数据,多数为table[0]到table[14]的数据,但有时候没有table[0],是从table[1】开始的,有时候甚至会有乱码。但此时定时器中断能进,加入看门狗在主程序喂狗解决不了该问题,用16M晶振,熔丝位是FE,09,3F.详细程序明天上传。
gaoyang9992006 发表于 2025-4-14 18:55 | 显示全部楼层
根据您描述的问题现象和代码结构,可能存在以下几个潜在原因:

竞态条件(Race Condition):

mark变量在主循环和中断服务程序(ISR)中被共享访问,但没有保护机制

当主程序正在发送数据时(已将mark置0),如果此时发生中断将mark置1,可能导致状态混乱

改进建议:将mark声明为volatile并使用原子操作或禁用中断保护

数组越界或内存损坏:

如果table数组大小正好是15,而循环使用了i<=15,可能导致内存越界

检查所有数组访问是否在合法范围内

改进建议:使用sizeof(table)/sizeof(table[0])作为循环边界

串口发送阻塞:

如果Uartsend_oneBit是阻塞式发送且没有超时机制,可能在长期运行后因干扰导致卡死

改进建议:实现非阻塞串口发送或添加超时检测

堆栈溢出:

长期运行后可能导致堆栈逐渐增长最终溢出

改进建议:检查堆栈大小设置,增加堆栈溢出检测机制

看门狗复位不彻底:

虽然使用了看门狗,但可能没有完全覆盖所有异常情况

改进建议:在关键位置添加更多的看门狗喂狗点

熔丝位配置问题:

FE 09 3F配置中时钟源为外部晶振,但启动时间设置(默认为16K CK+64ms)可能需要调整

改进建议:检查SUT_CKSEL熔丝位设置是否适合您的硬件

中断嵌套问题:

如果允许中断嵌套,可能在处理串口发送时被其他中断打断

改进建议:在关键代码段禁用中断

评论

后面找到原因l了吗?  发表于 2025-6-27 10:30
gaoyang9992006 发表于 2025-4-14 18:56 | 显示全部楼层
试试下面的代码
  1. volatile uint8_t mark = 0;  // 添加volatile修饰

  2. ISR(TIMER1_OVF_vect) {
  3.     // 重装初值20ms
  4.     if(PORTA != pastPORTA) {
  5.         uint8_t tmp[15];  // 使用临时缓冲区
  6.         for(uint8_t i=0; i<15; i++) {
  7.             tmp[i] = 某逻辑计算后的值;
  8.         }
  9.         
  10.         // 禁用中断保护临界区
  11.         cli();
  12.         for(uint8_t i=0; i<15; i++) {
  13.             table[i] = tmp[i];
  14.         }
  15.         mark = 1;
  16.         sei();
  17.     }
  18. }

  19. int main(void) {
  20.     while(1) {
  21.         wdt_reset();  // 喂狗
  22.         
  23.         if(mark) {
  24.             cli();
  25.             uint8_t local_mark = mark;
  26.             mark = 0;
  27.             sei();
  28.             
  29.             if(local_mark) {
  30.                 for(uint8_t i=0; i<15; i++) {
  31.                     while(!UART_ready_to_send());  // 等待发送就绪
  32.                     Uartsend_oneBit(table[i]);
  33.                     wdt_reset();  // 长循环中喂狗
  34.                 }
  35.             }
  36.         }
  37.         
  38.         // 其他任务...
  39.     }
  40. }
gaoyang9992006 发表于 2025-4-14 18:56 | 显示全部楼层
其他排查建议:

添加串口发送完成标志检查

在异常发生时记录状态信息到EEPROM

使用硬件CRC检查关键数据区完整性

考虑增加系统运行时间计数器,定期软复位

检查电源稳定性,劣质电源可能导致MCU异常
dffzh 发表于 2025-4-15 16:45 | 显示全部楼层
大概率是上面楼主说的问题:竞态条件(Race Condition)
xinxianshi 发表于 2025-4-18 15:48 | 显示全部楼层
也可能是硬件问题。最近我做了个东西,总是烧毁单片机,什么时候烧毁呢,我去动它  时候,不知道怎么暴力碰着了,就烧毁了。我怀疑是什么线的问题,或者板子上有锡膏残渣。
星空魔法师 发表于 2025-4-21 09:18 | 显示全部楼层
看起来像是定时器中断服务程序(ISR)中的逻辑问题。检查一下`if{PORTA!=pastPORTA}`的条件判断是否正确,确保`pastPORTA`在每次中断后都被更新。
瞌睡虫本虫 发表于 2025-4-21 12:23 | 显示全部楼层
看起来像是定时器中断服务程序中的状态检测逻辑有问题。检查一下`PORTA != pastPORTA`的条件是否正确,可能在某些情况下没有正确地重置`pastPORTA`。
迷雾隐者 发表于 2025-4-21 14:36 | 显示全部楼层
看起来像是定时器中断处理过程中的逻辑问题,可能是中断服务例程(ISR)中的代码没有正确处理状态变化,导致标志位`mark`被错误地设置。建议检查`if{PORTA!=pastPORTA}`的条件判断逻辑,确保每次IO状态变化时只设置一次`mark`。
暖茶轻语 发表于 2025-4-21 19:25 | 显示全部楼层
看起来你的程序可能存在一些潜在的问题。首先,检查你的定时器中断服务程序(ISR)是否正确地重新装载了初值,以确保定时器能够准确地每20ms触发一次。其次,考虑在中断服务程序中添加一些防抖动逻辑,以确保IO口状态的变化是稳定的。
穷得响叮当侠 发表于 2025-4-21 19:54 | 显示全部楼层
看起来像是定时器中断服务程序中存在逻辑错误,导致mark标志位被错误地设置。建议检查定时器中断服务程序中的逻辑,确保只有在IO口状态真正发生变化时才设置mark标志位。
yiyigirl2014 发表于 2025-4-21 20:47 | 显示全部楼层
长期工作,这个设定很难排错。
我是一颗胖蘑菇 发表于 2025-4-21 21:16 | 显示全部楼层
根据你的描述,可能是由于长时间运行导致某些寄存器或变量的值出现了异常。建议检查是否有可能的硬件问题,比如电源不稳定或者晶振频率漂移。同时,检查代码中是否有可能的逻辑错误或者溢出问题。
暖茶轻语 发表于 2025-4-21 22:33 | 显示全部楼层
根据你的描述,可能存在几个问题。首先,检查你的定时器中断服务例程(ISR)是否正确地重新加载了初值,以确保定时器能够以20ms的间隔触发中断。其次,考虑是否存在变量溢出或内存泄漏的问题,这可能会导致程序在长时间运行后出现异常。
Unarty 发表于 2025-6-17 15:55 | 显示全部楼层
请问有结论了吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1636

主题

5575

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部

1636

主题

5575

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部