STM32 ADC实战:用光敏和红外传感器做个简易环境监测器(附完整代码)
STM32 ADC实战用光敏和红外传感器构建智能环境监测系统清晨的阳光透过窗帘缝隙洒进房间光敏电阻的阻值悄然变化走廊里有人经过时红外传感器默默记录下这一瞬间——这些看似微小的信号通过STM32的ADC模块转化为数字世界可理解的数据。本文将带你从零开始用最常见的两种传感器打造一个能感知环境光照强度和物体移动的智能监测装置。1. 硬件选型与电路设计1.1 传感器特性对比选择传感器时我们需要考虑灵敏度、响应速度和环境适应性。以下是两种传感器的关键参数对比传感器类型工作电压输出范围典型应用场景响应时间光敏电阻3.3-5V0-3.3V光照强度监测20-50ms红外对管3.3-5V0-3.3V物体检测/循迹10-30ms提示实际购买时建议选择带有模拟输出(AO)和数字输出(DO)双接口的模块便于后期功能扩展。1.2 电路连接方案典型接线配置如下以STM32F103C8T6为例// 引脚定义 #define LIGHT_SENSOR_PIN GPIO_Pin_0 // PA0 #define IR_SENSOR_PIN GPIO_Pin_1 // PA1硬件连接要点传感器VCC接3.3V避免5V直接接入STM32的ADC引脚共地连接至关重要GND必须相连模拟输出接STM32的ADC输入通道如PA0、PA1等2. ADC模块配置与优化2.1 基础ADC初始化不同于简单的库函数调用我们需要深入配置ADC参数以适应环境监测场景void ADC1_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 12MHz ADC时钟 // 配置GPIO为模拟输入 GPIO_InitStructure.GPIO_Pin LIGHT_SENSOR_PIN | IR_SENSOR_PIN; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, GPIO_InitStructure); // ADC参数配置 ADC_InitStructure.ADC_Mode ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode ENABLE; // 多通道扫描 ADC_InitStructure.ADC_ContinuousConvMode ENABLE; // 连续转换 ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel 2; ADC_Init(ADC1, ADC_InitStructure); // 配置规则组通道 ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); // 光敏 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5); // 红外 ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartConvCmd(ADC1, ENABLE); }2.2 采样优化技巧环境监测中信号噪声是常见问题。以下是三种实用的滤波方法移动平均滤波取最近N次采样的平均值中值滤波取N次采样的中间值一阶滞后滤波Y(n) αX(n) (1-α)Y(n-1)实现移动平均滤波的代码示例#define SAMPLE_TIMES 10 uint16_t Get_Adc_Average(uint8_t channel) { uint32_t sum 0; for(uint8_t i 0; i SAMPLE_TIMES; i) { sum ADC_GetConversionValue(ADC1); delay_ms(2); // 适当延时避免采样过快 } return sum / SAMPLE_TIMES; }3. 数据转换与校准3.1 电压值转换原理STM32的ADC是12位精度参考电压通常为3.3V。转换公式为电压值(V) ADC原始值 × (Vref / 4096)但在实际应用中我们需要考虑传感器特性曲线。例如光敏电阻的阻值-照度关系通常呈对数特性float ConvertToLux(uint16_t adcValue) { float voltage adcValue * (3.3f / 4096.0f); // 假设使用GL5528光敏电阻 float resistance (3.3f - voltage) * 10.0f / voltage; // 分压电阻10kΩ return pow(10, (log10(resistance) - 3.2) / -0.8); // 近似转换公式 }3.2 传感器校准方法为提高测量精度建议进行两点校准暗校准完全遮光时记录ADC值亮校准在标准光照条件下记录ADC值校准数据可存储在STM32的Flash中typedef struct { uint16_t dark_value; uint16_t bright_value; float dark_lux; float bright_lux; } SensorCalibration; void SaveCalibration(SensorCalibration *cal) { FLASH_Unlock(); FLASH_ErasePage(0x0800F000); FLASH_ProgramHalfWord(0x0800F000, cal-dark_value); // 继续存储其他校准参数... FLASH_Lock(); }4. 系统集成与功能实现4.1 多任务数据采集框架使用定时器触发ADC采样实现稳定的数据采集节奏void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3, TIM_IT_Update) ! RESET) { static uint8_t channel 0; if(channel 0) { light_value Get_Adc_Average(ADC_Channel_0); channel 1; } else { ir_value Get_Adc_Average(ADC_Channel_1); channel 0; ProcessSensorData(); // 处理完整的一组数据 } TIM_ClearITPendingBit(TIM3, TIM_IT_Update); } }4.2 状态判断算法对于红外传感器动态阈值检测比固定阈值更可靠#define DYNAMIC_THRESHOLD_RATIO 0.2f uint8_t DetectObject(uint16_t current, uint16_t *baseline) { uint16_t threshold *baseline * DYNAMIC_THRESHOLD_RATIO; if(abs(current - *baseline) threshold) { *baseline (*baseline * 0.9f) (current * 0.1f); // 基线缓慢适应 return 1; } return 0; }4.3 数据可视化输出通过串口输出结构化JSON格式数据方便上位机解析void SendSensorData(float light, float ir) { printf({\light\:%.2f,\ir\:%.2f,\time\:%lu}\r\n, light, ir, millis()); }示例输出{light:325.67,ir:1.23,time:123456} {light:318.92,ir:1.45,time:123486}5. 进阶应用与扩展思路5.1 低功耗优化策略对于电池供电的应用可采取以下措施间歇采样模式如每秒唤醒一次动态调整采样频率根据环境变化程度关闭未使用的外设时钟void EnterLowPowerMode(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, DISABLE); ADC_Cmd(ADC1, DISABLE); // 配置MCU进入STOP模式 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); // 唤醒后重新初始化 SystemInit(); ADC1_Init(); }5.2 多节点组网方案通过添加无线模块如ESP8266或NRF24L01实现数据远程传输void SendViaWiFi(const char *data) { USART_SendString(USART3, ATCIPSEND0,); USART_SendString(USART3, strlen(data)); USART_SendString(USART3, \r\n); delay(100); USART_SendString(USART3, data); }5.3 机械结构设计建议使用3D打印外壳保护电路考虑传感器朝向和安装角度预留调试接口如SWD和串口实际部署中发现将光敏传感器朝北安装可避免阳光直射导致的读数剧烈波动红外传感器的最佳安装高度在80-120cm之间这个高度最适合检测人体移动。