一个人也能做的嵌入式毕设项目推荐,附思路和代码
一个人也能做的嵌入式毕设项目推荐,附思路和代码
毕设选题这件事,两个极端都不好:选太难的,一个人做不完;选太简单的,老师一看就知道你在凑数。
嵌入式方向,理想的毕设项目应该是:硬件+软件都有,有一个完整可演示的功能,代码有一定技术含量,但复杂度在一个人三四个月内能完成的范围里。
下面推荐5个项目,按难度从低到高排列,每个都给关键思路和核心代码片段。
项目一:基于STM32的多参数环境监测系统(难度:★★☆)
适合谁:嵌入式入门阶段,C语言扎实,用过STM32基本外设。
功能描述:
- 采集温湿度(SHT30)、CO₂浓度(MH-Z19B)、光照强度(BH1750)
- 数据显示在OLED屏幕上,超阈值触发蜂鸣器报警
- 串口输出数据,可通过PC上位机实时查看曲线
- 按键可以设置报警阈值,参数保存到Flash
技术含量亮点(给老师的加分点):
- 多传感器统一管理,用统一的驱动接口框架
- 参数持久化(掉电不丢失配置)
- 上位机通信协议自定义(不是简单的串口打印,是有帧头帧尾校验的协议)
核心代码片段——传感器统一管理框架:
// 定义统一的传感器接口(工厂模式思路)
typedef struct {
const char* name;
void (*Init)(void);
uint8_t (*ReadData)(float* value);
float last_value;
float alarm_threshold;
uint8_t alarm_enabled;
} SensorHandle_t;
// 各传感器实现各自的Init和ReadData
uint8_t SHT30_Read(float* value)
{
uint8_t data[6];
// 发送测量命令
I2C_Write(SHT30_ADDR, 0x2C, 0x06);
HAL_Delay(20);
// 读取结果
I2C_Read(SHT30_ADDR, data, 6);
// 换算(SHT30标准换算公式)
uint16_t raw_temp = (data[0] << 8) | data[1];
*value = -45.0f + 175.0f * (float)raw_temp / 65535.0f;
return 1;
}
// 注册所有传感器
SensorHandle_t sensors[] = {
{"Temperature", SHT30_Init, SHT30_Read, 0, 35.0f, 1},
{"CO2", MHZ19_Init, MHZ19_Read, 0, 1000, 1},
{"Light", BH1750_Init, BH1750_Read, 0, 200, 0},
};
#define SENSOR_COUNT (sizeof(sensors)/sizeof(SensorHandle_t))
// 主循环里统一处理
void Main_Loop(void)
{
for (int i = 0; i < SENSOR_COUNT; i++) {
float value;
if (sensors[i].ReadData(&value)) {
sensors[i].last_value = value;
// 检查报警
if (sensors[i].alarm_enabled &&
value > sensors[i].alarm_threshold) {
Buzzer_Alert(sensors[i].name);
}
}
}
Display_Update(sensors, SENSOR_COUNT);
}
通信协议设计(让老师觉得你认真的部分):
// 自定义串口帧格式
// 帧头(2B) | 帧类型(1B) | 数据长度(1B) | 数据(nB) | CRC16(2B) | 帧尾(2B)
// 0xAA 0x55 | TYPE | LEN | DATA | CRC_L CRC_H | 0x0D 0x0A
typedef struct {
uint8_t frame_type;
uint8_t data_len;
uint8_t data[32];
} TxFrame_t;
void Send_SensorData(SensorHandle_t* sensors, uint8_t count)
{
TxFrame_t frame;
frame.frame_type = 0x01; // 传感器数据帧
frame.data_len = count * 4; // 每个传感器4字节float
for (int i = 0; i < count; i++) {
memcpy(&frame.data[i*4], &sensors[i].last_value, 4);
}
Protocol_Send(&frame); // 加帧头帧尾和CRC后发送
}
论文写作建议:重点写传感器驱动框架设计(可以画UML类图)、通信协议设计(画帧格式图)、上位机软件(Python + pyserial + matplotlib,画实时曲线)。
项目二:基于FreeRTOS的智能家居控制器(难度:★★★)
适合谁:学过RTOS,想展示多任务编程能力。
功能描述:
- 控制多路继电器(灯、风扇、窗帘模拟)
- 温湿度传感器实现恒温控制
- 支持手机App通过蓝牙(HC-05或BLE模块)远程控制
- 有本地按键和OLED界面
- 支持定时任务(比如"每天早上8点开灯")
RTOS任务划分(这是给老师展示系统设计能力的核心):
// 任务划分和优先级设计
// 优先级越高数字越大(FreeRTOS规则)
// 传感器采集任务(中优先级,每500ms采集一次)
void Task_SensorRead(void* pvParam)
{
TickType_t last_wake = xTaskGetTickCount();
while (1) {
SensorData_t data;
data.temperature = SHT30_ReadTemp();
data.humidity = SHT30_ReadHumi();
// 把数据发到队列,控制任务从队列取
xQueueSend(sensor_queue, &data, pdMS_TO_TICKS(10));
vTaskDelayUntil(&last_wake, pdMS_TO_TICKS(500));
}
}
// 控制任务(中高优先级)
void Task_Control(void* pvParam)
{
SensorData_t data;
while (1) {
// 等待新的传感器数据
if (xQueueReceive(sensor_queue, &data, pdMS_TO_TICKS(1000)) == pdTRUE) {
// 恒温控制逻辑
if (data.temperature > target_temp + 0.5f) {
Relay_Set(RELAY_FAN, ON);
} else if (data.temperature < target_temp - 0.5f) {
Relay_Set(RELAY_FAN, OFF);
}
}
}
}
// 蓝牙通信任务(低优先级)
void Task_Bluetooth(void* pvParam)
{
uint8_t cmd_buf[32];
while (1) {
// 等待蓝牙数据(阻塞等待,不占CPU)
if (BT_Receive(cmd_buf, sizeof(cmd_buf), pdMS_TO_TICKS(100))) {
BT_ParseCommand(cmd_buf);
}
// 周期性推送状态给手机
static TickType_t last_push = 0;
if (xTaskGetTickCount() - last_push > pdMS_TO_TICKS(2000)) {
BT_PushStatus();
last_push = xTaskGetTickCount();
}
}
}
// 定时任务(低优先级)
void Task_Scheduler(void* pvParam)
{
while (1) {
RTC_Time_t now;
RTC_GetTime(&now);
// 检查所有定时任务
Schedule_Check(&now);
vTaskDelay(pdMS_TO_TICKS(1000)); // 每秒检查一次
}
}
// 主函数里创建任务
int main(void)
{
// 硬件初始化...
// 创建任务间通信的队列
sensor_queue = xQueueCreate(5, sizeof(SensorData_t));
command_queue = xQueueCreate(10, sizeof(Command_t));
// 创建任务
xTaskCreate(Task_SensorRead, "Sensor", 256, NULL, 3, NULL);
xTaskCreate(Task_Control, "Control", 256, NULL, 4, NULL);
xTaskCreate(Task_Bluetooth, "BT", 512, NULL, 2, NULL);
xTaskCreate(Task_Scheduler, "Sched", 256, NULL, 1, NULL);
vTaskStartScheduler(); // 启动调度器
}
论文亮点:
- 任务划分的依据(实时性要求、资源占用)
- 任务间通信设计(队列而不是全局变量)
- 优先级反转问题和解决方案(引出Mutex的使用)
项目三:基于STM32的无刷电机控制器(难度:★★★★)
适合谁:数学基础较好,对电机控制感兴趣,想在简历上有含金量高的项目。
功能描述:
- 三相无刷电机(BLDC)的梯形波驱动(入门)
- 霍尔传感器换相
- 转速闭环PID控制
- 串口设置目标转速,显示实时转速和电流
核心技术点——六步换相逻辑:
// 霍尔传感器读值 → 换相表 → 驱动信号
// 霍尔传感器三个信号H1H2H3有6种有效状态
typedef struct {
uint8_t AH, AL; // A相上下桥
uint8_t BH, BL; // B相上下桥
uint8_t CH, CL; // C相上下桥
} CommutationStep_t;
// 正转换相表(根据电机实际接线调整)
static const CommutationStep_t commutation_table[8] = {
{0,0, 0,0, 0,0}, // 000,无效状态
{1,0, 0,0, 0,1}, // 001:A+ C-
{0,0, 1,0, 0,1}, // 010:B+ C-
{1,0, 0,1, 0,0}, // 011:A+ B-
{0,1, 0,0, 1,0}, // 100:C+ A-(注意顺序)
{0,0, 0,1, 1,0}, // 101:C+ B-
{0,1, 1,0, 0,0}, // 110:B+ A-
{0,0, 0,0, 0,0}, // 111,无效状态
};
void Motor_Commutate(uint8_t hall_state, uint16_t pwm_duty)
{
const CommutationStep_t* step = &commutation_table[hall_state];
// 根据换相表设置各相的PWM和使能状态
// 上桥用PWM控制占空比(调速)
// 下桥用GPIO直接开关
if (step->AH) TIM_SetPWM(TIM_CH_AH, pwm_duty);
else TIM_SetPWM(TIM_CH_AH, 0);
GPIO_Write(PIN_AL, step->AL);
if (step->BH) TIM_SetPWM(TIM_CH_BH, pwm_duty);
else TIM_SetPWM(TIM_CH_BH, 0);
GPIO_Write(PIN_BL, step->BL);
if (step->CH) TIM_SetPWM(TIM_CH_CH, pwm_duty);
else TIM_SetPWM(TIM_CH_CH, 0);
GPIO_Write(PIN_CL, step->CL);
}
// 转速PID控制
typedef struct {
float kp, ki, kd;
float error_sum;
float last_error;
float output_min, output_max;
} PID_t;
float PID_Update(PID_t* pid, float setpoint, float measured)
{
float error = setpoint - measured;
pid->error_sum += error;
float d_error = error - pid->last_error;
pid->last_error = error;
float output = pid->kp * error
+ pid->ki * pid->error_sum
+ pid->kd * d_error;
// 限幅
if (output > pid->output_max) output = pid->output_max;
if (output < pid->output_min) output = pid->output_min;
return output;
}
论文亮点:无刷电机控制是嵌入式里含金量较高的方向,能展示定时器、PWM、中断协同工作的能力,PID控制器设计可以单独写一章。
项目四:基于NB-IoT的低功耗智能水表(难度:★★★★)
适合谁:对物联网方向感兴趣,想展示完整的端到端系统能力。
功能描述:
- 脉冲计数模拟水表读数(传感器输入)
- MCU处于低功耗状态,每天定时上报读数
- 通过NB-IoT(BC660K模块)接入运营商网络
- 数据上报到MQTT服务器(阿里云IoT或自建)
- 网页后台可查看用量曲线
系统架构(这是毕设里最能展示系统思维的部分):
水表脉冲 → STM32(低功耗)→ NB-IoT模块 → 运营商基站
↓
MQTT Broker
↓
后台服务器(Python)
↓
Web展示页面
关键代码——低功耗策略:
// 大部分时间处于Stop模式,RTC每天定时唤醒一次
void Enter_LowPower_Until_Report(void)
{
// 关闭所有外设时钟
__HAL_RCC_SPI1_CLK_DISABLE();
__HAL_RCC_USART1_CLK_DISABLE();
// 未使用GPIO配成模拟输入(降低漏电流)
GPIO_ConfigAllAnalog_ExceptWakeup();
// 设置RTC闹钟(下次上报时间)
RTC_SetDailyAlarm(REPORT_HOUR, REPORT_MINUTE);
// 进入Stop2模式(STM32L4),RTC继续运行
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
// 唤醒后恢复时钟
SystemClock_Restore();
}
// NB-IoT AT指令交互
uint8_t NB_SendMQTT(uint32_t meter_value)
{
char payload[64];
snprintf(payload, sizeof(payload),
"{\"meter\":%lu,\"ts\":%lu}",
meter_value, RTC_GetUnixTime());
// 发送AT指令
char at_cmd[128];
snprintf(at_cmd, sizeof(at_cmd),
"AT+QMTPUBEX=0,0,0,0,\"water/meter001\",%d\r\n",
strlen(payload));
AT_Send(at_cmd);
AT_WaitResponse("OK", 5000);
AT_Send(payload);
return AT_WaitResponse("OK", 10000);
}
论文亮点:
- 完整的端到端IoT系统(硬件+固件+云端+展示)
- 低功耗设计和分析(可以算出理论电池寿命)
- 通信安全(MQTT over TLS)
项目五:基于RISC-V的自制小型操作系统内核(难度:★★★★★)
适合谁:操作系统课学得好,对底层感兴趣,目标是大厂或者研究所,想做一个让人眼前一亮的毕设。
功能描述:
- 在RISC-V开发板(如SiFive Freedom E310)或QEMU上实现一个迷你OS内核
- 实现:内存管理(简单页式管理)、任务调度(时间片轮转)、基本系统调用
- 能跑一个简单的用户程序
这个项目复杂度最高,但参考资料也足——xv6(MIT开源的教学OS)是最好的参考,在RISC-V上移植xv6是一个经典的课程项目。
核心代码——上下文切换(RISC-V汇编):
# RISC-V上下文切换
# 保存当前任务的寄存器到栈,恢复下一个任务的寄存器
.globl context_switch
context_switch:
# a0 = 当前任务的上下文指针
# a1 = 下一个任务的上下文指针
# 保存通用寄存器(ra, sp, s0-s11)
sd ra, 0(a0)
sd sp, 8(a0)
sd s0, 16(a0)
sd s1, 24(a0)
# ... 保存 s2-s11
# 恢复下一个任务的寄存器
ld ra, 0(a1)
ld sp, 8(a1)
ld s0, 16(a1)
ld s1, 24(a1)
# ... 恢复 s2-s11
ret # 跳转到下一个任务(ra里是下一个任务的返回地址)
论文亮点:
- 操作系统底层原理的实际实现(不只是理解,是做出来了)
- RISC-V架构的理解(顺应RISC-V发展趋势,有前沿性)
- 代码量大但结构清晰,每个模块可以单独成章
选题建议
| 你的情况 | 推荐项目 |
|---|---|
| 嵌入式入门,C语言还行 | 项目一:环境监测系统 |
| 学过RTOS,想展示多任务 | 项目二:智能家居控制器 |
| 对电机感兴趣,数学好 | 项目三:BLDC电机控制器 |
| 对IoT方向感兴趣 | 项目四:NB-IoT智能水表 |
| 操作系统学得好,目标大厂 | 项目五:RISC-V迷你OS |
最后说一句
毕设不是让你做出一个工业级的产品,而是让你证明你有独立完成一个有一定技术深度的系统的能力。
关键不是选了多难的题,而是你能不能把选的题做扎实——代码能跑,逻辑能说清楚,遇到问题能说出你是怎么解决的。
选一个能在三个月内认真做完的题,比选一个做了一半放弃的更有价值。
加油。
更多推荐

所有评论(0)