登录/注册

单片机 STM32 大小端对程序的影响

更多

好的,STM32作为基于ARM Cortex-M内核的微控制器,其字节序(大小端)会对程序产生几方面显著的影响。了解这些影响对于编写正确、稳定和兼容的嵌入式代码至关重要。

核心概念回顾:

STM32的大小端配置:

大小端对STM32程序的具体影响:

  1. 数据访问(尤其是强制类型转换和结构体/联合体):

    • 问题: 这是最常见的影响点。当你使用强制类型转换((uint16_t*)(float*))或通过结构体/联合体访问不同数据类型的数据时,大小端决定了内存中字节的排列顺序。
    • 例子: 假设你有一个uint32_t变量value = 0xAABBCCDD;,存储在地址0x20000000开始的内存中。
      • 小端模式下:
        • 0x20000000: 0xDD (LSB)
        • 0x20000001: 0xCC
        • 0x20000002: 0xBB
        • 0x20000003: 0xAA (MSB) 如果程序中使用uint16_t *ptr = (uint16_t*)&value;,那么*ptr在地址0x20000000处读取到的将是0xDDCC
      • 大端模式下:
        • 0x20000000: 0xAA (MSB)
        • 0x20000001: 0xBB
        • 0x20000002: 0xCC
        • 0x20000003: 0xDD (LSB) 同样的指针操作,*ptr(在0x20000000)读取到的将是0xAABB
    • 影响: 如果代码期望以特定方式解释内存中的数据(比如,通过uint16_t指针读取uint32_t的低16位),而在另一种大小端模式下编译运行,结果会完全错误。
  2. 外设寄存器访问:

    • 问题: STM32的外设寄存器有自己固定的物理字节顺序(通常按位域在寄存器中的位置定义,这种顺序与CPU的大小端模式无关)。
    • ST的硬件库(HAL/LL, 标准外设库): 这些库已经为你处理了大小端问题。当库函数使用uint32_t *指针访问一个32位寄存器时,编译器会根据STM32当前的大小端模式进行正确的内存访问。只要寄存器被定义为特定的uint32_t类型,库函数就能正确读写寄存器的值。
    • 手动寄存器操作: 如果你自己直接通过绝对地址指针访问寄存器(不推荐,但有时需要),你需要非常小心:
      • 即使在小端STM32上,物理寄存器的位[31:24]仍然对应最高字节。当你用uint32_t *reg = (uint32_t*)0x40000000; *reg = 0xAABBCCDD;写入时,内核会自动根据当前大小端模式将0xDD写到低地址(小端)或将0xAA写到低地址(大端)。在另一端读取该寄存器的设备必须知道STM32当前的大小端模式才能正确解释数据。
      • 使用__packed结构体访问寄存器位域需要极其小心,因为__packed会强制不同字节/半字的位域使用紧密内存排列,其解释也依赖于大小端。这容易出错,应尽量避免。建议使用库提供的位域宏或直接使用位操作(&, |, ~, <<, >>)。
      • 以字节(uint8_t *)或半字(uint16_t *)方式访问寄存器的一部分时,访问到的内容也取决于STM32当前的大小端模式,这可能与外设寄存器定义的内部位域顺序不一致。
  3. 外设数据传输:

    • 问题: 通过外设(如UART, SPI, I2C, CAN, USB, Ethernet, DMA)发送和接收的数据流(字节序列)通常依赖于应用层的协议定义。
    • 数据打包/解包: 当协议要求将多字节数据(如int16_t, int32_t, float)传输为一个字节序列时,发送方和接收方必须约定这些多字节数据的字节序
    • 影响: 例如,UART协议本身没有定义字节序。如果STM32用小端方式存储一个uint32_t sensorValue,然后简单地将&sensorValue的地址交给DMA或直接用指针按字节循环发送,它会从低地址开始发送,也就是先发LSB。如果接收方期望的是大端格式(先发MSB),那么接收方解析到的将是错误的值。解决方案通常是在发送前或接收后进行显式的字节序转换(Byte Swapping),使用htons, htonl, ntohs, ntohl函数或自定义的位操作来实现。
    • 使用DMA: DMA控制器在执行外设<->内存或内存<->内存传输时,它会按字节或设定的字长进行复制,但不会自动改变字节顺序。如果外设的字节序与内存中的期望不一致(比如内存中变量是小端,而外设的数据线要求特定顺序),就需要在数据传输前或后进行软件转换。
  4. 与外部系统的兼容性:

    • 问题: 当STM32与其他系统(可能是大端的,如某些DSP、PowerPC处理器、网络协议、文件格式)通信或共享数据(如通过共享内存、文件系统)时,字节序必须匹配。
    • 影响: 如果不处理差异,双方无法正确解读交换的数据。网络通信中通常使用网络字节序(即大端序) 作为标准,所以STM32(小端)在发送网络数据前需要用hton*()系列函数转换为大端序,接收后需要用ntoh*()函数转换回小端序。

