实验目的:本文基于stm32开发板做一个模拟光控开关的实验,实验最后的实现的功能是,在光照强度大于临界值LED灯就变暗,如果光照强度小于临界值LED灯就变亮。
一、硬件设计
1.本实验所用到的硬件资源
1:一块stm32开发板
2:一个光敏电阻
3:手电筒
2.原理图
LS1表示光敏电阻,PF8具有ADC3_IN6的功能。如果自己的开发板没有PF8引脚的可以选择一个具有ADC功能的引脚来替换,对实验结果不会有影响。
3.工作原理
光敏电阻特性:光照强度越强,电阻就越小,光照强度越弱,电阻就越大。
通过ADC采集光敏电阻的电压:如果采集到的电压越大,就说明此时的电阻就越大,从而说明光照强度越弱。
我们就可以通过判断ADC转换的值来判断此时外界的光照强度。在判断之后就可以做出相应的命令,例如LED的亮灭,蜂鸣器发声与不发声,等等其他的功能。
二、软件设计
1.主函数mian.c
代码如下(示例):
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "adc.h"
#include "led.h"
int main(void)
{
u8 adcx;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组,给串口使用的
delay_init();//延时初始化
LED_Init();//led(PB5)初始化
uart_init(115200);//串口初始化
ADC3_CH6_Init();//ADC3_CH6初始化
while(1)
{
adcx=Lsens_Get_Val();
printf("光照强度为=%d\r\n",adcx);
delay_ms(500);
if(adcx<5)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_5); //PB.5 输出低
}
else
{
GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
}
}
}
2.ADC.c
代码如下(示例):
#include "sys.h"
#include "adc.h"
#include "delay.h"
#include "stdio.h"
void ADC3_CH6_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF | RCC_APB2Periph_ADC3, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init( GPIOF, &GPIO_InitStruct);//管脚初始化
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//把时钟分频为12MHz,ADC的时钟不能超过14M,超过的话可能不准。
ADC_DeInit(ADC3);
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//指定是否是连续转换还是单个转换。也就是连续采集还是单次采集。我这里不管配置什么都是一直在采集
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Left;//数据向右对齐
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//单通道的独立模式
ADC_InitStruct.ADC_NbrOfChannel=1;//顺序进行规则转换的ADC通道的数目
ADC_InitStruct.ADC_ScanConvMode=DISABLE;//模数转换工作在单通道模式
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
ADC_Init( ADC3, & ADC_InitStruct);//ADC模式初始化
ADC_Cmd( ADC3, ENABLE);//ADC使能
ADC_ResetCalibration(ADC3);//复位校准使能
while(ADC_GetResetCalibrationStatus(ADC3));//等待复位校准完成
ADC_StartCalibration(ADC3);//开启AD校准
while(ADC_GetCalibrationStatus(ADC3));//等待AD校准完成
}
u16 Get_AdcValue(u8 ch)
{
ADC_RegularChannelConfig(ADC3, ch, 1, ADC_SampleTime_239Cycles5);
//ADC1,通道1,
ADC_SoftwareStartConvCmd(ADC3, ENABLE);//ADC1的软件转换启动使能
while(ADC_GetFlagStatus( ADC3, ADC_FLAG_EOC)==RESET);//等待转换结束
return ADC_GetConversionValue(ADC3);//返回转换值
}
//读取Light Sens的值
u8 Lsens_Get_Val(void)
{
u32 temp_val=0;
u8 result;
u8 t;
for(t=0;t<10;t++)
{
temp_val+=Get_AdcValue(ADC_Channel_6); //读取ADC值
delay_ms(5);
}
temp_val/=10;//得到平均值
if(temp_val>3000)temp_val=3000;//电压最大值为3.3v,3.3v对应的ADC转换数据为4096。所以读到的数据不会超过4096
// 光照最强的时候,电阻最小,电压也最小,ADC转换出来的数据也最小
// 光照最弱的时候,电阻最大,电压也最大,ADC转换出来的数据也最大
//我希望把光照等级分成10份,光照最强的时候为10,最弱的时候为0。在正常状态数据为(0-4),打开手电筒数据为(5-10)。
result=10-(temp_val/300);
return result;
}
3.ADC.h
代码如下(示例):
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
void ADC3_CH6_Init(void);
u16 Get_AdcValue(u8 ch);
u16 Get_Adc_Average(u8 ch,u8 times);
u8 Lsens_Get_Val(void);
#endif
验证
当我关闭手电筒的时候,串口打印出来的数据小于5,此时LED变亮。
当我用手电筒照着光敏电阻时,串口打印出来的数据大于等于5,此时LED变暗。
说明此时模拟楼道光控开关试验成功。