嵌入式到机器人开发一(硬件编)
本文档是记录嵌入式到机器人开发技术编,为便记录如何从电子电路到自己开发一个机器人的流程,
第一部份
嵌入式基础
什么是嵌入式,就是将软件硬件嵌入到一个微型控制中,嵌入嘛,就是将软件硬 件全嵌入在一块小块子中,我们的台式机和笔记本呢,他们软件是可以自由安装的,但是嵌入的发展也会功能越来越强,走到ai ,所以可能以后会糊模定义,
目前特点:
- 固化在设备里、不能随便拆
- 功能固定:只做控制、显示、采集、联网
- 体积小、低成本、省电、专用系统
- 如:平板、电视、盒子、投影仪、音箱、手环手表智能设备,智能门锁、门禁、烟雾报警器、温湿度传感器、PLC、工业触摸屏、变频器、伺服驱动器、工业网关、
- 数据采集器、机床控制器。全是嵌入式。
按算力类型业区别,可能有精简功能的stm32 连网方便的 esp32 算力并发的gpu类型的jetson nano rk系统 还有支持实时,高并发的比如华为的路由 , 基站 ,
开发前必烦知道的理伦
我们开发嵌入式,实际就是操作gpio引脚 ,但是引脚的通信需要通信的频率,需要晶振,晶振就是时钟,比如说多少时间内发出脉冲,都 要需要配置的,还是配置高电平通信还是低电平通信,在距离较远的电路中,电路会衰减,本应高电平的可能都 不高了,所以通信有很多方式,最直接就是一会高电平,一下低电平来代表01 但是可能是受电压响,复杂的要用来传数据的 ,用其它方式,比如差分信号,就是一根高电平,一根低电,用有没有差别来表示0.1 所以嵌入式的通信才为为很多种 ,对于更复杂的需要配置的,我们还用at 配置信息,然后在信号中每次带上配置信号,来完成加密。
还有最后一个就是变量,为了开发方便,核心板产商开发编程工个。,,在里面对一个固定的gpio 串口,很多硬 件都 命 了名,我们直接拿来用,所以与代码时不需要问,这些变量那儿来的,专业术语叫 向量表
引脚功能:
GPIO_MODE_INPUT 浮空输入: 引脚电平完全由外部决定,悬空时电平乱跳。用于按键、传感器、外部信号输入。 GPIO_MODE_OUTPUT_PP 推挽输出: 能直接输出强高低电平,驱动能力强。用于LED、蜂鸣器、继电器、普通控制。 GPIO_MODE_OUTPUT_OD 开漏输出: 只能拉低电平,高电平要靠外部上拉,可多芯片共用总线。用于I2C、1-Wire、电平转换。 GPIO_MODE_AF_PP 复用推挽: 给串口、PWM、SPI等外设用,强驱动输出。用于串口TX、PWM输出、SPI时钟。 GPIO_MODE_AF_OD 复用开漏: 给外设开漏用,只能拉低,需上拉。用于硬件I2C的SDA/SCL。 GPIO_MODE_AF_INPUT 复用输入: 给外设专用输入口。用于串口RX、SPI输入、定时器捕获。 GPIO_MODE_ANALOG 模拟模式: 只测电压,不走数字信号。用于ADC采样、模拟信号输入。
1. 什么是 MSP?
它的核心工作,就是给单片机的各种外设(比如串口、定时器、GPIO、中断这些)做最基础的初始化:
- 给外设开时钟(相当于给外设通电,不通电外设没法干活)
- 配置外设用到的 GPIO 引脚(比如串口要用到 TX/RX 两个引脚,得先把这俩脚设成串口模式)
- 配置外设相关的中断(比如串口接收数据要触发中断,得先把中断打开、设好优先级)
举个例子:你要用串口(USART)发数据,HAL 库会先自动调用串口的 MSP 函数,把串口的时钟、引脚、中断都配置好,再执行发数据的功能,不用你手动去管这些底层操作。
2. MSP 的调用逻辑
- 程序从
main()函数开始运行 - 先执行
HAL_Init(),初始化 HAL 库的基础环境 - 自动调用
HAL_MspInit(),这就是全局的 MSP 初始化入口 - 后续你初始化某个具体外设(比如串口、SPI)时,HAL 库会自动调用对应外设的 MSP 函数,完成该外设的底层配置
编写第一个示例,点亮一个灯,首先打开stmcubeMx 选中芯片型号 ,选择我们当下用的是gpio8,和9 开发板是立创星空学习板

