首页 > 编程语言 >STM32:ADC采集光照(含完整源码)

STM32:ADC采集光照(含完整源码)

时间:2024-07-06 14:57:42浏览次数:20  
标签:include void 寄存器 STM32 源码 ADC ADC1 0x01CR2

需求
通过ADC转换实现光照亮度的数字化测量,最后将实时测量的结果打印在串口上。
在这里插入图片描述
一、ADC概要
   ADC全称是Analog-to-Digital Converter模数转换器,一般我们把模拟信号(Analog signal) 用A来进行简写,数字信号(digital signal) 用D来表示。
  自然界中绝大部分都是模拟信号,例如压力或温度的测量,为了方便储存,处理和传输,我们会通过ADC把模拟信号转化成数字形式给计算机处理。将模拟转换成数字的形式有两个步骤:采样和量化。
  本例中就是将光照亮度这种模拟量转换为具体的数字量。
在这里插入图片描述

二、实现流程
1.开时钟,分频,配IO
先打开原理图,找到该光敏电阻的位置。
在这里插入图片描述
由该电路可知VAL测量的是该光敏电阻的分压,而随着光照的变化,该光敏电阻的电压也会发生实时的波动。
此时我们就利于该光敏电压的变化来实现需求。
先找到CPU上对应的引脚
在这里插入图片描述
由上图可知该模块对应的引脚为PA5,ADC为ADC12_IN5,代表该引脚PA5是ADC1/2的通道5。
此时我们就开GPIOA的时钟和ADC1的通道(1,2都行,无所谓)
代码如下:

	RCC->APB2ENR |= 0x01<<9;//ADC1通道
	RCC->APB2ENR |= 0x01<<2;//使能GPIOA

下面就要进行分频了,由于本次使用的ADC的特征为12分辨率,而APB2所传输的频率为72M,所以此时我们要进行6分频(72 ÷ 6 = 12)在这里插入图片描述

	RCC->CFGR &= ~(0x03<<14);
	RCC->CFGR |= (0x02<<14);//6分频

最后进行PA5引脚的模式配置,由于要获得该引脚的电压值,而该电压值为动态变化的模拟量,所以此处要将模式置为模拟输入模式(0000)

GPIOA->CRL &= ~(0x0F<<20);//配置成模拟输入

2.配置ADC工作模式
首先打开手册找ADC1的控制寄存器(CR1,CR2),一个一个查看,看是否需要配置。
在这里插入图片描述
双模式选择也是必要的,此处选独立模式就行,因为只用这一个ADC1。
到这里ADC1的CR1寄存器的基本配置就算完成了。
下面来看ADC1的CR2寄存器。

在这里插入图片描述

再来看19-17位,规则通道组转换的外部触发条件。
我们这里选择111:SWSTART(软件触发)因为是通过软件代码置位来触发。

在这里插入图片描述
最后使能一下第0位:开启ADC并启动转换。

	//3、配置ADC的工作模式
	ADC1->CR1 &= ~(0x0F<<16);//独立模式
	ADC1->CR1 &= ~(0x01<<8);//不开扫描
	ADC1->CR2 |= 0x01<<20;//选择开启外部触发
	ADC1->CR2 |= 0x07<<17;//触发方式swsatrt(软件触发)
	ADC1->CR2 &= ~(0x01<<11);//选择数据右对齐
	ADC1->CR2 &= ~(0x01<<1);//关闭连续转换
	ADC1->CR2 |= 0x01<<0;//ADC使能

3.配置通道
由于该引脚PA5对应的是ADC12_IN5,所以我们只需要配置通道5即可。
配置通道在ADC规则序列寄存器和ADC采样时间寄存器中。
先找到SQR1寄存器
在这里插入图片描述
在这里插入图片描述
最后配置一下采样周期,周期越大越准,所以我选择了111:239.5周期。

	//配置一个通道:通道5,第一个转换,采样周期最大(239.5)
	ADC1->SQR1 &= ~(0x0F<<20);//规则组通道只转换一个(配置通道数量)
	//具体某个通道的配置
	ADC1->SQR3 &= ~(0x1F<<0);//0-5位清0
	ADC1->SQR3 |= 0x05<<0;//选择第一个转换通道5
	ADC1->SMPR2 |= 0x07<<15;//采样周期最大(239.5)

4.复位,AD校准
校准可有可无,不过为了更加保险,我还是加上了。
复位校准在CR2寄存器的第3位。
在这里插入图片描述
每次校准后会自动置位0,所以此处while(1)等待非0,若为1就等待,为0就校准完成,继续往下执行。

	ADC1->CR2 |= 0x01<<3;//启动复位校准
	//等待复位校准结束
	while((ADC1->CR2&(0x01<<3))!=0)//判断寄存器的位3是不是等于1
	{}
	ADC1->CR2 |= 0x01<<2;//启动AD校准
	//等待AD校准结束
	while((ADC1->CR2&(0x01<<2))!=0)//判断寄存器的位2是不是等于1,是1就等待
	{}

