GD32_ADC采样+DMA多通道扫描传输

GD32_ADC采样+DMA多通道扫描传输

文章目录

  • GD32_ADC采样+DMA多通道扫描传输
  • 前言
  • 一、资源介绍
  • 二、原理
    • 1.ADC连续扫描模式
    • 2.DMA传输
    • 3.ADC内部通道
  • 三、配置
    • 1.ADC配置
    • 2.DMA配置
    • 3.注意事项
  • 四、计算
    • 1.分压转换
    • 2.数据转换


前言

<1>、硬件平台:可运行软件程序的GD32单片机(本项目使用GD32F103CBT6硬件平台)
<2>、软件平台:基于使用标准库GD32F10x_Firmware_Library_V2.2.4固件库编写


一、资源介绍

所使用的MCU 片上集成了 12 位逐次逼近式模数转换器模块(ADC),可以采样来自于 16 个外部通道和 2 个内部通道上的模拟信号。这 18 个 ADC 采样通道都支持多种运行模式,采样转换后,转换结果可以按照最低有效位对齐或最高有效位对齐的方式保存在相应的数据寄存器中。我们主要介绍其多通道扫描转换和DMA传输功能,在多个通道轮询采集ad数据,并使用DMA分别保存各个数据值,其能大大提高ADC的工作效率。以下为ADC 模块框图:
ADC 模块框图

二、原理

1.ADC连续扫描模式

在配置多个通道采集时,如图:CH2、CH1、CH5、CH7、CH11,在扫描模式下,会对各个通道一次进行数据采样,再使用连续模式时,会对循环对上述通道进行连续数据采样,配置原理如下:

扫描运行模式可以通过将 ADC_CTL0 寄存器的 SM 位置 1 来使能。在此模式下, ADC 扫描转换所有被 ADC_RSQ0~ADC_RSQ2 寄存器选中的所有通道。一旦 ADCON 位被置 1,当相应软件触发或者外部触发产生, ADC 就会一个接一个的采样和转换常规序列通道。转换数据存储在 ADC_RDATA 寄存器中。常规序列转换结束后, EOC 位将被置 1。如果 EOCIE 位被置1,将产生中断。当常规序列工作在扫描模式下时, ADC_CTL1 寄存器的 DMA 位必须设置为1。如果 ADC_CTL1 寄存器的 CTN 位也被置 1,则在常规序列转换完之后,这个转换自动重新开始。

在这里插入图片描述
常规序列扫描运行模式的软件流程:

  1. 设置 ADC_CTL0 寄存器的 SM 位和 ADC_CTL1 寄存器的 DMA 位为 1;
  2. 配置 ADC_RSQx 和 ADC_SAMPTx 寄存器;
  3. 如果有需要,配置 ADC_CTL1 寄存器中的 ETERC 和 ETSRC 位;
  4. 准备 DMA 模块,用于传输来自 ADC_RDATA 的数据;
  5. 设置 SWRCST 位,或者给常规序列产生一个外部触发;
  6. 等待 EOC 标志位置 1;
  7. 写 0 清除 EOC 标志位。

2.DMA传输

当ADC使用连续扫描时,采样数据非常快且数据都暂存在ADC_RDATA寄存器中,我们可使用DMA自动将采样数据依次保存到内存中备用,各个通道采样数据经DMA传输到内存后的映射关系如图:

在这里插入图片描述

如图:一共五个通道需要连续扫描,我们定义一个二维数组Value[3][5]储存扫描值,3表示每个通道保存最近3次扫描的数据,5表示五个通道,该二维数组的内存分布如图所示,每个数据为两个字节大小。扫描时会依次将各通道数据保存到ADC_data寄存器,DMA会将寄存器数据依次搬迁到Value[][]数组中备用,Value空间30个字节,为当第四次扫描时会覆盖第一次扫描的数据,依次覆盖更新。

3.ADC内部通道

