发新帖本帖赏金 3.00元(功能说明)我要提问
123
返回列表
打印
[STM32F1]

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

[复制链接]
楼主: 工行ATM
手机看帖
扫描二维码
随时随地手机跟帖
41
john_lee| | 2016-12-9 10:09 | 只看该作者 回帖奖励 |倒序浏览
我教你一个正规的方法:你的 MCU 是 Cortex-M3,你应该直接把两个字节的数据“一次”取出,然后使用 CMSIS 提供的字节序反转函数:__REV16。这个函数是编译器的 builtin (内置) 函数,生成的 CPU 指令最少就只有一条。
以你的表达式为例:
result = __REV16 (((uint16_t*)str)[counter]); // 这里只有一次读取数据
counter += sizeof (uint16_t);

使用特权

评论回复
42
xiaofei558008| | 2016-12-9 10:18 | 只看该作者
数组是往下生长的;和C语言和单片机都没关系;

使用特权

评论回复
43
jgp886585| | 2016-12-9 10:23 | 只看该作者
学习到了,之前我也这么干过,但是算出来值怎么都不对,还纠结了好多天,后边拆开就好了

使用特权

评论回复
44
聿怀嘿嘿| | 2016-12-9 10:30 | 只看该作者
本帖最后由 聿怀嘿嘿 于 2016-12-9 10:32 编辑

应该是表达式逻辑问题,试试result = (str[counter ++] << 8) | (str[counter +1]);

使用特权

评论回复
45
zsxsdu| | 2016-12-9 10:31 | 只看该作者
诡异,同求解1111111

使用特权

评论回复
46
LearningASM| | 2016-12-9 11:19 | 只看该作者
本帖最后由 LearningASM 于 2016-12-9 11:21 编辑

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

32bit下用__REV,专门针对大端小端转换的汇编封装函数

使用特权

评论回复
47
oufuqiang| | 2016-12-9 11:44 | 只看该作者
工行ATM 发表于 2016-12-8 16:40
但是。。。拆开看起来不爽。。。

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

zhuangbility leads leipility。

使用特权

评论回复
48
taoest| | 2016-12-9 12:04 | 只看该作者
不要写那种自己不知道计算机会如何执行的代码

纠结这种代码做什么,还有更多更重要的事情等着你去做。

使用特权

评论回复
49
工行ATM|  楼主 | 2016-12-9 12:44 | 只看该作者
john_lee 发表于 2016-12-9 10:09
我教你一个正规的方法:你的 MCU 是 Cortex-M3,你应该直接把两个字节的数据“一次”取出,然后使用 CMSIS  ...

这个代码不起作用。。

使用特权

评论回复
50
xlsbz| | 2016-12-9 13:01 | 只看该作者
楼主是初学者   当然是你自身的问题

使用特权

评论回复
51
LyCrystal| | 2016-12-9 13:28 | 只看该作者
关于result = ((u16)str[counter ++] << 8) | str[counter ++];
不要写这种依赖编译器具体实现、芯片相关的操作;它的计算结果受计算顺序影响;
应该分成两步计算

使用特权

评论回复
52
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] 的数据。

使用特权

评论回复
53
john_lee| | 2016-12-9 15:47 | 只看该作者
工行ATM 发表于 2016-12-9 12:44
这个代码不起作用。。

贴结果来看,最好附带反汇编。光说一句不起作用算什么意思。

使用特权

评论回复
54
rgwan| | 2016-12-9 15:48 | 只看该作者
楼主的代码是UB。计算顺序看编译器实现。没有可移植性可言。

使用特权

评论回复
55
LearningASM| | 2016-12-9 16:54 | 只看该作者
john_lee 发表于 2016-12-9 15:44
你这个写法只取了一字节数据,然后扩展为两字节(高字节为 0),然后 _REV16,结果是 result 低字节为 0, ...

2333,果然是啊

使用特权

评论回复
56
工行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.
周末没有上论坛,大神看下是什么原因

使用特权

评论回复
57
john_lee| | 2016-12-12 16:21 | 只看该作者
  • 反汇编的逻辑没有问题,你确定原始数据正确?
    可以这样验证一下:
    result = ((uint16_t*)usart_receive_temp)[modbus_rx_num];    // 取数据
    printf ("%d\n", result);        // 输出字节交换前数据
    result = __REV16 (result);
    printf ("%d\n", result);        // 输出字节交换后数据

  • 你用的 MDK 是 5.20 之前的版本,__REV16 是以函数的形式提供的,最新版本的 MDK,__REV16 是直接以指令的形式提供的。
  • 你不开优化的么?

使用特权

评论回复
发新帖 本帖赏金 3.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则