STM32的HAL库开发---单通道ADC采集(DMA读取)实验

ops/2025/2/22 9:55:30/

一、实验简介

正常单通道ADC采集顺序是先开启ADC采集,然后等待ADC转换完成,也就是判断EOC位置1,然后再读取数据寄存器的值。

如果配置了DMA功能,在EOC位被硬件置1后,自动产生DMA请求,然后DMA进行数据搬运。

1,功能描述 通过DMA读取数据

通过ADC1通道1PA1)采集电位器的电压,并显示ADC转换的数字量及换算后的电压值

2、确定最小刻度

VREF+ = 3.3V ---》 0V ≤ VIN ≤  3.3V ---》最小刻度 = 3.3 / 4096 ,F1的分辨率是12位的,也就是把3.3V分为4096份。F4/F7/H7还可以自己配置分辨率,例如H7可以把分辨率配置为16位的,也就是把3.3V进行65536等分。

3,确定转换时间

采样时间239.5个ADC时钟周期为例,可以得到转换时间为21us。例如配置为最长的采样时间239.5个采样周期,那么采样时间就是239.5 + 12.5  = 252个时钟周期。配置ADC的时钟的12M,则转换时间为252 * (1 / 12000000) = 21us,采样时间设置的越大,准确度越高,设置的越小,准确度越低。

4、模式组合

由于使用了DMA搬运,所以使用连续转换模式、不使用扫描模式

二、单通道ADC采集实验配置步骤 

1、HAL_DMA_Init()函数,初始化DMA

2、__HAL_LINKDMA()宏定义,将DMAADC句柄联系起来

3、HAL_ADC_Init()函数,用于初始化ADC,配置ADC工作参数。

4、HAL_ADCEx_Calibration_Start()函数,用于ADC校准的。

5、HAL_ADC_MspInit()函数, 配置NVIC、CLOCK、GPIO

6、HAL_ADC_ConfigChannel()函数,配置ADC相应通道相关参数

7、HAL_NVIC_SetPriority()HAL_NVIC_EnableIRQ()函数,使能DMA数据流传输完成中断

8、DMAx_Channely_IRQHandler()函数,编写DMA数据流中断服务函数

9、HAL_DMA_Start_IT()函数,启动DMA,开启传输完成中断

10、HAL_ADC_Start_DMA()函数,触发ADC转换,DMA传输数据

三、 实验程序

1、寄存器版本

dma.c源程序

#include "./BSP/DMA/dma.h"
#include <string.h>uint16_t ADC_data[20];
//配置ADC1的DMA1的通道1请求
void DMA_Init(void)
{//开启DMA1时钟RCC->AHBENR |= (1 << 0);//MEM2MEM 设置为非存储器到存储器模式DMA1_Channel1->CCR &= ~(1 << 14);//PL 设置通道优先级为中DMA1_Channel1->CCR |= (1 << 12);//MSIZE 设置存储器数据宽度为16位DMA1_Channel1->CCR |= (1 << 10);//PSIZE 设置外设数据宽度为16位DMA1_Channel1->CCR |= (1 << 8);//MINC 设置存储器增量模式DMA1_Channel1->CCR |= (1 << 7);//PINC 设置外设不增量模式DMA1_Channel1->CCR &= ~(1 << 6);//CIRC 不执行循环模式//DMA1_Channel1->CCR &= ~(1 << 5);DMA1_Channel1->CCR |= (1 << 5);//DIR 从外设读取DMA1_Channel1->CCR &= ~(1 << 4);	//设置传输数量DMA1_Channel1->CNDTR = 20;//设置DMA的外地址DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;//清空ADC_datamemset((void*)ADC_data,0,20);DMA1_Channel1->CMAR = (uint32_t)ADC_data;//EN 开启DMA  这个必须放在最后  不然CNDTR寄存器不能写入DMA1_Channel1->CCR |= (1 << 0);
}

adc.c源程序