将 ADC_CTL1 寄存器的 TSVREN 位置 1 可以使能温度传感器通道(ADC0_IN16)和 VREFINT 通道(ADC0_IN17)。温度传感器可以用来测量器件周围的温度。传感器输出电压能被 ADC 转换成数字量。建议温度传感器的采样时间至少设置为 ts_temp µs(具体数值请参考datasheet 文档)。温度传感器不用时,复位 TSVREN 位可以将其置于掉电模式。温度传感器的输出电压随温度线性变化,由于生产过程的多样化,温度变化曲线的偏移在不同的芯片上会有不同(最多相差 45°C)。内部温度传感器更适合于检测温度的变化,而不是测量绝对温度。如果需要测量精确的温度,应该使用一个外置的温度传感器来校准这个偏移错误。内部电压参考(VREFINT)提供了一个稳定的(带隙基准)电压输出给 ADC 和比较器。 VREFINT 内部连接到 ADC0_IN17 输入通道
在这里插入图片描述

使用温度传感器:

  1. 配置温度传感器通道(ADC0_IN16)的转换序列和采样时间为 ts_temp µs
  2. 置位 ADC_CTL1 寄存器中的 TSVREN 位,使能温度传感器
  3. 置位 ADC_CTL1 寄存器的 ADCON 位,或者由外部触发启动 ADC 转换
  4. 读取内部温度传感器输出电压 Vtemperature, 并由下面公式计算出实际温度:
    温度 ( ° C ) = ( V 25 – V t e m p e r a t u r e ) / A v g S l o p e + 25 温度 (°C) = {(V_{25} – V_{temperature}) / A_{vg_Slope}} + 25 温度(°C)=(V25Vtemperature)/AvgSlope+25
    V25: 内部温度传感器在 25°C 下的电压,典型值请参考相关型号 datasheet。
    Avg_Slope:温度与内部温度传感器输出电压曲线的均值斜率,典型值请参考相关型号datasheet。

三、配置

我们使用通道ADC_CHANNEL_8和通道ADC_CHANNEL_1分别采样3.3V和12V电压,再使用通道ADC_CHANNEL_16和通道ADC_CHANNEL_17分别采样内部温度传感器和内部参考电压,一共四个通道,每个通道采集五个数据,计算时候再取平均值,因此定义一个二维数组ADC0_Vallue保存数据。

1.ADC配置

代码如下(示例):

static void ADC_Init(void){uint16_t i = 0;/* enable ADC0 clock */rcu_periph_clock_enable(RCU_ADC0);/* config ADC clock */rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);/* ADC mode config */adc_mode_config(ADC_MODE_FREE); /* ADC scan function enable */adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE); /* ADC continous function enable */adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);/*ADC data alignment config */adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);/* ADC channel length config */adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,ADC_CHANNEL_NUM); /* enable the temperature sensor and Vrefint channel */adc_tempsensor_vrefint_enable();/* ADC regular channel config,一个通道转换时长是2.06us */adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_8, ADC_SAMPLETIME_239POINT5);  				//12V adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_1, ADC_SAMPLETIME_239POINT5);				//3V3adc_regular_channel_config(ADC0, 2, ADC_CHANNEL_16,ADC_SAMPLETIME_239POINT5);				//内部温度adc_regular_channel_config(ADC0, 3, ADC_CHANNEL_17,ADC_SAMPLETIME_239POINT5);				//内部参考电压/* ADC trigger config */adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);/* enable ADC0 interface */adc_enable(ADC0);/*延迟14个ADCCLK以等待ADC稳定*/    for(i = 1000u; i > 0; i--){}/* ADC calibration and reset calibration */adc_calibration_enable(ADC0);/* ADC DMA function enable */adc_dma_mode_enable(ADC0);/* ADC software trigger enable */adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);}

2.DMA配置

代码如下(示例):

#define CHANNEL_NUM    (4u)	
#define FILTER_NUM     (5U)uint16_t ADC0_Vallue[FILTER_NUM][CHANNEL_NUM];static void ADC_DMA_Init(void){/* ADC_DMA_channel configuration */dma_parameter_struct dma_data_parameter; rcu_periph_clock_enable(RCU_DMA0);dma_deinit(DMA0, DMA_CH0);/* initialize DMA single data mode */dma_data_parameter.periph_addr  = (uint32_t)(&ADC_RDATA(ADC0));dma_data_parameter.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;dma_data_parameter.memory_addr  = (uint32_t)(&ADC0_Vallue);dma_data_parameter.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT;  dma_data_parameter.direction    = DMA_PERIPHERAL_TO_MEMORY;dma_data_parameter.number       = ADC_FILTER_NUM * ADC_CHANNEL_NUM;dma_data_parameter.priority     = DMA_PRIORITY_HIGH;dma_init(DMA0, DMA_CH0, &dma_data_parameter);dma_circulation_enable(DMA0,DMA_CH0);/* enable DMA channel */dma_channel_enable(DMA0, DMA_CH0);}

