STM32——ADC模数转换器

news2024/9/21 22:55:18

文章目录

  • 一、ADC模数转化器
    • ADC简介
    • 逐次逼近型ADC
    • ADC框图
  • 二、ADC基本结构
  • 三、触发转换控制
  • 四、输入通道
  • 五、规则组的四种转换模式
    • 单次转换,非扫描模式
    • 连续转换,非扫描模式
    • 单次转换,扫描模式
    • 连续转换,扫描模式
  • 六、数据对齐
  • 七、转换时间(可编程的通道采样时间)
  • 八、校准
  • 九、硬件电路
  • 十、电压值在抖动的解决方案:
  • 十一、AD单通道
    • 电路设计
    • 关键代码
  • 十二、AD多通道
    • 电路设计
    • 关键代码

一、ADC模数转化器

ADC简介

  • ADC(Analog-Digital Converter)模拟-数字转换器
  • ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
  • ADC其实是一个电压表将引脚输入的高低电平间的任意电压进行量化,放在数据寄存器里面
  • 12位【分辨率】逐次逼近型ADC,1us转换时间【转化频率1MHZ】
  • 输入电压范围:0~ 3.3V,转换结果范围:0~4095【2^12-1】
  • 18个输入通道,可测量16个外部和2个内部信号源【内部温度传感器和参考电压VREFINT=1.2V】
  • 规则组和注入组两个转换单元
  • 模拟看门狗自动监测输入电压范围【应用于中断】
  • STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道
  • PWM也属于数字信号到模拟信号的桥梁,在某些方面优于DAC,没有功率损耗,DAC应用于信号发生器,音频解码,PWM用于控制电机速度

逐次逼近型ADC

通过ADC0809外挂芯片了解逐次逼近型ADC
在这里插入图片描述

  • 电压比较器,未知编码电压与已知编码电压比较,采用二分法比较,二分法选取的电压值恰好是二进制的位权,所以8位只要分8次就可以找到对应编码电压,8位的二级制最大值是255
  • 电压比较器比较未知编码电压与已知编码电压,大于时调小DAC的模拟电压,反之调大,DAC的输出数据就是未知编码电压
  • DAC参考电压决定ADC参考电压,因为两者相互比较,通常ADC的供电电压(Vcc)和DAC参考电压(VREF+)连接在一起
  • DAC内部是由加权电阻网络实现
  • EOC输出转换结束信号
  • CLOCK为ADC时钟,因为比较是需要时钟推动
  • START信号:触发转化的信号源,如定时器,外部中断等

ADC框图

在这里插入图片描述

  • 常规情况使用规则组,突发事件的注入组
  • 开启注入通道,可以同时接收4个通道的输入,经过逐次比较后输出到四个数据寄存器,不会有覆盖问题,而规则通道会有覆盖问题,只能存放一个通道的值在一个数据寄存器中【配合DMA实现,避免数据被覆盖】
  • VREF+和VREF-为参考电压,是进行逐次比较的已知编码电压
  • VDDA和VSSA是供电引脚,是内部模拟部分的电源,比如ADC,RC振荡器,锁相环等
  • ADCCLK:来自ADC预分频器,通过RCC时钟树可以知道最大是频率是14MHZ,只能选择6分频【12MHZ】或8分频【9MHZ】
    在这里插入图片描述
  • EOC是规则组的完成信号,JEOC是注入组的完成信号,通过读取状态标志位了解是否完成转换。可以使能中断功能,由NVIC管理外设ADC中断
  • ADC触发方式有软件触发和硬件触发,此处是硬件触发,包含定时器触发,外部中断引脚触发,规则组合注入组都不一样。
    • 定时器中断可以触发ADC、DAC转换,但是频繁进入中断会消耗资源,通过定时器的更新事件映射到TRGO输出,此时就是通过硬件自动触发ADC转换

二、ADC基本结构

在这里插入图片描述

关键函数

ADC_RegularChannelConfig()//模拟多路开关函数
ADC_SoftwareStartConvCmd()//软件触发函数,转换开启的函数
ADC_Cmd()//开关控制
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADCCLK函数在rcc.h文件里面
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待转换结果的完成,通过判断EOC标志位

ADC输入引脚必须配置为模拟输入
在这里插入图片描述

  • 在模拟输入模式下,会断开GPIO口,GPIO口输入的电压失效,防止对模拟输入造成影响

三、触发转换控制

规则组合注入组触发控制的方式:
在这里插入图片描述
规则组触发控制的方式

在这里插入图片描述

四、输入通道

stm32f103c8t6的10个输入通道
在这里插入图片描述

  • ADC1和ADC2通道的引脚相同,可以用于组成双ADC模式:配合组成同步模式,交叉模式(ADC1和ADC2交叉对一个通道进行采样,提高采样频率)

