再STM32F103C8T6中小端存储和大端存储有什么不同,STM32F103C8T6用的是那个,为什么要这么使用?

这是一个非常关键的问题,直接关系到如何正确地理解内存中的数据。STM32F103C8T6的Cortex-M3内核明确采用小端存储模式。

一.核心差异:字节的排列顺序

大端和小端,解决的根本问题是:当一个多字节数据(如32位的 0x12345678)存入内存时,它的高位字节和低位字节,谁放在低地址?

  • 大端模式 :高位字节在前。像阅读一样从左到右,最重要的部分放在最前面。

    • 存储 0x12345678 到地址 0x20000000:

      地址: 0x20000000 | 0x20000001 | 0x20000002 | 0x20000003

      内容(字节): 0x12 | 0x34 | 0x56 | 0x78

      (最高字节0x12在最低地址)

  • 小端模式 :低位字节在前。像做加法从个位算起,最不重要的部分放在最前面。

    • 存储 0x12345678 到地址 0x20000000:

      地址: 0x20000000 | 0x20000001 | 0x20000002 | 0x20000003

      内容(字节): 0x78 | 0x56 | 0x34 | 0x12

      (最低字节0x78在最低地址)

STM32F103C8T6的Cortex-M3内核明确采用小端模式。

二 小端模式的内存视角与优势

  1. 变量访问符合直觉:在小端模式下,用不同宽度的指针访问同一地址,得到的是数据的"低位部分",这更符合编程思维。

    cs 复制代码
    // 假设0x20000000起始存放32位数据 0x12345678
    uint32_t *p32 = (uint32_t*)0x20000000; // *p32 == 0x12345678
    uint16_t *p16 = (uint16_t*)0x20000000; // *p16 == 0x5678  (低16位)
    uint8_t  *p8  = (uint8_t*) 0x20000000; // *p8  == 0x78    (低8位)

    在大端模式下,*p16 会得到 0x1234,这通常不是我们想要的。

  2. 计算效率高:CPU做加法、乘法等运算时,通常从最低有效位开始。小端模式让CPU读取到的第一个字节就是最低位,可以立刻开始计算,无需等待或调整字节顺序。

三 必须警惕的实战场景

虽然CPU在内部自动处理字节序,但在数据交换时你必须手动处理:

1. 与外围设备通信 (如传感器、屏幕、其他MCU):

当通过UART、SPI、I2C发送/接收多字节数据时,双方必须约定字节顺序。

cs 复制代码
// 示例:向一个大端设备发送一个16位数据 0x1234
uint16_t data = 0x1234;
uint8_t buffer[2];

// 错误发送(直接按内存字节序发送,STM32是小端):
// buffer[0] = data & 0xFF;       // 得到 0x34
// buffer[1] = (data >> 8) & 0xFF; // 得到 0x12
// 对方大端设备会理解为 0x3412!

// 正确转换后发送(小端->大端转换):
buffer[0] = (data >> 8) & 0xFF;   // 先发高字节 0x12
buffer[1] = data & 0xFF;          // 后发低字节 0x34
// 通过UART发送buffer

2. 处理网络协议 :

TCP/IP协议明确规定使用大端字节序(网络字节序)。任何网络数据都必须转换。

cs 复制代码
#include <stdint.h>

// 简化的转换函数(实际使用标准库的htonl/htons)
uint16_t htons(uint16_t host_short) {
    return ((host_short & 0xFF) << 8) | ((host_short >> 8) & 0xFF);
}

uint32_t htonl(uint32_t host_long) {
    return ((host_long & 0xFF) << 24) |
           ((host_long & 0xFF00) << 8) |
           ((host_long >> 8) & 0xFF00) |
           ((host_long >> 24) & 0xFF);
}

// 使用示例
uint16_t my_port = 12345;
uint16_t network_port = htons(my_port); // 转换为网络字节序

3. 读取Flash中的常量数据 :

当你在代码中定义 const uint32_t value = 0x12345678; 时,编译器会直接按小端模式将其写入Flash。如果你用烧写工具读取Flash的二进制内容,会看到 78 56 34 12 的排列。

4. 调试时查看内存 :

在调试器(如ST-Link Utility)中查看内存 0x20000000,你会看到:

0x20000000: 78 56 34 12 ...

要知道这实际代表32位值 0x12345678。

四 如何验证你的STM32是小端模式?

用一个简单的程序即可验证:

cs 复制代码
#include <stdint.h>
#include <stdio.h> // 通过串口打印

int main(void) {
    uint32_t test_value = 0x12345678;
    uint8_t *byte_ptr = (uint8_t*)&test_value;
    
    // 打印每个字节的地址和内容
    printf("地址 %p: 0x%02X\n", &byte_ptr[0], byte_ptr[0]);
    printf("地址 %p: 0x%02X\n", &byte_ptr[1], byte_ptr[1]);
    printf("地址 %p: 0x%02X\n", &byte_ptr[2], byte_ptr[2]);
    printf("地址 %p: 0x%02X\n", &byte_ptr[3], byte_ptr[3]);
    
    // 判断
    if(byte_ptr[0] == 0x78 && byte_ptr[3] == 0x12) {
        printf("这是小端模式!\n");
    } else {
        printf("这是大端模式!\n");
    }
    
    return 0;
}

总结:

STM32F103C8T6采用小端模式 是出于效率考虑和ARM生态的统一。在纯单片机编程时,你几乎感觉不到它的存在。但每当你的系统需要与外部世界(网络、其他设备、PC工具)交换原始字节数据时,字节序问题就会凸显,必须谨慎处理。

相关推荐
学长毕设8 小时前
基于SpringBoot的青少年编程学习平台系统-附源码
spring boot·学习·青少年编程
wuyk5559 小时前
防逆向基础:在量产固件中关闭调试接口并设置读保护(RDP)的正确姿势
stm32·单片机·嵌入式硬件·性能优化·重构
小小de风呀12 小时前
de风——【从零开始学习Linux】(九):进程基础 —— 从冯诺依曼体系到 fork 创建进程
linux·学习
李某学编程12 小时前
基于ARM的微机原理学习笔记(一)
arm开发·笔记·学习
zhangrelay13 小时前
单片机原理与接口技术-2026融合版-从MEGA2560-ESP32与Wokwi到ROS2-Lyrical与具身智能栈
单片机·嵌入式硬件
Song_RsHt13 小时前
Redis 与微服务,什么场景下无可替代
java·redis·后端·学习·微服务
sbjdhjd13 小时前
AI产业周度动态:从“更强模型”走向“可执行、可治理、可计价”的系统竞争 (2026年10月19日—10月25日)
人工智能·笔记·ai·开源·gemini·信息差·claude code
lhbweilai14 小时前
分析FreeRTOS内核对象API的源码实现(八)
c语言·开发语言·stm32·单片机
艾络迅Acceleronix14 小时前
环境监测终端:STM32+EG800Z AT+ 艾络迅平台实战|多传感器采集联动全流程
c语言·stm32·单片机·嵌入式硬件·物联网·1024程序员节
涂山苏苏⁠14 小时前
stm32复习总结
stm32·单片机·嵌入式硬件