找回密码
 立即注册
查看: 316|回复: 11

发现一个BUG,不知道是编译器问题还是芯片问题

[复制链接]
已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
发表于 2026-10-31 14:47:13 | 显示全部楼层 |阅读模式
截图202610311440229943.jpg


我在bdata中声明一个unsigned int型变量,再把这个变量的某一位用sbit单独引用出来
截图202610311442537522.jpg
这个函数在中断里运行,DianJiaoDu的最大值2047,所以DianJiaoDu^15永远为0
但是这个if(aa)一直能进入,看不懂汇编帮忙看下什么问题
截图202610311445144963.jpg
我在aa判断之前等于0,就进不了这个if判断中了,没有其他地方更改DianJiaoDu这个变量
FOC.zip (434.16 KB, 下载次数: 23)
回复

使用道具 举报 送花

已绑定手机

2

主题

154

回帖

470

积分

中级会员

积分
470
发表于 2026-10-31 15:41:14 | 显示全部楼层
问了下ai,说
sbit不能用于多字节,只能用于字节。
我猜测  sbit aa=xx^15;//xx为 int
相当于sbit aa=xx^7;

可以改为使用位计算:if(xx&0x8000)...
回复

使用道具 举报 送花

已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
 楼主| 发表于 2026-10-31 16:22:47 | 显示全部楼层
jrc*** 发表于 2026-10-31 15:41
问了下ai,说
sbit不能用于多字节,只能用于字节。
我猜测  sbit aa=xx^15;//xx为 int

可以的,c51我一直这么用没问题
回复

使用道具 举报 送花

已绑定手机

2

主题

154

回帖

470

积分

中级会员

积分
470
发表于 2026-10-31 16:57:20 | 显示全部楼层
测试了下,sbit确实可以用于bdata  int,而且看汇编地址也是正常的。
测试代码:
截图202610311650575717.jpg

汇编
截图202610311652195515.jpg

x1的字节地址=0x20;
x2的字节地址=0x21;
x3的字节地址=0x22;

if(b1)对应汇率编
0xFF0306   300702      JNB      0x20.7,C:0x030B
300702 中的07 是位地址 = 0x07;  对应字节地址 0x20的第7位.

if(b7)对应汇率编
0xFF030B   301702      JNB      0x22.7,C:0x0310
301702中的17 是位地址 = 0x17;  对应字节地址 0x20 + 0x17/8 = 0x20+2 = 0x22 的第7位.

if(b15)对应汇率编
0xFF0310   301F02      JNB      0x23.7,C:0x0315
301F02中的1F 是位地址 = 0x1F;  对应字节地址 0x20 + 0x1F/8 = 0x20+3 = 0x23 的第7位.




回复

使用道具 举报 送花

已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
 楼主| 发表于 2026-10-31 17:06:59 | 显示全部楼层
jrc*** 发表于 2026-10-31 16:57
测试了下,sbit确实可以用于bdata  int,而且看汇编地址也是正常的。
测试代码:

long也能这样操作啊,
回复

使用道具 举报 送花

已绑定手机

2

主题

154

回帖

470

积分

中级会员

积分
470
发表于 2026-10-31 17:38:42 | 显示全部楼层
void SheZhiSVPWM()中的有关DianJiaoDu变量的汇编如下,
看起来是没有问题的,字节地址=0x20;
截图202610311734171053.jpg

截图202610311734562960.jpg


如果if(aa)能进,有可能是别的数组越界写入了?
回复

使用道具 举报 送花

已绑定手机

2

主题

154

回帖

470

积分

中级会员

积分
470
发表于 6 天前 | 显示全部楼层
先说结论:
是大端内存序的问题,DianJiaoDu ^15 是指向高位地址的第7位。
  即 DianJiaoDu字节地址为0x20, DianJiaoDu ^15 则是字节地址为0x21的第7位。
stc单片机是是大端内存序,即高位字节数值 存在 低位地址。
如 DianJiaoDu = 0x1234, 则 34是存在高位地址0x21,12存在低位地址0x20;
假设DianJiaoDu = 0x07FF, 则0x21字节地址的值 = FF, 所以aa为1。
所以,你如果有取DianJiaoDu的最高位,应该是DianJiaoDu ^7;