五、规则组的四种转换模式

单次转换,非扫描模式

在这里插入图片描述

连续转换,非扫描模式

在这里插入图片描述

单次转换,扫描模式

在这里插入图片描述

  • 扫描模式只有在列表里面所有的通道都转换完成才会发出EOC信号

连续转换,扫描模式

在这里插入图片描述

六、数据对齐

因为数据寄存器16位,而ADC寄存器是12位,所以涉及数据对齐

数据右对齐:

在这里插入图片描述

数据左对齐:
在这里插入图片描述

  • 数据左移四次,等效于乘以16
  • 左对齐的好处是当不需要12位的精度而只需要8位精度时,采用左对齐,然后只取出前8位即可

七、转换时间(可编程的通道采样时间)

AD转换的步骤:采样,保持,量化,编码

  • 采样保持:闭合采样开关,存储需要量化的电压
  • 量化编码:比较器比较电压

STM32 ADC的总转换时间为:

  • TCONV = 采样(保持)时间 + 12.5个ADC周期【ADCCLK】

  • 例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期

    • TCONV = 1.5 + 12.5 = 14个ADC周期 = 1μs
//采样保持时间在这个函数的最后一个参数里面设置
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);//配置通道选择器
//ADCCLK设置
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADCCLK函数在rcc.h文件里面
//参数
@arg RCC_PCLK2_Div6: ADC clock = PCLK2/6//6分频为12MHZ
@arg RCC_PCLK2_Div8: ADC clock = PCLK2/8//8分频为9MHZ

八、校准

  • ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差
  • 建议在每次上电后执行一次校准
  • 启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期

固定代码

ADC_ResetCalibration(ADC1);//校准寄存器
while (ADC_GetResetCalibrationStatus(ADC1) == SET);//获取所选ADC重置校准寄存器状态。当校准完成会变为RESET,此时跳出循环
ADC_StartCalibration(ADC1);//启动选定的ADC校准过程。
while (ADC_GetCalibrationStatus(ADC1) == SET);//获取所选ADC校准状态。

九、硬件电路

在这里插入图片描述

  • 传感器输出电压电路输出引脚是AO
  • 电压转换电路中输入的电压范围为0-5V,通过串联两个电阻将电压转化为0-3.3V

十、电压值在抖动的解决方案:

当设定了阈值与电压值进行比较时会遇到抖动导致功能无法正常实现,可以采用如下方法:

  1. 采用迟滞比较方式:设置两个阈值,优于一个阈值的方式,在两个阈值中间抖动不会影响
  2. 采用滤波:均值滤波
  3. 裁剪分辨率

十一、AD单通道

电路设计

在这里插入图片描述

关键代码

AD.c

#include "stm32f10x.h"                  // Device header


void AD_Init(void){
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADCCLK函数在rcc.h文件里面
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//ADC输入引脚必须配置为模拟输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//ADC12_IN0
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);//配置规则组通道选择器,第三个参数是通道里面的序列
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立通道or双通道
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//指定ADC数据对齐是左对齐还是右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//触发方式,外部触发None表示采用软件触发
	//设置成单次转换非扫描
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//连续转换or单次转换
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//扫描模式or非扫描模式
	ADC_InitStructure.ADC_NbrOfChannel = 1;//指定ADC通道数量,在扫描模式下才有
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	//校准固定代码
	ADC_ResetCalibration(ADC1);//校准寄存器
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);//获取所选ADC重置校准寄存器状态。当校准完成会变为RESET,此时跳出循环
	ADC_StartCalibration(ADC1);//启动选定的ADC校准过程。
	while (ADC_GetCalibrationStatus(ADC1) == SET);//获取所选ADC校准状态。
	
	//ADC_SoftwareStartConvCmd(ADC1, ENABLE);//当选择连续单通道时可以将触发函数写在初始化函数内部,在while循环里面就不会频繁触发。此时EOC标志位也可以不用判断是否置1,直接返回数据寄存器里面的ADC转换结果值即可
}

uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//启用或禁用所选ADC的软件触发
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待转换结果的完成,
	return ADC_GetConversionValue(ADC1);//返回常规通道的最后ADCx转换结果数据。读取DR寄存器会自动清除EOC标志位,不用手动清除
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

uint16_t ADValue;
float Voltage;

int main(void)
{
	OLED_Init();
	AD_Init();
	
	OLED_ShowString(1, 1, "ADValue:");
	OLED_ShowString(2, 1, "Volatge:0.00V");
	
	while (1)
	{
		ADValue = AD_GetValue();
		Voltage = (float)ADValue / 4095 * 3.3;
		
		OLED_ShowNum(1, 9, ADValue, 4);
		//showNum显示的是整数,通过计算获取小数部分
		OLED_ShowNum(2, 9, Voltage, 1);
		OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2);
		
		Delay_ms(100);
	}
}

