STM32第九课:ADC单通道模数转换

一、ADC简介

        ADC是Analog-to-DigitalConverter的缩写。指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。

        STM32f103 系列有3个ADC,精度为12位,每个ADC最多有16个外部通道。其中ADC1和ADC2都有16个外部通道, ADC3根据CPU引脚的不同通道数也不同,一般都有8个外部通道。ADC的模式非常多,功能非常强大,具体的我们在功能框图中分析每个部分的功能。

        先掌握ADC功能图的一个大致的结构是什么,对于我们后期的学习,对ADC这个模块的了解大有益处。这一个部分可以多花些时间理解一下。

1.1 ADC功能图剖析

 1.2 电压输入范围

        ADC输入范围为:VREF- ≤ VIN ≤ VREF+。由VREF-、 VREF+ 、VDDA 、VSSA、这四个外部引脚决定。

        我们在设计原理图的时候一般把VSSA和VREF-接地, 把VREF+和VDDA 接3V3,得到ADC的输入电压范围为:0~3.3V。

        如果我们想让输入的电压范围变宽,去到可以测试负电压或者更高的正电压,我们可以在外部加一个电压调理电路, 把需要转换的电压抬升或者降压到0~3.3V,这样ADC就可以测量。

1.3 输入通道

        我们确定好ADC输入电压之后,那么电压怎么输入到ADC?这里我们引入通道的概念,STM32的ADC多达18个通道, 其中外部的16个通道就是框图中的ADCx_IN0、ADCx_IN1…ADCx_IN5。这16个通道对应着不同的IO口,具体是哪一个IO口可以从手册查询到。

 二、电路接线方法

        电路接线方法还是很简单的,主要就是一个OLED屏幕的接线,这个接线之前说过好多次了。还有一个就是旋转编码器的接线,这个也比较简单。

三、代码编写思路

        首先,我们可以复制之前的文章所编写的OLED的工程文件,改个名字为旋转编码器,后续就在这个文件的基础上进行编写代码。

3.1 创建AD.c和AD.h两个ADC模块的驱动文件

        我们首先创建一个名为AD.h的文件,创建在文件夹Hardware里面,具体步骤如下:

        第一步:右键单击代码信息栏最左侧的Hardware文件夹,选择创建新的文件在Hardware里面。

 第二步:选择第一个后缀名字为.c的文件,名字设置为AD,位置选在本项目文件家里面的Hardware文件夹里面。(注:在引用头文件AD.c或者AD.h的时候,创建的Hardware文件夹的路径必须在调试设置中包含在里面,具体步骤可以看我之前的文章。)

 第三部:同理创建AD.h文件,步骤与上一步类似。

 3.2 编写驱动文件代码

        首先编写AD.h中我们一贯熟悉的防止重复引用的代码:

#ifndef __AD_H
#define __AD_H#endif

         然后再看AD.c文件中的驱动代码怎么编写。

        首先编写ADC初始化函数AD_Init。

        使用RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  
               RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

两串代码开启ADC1和GPIOA的时钟。再设置ADC时钟为6分频,因为ADC时钟最大时钟频率为14MHz,六分频为12MHz,刚好满足。接下来是我们熟悉的GPIO初始化,然后配置规则组通道。紧接着对ADC进行初始化,ADC使能,ADC校准。

        再通过AD_GetValue函数获取采集到的ADC转换的值。

        不多逼逼,代码如下:

