GD32 ADC模数转换器

news2024/11/15 14:08:43

前言:


...


1:简介

12 位 ADC 是一种采用逐次逼近方式的模拟数字转换器。它有 18 个多路复用通道,可以转换来自 16 个外部通道和 2 个内部通道的模拟信号。模拟看门狗允许应用程序来检测输入电压是否超出用户设定的高低阈值。各种通道的 A/D 转换可以配置成单次、连续、扫描或间断转换模式。 ADC 转换的结果可以按照左对齐或右对齐的方式存储在 16 位数据寄存器中。片上的硬件过采样机制可以通过减少来自 MCU 的相关计算负担来提高性能。
 


2:ADC 主要特征

高性能:

– 可配置12位、 10位、 8位、或者6位分辨率;

– 自校准;

– 可编程采样时间;

– 数据寄存器可配置数据对齐方式;

– 支持规则数据转换的DMA请求。

 模拟输入通道:

– 16个外部模拟输入通道;

– 1个内部温度传感通道(VSENSE);

– 1个内部参考电压输入通道(VREFINT)。

 转换开始的发起:

– 软件;

– 硬件触发。

 转换模式:

– 转换单个通道,或者扫描一序列的通道;

– 单次模式,每次触发转换一次选择的输入通道;

– 连续模式,连续转换所选择的输入通道;

– 间断模式;

– 同步模式(适用于具有两个或多个ADC的设备)。

 模拟看门狗。

 中断的产生:

– 规则组或注入组转换结束;

– 模拟看门狗事件。

 过采样:

– 16位的数据寄存器;

– 可调整的过采样率,从2x到256x;

– 高达8位的可编程数据移位。

 ADC供电要求: 2.6V到3.6V,一般电源电压为3.3V。

 ADC输入范围: VREFN ≤VIN ≤VREFP。


3:ADC 硬件结构

以上是ADC的程序框图

ADC 的硬件结构,有来自GPIO的输入(16个外部模拟输入通道),有来自外部采集温度输入,以及参考电压输入,AD模拟数字转换器内含规则组与注入组,含触发方式有软件触发,硬件触发,定时器触发等,规则组可以理解为程序的主流程,注入组可以理解为程序里面的中断注入组可以打断规则组的执行直到执行完成以后才会继续执行规则组的内容,转换完成后执行的结果会放在AD数据寄存器中,规则组16个通道共用一个数据寄存器,注入组:对应有4个数据寄存器,转换完成后设置EOC中断标志位,产生EOC中断,时钟的频率是40MHz,中断输出控制需要使能,NVIC也要打开相关的中断才能正常使能。


4:外部模拟输入通道IO口

5:ADC 转换模式

转换模式中的单次转换和连续转换:单次转换表示的含义是,每次转换都需要一次外部出发,同时设置EOC标志位,连续模式表示的含义是:开始转换时只需要外部触发一次,后续的转换会自己连续的触发,这里采用的是非扫描的模式。

扫描模式:主要针对某个ADC使用多个还是单个

 单次转换扫描模式,单次转换连续模式,需要配合DMA进行使用,因为存储的数据寄存器只有1个

如果不使用DMA进行数据转运会导致后面一次转换的数据覆盖前面一次转换的数据,造成数据丢

失。


同步模式:针对ADC多个同时触发的场景,交替触发等,相互之间配合使用


6:数据对齐

数据的对齐方式有,数据左对齐,数据右对齐

数据右对齐就是高位补0

数据左对齐就是低位补0


7:转换时间

采样的时间可以等同为:采样 + 保持, 对应的ADC周期可以等同为量化加编码。

8:校准

9:初始化ADC配置

单次连续非非扫描模式初始化

使用ADC0进行配置,PC2这个通道对应我们开发板上的可调电阻模块。

初始化函数

#include <stdint.h>
#include <stdio.h>
#include "gd32f30x.h"
#include "delay.h"

static void GpioInit(void)
{
	rcu_periph_clock_enable(RCU_GPIOC);
	gpio_init(GPIOC,GPIO_MODE_AIN,GPIO_OSPEED_10MHZ,GPIO_PIN_2);
}

