cdg 发表于 2025-8-15 09:54:35

单片机计时比较导致的BUG

工作中发现一个偶发BUG,经过反复查找,发现是计时变量比较导致的。故写了一个测试程序(主体都是工具生成的)验证。

#include "reg51.h"
#include "intrins.h"

sfr   T2L   =   0xd7;
sfr   T2H   =   0xd6;
sfr   AUXR    =   0x8e;
sfr                        P_SW1                =         0xa2;

sfr   P0M1    =   0x93;
sfr   P0M0    =   0x94;
sfr   P1M1    =   0x91;
sfr   P1M0    =   0x92;
sfr   P2M1    =   0x95;
sfr   P2M0    =   0x96;
sfr   P3M1    =   0xb1;
sfr   P3M0    =   0xb2;
sfr   P4M1    =   0xb3;
sfr   P4M0    =   0xb4;
sfr   P5M1    =   0xc9;
sfr   P5M0    =   0xca;

sbit    P10   =   P1^0;
sbit    P11   =   P1^1;
sbit    P12   =   P1^2;

void UART1_Isr() interrupt 4
{
    if (TI)
    {
      TI = 0;                                 //清中断标志
      P10 = !P10;                           //测试端口
    }
    if (RI)
    {
      RI = 0;                                 //清中断标志
      P11 = !P11;                           //测试端口
    }
}

unsigned long tick=0;

void TM0_Isr() interrupt 1
{
    tick++;                              //测试端口
}


void main()
{
      unsigned long curTime=0;
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;

      // 串口设置
    SCON = 0x50;
                P_SW1 &= 0x3F;// 使用P30 P31
    T2L = 0xe8;                                 //65536-11059200/115200/4=0FFE8H
    T2H = 0xff;
    AUXR = 0x15;                              //启动定时器
    ES = 1;                                     //使能串口中断
    EA = 1;
    SBUF = 0x5a;                              //发送测试数据

// 定时器设置
    TL0 = 0x66;                                 //65536-11.0592M/12/1000
    TH0 = 0xfc;
    TR0 = 1;                                    //启动定时器
    ET0 = 1;                                    //使能定时器中断
    EA = 1;
               
    while (1)
                {
                        if((tick/500)%2) P12=0;
                        else P12 = 1;
                        curTime = tick+100;
                        if(tick>curTime)
                        {
                              SBUF = 0xaa;                              //发送测试数据
                        }
                }
}



上述单文件代码,会偶发出现 if(tick>curTime) 满足的情况,见下面截图:



以上记录。
1、方便其他人能够规避发现该问题,避免走弯路;
2、有没有好的解决方法?

国芯人工智能 发表于 2025-8-15 09:58:00

针对您提到的STC单片机计时比较导致的BUG问题,我们作为国芯人工智能团队,对相关技术细节进行了深入分析,并结合实际应用场景提出以下专业意见与建议。

首先,从您提供的代码片段来看,程序中使用了STC系列单片机的定时器T2,并在中断服务函数中对P10引脚进行翻转操作。此行为通常用于测试定时器功能或观察系统运行状态。然而,在您的描述中提到“计时变量比较导致的BUG”,这表明在定时器计数过程中,存在因变量比较逻辑不当引发的异常行为。

此类问题常见于以下几种情况:

1. 定时器初始化不规范:若未正确配置定时器模式、分频系数或自动重载值,可能导致计时精度偏差,进而影响比较逻辑的准确性。

2. 中断处理不及时:在多任务环境下,若中断服务函数执行时间过长或未及时清零标志位,可能造成定时器溢出或比较事件被重复触发。

3. 变量类型选择不当:若使用无符号整型(如unsigned int)存储计时值,而实际应用中需要处理负值或大范围计时,可能导致溢出或比较结果错误。

4. 比较逻辑设计缺陷:例如在判断计时是否达到设定值时,未考虑变量更新的同步性,可能导致因读取顺序不同而产生误判。

为验证上述问题,建议您通过以下步骤进一步排查:
检查定时器T2的初始化代码,确认其工作模式、分频设置及自动重载寄存器(T2L/T2H)的配置是否符合预期。
在中断服务函数中添加调试输出(如通过串口打印当前计时值),以观察计时变量的变化趋势。
对比不同环境下的测试结果,确认BUG是否为偶发性,从而判断是否与外部干扰或硬件稳定性有关。