十二、AD多通道

电路设计

在这里插入图片描述

关键代码

AD多通道采集一般采用扫描模式,在本案例中可以用单次转换非扫描模式,在每次触发转换之前,更改列表第一个序列的通道

AD.c

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
		
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}

uint16_t AD_GetValue(uint8_t ADC_Channel)
{
	//在规则组通道选择器配置函数中,将采样通道设置为形参
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);//第三个参数表示序列1
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//切换序列上的通道后在开启转换
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

uint16_t AD0, AD1, AD2, AD3;

int main(void)
{
	OLED_Init();
	AD_Init();
	
	OLED_ShowString(1, 1, "AD0:");
	OLED_ShowString(2, 1, "AD1:");
	OLED_ShowString(3, 1, "AD2:");
	OLED_ShowString(4, 1, "AD3:");
	
	while (1)
	{
		AD0 = AD_GetValue(ADC_Channel_0);
		AD1 = AD_GetValue(ADC_Channel_1);
		AD2 = AD_GetValue(ADC_Channel_2);
		AD3 = AD_GetValue(ADC_Channel_3);
		
		OLED_ShowNum(1, 5, AD0, 4);
		OLED_ShowNum(2, 5, AD1, 4);
		OLED_ShowNum(3, 5, AD2, 4);
		OLED_ShowNum(4, 5, AD3, 4);
		
		Delay_ms(100);
	}
}

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

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

相关文章

Linux系统下的rpm管理

文章目录Linux系统下的rpm管理1.介绍2.rpm包的简单查询指令3.rpm包的其它查询指今4.卸载rpm包5.安装rpm包Linux系统下的rpm管理 1.介绍 rpm用于互联网下载包的打包及安装工具,它包含在某些Linux分发版中。它生成具有.RPM扩展名的文件。RPM是RedHat Package Manage…

【设计篇】35 # 如何让可视化设计更加清晰?

说明 【跟月影学可视化】学习笔记。 分清信息主次&#xff0c;建立视觉层次 用醒目的颜色突出显示数据&#xff0c;把被淡化的其他视觉元素当作背景。 比如&#xff1a;平均温度与露点的散点例子 <!DOCTYPE html> <html lang"en"><head><m…

linux上安装python3.7.4

1.wget下载python3安装包 wget https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tgz2.wget下载的压缩包默认在~目录下 3.进入~目录&#xff0c;直接解压压缩包 tar -xzvf Python-3.7.2.tgz4.进入python解压后的目录&#xff0c;为python配置环境&#xff0c;指定pytho…

CMMI-培训管理

培训管理&#xff08;Training Management, TM&#xff09;是指根据机构&#xff08;或项目&#xff09;的需求来制定培训计划&#xff0c;并监督该计划的实施&#xff0c;确保培训取得预期效果。培训管理过程域是SPP模型的重要组成部分。本规范阐述了培训管理过程域的两个主要…

头歌:UDP Ping程序实现 接收并转发消息

头歌平台&#xff1a;头歌实践教学平台 (educoder.net)任务描述本关任务&#xff1a;在 Ping 服务端程序框架中&#xff0c;完成接收数据&#xff0c;并回传给相应客户端。如何接收数据包套接字数据在 UDP 通信中使用sendto()函数发送 UDP 数据。将数据发送到套接字&#xff0c…

Parallel Processing in Python - Python 中的并行处理

并行处理可以增加程序完成的任务数量&#xff0c;从而减少整体处理时间。这些有助于处理大规模问题。 参考链接&#xff1a;Parallel Processing in Python - GeeksforGeeks 1 并行处理介绍 对于并行性&#xff0c;重要的是将问题划分为不依赖于其他子单元 (或较少依赖) 的子…

【Vue中使用Echarts】大屏可视化项目整体布局(pink老师vue 版)

文章目录一、效果展示二、基本的布局三、背景四、代码布局中遇到的一些问题一、效果展示 先看一下展示的效果&#xff0c;无论是尺寸多宽的屏幕&#xff0c;都会将内容显示完整&#xff0c;做到了正正的响应式。唯一不足的是图表中的样例&#xff0c;会随着图表的缩放而变换位…

35-剑指 Offer 37. 序列化二叉树

题目 请实现两个函数&#xff0c;分别用来序列化和反序列化二叉树。 你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑&#xff0c;你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。 …

第02讲:HTTP操作之ElasticSearch索引操作

