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

news2024/11/28 9:47:58

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){//初始化AD
	   RCC_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();//初始化OLED
	AD_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){//初始化AD
	   RCC_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();//初始化OLED
	AD_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){//初始化AD
	   RCC_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();//初始化OLED
	AD_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所以要加3
        OLED_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);
	}
}

效果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1069978.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql存储-EAV模式

Mysql存储-EAV模式 最近又又又搞一点新东西&#xff0c;要整合不同业务进行存储和查询&#xff0c;一波学习过后总结了一下可扩展性MAX的eav模式存储。 在eav这里的数据结构设计尤为关键&#xff0c;需要充分考虑你需要使用的字段、使用场景&#xff0c;当数据结构设计完成后便…

skywalking功能介绍

服务 服务信息 请求接口后查看skywalking&#xff0c;可以看到有一个请求&#xff0c;响应时间为1852ms&#xff0c;性能指数Apdex为0.5。 详细表盘 点进应用可以看到表盘 可以看到显示有一个slow endpoints&#xff0c;就是我请求的这个接口。 JVM信息 也可以看到JVM信息。…

点餐小程序实战教程06-首页开发

用户注册功能开发好了之后&#xff0c;我们就要开发小程序&#xff0c;首先我们是规划小程序的功能模块&#xff0c;我们一共是四个模块&#xff0c;分别是首页、订单、消息和我的。 首页我们主要是点餐的功能&#xff0c;可以选择菜品&#xff0c;加入到购物车&#xff0c;然…

deckGL自定义图层学习笔记

1.自定义图层 当使用DeckGL提供的图层还无法满足需求时&#xff08;https://deck.gl/docs/api-reference/layers&#xff09;&#xff0c;可能就需要自定义图层了。在DeckGL中有常见的三种自定义图层的方式 创建复合层&#xff08;composite layers.&#xff09;——复合层是一…

ffmpeg从一个视频中提取音频

ffmpeg -i ~/video/video.mp4 -vn -acodec copy ~/video/audioFile.m4a 从video.mp4中提取音频到文件audioFile.m4a中 查看提取的音频文件 ffprobe ~/video/audioFile.m4a

OneDrive下的OneNote扩容方法,及查看OneDrive容量的方法(详细图文教程)

目录 一、内存不足的问题二、土豪续费扩容法三、X宝扩容法3.1 购买链接3.2 登录接口3.3 详细图文操作过程3.3.1 获取链接&#xff1a;3.3.2 用订单号和获取链接扩容&#xff1a; 3.4 扩容后的容量 四、查看自己OneDrive的容量五、总结 一、内存不足的问题 一直都在用OneNote记…

STM32H723 CubeMX 三路FDCAN 代码