// 初始化ADC
static void AdcInit(void)
{
	// 使能时钟
	rcu_periph_clock_enable(RCU_ADC0);
	// 设置分频系数,设置分频系数为6分频,120M的时钟频率6分频后得到的时钟主频为20
	rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6);
	// 设置独立模式
	adc_mode_config(ADC_MODE_FREE);
	// 设置单次模式
	adc_special_function_config(ADC0,ADC_CONTINUOUS_MODE,DISABLE);
	// 设置数据对齐
	adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
	// 设置和转换通道个数
	adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,1);
	// 设置转换的通道以及所处在的序列位置,PC2对应的通道为12,放在寄存器序列0中,239.5个周期
	adc_regular_channel_config(ADC0,0,ADC_CHANNEL_12,ADC_SAMPLETIME_239POINT5);
	// 设置选择哪一个外部触发源,使用软件的方式触发
	adc_external_trigger_source_config(ADC0,ADC_REGULAR_CHANNEL,ADC0_1_2_EXTTRIG_REGULAR_NONE);
	// 使能外部触发,规则组触发,使能
	adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,ENABLE);
	// 使能ADC
	adc_enable(ADC0);
	DelayNus(50);
	// 内部校准
	adc_calibration_enable(ADC0);

	
}


void VresDrvInit(void)
{
	GpioInit();
	AdcInit();
}


/*
   *****************************************
   * @brief :  获取ADC数据
   * @param :  
   * @param : 
   * @retval: 
   *****************************************
*/
uint16_t GetAdcVal(void)
{
	// 使能软件触发,每一次转换都需要软件触发一次
	adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
	// 判断ADC标志位是否置位
	while(!adc_flag_get(ADC0, ADC_FLAG_EOC));
	// 读取ADC规则组数据并返回
	return adc_regular_data_read(ADC0);
}

/*
   *****************************************
   * @brief :  测试函数
   * @param :  
   * @param : 
   * @retval: 
   *****************************************
*/
void VresDrvTest(void)
{
	// 获取返回的数据
	uint16_t AdcVal = GetAdcVal();
	// 对数据进行转换,将数据转换为电压的值
	float Voltage = (float)AdcVal / 4095 * 3.3f;
	// 打印输出电压数据
	printf("AdcVal = %d, Voltage = %.1f.\n",AdcVal,Voltage);
	// 延时1s
	DelayNms(1000);
}




 对代码相关参数的解释:

可以有如下的理解:就是把系统的采样和保持理解为采样时间+量化和编码理解为ADC的周期

ADC电压转换

一个12位的模数转换器(ADC)的分辨率意味着它可以区分输入信号的2^12个不同的级别。这是因为二进制数的每一位都可以有两个状态(0或1),所以n位的ADC可以表示2^n个不同的值。

对于12位的ADC,其分辨率为2^12,即4096个不同的数值级别。这意味着如果ADC的全量程范围是从0V到Vref(参考电压),那么每一个数值级别代表的电压增量为Vref除以4096。

例如,如果Vref是3.3V,则每个数值级别代表的电压为: 3.3 V4096≈0.805 mV40963.3V​≈0.805mV

因此,12位分辨率的ADC可以提供相当精细的电压测量,最小可以分辨出大约0.805毫伏的变化。这种精度对于许多应用来说已经足够,尤其是在需要高精度测量的场合,如精密仪器、传感器信号采集和控制系统中。

初始化配置头文件

#ifndef _VRES_DRV_H_
#define _VRES_DRV_H_

/**
***********************************************************
* @brief ADC硬件初始化
* @param
* @return 
***********************************************************
*/
void VresDrvInit(void);
void VresDrvTest(void);
#endif

主函数调用

 实验结果:

10:单次连续模式

注:使用单次连续模式只需要软件触发一次无需每次都使用软件进行触发,触发成功后转换后的数据会自动的存储到数据寄存器中,无需每次都判断EOC标志位,直到转换完成后判断一次EOC标志位即可。

#include <stdint.h>
#include <stdio.h>
#include "gd32f30x.h"
#include "delay.h"

static void GpioInit(void)
{
	rcu_periph_clock_enable(RCU_GPIOC);
	gpio_init(GPIOC,GPIO_MODE_AIN,GPIO_OSPEED_10MHZ,GPIO_PIN_2);
}

// 初始化ADC
static void AdcInit(void)
{
	// 使能时钟
	rcu_periph_clock_enable(RCU_ADC0);
	// 设置分频系数,设置分频系数为6分频,120M的时钟频率6分频后得到的时钟主频为20
	rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6);
	// 设置独立模式
	adc_mode_config(ADC_MODE_FREE);
	// 设置连续转换模式
	adc_special_function_config(ADC0,ADC_CONTINUOUS_MODE,ENABLE);
	// 设置数据对齐
	adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
	// 设置和转换通道个数
	adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,1);
	// 设置转换的通道以及所处在的序列位置,PC2对应的通道为12,放在寄存器序列0中,239.5个周期
	adc_regular_channel_config(ADC0,0,ADC_CHANNEL_12,ADC_SAMPLETIME_239POINT5);
	// 设置选择哪一个外部触发源,使用软件的方式触发
	adc_external_trigger_source_config(ADC0,ADC_REGULAR_CHANNEL,ADC0_1_2_EXTTRIG_REGULAR_NONE);
	// 使能外部触发,规则组触发,使能
	adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,ENABLE);
	// 使能ADC
	adc_enable(ADC0);
	DelayNus(50);
	// 内部校准
	adc_calibration_enable(ADC0);
	// 使能软件触发,每次转换完成会将数据放到数据寄存器中
	adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
	
}


