用定时器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相关推荐

  1. 以架构视角解读和落实银行数字化转型的两份指导文件

    以架构视角解读和落实银行数字化转型的两份重磅指导文件 技术作品介绍 2021年12月和2022年1月,两份关于银行数字化转型的重量级指导文件-中国人民银行的<金融科技发展规划(2022-2025 ...

  2. 声控灯程序C语言,基于51单片机的声控灯设计设计-包含完整设计与指导文件.doc...

    基于51单片机的声控灯设计设计-包含完整设计与指导文件 工 学 院 毕 业 设 计(论文) 题 目:基于单片机的智能光控路灯的设计 专 业: 机电技术教育 班 级: *** 姓 名: *** 学 号: ...

  3. IDL简明教程-文件读写

    学习一门编程语言很多书都从数据类型.程序控制与优化等来讲起,体系庞大.然后我们作为一名菜鸟了解了很多,却跟实际的联系不起来,可能就坚持不下去了,或者看过无痕.我结合自己这一年的学习IDL编程并应用于实 ...

  4. C++调用Python文件,TensorFlow和PyTorch构建的深度学习模型,无法使用GPU的情况分析。

    C++调用Python深度学习模型,包含TensorFlow和PyTorch等构造的模型,然后使用GPU出现问题.包含C++调用Python函数,C++加载模型到GPU,GPU内存占用过大,计算完毕内 ...

  5. 简述数学建模的过程_数学建模研究过程指导:从高中数学体会数学概貌和数学建模...

    说明:此文稿为朱浩楠老师于2018年11月-12月北京地区联校数学建模活动的课题研究阶段中,每天一篇发布给各课题组的研究方法指导文件的汇总.为方便更多的同学参考使用,现调整为正序后通过遇见数学微信公众 ...

  6. openWRT自学---针对backfire版本的主要目录和文件的作用的分析整理

    特别说明:要编译backfire版本,一定要通过svn下载:svn co svn://svn.openwrt.org/openwrt/branches/backfire,而不能使用http://dow ...

  7. 【STM32】HAL库 STM32CubeMX教程十---DAC

    前言: 本系列教程将 对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用 所用工具: 1.芯片: STM32F407ZET6/ STM32F103ZET6 ...

  8. 【STM32】STM32CubeMX教程二--基本使用(新建工程点亮LED灯)

    前言 在配置好CubeMX之后,就是新建工程的开始了,那么首先我们需要一些准备,本片博客我们会很详细的介绍STM32CubeMx的基本使用和如何创建一个新的工程并且点亮LED灯  面向初学者   如果 ...

  9. 简述数学建模的过程_数学建模研究过程指导(精编版) Part IV

    向上滑动阅览说明及建模目录  说明:此文稿为朱浩楠老师于2018年11月-12月北京地区联校数学建模活动的课题研究阶段中,每天一篇发布给各课题组的研究方法指导文件的汇总.为方便更多的同学参考使用,现调 ...

最新文章

  1. linux中使用net方式连接网络,如何使用 Netplan 从终端连接到无线网络?
  2. 一张图探秘施耐德电气全生命周期服务的无限可能
  3. 自动配置IE代理脚本
  4. C++ error:LNK2005 已经在*.obj中定义
  5. JS----JavaScript数组方法及总结
  6. 后续升级鸿蒙系统,荣耀部分机型后续将支持升级为鸿蒙系统
  7. docker查看命令帮助手册
  8. 延迟加载图片 Lazy Load
  9. 教你如何解决JS/TS里特定String进行拆分然后遍历各个元素
  10. centos6.5命令行 安装锐起 RDV(Rich Desktop Virtualization)
  11. MySQL卸载教程 (Windows版)
  12. C语言中文件指针,文件位置指针,详细解析
  13. 鹏业安装算量软件V8.0.0.92升级内容
  14. 锁定计算机和睡眠有什么区别,电脑休眠和睡眠哪个好?电脑计算机睡眠和休眠有什么区别...
  15. 选项不属于HTML语言特点,JavaScript选择题
  16. 迈阿密大学的计算机系咋样,迈阿密大学牛津分校计算机专业如何?过来人告诉你...
  17. Mac idea打开项目Java文件和resources文件都被标记了resources类型
  18. .NET WebAPI 微信网页授权的实现(一)前端篇
  19. 技能高考 计算机 试题,计算机技能高考模拟试题一
  20. 爱奇艺html搜索栏代码,如何找到视频的通用代码?

热门文章

  1. IOS UIViewController API,生命周期详解
  2. 各种说明方法的答题格式_初中语文阅读答题公式 语文阅读理解万能公式大全...
  3. 【OpenCV 例程200篇】29. 图像的翻转(cv2.flip)
  4. c语言简单选择对字符串数组排序,简单了解C语言中直接插入排序与直接选择排序实现...
  5. java 下载后删除,在服务器端生成文件后,下载后并删除,改了后发现文件变成空白解决思路...
  6. java中测试计算能力_这 10 道 Java 测试题,据说阿里 P7 的正确率只有 50%
  7. [图解tensorflow源码] 入门准备工作附常用的矩阵计算工具[转]
  8. nginx反向代理获取用户真实ip
  9. 两点之间最短路径:弗洛伊德算法
  10. IAR7.51提示秘钥无效IAR 以及 CCDebug驱动(包含win7 64bit)