news 2026/9/12 11:03:56

代码如何在单片机中运行?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
代码如何在单片机中运行?

从人类编写的高级语言代码,最终转化为单片机内核能执行的机器指令,并被内核一步步运行的完整链路。这个过程分为两大阶段:编译链接阶段(离线)运行执行阶段(芯片内)

一、 离线阶段:代码→机器指令(编译链接)

这一步在电脑上完成,核心是把你写的C代码转换成芯片内核能识别的二进制指令(机器码),最终生成可烧录的.hex/.bin文件。

步骤1:编写源代码(C语言/汇编)

你编写的代码分为两类,内核最终只认汇编/机器码,C语言是“高级封装”:

// 示例:GPIO输出高电平的C代码#include"stm32f10x.h"intmain(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);GPIO_SetBits(GPIOA,GPIO_Pin_0);while(1);}
步骤2:预处理(Preprocessing)

编译器(如ARM-GCC)先处理代码中的#include#define等预处理指令:

  • #include "stm32f10x.h"替换为头文件里的寄存器定义、宏定义;
  • 展开#define宏,删除注释,最终生成纯C代码(无预处理指令)。
步骤3:编译(Compilation)

将预处理后的C代码转换成汇编代码,再把汇编代码转换成机器指令(二进制),生成.o目标文件:

  • 核心:把GPIO_SetBits等函数,翻译成内核能识别的Thumb-2指令(如STR(存储)、LDR(加载)、MOV(赋值)等);
  • 例:GPIO_SetBits最终会被编译成操作GPIOA_BSRR寄存器的机器指令:STR r1, [r0, #0x10](将r1的值写入r0+0x10地址,即BSRR寄存器)。
步骤4:链接(Linking)

链接器将所有.o文件(用户代码+标准库+启动文件)合并,并根据STM32的内存映射(如Flash起始地址0x08000000、SRAM起始地址0x20000000)分配地址,生成.elf可执行文件:

  • 关键:启动文件(startup_stm32f10x_md.s)是链接的核心,包含内核启动时的初始化逻辑(如栈初始化、中断向量表定义);
  • 中断向量表:将main函数、中断服务函数的地址映射到固定位置,内核复位后从向量表第一条指令开始执行。
步骤5:格式转换(生成烧录文件)

通过objcopy工具将.elf文件转换成烧录工具能识别的.hex/.bin文件:

  • .bin:纯二进制机器码,直接对应Flash地址;
  • .hex:带地址信息的文本格式,适合烧录工具解析。

二、 芯片内阶段:机器指令→内核执行

烧录工具将.hex/.bin文件写入STM32的Flash后,复位芯片,内核开始执行指令,核心流程如下:

步骤1:内核复位(Reset)

芯片上电/复位后,内核首先读取中断向量表的第0项(栈顶地址),将栈顶地址加载到MSP(主栈指针),完成栈初始化;
接着读取向量表第1项(复位中断服务函数地址),跳转到该地址执行。

步骤2:启动文件执行(汇编级初始化)

复位中断服务函数指向启动文件的Reset_Handler,完成核心初始化:

  1. 初始化.data段(将Flash中的初始化数据复制到SRAM);
  2. 清零.bss段(未初始化的全局变量置0);
  3. 调用SystemInit()函数:配置时钟系统(如将SYSCLK设为72MHz);
  4. 跳转到main函数,内核开始执行你的业务代码。
步骤3:内核执行main函数(指令流水线)

Cortex-M3内核采用三级流水线(取指→译码→执行),并行处理指令,提升效率:

  1. 取指:内核通过ICode总线从Flash中读取机器指令(如0x2001);
  2. 译码:将机器指令翻译成内核能执行的操作(如“将立即数1写入寄存器r0”);
  3. 执行:内核操作寄存器/总线,完成具体功能(如向GPIOA_BSRR寄存器写值,控制引脚电平)。
步骤4:指令执行的核心逻辑(与硬件交互)

内核执行指令时,通过总线与外设/存储器交互,例:

  • 执行RCC_APB2PeriphClockCmd:内核通过APB2总线向RCC_APB2ENR寄存器写值,开启GPIOA时钟;
  • 执行GPIO_SetBits:内核通过APB2总线向GPIOA_BSRR寄存器写值,触发硬件电路输出高电平;
  • 执行while(1):内核循环执行“空指令”,停留在该位置。
步骤5:中断/异常处理(内核的实时响应)

若外设触发中断(如UART接收完成):

  1. 内核暂停当前指令执行,保存现场(寄存器值入栈);
  2. 读取中断向量表中对应中断的服务函数地址,跳转到中断服务函数执行;
  3. 执行完成后,恢复现场(寄存器值出栈),继续执行之前暂停的指令。

三、 关键节点总结(代码→内核执行的核心链路)

编写C代码

预处理:展开头文件/宏

编译:C→汇编→机器指令(.o)

链接:合并.o+分配地址(.elf)

格式转换:生成.hex/.bin

烧录到STM32 Flash

芯片复位:内核加载栈顶+复位向量

启动文件:初始化内存/时钟

内核执行main函数(取指→译码→执行)

内核通过总线操作外设寄存器

总结

  1. 代码到内核执行的核心是**“高级语言→机器指令→硬件操作”** 的转换,编译链接是“翻译”过程,内核流水线是“执行”过程;
  2. 启动文件是连接内核初始化和main函数的关键,负责内存、时钟的基础配置;
  3. 内核执行指令的本质是通过总线读写寄存器,最终触发硬件电路完成功能。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 2:15:55

科研写作新范式:书匠策AI如何重塑期刊论文创作生态?

在学术研究的赛道上,期刊论文的撰写始终是研究者必须跨越的“技术门槛”。从浩如烟海的文献中梳理研究脉络,到构建逻辑严密的论证体系,再到应对不同期刊的格式要求,每一步都考验着研究者的耐心与智慧。而书匠策AI科研工具的出现&a…

作者头像 李华
网站建设 2026/9/12 2:23:20

如何利用GPT-SoVITS提升智能客服语音体验?

如何利用GPT-SoVITS提升智能客服语音体验? 在客户体验日益成为企业竞争核心的今天,一个“听得懂、答得准、说得像人”的智能客服系统,早已不再是锦上添花的功能,而是服务链条中不可或缺的一环。然而,当我们点开某电商平…

作者头像 李华
网站建设 2026/9/10 4:10:14

从新手到高手:Klipper固件全功能实战指南

还在为3D打印的精度问题烦恼吗?打印模型表面总是出现波纹?换料操作繁琐耗时?别担心,Klipper固件正是为你量身打造的解决方案!通过本文,你将掌握从基础配置到高级优化的完整技能链,彻底告别打印困…

作者头像 李华
网站建设 2026/9/12 0:20:39

java springboot基于微信小程序的餐厅食堂预约点餐系统(源码+文档+运行视频+讲解视频)

文章目录 系列文章目录目的前言一、详细视频演示二、项目部分实现截图三、技术栈 后端框架springboot前端框架vue持久层框架MyBaitsPlus微信小程序介绍系统测试 四、代码参考 源码获取 目的 摘要:传统餐厅食堂就餐常面临排队时间长、点餐效率低等问题,…

作者头像 李华
网站建设 2026/9/3 8:27:58

Open-AutoGLM沉思版地址难求,1小时快速部署方案全网首发

第一章:Open-AutoGLM沉思版地址难求的现状与挑战在当前开源大模型生态快速发展的背景下,Open-AutoGLM沉思版作为一款聚焦于逻辑推理与深度思考能力优化的语言模型,其实际可访问性却面临严峻挑战。尽管项目在技术理念和架构设计上具备前瞻性&a…

作者头像 李华
网站建设 2026/9/2 14:15:59

终极指南:5步搭建专属Pokemon多人在线游戏世界

想要创建属于自己的Pokemon多人在线游戏吗?PokeMMO引擎正是你需要的工具!这款基于Web技术的开源项目让你能够轻松构建功能丰富的Pokemon游戏世界,支持实时编辑和多人联机功能。无论你是游戏开发新手还是经验丰富的开发者,都能快速…

作者头像 李华