5.数值的获取
对于数值的获取,我是单独写了个函数来执行,放便主函数调用并发送给串口。
想要获取数据,就要让ADC的CR2寄存器的第22位置1转换一下
在这里插入图片描述
每转换一次,就代表着ADC1把数据传输到DR规则组通道数据寄存器上,该寄存器为16位,并且每传输一次,数据就会被覆盖一次。
所以此时我们让ADC的CR2寄存器的第22位置为1

那么什么时候代表转换完了?此时就要查看ADC的状态寄存器SR了在这里插入图片描述
可以看到,每一次转换结束时,ADC_SR寄存器的第一位就会置1,并且不用我们去清零,每当我们去ADC_DR读取数据时,就会自动清除。
那么此时我们就可判断转换结束位的0,1来进行数据的读取了。
最后,将读取到的光照强度数据打印即可。(之前已经给printf重定向了,会自动打印到串口中)

void GetLightValue()
{
	uint16_t Light=0;
	//让规则通道转换一次
	ADC1->CR2 |= 0x01<<22;
	while((ADC1->SR&(0x01<<1))==0)//判断寄存器的位2是不是等于1,是0就等待转换完成
	{}
	Light = ADC1->DR; //读规则组通道数据寄存器
	printf("光照强度参数 = %d \r\n",Light);
}


三、需求的实现
关键代码如下:
main.c

#include "stm32f10x.h"
#include "usart.h"
#include "stdio.h"
#include "delay.h"
#include "string.h"
#include "pwm.h"
#include "adc.h"

int main()
{
		NVIC_SetPriorityGrouping(5);//两位抢占两位次级
    Usart1_Config(); 
	  SysTick_Config(72000);
	  RGBpwm_Config();
	  uint8_t cai_count=0;
	  uint16_t cont=0;
	  Adc_Config();
    while(1)
    {	
	
	
			if(ledcnt[0]>=ledcnt[1]){//过去500ms
			ledcnt[0]=0;
					GetLightValue();
		}
    }
}

adc.c

#include "ADC.h"

void Adc_Config(void)
{
	//PA5
	//1、设置ADC的时钟(开时钟和时钟分频6分频)
	RCC->APB2ENR |= 0x01<<9;//ADC1通道
	RCC->APB2ENR |= 0x01<<2;//使能GPIOA
	
	RCC->CFGR &= ~(0x03<<14);
	RCC->CFGR |= (0x02<<14);//6分频
	//2、配置IO模式(模拟输入)
	GPIOA->CRL &= ~(0x0F<<20);//配置成模拟输入
	//3、配置ADC的工作模式
	ADC1->CR1 &= ~(0x0F<<16);//独立模式
	ADC1->CR1 &= ~(0x01<<8);//不开扫描
	ADC1->CR2 |= 0x01<<20;//选择开启外部触发
	ADC1->CR2 |= 0x07<<17;//触发方式swsatrt(软件触发)
	ADC1->CR2 &= ~(0x01<<11);//选择数据右对齐
	ADC1->CR2 &= ~(0x01<<1);//关闭连续转换
	ADC1->CR2 |= 0x01<<0;//ADC使能
	//配置一个通道:通道5,第一个转换,采样周期最大(239.5)
	ADC1->SQR1 &= ~(0x0F<<20);//规则组通道只转换一个(配置通道数量)
	//具体某个通道的配置
	ADC1->SQR3 &= ~(0x1F<<0);//0-5位清0
	ADC1->SQR3 |= 0x05<<0;//选择第一个转换通道5
	ADC1->SMPR2 |= 0x07<<15;//采样周期最大(239.5)

	ADC1->CR2 |= 0x01<<3;//启动复位校准
	//等待复位校准结束
	while((ADC1->CR2&(0x01<<3))!=0)//判断寄存器的位3是不是等于1
	{}
		ADC1->CR2 |= 0x01<<2;//启动AD校准
	//等待AD校准结束
	while((ADC1->CR2&(0x01<<2))!=0)//判断寄存器的位2是不是等于1,是1就等待
	{}
}

void GetLightValue()
{
	uint16_t Light=0;
	//让规则通道转换一次
	ADC1->CR2 |= 0x01<<22;
	while((ADC1->SR&(0x01<<1))==0)//判断寄存器的位2是不是等于1,是0就等待转换完成
	{}
	Light = ADC1->DR; //读规则组通道数据寄存器
	printf("光照强度参数 = %d \r\n",Light);
}


adc.h

#ifndef _ADC_H_
#define _ADC_H_
#include "stm32f10x.h"
#include "stdio.h"
void GetLightValue();

void Adc_Config(void);
#endif
		

delay.c

#include "stm32f10x.h"
#include "delay.h"

uint32_t systicktime=0;

uint16_t ledcnt[2]={0,1000};//500ms   每个任务执行的时间
uint16_t led2cnt[2]={0,2000};//700ms
uint16_t keycnt[2]={0,10};//10ms检测一次
void SysTick_Handler(void)//1ms调用一次
{
	//不需要清中断挂起位
	systicktime++;
	ledcnt[0]++;
	led2cnt[0]++;
	keycnt[0]++;
}

