GD32/STM32 ADC/DMA使用指南

首先我们对ADC及DMA的基础知识作一下简单介绍。

一、 GD32/STM32  ADC模块的核心要点

一)、ADC基础特性

  1. 12位逐次逼近型
    GD32/STM32 ADC为12位分辨率,最大量化值为4095(对应3.3V参考电压),支持0-3.3V模拟输入范围。
  2. 多通道架构
    • 外部通道:16个(部分型号支持24个外部通道)
    • 内部通道:2个(温度传感器、内部参考电压)
  3. 时钟系统
    • 模拟时钟(ADCCLK):由APB2时钟分频(/2、/4、/6、/8)生成,上限14MHz
    • 数字时钟:等同于APB2时钟

二)、核心功能模式

  1. 转换模式
    • 单次转换‌:手动触发单次采样
    • 连续转换‌:自动循环采样同一通道
    • 扫描模式‌:自动遍历多通道
  2. 通道分组机制
    • 规则组‌:常规转换队列(最多16路)
    • 注入组‌:高优先级中断式转换(最多4路)
  3. 触发方式
    • 软件触发
    • 硬件触发(TIMER、EXTI等)

三)、数据管理

  1. 对齐方式
    • 右对齐:默认模式,数据存于寄存器低12位
    • 左对齐:便于快速读取高8位数据
  2. 校准机制
    • 上电自校准
    • 温度传感器校准(需单独使能)

四)、典型应用配置

// HAL库配置示例(单通道连续转换)
ADC_HandleTypeDef hadc;
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;  // ADCCLK=21MHz
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.ContinuousConvMode = ENABLE;  // 连续转换模式
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
HAL_ADC_Init(&hadc);

五)、进阶应用方案

  1. DMA传输
    实现多通道数据自动搬运,减少CPU开销
  2. 定时器触发
    精确控制采样间隔(适用于波形采集)
  3. 模拟看门狗
    设置电压阈值触发中断(过压/欠压保护)

六)、关键注意事项

  1. 输入阻抗匹配:建议源阻抗≤10kΩ
  2. 抗干扰设计:
    • 独立模拟供电引脚(VDDA、VSSA)
    • 添加RC滤波电路
    • 避免数字信号线平行走线
  3. 开启DMA双缓冲模式提升吞吐量
  4. 使用过采样技术提高有效分辨率
  5. 低温漂外部基准电压(如REF3030)提升精度

七)、关于ADC转换时间计算

转换时间 = (采样周期 + 12.5周期) / ADCCLK
例如:当ADCCLK=21MHz,采样周期=84周期时,总转换时间≈4.59μs37

二、GD32/STM32  DMA 介绍

 一)、DMA基础概念

  1. 定义与作用
    DMA(Direct Memory Access)是一种无需CPU参与的硬件数据传输机制,可实现外设与内存之间(如ADC数据存入数组)、内存与外设之间(如UART发送数据)或内存与内存之间的高速数据搬运56。其核心作用是释放CPU资源,提升系统实时性与效率。

  2. 硬件架构

    • 双控制器架构‌:STM32F1系列包含DMA1(7通道)和DMA2(5通道,仅大容量型号支持)
    • 总线矩阵‌:DMA通过总线矩阵连接AHB总线,实现与外设、存储器的并行访问
    • 数据流与通道‌:每个DMA控制器包含独立的数据流(Stream),每个数据流可映射至8个硬件通道(如DMA1_Channel4对应UART1_TX)

二)、DMA核心特性

  1. 传输方向

    • 外设→存储器(如ADC采集数据)
    • 存储器→外设(如SPI发送数据)
    • 存储器→存储器(高速数据拷贝)
  2. 数据管理

    • 数据宽度‌:支持8/16/32位,源与目标宽度可独立配置(自动填充/截断)
    • 地址递增‌:传输后自动递增源/目标地址,支持非连续数据传输
    • 循环模式‌:自动重置传输计数器,实现环形缓冲区(适用于连续采样场景)
  3. 优先级与仲裁

    • 软件可设4级优先级(很高、高、中、低)
    • 硬件仲裁器自动处理同优先级请求

三)、DMA配置流程(以HAL库为例)

// 示例:配置UART通过DMA发送数据
// 1. 使能DMA时钟
__HAL_RCC_DMA1_CLK_ENABLE();  // DMA1时钟使能:ml-citation{ref="4,8" data="citationList"}// 2. 初始化DMA参数
DMA_HandleTypeDef hdma_uart_tx;
hdma_uart_tx.Instance = DMA1_Channel4;          // 选择通道
hdma_uart_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; // 存储器→外设
hdma_uart_tx.Init.PeriphInc = DMA_PINC_DISABLE;     // 外设地址固定
hdma_uart_tx.Init.MemInc = DMA_MINC_ENABLE;         // 存储器地址递增
hdma_uart_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; 
hdma_uart_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_uart_tx.Init.Mode = DMA_NORMAL;            // 单次传输模式
HAL_DMA_Init(&hdma_uart_tx);// 3. 绑定外设与DMA
__HAL_LINKDMA(&huart1, hdmatx, hdma_uart_tx);  // 关联UART1发送端:ml-citation{ref="4,8" data="citationList"}