void VresDrvInit(void)
{
	GpioInit();
	AdcInit();
}


/*
   *****************************************
   * @brief :  获取ADC数据
   * @param :  
   * @param : 
   * @retval: 
   *****************************************
*/
uint16_t GetAdcVal(void)
{

	// 判断ADC标志位是否置位
	while(!adc_flag_get(ADC0, ADC_FLAG_EOC));
	// 读取ADC规则组数据并返回
	return adc_regular_data_read(ADC0);
}

/*
   *****************************************
   * @brief :  测试函数
   * @param :  
   * @param : 
   * @retval: 
   *****************************************
*/
void VresDrvTest(void)
{
	// 获取返回的数据
	uint16_t AdcVal = GetAdcVal();
	// 对数据进行转换,将数据转换为电压的值
	float Voltage = (float)AdcVal / 4095 * 3.3f;
	// 打印输出电压数据
	printf("AdcVal = %d, Voltage = %.1f.\n",AdcVal,Voltage);
	// 延时1s
	DelayNms(1000);
}

代码做了一定程序的小修改,以下是想啊滚修改的位置

 使能触发的位置放到初始化的位置处


 11 :多通道扫描模式

多通道扫描模式配合DMA初始化


后记:


...


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

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

相关文章

解决m-tabbar部分页面元素浮动导致第一个单元格元素点击失效问题

工作中遇到一个神奇的bug&#xff0c;代码没有问题点击第一个单元格的时候无法正常点击&#xff0c;通过调试工具定位发现是m-tabbar组件的m-tabbar-box元素有浮动导致了点击失效。 解决办法1&#xff1a; 设置元素的z-index大于tabbar的&#xff0c;这样要对页面元素底部做一…

VMware虚拟机设置桥接网络固定IP

VMware虚拟机设置桥接网络固定IP 在VMware虚拟机中设置桥接网络并固定IP地址&#xff0c;主要涉及到几个步骤&#xff1a;设置虚拟网络编辑器、配置虚拟机的网络适配器&#xff0c;以及修改虚拟机内的网络配置文件。以下是详细的步骤说明&#xff1a; 设置虚拟网络编辑器 以…

[ BLE4.0 ] 伦茨ST17H66开发-ADC采集电压数据-ADC中断采集-ADC单端输入与差端输入

目录 一、前言 二、采集模式 三、详细步骤 3.1 引脚选择 3.2 代码实现 3.2.1 导入库文件 3.2.2 模式选择 3.2.3 bypass模式 3.2.4 attenuation模式 3.2.5 代码配置 四、效果展示 一、前言 使用单片机面对数据采集时&#xff0c;往往设计到模拟量的采集&#xff0c;因此&…

【进制转换】《进制大乱斗,谁才是真正的赢家!》

目录 进制转换详解1. 引言2. 进制简介2.1 十进制2.2 二进制2.3 八进制2.4 十六进制 3. 进制转换方法3.1 十进制转二进制3.2 二进制转十进制3.3 十进制转八进制3.4 八进制转十进制3.5 十进制转十六进制3.6 十六进制转十进制3.7 二进制转八进制3.8 八进制转二进制3.9 二进制转十六…

缓存穿透

目录 概念 业务逻辑改造 代码实现 概念 用户请求查询的数据在缓存和数据库中都没有&#xff0c;那么最终请求都会进入到数据库&#xff0c;缓存会失效 两种解决方法&#xff1a;缓存NULL对象&#xff0c;使用布隆过滤器 业务逻辑改造 代码实现 解决缓存穿透问题public Shop…

3.redis客户端

1.命令行客户端 在安装redis的时候就已经安装好了&#xff0c;就是redis-cli redis-cli -h 127.0.0.1 -p 6379 -a 123456 -a 表示密码 -h 表示ip&#xff0c;不配置默认为本机 127.0.0.1 -p 表示端口&#xff0c;不配置默认为 6379 进入后可以输入ping&#xff0c;返回pong代表…

【C++】实验十三

题目&#xff1a; 1、声明Point&#xff08;点&#xff09;类&#xff0c;由Point类派生出Circle&#xff08;圆&#xff09;类&#xff0c;再由Circle类派生出Cylinder&#xff08;圆柱&#xff09;类。将类的定义部分分别作为3个头文件。对它们的成员函数的声明部分分别作为…