3.注意事项

  1. ADC_CTL1 寄存器中的 ADCON 位是 ADC 模块的使能开关。如果该位为 0,则 ADC 模块保持复位状态。为了省电,当 ADCON 位为 0 时, ADC 模拟子模块将会进入掉电模式。ADC 使能后需要等待 tsu时间后才能采样 , tsu 数值详见芯片数据手册;
  2. 实际电压值最好先拿万用表测一下,避免踩了硬件的坑;

四、计算

1.分压转换

因GPIO口无法直接连接3.3v和12v,所以需要使用分压电阻使得接入到adc通的电压小于3.3v,ADC 电阻值应该将为千欧级的电阻,分压原理图如图所示:

在这里插入图片描述

这里以为12v为例,根据初中物理电阻串联分压知识,计算12V实际值:

V i n = V o u t ∗ ( ( R 2 + R 1 ) / R 1 ) V_{in} = V_{out} *((R2+R1)/R1) Vin=Vout((R2+R1)/R1)

2.数据转换

以为12bit分辨率为例,读取到的模拟电压转换后是一个12位的数字值,但这个值对于使用者没什么概念,所以需要再次转换成可读性较好的电压值,也就是用万用表量到的电压值。这里主要用到一个比例概念:一般情况下,ADC的输入电压范围在0~3.3v,所以12位满量程对应的电压值为3.3v,数字值为2^12。我们假设ADC转换后的12位的值为x,其对应的电压值为y,那么:

y x = 3.3 2 12 − 1 (1) \frac{y}{x}=\frac{3.3}{2^{12}-1} \tag{1} xy=21213.3(1)

y = x ∗ ( 3.3 / 2 12 − 1 ) y = x * (3.3 / 2^{12}-1) y=x(3.3/2121)

总结公式为:

V i n = A D V v a l ∗ ( V r e f / 2 N − 1 ) (2) V_{in} = ADV_{val} * (V_{ref}/ 2^N-1)\tag{2} Vin=ADVvalVref/2N1(2)

Vin 为实际电压值,ADCval​ 为ADC采集得到的数字信号值,Vref 为参考电压,N分辨率,
顺便一提:同样的原理通过电流转化公式和电流芯片,也可以采集电流信号

在这里插入图片描述
我们以1.2v作为参考电压标准值,17通道数据作为参数电压值,根据上述公式和数据参数,温度转换函数如下:

static uint8_t ADC_GetTemp(float* Temp)
{ReturnType_u8 ret = 0;uint32_t FilterVltg_Temp;uint32_t SampleVltg_1V2;SampleVltg_1V2 = (uint32_t)(ADC0_Vallue[0][3] + ADC0_Vallue[1][3] + ADC0_Vallue[2][3] + ADC0_Vallue[3][3] + ADC0_Vallue[4][3]) / 5u;FilterVltg_Temp = (uint32_t)(ADC0_Vallue[0][2] + ADC0_Vallue[1][2] + ADC0_Vallue[2][2] + ADC0_Vallue[3][2] + ADC0_Vallue[4][2]) / 5u;if(Temp != NULL_PTR){*Temp = ((float)((1.45 - (FilterVltg_Temp * 1.2 / SampleVltg_1V2)) / 0.0041) + 25);ret = 1;}else{ret = 0;}return ret;
}

对于12V电压的计算原理也一样。

static uint8_t ADC_Get12VVltg(float* Vltg){uint8_t ret = 0;uint32_t FilterVltg_Temp; uint32_t SampleVltg_1V2;SampleVltg_1V2 = (uint32_t)(ADC0_Vallue[0][3] + ADC0_Vallue[1][3] + ADC0_Vallue[2][3] + ADC0_Vallue[3][3] + ADC0_Vallue[4][3]) / 5u;FilterVltg_Temp = (uint32_t)(ADC0_Vallue[0][0] + ADC0_Vallue[1][0] + ADC0_Vallue[2][0] + ADC0_Vallue[3][0] + ADC0_Vallue[4][0]) / 5u;if(Vltg != NULL_PTR){*Vltg = (float)((uint64_t)FilterVltg_Temp * 1.2u * (1u + 11u) / SampleVltg_1V2 / 1u);ret = 1;}         else{ret = 0;}return ret;}

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

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

