目录
一、系统概述
本系统采用STM32F103C8T6单片机(Blue Pill开发板)和光敏电阻传感器模块,实现环境光照强度的检测与显示功能。系统通过标准外设库开发,具有结构简单、响应灵敏的特点,可广泛应用于智能家居、农业温室、自动照明等领域。
二、光敏电阻传感器模块简介
2.1 基本概述
光敏电阻(Photoresistor 或 LDR,Light Dependent Resistor)是一种基于半导体材料的光电传感器,其电阻值随光照强度变化而变化。核心特性如下:
- 工作原理:利用硫化镉(CdS)等半导体材料的光电效应,光照时电子被激发,电阻降低。
- 核心特点:成本低、结构简单、灵敏度高,但响应速度较慢(毫秒级)。
光敏电阻传感器图片:
2.2 模块组成与引脚定义
四线制模块典型结构:
引脚 | 功能说明 |
---|---|
VCC | 供电(3.3V/5V) |
GND | 地线 |
AO | 模拟输出(电压随光照变化) |
DO | 数字输出(阈值触发) |
模块附加功能:
- 比较器电路:将AO信号与可调阈值比较,输出数字信号(DO)。
- 灵敏度电位器:调节DO的触发阈值。
- 状态指示灯:显示数字输出状态。
2.3 工作原理与电气特性
2.3.1 电路原理图
该电路是一个基于光敏电阻和LM393电压比较器的光敏电阻传感器电路,常用于检测环境光强度并根据光强变化输出数字信号。以下是对该电路的详细说明:
电源部分:
- VCC:电路的电源正极,为整个电路提供工作电压。
- 电源指示:由一个发光二极管(LED)和限流电阻(1K)组成。当电路接通电源时,LED点亮,指示电路已通电。电容104(0.1μF)用于电源滤波,减少电源噪声对电路的影响。
光敏电阻部分:
- 光敏电阻:其阻值会随着环境光强度的变化而变化。光强增加时,阻值减小;光强减弱时,阻值增大。
- 电位器VR1:一个10K的可调电阻,用于设置比较器的参考电压。通过调节VR1,可以改变光敏电阻触发比较器的阈值。
电压比较器部分:
- LM393:这是一个双电压比较器芯片,在此电路中使用了其中一个比较器。比较器的同相输入端(+)连接到电位器VR1的滑动端,反相输入端(-)连接到光敏电阻和固定电阻(10K)组成的分压电路。
- 工作原理:比较器将反相输入端的电压(由光敏电阻分压得到)与同相输入端的参考电压(由VR1设置)进行比较。当反相输入端电压低于同相输入端电压时,比较器输出高电平;反之,输出低电平。
输出部分:
- DO:数字输出引脚,直接连接到比较器的输出端。当环境光强度低于设定阈值时,DO输出低电平;当环境光强度高于设定阈值时,DO输出高电平。
- AO:模拟输出引脚,连接到光敏电阻和固定电阻组成的分压电路。AO输出的电压值与光敏电阻的阻值成比例,可以用于获取更精确的光强信息。
- 开关指示:由一个发光二极管(LED)和限流电阻(1K)组成,用于指示比较器的输出状态。当DO输出低电平时,LED点亮;当DO输出高电平时,LED熄灭。
接口部分:
- 3线制和4线制接口:提供了两种不同的接口方式,方便与不同的微控制器或电路连接。3线制接口包括VCC、GND和DO;4线制接口包括VCC、GND、DO和AO。
2.3.2 模块输出特性
输出类型 | 信号范围 | 特点 |
---|---|---|
AO | 0-VCC(模拟电压) | 连续变化,需ADC采集 |
DO | 高/低电平 | 超过阈值时触发,直接控制 |
2.3.3 典型参数
参数 | 值/范围 |
---|---|
工作电压 | 3.3V-5V |
检测波长范围 | 400-700nm(可见光) |
响应时间 | 20-100ms |
工作温度 | -30℃~+70℃ |
视角 | 约120°(广角检测) |
2.4 使用注意事项
安装与环境:
- 避免强光直射导致老化。
- 远离热源(温度影响电阻值)。
校准方法:
- 暗校准:覆盖传感器,记录暗电阻对应的ADC值。
- 亮校准:在标准光源(如1000Lux)下记录亮电阻值。
硬件设计:
- 分压电阻选择:建议2kΩ-10kΩ(平衡灵敏度与功耗)。
- 添加电容滤波(如0.1μF陶瓷电容并联AO)。
软件优化:
- 非线性补偿:分段线性化或查表法。
- 动态阈值:根据环境光自动调整触发阈值。
2.5 与其他光传感器的对比
特性 | 光敏电阻 | 光电二极管 | 环境光传感器(如BH1750) |
---|---|---|---|
成本 | 最低(¥0.5) | 中等 | 较高 |
精度 | 低 | 中 | 高 |
响应速度 | 慢(ms级) | 快(μs级) | 中(ms级) |
输出 | 模拟/数字 | 模拟 | 数字(I2C) |
线性度 | 差 | 较好 | 优秀 |
三、硬件设计
3.1 硬件组成
- STM32F103C8T6最小系统板
- 光敏电阻传感器模块(四线制)
- 0.96寸OLED显示屏(I2C接口)
- LED指示灯(用于阈值提示)
- 10KΩ电位器(用于阈值调节)
- 杜邦线若干
STM32F103C8T6最小系统板示意图:
LED模块:
STM32F103C8T6最小系统板PCB13默认接到自带的LED灯,无需外接 。
3.2 硬件连接
STM32引脚 | 连接模块 | 说明 |
---|---|---|
PA0 | 传感器AO | ADC1通道0 |
PA1 | 传感器DO | 数字输入 |
PB6 | OLED_SCL | I2C1时钟线 |
PB7 | OLED_SDA | I2C1数据线 |
PC13 | LED | 光强阈值提示 |
3.3V | 传感器VCC | 电源 |
GND | 传感器GND | 共地 |
四、软件设计
4.1 开发环境配置
- 开发工具:Keil MDK-ARM 5
- 库版本:STM32F10x标准外设库
- 调试工具:ST-Link V2
4.2 关键代码实现
4.2.1 初始化代码
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_i2c.h"
#include "oled.h"
#include "delay.h"
// 光强阈值(可根据需要调整)
#define LIGHT_THRESHOLD 1500
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC, ENABLE);
// 配置PA0为模拟输入(AO)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置PA1为浮空输入(DO)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置PC13为推挽输出(LED)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// 配置I2C引脚(PB6,PB7)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
// 使能ADC1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// ADC配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC通道0(PA0)
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
// 使能ADC1
ADC_Cmd(ADC1, ENABLE);
// ADC校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
// 启动ADC转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
// 使能I2C1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// I2C配置
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000; // 100kHz
I2C_Init(I2C1, &I2C_InitStructure);
// 使能I2C1
I2C_Cmd(I2C1, ENABLE);
}
GPIO配置函数(GPIO_Configuration)功能:
初始化所有用到的GPIO引脚,包括:
-
PA0:模拟输入,连接光敏电阻的模拟输出(AO)
-
PA1:数字输入,连接光敏电阻的数字输出(DO)
-
PC13:推挽输出,控制LED指示灯
-
PB6/PB7:开漏输出,配置为I2C接口(用于OLED显示屏)
ADC配置函数(ADC_Configuration)功能:
配置ADC1(通道0,PA0)用于读取光敏电阻的模拟电压值。
-
GPIO_Mode_AIN:将PA0设为模拟输入模式,用于ADC采集电压信号。
-
PB6/PB7的GPIO_Mode_AF_OD:I2C协议要求引脚为开漏输出模式,需外接上拉电阻。
-
连续转换模式:ADC自动持续采样,无需手动触发。
-
ADC校准:通过
ADC_ResetCalibration
和ADC_StartCalibration
确保转换精度。 -
采样时间:
ADC_SampleTime_239Cycles5
表示采样周期为239.5个时钟周期,适合高阻抗信号源(如光敏电阻)。
I2C配置函数(I2C_Configuration)功能:
初始化I2C1接口(PB6-SCL, PB7-SDA),用于驱动OLED显示屏。
-
时钟速度:100kHz是I2C标准模式,兼顾速度和稳定性。
-
开漏引脚:I2C协议要求SCL和SDA均为开漏输出,需外部上拉电阻。
4.2.2 主程序逻辑
uint16_t Get_ADC_Value(void)
{
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 等待转换完成
return ADC_GetConversionValue(ADC1);
}
void Display_Light_Intensity(uint16_t value)
{
char buffer[16];
// 显示ADC原始值
sprintf(buffer, "ADC: %4d", value);
OLED_ShowString(0, 2, (uint8_t *)buffer);
// 显示光强状态
if(value > LIGHT_THRESHOLD) {
OLED_ShowString(0, 4, (uint8_t *)"Status: Bright ");
GPIO_SetBits(GPIOC, GPIO_Pin_13); // LED灭(低电平点亮)
} else {
OLED_ShowString(0, 4, (uint8_t *)"Status: Dark ");
GPIO_ResetBits(GPIOC, GPIO_Pin_13); // LED亮
}
}
int main(void)
{
uint16_t adc_value = 0;
uint8_t digital_state = 0;
// 初始化系统时钟
SystemInit();
// 外设初始化
GPIO_Configuration();
ADC_Configuration();
I2C_Configuration();
// OLED初始化
OLED_Init();
OLED_Clear();
OLED_ShowString(0, 0, (uint8_t *)"Light Sensor");
while(1)
{
// 读取模拟量
adc_value = Get_ADC_Value();
// 读取数字量
digital_state = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1);
// 显示光强信息
Display_Light_Intensity(adc_value);
// 简单延时
Delay_ms(200);
}
}
ADC值读取(Get_ADC_Value):
-
EOC标志:检查ADC转换结束标志位,确保数据有效。
-
返回值:12位ADC结果(0-4095),对应电压0-3.3V。
光强显示与LED控制(Display_Light_Intensity):
-
阈值判断:
LIGHT_THRESHOLD
为预设的光强阈值,超过则判定为“明亮”。 -
LED逻辑:PC13连接LED,低电平点亮(STM32F103C8T6的LED电路设计特性)。
主循环:
-
双模式检测:同时读取模拟量(ADC)和数字量(DOUT),提高灵活性。
-
延时控制:200ms的采样间隔避免频繁刷新,平衡响应速度与稳定性。
五、系统调试与优化
光敏电阻特性测试:
- 在完全黑暗环境下记录ADC值
- 在不同光照条件下(如室内光、阳光直射)记录ADC值
- 绘制光照强度-ADC值曲线
软件滤波算法:
#define FILTER_SIZE 5
uint16_t Moving_Average_Filter(void)
{
static uint16_t filter_buf[FILTER_SIZE] = {0};
static uint8_t filter_index = 0;
uint32_t sum = 0;
filter_buf[filter_index++] = Get_ADC_Value();
if(filter_index >= FILTER_SIZE) filter_index = 0;
for(uint8_t i=0; i<FILTER_SIZE; i++) {
sum += filter_buf[i];
}
return sum / FILTER_SIZE;
}
六、应用扩展
自动调光系统:
根据光照强度控制PWM的占空比达到亮度调节的目的。
void PWM_Control(uint16_t light_level)
{
// 根据光照强度控制PWM输出
// 光照越强,PWM占空比越小
uint16_t duty_cycle = 100 - (light_level * 100 / 4095);
TIM_SetCompare1(TIM3, duty_cycle);
}
七、总结
本系统实现了基于STM32F103C8T6的光敏电阻检测方案,通过标准库开发保证了良好的可移植性,可根据实际需求扩展为各种光控应用系统。