一、编写读取AD值的函数,之后判断AD值,进行相应操作,比如点灯。
二、用ADC读取光敏传感器AO口输出,并配置ADC通道看门狗监控这条通道,当光线太暗时打开LED灯。
之后会再介绍可编程RGB灯带WS2812B。
光敏传感器有两个输出口,一个是DO(Digital Output),一个是AO(Analog Output),DO是数字输出,只会输出0或1,AO是模拟输出,可以配合stm32的ADC转换器得到数值存放在12位的寄存器中,因此AD值的范围是4095 - 0,即2的12次方-1到2的0次方。
#include "LightAD.h"
#include "stm32f10x.h" // Device header
#include "LED.h"
#define RCC_LightADC RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA
#define GPIO_LightADC GPIOA
#define PIN_LightADC GPIO_Pin_0
#define Channel_LightADC ADC_Channel_0
unsigned int HighThreshold = 3000;
unsigned int LowThreshold = 0;
//用AD转换配合模拟看门狗 单次转换非扫描
extern char BrightEnough;
先宏定义引脚和通道,定义三个变量,两个是看门狗监控的高低阈值,一个是main.c中定义的标志位,判断当前光线是否够亮。
void Light_GPIOInit()
{
GPIO_InitTypeDef GPIO_AD;
GPIO_AD.GPIO_Mode = GPIO_Mode_AIN;
GPIO_AD.GPIO_Pin = PIN_LightADC;
GPIO_AD.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_LightADC,&GPIO_AD);
}
配置GPIO口,注意GPIO模式要选择模拟输入。
void WatchDog_ADInit()
{
ADC_AnalogWatchdogSingleChannelConfig(ADC1, Channel_LightADC);
ADC_AnalogWatchdogThresholdsConfig(ADC1,HighThreshold,LowThreshold);
ADC_AnalogWatchdogCmd(ADC1,ADC_AnalogWatchdog_SingleRegEnable);
ADC_ITConfig(ADC1,ADC_IT_AWD,ENABLE);
}
配置看门狗,选择ADC1或2,选择对应通道,这里只有一个光敏传感器,一般选择通道0。
void Light_NVICInit()
{
NVIC_InitTypeDef nvic_struct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
nvic_struct.NVIC_IRQChannel = ADC1_2_IRQn;
nvic_struct.NVIC_IRQChannelCmd = ENABLE;
nvic_struct.NVIC_IRQChannelPreemptionPriority = 3;
nvic_struct.NVIC_IRQChannelSubPriority = 3;
NVIC_Init(&nvic_struct);
}
开启NVIC通道,优先级随便填。
void ADC1_2_IRQHandler()
{
if(ADC_GetITStatus(ADC1,ADC_IT_AWD) == 1)
{
BrightEnough = 0;
LEDOn();
ADC_ClearITPendingBit(ADC1,ADC_IT_AWD);
}
}
配置中断函数,当进入中断,则光线不够亮,并打开LED灯,最后清除标志位,注意中断标志位是ADC_IT_AWD。
void Light_ADInit()
{
//ADC1通道0在PA0
RCC_APB2PeriphClockCmd(RCC_LightADC,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//最高14Mhz,72 六分频 12Mhz
Light_GPIOInit();//1
//选择规则组的输入通道
//通道0,序列1,中等采样时间
ADC_RegularChannelConfig(ADC1, Channel_LightADC, 1, ADC_SampleTime_55Cycles5);
//初始化ADC
ADC_InitTypeDef adc_struct;
adc_struct.ADC_Mode = ADC_Mode_Independent;
adc_struct.ADC_DataAlign = ADC_DataAlign_Right;
adc_struct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
adc_struct.ADC_NbrOfChannel = 1;
adc_struct.ADC_ContinuousConvMode = DISABLE;
adc_struct.ADC_ScanConvMode = DISABLE;
//单次转换非扫描,只有一个通道
ADC_Init(ADC1,&adc_struct);
//配置看门狗和中断
WatchDog_ADInit();//2
Light_NVICInit();//3
ADC_Cmd(ADC1,ENABLE);
//先复位校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1) == 1);
//等待复位校准完成,当寄存器软件置1开始校准,校准完硬件置0
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) == 1);
}
配置ADC,选择规则组的输入通道,选择ADC独立模式,而不是ADC1和ADC2共同工作的合作模式,后者的优势是转换更快,但是没必要,ADC转换时间是很短的,下面会有计算。设置数据对齐方式是右对齐。一般都是设置右对齐,左右对齐的知识大家可以自行搜索。选择不设置外部触发源,选择单次触发,非扫描模式。通道数量设置为1条。之后记得复位校准,否则可能造成数值漂移。
//可以采用单次扫描更改扫描通道的方式来实现多通道采集,注意修改GPIO初始化引脚
unsigned int Light_GetADVal()
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == 0);
//等待规则组转换完成
//采样时间是55.5,转换固定周期是12.5,一共68个周期
//72MHZ6分频,12Mhz 68个周期,时间大约是1/12M * 68,约5.6us
ADC_SoftwareStartConvCmd(ADC1,DISABLE);
return ADC_GetConversionValue(ADC1);
}
读取AD值,AD转换周期如程序中注释所示,得出时间大约为5.6us,时间非常短。同时,如果有多个输入设备,可以采用单次非扫描的方式来达到单次连续扫描的效果,只需要在一个设备读取完之后更改下次要读取的通道,每次读取完之后更新AD数值和通道。
方法一只要在主函数中拿读取到的AD值判断后再执行功能就行,方法二用上面的看门狗代码配置后在看门狗中断中配置函数即可。
STM32的ADC功能很多,这里只是简单介绍基本使用的方法,剩下内容留待读者去探索。