Stm32_标准库_8_ADC_光敏传感器_测量具体光照强度

2023-10-08 20:52

本文主要是介绍Stm32_标准库_8_ADC_光敏传感器_测量具体光照强度,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ADC简介

在这里插入图片描述
测量方式

在这里插入图片描述
采用二分法比较数据

IO通道

在这里插入图片描述
ADC基本结构及配置路线

在这里插入图片描述


获取数字变量需要用到用到光敏电阻的AO口,AO端口接在PA0引脚即可
在这里插入图片描述
测得的模拟数据与实际光照强度之间的关系为

光照强度 = 100 - 模拟量 / 40;

代码:

完整朴素代码:

#include "stm32f10x.h"    // Device header
#include "Delay.h"
#include "OLED.h"GPIO_InitTypeDef GPIO_InitStruct;
ADC_InitTypeDef ADC_InitStruct;void AD_Init(void){//初始化ADRCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIOA的时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADC模块工作时钟 72 / 6 = 12MHZ/*配置GPIO口*/GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;//模拟输入GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);/*在规则组列表第一个位置,写入通道0这个通道*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);/*结构体初始化ADC*/ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//单次转换ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//触发方式,不使用外部触发,即软件触发ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//ADC工作模式为独立模式ADC_InitStruct.ADC_NbrOfChannel = 1;//通道数目ADC_InitStruct.ADC_ScanConvMode = DISABLE;//非扫描ADC_Init(ADC1, &ADC_InitStruct);//开启ADC电源ADC_Cmd(ADC1, ENABLE);/*给ADC校准*/ADC_ResetCalibration(ADC1);//复位校准while(ADC_GetResetCalibrationStatus(ADC1) == SET);//返回ADC1复位校准状态ADC_StartCalibration(ADC1);//开始校准while(ADC_GetCalibrationStatus(ADC1) == SET);//等待校准完成
}uint16_t AD_Getvailue(void){//获取信息ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发转换while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待转换完成return ADC_GetConversionValue(ADC1);//读取数据
}uint16_t Reality_ADLight(uint16_t ADCnum){//获取光照强度return 100 - ADCnum / 40;
}int main(void){OLED_Init();//初始化OLEDAD_Init();while(1){uint16_t num  = AD_Getvailue();uint16_t num1 = Reality_ADLight(num); OLED_ShowString(1, 1, "ADO:");OLED_ShowNum(1, 5, num, 5);OLED_ShowString(2, 1, "LUX:");OLED_ShowNum(2, 5, num1, 3);Delay_ms(300);}
}

效果:

在这里插入图片描述
此代码的不足之处在于每次写入数字都会提前占据固定位置,这个固定位置在整个过程是不能更改的,十分影响观感

所以添加求数字长度的函数,方便随时捕捉并调正所占空间
添加代码:

uint8_t length(uint16_t num){uint8_t length = 0;while(num > 0){num = num / 10;length = length + 1;}return length;
}

完整优化代码1:

#include "stm32f10x.h"    // Device header
#include "Delay.h"
#include "OLED.h"GPIO_InitTypeDef GPIO_InitStruct;
ADC_InitTypeDef ADC_InitStruct;void AD_Init(void){//初始化ADRCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIOA的时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADC模块工作时钟 72 / 6 = 12MHZ/*配置GPIO口*/GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;//模拟输入GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);/*在规则组列表第一个位置,写入通道0这个通道*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);/*结构体初始化ADC*/ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//单次转换ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//触发方式,不使用外部触发,即软件触发ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//ADC工作模式为独立模式ADC_InitStruct.ADC_NbrOfChannel = 1;//通道数目ADC_InitStruct.ADC_ScanConvMode = DISABLE;//非扫描ADC_Init(ADC1, &ADC_InitStruct);//开启ADC电源ADC_Cmd(ADC1, ENABLE);/*给ADC校准*/ADC_ResetCalibration(ADC1);//复位校准while(ADC_GetResetCalibrationStatus(ADC1) == SET);//返回ADC1复位校准状态ADC_StartCalibration(ADC1);//开始校准while(ADC_GetCalibrationStatus(ADC1) == SET);//等待校准完成
}uint16_t AD_Getvailue(void){//获取信息ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发转换while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待转换完成return ADC_GetConversionValue(ADC1);//读取数据
}
uint8_t length(uint16_t num){uint8_t length = 0;while(num > 0){num = num / 10;length = length + 1;}return length;
}
uint16_t Reality_ADLight(uint16_t ADCnum){//获取光照强度return 100 - ADCnum / 40;
}int main(void){OLED_Init();//初始化OLEDAD_Init();while(1){uint16_t num  = AD_Getvailue();uint16_t num1 = Reality_ADLight(num); OLED_ShowString(1, 1, "ADO:");OLED_ShowNum(1, 5, num, length(num));OLED_ShowString(2, 1, "LUX:");OLED_ShowNum(2, 5, num1, length(num1));Delay_ms(300);OLED_Clear();}
}