时钟频率 FDCAN1 设置250kbit/s FDCAN2 设置500kbit/s FDCAN3 设置500kbit/s fdcan.c /* USER CODE BEGIN Header */ /********************************************************************************* file fdcan.c* brief This file provides code fo…

【刷题篇】回溯算法(深度优先搜索(二))

文章目录 岛屿数量电话号码的字母组合组合总和活字印刷 岛屿数量 给你一个由 ‘1’&#xff08;陆地&#xff09;和 ‘0’&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直…

CentOS7.9中使用packstack安装train版本

这里写目录标题 材料准备为什么选择packstack安装静态ip系统配置使用阿里云yum源安装packstack部署openstack 安装成功和后续使用all in one模式下虚拟机外网和浮动ip原理讲解nat网桥的创建方法 材料准备 ecs云服务器8核心16g内存一台&#xff0c;系统盘100GB&#xff0c;系统…

2.2 数据通信的基础知识

前言&#xff1a; 2.2.1 数据通信的基础知识 **笔记**&#xff1a;2.2.1 数据通信系统的模型 --- **1. 数据通信系统组成**&#xff1a; - 三大部分&#xff1a; 1. 源系统 (发送端) 2. 传输系统 (传输网络) 3. 目的系统 (接收端) --- **2. 源系统**&#xff1a; -…

vue-4

一、文章内容概括 1.组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; ​ scoped解决样式冲突/data是一个函数 2.组件通信 组件通信语法父传子子传父非父子通信&#xff08;扩展&#xff09; 3.进阶语法 v-model原理v-model应用于组件sync修饰符ref和$refs$nex…

SAP SMARTFORMS 文本框显示默认浏览器

问题描述&#xff1a;新上的SAP系统SMARTFORMS文本框显示浏览器&#xff0c;导致无法拉取系统变量 解决方法&#xff1a; 类CL_COS_UTILITIES做隐式增强 IF sy-tcode SMARTFORMS.rv_is_s4h .ENDIF. 然后执行程序&#xff1a;RSCPSETEDITOR 把这俩√去掉后激活即可

MISRA C 2012 阅读笔记

背景 C语言诞生至今已有50年&#xff0c;因其语言简洁&#xff0c;语法丰富&#xff0c;可移植性高&#xff0c;和执行效率高等优点&#xff0c;至今仍保持着强大的生命力&#xff0c;在各个行业发挥着作用。 然而C语言的一些优点有时候也是一把双刃剑&#xff0c;在使用者使用…

Acwing.886 求组合数Ⅱ

题目 给定n组询问&#xff0c;每组询问给定两个整数a&#xff0c; b&#xff0c;请你输出 的值。 输入格式 第一行包含整数n。 接下来n行&#xff0c;每行包含—组a和b。 输出格式 共n行&#xff0c;每行输出—个询问的解。 数据范围 1<n≤10000, 1 <b<a≤105…

Acwing.889 满足条件的01序列

题目 给定n个0和n个1&#xff0c;它们将按照某种顺序排成长度为2n的序列&#xff0c;求它们能排列成的所有序列中&#xff0c;能够满足任意前缀序列中0的个数都不少于1的个数的序列有多少个。 输出的答案对109&#xff0b;7取模。 输入格式 共一行&#xff0c;包含整数n。 …

【python】python虚拟环境--20231008

https://blog.csdn.net/m0_69023493/article/details/129158656 安装好python和pip 略 新建python虚拟空间 安装virtualenv pip install virtualenv -i https://pypi.tuna.tsinghua.edu.cn/simple安装virtualenvwrapper-win&#xff08;可选&#xff09; pip install vir…

软件测试/测试开发丨接口测试学习笔记-常见的接口协议

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27726 一、网络模型 二、常见接口协议 RPC协议 RPC(remote procedure call)以本地代码调用的方式实现远程执行主要用于公司内部的服务调用 优点 传输效…

3分钟轻松实现网关网口连接罗克韦尔AB CompactLogix系列PLC

目录 EG网关网口连接罗克韦尔AB CompactLogix系列PLC 一. 准备工作 1.1 在对接前我们需准备如下物品 1.2 EG20网关准备工作 1.3 PLC准备工作 二. EMCP平台设置 2.1 新增EG设备 2.2 远程配置网关 2.3 网关绑定 2.4 通讯参数设置 2.5 创建设备驱动 2.5.1 添加变量 2.…

springcloud之项目实战搭建单体

写在前面 在上篇文章 中我们介绍了项目的整体内容以及架构&#xff0c;本文就开始实现一个单体的版本&#xff0c;在之后的文章中&#xff0c;在使用springcloud相关组件将这个单体的版本一步步的拆分为微服务的版本&#xff0c;在开始之前再贴下组件图&#xff1a; 本文我们分…

win11 vscode配置c/c++,使用mingw编译器

文章目录 第一步&#xff1a;装好vscode第二步&#xff1a;下载 mingw创建一个文件夹作为C或者C的项目文件夹&#xff0c;用vscode打开 第一步&#xff1a;装好vscode 之前使用python时装过 第二步&#xff1a;下载 mingw 官网 3.从这个界面一直往下滑 找到&#xff1a; 下…