123
返回列表 发新帖我要提问本帖赏金: 3.00元(功能说明)

[STM32F1] STM32芯片导致的还是C语言导致的这个灵异事件,求大神解释!

[复制链接]
9162|56
john_lee 发表于 2016-12-9 10:09 | 显示全部楼层
我教你一个正规的方法:你的 MCU 是 Cortex-M3,你应该直接把两个字节的数据“一次”取出,然后使用 CMSIS 提供的字节序反转函数:__REV16。这个函数是编译器的 builtin (内置) 函数,生成的 CPU 指令最少就只有一条。
以你的表达式为例:
  1. result = __REV16 (((uint16_t*)str)[counter]); // 这里只有一次读取数据
  2. counter += sizeof (uint16_t);
xiaofei558008 发表于 2016-12-9 10:18 | 显示全部楼层
数组是往下生长的;和C语言和单片机都没关系;
jgp886585 发表于 2016-12-9 10:23 | 显示全部楼层
学习到了,之前我也这么干过,但是算出来值怎么都不对,还纠结了好多天,后边拆开就好了
聿怀嘿嘿 发表于 2016-12-9 10:30 来自手机 | 显示全部楼层
本帖最后由 聿怀嘿嘿 于 2016-12-9 10:32 编辑

应该是表达式逻辑问题,试试result = (str[counter ++] << 8) | (str[counter +1]);
zsxsdu 发表于 2016-12-9 10:31 | 显示全部楼层
诡异,同求解1111111
LearningASM 发表于 2016-12-9 11:19 | 显示全部楼层
本帖最后由 LearningASM 于 2016-12-9 11:21 编辑

试一下__REV16
result = __REV16((u16)(str[counter]));counter += 2;

32bit下用__REV,专门针对大端小端转换的汇编封装函数
oufuqiang 发表于 2016-12-9 11:44 | 显示全部楼层
工行ATM 发表于 2016-12-8 16:40
但是。。。拆开看起来不爽。。。

拆开写又不会增大最终代码大小,还能明确计算过程和逻辑,为什么非要写成一行?

zhuangbility leads leipility。
taoest 发表于 2016-12-9 12:04 | 显示全部楼层
不要写那种自己不知道计算机会如何执行的代码

纠结这种代码做什么,还有更多更重要的事情等着你去做。
 楼主| 工行ATM 发表于 2016-12-9 12:44 | 显示全部楼层
john_lee 发表于 2016-12-9 10:09
我教你一个正规的方法:你的 MCU 是 Cortex-M3,你应该直接把两个字节的数据“一次”取出,然后使用 CMSIS  ...

这个代码不起作用。。
xlsbz 发表于 2016-12-9 13:01 | 显示全部楼层
楼主是初学者   当然是你自身的问题
LyCrystal 发表于 2016-12-9 13:28 | 显示全部楼层
关于result = ((u16)str[counter ++] << 8) | str[counter ++];
不要写这种依赖编译器具体实现、芯片相关的操作;它的计算结果受计算顺序影响;
应该分成两步计算
john_lee 发表于 2016-12-9 15:44 | 显示全部楼层
LearningASM 发表于 2016-12-9 11:19
试一下__REV16
result = __REV16((u16)(str[counter]));counter += 2;

你这个写法只取了一字节数据,然后扩展为两字节(高字节为 0),然后 _REV16,结果是 result 低字节为 0,高字节是 str[counter] 的数据。
john_lee 发表于 2016-12-9 15:47 | 显示全部楼层
工行ATM 发表于 2016-12-9 12:44
这个代码不起作用。。

贴结果来看,最好附带反汇编。光说一句不起作用算什么意思。
rgwan 发表于 2016-12-9 15:48 来自手机 | 显示全部楼层
楼主的代码是UB。计算顺序看编译器实现。没有可移植性可言。
LearningASM 发表于 2016-12-9 16:54 | 显示全部楼层
john_lee 发表于 2016-12-9 15:44
你这个写法只取了一字节数据,然后扩展为两字节(高字节为 0),然后 _REV16,结果是 result 低字节为 0, ...

2333,果然是啊
 楼主| 工行ATM 发表于 2016-12-12 08:47 | 显示全部楼层
john_lee 发表于 2016-12-9 15:47
贴结果来看,最好附带反汇编。光说一句不起作用算什么意思。

   406:                                         ConfigDeviceRAM.Sort.limit_OA_VA = __REV16 (((uint16_t*)usart_receive_temp)[modbus_rx_num]); // 这里只有一次读取数据
0x080014D6 49B5      LDR      r1,[pc,#724]  ; @0x080017AC
0x080014D8 4AB3      LDR      r2,[pc,#716]  ; @0x080017A8
0x080014DA 7812      LDRB     r2,[r2,#0x00]
0x080014DC F8310012  LDRH     r0,[r1,r2,LSL #1]
0x080014E0 F7FEFE5E  BL.W     __REV16 (0x080001A0)
0x080014E4 49B2      LDR      r1,[pc,#712]  ; @0x080017B0
0x080014E6 8308      STRH     r0,[r1,#0x18]
   407:                                         modbus_rx_num += sizeof (uint16_t);
   408:                                          
   409:                                 }
0x080014E8 48AF      LDR      r0,[pc,#700]  ; @0x080017A8
0x080014EA 7800      LDRB     r0,[r0,#0x00]
0x080014EC 1C80      ADDS     r0,r0,#2
0x080014EE 49AE      LDR      r1,[pc,#696]  ; @0x080017A8
0x080014F0 7008      STRB     r0,[r1,#0x00]
0x080014F2 E000      B        0x080014F6
   410:                                 else break;


上面是汇编,我用0x1234做测试,出来的结果是0x2030.
周末没有上论坛,大神看下是什么原因
john_lee 发表于 2016-12-12 16:21 | 显示全部楼层
  • 反汇编的逻辑没有问题,你确定原始数据正确?
    可以这样验证一下:
    1. result = ((uint16_t*)usart_receive_temp)[modbus_rx_num];    // 取数据
    2. printf ("%d\n", result);        // 输出字节交换前数据
    3. result = __REV16 (result);
    4. printf ("%d\n", result);        // 输出字节交换后数据

  • 你用的 MDK 是 5.20 之前的版本,__REV16 是以函数的形式提供的,最新版本的 MDK,__REV16 是直接以指令的形式提供的。
  • 你不开优化的么?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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