一个人也能做的嵌入式毕设项目推荐,附思路和代码

毕设选题这件事,两个极端都不好:选太难的,一个人做不完;选太简单的,老师一看就知道你在凑数。

嵌入式方向,理想的毕设项目应该是:硬件+软件都有,有一个完整可演示的功能,代码有一定技术含量,但复杂度在一个人三四个月内能完成的范围里。

下面推荐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

最后说一句

毕设不是让你做出一个工业级的产品,而是让你证明你有独立完成一个有一定技术深度的系统的能力。

关键不是选了多难的题,而是你能不能把选的题做扎实——代码能跑,逻辑能说清楚,遇到问题能说出你是怎么解决的。

选一个能在三个月内认真做完的题,比选一个做了一半放弃的更有价值。

加油。

更多推荐