四)、典型应用场景

场景描述关键配置要点
ADC多通道采样循环采集多个传感器数据并存入数组扫描模式 + DMA循环传输
串口大数据传输高速发送/接收数据包(如Modbus通信)双缓冲机制 + 传输完成中断
内存高速拷贝内部Flash到SRAM的固件升级存储器到存储器模式

五)、关键注意事项

  1. 时钟使能

    • 必须使能DMA控制器时钟(如__HAL_RCC_DMA1_CLK_ENABLE())和外设时钟
  2. 中断管理

    • 使能传输完成/半传输/错误中断,并在中断服务函数中清除标志位
  3. 数据对齐

    • 确保源/目标地址对齐(如32位传输时地址需4字节对齐)

三、ADC校正 

一)、校准核心流程

  1. 基础校准(标准模式)

    • 上电后执行基础校准,消除电容误差
    • 操作步骤‌:
      ① ADC上电(ADON=1)但未启动转换
      ② 执行校准命令(ADC_StartCalibration(ADC1))
      ③ 等待校准完成标志位
  2. 内部参考电压校准

    • 利用内置VREFINT通道(通道17)实现动态精度补偿
    • 实现逻辑‌:
      ① 测量VREFINT通道原始值(典型值约1.2V)
      ② 计算比例因子:Scale = VREFINT_实际值 / ADC_VREFINT原始值
      ③ 应用比例因子至其他通道

        考虑到电压校准需要手动测量VREFINT,加上我们大多应用并不需要获取准确电压值,只需要知道ADC值的变化,所以通常我们可以不做电压校准。

 四、ADC程序实现示例

 一)、单通道轮询模式(标准库)

// 引用[1][8]的配置逻辑
#include "stm32f10x.h"void ADC1_Init(void) {// 开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);// 配置ADC时钟为PCLK2的6分频(ADCCLK=12MHz)RCC_ADCCLKConfig(RCC_PCLK2_Div6); // GPIO配置为模拟输入GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStruct);// ADC参数配置ADC_InitTypeDef ADC_InitStruct;ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;       // 独立模式ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;   // 右对齐ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;      // 单次转换ADC_InitStruct.ADC_ScanConvMode = DISABLE;            // 非扫描模式ADC_Init(ADC1, &ADC_InitStruct);// 校准ADCADC_Cmd(ADC1, ENABLE);ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1));ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1));
}uint16_t Get_ADC_Value(void) {ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);ADC_SoftwareStartConvCmd(ADC1, ENABLE);  // 启动转换while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 等待转换完成return ADC_GetConversionValue(ADC1);     // 返回12位转换结果
}

 二)、多通道DMA传输(标准库)

void	ADC1_Init(void)
{
#if 1GPIO_InitTypeDef GPIO_InitStructure;DMA_InitTypeDef DMA_InitStructure;ADC_InitTypeDef ADC_InitStructure;u8	rank = 1;/* Enable DMA clock */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	/* Enable ADC1 clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);/* Configure PB0 & PB1 as analog input */GPIO_InitStructure.GPIO_Pin = PAPER_END_SEN | PAPER_IN_SEN;// | GPIO_BM_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIO_SENSOR, &GPIO_InitStructure);				// PB0 & PB1,输入时不用设置速率/* DMA channel1 configuration */DMA_DeInit(DMA1_Channel1);DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;;	 //ADC地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SensorNow.ADC_Val;//内存地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = ADC_CH_MAX;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址固定DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址增加DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	//半字DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;		//循环传输DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel1, &DMA_InitStructure);/* Enable DMA channel1 */DMA_Cmd(DMA1_Channel1, ENABLE);/* ADC1 configuration */ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//独立ADC模式ADC_InitStructure.ADC_ScanConvMode = ENABLE ; 	 //使能扫描模式,扫描模式用于多通道采集ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//开启连续转换模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//不使用外部触发转换ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 	//采集数据右对齐ADC_InitStructure.ADC_NbrOfChannel = ADC_CH_MAX;	 	//通道数目ADC_Init(ADC1, &ADC_InitStructure);/*配置ADC时钟,为PCLK2的8分频,即9MHZ*/RCC_ADCCLKConfig(RCC_PCLK2_Div8); /*配置ADC的通道采样周期及序列 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_15, rank ++, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_14, rank ++, ADC_SampleTime_55Cycles5);
/* Enable ADC1 DMA */ADC_DMACmd(ADC1, ENABLE);/* Enable ADC1 */ADC_Cmd(ADC1, ENABLE);/*复位校准寄存器*/   ADC_ResetCalibration(ADC1);/*等待校准寄存器复位完成*/while(ADC_GetResetCalibrationStatus(ADC1));/* ADC校准*/ADC_StartCalibration(ADC1);/* 等待校准完成*/while(ADC_GetCalibrationStatus(ADC1));/* 前面设置为不使用外部触发转换,所以使用软件触发ADC转换 */ ADC_SoftwareStartConvCmd(ADC1, ENABLE);
#endif	
}

 三)、定时器触发ADC采样(标准库)

   1、TIM定时器配置

  • 时钟使能与模式设置
    选择TIM工作模式(如PWM模式或基本定时模式),配置预分频器(PSC)和自动重载值(ARR)以设定触发频率。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能TIM3时钟TIM_TimeBaseInitTypeDef TIM_InitStruct;