此外,考虑到STC系列单片机广泛应用于工业控制、智能终端等领域,建议在开发过程中遵循以下最佳实践:
采用模块化设计,将定时器、中断等核心功能封装为独立模块,便于维护与调试。
使用可靠的数据类型和运算方式,避免因变量溢出或精度问题引发逻辑错误。
在关键代码段加入必要的保护机制,如临界区锁、状态检查等,提升系统鲁棒性。

综上所述,STC单片机计时比较BUG的根源可能涉及多个层面,需结合具体应用场景进行细致分析。国芯人工智能将持续关注此类技术问题,致力于提供更稳定、高效的嵌入式解决方案。如需进一步技术支持,欢迎随时联系。

[本文内容由国芯人工智能辅助生成,仅供参考]

32G12K128 发表于 2025-8-15 10:45:38

您可以先学习
AiCube 三个实验:
AiCube 实验一:直接 printf_usb("Hello World !\r\n")
===现代 1T 8位8051单片机入门的第一个完整的C语言程序
AiCube 实验二:查询方式,查询到电脑命令后,
                           printf_usb("Hello World !\r\n")或其他
AiCube 实验三:中断方式,单片机USB中断接收服务函数收到命令后,
                           printf_usb("Hello World !\r\n")或其他
https://v.stcai.com/sv/1c5eec2-197fcd9b766/1c5eec2-197fcd9b766.mp4
上面是 小李 演示:Ai8051U, printf_usb("Hello World !\r\n")及usb不停电下载@AiCube之图形化程序自动生成

https://v.stcai.com/sv/1fce8086-197cf2b9dd4/1fce8086-197cf2b9dd4.mp4
上面是 小赵 演示:Ai8051U, printf_usb("Hello World !\r\n")及usb不停电下载@AiCube之图形化程序自动生成

https://v.stcai.com/sv/e49742d-1978afcb431/e49742d-1978afcb431.mp4
上面是 小李 演示:STC8H8K64U, printf_usb("Hello World !\r\n")及usb不停电下载@AiCube之图形化程序自动生成

https://v.stcai.com/sv/61d1aa5-1978c2a6adb/61d1aa5-1978c2a6adb.mp4
上面是 小赵 演示:STC8H8K64U, printf_usb("Hello World !\r\n")及usb不停电下载@AiCube之图形化程序自动生成




cnos 发表于 2025-8-15 11:36:20

EA=0;
                        curTime = tick+100;
                        if(tick>curTime)
                        {
                              SBUF = 0xaa;                              //发送测试数据
                        }
EA=1;

cdg 发表于 2025-8-15 13:56:32

cnos 发表于 2025-8-15 11:36
EA=0;
                        curTime = tick+100;
                        if(tick>curTime)


这样操作是否会导致tick 不准?
另外这里不好关总的中断,业务可能还需要收发数据,最好关定时器的中断,

Ayb_ice 发表于 2025-8-15 15:17:56

可以飞读tick变量

cnos 发表于 2025-8-15 15:25:23

cdg 发表于 2025-8-15 13:56
这样操作是否会导致tick 不准?
另外这里不好关总的中断,业务可能还需要收发数据,最好关定时器的中断, ...

原因就是比较到一半的时候发生了中断导致数据出问题。你自己想办法规避就好了。

cdg 发表于 2025-8-15 16:45:52

Ayb_ice 发表于 2025-8-15 15:17
可以飞读tick变量

飞读是怎么操作?

Ayb_ice 发表于 2025-8-15 17:05:21

cdg 发表于 2025-8-15 16:45
飞读是怎么操作?

就是避免读的时候正好产生了进位,从而产生错误,16位的飞读,先读高字节,再读低字节,再读高字节,如果两次高字节相等则成功,否则连续此操作,直到成功

小飞侠 发表于 2025-8-16 09:59:15

看看这个帖子
https://www.stcaimcu.com/thread-11928-1-1.html
页: [1]
查看完整版本: 单片机计时比较导致的BUG