AD.c
#include "stm32f10x.h"                  // Device header/*** 函    数:AD初始化* 参    数:无* 返 回 值:无*/
void AD_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟/*设置ADC时钟*/RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0引脚初始化为模拟输入/*规则组通道配置*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);		//规则组序列1的位置,配置为通道0/*ADC初始化*/ADC_InitTypeDef ADC_InitStructure;						//定义结构体变量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//模式,选择独立模式,即单独使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐,选择右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发,使用软件触发,不需要外部触发ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//连续转换,失能,每转换一次规则组序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE;			//扫描模式,失能,只转换规则组的序列1这一个位置ADC_InitStructure.ADC_NbrOfChannel = 1;					//通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure);						//将结构体变量交给ADC_Init,配置ADC1/*ADC使能*/ADC_Cmd(ADC1, ENABLE);									//使能ADC1,ADC开始运行/*ADC校准*/ADC_ResetCalibration(ADC1);								//固定流程,内部有电路会自动执行校准while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);
}/*** 函    数:获取AD转换的值* 参    数:无* 返 回 值:AD转换的值,范围:0~4095*/
uint16_t AD_GetValue(void)
{ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位,即等待AD转换结束return ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

编写的函数只需要在 AD.h里面声明一下就可以使用了。代码如下

AD.h
#ifndef __AD_H
#define __AD_Hvoid AD_Init(void);
uint16_t AD_GetValue(void);#endif

        在住函数里面,当然首先要引用"stm32f10x.h"、"Delay.h"、"OLED.h"、"AD.h"头文件。

紧接着定义一个16位的变量ADValue,用于接收采集到的ADC变量。后面就初始化各种模块,接收获取的ADC的值,进行转化,打印在OLED屏幕上。

main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"uint16_t ADValue;			//定义AD值变量
float Voltage;				//定义电压变量int main(void)
{/*模块初始化*/OLED_Init();			//OLED初始化AD_Init();				//AD初始化/*显示静态字符串*/OLED_ShowString(1, 1, "ADValue:");OLED_ShowString(2, 1, "Voltage:0.00V");while (1){ADValue = AD_GetValue();					//获取AD转换的值Voltage = (float)ADValue / 4095 * 3.3;		//将AD值线性变换到0~3.3的范围,表示电压OLED_ShowNum(1, 9, ADValue, 4);				//显示AD值OLED_ShowNum(2, 9, Voltage, 1);				//显示电压值的整数部分OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2);	//显示电压值的小数部分Delay_ms(100);			//延时100ms,手动增加一些转换的间隔时间}
}

四、实操效果展示

 与君共勉 დ,关注我,持续更新中~

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

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

相关文章

Linux中线程的实现,线程的接口相关函数pthread_create、pthread_join、pthread_exit

目录 一.线程的概念 二.操作系统中线程的实现 三.Linux中线程的实现 四.进程与线程的区别 五.线程的接口相关函数 5.1 pthread_create 5.2 pthread_join 5.3 pthread_exit 六.代码演示 七.如何解决上述问题? 方案1. 方案2. 方案3. 一.线程的概念 进程是…

使用 Docker 部署 Stirling-PDF 多功能 PDF 工具

1)Stirling-PDF 介绍 大家应该都有过这样的经历,面对一堆 PDF 文档,或者需要合并几个 PDF,或者需要将一份 PDF 文件拆分,又或者需要调整 PDF 中的页面顺序,找到的线上工具 要么广告满天飞,要么 …

小程序API能力集成指南——画布API汇总(四)

CanvasContext canvas 组件的绘图上下文。 方法如下(3): scale CanvasContext.scale CanvasContext.scale(number scaleWidth, number scaleHeight) 功能描述 在调用后,之后创建的路径其横纵坐标会被缩放。多次调用倍数会相…

Flutter性能优化

性能分析工具 (1)performance overlay 开启performance overlay后,Flutter APP上将显示一个展示一个浮层,浮层中会实时展示当前的UI线程及Raster线程的运行情况。如果都是蓝色竖条,说明界面运行流畅,否则则…

【CSP考点回顾】前缀和数组

一、一维数组前缀和 前缀和算法是一种用于处理数组的技术,它可以快速计算任何连续子数组的和。适合在多次查询中需要求解多个范围和的情况。使用前缀和算法可以将每次求和的时间复杂度从 O(n) 降低到 O(1)。 前缀和的思想是创建一个新数组 A r r Arr Arr&#xff0…

递增三元组(第九届蓝桥杯)

文章目录 题目原题链接思路分析二分做法1二分做法2双指针做法前缀和解法 题目 原题链接 递增三元组 思路分析 由时间复杂度可知需要至少优化到 O ( n l o g n ) O(nlogn) O(nlogn)才行 而纯暴力枚举三个数组的话: O ( n 3 ) O(n^3) O(n3) 可以考虑将b[]作为标志&…

RabbitMQ 交换器

RabbitMQ 交换器 官方例子 http://www.rabbitmq.com/getstarted.html direct 如上图所示,两个队列绑定到了direct交换器上,第一个队列绑定的 binding key 为 orange ,第二个队列有两个绑定,分别是 black 和 green 。 如上图所示…

基础小白快速入门web前端开发技术------>web概述

Web概述 我们在编程的学习中,随着学习的深入,我们会理解到WEB这个东西,那么 web究竟是个啥,到底该咋用? web,是网站的英文意思,又被称作“下一代Web3.0,互联网”,是在We…