效果:在这里插入图片描述

写入数据是采用覆盖制,例如上次写入的数据是1234,本次写入的数据是999,那么此时展现的效果为9994,由于ADO取值范围为[0 ~4095],LUX(光照强度)取值范围为[1, 100],所以为了不影响数据的合理性,所以必须要在每次写入新数据时必须要清理一下OLED

但是由于提供的清屏函数每次都是将全部数据清理掉,所以画面刷新也要从新再全部刷新一次所以整体画面会不连贯

所以我写入了一个只清屏某个部分的函数
添加代码:

/* 直接用清屏函数整体刷新会导致OLED画面不连贯清除行函数:保留本行字符串,清除本行剩余部分row:清除的具体行len:不希望被清除的字符串长度
*/void OLED_LoactionClear(uint8_t row, uint8_t len)
{  uint8_t i, j;for (j = row * 2 - 2; j < row * 2; j++){OLED_SetCursor(j, len * 8);for(i = len * 8; i < 128; i++){OLED_WriteData(0x00);}}
}

放入位置

需要将其copy到OLED.c文件下,并在OLED.h文件内声明一下
在这里插入图片描述
在这里插入图片描述
具体函数使用方法:

OLED_LoactionClear(uint8_t row, uint8_t len);
此函数有两个参数:

其中row指你想要进行清屏操作的具体行,OLED上一共能显示4行
其中len代表row行从左到右len长度区间的字符串将会被保留,row行剩余其他数据将全被清除

完整优化代码2:

#include "stm32f10x.h"    // Device header
#include "Delay.h"
#include "OLED.h"GPIO_InitTypeDef GPIO_InitStruct;
ADC_InitTypeDef ADC_InitStruct;void AD_Init(void){//初始化ADRCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIOA的时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADC模块工作时钟 72 / 6 = 12MHZ/*配置GPIO口*/GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;//模拟输入GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);/*在规则组列表第一个位置,写入通道0这个通道*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);/*结构体初始化ADC*/ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//单次转换ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//触发方式,不使用外部触发,即软件触发ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//ADC工作模式为独立模式ADC_InitStruct.ADC_NbrOfChannel = 1;//通道数目ADC_InitStruct.ADC_ScanConvMode = DISABLE;//非扫描ADC_Init(ADC1, &ADC_InitStruct);//开启ADC电源ADC_Cmd(ADC1, ENABLE);/*给ADC校准*/ADC_ResetCalibration(ADC1);//复位校准while(ADC_GetResetCalibrationStatus(ADC1) == SET);//返回ADC1复位校准状态ADC_StartCalibration(ADC1);//开始校准while(ADC_GetCalibrationStatus(ADC1) == SET);//等待校准完成
}uint16_t AD_Getvailue(void){//获取信息ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发转换while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待转换完成return ADC_GetConversionValue(ADC1);//读取数据
}
uint8_t length(uint16_t num){uint8_t length = 0;while(num > 0){num = num / 10;length = length + 1;}return length;
}
uint16_t Reality_ADLight(uint16_t ADCnum){//获取光照强度return 100 - ADCnum / 40;
}int main(void){OLED_Init();//初始化OLEDAD_Init();while(1){uint16_t num  = AD_Getvailue();uint16_t num1 = Reality_ADLight(num); OLED_ShowString(1, 1, "ADO:");OLED_LoactionClear(1, length(num) + 3);//"ADO:"长度为3所以要加3OLED_ShowNum(1, 5, num, length(num));OLED_ShowString(2, 1, "LUX:");OLED_LoactionClear(2, length(num1) + 3);OLED_ShowNum(2, 5, num1, length(num1));Delay_ms(300);}
}