这是今天我想起了大端的事,
然后特意测试了,测试代码如下:
unsigned int mot_vp,mot_speed;//相位累加器,相位步进速度
unsigned int bdata DianJiaoDu;//电角度
sbit aa=DianJiaoDu^15;
unsigned int x1,x2;
unsigned char  c1,c2;

void SheZhiSVPWM(){//写PWM寄存器
        unsigned int PWMU;
        unsigned char* p;
        PWMU=DianJiaoDu;
        DianJiaoDu=(mot_vp)>>5;//右移5量化到2048
        p = (unsigned char*)&DianJiaoDu;
        c1 =  p[0];
        c2 =  p[1];
        if(0!=DianJiaoDu){
                if(aa){//PWM平滑过度
                        x1++;
                        x2--;
                }
        }
        mot_speed --;
}
void main(){
        WTST=0;
        CKCON=0;
        P_SW2=0x80;
        
        mot_vp = 0xFFff;
        mot_speed = 10;
        
        while(1){
                SheZhiSVPWM();
                mot_speed +=1;
        };
}

断点放在if(aa),中断后,各变量的值如下截图,
DianJiaoDu为0x07FF时,aa=1, DianJiaoDu的低地址字节c1=07,高地址字节c2=FF; 而aa指向高地址字节。

截图202611021043198948.jpg




后面补充更正 (2026-11/02 12:15):
不是stc单片机内存序是大端,是keil c251编译器决定的,“多字节变量"大端"存放是 Keil 编译器(C51 / C251)的约定”
stc32G.pdf文档中也有一处这个解释:
截图202611021213171604.jpg



回复

使用道具 举报 送花

已绑定手机

24

主题

701

回帖

2731

积分

金牌会员

积分
2731
发表于 6 天前 | 显示全部楼层
QQ6243*** 发表于 2026-10-31 16:22
可以的,c51我一直这么用没问题

可以用,但位15可不是真的BIT5
回复

使用道具 举报 送花

已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
 楼主| 发表于 6 天前 | 显示全部楼层
jrc*** 发表于 2026-11-2 10:46
先说结论:
是大端内存序的问题,DianJiaoDu ^15 是指向高位地址的第7位。
  即 DianJiaoDu字节地址为0x20 ...

测试了下确实如此
回复

使用道具 举报 送花

已绑定手机

232

主题

239

回帖

1302

积分

版主

积分
1302
发表于 5 天前 | 显示全部楼层

我看到了这个帖子,结论已经清楚了。这个问题的本质不是芯片 BUG,也不是编译器 BUG,是 C51 的 bdata 位寻址规则 + Keil C51 的小端字节序,属于使用问题。

一、C51 的 sbit 位编号规则(关键)

在 Keil C51 里,对 bdata 区变量用 ^ 取位时,位编号是"从变量起始字节算起的绝对位序号",跨字节连续编号,低字节在前:

  • xx^0 ~ xx^7 → 变量第一个字节(低字节)的 B0~B7
  • xx^8 ~ xx^15 → 变量第二个字节(高字节)的 B0~B7

也就是说,对 unsigned int xx(2 字节):

sbit b = xx^15;   // 等价于第二字节(高字节)的 B7

而 xx^8 才是第二字节的 B0。

所以 DianJiaoDu ^ 15 不是"第 15 位"这个直观理解,它指向的是高字节的 bit7,也就是整个 16 位变量的 bit15 —— 从数值角度讲确实是最高位。这本身没错。

二、问题出在哪里

帖主说 DianJiaoDu 最大 2047(0x07FF),所以"DianJiaoDu ^ 15 永远为 0"——这个推断是错的,问题在字节序。

XX 单片机的 C51 实际内存布局是小端(little-endian)?这里要更正一下:帖子里第 6 楼说"stc单片机是大端内存序,即高位字节存低位地址",这个说法是错的。

C51 是严格的小端序(little-endian):低字节存低地址,高字节存高地址。

对 unsigned int DianJiaoDu,起始字节地址 0x20:

  • 0x20 存 低字节(bit0~bit7)
  • 0x21 存 高字节(bit8~bit15)

