stm32cubemx adc_STM32CubeMX__Exp5_ADC1_2CH_DMA_TIM3_Trig__简明指导文件__jyb
用定时器TIM3触发DMA方式的双通道ADC定时采样:
拷贝STM32CubeMX工程文件LED_Flash_PC12.ioc,修改为:Exp5_ADC1_2CH_DMA_TIM3_Trig.ioc
(1)配置ADC1的通道和参数
配置ADC通道参数
(2)配置ADC1的DMA
①通过点"Add"按钮,添加ADC1---DMA1 Channel 1。选择后ADC1后自动添加其DMA通道。
② DMA Request Settings:配置结果如下图所示。
Mode:Circular;设置DMA的传输模式为连续不断的循环模式。若只想访问一次后就不要访问了(或按指令操作来反问,也就是想要它访问的时候就访问,不要它访问的时候就停止),可以设置成通用模式:DMA_Mode_Normal。
Peripheral:Increment Address:不勾选。如果DMA通道有外设,可以通过DMA通道将数据输出。
Memory:勾选。DMA通过地址递增方式将数据存储到内部数据存储器中。
Data Width:Word。Word是32bits,Half Word是16bits。选择要与ADC转换结果的数据宽度相同。
配置ADC的DMA
(3)配置ADC1的NVIC:不做任何选择,按默认即可,如下图所示。DMA1中断已经默认强制选择了。我们在这里是采用TIM3的定时溢出事件触发ADC转换的,在DMA中断服务程序中读取数据,所以不需要使能ADC的中断。
配置ADC的NVIC
(4)"User Constants"和"GPIO Settings"按默认即可。
(5)配置TIM3。配置结果如下图所示。
配置TIM3
用其更新事件作为TRGO触发ADC。用鼠标点"Pinout & Configuration"点"Timers"点"TIM3""Mode"选项卡中,"Clock Source"选"Internal Clock""TIM3 Mode and Configuration"的"Configuration"菜单栏中,点"Parameter Settings""Trigger Output(TRGO)Parameters"下拉选项中,"Trigger Event Selection"选择"Update Event"。这样就为ADC的启动提供触发信号。72MHz的时钟信号经过(7199+1)和(39999+1)分频后,频率为0.25Hz,其周期为4秒,也就是说每4秒触发一次ADC转换。
(6) 为了观察程序运行,添加PC12接LED。
(7) ADC的时钟为12MHz
配置ADC的时钟
(8)配置完成,保存STM32CubeMX工程文件,点击"GENERATE CODE",生成代码工程框架并打开。
添加代码
(1) 在main.c里面添加ADC转换的相关变量
/* USER CODE BEGIN PV */
uint32_t ADC_Value[10]; //通道IN6、IN7采样5次的值
uint8_t i,j,ADC_DMA_ConvCpltFlag=0; //ADC1_DMA方式转换结束标志
uint32_t IN6_Value[5],IN7_Value[5]; //从DMA转换值中分离IN6和IN7的值
uint32_t IN6_AverageValue,IN7_AverageValue; //IN6和IN7的平均值
/* USER CODE END PV */
(2)开启定时器TIM3,通过TIM3启动ADC。开启DMA方式的ADC1
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim3); //启动TIM3基本定时功能,定时到触发ADC启动
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 10); //启动DMA方式的ADC转换,采样到10个之后触发DMA方式的ADC中断
/* USER CODE END 2 */
(3)在中断回调函数中做简单的数据处理
/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle) //DMA方式的ADC中断回调函数
{
// HAL_TIM_Base_Stop(&htim3);
// HAL_ADC_Stop_DMA(&hadc1);
j=0; //将采样到的10个ADC转换值分离给IN6和IN7
for(i = 0; i < 10;i++)
{
IN6_Value[j]=ADC_Value[i];
i++;
IN7_Value[j]=ADC_Value[i];
j++;
}
ADC_DMA_ConvCpltFlag=1; //置DMA方式的ADC转换结束标志
}
/* USER CODE END 4 */
(4)在主程序中做复杂些的数据处理
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOB,LED1_Pin); //用LED1指示主程序运行
HAL_Delay(200); //每200msLED1闪烁一次
if(ADC_DMA_ConvCpltFlag==1) //判断DMA方式的ADC转换结束了没有
{
IN6_AverageValue=0; //一次DMA方式的ADC转换结束,计算两个通道的平均值
IN7_AverageValue=0;
for(i =0;i <5;i++)
{
IN6_AverageValue+=IN6_Value[i];
IN7_AverageValue+=IN7_Value[i];
}
IN6_AverageValue=IN6_AverageValue/5;
IN7_AverageValue=IN7_AverageValue/5;
// HAL_TIM_Base_Start(&htim3);
// HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 10);
ADC_DMA_ConvCpltFlag=0; //清除转换结束标志,以便判断下次中断
}
}
/* USER CODE END 3 */
在启动了TIM3定时器后,TIM3计数溢出事件将触发ADC启动转换,ADC转换按照规定的DMA方式进行,先转换IN6通道,再转换IN7通道,这就是扫描转换各个通道一次,等到下一次TIM3溢出事件再次启动ADC转换,这样反复5次,转换得到10个ADC转换值,将触发DMA中断,在DMA中断回调函数中做简单的数据处理,置DMA中断标志。在主程序中,通过LED1指示主程序的运行情况,检测到DMA中断后对采样到的数据做处理,并复位DMA中断标志。
这里你也许会问,DMA中断为什么是void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)这个函数呀?这个函数不是当开启AD的中断的时候才调用的吗? 对,是这样的。我们仔细分析一下开启AD的DMA中断函数,在里面就会发现这个函数也在啊。在main.c中找到HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 10);,在HAL_ADC_Start_DMA上点鼠标右键,跟踪其定义可以找到函数:HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length),该函数中有一句:
/* Set the DMA transfer complete callback */
hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt;
DMA传输完成,自动调用名字为ADC_DMAConvCplt函数,在ADC_DMAConvCplt上点鼠标右键,跟踪其定义,进入到void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma)函数里面可以找到
/* Conversion complete callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->ConvCpltCallback(hadc);
#else
HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
发现DMA方式的ADC转换,按照开辟的数据区大小,转换结果将数据区填满后,转换完成,还是调用HAL_ADC_ConvCpltCallback(hadc); 这个回调函数,在回调函数中对数据做初步处理。今后用到AD,不论是中断方式还是DMA方式,都可以直接调用这个回调函数了,不用再纠结了。需要注意的是,中断方式的ADC在回调函数中需要通过uhADCxConvertedValue = HAL_ADC_GetValue(AdcHandle); 获得ADC的转换值,而DMA方式的ADC,则通过DMA直接将转换值存放在用数组名开辟的片内RAM中,当数组存满数据后会触发DMA中断,在回调函数中直接从数组中取转换结果即可。
以上程序是连续启动ADC转换的,如果要想控制这个转换过程,可以通过以下语句实现:
HAL_TIM_Base_Stop(&htim3); //关闭定时器,停止溢出事件触发ADC
HAL_ADC_Stop_DMA(&hadc1); //停止DMA方式的ADC转换
HAL_TIM_Base_Start(&htim3); //启动定时器,定时溢出事件触发ADC
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 10); //启动DMA方式的ADC转换,得到10个转换值后中断
第三步:编译、下载、运行
为观察到变化效果,可以先将PA6(IN6)和PA7(IN7)悬空,此时测量到是干扰。程序运行后,可以看到LED持续闪烁,表明主程序一直在运行,不用设置断点,全速运行程序,在观察窗口中添加变量ADC_Value、IN6_Value、IN7_Value、IN6_AverageValue、IN7_AverageValue、i、j,可以看到,每隔4秒钟ADC_Value的值以组(IN6和IN7)为单位变化一次,因为TIM3定时4秒,所以每隔4秒触发一次ADC转换,转换结果通过DMA送给ADC_Value数组。需要20秒后,ADC_Value填满,触发DMA中断,IN6_Value和IN7_Value在中断回调函数中得到各自的转换结果,如下图所示。也可以将PA6和PA7接GND、3.3V,做进一步观察。
观察运行结果
stm32cubemx adc_STM32CubeMX__Exp5_ADC1_2CH_DMA_TIM3_Trig__简明指导文件__jyb相关推荐
- 以架构视角解读和落实银行数字化转型的两份指导文件
以架构视角解读和落实银行数字化转型的两份重磅指导文件 技术作品介绍 2021年12月和2022年1月,两份关于银行数字化转型的重量级指导文件-中国人民银行的<金融科技发展规划(2022-2025 ...
- 声控灯程序C语言,基于51单片机的声控灯设计设计-包含完整设计与指导文件.doc...
基于51单片机的声控灯设计设计-包含完整设计与指导文件 工 学 院 毕 业 设 计(论文) 题 目:基于单片机的智能光控路灯的设计 专 业: 机电技术教育 班 级: *** 姓 名: *** 学 号: ...
- IDL简明教程-文件读写
学习一门编程语言很多书都从数据类型.程序控制与优化等来讲起,体系庞大.然后我们作为一名菜鸟了解了很多,却跟实际的联系不起来,可能就坚持不下去了,或者看过无痕.我结合自己这一年的学习IDL编程并应用于实 ...
- C++调用Python文件,TensorFlow和PyTorch构建的深度学习模型,无法使用GPU的情况分析。
C++调用Python深度学习模型,包含TensorFlow和PyTorch等构造的模型,然后使用GPU出现问题.包含C++调用Python函数,C++加载模型到GPU,GPU内存占用过大,计算完毕内 ...
- 简述数学建模的过程_数学建模研究过程指导:从高中数学体会数学概貌和数学建模...
说明:此文稿为朱浩楠老师于2018年11月-12月北京地区联校数学建模活动的课题研究阶段中,每天一篇发布给各课题组的研究方法指导文件的汇总.为方便更多的同学参考使用,现调整为正序后通过遇见数学微信公众 ...
- openWRT自学---针对backfire版本的主要目录和文件的作用的分析整理
特别说明:要编译backfire版本,一定要通过svn下载:svn co svn://svn.openwrt.org/openwrt/branches/backfire,而不能使用http://dow ...
- 【STM32】HAL库 STM32CubeMX教程十---DAC
前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1.芯片: STM32F407ZET6/ STM32F103ZET6 ...
- 【STM32】STM32CubeMX教程二--基本使用(新建工程点亮LED灯)
前言 在配置好CubeMX之后,就是新建工程的开始了,那么首先我们需要一些准备,本片博客我们会很详细的介绍STM32CubeMx的基本使用和如何创建一个新的工程并且点亮LED灯 面向初学者 如果 ...
- 简述数学建模的过程_数学建模研究过程指导(精编版) Part IV
向上滑动阅览说明及建模目录 说明:此文稿为朱浩楠老师于2018年11月-12月北京地区联校数学建模活动的课题研究阶段中,每天一篇发布给各课题组的研究方法指导文件的汇总.为方便更多的同学参考使用,现调 ...
最新文章
- linux中使用net方式连接网络,如何使用 Netplan 从终端连接到无线网络?
- 一张图探秘施耐德电气全生命周期服务的无限可能
- 自动配置IE代理脚本
- C++ error:LNK2005 已经在*.obj中定义
- JS----JavaScript数组方法及总结
- 后续升级鸿蒙系统,荣耀部分机型后续将支持升级为鸿蒙系统
- docker查看命令帮助手册
- 延迟加载图片 Lazy Load
- 教你如何解决JS/TS里特定String进行拆分然后遍历各个元素
- centos6.5命令行 安装锐起 RDV(Rich Desktop Virtualization)
- MySQL卸载教程 (Windows版)
- C语言中文件指针,文件位置指针,详细解析
- 鹏业安装算量软件V8.0.0.92升级内容
- 锁定计算机和睡眠有什么区别,电脑休眠和睡眠哪个好?电脑计算机睡眠和休眠有什么区别...
- 选项不属于HTML语言特点,JavaScript选择题
- 迈阿密大学的计算机系咋样,迈阿密大学牛津分校计算机专业如何?过来人告诉你...
- Mac idea打开项目Java文件和resources文件都被标记了resources类型
- .NET WebAPI 微信网页授权的实现(一)前端篇
- 技能高考 计算机 试题,计算机技能高考模拟试题一
- 爱奇艺html搜索栏代码,如何找到视频的通用代码?
热门文章
- IOS UIViewController API,生命周期详解
- 各种说明方法的答题格式_初中语文阅读答题公式 语文阅读理解万能公式大全...
- 【OpenCV 例程200篇】29. 图像的翻转(cv2.flip)
- c语言简单选择对字符串数组排序,简单了解C语言中直接插入排序与直接选择排序实现...
- java 下载后删除,在服务器端生成文件后,下载后并删除,改了后发现文件变成空白解决思路...
- java中测试计算能力_这 10 道 Java 测试题,据说阿里 P7 的正确率只有 50%
- [图解tensorflow源码] 入门准备工作附常用的矩阵计算工具[转]
- nginx反向代理获取用户真实ip
- 两点之间最短路径:弗洛伊德算法
- IAR7.51提示秘钥无效IAR 以及 CCDebug驱动(包含win7 64bit)