当前位置: 首页 > news >正文

嵌入式学习笔记——大小端及跳转到绝对地址

大小端以及跳转到绝对地址 0x100000

    • 嵌入式编程中的大小端详解
      • 一、大端模式与小端模式
      • 二、判断当前系统是大端还是小端
        • 方法一:指针强制类型转换
        • 方法二:使用联合体(union)
      • 三、结构体位段和大小端的影响
      • 四、大小端影响内存的 memcpy 拷贝效果
      • 五、大小端转换函数
      • 六、总结
    • 跳转到绝对地址 0x100000 的原理与实现
      • 一、为何需要跳转?
      • 二、跳转原理
      • 三、代码实现
      • 四、简化写法
      • 五、Flash 分区结构示意图
      • 六、注意事项
      • 七、小结

嵌入式编程中的大小端详解

在嵌入式编程中,理解大小端是非常重要的,它直接关系到数据在内存中的布局和跨平台通信时的数据解析正确性。


一、大端模式与小端模式

大端模式(Big Endian):高字节存在低地址,低字节存在高地址。
小端模式(Little Endian):低字节存在低地址,高字节存在高地址。

例如:

unsigned int temp = 0x12345678;

假设 temp 的地址是 0x20000010,那么:

  • 大端模式 中,内存排列为:

    • 0x20000010:0x12
    • 0x20000011:0x34
    • 0x20000012:0x56
    • 0x20000013:0x78
  • 小端模式(STM32) 中,内存排列为:

    • 0x20000010:0x78
    • 0x20000011:0x56
    • 0x20000012:0x34
    • 0x20000013:0x12

二、判断当前系统是大端还是小端

方法一:指针强制类型转换
#include <stdio.h>

int main() {
    int num = 1;                          // 定义整型变量 num,值为1
    char *ptr = (char *)&num;             // 强制转换为字符型指针,查看最低地址的字节内容

    if (*ptr == 1) {
        printf("小端模式\n");
    } else {
        printf("大端模式\n");
    }
    return 0;
}
方法二:使用联合体(union)
#include <stdio.h>

union endian_check {
    int num;
    char single_byte;                     // 访问低地址的单字节
};

int main() {
    union endian_check check;
    check.num = 1;                        // 赋值为1(0x00000001)

    if (check.single_byte == 1) {
        printf("小端模式\n");
    } else {
        printf("大端模式\n");
    }
    return 0;
}

三、结构体位段和大小端的影响

#include <stdio.h>

struct mybitfields {
    unsigned short a : 4;     // 4位位段
    unsigned short b : 5;     // 5位位段
    unsigned short c : 7;     // 7位位段
} test;

int main() {
    int i;
    test.a = 2;               // 二进制 0010
    test.b = 3;               // 二进制 00011
    test.c = 0;               // 二进制 0000000

    i = *((short *)&test);   // 强制转换结构体地址为 short* 后解引用
    printf("%d\n", i);        // 输出为50,实际内存内容:0010 00011 0000000 => 0x32
    return 0;
}

四、大小端影响内存的 memcpy 拷贝效果

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main() {
    unsigned int uiVal_1 = 0x12345678;             // 原始整型变量
    unsigned int uiVal_2 = 0;                      // 存储从字节数组拷贝后的数据
    unsigned char aucVal[4] = {0x12, 0x34, 0x56, 0x78};  // 定义字节数组

    unsigned short usVal_1 = 0;
    unsigned short usVal_2 = 0;

    memcpy(&uiVal_2, aucVal, sizeof(uiVal_2));     // 把数组内容复制到uiVal_2中

    usVal_1 = (unsigned short)uiVal_1;              // 截断低16位 => 0x5678
    usVal_2 = (unsigned short)uiVal_2;              // 拷贝后低16位 => 0x3412 (小端存储顺序)

    printf("usVal_1: %x\n", usVal_1);               // 输出截断值
    printf("usVal_2: %x\n", usVal_2);               // 输出截断值

    return 0;
}

五、大小端转换函数

// 32位整数转换
int swapInt32(int intValue) {
    int temp = 0;
    temp = ((intValue & 0x000000FF) << 24) |
           ((intValue & 0x0000FF00) << 8)  |
           ((intValue & 0x00FF0000) >> 8)  |
           ((intValue & 0xFF000000) >> 24);
    return temp;
}

// 16位短整型转换
unsigned short swapShort16(unsigned short shortValue) {
    return ((shortValue & 0x00FF) << 8) | ((shortValue & 0xFF00) >> 8);
}

// 32位浮点数转换(使用联合体)
float swapFloat32(float floatValue) {
    typedef union {
        float unionFloat;
        int unionInt;
    } SWAP_UNION;

    SWAP_UNION swapUnion;
    swapUnion.unionFloat = floatValue;
    swapUnion.unionInt = swapInt32(swapUnion.unionInt);
    return swapUnion.unionFloat;
}

// 64位双精度浮点数转换(使用指针反转)
void swapDouble64(unsigned char *pIn, unsigned char *pOut) {
    for (int i = 0; i < 8; i++) {
        pOut[7 - i] = pIn[i];     // 将输入按字节反转存入输出
    }
}

int main() {
    int x = 0x12345678;
    int y = swapInt32(x);         // 调用函数转换大小端
    printf("%x\r\n", y);           // 输出结果应为 0x78563412
    return 0;
}