#include "./BSP/ADC/adc.h"//配置ADC1的通道1 PA1进行
void ADC_Init(void)
{//开启ADC1时钟RCC->APB2ENR |= (1 << 9);//关闭扫描模式ADC1->CR1 &= ~(1 << 8);//开启外部触发转换ADCADC1->CR2 |= (1 << 20);//EXTSEL 设置软件触发ADC转换ADC1->CR2 |= (7 << 17);//ALIGN 数据右对齐ADC1->CR2 &= ~(1 << 11);//DMA 开启DMA转换ADC1->CR2 |= (1 << 8);//CONT 开启连续转换模式ADC1->CR2 |= (1 << 1);//设置ADC1通道1转换时间为239.5个周期ADC1->SMPR2 |= (7 << 3);//L 设置总共1一个转换通道ADC1->SQR1 |= (1 << 20);//设置ADC第一个转换为通道1ADC1->SQR3 |= (1 << 0);//EXTTRIG 开启GPIOA时钟RCC->APB2ENR |= (1 << 2);//设置PA1为输入模式GPIOA->CRL &= ~(0XF << 4);//ADON 开启ADC功能ADC1->CR2 |= (1 << 0);//RSTCAL 初始化ADC校准寄存器ADC1->CR2 |= (1 << 3);//等待ADC校准寄存器初始化完毕while(ADC1->CR2 & (1 << 3));//开启ADC校准ADC1->CR2 |= (1 << 2);//等待ADC校准完成while(ADC1->CR2 & (1 << 2));//SWSTART 开启规则组转换 软件触发ADC1->CR2 |= (1 << 22);
}

2、库函数版本

dam.c源程序

