再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工具)交换原始字节数据时,字节序问题就会凸显,必须谨慎处理。

相关推荐
Chloeis Syntax2 小时前
MySQL初阶学习日记(5)--- 联合查询
java·笔记·学习·mysql
2301_801821712 小时前
两个模型整合问题解决
笔记
思成不止于此2 小时前
【MySQL 零基础入门】DQL 核心语法(三):学生表排序查询与分页查询篇
数据库·笔记·学习·mysql
云山工作室2 小时前
基于物联网的体温心率监测系统设计(论文+源码)
stm32·单片机·嵌入式硬件·物联网·课程设计
猫猫的小茶馆2 小时前
【ARM】VSCode和IAR工程创建
c语言·开发语言·arm开发·ide·vscode·stm32·嵌入式硬件
霍金的微笑2 小时前
三问三[特殊字符]
学习
每次的天空2 小时前
Android车机开发——内存优化操作
android·学习·设计模式
zephyr_zeng2 小时前
CubeMX项目轻松导入Vscode+EIDE编译
c语言·ide·vscode·stm32·mcu·物联网·编辑器
wgego2 小时前
Polar靶场web 随写笔记
笔记·web