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

一、实验简介

正常单通道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.mzph.cn/news/896066.shtml

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

相关文章

编译原理基础(1)

1.什么是ASCII码&#xff1f; ASCII码即美国信息交换标准代码&#xff0c;是基于拉丁字母的电脑编码系统&#xff0c;用于显示现代英语和部分西欧语言。其7位编码范围0-127&#xff0c;8位扩展到0-255。字符集含控制字符&#xff08;0-31、127&#xff0c;用于控制设备或表示通…

基于 Highcharts 实现 Vue 中的答题统计柱状图组件

在现代 Web 开发中&#xff0c;数据可视化是一个重要的组成部分&#xff0c;而 Highcharts 是一个广泛使用的 JavaScript 图表库&#xff0c;可以帮助开发者在 Web 页面上轻松地绘制丰富的图表。在本文中&#xff0c;我们将基于 Highcharts 创建一个用于答题统计的柱状图&#…

SQLAlchemyError: A transaction is already begun on this Session.

资料 sqlalchemy 事务 - 简书 在 SQLAlchemy 中&#xff0c;事务是通过会话来管理的。当你开始一个事务&#xff08;例如使用 async with db.begin()&#xff09;&#xff0c;它会开启一个新的事务&#xff0c;并在事务块结束时自动提交或回滚。如果在同一个会话中&#xff0c…

Java Web开发实战与项目——Spring Boot与Redis实现缓存管理

缓存技术在现代Web开发中至关重要&#xff0c;尤其是在高并发的环境中&#xff0c;缓存能够有效减少数据库访问压力、提高系统性能。Redis作为最流行的内存数据存储系统之一&#xff0c;常用于缓存管理。本节将讲解如何在Spring Boot项目中集成Redis&#xff0c;实现缓存管理&a…

C语言学习【1】C语言关于寄存器的封装

目录 1.封装寄存的C语言的语法volatile&#xff1a;unsigned int:*pGpiobOdrvolatile unsigned int * 2.进一步C语言的封装 在嵌入式中&#xff0c;底层一定是操作寄存器&#xff0c;我有一个理念&#xff0c;凡事一定要想清楚&#xff0c;把任何知识点融入自己的理解之中&…

#渗透测试#批量漏洞挖掘#畅捷通T+远程命令执行漏洞

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章读。 目录 一、漏洞概况 二、攻击特征 三、应急处置…

ollama 学习笔记

1. 参考博客&#xff1a;1. Ollama完整教程&#xff1a;本地LLM管理、WebUI对话、Python/Java客户端API应用&#xff1a;https://blog.csdn.net/python122_/article/details/1409457202. https://gitee.com/ai-big-model/ollama/tree/main --》REST APIollama 离线安装包 ollam…

ARM Linux平台下 OpenCV Camera 实验

一、硬件原理 1. OV2640 1.1 基本功能 OV2640 是一款低功耗、高性能的图像传感器&#xff0c;支持以下功能&#xff1a; 最高分辨率&#xff1a;200 万像素&#xff08;1600x1200&#xff09;。 输出格式&#xff1a;JPEG、YUV、RGB。 内置图像处理功能&#xff1a;自动曝…

vue2.x中父组件通过props向子组件传递数据详细解读

1. 父组件向子组件传递数据的步骤 在子组件中定义 props&#xff1a; 子组件通过 props 选项声明它期望接收的数据。props 可以是数组形式&#xff08;简单声明&#xff09;或对象形式&#xff08;支持类型检查和默认值&#xff09;。 在父组件中使用子组件时绑定 props&#x…

【Gin】2:快速上手Gin框架(模版、cookie、session)

本文目录 一、模版渲染二、自定义模版函数三、cookie四、Session五、cookie、session区别六、会话攻击 一、模版渲染 在 Gin 框架中&#xff0c;模板主要用于动态生成 HTML 页面&#xff0c;结合 Go 语言的模板引擎功能&#xff0c;实现数据与视图的分离。 模板渲染是一种动态…

【AI绘画】大卫• 霍克尼风格——自然的魔法(一丹一世界)