需要用stmcubeMx 创立工程, 选中型号 然后配置引脚 gpio 8 gpio 9 ,因为我们要做点亮灯,默认要高电平,所以要配置为高电平 ,推换推出,由于是输出,下上拉无意义,这儿不用管, 如果设低电平,默认灯就亮了,好像也不是不行,这儿其实任意哈,,,
关于stmcubeMx 要下载6.14.1,老版有很多坑,传说6.15也有乱码的坑,所以还是选6.14.1 老版本的坑比如中文乱码问题 ,配置的时钟与实际硬件运行频率不一致(差一半、翻倍),如果用低本遇到需要解决中文乱码可以先增加一个环境变量,
选择新建,在变量名和变量值如下如下内容 变量名称: JAVA_TOOL_OPTIONS 变量值:-Dfile.ecoding=UTF-8 修改完成后,全部点确定。然后重启stm32CubeMX软件即可。
配置好工程后,可以用kial 或vscode 找开项目,在maian.c 写引脚 代码,完成第一个示例
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); // led1 熄灭
HAL_Delay(500); // 延时500ms
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); // led1 点亮
HAL_Delay(500); // 延时500ms
}
/* U
这儿我们可以看到软件工作文件目录,需要介绍一下, stm32f1xx.it 是中断函数的编写地方,
stm32f1xx.hal.map.c 是核心底层配置的地方,stm32f1xx_hal_msp.c。 是 STM32CubeMX 自动生成, MSP = MCU Support Package,MCU 底层支撑配置
专门存放所有外设的底层硬件初始化:比如以下配置
- 开启外设时钟(GPIO、UART、ADC、TIM 等)
- 配置引脚复用功能
- 配置 NVIC 中断
- 配置 DMA(如果用到)
所有
HAL_XXX_MspInit()统一放在这里。以下这个文件的代码片断,可能总结为main.c 虽然也有配置,他是基于这个文件的配置,这个文件才是操作硬 件的配置
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
__HAL_RCC_USART1_CLK_ENABLE(); // 开时钟
// 配置GPIO、NVIC等
}
其它文件的分布,如下,

常见方法介绍:
main.c 文件中常用方法介绍:
HAL_Init() 初始化项目和初始化hal 库 ,项目第一句代码,不要在HAL_Init()之前调用任何外设相关的代码,否则会出奇怪的 bug。
SystemClock_Config() 配置时钟,CubeMX 生成的工程里,这个函数会自动写好,一般不用自己改。时钟 没 配置对,外设波特率、定时器、延时都会出错。
MX_GPIO_Init() 这个函数是 CubeMX 生成的,里面会调用HAL_GPIO_Init()。帮你一次性配置好所有引脚的输入 / 输出模式、上下拉电阻、速度等。不要在这个函数里手动写引脚操作代码, 否则重新生成工程会被覆盖。
HAL_GPIO_WritePin() 控制 GPIO 引脚输出高 / 低电平。给引脚 “发信号”,比如让 LED 亮 / 灭、给模块发指令。
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // PA5输出高电平 参数介绍,第一个参数,那一组引脚 ,第二个参数,这组引脚中那个编号 第三个参数,高还是低电平
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // PA5输出低电平
HAL_Delay() 毫秒级延时函数,让程序 “等一会儿再往下走” 这个延时是阻塞的,延时期间程序什么都做不了,游戏里用多了会卡顿。高优先级中断会打断延时,导致实际延时时间变长。
HAL_Delay_Us()(或自定义微秒延时) 功能同上,只是时间不同
其它以后才用到的函数
HAL_GPIO_ReadPin() 读取 GPIO 引脚的电平状态,判断按键是否按下。
HAL_GPIO_TogglePin() 翻转 GPIO 引脚的电平状态(高变低、低变高)。
HAL_TIM_Base_Start() / HAL_TIM_Base_Start_IT() 启动定时器,用来做定时任务、PWM、游戏帧率控制。
HAL_TIM_PWM_Start() 启动定时器的 PWM 输出,用来驱动蜂鸣器、电机、LED 呼吸灯。
在正式写代码前,先了解一下软件环境 ,比如中文支持,界面样式,在kail5 的 edit 有一个 Configuration菜单,里面有软件相关配置

编译流程:
我们在写代码的时候,有部份代码是给编译器看的,比如以下的注解:

一个完成的功能包装封,包括功能封装,示例 我们要点灯,并且要把功能封装成来。
第一步,核心代码是
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // PA5输出高电平 参数介绍,第一个参数,那一组引脚 ,第二个参数,这组引脚中那个编号 第三个参数,高还是低电平 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // PA5输出低电平
封装:
我们们gpio.c 写函数本身 在gpio.h 需要爆露出宏定义和函数名,方便主函数据调用
gpio.c 新增二个函数功能代码,一个是功能函数,一个是测试函数
void LED_Control(uint8_t device, uint8_t cmd) { GPIO_PinState state = cmd ? GPIO_PIN_RESET : GPIO_PIN_SET; if(device == LED1) HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, state); else if(device == LED2) HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, state); }
测试函数:
void LED_Test(void) { LED_Control(LED1,ON); LED_Control(LED2,OFF); HAL_Delay(500); LED_Control(LED1,OFF); LED_Control(LED2,ON); HAL_Delay(500); }
载图如下 :

其它写法参考:
void LED_Control(uint8_t device, uint8_t cmd)
{
switch(device)
{
case LED1: HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, cmd ? 0 : 1); break;
case LED2: HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, cmd ? 0 : 1); break;
}
}
最后主函数调用:

以下功能通常 蜂鸣器 接触器 开发都是一样,通过调节电平来控制,所以基础控制电位的的功能先不介结了,以下开始研究按健扫描
中断模式
要使中断的话,意思是事件,比如我们要绑定在gpio 让这个按扭中低变平或高电平发生时,运行一个函数就叫中断,中断还可以帮在定时器到点,按健被 按下等场
核心点中断
第一在stm32cubeMx中 将一下gpio绑定于引脚 为中断模式

然后在gpio 的配置中配置一下什么条件触发

还差一步,使其使能,这一步完成后就可以ai 可以写代码了
EXTI line[9:5] interrupts:对应 GPIO 引脚 5~9 的外部中断(共用一个中断服务函数)EXTI line[15:10] interrupts:对应 GPIO 引脚 10~15 的外部中断(共用一个中断服务函数)STM32F103 把多个 EXTI 线合并到同一个中断向量,比如 EXTI5~9 共享EXTI9_5_IRQHandler,EXTI10~15 共享EXTI15_10_IRQHandler,这就是这里配置的本质。

- 第一步将对应的 GPIO 引脚(比如 PB5、PC13 这类)配置成了外部中断模式,并设置了触发方式(上升 / 下降沿 / 双边沿)。这样的话,当这个事件发生时会产生中断,其实就是对方的中断函数会运行
- 还得配置中断优化,告诉内核 “这些中断我要用,优先级设为最高”,让 MCU 收到引脚电平变化时,能正确响应并跳转到对应的中断服务函数里执行你的代码。不能在延时器中配中断,好像好出问题 ,除非中断的时序较高
- 后续你需要在 HAL 库中,用
HAL_GPIO_EXTI_Callback()回调函数来写中断触发后的处理逻辑,还要清除中断标志位,不可我们用ai 写代码可以让ai 来写,至此中断就这点东西。嵌入式会了中断,时钟,通信,入门的话差不多就可以学其它的了,因为更高级的东西,直接上框架吧,先做出产品,再来优化细节,如是想要做好产品,肯定要自己会写寄存器,才能优化性能,但是作为新手我们做图做出成品, 下一章,我们直接开始通信
000000000000000000000

浙公网安备 33010602011771号