STM32 05 光敏传感器控制蜂鸣器
一、目标
在掌握了按键控制 LED 的模块化编程后,我开始尝试处理模拟量输入。本实验的目标是利用光敏电阻检测环境亮度,并据此控制蜂鸣器的报警。
这次的重点依然是代码封装。我将“光敏传感器读取”和“蜂鸣器控制”分别封装成独立的模块,主函数只负责逻辑判断。虽然目前用的是简单的软件计数法来模拟阈值触发,但这让我对 GPIO 输入输出配合有了更深的理解。
二、硬件连接说明
光敏传感器模块:DO 引脚接 STM32 的 PA1(或其他 GPIO),用于输出高低电平(亮/暗)。
蜂鸣器模块:I/O 引脚接 PB12,低电平触发鸣叫。
原理简述:当环境光线变暗时,光敏模块输出高电平,程序通过累加计数来判断是否达到报警阈值,从而驱动蜂鸣器响一声并重置计数。
三、代码块
main主函数
#include"stm32f10x.h"// Device header#include"delay.h"#include"buzzer.h"#include"lightsensor.h"uint16_tnumber=0;intmain(){BUZZER__init();lightsensor__init();while(1){if(lightsensor_get()==1){number+=30;}if(number>=300){BUZZER_on();number=0;Delay_ms(100);}else{BUZZER_off();}Delay_ms(30);}}buzzer.c
#include"stm32f10x.h"// Device headervoidBUZZER__init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct1;GPIO_InitStruct1.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStruct1.GPIO_Pin=GPIO_Pin_12;GPIO_InitStruct1.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStruct1);GPIO_SetBits(GPIOB,GPIO_Pin_12);}voidBUZZER_on(void){GPIO_ResetBits(GPIOB,GPIO_Pin_12);}voidBUZZER_off(void){GPIO_SetBits(GPIOB,GPIO_Pin_12);}voidBUZZER_turn(void){if(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_12)==0){GPIO_SetBits(GPIOB,GPIO_Pin_12);}else{GPIO_ResetBits(GPIOB,GPIO_Pin_12);}}lightsensor
#include"stm32f10x.h"// Device headervoidlightsensor__init(void){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct1;GPIO_InitStruct1.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStruct1.GPIO_Pin=GPIO_Pin_13;GPIO_InitStruct1.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStruct1);GPIO_SetBits(GPIOB,GPIO_Pin_13);}uint8_tlightsensor_get(void){returnGPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13);}四、个人学习心得与踩坑记录
作为一个刚入门 STM32 的初学者,这次写代码时我又遇到了一些“小麻烦”,但也收获颇丰:
关于变量类型的选择:一开始我把 number 定义成了 uint8_t ,结果发现最大只能存 255,永远达不到 300 的阈值,蜂鸣器死活不响。后来改成 uint16_t 才解决。这个低级错误提醒我,定义变量时一定要先算好数据范围!
对“软硬结合”的初体验:以前觉得代码就是代码,现在发现代码必须配合硬件特性。比如那个 Delay_ms(30) ,如果去掉它,循环跑得太快, number 瞬间就爆表了,蜂鸣器就会一直狂叫。原来延时不仅仅是为了让人眼看清,更是为了配合程序的逻辑节奏。
封装带来的便利:这次直接调用 lightsensor_get() ,完全不用去管底层是读哪个寄存器,这种感觉太棒了!我觉得这就是模块化的魅力,让我能专注于逻辑本身。
五、存在的不足与改进方向
目前的程序虽然能跑,但我深知这只是最基础的“玩具级”实现,还有很多需要向大佬们学习的地方:
阈值设定的随意性:现在的 30 和 300 都是我在 while 循环里试出来的“玄学数字”。如果环境光变化或者延时时间改变,这些数字就得重调。我知道应该用 ADC 采集具体电压值来做精确判断,但目前还没学会 ADC,只能用 GPIO 凑合一下。
阻塞式延时的弊端:这里的 Delay_ms(100) 会让 CPU 傻等 100 毫秒,这段时间里系统是什么都做不了的。如果以后要同时控制电机或者屏幕,这种写法肯定不行。定时器中断是我接下来的必学内容。
缺乏迟滞比较:现在的逻辑在临界点可能会让蜂鸣器“抖动”(响一下停一下)。如果能加入类似“施密特触发”的逻辑(比如大于 300 响,小于 200 才停),效果应该会好很多。
