找回密码
 立即注册
查看: 237|回复: 3

STC读取定时器原子保护!

[复制链接]

6

主题

7

回帖

114

积分

注册会员

积分
114
发表于 2026-8-13 12:47:57 | 显示全部楼层 |阅读模式
想请教各位大佬,我使用STCAI8051U32K64,使用逐飞库读取编码器数据,在调试速度环时候发现当我设置250以上脉冲速度时候速度环会突然反转,怀疑是zf库没原子读取导致突然一瞬间编码器数据变大导致反转,想请问ai8051有没有原子读取的机制
回复

使用道具 举报 送花

16

主题

943

回帖

4219

积分

超级版主

积分
4219
发表于 2026-8-14 09:21:24 | 显示全部楼层
STC32位单片机解决原子操作问题小技巧
https://www.stcaimcu.com/thread-22641-1-1.html
(出处: 国芯人工智能技术交流网站)


回复

使用道具 举报 送花

16

主题

943

回帖

4219

积分

超级版主

积分
4219
发表于 2026-8-14 09:21:46 | 显示全部楼层

我已获得充分的信息。让我结合手册内容,为用户详细解答关于 STC 读取定时器原子保护的问题。

需要补充确认一下:用户使用的是 AI8051U32K64(即 Ai8051U 系列)。手册中已经给出了非常明确的官方示例代码来解决这个原子读取问题。让我整理出完整专业的回答。

我注意到手册中提供了官方的原子保护方案(通过 TR 停止计数 + NOP + 关闭 EA 保护),以及论坛社区讨论的多种方案。让我把核心内容组织好。


关于 STC 读取定时器的原子保护问题

这位同学提到的问题非常典型,正是多字节读取非原子性导致的数据错乱。我先帮你把原理讲透,再给出几种可靠的解决方案。

一、问题根源

STC 的定时器计数寄存器(如 TH0/TL0、T2H/T2L 等)是分高、低字节两个地址存放的。8051 内核一次只能读 8 位数据,读取 16 位计数值必须分两次:

低字节  高字节
 ┌──┬──┐
 │TL│TH│   ← 需要两次 8 位读取
 └──┴──┘

如果恰好在读低字节与读高字节之间,定时器发生了进位/溢出(例如低字节从 0xFF 进位到 0x00,同时高字节 +1),那么你读到的高字节和低字节就不是同一个时刻的值,拼接出来就是一个"错位"的大数——这就是你速度环在高速(250+ 脉冲)时突然反转的根因:高速时进位发生概率急剧上升,一旦读到错位数据,编码器计数值瞬间"跳变",速度环判断出错。

AI8051U 的定时器没有硬件锁存寄存器(即没有像某些 MCU 那样在读取时硬件自动锁存高低字节的机制)。手册中关于各定时器(T0~T4、T11)的描述均未提及读取锁存,因此需要软件层面做原子保护。


二、官方推荐的原子保护写法(手册示例)

Ai8051U 手册在《定时器/计数器》一章中专门给出了官方解决方案。核心思想是 "先停计数 → 关中断 → 原子读取 → 恢复"。

⚠️ 特别提醒:AI8051U 内部是 4 级流水线,在关闭 TR(停止计数)后,必须插入 4 个 NOP,让之前的计数真正停下来、且中间可能发生的中断有空间响应,然后才能关闭 EA。

unsigned int  upper_timer = 0;   // 高16位(扩展用,如果你只读16位可不需要)
unsigned long time_value;        // 读取结果

// 定时器0中断:溢出时高16位+1(用于32位扩展,16位场景可省略)
void TIMER0_ISR(void) interrupt TMR0_VECTOR
{
    upper_timer++;
}

unsigned long get_timer(void)
{
    TR0 = 0;             // 1. 停止计数,防止读取过程中产生进位
    NOP(4);              // 2. 等TR0真正关闭(等4级流水线走完,期间Timer0中断可正常响应)
    EA  = 0;             // 3. 关闭总中断,防止主循环读取被中断打断(原子保护)
    *((unsigned int  *)&time_value)     = upper_timer;  // 载入高16位
    *(((unsigned char *)&time_value)+2) = TH0;          // 高字节
    *(((unsigned char *)&time_value)+3) = TL0;          // 低字节
    EA  = 1;             // 4. 恢复总中断
    TR0 = 1;             // 5. 恢复定时器运行
    return time_value;
}