相关文章

年产200万件的超级工厂投产!巨头「闭环」汽车电子全产业链

随着汽车电动化程度的提升&#xff0c;汽车电子部件占整车成本比重逐步升高&#xff0c;已经从2012年的25%上升到2021年的55%。 且汽车电子电气架构向整车集中演进&#xff0c;智能汽车已经进入了软件及数据定义时代&#xff0c;底层硬件打破了过去几十年围绕特定应用不断增加…

【luckfox】3、计算重量差

前言 本章结合之前的hx711驱动&#xff0c;实现读取质量&#xff0c;记录时间及剩余质量并存入csv文件&#xff0c;计算质量差并总计。 代码 luckfox-pico\project\app\test_app\hx711\hx711_app_addtime.c #include <stdio.h> #include <stdlib.h> #include &…

文心一言 VS 讯飞星火 VS chatgpt (136)-- 算法导论11.3 2题

二、用go语言&#xff0c;假设将一个长度为r的字符串散列到m 个槽中&#xff0c;并将其视为一个以 128 为基数的数&#xff0c;要求应用除法散列法。我们可以很容易地把数 m 表示为一个 32 位的机器字&#xff0c;但对长度为r的字符串&#xff0c;由于它被当做以 128 为基数的数…

基于JavaWeb+SSM+微信小程序基金优选系统的设计和实现

基于JavaWebSSM微信小程序基金优选系统的设计和实现 源码获取入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 前言 基金优选是金融机构的核心&#xff0c;是必不可少的一个部分。在金融机构的整个服务行业中…

使用requests解决请求库Session对象设置超时的问题

在使用 Python 中的 requests 库时&#xff0c;有一个常见的问题是关于 Session 对象设置超时的功能。默认情况下&#xff0c;requests 的 Session 对象没有提供一个全局设置超时的属性&#xff0c;而是需要在每个请求中单独设置超时时间&#xff0c;或者创建一个自定义的子类来…

【PTQ】Cross-Layer Equalization跨层均衡-证明和实践详细解读

Cross-Layer Equalization跨层均衡 aimet解读 符合规则的模型结构 统一要求&#xff1a;单数据流&#xff0c;中间激活不流向其他地方概念说明&#xff1a; Conv: gruoups1的普通卷积&#xff0c;包括TransposedConv和ConvDepthwiseConv: 深度可分离卷积&#xff0c;groupsi…

AIGC实战——变分自编码器(Variational Autoencoder, VAE)

AIGC实战——变分自编码器 0. 前言1. 变分自编码器1.1 基本原理1.2 编码器 2. 构建VAE编码器2.1 Sampling 层2.2 编码器2.3 损失函数2.4 训练变分自编码器 3. 变分自编码器分析小结系列链接 0. 前言 我们已经学习了如何实现自编码器&#xff0c;并了解了自编码器无法在潜空间中…

<C++> 反向迭代器

我们知道正向迭代器的设计&#xff1a;begin迭代器指向第一个数据&#xff0c;end迭代器指向最后一个数据的下一个位置 。移向下一个数据&#xff0c;解引用得到数据的值&#xff0c;并根据容器储存方式的不同&#xff0c;容器有不同类型的迭代器。 注意&#xff1a;rbegin迭代…

SecureCRT 9.4.2最新终端SSH工具

SecureCRT是一款终端SSH工具&#xff0c;它提供了类似于Telnet和SSH等协议的远程访问功能。SecureCRT软件特色包括&#xff1a; 支持SSH&#xff08;SSH1和SSH2&#xff09;的终端仿真程序&#xff0c;能在Windows下登录UNIX或Linux服务器主机。SecureCRT支持SSH&#xff0c;同…

媒体行业的3D建模:在影视中创造特效纹理

在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 在本文中&#xff0c;我们将探讨 3D 建模在媒体行业中的作用&#xff0c;特别是它在影视特效创作…

