1. 从RFID智能门禁到AI视觉追踪:STM32物联网毕设创新指南

做嵌入式开发的同学们,毕业设计总是让人头疼——既要体现技术水平,又要有创新点,还得保证工作量足够。我当年做毕设时也踩过不少坑,后来在工业界做了多年STM32项目,才发现学校里学的那些基础技术原来能玩出这么多花样。今天我就以过来人的身份,给大家分享几个基于STM32的物联网创新毕设案例,从简单的RFID门禁到复杂的AI视觉追踪,保证让你找到适合自己的方向。

先说个实话,好的毕设不在于用了多高端的技术,而在于把基础技术用出创新点。比如RFID门禁系统,很多人都做过,但如果你加入网络通信、数据分析和异常处理,立马就变得高大上了。我带的几个学生去年做的项目,就是把简单的门禁系统升级成了智能考勤管理系统,不仅拿了优秀毕设,还申请了专利。

2. RFID智能门禁系统实战:从基础到进阶

2.1 硬件选型与电路设计

做RFID门禁,硬件选型是第一步。我推荐用STM32F103C8T6作为主控,这款芯片性价比高,资源足够,社区支持也好。RFID模块首选MFRC522,价格便宜,资料丰富,特别适合学生项目。显示部分可以用0.96寸OLED,比LCD更省电,显示效果也不错。

电路设计时要注意电源隔离,我在第一个项目里就栽过跟头。当时直接用开发板供电,没加稳压电路,结果RFID模块一工作,单片机就复位。后来加了AMS1117-3.3V稳压芯片和100μF的滤波电容,问题就解决了。建议大家在原理图上留出测试点,调试时会方便很多。

接线方面,SPI接口的接法要记牢:

  • SCK → PA5
  • MISO → PA6
  • MOSI → PA7
  • NSS → PA4
  • RST → PA0

2.2 软件架构与代码优化

软件部分要分层设计,我习惯分成硬件驱动层、功能逻辑层和应用层。驱动层负责底层操作,比如RFID的读写、OLED显示等。功能逻辑层处理业务逻辑,比如卡号验证、门锁控制。应用层实现高级功能,比如数据存储、通信等。

RFID读卡的基础代码很简单:

// 初始化RC522
void RFID_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;
    
    // 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
    
    // 配置SPI引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 更多初始化代码...
}

// 读取卡号
uint8_t RFID_ReadCard(uint8_t* sn) {
    if (PCD_Request(PICC_REQALL, sn) == MI_OK) {
        if (PCD_Anticoll(sn) == MI_OK) {
            return 1;
        }
    }
    return 0;
}

但单纯读卡号太基础了,我建议增加以下功能提升项目档次:

  • 多卡管理:支持注册、删除、查询卡号
  • 数据存储:用STM32的Flash模拟EEPROM存储卡号
  • 异常处理:防拆报警、多次尝试锁定
  • 状态指示:用RGB LED显示不同状态

2.3 通信协议与上位机设计

单机系统已经过时了,现在都讲究物联网。可以给门禁系统加上WiFi或4G模块,实现远程监控。我用过ESP8266和SIM800L,推荐ESP8266,价格便宜,AT指令简单易懂。

通信协议建议用MQTT,特别适合物联网场景。我在项目里用的是FreeRTOS + MQTT的方案,稳定性很好。下面是MQTT初始化的代码片段:

void MQTT_Init(void) {
    // 连接WiFi
    ESP8266_Init();
    ESP8266_ConnectAP("your_ssid", "your_password");
    
    // 连接MQTT服务器
    MQTTClient client = MQTTClient_create();
    MQTTClient_connect(&client, "tcp://mqtt.server.com:1883", "door_client");
    
    // 订阅主题
    MQTTClient_subscribe(&client, "door/control");
}

上位机可以用Python的Tkinter开发,简单易用。主要功能包括:

  • 实时显示门禁状态
  • 卡号管理(添加、删除、查询)
  • 考勤数据导出
  • 异常报警通知

3. 传感器融合与环境监测系统

3.1 多传感器数据采集

单一传感器项目太单调了,现在流行多传感器融合。温湿度、光照、空气质量这些传感器都可以整合到一个系统中。我推荐以下传感器组合:

  • DHT11/DHT22:温湿度检测
  • BH1750:光照强度
  • MQ-2:烟雾检测
  • GP2Y1010AU0F:粉尘检测

硬件设计要注意电源管理,这么多传感器同时工作,功耗不小。建议用MOS管控制传感器电源,不需要采集时断电节能。我在一个项目中这样做了,整体功耗降低了60%。

传感器数据采集要采用轮询方式,避免阻塞主程序。最好用DMA方式读取ADC数据,效率更高。下面是多传感器数据采集的示例:

typedef struct {
    float temperature;
    float humidity;
    uint16_t light;
    uint16_t smoke;
    uint32_t dust;
} SensorData_t;

