硬汉嵌入式论坛

 找回密码
 立即注册
查看: 804|回复: 18
收起左侧

[技术讨论] keil(V9.61) c51平台数据比较大小怪事

  [复制链接]

0

主题

9

回帖

9

积分

新手上路

积分
9
发表于 2025-5-24 17:53:26 | 显示全部楼层 |阅读模式
本帖最后由 jxcrg_t35 于 2025-5-24 17:55 编辑

定义一个全局变量uint16_t sys_tick ,在10ms定时器内sys_tick ++,通过函数获取当前sys_tick计数
uint16 get_sys_tick(void)
{
   return sys_tick;
}

在主循环程序:
uintdata = get_sys_ticks();
uint16_t uintll               
while(1)
{
  uintll = get_sys_ticks();
  if((uintll - uintdata) >= 50u){uart0_dbg("\r\n[%u,%u]", uintdata, uintll); uintdata = uintll;}
}

现在软件仿真现象为
随机为获取到了sys_tick出现错误.如:
[0,50]
[50,100]
[100,150]
[150,200]
[200,250]
[250,0]
[0,256]

[256,306]
[306,356]

[1856,1906]
[1906,1956]
[1956,2006]
[2006,1792]

[1792,2049]
[2049,2099]

[3749,3799]
[3799,3584]
[3584,3841]

[3841,3891]


如果这样处理就不会.
if((uint8_t)(uintll - uintdata) >= 50u){uart0_dbg("\r\n[%u,%u]", uintdata, uintll); uintdata = uintll;}
请教各位



回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-5-25 09:42:51 | 显示全部楼层
这个情况下,你要看下这个if里面(uintll - uintdata)结果是以什么数据类类型存在了。可以看下反汇编的处理
回复

使用道具 举报

0

主题

9

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2025-5-25 10:09:08 | 显示全部楼层
eric2013 发表于 2025-5-25 09:42
这个情况下,你要看下这个if里面(uintll - uintdata)结果是以什么数据类类型存在了。可以看下反汇编的处理

谢谢回复.这个和具体数据类型没关系吧.是获取到sys_tick的数字随机变化了.
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-5-25 14:10:03 | 显示全部楼层
jxcrg_t35 发表于 2025-5-25 10:09
谢谢回复.这个和具体数据类型没关系吧.是获取到sys_tick的数字随机变化了.

我理解错了,可以试试sys_tick变量定义加个__IO或者volatile,防止优化,保证每次都从源地址读数据

或者get函数前后做个开关中断
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
发表于 2025-5-25 21:07:26 来自手机 | 显示全部楼层
51是8位机,执行get_sys_tick时进入中断了,sys_tick发生变化了,而且还发生了8位数据的进位
回复

使用道具 举报

0

主题

9

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2025-5-25 21:32:54 | 显示全部楼层
eric2013 发表于 2025-5-25 14:10
我理解错了,可以试试sys_tick变量定义加个__IO或者volatile,防止优化,保证每次都从源地址读数据

或 ...

谢谢回复 .
sys_tick已做了volatile定义.现解决的方法是在get_sys_tick()函数内做了关开中断.
个人理解为,在中断里只写,外部程序只读,觉得不存在资源同步问题.不知道理解对么
回复

使用道具 举报

0

主题

9

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2025-5-25 21:33:52 | 显示全部楼层
eric2013 发表于 2025-5-25 14:10
我理解错了,可以试试sys_tick变量定义加个__IO或者volatile,防止优化,保证每次都从源地址读数据

或 ...

再,外部程序单独读取sys_tick的值,不存在跳变的情况.
回复

使用道具 举报

69

主题

482

回帖

694

积分

金牌会员

积分
694
发表于 2025-5-25 22:17:53 | 显示全部楼层
你开的几级优化?关于 PY32 和 51 的问题也可以进我的 QQ 小群讨论:725436073
本人的 51 ARM PC RTOS 研究群:725436073
回复

使用道具 举报

0

主题

22

回帖

22

积分

新手上路

积分
22
发表于 2025-5-26 16:32:48 | 显示全部楼层
taobaofarmer 发表于 2025-5-25 22:17
你开的几级优化?关于 PY32 和 51 的问题也可以进我的 QQ 小群讨论:725436073

复位的那个问题,,搞清楚了么?
回复

使用道具 举报

0

主题

22

回帖

22

积分

新手上路