【数据结构算法经典题目刨析(c语言)】链表的回文结构(图文详解)

&#x1f493; 博客主页&#xff1a;C-SDN花园GGbond ⏩ 文章专栏&#xff1a;数据结构经典题目刨析(c语言) 目录 一、题目描述 二、解题思路 三、代码实现&#xff08;C语言&#xff09; 回文结构&#xff08;Palindromic structure&#xff09;是指一个序列或字符串从前往…

C++多线程常用的几种实现方式

1、std::thread C11标准之后便引入了线程库std::thread。无论是windows或是Linux开发者都可以非常简单的通过这种方式&#xff0c;在C程序中创建和管理线程。 示例代码&#xff1a; #include <unistd.h> #include <iostream> #include <thread>void thread…

App 自动化测试调研

App 自动化测试调研 App 自动化测试的价值 App 自动化测试在软件开发过程中扮演着重要的角色&#xff0c;具有以下几个方面的价值&#xff1a; 1.提高测试效率和覆盖率&#xff1a;自动化测试可以执行大量的测试用例&#xff0c;覆盖各种功能和场景&#xff0c;相比手动测试…

BootStrapBlazor中MultiSelect组件在表格中使用时存在的问题

仅作记录&#xff0c;备以后回忆 在Table中使用了双击弹出编辑框来修改数据&#xff0c;正好逆变器需要多选&#xff0c;就使用了MultiSelect组件&#xff0c;结果发现它选择后没有任何效果&#xff0c;不会显示&#xff0c;但是保存后发现它是有数据的&#xff0c;网上搜了下…

关于python问题 ,生成的excel文件内无爬取的数据存在,请问应如何解决?

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

深度分析 !中国 AI 产业商业化实践案例 ! 2024 !

提供客户全渠道全生命周期的营服销一体化智能服务 京东云言犀依托于全栈自研的人工智能技术&#xff0c;基于京东集团广泛实体业务、庞大而又复杂的产业生态&#xff0c;从内部真实、复杂的海量业务场景实践中推出千亿级参数的言犀大模型&#xff0c;打造全新的智能交互与生成…

中国人民解放军建军97周年

缅怀先烈&#xff0c;砥砺前行 付吾辈之韶华&#xff0c;耀吾辈之中华! 万里河山&#xff0c;有您心安!

单链表习题(3)(超详细)

前言&#xff1a; 这篇文章将会是小编最近做过的习题总结的最后一篇&#xff0c;这一篇有些习题颇有一些难度&#xff0c;不过小编将会带领读者朋友们一起克服难关&#xff0c;下面废话不多说&#xff0c;开启今天的习题之旅&#xff01; 目录&#xff1a; 1.链表分割 2.相交链…

复习Nginx

1.关于Nginx Nginx的关键特性 1.支持高并发 2.内存资源消耗低 3.高扩展性&#xff08;模块化设计&#xff09; 4.高可用性&#xff08;master-worker&#xff09; Nginx运行架构 注意 默认情况下&#xff0c;Nginx会创建和服务器cpu核心数量相等的worker进程 worker进程之间…

自从用了这些监控工具,我连续几天没睡好觉!

大家好&#xff0c;我是程序员鱼皮&#xff0c;今天分享一些很实用的系统监控告警工具。 为什么要用监控告警&#xff1f; 说到监控告警&#xff0c;没有企业开发经验的同学非常容易忽视它&#xff0c;甚至会有同学觉得没有必要&#xff0c;大不了出了 Bug 再修就是了。 这种…

MySQL:初识数据库初识SQL创建数据库

目录 1、初识数据库 1.1 什么是数据库 1.2 什么是MySQL 2、数据库 2.1 数据库服务&数据库 2.2 C/S架构 3、 初识SQL 3.1 什么是SQL 3.2 SQL分类 4、使用SQL 4.1 查看所有数据库 4.1.2 语句解析 4.2 创建数据库 4.2.1 if not exists校验 4.2.2 手动明确字符集…

第33篇 计算数据中最长的连续1的个数<三>

Q&#xff1a;如何将计算出的结果&#xff08;最长的连续1的个数&#xff09;显示在DE2-115开发板的HEX上&#xff1f; A&#xff1a;基本原理&#xff1a;DE2-115_Computer_System中的HEX并行端口作为内存映射设备连接到DE2-115开发板的七段数码管&#xff0c;每个端口都对应…

uniapp微信小程序按钮分享定制动态传参

打印 onShareAppMessage 中的传参&#xff08;注意&#xff1a;上方我定义了一个open-type为share的按钮&#xff09; 打印之后如下&#xff1a; 给按钮绑定 data-id 可以在这里的 dataset 中取到 然后根据 from 的值来动态返回分享的参数 示例代码&#xff1a; <…