那么 DianJiaoDu ^ 15:

  • ^15 按 C51 规则 = 第二字节(地址 0x21,高字节)的 B7 = 变量的 bit15
  • DianJiaoDu 最大 0x07FF,高字节 = 0x07,其 B7 = 0,所以 aa 应该恒为 0

所以按小端序分析,帖主的原代码逻辑其实是对的,aa 应该恒为 0。

那为什么帖主看到"能进 if(aa)"?第 5 楼 jrc 的怀疑更靠谱:别的数组越界,或者 bdata 布局被别的东西覆盖了。因为 bdata 只有 16 字节(0x20~0x2F),位寻址区非常紧张,多个 bdata 变量 + sbit 混用时,如果变量声明顺序变化,DianJiaoDu 的实际起始地址可能不在 0x20,帖子里反汇编看到的地址也要以实际为准。

三、给出的结论与建议

  1. 这不是芯片 BUG:XX 单片机(STC 8051 内核)不存在 bdata 位寻址的硬件缺陷,sbit 的位寻址是标准 8051 硬件功能(位寻址区 0x20~0x2F,可位寻址 16 字节 = 128 位)。
  2. 也不是编译器 BUG:Keil C51 的 ^n 位编号规则就是这样——跨字节连续编号,从变量首地址字节的 bit0 开始数。unsigned int xx 时 xx^8~xx^15 是第二个字节的 8 位。
  3. 帖子里第 6 楼"STC是大端内存序"的说法是错的,需要纠正:C51 是小端序,低字节在低地址。据我判断,这个错误结论会误导后续读者去写 DianJiaoDu ^ 7 来取最高位,那是错的。
  4. 正确的取最高位写法(unsigned int 变量,小端序):
unsigned int DianJiaoDu;
sbit aa = DianJiaoDu ^ 15;      /* 高字节的 B7,即 bit15,正确 */

如果想避免跨字节的混淆,最稳妥是用位运算,不要用 sbit:

if (DianJiaoDu & 0x8000) { ... }   /* 判断 bit15 */
  1. 排查真实问题的方向:既然逻辑上 aa 应恒为 0,却看到进了 if,按以下顺序查:
    • 反汇编确认 DianJiaoDu 实际分配的 bdata 地址,以及 aa 指向的位地址;
    • 检查是否有其他 bdata 变量/数组越界覆盖了 DianJiaoDu 所在字节;
    • bdata 总容量只有 16 字节(0x20~0x2F),位寻址变量多时注意别超;
    • 检查是否有中断重入(帖主说该函数在中断里运行,若 DianJiaoDu 在主循环也被改写,需加保护,注意关中断后要插 4 个 NOP)。

四、如果确实怀疑芯片

可以做一个最小验证:固定 DianJiaoDu = 0x0800,读 aa 看是否为 1;再 DianJiaoDu = 0x07FF,看 aa 是否为 0。用万用表/串口打印确认。若这都异常,再考虑芯片问题,但按原理不会。


总结:这是 Keil C51 的 sbit 跨字节位编号规则导致的误解,不是芯片 BUG 也不是编译器 BUG。xx^15 对 unsigned int 指向高字节 B7(bit15),在小端序下数值上确实是最高位,帖主逻辑没错;实际现象更可能是 bdata 变量地址/越界问题。另外请特别注意:第 6 楼"STC是大端"的结论是错误的,C51 是小端序。

如果你能把这个帖子的完整反汇编(尤其 DianJiaoDu 的地址分配和 aa 的位地址)贴出来,或者把你的实际工程代码发我,我可以帮你定位到底是谁改了那个字节。


🔍 搜索 "STC单片机 编译器BUG 芯片问题"

📌 相关论坛讨论

  1. 发现一个BUG,不知道是编译器问题还是芯片问题
  2. Keil C51编译器BUG修补插件,Keil C251编译器BUG修补插件
  3. keil编译问题汇总

⏱️ 查找用时 1.2s | 总回答用时 11.5s

回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-11-8 02:08 , Processed in 0.077569 second(s), 88 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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