六、总结

  • STM32 采用小端模式。
  • 小端:低位字节存在低地址;大端:高位字节存在低地址。
  • 判断大小端可使用指针、联合体等方法。
  • 位段的使用也会受到大小端的影响。
  • 在多平台数据交换时,必须进行大小端转换,确保数据一致性。

跳转到绝对地址 0x100000 的原理与实现

在嵌入式开发中,程序往往被分布在 Flash 的不同区域。例如,在采用 Bootloader + 主程序(APP)结构的设计中,Bootloader 启动后会跳转到主程序所在的地址开始执行。这种“跳转”就是我们常说的“跳转到绝对地址执行”,下面我们详细介绍其原理与实现方法。


一、为何需要跳转?

常见应用场景包括:

  • Bootloader 启动后跳转到主应用程序执行
  • 多镜像升级系统(A/B 双系统)
  • 不同 Flash 区域运行不同的功能模块

例如,如果主程序被烧录在 Flash 的地址 0x100000(假设起始地址),那么 Bootloader 启动后就需要跳转到这个地址运行主程序。


二、跳转原理

Cortex-M 内核芯片(如 STM32)启动时,会自动读取启动地址前 8 字节:

  • 第 1 个字(偏移 0):主堆栈指针初始值(MSP)
  • 第 2 个字(偏移 4):程序入口地址(Reset_Handler)

因此,跳转前必须:

  1. 设置新的 MSP 值为 *(uint32_t*)0x100000
  2. 设置跳转地址为 *(uint32_t*)(0x100000 + 4) 并执行

三、代码实现

推荐使用 typedef 简化函数指针写法:

#include <stdint.h>

#define APP_ADDRESS 0x100000  // 目标程序地址

typedef void (*pFunction)(void);  // 定义函数指针类型

void jump_to_app(void) {
    __disable_irq();  // 关闭中断,避免干扰

    uint32_t jump_address = *(volatile uint32_t*)(APP_ADDRESS + 4); // 程序入口地址
    pFunction JumpToApplication = (pFunction)jump_address;  // 转换成函数指针

    __set_MSP(*(volatile uint32_t*)APP_ADDRESS);  // 设置主堆栈指针(MSP)

    JumpToApplication();  // 跳转执行目标程序
}

上述代码完成了从 Bootloader 跳转到主程序的过程。


四、简化写法

((void (*)())0x100000)();  // 将地址当作函数指针并执行

虽然简洁,但不推荐用于 STM32,因为没有设置 MSP主堆栈指针,容易导致系统异常。


五、Flash 分区结构示意图

+------------------------+
| 地址 0x08000000       | → Bootloader
+------------------------+
| 地址 0x08010000       | → APP 主程序(即 0x100000)
+------------------------+
| ......                |

注:部分 STM32 芯片 Flash 起始地址是 0x08000000,此处 0x100000 视具体芯片配置而定。


六、注意事项

  • 跳转地址处必须是有效程序,并具备正确的中断向量表
  • 必须先设置 MSP,否则可能因栈指针错误导致 HardFault
  • 跳转前应关闭中断,避免中断未关闭造成干扰
  • 若使用 FreeRTOS 等 RTOS,需要考虑中断向量重定向问题

七、小结

项目说明
跳转地址比如 0x100000,主程序存放起点
MSP 设置必须从地址读取并设置 __set_MSP()
入口地址*(uint32_t*)(addr + 4)
函数指针跳转把地址强转为函数指针并调用

相关文章:

  • labelme json 标签转yolo txt【记录】
  • 在Spring Boot中实现图片上传和修改
  • STM32看门狗原理与应用详解:独立看门狗 vs 窗口看门狗(上) | 零基础入门STM32第九十四步
  • 设计模式:为什么使用模板设计模式(不相同的步骤进行抽取,使用不同的子类实现)减少重复代码,让代码更好维护。
  • C++语言的网络编程
  • 第一章:服务架构演进史_《凤凰架构:构建可靠的大型分布式系统》_Notes
  • 英文单词记忆系统:基于PyQt5与DeepSeek大模型的智能学习工具
  • UDP学习笔记(四)UDP 为什么大小不能超过 64KB?
  • 高级:性能优化面试题深度剖析
  • Node.js局部生效的中间件
  • pyTorch框架-迁移学习-实现四种天气图片多分类问题
  • 【Windows批处理】命令入门详解
  • Rust 2024介绍 | 开发环境搭建详细教程(rust 1.85.0)
  • 《Glance:一站式聚合信息,告别浏览器切换烦恼》
  • 国产芯片解析:龙讯USB Type-C/DP Transmitter多场景覆盖,定义高速互联新标杆
  • 21.OpenCV获取图像轮廓信息
  • 【js逆向】某日番动漫网视频地址解密
  • 车辆监控平台技术标准解析
  • Bert论文解析
  • 2019 CCF CSP-S2.树的重心
  • 外贸是做什么的学什么专业/南宁seo内部优化
  • 建设网站培训班/网络搜索关键词排名
  • 郑州新感觉会所网站哪里做的/360优化大师官方网站
  • 抖音小程序开发工具/湖南百度seo
  • 备案网站/北京网站优化seo
  • 专业模板网站制作多少钱/专业网络推广公司