前言

最近在做鸿蒙班 STM32L4 智能家居板实验,完成了AS312 热释电人体红外传感器(HC‑SR501) 的人体存在检测项目。实现功能:GPIO 读取人体红外信号、LCD 屏幕实时显示有人 / 无人状态、串口上报检测结果、软件定时采样 + 状态防抖,踩过的坑、原理、代码逻辑、现象全部整理出来,适合 STM32 嵌入式新手参考学习。

硬件平台:STM32L431VC 智能家居开发板 传感器:AS312(HC‑SR501)热释电人体红外传感器 开发库:STM32 HAL 库 调试工具:SSCOM 串口助手,波特率 115200

一、实验原理

HC‑SR501(AS312)属于热释电红外传感器,原理是捕捉人体发出的红外热辐射。

  1. 探测范围内检测到人体活动 → 输出高电平 1
  2. 范围内没有人活动 → 输出低电平 0

单片机通过 GPIO 输入引脚读取该电平信号,完成人体检测。

本实验整套链路: AS312人体红外传感器 → STM32 GPIO输入引脚 STM32 FSMC接口驱动LCD屏幕,展示检测状态图标+文字 USART2串口 → CH340 USB转串口 → PC端SSCOM串口助手打印日志

程序设计要点:

  • 使用HAL_GetTick()做软件计时,1000ms 采集一次传感器状态,不用占用硬件定时器
  • 做状态记忆,只有状态发生改变才进行串口打印,避免串口刷屏产生大量冗余数据
  • LED1 每秒电平翻转,作为程序运行心跳指示灯
  • 简单软件防抖,过滤传感器瞬时抖动误触发

硬件连接:传感器信号输出引脚接到单片机PC8引脚,传感器供电 3.3V。

二、整体程序架构

整个项目分为三大模块:主函数模块、系统时钟配置模块、人体红外业务处理模块。

1. main.c 主函数入口

int main(void)
{
	HAL_Init();
	SystemClock_Config();       //系统时钟初始化
	LCD_Display_Init();         //LCD屏幕初始化
	gpio_module_open(LEDS);     //LED引脚初始化
	uart_open(uart2, 115200);  //串口2初始化,波特率115200
	
	printf("\r\n\t人体红外检测实验\t\r\n");
	printf("----------------------------\r\n");
	printf("开始本实验:\r\n\r\n");
	
	AS312_Init();               //人体红外传感器GPIO初始化
	printf("** 人体红外传感器初始化\r\n");
	
	while(1)
	{
		Body_Handle();         //循环调用人体红外检测处理函数
	}
}

执行流程:

  1. HAL_Init()初始化 HAL 底层库,配置滴答定时器、中断优先级;
  2. 依次初始化时钟、LCD 显示屏、LED、串口、人体红外传感器外设;
  3. 全部硬件初始化完成后进入while(1)死循环,持续调用Body_Handle()处理检测逻辑,完成采集、屏幕刷新、串口输出、状态判断。

2. SystemClock_Config 系统时钟模块

系统时钟是所有外设工作的基础:

  1. 选择高速外部 HSE 或者内部 HSI 时钟源;
  2. 配置 PLL 锁相环倍频,生成系统主时钟 SYSCLK;
  3. 配置 AHB、APB 预分频,分配总线时钟;
  4. 开启 GPIO、串口等外设时钟,外设时钟不打开硬件将无法工作。

补充:_Error_Handler()是 HAL 库错误回调。时钟配置失败、外设初始化异常会进入该函数,卡在死循环。调试时可以在这里增加屏幕打印,快速定位硬件、时钟配置故障。

3. Body_Handle () 核心业务处理函数

这是本实验的业务核心,主循环反复调用。