TIM_InitStruct.TIM_Prescaler = 72 - 1;       // 72MHz/72=1MHz
TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_InitStruct.TIM_Period = 1000 - 1;        // 触发频率1kHz (1MHz/1000)
TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &TIM_InitStruct);TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update); // 更新事件触发TRGO
TIM_Cmd(TIM3, ENABLE);                                // 启动定时器

2. ‌ADC触发源配置
ADC初始化与外部触发选择

启用ADC外部触发,选择TIM的TRGO事件作为触发源。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 使能ADC1时钟ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;          // 独立模式
ADC_InitStruct.ADC_ScanConvMode = DISABLE;               // 单通道扫描
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;         // 单次转换模式
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; // TIM3触发
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;      // 右对齐
ADC_Init(ADC1, &ADC_InitStruct);ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); // 配置通道0
ADC_Cmd(ADC1, ENABLE);                                                       // 启动ADC

五、完整工程文件 

【免费】GD32/stm32ADC、DMA、UART、SPI、Flash读写、DRV8812/DRV8813步进马达驱动、TIMER中断、GPIO控制资源-CSDN文库

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

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

相关文章

Linux(十四)进程间通信(IPC),管道

一、进程间通信 (一)系统介绍进程间通信 进程间通信(IPC)介绍 小编插入的这篇文章详细介绍了进程间通信的一些内容,大家可以一起学习。 (二)进程间通信的方法 1、管道 2、信号量 3、共享…

使用Homebrew下载配置git和连接GitHub(Mac版)

本文详细介绍了在M系列Mac上安装Homebrew并配置Git的过程,包括git的下载、设置全局用户名和邮箱、生成SSH密钥、添加GitHubSSH密钥以及终端验证。这些步骤有助于用户顺利进行协同开发。 一、下载git 1、终端输入一下命令 brew install git2、这时下载完成 二、配…

悬崖边的摄影牧歌

在云雾缭绕的悬崖边,一场独属于自然与光影的邂逅悄然上演。 摄影师伫立于此,身旁是一群灵动的羊。他架起相机,眼神专注而炽热,仿佛要将这天地间的一切都收纳进小小的取景器。悬崖陡峭,岩石冷峻,却因羊群的洁…

Linux环境基础与开发工具使用

1. Linux编译器vim 1.1 vim的基本概念讲解 vim有很多种模式,我们初学者常用的就是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode)。 命令/正常模式(Normal mode) …

《Python星球日记》 第36天:线性代数基础

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏:《Python星球日记》,限时特价订阅中ing 目录 一、标量、…

使用VMware Workstation pro 17.5.1在Windows上安装Ubuntu 24.04.2的 详细步骤

一、准备工作 1. 下载Ubuntu 24.04.2 ISO镜像 官方下载地址:Ubuntu 24.04.2 (Noble Numbat) 选择 ubuntu-24.04.2-desktop-amd64.iso(桌面版)或 ubuntu-24.04.2-live-server-amd64.iso(服务器版)。 2. 确认系统要求…

ios systeam introduction

Here is an in-depth look at Apple’s iOS, from its inception to its latest major release, covering architecture, core components, security, app lifecycle, development tools, and the headline features of iOS 18. iOS began life as “iPhone OS,” unveiled alo…

优化04-选择率和直方图

选择率 在Oracle数据库中,选择率(Selectivity) 是优化器(CBO,基于成本的优化器)用来评估SQL语句中某个条件(如WHERE子句)过滤数据的比例的关键指标。它直接影响优化器选择执行计划的…

python实战:通过输入文字匹配在docx文档中的具体位置