void Sensors_ReadAll(SensorData_t* data) {
    // 读取温湿度
    DHT11_Read(&data->temperature, &data->humidity);
    
    // 读取光照
    data->light = BH1750_ReadLight();
    
    // 读取烟雾
    data->smoke = MQ2_Read();
    
    // 读取粉尘
    data->dust = GP2Y1010_Read();
}

3.2 数据滤波与算法处理

传感器数据都有噪声,直接使用效果很差。我常用的滤波算法有移动平均滤波、中值滤波和卡尔曼滤波。对于资源有限的STM32,推荐移动平均滤波,计算量小,效果不错。

#define FILTER_SIZE 10

uint16_t MovingAverageFilter(uint16_t new_value) {
    static uint16_t buffer[FILTER_SIZE] = {0};
    static uint8_t index = 0;
    static uint32_t sum = 0;
    
    sum -= buffer[index];
    buffer[index] = new_value;
    sum += new_value;
    index = (index + 1) % FILTER_SIZE;
    
    return sum / FILTER_SIZE;
}

对于环境监测系统,可以加入一些智能算法。比如根据温湿度和光照自动控制窗帘和空调,或者根据空气质量自动开启净化器。这些功能看似简单,但很能体现技术水平。

3.3 低功耗设计与电源管理

物联网设备很多需要电池供电,低功耗设计很重要。我的经验是:

  1. 选用低功耗芯片,比如STM32L系列
  2. 合理使用睡眠模式,在空闲时进入睡眠
  3. 用中断唤醒代替轮询,减少CPU工作时间
  4. 优化电源电路,降低静态功耗

下面是低功耗设计的代码示例:

void EnterSleepMode(void) {
    // 关闭外设时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, DISABLE);
    
    // 配置唤醒源
    PWR_WakeUpPinCmd(ENABLE);
    
    // 进入睡眠模式
    PWR_EnterSleepMode(PWR_Regulator_LowPower, PWR_SLEEPEntry_WFI);
}

电池电量监测也很重要,可以用STM32的ADC监测电池电压,电量低时及时报警。

4. AI视觉追踪与图像处理

4.1 硬件平台选型与搭建

AI视觉是现在的热点,用在毕设里很加分。STM32做图像处理确实吃力,但不是不可能。我推荐用STM32H7系列,主频高,带DSP指令集,处理图像更轻松。摄像头可以用OV7670,便宜够用,或者用更高端的OV2640。

硬件搭建要注意以下几点:

  • 摄像头接口最好用DCMI,速度比模拟接口快很多
  • 预留足够的内存,图像处理很吃内存
  • 加上TF卡槽,用于存储图像和模型

如果处理能力不够,可以考虑STM32+Linux的方案,用STM32做控制,Linux做图像处理。我在一个项目中这样做的,效果很好。

4.2 图像处理基础算法

图像处理先从基础开始,比如边缘检测、颜色识别、简单滤波。这些算法在STM32上都能实现。下面是一个简单的边缘检测函数:

void EdgeDetection(uint8_t* input, uint8_t* output, uint16_t width, uint16_t height) {
    for (int y = 1; y < height - 1; y++) {
        for (int x = 1; x < width - 1; x++) {
            int gx = -input[(y-1)*width + x-1] + input[(y-1)*width + x+1]
                     -2*input[y*width + x-1] + 2*input[y*width + x+1]
                     -input[(y+1)*width + x-1] + input[(y+1)*width + x+1];
            
            int gy = -input[(y-1)*width + x-1] - 2*input[(y-1)*width + x] - input[(y-1)*width + x+1]
                     + input[(y+1)*width + x-1] + 2*input[(y+1)*width + x] + input[(y+1)*width + x+1];
            
            output[y*width + x] = sqrt(gx*gx + gy*gy) > EDGE_THRESHOLD ? 255 : 0;
        }
    }
}

实际项目中要优化算法,减少计算量。比如降低图像分辨率,只处理感兴趣区域,使用查表法等。

4.3 机器学习模型部署

虽然在STM32上跑深度学习模型比较困难,但一些轻量级模型还是可以的。比如TinyML、TensorFlow Lite Micro等框架都支持STM32。我去年帮一个学生做了人脸检测项目,用的就是TensorFlow Lite Micro。

模型部署的步骤:

  1. 在PC上训练模型并量化
  2. 转换为TensorFlow Lite格式
  3. 用STM32Cube.AI转换为C代码
  4. 集成到STM32项目中

下面是一个简单的模型推理示例:

// 初始化模型
static tflite::MicroErrorReporter micro_error_reporter;
static tflite::ErrorReporter* error_reporter = &micro_error_reporter;

// 加载模型
const tflite::Model* model = tflite::GetModel(g_model);
static tflite::MicroInterpreter static_interpreter(
    model, resolver, tensor_arena, kTensorArenaSize, error_reporter);