void Body_Handle(void)
{
	static uint8_t as312_state_rev = 2;
	uint8_t as312_state = 0;
	static uint32_t tickstart;
	
	if((HAL_GetTick() - tickstart) >= 1000) //1000ms采集一次
	{
		tickstart = HAL_GetTick();
		as312_state = Infrared_Read_State(); //读取传感器电平
		
		if(as312_state == 1)
		{
			//LCD绘制有人图标,显示someone
			LCD_draw_bmp(96,120,48,gImage_Body);
			LCD_Fill1(96,178,137,194,WHITE);
			Show_Str(96,178,BLUE,WHITE,"someone",16,1);
		}
		else if(as312_state == 0)
		{
			//LCD绘制无人图标,显示no one
			LCD_draw_bmp(96,120,48,gImage_Body_hui);
			LCD_Fill1(96,178,137,194,WHITE);
			Show_Str(96,178,BLUE,WHITE,"no one",16,1);
		}
		
		//状态发生变化才打印串口,减少冗余输出
		if(as312_state != as312_state_rev)
		{
			if(as312_state == 1)
			{
				printf("** 读取人体红外传感器数据\r\n");
				printf("** 人体红外传感数据:someone\r\n\r\n");
			}
			else if(as312_state == 0)
			{
				printf("** 读取人体红外传感器数据\r\n");
				printf("** 人体红外传感数据:no one\r\n\r\n");
			}
			as312_state_rev = as312_state; //保存上一次状态
		}
		led_toggle(LED1_PORT); //翻转LED,作为运行指示
	}
}

关键逻辑解读:

  1. HAL_GetTick()实现软件 1 秒定时,周期性读取传感器;
  2. Infrared_Read_State()读取 PC8 引脚电平,返回 1 代表有人,0 代表无人;
  3. 根据状态刷新 LCD 图标与文字;
  4. 使用静态变量保存上一回检测状态,状态改变才 printf 输出,防止串口疯狂刷屏;
  5. 每次采样完成翻转 LED1,直观证明程序正常在跑。

三、实验现象与结果

把程序下载到 STM32 开发板,PC 打开 SSCOM 串口助手:

  • 参数设置:选择对应 COM 口,波特率115200
  • 上电后串口打印实验标题、初始化提示;LCD 屏幕显示标题 “人体红外检测实验”
  1. 人进入传感器探测范围 LCD 显示有人图标 +someone;串口输出:
** 读取人体红外传感器数据
** 人体红外传感数据:someone
  1. 人离开探测范围 LCD 切换为无人图标 +no one;串口输出:
** 读取人体红外传感器数据
** 人体红外传感数据:no one
  1. LED 指示灯每 1 秒翻转一次,代表程序持续运行。

⚠️注意:HC‑SR501 硬件自带延时,人走开之后不会立刻变为无人,是传感器硬件本身特性,不是程序 bug。

四、调试遇到的问题与排错

  1. 串口完全没有输出 排查:COM 端口是否选对、波特率是否 115200;检查 CH340 驱动;检查串口硬件接线、串口初始化代码。
  2. LCD 屏幕黑屏 / 无内容 排查 LCD 初始化函数,FSMC 硬件接线,屏幕电源。
  3. 传感器乱跳、误触发 热释电传感器容易受环境温度干扰,可以增加多次采样判断做软件滤波防抖。

感悟:串口打印是嵌入式调试最高效手段之一,很多硬件故障、逻辑问题都可以通过串口日志定位。

五、拓展创新思路

做完基础检测功能,还可以做二次开发:

  1. 入侵报警:检测到人触发蜂鸣器鸣叫,简单安防告警;
  2. 人体感应灯:外接继电器,检测到人自动开灯;
  3. 云端上报:对接 WiFi 模块,把有人 / 无人状态上传云平台,远程查看;
  4. 增强抗干扰:连续多次采样确认状态,降低误触发概率;
  5. 按键调参:增加按键,修改传感器采样周期,改变系统响应快慢。

总结

本次实验完整走完从硬件接线、GPIO 采集传感器信号、屏幕显示、串口上报的完整流程。 学会使用 HAL 库HAL_GetTick()做软件定时采样,理解状态记忆,解决串口输出刷屏的问题,同时认识热释电人体红外传感器的固有硬件特性。对于想要入门 STM32 智能家居项目,这个是非常适合上手的小 Demo。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