如果你只是读 16 位编码器计数值(不需要 32 位扩展),可简化为:

unsigned int get_timer0_16(void)
{
    unsigned int cnt;
    TR0 = 0;     // 停止计数
    NOP(4);      // 等TR0真正关闭
    EA  = 0;     // 关总中断,原子保护
    cnt = (TH0 << 8) | TL0;   // 读取高、低字节
    EA  = 1;     // 恢复中断
    TR0 = 1;     // 恢复计数
    return cnt;
}

这里的 NOP(4) 在 Keil C251 中是 _nop_() 宏(intrins.h),或直接写 _nop_();_nop_();_nop_();_nop_();。


三、针对你的编码器场景(逐飞库)的建议

从论坛讨论看,你说用的是**逐飞库(zf库)**读取编码器计数值,怀疑其未做原子保护。建议:

  1. 确认 zf 库的读取函数是否只做了一次 (T2H<<8)|T2L 式的普通读取——如果是,那就没有原子保护,需要替换成上文的原子读取方式。
  2. 编码器的计数值读取频率不高(速度环一般几十到几百 Hz),停一下计数再读的代价极小,完全不影响性能,放心用。
  3. 如果你不想停计数器,社区还有一种**"关键段自旋校验"**思路(据论坛用户分享,见 STC32G 定时器读取竞争修复帖):读两次,若两次高低字节拼接一致则认为有效,否则重读。但建议优先采用官方"停计数+关中断"方案,最可靠。

四、补充:原子操作的一般原则

据论坛技术贴(STC32 原子操作小技巧)总结,无论 8 位还是 32 位机,只要主循环和中断里同时操作超过总线位宽(8 位)的变量,都存在被"分步修改/读取"而拼错的风险。通用对策:

  • 写:先算到中间变量,最后一次性赋值;
  • 读:先读到缓冲变量。

而 AI8051U 上最直接的"硬件级原子"手段,就是临时关闭总中断 EA(配合 4 级流水线的 NOP),手册也正是推荐的这条路线。


小结:AI8051U 的定时器没有硬件读锁存,但官方提供了标准的**"停 TR + NOP(4) + 关 EA + 原子读 + 恢复"**方案,可直接套用解决你编码器高速反转的问题。若逐飞库的读取函数未做保护,请按上述方法改写。

如果你的编码器是用的定时器 2/3/4(T2H/T2L 等),把例子里的 TR0/TH0/TL0 对应替换成 T2R/T2H/T2L 即可,逻辑完全一样。需要我帮你按你具体用的定时器写一份完整代码吗?


🔍 搜索 "STC 定时器 原子保护 读取"

📌 相关论坛讨论

  1. 系列文章目录--STC单片机 FreeRTOS入门
  2. STC读取定时器原子保护!
  3. STC32G144K246单片机(齐芯32051单片机)论道--系列文章

⏱️ 查找用时 16.9s | 总回答用时 31.5s

回复

使用道具 举报 送花

6

主题

7

回帖

114

积分

注册会员

积分
114
 楼主| 发表于 2026-8-14 11:07:20 | 显示全部楼层
AI*** 发表于 2026-8-14 09:21
我已获得充分的信息。让我结合手册内容,为用户详细解答关于 STC 读取定时器原子保护的问题。
需要补充确认 ...

学习到了,我使用了校验高字节的方式解决了这个问题
        case TIM1_ENCOEDER:
        {
            do
            {
                th1 = TH1;
                tl  = TL1;
                th2 = TH1;
            } while (th1 != th2);
            dat = ((uint16)th1 << 8) | (uint16)tl;
            break;
        },顶多多读取一次
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-7 12:46 , Processed in 0.067749 second(s), 52 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表