11.STM32F407ZGT6-光敏传感器
STM32F407ZGT6 光敏传感器采集
参考:
1.正点原子
前言:
本笔记的主要目的和意义就是,再次练习ADC的使用。
33.1 光敏传感器简介
光敏传感器是最常见的传感器之一,它的种类繁多,主要有:光电管、光电倍增管、光敏电阻、光敏三极管、太阳能电池、红外线传感器、紫外线传感器、光纤式光电传感器、色彩传感器、CCD 和 CMOS 图像传感器等。光传感器是目前产量最多、应用最广的传感器之一,它在自动控制和非电量电测技术中占有非常重要的地位。
光敏传感器是利用光敏元件将光信号转换为电信号的传感器,它的敏感波长在可见光波长附近,包括红外线波长和紫外线波长。光传感器不只局限于对光的探测,它还可以作为探测元件组成其他传感器,对许多非电量进行检测,只要将这些非电量转换为光信号的变化即可。
探索者 STM32F407 开发板板载了一个光敏二极管(光敏电阻),作为光敏传感器,它对光的变化非常敏感。光敏二极管也叫光电二极管。光敏二极管与半导体二极管在结构上是类似的,其管芯是一个具有光敏特征的 PN 结,具有单向导电性,因此工作时需加上反向电压。无光照时,有很小的饱和反向漏电流,即暗电流,此时光敏二极管截止。当受到光照时,饱和反向漏电流大大增加,形成光电流,它随入射光强度的变化而变化。当光线照射 PN 结时,可以使 PN结中产生电子一空穴对,使少数载流子的密度增加。这些载流子在反向电压下漂移,使反向电流增加。因此可以利用光照强弱来改变电路中的电流。
利用这个电流变化,我们串接一个电阻,就可以转换成电压的变化,从而通过 ADC 读取电压值,判断外部光线的强弱。
本章,我们利用 ADC3 的通道 5(PF7)来读取光敏二极管电压的变化,从而得到环境光线的变化,并将得到的光线强度,通过串口输出。关于 ADC 的介绍,前面已经有详细介绍了,这里我们就不再细说了。
33.2 硬件设计
1. 例程功能
通过 ADC3 的通道 5(PF7)读取光敏传感器(LS1)的电压值,并转换为 0~100 的光线强度值,同过串口输出。光线越亮,值越大;光线越暗,值越小。大家可以用餐厅纸多次折叠遮盖 LS1和用手电筒照射 LS1,来查看光强变化。
2. 硬件资源
1)串口 1(PA9/PA10 连接在板载 USB 转串口芯片 CH340 上面)
2)ADC3 :通道 5 – PF7
3)光敏传感器 – PF7
3. 原理图
我们主要来看看光敏传感器和开发板的连接,如下图所示:
图中,LS1 是光敏二极管,外观看与贴片 LED 类似(实物在开发板 OLED 右侧),R76 为其提供反向电压,当环境光线变化时,LS1 两端的电压也会随之改变,从而通过 ADC3_IN5 通道,读取 LIGHT_SENSOR(PF7)上面的电压,即可得到环境光线的强弱。光线越强,电压越低,光线越暗,电压越高。
33.3 程序设计
33.3.1 ADC 的 HAL 库驱动
本实验用到的 ADC 的 HAL 库 API 函数前面都介绍过,具体调用情况请看程序解析部分。下面介绍读取光敏传感器 ADC 值的配置步骤。
读取光敏传感器 ADC 值配置步骤
1)开启 ADCx 和通道输出的 GPIO 时钟,配置该 IO 口的复用功能输出
首先开启 ADCx 的时钟,然后配置 GPIO 为复用功能输出。本实验我们默认用到 ADC3 通道 5,对应 IO 是 PF7,它们的时钟开启方法如下:
__HAL_RCC_ADC3_CLK_ENABLE (); /* 使能 ADC3 时钟 /
__HAL_RCC_GPIOF_CLK_ENABLE(); / 开启 GPIOF 时钟 */
IO 口复用功能是通过函数 HAL_GPIO_Init 来配置的。
2)设置 ADC3,开启内部温度传感器
调用 HAL_ADC_Init 函数来设置 ADC3 时钟分频系数、分辨率、模式、扫描方式、对齐方式等信息。
注意:该函数会调用:HAL_ADC_MspInit 回调函数来完成对 ADC 底层的初始化,包括:ADC3 时钟使能、ADC3 时钟源的选择等。
3)配置 ADC 通道并启动 AD 转换器
调用 HAL_ADC_ConfigChannel()函数配置 ADC3 通道 5,根据需求设置通道、序列、采样时间和校准配置单端输入模式或差分输入模式等。然后通过 HAL_ADC_Start 函数启动 AD 转换器。
4)读取 ADC 值,转换为光线强度值
这里选择查询方式读取,在读取 ADC 值之前需要调用 HAL_ADC_PollForConversion 等待上一次转换结束。然后就可以通过 HAL_ADC_GetValue 来读取 ADC 值。最后把得到的 ADC 值转换为 0~100 的光线强度值。
33.3.2 程序解析
1. LSENS 驱动代码
首先是光敏传感器初始化函数,其定义如下:(STM32CubeMX配置,自动生成)
void MX_ADC3_Init(void)
{
/* USER CODE BEGIN ADC3_Init 0 */
/* USER CODE END ADC3_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC3_Init 1 */
/* USER CODE END ADC3_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc3.Instance = ADC3;
hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc3.Init.Resolution = ADC_RESOLUTION_12B;
hadc3.Init.ScanConvMode = DISABLE;
hadc3.Init.ContinuousConvMode = DISABLE;
hadc3.Init.DiscontinuousConvMode = DISABLE;
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc3.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc3.Init.NbrOfConversion = 1;
hadc3.Init.DMAContinuousRequests = DISABLE;
hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc3) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_5; /*配置ADC3的通道5*/
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC3_Init 2 */
/* USER CODE END ADC3_Init 2 */
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(adcHandle->Instance==ADC1)
{
/* USER CODE BEGIN ADC1_MspInit 0 */
/* USER CODE END ADC1_MspInit 0 */
/* ADC1 clock enable */
__HAL_RCC_ADC1_CLK_ENABLE();
/* USER CODE BEGIN ADC1_MspInit 1 */
/* USER CODE END ADC1_MspInit 1 */
}
else if(adcHandle->Instance==ADC3)
{
/* USER CODE BEGIN ADC3_MspInit 0 */
/* USER CODE END ADC3_MspInit 0 */
/* ADC3 clock enable */
__HAL_RCC_ADC3_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
/**ADC3 GPIO Configuration
PF7 ------> ADC3_IN5
*/
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/* USER CODE BEGIN ADC3_MspInit 1 */
/* USER CODE END ADC3_MspInit 1 */
}
}
光敏传感器初始化函数其实就是初始化 PF7 为不带上下拉的模拟模式和配置ADC3 通道5。
最后是读取光敏传感器值,函数定义如下:
uint32_t adc3_get_result(uint32_t ch)
{
/* 设置通道,序列和采样时间 */
//adc_channel_set(&hadc3, ch, 1, ADC_SAMPLETIME_480CYCLES);
HAL_ADC_Start(&hadc3); /* 开启 ADC */
HAL_ADC_PollForConversion(&hadc3, 10); /* 轮询转换 */
/* 返回最近一次 ADC3 规则组的转换结果 */
return (uint16_t)HAL_ADC_GetValue(&hadc3);
}
uint32_t adc3_get_result_average(uint32_t ch, uint8_t times)
{
uint32_t temp_val = 0;
uint8_t t;
for (t = 0; t < times; t++) /* 获取 times 次数据 */
{
temp_val += adc3_get_result(ch);
}
return temp_val / times; /* 返回平均值 */
}
/**
* @brief 读取光敏传感器值
* @param 无
* @retval 0~100:0,最暗;100,最亮
*/
uint32_t adc_get_lsens_val(void)
{
uint32_t temp_val = 0;
/* 读取平均值 */
temp_val = adc3_get_result_average(ADC_CHANNEL_5, 10);
temp_val /= 40;
if (temp_val > 100)
{
temp_val = 100;
}
return (100 - temp_val);
}
adc_get_lsens_val 函数用于获取当前光照强度,该函数通过 adc3_get_result_average 函数得到ADC3 通道 5 转换的电压值,经过简单量化后,处理成 0~100 的光强值。0 对应最暗,100 对应最亮。
2. main.c 代码
在 main.c 里面编写如下代码:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_TIM6_Init();
MX_RTC_Init();
MX_ADC1_Init();
MX_ADC3_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
uart_debug_task();
XL_TIME6_time_show();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
该部分的代码逻辑很简单,初始化各个外设之后,进入死循环,XL_TIME6_time_show 周期输出光敏的值。
3.光敏传感器获取及输出
void XL_TIME6_time_show(void)
{
if (g_time_1s >= TIME_PERIODIC_1S)
{
g_time_1s = g_time_1s - TIME_PERIODIC_1S;
float tmp_value = adc_get_temperature();
printf("tmp_value:%f\r\n", tmp_value);
uint32_t lsens_value = adc_get_lsens_val();
printf("lsens:%d\r\n", lsens_value);
}
if (g_time_10s >= TIME_PERIODIC_10S)
{
g_time_10s = g_time_10s - TIME_PERIODIC_10S;
RTC_TimeTypeDef sTime = {0};
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
printf("H:%d, M:%d, S:%d\r\n", sTime.Hours, sTime.Minutes, sTime.Seconds);
RTC_DateTypeDef sDate = {0};
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
printf("Y:%d, M:%d, W:%d, D:%d\r\n", sDate.Year, sDate.Month, sDate.WeekDay, sDate.Date);
}
}
33.4 下载验证
将程序下载到开发板后,光敏值周期输出,通过餐厅纸遮盖光敏传感器,光敏值在不断地变化:
我们可以通过给 LS1 不同的光照强度,来观察 LSENS_VAL 值的变化,光照越强,该值越大,光照越弱,该值越小,LSENS_VAL 值的范围是 0~100。
33.5 STM32CubeMX

33.6 源码路径
git clone git@gitee.com:xiaoliangliangcong/stm32.git
STM32F407ZGT6/11. light_sensor
更多推荐



所有评论(0)