// 运行推理
TfLiteStatus invoke_status = interpreter->Invoke();
if (invoke_status != kTfLiteOk) {
    error_reporter->Report("Invoke failed");
    return;
}

实际项目中要注意模型大小和内存占用,STM32的资源很有限。建议先用模拟器测试,再移植到硬件上。

5. 物联网通信与云平台对接

5.1 无线通信技术选型

物联网项目离不开无线通信。常用的技术有:

  • WiFi:适合室内应用,带宽大,功耗高
  • Bluetooth:适合短距离通信,功耗低
  • LoRa:适合远距离通信,功耗低,带宽小
  • NB-IoT:覆盖广,功耗低,需要SIM卡

根据项目需求选择合适的通信方式。我一般这样选择:

  • 室内环境监测用WiFi
  • 穿戴设备用Bluetooth
  • 户外监控用LoRa
  • 移动设备用NB-IoT

硬件设计时要注意天线布局,影响通信质量。我建议留出PCB天线位置,同时支持外接天线。

5.2 通信协议设计

通信协议要设计得简单高效。我常用的格式:

#pragma pack(1)
typedef struct {
    uint8_t header;     // 帧头
    uint8_t type;       // 消息类型
    uint16_t length;    // 数据长度
    uint8_t data[256];  // 数据
    uint16_t checksum;  // 校验和
} MessageFrame_t;
#pragma pack()

数据传输要加入重传机制,保证可靠性。我一般用简单的ACK机制:

  1. 发送方发送数据帧
  2. 接收方收到后回复ACK
  3. 发送方超时未收到ACK则重传

5.3 云平台对接与数据可视化

现在很多云平台都提供物联网服务,比如阿里云、腾讯云、ThingsBoard等。我比较喜欢ThingsBoard,开源免费,功能强大。

对接云平台的步骤:

  1. 创建设备,获取访问令牌
  2. 实现MQTT或HTTP协议对接
  3. 定义数据格式和遥测数据
  4. 设计仪表盘和数据可视化

下面是一个MQTT发布数据的示例:

void PublishSensorData(SensorData_t* data) {
    char topic[100];
    char payload[200];
    
    sprintf(topic, "v1/devices/me/telemetry");
    sprintf(payload, "{\"temp\":%.1f,\"humi\":%.1f,\"light\":%d}",
            data->temperature, data->humidity, data->light);
    
    MQTTClient_publish(client, topic, payload, strlen(payload), 0, 0);
}

数据可视化可以用Grafana或平台自带的仪表盘。建议显示实时数据、历史曲线、报警信息等。

6. 系统优化与调试技巧

6.1 性能优化方法

STM32资源有限,优化很重要。我的经验是:

  1. 使用DMA减少CPU占用
  2. 优化算法,减少计算量
  3. 使用查表法代替复杂计算
  4. 合理使用缓存,减少内存访问

比如三角函数计算,可以用查表法:

const int16_t sin_table[360] = {0,17,35,...}; // 预计算好的正弦值

int16_t fast_sin(int16_t angle) {
    angle %= 360;
    if (angle < 0) angle += 360;
    return sin_table[angle];
}

内存管理也很重要,避免动态内存分配,使用静态内存池。

6.2 系统调试技巧

调试是项目开发的重要环节。我常用的调试方法:

  1. 串口打印:最简单实用的调试方法
  2. LED指示:用不同颜色的LED表示不同状态
  3. 逻辑分析仪:分析时序问题
  4. ST-Link调试:单步调试,查看变量

串口调试要设计好输出格式,便于分析:

void DebugPrint(const char* format, ...) {
    va_list args;
    va_start(args, format);
    
    char buffer[256];
    vsprintf(buffer, format, args);
    
    printf("[%08lu] %s\r\n", HAL_GetTick(), buffer);
    
    va_end(args);
}

调试时要有耐心,一个问题可能要多方面排查。我建议先确认硬件没问题,再调试软件。

6.3 稳定性提升方法

物联网设备要长时间运行,稳定性很重要。我总结了几点经验:

  1. 加入看门狗,防止程序跑飞
  2. 重要数据要备份,防止丢失
  3. 通信要加入重连机制
  4. 定期自检,及时发现故障

看门狗的使用示例:

void Watchdog_Init(void) {
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    IWDG_SetPrescaler(IWDG_Prescaler_256);
    IWDG_SetReload(0xFFF);
    IWDG_ReloadCounter();
    IWDG_Enable();
}

// 在主循环中喂狗
while (1) {
    // 业务逻辑
    IWDG_ReloadCounter();
}

异常处理也要考虑周全,比如网络断开、传感器故障等情况都要有相应的处理措施。

做完一个项目后,要好好整理代码和文档,这对答辩和以后的工作都有帮助。我见过很多学生代码写得一团糟,答辩时自己也讲不清楚。好的代码风格和文档习惯会让你受益终身。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