最佳实践和建议:

  1. 默认为小端模式: 除非有强制性的特定需求(如兼容外部大端芯片或协议),否则应坚持使用STM32的默认小端模式。更改需要谨慎配置内核寄存器。
  2. 避免依赖字节序的代码: 尽量避免代码逻辑依赖于特定的内存字节排列。尤其是:
    • 慎用强制类型转换读取内存的不同部分,除非你非常清楚当前大小端模式。
    • 避免依赖结构体或联合体内存布局进行跨字节边界的位域访问(尤其使用__packed时)。优先使用位操作(&, |, ~, <<, >>)来访问寄存器的位。
  3. 使用字节序转换函数:
    • 在与外部系统通信或处理协议数据时,显式进行字节序转换是最可靠的做法。
    • 标准做法是定义并使用类似网络字节序转换的函数:
      uint16_t swap_bytes_u16(uint16_t x) {
        return ((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8);
      }
      uint32_t swap_bytes_u32(uint32_t x) {
        return ((x & 0xFF000000) >> 24) |
               ((x & 0x00FF0000) >> 8) |
               ((x & 0x0000FF00) << 8) |
               ((x & 0x000000FF) << 24);
      }
    • 许多编译器(如GCC)也提供内置函数:__builtin_bswap16, __builtin_bswap32
    • 对于符合POSIX标准的嵌入式系统(可能基于Linux),可以使用标准库中的htons, htonl, ntohs, ntohl
  4. 清晰定义通信协议: 在跨系统通信中,明确协议中所有多字节整数、浮点数等的字节序。统一约定为网络字节序(大端)是一种常见选择。
  5. 使用标准整数类型: 使用stdint.h中的固定宽度类型(uint8_t, int16_t, uint32_t等)代替int, long等,避免因平台字长不同带来的混淆(尽管字长变化通常比字节序问题更少)。
  6. 关注数据流的字节序: 当通过外设(UART, SPI, I2C, DMA等)读写多字节数据到内存时,思考数据流的物理顺序(MSB/LSB First?)以及它如何映射到内存变量的期望顺序,必要时在软件中及时进行转换。

总结:

STM32默认的小端模式本身在代码内部通常不会引起问题。问题主要发生在:

  1. 涉及强制类型转换、直接指针操作访问不同数据类型或结构体/联合体内部布局时。
  2. 手动操作外设寄存器字节/半字时。
  3. 与外部系统通信或交换多字节数据而未正确处理字节序差异时。
  4. 与外设进行多字节数据传输(包括DMA)但未考虑外设期望的字节序时。

因此,编写健壮的STM32代码,关键在于:

遵循这些实践,大小端就不会成为程序中的隐藏陷阱。

stm32单片机烧录程序会擦除原来的程序

在STM32单片机烧录程序的过程中, 通常情况下会擦除原来的程序 ,并将

2024-09-02 09:42:21

单片机大小转换的几点小技巧

单片机大小端转换的几点小技巧

2023-09-18 10:58:41

stm32单片机如何实现一个按键切换两个程序

stm32单片机如何实现一个按键切换两个程序? 作为一款功能强大的微控制器,STM32

2023-09-14 14:22:44

基于STM32单片机的智能灯电路图设计

基于STM32单片机的智能灯电路图设计

资料下载 yuu_cool 2021-07-30 10:21:24

STM32单片机使用六轴传感器的C语言程序免费下载

本文档的主要内容详细介绍的是STM32单片机使用六轴传感器的C语言程序免费下载。

资料下载 佚名 2020-06-12 16:36:08

使用STM32单片机实现手势识别的程序和工程文件免费下载

本文档的主要内容详细介绍的是单片机使用STM32单片机实现手势识别的程序

资料下载 佚名 2019-09-11 11:37:01

使用STM32单片机和51单片机实现HC04超声波测距模块的程序免费下载

本文档的主要内容详细介绍的是使用STM32单片机和51单片机实现HC04超声波模块测距的

资料下载 佚名 2019-08-21 17:31:00

51单片机STM32单片机有哪些区别

大部分朋友可能都知道51单片机和stm32单片机也知道一般入门会先学习51单片机

资料下载 417804 2019-08-13 17:32:00

怎么擦除stm32单片机里面的程序呢?

怎么擦除stm32单片机里面的程序呢? 要擦除STM32

2023-09-14 14:22:37

STM32单片机程序编译及下载配置

当拿到STM32单片机开发板的时候,程序的编译和下载将是我们踏入STM32

2023-08-11 16:08:41

全方位对比STM32单片机和51单片机

萌新初入单片机领域,常会遇到STM32和51单片机两大种类,无法选择其一来提升技术,也不确定哪个

2023-03-02 14:18:19

ARM单片机STM32单片机之间有什么区别

单片机工程师在进行项目开发的时候,经常需要进行单片机选型,根据项目功能需求选择合适的单片,这就要求对每种

2023-01-07 13:59:38

STM32单片机程序加密解密方法

单片机加密、解密 单片机(MCU)一般都有内部程序区和数据区(或者其一)供用户存放程序

2021-09-26 11:14:38

stm32单片机和51单片机区别是什么

单片机也就是单片微型计算机,和集CPU、RAM、ROM、输入输出设备、中断系统在同一个芯片上的器件。 stm32

2021-08-19 18:21:18

stm32单片机引脚介绍及功能

和I/O引脚。stm32的引脚一般有GPIO和AFIO两种用途。 比如有的引脚是电源正极和黑色标记的电源负极,这是来给单片机提供电源的,要把电流引到对应的引脚才能正常工作。 还有晶体震荡电路反向输入

2021-08-19 16:50:15

7天热门专题 换一换
相关标签