#include "./BSP/DMA/dma.h"
#include <string.h>extern ADC_HandleTypeDef hadc;
DMA_HandleTypeDef hdma;
//配置ADC1的DMA1的通道1请求
void DMA_Init(void)
{//开启DMA1时钟__HAL_RCC_DMA1_CLK_ENABLE();//配置DMA1通道  因为ADC1连接在DMA1的通道1  这个在使用手册可以查找到hdma.Instance = DMA1_Channel1;//外设到内存hdma.Init.Direction = DMA_PERIPH_TO_MEMORY;//内存为16位hdma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;//内存递增hdma.Init.MemInc = DMA_MINC_ENABLE;//循环搬运 //当启动了循环模式,数据传输的数目变为0时,将会自动地被恢复成配置通道时设置的初值,DMA操作将会继续进行。hdma.Init.Mode = DMA_NORMAL;//外设16位hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;//外设地址不递增hdma.Init.PeriphInc = DMA_PINC_DISABLE;//通道1优先级为中hdma.Init.Priority = DMA_PRIORITY_MEDIUM;//配置DMA的通道1为外设到内存HAL_DMA_Init(&hdma);//将DMA句柄于ADC句柄连接起来 可以理解为将这个DMA句柄拷贝到ADC句柄里的DMA句柄上__HAL_LINKDMA(&hadc,DMA_Handle,hdma);
}//标志DMA数据搬运完
uint8_t state = 0;
void DMA1_Channel1_IRQHandler(void)
{if(DMA1->ISR & (1 << 1)){state = 1;//清除中断标志位DMA1->IFCR |= (1 << 1);}DMA1->IFCR |= (1 << 0);
}

adc.c源程序

#include "./BSP/ADC/adc.h"
#include "string.h"extern DMA_HandleTypeDef hdma;
uint16_t ADC_data[20];
ADC_HandleTypeDef hadc;
//配置ADC1的通道1 PA1进行
void ADC_Init(void)
{hadc.Instance = ADC1;//配置ADC连续转换模式 就是ADC转换完成一次后会自动下一次转换hadc.Init.ContinuousConvMode = ENABLE;//转换结果采用右对齐hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;//不开启间断模式hadc.Init.DiscontinuousConvMode = DISABLE;//ADC触发选用软件触发hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;//设置ADC转换数量的 SQR1的L位hadc.Init.NbrOfConversion = 1;//设置间断模式写转换一次转换数量hadc.Init.NbrOfDiscConversion = 0;//不开启扫描模式 因为就一个通道hadc.Init.ScanConvMode = ADC_SCAN_DISABLE;//设置ADC为软件触发转换HAL_ADC_Init(&hadc);//开启ADC校准HAL_ADCEx_Calibration_Start(&hadc);ADC_ChannelConfTypeDef sConfig;//配置通道1sConfig.Channel = ADC_CHANNEL_1;//通道1第一个转换sConfig.Rank = ADC_REGULAR_RANK_1;//采样周期采用239.5sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;//配置ADC通道一为第一个转换HAL_ADC_ConfigChannel(&hadc, &sConfig);memset((void*)ADC_data,0,20);//这句话最好写 不然下面那个会把半传输中断也开开  这里就会开一个中断 因为下面那个函数回把ADC半传输回调函数复制 //这句话不写也行 但是中断里边要清除所有位  不然卡在中断HAL_DMA_Start_IT(&hdma, (uint32_t)ADC1->DR, (uint32_t)ADC_data, 20);//开启DMA传输 这个函数里边会把中断都打开HAL_ADC_Start_DMA(&hadc, (uint32_t* )ADC_data, 20);
}void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{//开启ADC1时钟__HAL_RCC_ADC1_CLK_ENABLE();//开启GPIOA时钟__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitTypeDef GPIO_Init;GPIO_Init.Mode = GPIO_MODE_ANALOG;GPIO_Init.Pin = GPIO_PIN_1;GPIO_Init.Pull = GPIO_NOPULL;//设置PA1为模拟输入模式HAL_GPIO_Init(GPIOA,&GPIO_Init);//使能DMA1通道1中断HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);//设置中断优先级HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,2,2);
}

这里主要是要注意先配置DMA中断,再调用ADC的DMA函数,具体原因在代码里写了


http://www.ppmy.cn/ops/160481.html

相关文章

【c语言初阶】函数_递归和迭代

前言&#xff1a; 内容&#xff1a; n的阶乘的公式&#xff0c;什么情况&#xff0c;怎么没有听懂 我咋知道n的阶乘公式啊 就是这个&#xff0c;老师说知道n的阶乘公式就容易写递归函数了&#xff0c;算了没阿关系 n!(fac(n)) 1 ,n<1 n*fac(n-1) 计算n的阶乘 &#x…

【愚公系列】《Python网络爬虫从入门到精通》025-进程间通信

标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度…

本地部署DeepSeek R1大模型

一、安装软件 1.1 安装Ollama 你可以访问Ollama的官方网站https://ollama.com/download&#xff0c;选择适合你操作系统的安装包进行下载。老周这里是Mac系统&#xff0c;所以选择下载macOS系统。 1.2 安装cherry studio 前往官网https://cherry-ai.com/download下载对应操…

【Gin-Web】Bluebell社区项目梳理3:社区相关接口开发

本文目录 一、接口详情1. 获取分类社区列表接口2. 根据id查询社区 二、值类型与引用类型 一、接口详情 跟社区有关的接口详情如下。 1. 获取分类社区列表接口 首先是Controller层&#xff0c;然后跳转到Logic层业务逻辑的开发。 这是Logic层&#xff0c;再做一次跳转&#…

支持向量机 (Support Vector Machine, SVM)

支持向量机 (Support Vector Machine, SVM) 支持向量机&#xff08;SVM&#xff09;是一种广泛应用于分类、回归分析以及异常检测的监督学习算法。它基于结构风险最小化&#xff08;Structural Risk Minimization&#xff0c;SRM&#xff09;原则&#xff0c;通过寻找一个最优…

tp6上传文件大小超过了最大值+验证文件上传大小和格式函数

问题&#xff1a; 最近用tp6的文件上传方法上传文件时报文件过大错误。如下所示&#xff1a; $file $this->request->file(file);{"code": 1,"msg": "上传文件大小超过了最大值&#xff01;","data": {"code": 1,&q…

TSMaster【第三篇:神兵认主——TSMaster开发环境开锋 】

&#xff08;软件安装如铸剑九步&#xff0c;硬件通道映射暗藏乾坤大挪移心法&#xff09; 【武侠场景导入】光明顶密道寻宝 昔年明教光明顶密道中&#xff0c;张无忌偶得《乾坤大挪移》心法&#xff0c;须打通全身经脉方能施展。今我辈工程师欲驾驭TSMaster这把"倚天剑&…

机器视觉检测中,2D面阵相机和线扫相机的区别

2D面阵相机和线扫相机是工业视觉系统中常用的两种相机类型&#xff0c;各有其特点和应用场景。 2D面阵相机 特点&#xff1a; 成像方式&#xff1a;通过二维传感器一次性捕捉整个场景的图像。 分辨率&#xff1a;分辨率由传感器的像素数决定&#xff0c;常见的有百万像素到几千…