当前位置: 首页 > news >正文

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文库

相关文章:

  • 人工智能端侧热度再起
  • hybird接口配置
  • FTPS和SFTP(文件传输安全协议)
  • ProteinTools辅助探索蛋白稳定性、动态调控以及结构关系
  • windows操作系统开机自启(自动启动) 运行窗口 shell:startup 指令调出开机自启文件夹
  • mux-vlan基础配置
  • Linux服务之nginx中http设置及虚拟主机搭建
  • day 13 不平衡数据集的处理
  • ctfshow web入门 web52
  • 【coze】记忆体(变量、数据库、长期记忆、消息盒子)
  • B站视频下载到电脑的方法总结
  • 商业实战将归巢网内容构建为本地RAG模型的完整指南01-优雅草卓伊凡
  • 开发搭载OneNet平台的物联网数据收发APP的设计与实现
  • 【大模型面试】大模型(LLMs)高频面题全面整理(★2025年5月最新版★)
  • Python+Scrapy跨境电商爬虫实战:从亚马逊/沃尔玛数据采集到反爬攻克(附Pangolin API高效方案)
  • HarmonyOS开发:粒子动画使用详解
  • shell-流程控制-循环-函数
  • 新一代Python专业编译器Nuitka简介
  • 20. LangChain电商场景:构建智能客服与个性化推荐系统
  • MySQL 强制使用特定索引
  • 纪念苏联伟大卫国战争胜利80周年阅兵彩排,解放军仪仗队亮相
  • 诺和诺德一季度减重版司美格鲁肽收入增83%,美国市场竞争激烈下调全年业绩预期
  • 驱逐行动再加码?特朗普或向利比亚和卢旺达遣送非法移民
  • 李云泽:将尽快推出支持小微企业民营企业融资一揽子政策
  • 印度导弹凌晨打击巴基斯坦多座设施,巴总理:正对战争行为作有力回应
  • 【社论】跑赢12级狂风,敦煌做对了什么