void Delay_ms(uint32_t time)
{
    uint32_t nowtime = systicktime;
		while(systicktime < time+nowtime);
}

void Delay_nus(uint32_t time)
{
    uint32_t i=0;
    for(i=0;i<time;i++){
        delay1us();
    }    
}

void Delay_nms(uint32_t time)
{
    uint32_t i=0;
    for(i=0;i<time;i++){
         Delay_nus(1000);//延时1ms
    }    
}


总结
1.先看该光敏电阻的电路图,分析如何获取光照的数值。
2.想到可以通过ADC转换得到光照的树数值,开始学习ADC的知识。
3.先看ADC的功能描述,然后开时钟,分频,配IO。
4.看手册中的ADC的控制寄存器,一个一个查看,看看究竟需要配置那些。
5.看该引脚的ADC是那个通道的,开始配置通道。
6.都配置完后进行复位校准和数据获取函数的编写。
7.最后在主函数按照需求调用即可。

标签:include,void,寄存器,STM32,源码,ADC,ADC1,0x01CR2
From: https://blog.csdn.net/m0_63150463/article/details/140229406

相关文章

  • 基于java+springboot+vue实现的图书商城管理系统(文末源码+Lw)283
     摘 要现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本图书商城管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理......
  • 基于java+springboot+vue实现的旅游推荐系统(文末源码+Lw)280
    摘 要传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装旅游推荐系统软件来发挥其高效地信息处理的作用,可以规范信息管理流程,让管理工作可以系统化和程序化,同时,旅游推荐系统的有效......
  • 基于java+springboot+vue实现的流浪动物管理系统(文末源码+Lw)277
     摘    要在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以,对流浪动物信息管理的提升,也为了对流浪动物信息进行更好的维护,流浪动物管理系统的出现就变得水到渠成......
  • 基于java+springboot+vue实现的药店管理系统(文末源码+Lw)285
    摘   要传统信息的管理大部分依赖于管理人员的手工登记与管理,然而,随着近些年信息技术的迅猛发展,让许多比较老套的信息管理模式进行了更新迭代,药品信息因为其管理内容繁杂,管理数量繁多导致手工进行处理不能满足广大用户的需求,因此就应运而生出相应的药店管理系统。本药店......
  • 基于java+springboot+vue实现的药店管理系统(文末源码+Lw)285
    摘   要传统信息的管理大部分依赖于管理人员的手工登记与管理,然而,随着近些年信息技术的迅猛发展,让许多比较老套的信息管理模式进行了更新迭代,药品信息因为其管理内容繁杂,管理数量繁多导致手工进行处理不能满足广大用户的需求,因此就应运而生出相应的药店管理系统。本药店......
  • Java计算机毕业设计信阳市多目的地同步导航系统(开题+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信阳市城市化进程的加快,交通网络日益复杂,市民出行需求日益多样化,对导航系统的要求也愈发提高。传统单一目的地的导航系统已难以满足市民在日常出......
  • 好久不见!写了一个自动截图神器~【附源码】
    文章目录前言新增功能介绍截图功能快捷键设置程序设计和使用介绍操作菜单栏选择点击坐标点选择图片选择截图区域快捷键设置表格循环次数状态栏使用案例源代码前言好久没更新文章了。上一次更新是在4月16日差不多,也只是写了一个错误集,没什么太多内容。这一次,算是复......
  • 毕业设计-基于Springboot+Vue的在线考试系统的设计与实现(源码+LW+包运行)
    源码获取:https://download.csdn.net/download/u011832806/89456184基于SpringBoot+Vue的在线考试系统开发语言:Java数据库:MySQL技术:SpringBoot+MyBatis+Vue.js工具:IDEA/Ecilpse、Navicat、Maven系统演示视频:链接:https://pan.baidu.com/s/1ylSj7umVPabcPHK9oO5psA?pwd=iw......
  • Dubbo 2.7 源码解析 - 之 远程调用
    Dubbo2.7中的远程调用是其核心功能之一,涉及从客户端发起请求到服务端处理并返回结果的整个过程。这个过程高度抽象且灵活,支持多种协议、序列化方式和负载均衡策略。以下是远程调用的关键流程和相关源码解析:远程调用流程概览构建请求:消费者通过代理对象(由ProxyFactory创......
  • 毕业设计-基于Springboot+Vue的校园交友网站的设计与实现(源码+LW+包运行)
    源码获取:https://download.csdn.net/download/u011832806/89461651基于SpringBoot+Vue的校园交友网站开发语言:Java数据库:MySQL技术:SpringBoot+MyBatis+Vue.js工具:IDEA/Ecilpse、Navicat、Maven系统演示视频:链接:https://pan.baidu.com/s/146tUBgOIUaVG1IIsqVLy8A?pwd=xt......