效果:

在这里插入图片描述

这篇关于Stm32_标准库_8_ADC_光敏传感器_测量具体光照强度的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/167933

相关文章

MySQL分区表的具体使用

《MySQL分区表的具体使用》MySQL分区表通过规则将数据分至不同物理存储,提升管理与查询效率,本文主要介绍了MySQL分区表的具体使用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、分区的类型1. Range partition(范围分区)2. List partition(列表分区)3. H

Java Multimap实现类与操作的具体示例

《JavaMultimap实现类与操作的具体示例》Multimap出现在Google的Guava库中,它为Java提供了更加灵活的集合操作,:本文主要介绍JavaMultimap实现类与操作的... 目录一、Multimap 概述Multimap 主要特点:二、Multimap 实现类1. ListMult

go rate 原生标准限速库的使用

《gorate原生标准限速库的使用》本文主要介绍了Go标准库golang.org/x/time/rate实现限流,采用令牌桶算法控制请求速率,提供Allow/Reserve/Wait方法,具有一定... 目录介绍安装API介绍rate.NewLimiter:创建限流器limiter.Allow():请求是否

golang中slice扩容的具体实现

《golang中slice扩容的具体实现》Go语言中的切片扩容机制是Go运行时的一个关键部分,它确保切片在动态增加元素时能够高效地管理内存,本文主要介绍了golang中slice扩容的具体实现,感兴趣... 目录1. 切片扩容的触发append 函数的实现2. runtime.growslice 函数gro

Golang interface{}的具体使用

《Golanginterface{}的具体使用》interface{}是Go中可以表示任意类型的空接口,本文主要介绍了Golanginterface{}的具体使用,具有一定的参考价值,感兴趣的可以了... 目录一、什么是 interface{}?定义形China编程式:二、interface{} 有什么特别的?✅

Qt之QMessageBox的具体使用

《Qt之QMessageBox的具体使用》本文介绍Qt中QMessageBox类的使用,用于弹出提示、警告、错误等模态对话框,具有一定的参考价值,感兴趣的可以了解一下... 目录1.引言2.简单介绍3.常见函数4.按钮类型(QMessage::StandardButton)5.分步骤实现弹窗6.总结1.引言

PyQt5 QDate类的具体使用

《PyQt5QDate类的具体使用》QDate是PyQt5中处理日期的核心类,本文主要介绍了PyQt5QDate类的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录核心功能常用方法及代码示例​1. 创建日期对象​2. 获取日期信息​3. 日期计算与比较​4. 日

SQL Server中的PIVOT与UNPIVOT用法具体示例详解

《SQLServer中的PIVOT与UNPIVOT用法具体示例详解》这篇文章主要给大家介绍了关于SQLServer中的PIVOT与UNPIVOT用法的具体示例,SQLServer中PIVOT和U... 目录引言一、PIVOT:将行转换为列核心作用语法结构实战示例二、UNPIVOT:将列编程转换为行核心作用语

Pandas透视表(Pivot Table)的具体使用

《Pandas透视表(PivotTable)的具体使用》透视表用于在数据分析和处理过程中进行数据重塑和汇总,本文就来介绍一下Pandas透视表(PivotTable)的具体使用,感兴趣的可以了解一下... 目录前言什么是透视表?使用步骤1. 引入必要的库2. 读取数据3. 创建透视表4. 查看透视表总结前言

Qt中QUndoView控件的具体使用

《Qt中QUndoView控件的具体使用》QUndoView是Qt框架中用于可视化显示QUndoStack内容的控件,本文主要介绍了Qt中QUndoView控件的具体使用,具有一定的参考价值,感兴趣的... 目录引言一、QUndoView 的用途二、工作原理三、 如何与 QUnDOStack 配合使用四、自