积分
22
发表于 2025-5-26 16:45:49 | 显示全部楼层
jxcrg_t35 发表于 2025-5-25 21:32
谢谢回复 .
sys_tick已做了volatile定义.现解决的方法是在get_sys_tick()函数内做了关开中断.
个人理解 ...

理解的并不对,,对于8位机来说,读取一个16位的数据要分两个指令,,如果再读一个字节的时候来了中断,并更新了另一个字节,那么回到主函数继续执行指令就会造成读取错误。所以必须保证读取16字节数据时必须保证这个过程的原子性。
回复

使用道具 举报

0

主题

9

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2025-5-27 22:55:01 | 显示全部楼层
CofMilk 发表于 2025-5-26 16:45
理解的并不对,,对于8位机来说,读取一个16位的数据要分两个指令,,如果再读一个字节的时候来了中断, ...

谢谢,目前关开中断,解决了.
回复

使用道具 举报

0

主题

2

回帖

2

积分

新手上路

积分
2
发表于 2025-6-26 11:02:17 | 显示全部楼层
参考一下这段代码,建议和我一样这么做。关中断、停定时器之类的我都试过,很影响定时器的周期一致性,这种写法就算碰到刚好进位的情况,也就是多执行一轮循环的事,几us的事情
uint32_t SysTick_get(void)
{
        uint32_t tmp_tick;
        do
        {
                tmp_tick = SysTick;
        } while (tmp_tick != SysTick);
        return tmp_tick;
}
回复

使用道具 举报

0

主题

2

回帖

2

积分

新手上路

积分
2
发表于 2025-6-26 11:17:27 | 显示全部楼层
这种情况本质原因是,你刚读出其中8位数据,就碰到定时器中断,然后恰好低8位又进位了,然后你拿着进位前的8位和进位后的另外8位做拼接,就读出来错误的数据了
回复

使用道具 举报

0

主题

9

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2025-6-26 20:26:03 | 显示全部楼层
zhaohaofan 发表于 2025-6-26 11:02
参考一下这段代码,建议和我一样这么做。关中断、停定时器之类的我都试过,很影响定时器的周期一致性,这种 ...

试验过了,程序运行正常.非常感谢
回复

使用道具 举报

1

主题

17

回帖

20

积分

新手上路

积分
20
发表于 2025-6-26 21:14:28 来自手机 | 显示全部楼层
eric2013 发表于 2025-5-25 14:10
我理解错了,可以试试sys_tick变量定义加个__IO或者volatile,防止优化,保证每次都从源地址读数据

或 ...

C51编译器团队认为他们的用户都是不懂volatile关键字的制杖,所以这个编译器下面写不写volatile效果是一样的。
回复

使用道具 举报

3

主题

91

回帖

100

积分

初级会员

积分
100
发表于 2025-6-27 06:20:41 来自手机 | 显示全部楼层
如果是多指令,读的时候,读到2次相同才返回就好了
回复

使用道具 举报

4

主题

24

回帖

36

积分

新手上路

积分
36
发表于 2025-6-27 08:38:16 | 显示全部楼层
lxh0508 发表于 2025-5-25 21:07
51是8位机,执行get_sys_tick时进入中断了,sys_tick发生变化了,而且还发生了8位数据的进位

考虑一下这个原因,8位CPU读取16位数据时,会读两次的,低八位和高八位,如果在两次中间读数据中间发生了中断,低八位就会发生变化。如果不巧低八位位0xFF就会进位,读到错误的高八位。定时器中断频率越高,越容易触发这个现象。
回复

使用道具 举报

0

主题

9

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2025-6-27 21:03:36 | 显示全部楼层
way2888 发表于 2025-6-27 06:20
如果是多指令,读的时候,读到2次相同才返回就好了

你说得对,zhaohaofan的网友的方法就是这个思路,只是比较了一次.现在我的程序是10ms中断一次,目前运行正常.
回复

使用道具 举报

4

主题

20

回帖

32

积分

新手上路

积分
32
发表于 2025-7-3 00:29:47 | 显示全部楼层
Rundstedt 发表于 2025-6-26 21:14
C51编译器团队认为他们的用户都是不懂volatile关键字的制杖,所以这个编译器下面写不写volatile效果是一 ...

不会吧,我在51内核单片机上用过,队列缓冲里面有个变量用于计数缓冲区数据的字节数,中断里面进数据,任务读数据,结果发现运行异常,后面发现是忘记加volatile了,加了volatile就运行正常了。中断和任务都会改写的数据,加关键字volatile准没错
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-12 02:49 , Processed in 0.066754 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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