vue在线查看pdf文件

1.引入组件 npm install --save vue-pdf2、pdf组件页面模板 <template><div class"scrollBox" ><el-dialog :visible.sync"open" :top"1" width"50%" append-to-body><div slot"title"><el…

混沌工程-经典案例分享

目录 前言 案例 1、强弱依赖不合理 2、预案不生效 3、异常数据不兼容 4、监控体系缺陷 5、系统缺整体架构设计 总结 前言 我们公司从启动混沌工程到现在已经几乎覆盖了线上的所有核心业务&#xff0c;先后进行过2000次演练共挖掘出120个漏洞。这些漏洞有些得了及时修复…

DevEco Studio编译时候自动生成js、js.map文件导致项目无法运行

这算是开发工具的bug吧&#xff0c;估计后期能修复。 解决办法&#xff0c;手动删除.js、.js.map文件即可&#xff1b; 文件太多&#xff0c;删除很麻烦&#xff0c;有个大佬写了个插件&#xff0c;可一键删除&#xff1a;ArkCompilerSupport DevEco Studio 运行项目有时会自动…

二叉树进阶leetcode

606. 根据二叉树创建字符串 要点&#xff1a;前序遍历&#xff0c;当左子树为空时&#xff0c;右结点有数字时要给左边加括号 class Solution { public:string tree2str(TreeNode* root) {string s;//创建一个字符串if(rootnullptr){return s;}sto_string(root->val);//保存…

网络、网络协议模型、UDP编程——计算机网络——day01

今天来到了网络编程&#xff0c;主要讲了网络、网络协议模型以及UDP编程 网络 网络主要是进行&#xff1a;数据传输和数据共享 网络协议模型 OSI协议模型应用层 实际发送的数据表示层 发送的数据是否加密会话层 是否建立会话连接传…

调研图基础模型(Graph Foundation Models)

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 图基础模型&#xff08;Graph Foundation Models&#xff0c;简称 GFMs&#xff09; 是一种经过预训练的图大模型&#xff0c;旨在处理不同领域的图数据和任务。让我们详细探讨一下这个概念。 Github …

uniapp让输入框保持聚焦状态,不会失去焦点

使用场景&#xff1a;当输入框还有发送按钮的时候&#xff0c;点击发送希望软键盘不消失&#xff0c;还可以继续输入&#xff0c;或者避免因输入图片标签造成的屏闪问题 多次尝试后发现一个很实用的方法&#xff0c;适用input输入框和editor输入框 解决办法&#xff1a;把cli…

AXI4总线解析

一、读地址 AWVALID和AWREADY同时为高时&#xff0c;在这个上升沿&#xff0c;图中黄线&#xff0c;将接下来的数据写入地址40000000中。 在

基于状态机的按键消抖实现

摸鱼记录 Day_14 !(^O^)y review 在day_13中以按键状态判断为例学习了状态分析基于状态机的按键消抖原理-CSDN博客 分析得到了下图&#xff1a; 今日任务&#xff1a;完成此过程 !(^O^)y 小梅哥对应视频&#xff1a; 15B 基于状态机的按键消抖Verilog实现_哔哩哔哩…

DataFunSummit 2023:洞察现代数据栈技术的创新与发展(附大会核心PPT下载)

随着数字化浪潮的推进&#xff0c;数据已成为企业竞争的核心要素。为了应对日益增长的数据挑战&#xff0c;现代数据栈技术日益受到业界的关注。DataFunSummit 2023年现代数据栈技术峰会正是在这样的背景下应运而生&#xff0c;汇聚了全球数据领域的精英&#xff0c;共同探讨现…

Linux 文件操作命令

1 文件与目录操作 cd /home 进入 ‘/home’ 目录 cd .. 返回上一级目录cd ../.. 返回上两级目录cd - 返回上次所在目录cp file1 file2 将file1复制为file2cp -a dir1 dir2 复制一个目录 cp -a /tmp/dir1 . 复制一个…

【Qt】初识Qt

文章目录 一. 行业岗位介绍二. 什么是客户端&#xff1f;三. GUI 开发的各自技术方案四. 什么是框架&#xff1f;五. Qt 的发展史五. Qt 支持的系统六. Qt 的优点 一. 行业岗位介绍 二. 什么是客户端&#xff1f; 既然 Qt 是用来进行客户端开发的&#xff0c;那我们就要了解什…