3.1.1、索引操作 实验1&#xff1a;创建索引 对比关系型数据库&#xff0c;创建索引就等同于创建数据库 在 Postman 中&#xff0c;向 ES 服务器发 PUT 请求 :http://127.0.0.1:9200/shopping { "acknowledged"【响应结果】: true, # true操作成功 "shards…

npm与包

1、包 1.1、什么是包 Node.js 中的第三方模块又叫做包。就像电脑和计算机指的是相同的东西&#xff0c;第三方模块和包指的是同一个概念&#xff0c;只不过叫法不同。 1.2、包的来源 不同于 Node.js 中的内置模块与自定义模块&#xff0c;包是由第三方个人或团队开发出来的&a…

跟踪数据集汇总

文章目录DanceTrack 运动跟踪数据集简介转为Labelme标注的物体检测数据集格式WiderPerson行人检测数据集简介转为Labelme标注的物体检测数据集格式DanceTrack 运动跟踪数据集 简介 DanceTrack 是一个大规模的多对象跟踪数据集。用于在遮挡、频繁交叉、同样服装和多样化身体姿…

DVWA之SQL注入漏洞与防御

数据来源 本文仅用于信息安全学习&#xff0c;请遵守相关法律法规&#xff0c;严禁用于非法途径。若观众因此作出任何危害网络安全的行为&#xff0c;后果自负&#xff0c;与本人无关。 耳熟能详的SQ注入是什么&#xff1f; 关于SQL注入漏洞&#xff0c;维基百科是这样解释的 …

传统离散制造行业的9个维度,你知道吗?

制造业是国家的经济基础&#xff0c;是立国之本、兴国之器、强国之基&#xff1b;作为我国实体经济的主体&#xff0c;是国民经济体系的重要组成部分。按照产品制造工艺过程特点&#xff0c;制造业总体上可以分为离散型制造、流程型制造、混合型制造。离散制造包括家电、家居、…

2022亚太杯数学建模E题(1月补赛)

占个位置吧&#xff0c;更新E题的详细思路代码&#xff0c;文章末尾名片获取&#xff01;ABC题已更新 持续为更新参考思路 E题思路分析&#xff1a; 第一问都是一些基础的数据分析问题&#xff0c;使用题目给出的数据稍加整理归纳即可得出结论。 E题给了4张表格数据&#x…

MySQL调优-MySQL索引优化实战二

目录 MySQL调优-MySQL索引优化实战二 分页查询优化 >>常见的分页场景优化技巧&#xff1a; 1、根据自增且连续的主键排序的分页查询 2、根据非主键字段排序的分页查询 Join关联查询优化 MySQL的表关联常见有两种算法&#xff1a; 1.嵌套循环连接 Nested-Loop Join…

Python入门注释和变量

1.1计算机的基本原理 1.2 计算机的组成 2.1编程语言与python 2.2在 Welcome to Python.org 里面进入 无脑下一步下载 下载后打开cmd&#xff0c;输入名令Python显示下载的版本号 exit&#xff08;&#xff09;退出编辑 Pycharm无脑安装 社区版无需破解&#xff0c;专业版需破…

MATLAB 矩阵数据可视化imagesc 以及 如何多图共用一个 colorbar

当遇到需要查看一个二维矩阵数据中值的大小分布情况时可以使用 MATLAB 把矩阵以图像的形式展现出来&#xff0c;这样更直观。MATLAB 的可视化函数之一是 imagesc( )&#xff0c;还有其他的方法&#xff0c;这里只介绍下 imagesc。 目录 1、单一作图 2、同时绘制多图并共用 c…

谷粒学院——第十九章、数据同步_网关

Canal 数据同步&#xff08;了解&#xff09; 网关 API 网关介绍 API 网关出现的原因是微服务架构的出现&#xff0c;不同的微服务一般会有不同的网络地址&#xff0c;而外部客户端可能 需要调用多个服务的接口才能完成一个业务需求&#xff0c;如果让客户端直接与各个微服务…

vue+element对接第三方接口实现校园发帖网站“淘柳职”

一.前言 接上一篇博客《vueelementuijava 前后端分离实现学校帖子网站&#xff0c;仿照“淘柳职”学校大作业》 上一篇博客介绍的项目完全自带前、后端实现的&#xff0c;是一个完整的项目&#xff0c;现在作者在此基础上&#xff0c;利用已实现的前端&#xff0c;对接《淘柳职…

android12.0(S) DeviceOwner 应用默认授权(MDM 权限)

MDM(Mobile Device Manager) 通俗来讲就是管理设备使用 国内 MDM 服务商有 360 等 国外 MDM 服务商有 hexnode 等 当你在设备上配置了 DeviceOwner 后&#xff0c;状态栏下拉中会多出如下 关于 DeviceOwner 介绍可参考下面 Android DeviceOwner 应用的能力 Android Device…