嵌入式开发完整教程(零基础→就业,分4大阶段)
嵌入式分两大方向:MCU裸机/RTOS(单片机,入门首选,STM32、ESP32)、嵌入式Linux(ARM Linux,驱动/应用,薪资上限高)。学习原则:软硬结合,必须买开发板实操,只看视频学不会
阶段1:前置基础(1~2个月,必学)
1.1 C语言(嵌入式唯一主力语言,重中之重)
重点不是语法,是指针、结构体、位运算、内存
✅ 核心知识点
- 基础:变量、if/for/while、函数、数组
- 嵌入式核心:指针、指针数组、函数指针、结构体、联合体、枚举
- 位操作:
& | ^ << >>(寄存器配置天天用) - 编译链接:
gcc、Makefile、程序内存分区(栈/堆/全局区)
❌ 不用深挖:C++、STL(Linux QT再学)
📖 推荐资源:B站翁恺C语言;书籍《C Primer Plus》《C和指针》
1.2 硬件基础(看得懂原理图)
- 元件:电阻、电容、二极管、三极管、MOS管、LED、按键
- 电路:高低电平、上拉下拉、I2C/SPI/UART串口原理
- 工具:万用表,看懂最小系统原理图>
不用精通模电数电,能看懂开发板原理图即可
1.3 计算机基础
CPU、总线、内存、中断概念。数据结构只学:链表、队列。
阶段2:MCU单片机开发(裸机 + RTOS,2~3个月,入门就业方向)
推荐硬件:STM32F103C8T6最小系统板(几十元),或者ESP32(带WiFi物联网)
开发工具:Keil MDK + STM32CubeMX(ST官方图形化配置工具,自动生成初始化代码)
2.1 51单片机(快速入门,1周,可选)
学习:GPIO、定时器、串口、中断,做流水灯、按键、温湿度采集。
B站:江协科技(江科大)51教程,通俗易懂。
2.2 STM32裸机开发(核心)
学习顺序:
- 环境搭建:Keil安装、芯片包、CubeMX配置时钟树、引脚
- GPIO:LED点亮、按键输入(第一个项目:流水灯)
- UART串口:串口打印、收发数据(PC和单片机通信)
- 中断:外部中断、定时器中断
- 外设:ADC采集模拟量、I2C(OLED/温湿度传感器)、SPI、DMA
- 项目:OLED屏幕显示 + 温湿度采集 + 按键控制
学习思路:先用HAL库快速写代码,再回头看寄存器,理解底层原理,不要死磕寄存器劝退自己
2.3 RTOS实时操作系统(FreeRTOS,企业高频考点)
单片机上的轻量操作系统,做多任务,物联网产品大量使用
知识点:任务创建、优先级、信号量、消息队列、事件组、软件定时器
实战项目:多任务同时跑【LED闪烁+串口接收+传感器采集】
✅ 本阶段完成后,可以应聘:单片机开发、物联网硬件开发岗位
阶段3:嵌入式Linux开发(进阶,3~4个月,高薪方向)
硬件:IMX6ULL开发板(野火/正点原子)
环境:Windows虚拟机安装 Ubuntu
3.1 Linux基础
- Linux常用命令:
cd ls cp rm mkdir grep chmod tar - Vim编辑器、Shell脚本
- GCC交叉编译工具链(重点:PC编译ARM板子程序)
- Makefile、CMake
3.2 Linux应用开发(不用写驱动,门槛更低)
- 文件IO、进程、线程、信号
- 网络编程:Socket TCP/UDP(MQTT物联网协议)
- 项目:Linux下TCP服务器,开发板和电脑网络通信
3.3 Linux驱动开发(难点,高薪)
- Bootloader(u-boot)、Linux内核编译、根文件系统制作
- 设备树DTS(现代Linux驱动必备)
- 字符设备驱动框架:GPIO、LED驱动
- 平台驱动、中断、I2C/SPI子系统>
示例极简字符设备驱动框架(LED)
#include <linux/module.h>
#include <linux/fs.h>
static int led_open(struct inode *inode, struct file *file)
{
printk("led open\n");
return 0;
}
static struct file_operations fops = {
.open = led_open,
};
static int __init led_init(void)
{
register_chrdev(0,"led",&fops);
return 0;
}
static void __exit led_exit(void)
{
unregister_chrdev(0,"led");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
3.4 进阶扩展(可选)
QT图形界面开发、音视频、Buildroot/Yocto构建文件系统
✅ 本阶段完成:嵌入式Linux驱动工程师、Linux应用工程师
阶段4:综合项目实战(求职必备)
MCU项目(简历可写)
- 基于STM32温湿度采集,OLED显示,串口上传PC
- ESP32物联网:WiFi连接MQTT,手机APP远程控制LED
- FreeRTOS多任务:智能门禁(按键+蜂鸣器+传感器)
Linux项目
- IMX6ULL字符设备驱动:控制LED
- Linux Socket TCP通信,开发板作为客户端上传传感器数据
- QT嵌入式GUI界面
推荐免费学习资源清单
- B站
- 江协科技:51单片机、STM32(新手首选)
- 正点原子、野火:STM32 / Linux全套教程
- 韦东山:嵌入式Linux驱动实战
- 书籍
- 《STM32开发指南》正点原子
- 《嵌入式Linux应用开发完全手册》韦东山
- 《FreeRTOS内核实现与应用开发》
- 文档:乐鑫ESP-IDF官方文档、ST官方参考手册
学习避坑指南(非常重要)
- ❌ 只看视频不买开发板:嵌入式是实操学科,看会 ≠ 会写代码
- ❌ 跳过C语言直接学STM32:指针不懂,寸步难行
- ❌ 一上来就学Linux驱动:难度极高,建议先学好STM32
- ✅ 每学一个外设,必须独立写代码,遇到bug学会用串口/调试器排查
学习路线选择建议
- 想快速就业、物联网产品:C语言 → STM32 → FreeRTOS → ESP32
- 目标Linux驱动、音视频、工业主板:C语言 → STM32打基础 → 嵌入式Linux
如果你需要,我可以:
- 给你一份STM32快速上手,点灯完整工程代码(CubeMX+HAL库)
- 或者整理一份嵌入式面试题库
- 或者单独写《嵌入式Linux驱动入门教程》
STM32 CubeMX + HAL库 点灯完整工程教程
目标芯片:STM32F103C8T6(最常用最小系统板),LED:PA0 推挽输出,高电平点亮
工具:STM32CubeMX 6.x / Keil MDK5
一、CubeMX配置步骤(一步步照着点)
- 打开CubeMX → New Project → 选择
STM32F103C8T6,Start Project - 芯片引脚配置
- 找到
PA0,点击引脚,选择:GPIO_Output - 点击左侧 System Core → GPIO
- PA0 参数设置:
- GPIO mode: Output Push Pull(推挽输出)
- GPIO Pull-up/Pull-down: No pull-up and no pull-down
- Maximum output speed: Low
- User Label:LED(可选,方便识别)
- 找到
- 时钟配置(RCC)
- System Core → RCC → High Speed Clock (HSE):Crystal/Ceramic Resonator(外部8M晶振)
- 切换到 Clock Configuration 标签页
- HSE=8M → PLL倍频到 72MHz(F1最高主频)
- 工程配置(Project Manager)
- Project Name:
LED_Demo - Project Location:选英文路径(不要中文、空格)
- Toolchain/IDE:
MDK-ARM V5 - Code Generator:
✅ Generate initialization code only
✅ Generate peripheral initialization as a pair of '.c/.h' files per peripheral
- Project Name:
- 右上角 GENERATE CODE,生成工程,打开Keil
二、Keil工程代码修改(只需要修改 main.c)
生成的框架代码不用改动,只在
while(1)循环添加点灯逻辑
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* 1. 初始化HAL库、系统时钟、所有外设 */
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
/* 2. 主循环 */
while (1)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // PA0输出高,LED亮
HAL_Delay(500); // 延时500ms
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // PA0输出低,LED灭
HAL_Delay(500); // 延时500ms
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
⚠️ 如果你的LED是低电平点亮(很多最小系统板LED接3.3V,IO拉低导通),把代码改成:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
HAL_Delay(500);
三、GPIO初始化代码(gpio.c,CubeMX自动生成,供参考)
#include "gpio.h"
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 开启GPIOA时钟
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
四、Keil编译+下载要点
- Keil魔术棒 → Target:选择芯片
STM32F103C8 - Debug:选你调试器(ST-Link),勾选 Reset and Run
- 编译:Build,0 Error 0 Warning
- 插入ST-Link,连接开发板:
- ST-Link GND ↔ 开发板GND
- ST-Link SWDIO ↔ PA13
- ST-Link SWCLK ↔ PA14
- Download,下载完成LED周期性闪烁
五、核心HAL库API说明
// 设置引脚电平
HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
// 读取引脚电平
HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
// 翻转引脚电平(推荐,代码更简洁)
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
使用翻转写法简化while循环:
while (1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0);
HAL_Delay(500);
}
六、常见踩坑排查
- 工程路径带中文:CubeMX生成代码报错,Keil无法编译
- 时钟没配置对:
HAL_Delay延时不准 - LED电平逻辑搞反:LED一直常亮/不亮,调换SET/RESET
- ST-Link接线错误:下载失败,检查SWDIO/SWCLK/GND
- 忘记开启GPIO时钟:CubeMX自动开启,手动写寄存器才需要自己开
下一步可选:
- 给这个工程加上外部按键中断,按键控制LED
- 或者加上串口USART,PC串口打印调试信息
- 或者直接讲解寄存器版本点灯,对比HAL库底层