在指定的docx文档中,输入一串文字来查看该文字在文档中的具体位置;方便后续处理(如替换文字,高亮显示等等操作) from docx import Documentdef find_text_in_docx(file_path, search_text):# 读取docx文件doc = Document(file_path)# 遍历段落,查找匹配的文本for i

Flutter——数据库Drift开发详细教程(二)

目录 1.核心API1.1查询数据列表分页1.2 列表排序1.3推迟获取与观察 1.核心API 1.1查询数据列表分页 限制返回的结果数量limit&#xff0c;从某一位置开始查询offset ///limit10, offset10 Future<List<TodoItem>> limitTodos(int limit, {int? offset}) {return …

mux-vlan基础配置

1.top配置 2.各个交换机设置 sw3交换机的 sysname swb # undo info-center enable # vlan batch 10 20 30 100 # vlan 10description financial vlan vlan 20description marketing vlan vlan 30description client vlan vlan 100description principal vlanmux-vlansubordi…

SAM详解2(初级应用)

SAM SAM5. 初级应用5.1 静态本质不同子串个数5.2 字符串匹配5.3 关于子串出现次数5.4 动态添加时本质不同子串个数SAM 5. 初级应用 记 l o n g e s t ( x ) longest(x) longest(x) 为点 x x x 代表子串集合中最长串的长度。记 s h o r t e s t ( x ) shortest(x) shortest(…

【日撸 Java 三百行】Day 4(条件语句实战——闰年问题)

目录 Day 4&#xff1a;条件语句实战——闰年问题 一、基础知识及代码思路 二、代码及测试 小结 Day 4&#xff1a;条件语句实战——闰年问题 Task&#xff1a; if 语句的嵌套.基本规律自行百度.布尔类型. 一、基础知识及代码思路 1. 什么是闰年&#xff1f; 闰年是历法中…

MySQL 中 EXISTS (SELECT 1 FROM ...) 的用法详解

EXISTS (SELECT 1 FROM ...) 是 MySQL 中用于存在性检查的核心语法&#xff0c;其核心逻辑是判断子查询是否返回至少一行数据。以下从作用原理、使用场景、性能优化等方面展开解析&#xff0c;并结合具体示例说明。 1. 基本语法与作用原理 语法结构&#xff1a; SELECT 列名 F…

阿里云服务器防御是怎么做出来的?服务器攻击方式有几种?

阿里云服务器防御是怎么做出来的?服务器攻击方式有几种&#xff1f; 服务器防御是一个多层次、多维度的体系&#xff0c;通常包括以下核心措施&#xff1a; 1. 网络层防御 防火墙&#xff08;Firewall&#xff09;&#xff1a;过滤非法流量&#xff0c;仅允许授权通信&#xf…

ElasticSearch深入解析(八):索引设置、索引别名、索引模板

一、索引的动态设置、静态设置 索引设置包含两部分核心内容&#xff1a; 静态设置(static index settings)&#xff0c;只允许在创建索引时或者针对已关闭的索引进行设置。指动态设置(dynamic index settings)&#xff0c;可以借助更新设置(update settings)的方式进行动态更新…

Prometheus实战教程:k8s平台手动部署Grafana

以下是一个可用于生产环境的 Kubernetes 部署 Grafana 的 YAML 文件。该配置包括 Deployment、Service、ConfigMap 和 PersistentVolumeClaim&#xff0c;确保 Grafana 的高可用性和数据持久化。 Grafana 生产部署 YAML 文件 ☆实操示例 cat grafana-deployment.yaml 登录后复制…

VSTO外接程序与VBA的联动尝试

文章目录 前言一、第一坑&#xff1a;安装offic2007后excel加载项找不到了二、示例1 通过Ribbon XML自定义Excel主菜单并添加新项二、示例1 总结三、示例2 创建VSTO外接程序三、示例2 总结四、示例 3 C# VSTO外接程序示例四、示例 3 总结五、实现C# 的VSTO调用VBA函数(xlam)六、…

DeepSeek驱动的金市情绪量化:NLP解析贸易政策文本的情绪传导路径

【AI观察】政策信号与市场情绪的量化关联 基于自然语言处理技术对全球财经文本的情绪分析显示&#xff0c;4月30日亚盘时段现货黄金价格波动率较前日下降12.3%&#xff0c;与技术面修正指标呈现强相关性。特政府最新关税政策调整引发市场风险偏好指数&#xff08;RPI&#xff…

期末代码Python

以下是 学生信息管理系统 的简化版代码示例&#xff08;控制台版本&#xff0c;使用文件存储数据&#xff09;&#xff0c;包含核心功能&#xff1a; 1. 定义学生类 class Student: def __init__(self, sid, name, score): self.sid sid # 学号 self.name name # 姓名 self.s…