基于STM32的无线通信系统设计与实现

【引言】 随着物联网的迅速发展&#xff0c;无线通信技术逐渐成为现代通信领域的关键技术之一。STM32作为一款广受欢迎的微控制器&#xff0c;具有丰富的外设资源和强大的计算能力&#xff0c;在无线通信系统设计中具有广泛的应用。本文将介绍如何基于STM32实现一个简单的无线通…

站群服务器 CentOS 搭建socks5多IP代理服务器详细教程,12个步骤教会你!

准备工作 首先要保证服务上能正常使用wget tar make vim&#xff0c;如果正常就直接进入【第一步】 #安装wget的命令 yum install wget#安装tar解压工具 yum install -y tar#安装make的命令 yum groupinstall "Development Tools"#安装vim的命令 yum install…

《洛谷深入浅出进阶篇》P3397 地毯————二维差分

上链接&#xff1a;P3397 地毯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P3397 上题干&#xff1a; 题目描述 在 nn 的格子上有 m 个地毯。 给出这些地毯的信息&#xff0c;问每个点被多少个地毯覆盖。 输入格式 第一行&#xff0c;两个…

浅尝:iOS的CoreGraphics和Flutter的Canvas

iOS的CoreGraphic 基本就是创建一个自定义的UIView&#xff0c;然后重写drawRect方法&#xff0c;在此方法里使用UIGraphicsGetCurrentContext()来绘制目标图形和样式 #import <UIKit/UIKit.h>interface MyGraphicView : UIView endimplementation MyGraphicView// Onl…

桌面云架构讲解(VDI、IDV、VOI/TCI、RDS)

目录 云桌面架构 VDI 虚拟桌面基础架构 IDV 智能桌面虚拟化 VOI/TCI VOI 虚拟系统架构 TCI 透明计算机架构 RDS 远程桌面服务 不同厂商云桌面架构 桌面传输协议 什么是云桌面 桌面云是虚拟化技术成熟后发展起来的一种应用&#xff0c;桌面云通常也称为云桌面、VDI等 …

Flink(五)【DataStream 转换算子(上)】

前言 这节注定是一个大的章节&#xff0c;我预估一下得两三天&#xff0c;涉及到的一些东西不懂就重新学&#xff0c;比如 Lambda 表达式&#xff0c;我只知道 Scala 中很方便&#xff0c;但在 Java 中有点发怵了&#xff1b;一个接口能不能 new 来构造对象? 答案是可以的&…

代码随想录 Day47 动态规划15 LeetCode T583 两个字符串的删除操作 T72 编辑距离

LeetCode T583 两个字符串的删除操作 题目链接:583. 两个字符串的删除操作 - 力扣&#xff08;LeetCode&#xff09; 题目思路: 本题有两个思路 1.使用两个字符串的长度之和-2*最长公共子串(换汤不换药) 代码随想录Day45 动态规划13 LeetCode T1143最长公共子序列 T1135 不相交…

跨国企业如何选择安全靠谱的跨国传输文件软件?

随着全球化的不断发展&#xff0c;跨国企业之间的合作变得越来越频繁。而在这种合作中&#xff0c;如何安全、可靠地将文件传输给合作伙伴或客户&#xff0c;成为了跨国企业必须面对的问题。 然而&#xff0c;跨国文件传输并不是一件容易的事情&#xff0c;由于网络物理条件的…

OpenCV入门4——实现图形的绘制

文章目录 OpenCV绘制直线OpenCV绘制矩形和圆画矩形画圆 OpenCV椭圆的绘制OpenCV绘制多边形OpenCV绘制文本实现鼠标绘制基本图形 OpenCV绘制直线 # -*- coding: utf-8 -*- import cv2 import numpy as npimg np.zeros((480, 640, 3), np.uint8) # 坐标点为(x, y) cv2.line(img,…

《视觉SLAM十四讲》-- 后端 1(下)

8.2 BA 与图优化 Bundle Adjustment 是指从视觉图像中提炼出最优的 3D 模型和相机参数&#xff08;内参和外参&#xff09;。 8.2.1 相机模型和 BA 代价函数 我们从一个世界坐标系中的点 p \boldsymbol{p} p 出发&#xff0c;把相机的内外参数和畸变都考虑进来&#xff0c;…