大卫• 霍克尼&#xff0c;很喜欢这个老头&#xff0c;“艺术是一场战斗”。老先生零九年有了iphone&#xff0c;开始用iphone画画&#xff0c;一零年开始用ipad画画&#xff0c;用指头划拉&#xff0c;据说五分钟就能画一幅&#xff0c;每天早上随手画几幅送给身边的朋友。很c…

解码 NLP:从萌芽到蓬勃的技术蜕变之旅

内容概况&#xff1a; 主要讲述NLP专栏的内容和NLP的发展及其在现代生活中的广泛应用。专栏强调实践为主、理论为辅的学习方法&#xff0c;并通过多个生活场景展示了NLP技术的实际应用&#xff0c;如对话机器人、搜索引擎、翻译软件、电商推荐和智能客服等。 这边我就不多做自我…

解决DeepSeek服务器繁忙问题的实用指南

目录 简述 1. 关于服务器繁忙 1.1 服务器负载与资源限制 1.2 会话管理与连接机制 1.3 客户端配置与网络问题 2. 关于DeepSeek服务的备用选项 2.1 纳米AI搜索 2.2 硅基流动 2.3 秘塔AI搜索 2.4 字节跳动火山引擎 2.5 百度云千帆 2.6 英伟达NIM 2.7 Groq 2.8 Firew…

前端(AJAX)学习笔记(CLASS 2):图书管理案例以及图片上传

* BootStrap弹框 功能&#xff1a;不离开当前页面&#xff0c;显示单独内容&#xff0c;供用户操作 步骤&#xff1a; 1、引入bootstrap.css和bootstrap.js 2、准备弹框标签&#xff0c;确认结构 3、通过自定义属性&#xff0c;控制弹框的显示和隐藏 其中的bootstrap.css…

数据结构:双链表list

list 是 C 标准库中的双向链表容器。 list初始化示例&#xff1a; #include <list>int n 7;std::list<int> lst; // 初始化一个空的双向链表 lststd::list<int> lst(n); // 初始化一个大小为 n 的链表 lst&#xff0c;链表中的值默认都为 0std::list<i…

AI Agent Service Toolkit:一站式大模型智能体开发套件

项目简介 该工具包基于LangGraph、FastAPI和Streamlit构建,提供了构建和运行大模型Agent的最小原子能力,包含LangGraph代理、FastAPI服务、用于与服务交互的客户端以及一个使用客户端提供聊天界面的Streamlit应用。用户可以利用该工具包提供的模板快速搭建基于LangGraph框架…

论文概览 |《Urban Analytics and City Science》2023.10 Vol.50 Issue.8

本次给大家整理的是《Environment and Planning B: Urban Analytics and City Science》杂志2023年10月第50卷第8期的论文的题目和摘要&#xff0c;一共包括21篇SCI论文&#xff01; 论文1 Advances in geospatial approaches to transport networks and sustainable mobility …

大语言模型推理能力从何而来?

前言 DeepSeek R1采用强化学习进行后训练&#xff0c;通过奖励机制和规则引导模型生成结构化思维链&#xff08;CoT&#xff09;&#xff0c;从而显著提升了推理能力。这一创新方法使得DeepSeek R1能够在无需大量监督数据的情况下&#xff0c;通过自我进化发展出强大的推理能力…

用 WOW.js 和 animate.css 实现动画效果

用 wow.js 就可以实现动画效果&#xff0c;但由于里面的动画样式太少&#xff0c;一般还会引入 animated.css 第一步&#xff1a;下载 选择合适的包管理器下载对应的内容 pnpm i wow.js animated.css --save 第二步&#xff1a;引入 在main.js中加入&#xff1a; import …

设计模式教程:解释器模式(Interpreter Pattern)

1. 什么是解释器模式&#xff1f; 解释器模式&#xff08;Interpreter Pattern&#xff09;是一种行为型设计模式&#xff0c;通常用于处理语言&#xff08;例如数学表达式、SQL查询等&#xff09;中的语法和解释。该模式定义了一个文法&#xff0c;并通过解释器类来解释文法中…