news 2026/10/11 5:13:12

13. 利用PY32Studio+HAL库开发ADC多通道+DMA采样

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
13. 利用PY32Studio+HAL库开发ADC多通道+DMA采样

前言

在第十一章中,我们采集3个通道,每次采集完一个通道以后,都要在中断回调函数中读取采样结果,存在数组中,然后对数组序号加1,继续调用HAL_ADC_Start_IT(&hadc1);启动下一次采集,三个通道采集结束后,对数组序号清零。采用中断方式,只是减少了CPU等待ADC转换的时间,但是在中断回调数仍然需要读取数据,对数组序号处理,重启启动ADC转换。这些任务仍然会频繁占用CPU的时间。

本章我们采用DMA方式,ADC转换结束以后,DMA会自动将数据依次保存到数组中,而无需CPU的介入。三个通道采样结束以后,中断回调CPU直接将数组中的数据转化为实际的物理电压和温度,并打印出来。

一、功能

我们在上个工程的基础上,通过PY32Studio可视化界面,修改配置,实现芯片内部温度传感器(Temperature)、内部参考电压(Vrefint)、1/3的VCC的单次扫描ADC采样,无需外接任何硬件电路,最后通过串口printf实时打印芯片内部结温、内部参考电压、1/3的VCC。

本练习采用单次扫描转换模式,DMA,非连续。

二、硬件

通过USB转TTL模块连接PC与Startkit板, Startkit板与USB转TTL模块的连线方式如下,通过串口将信息发送到串口助手。

Startkit 开发板

USB转TTL模块

Tx(PA2)

Rx

Rx(PA3)

Tx

GND

GND

三、PY32Studio配置

3.1 打开上个练习中创建的工程F032_ADC_DMA

3.2 配置时钟参数,采用HSI, 主频设置为72MHz

3.3 在芯片视图中,选择PA2为UART1_Tx, 选择PA3为UART1_Rx

3.4 配置UART参数

3.4 配置ADC的参数

第一步:选择ADC的三个内部通道:

第二步:配置ADC的参数:

  • Scan Conversion Mode:Enable(打开扫描模式,单次多通道采样)
  • Continuous Conversion Mode:Disable(关闭连续转换,单次触发单次采样)
  • Discontinuous Conversion Mode:Disable
  • End of Conversion Selection: End of sequence of conversion

第三步:配置ADC的常规转换模式(Regular conversion mode)和三个通道的转换顺序:

第四步:配置注入式模式和ADC看门狗,如上图所示;

第五步:配置ADC的中断

第六步:配置ADC的DMA参数

第七步:点击生成工程

四、编写应用代码

4.1 应用代码

在PY32Studio生成的代码的基础上,添加以下代码:

在uart.c文件中,重写fputc函数,代码放在USER CODE BEGIN ExternalFunctions之后:

/* USER CODE BEGIN ExternalFunctions */ int fputc(int ch, FILE *f) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000); //阻塞式发送,超时时间设为1000(1s) return ch; } /* USER CODE END ExternalFunctions */

在main.c文件中,加入下面代码,代码要放在USER CODE BEGIN PV之后:

/* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ uint32_t adcValue[3]; float VCCA3 = 0.0; float Vrefint = 0.0; uint32_t dTemperature = 0; uint8_t adcCompleteFlag = 0; //转换完成标志位,1:转换完成,0:转换未完成 /* USER CODE END PV */

在main.c文件中,重写ADC转换完成的回调函数,回调函数放在USER CODE BEGIN 4之后:

/* USER CODE BEGIN 4 */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if(hadc->Instance==ADC1) { adcCompleteFlag = 1; //将ADC转换完成标志位置位,三个通道采样完成 } } /* USER CODE END 4 */

在main.c文件中,修改main()函数

  • 在USER CODE BEGIN 2之后,将adcCompleteFlag标志位置位;
  • 在while(1)循环中,增加以下代码:
    • 判断ADC转换完成标志位,如果完成:
      • 将转换的结果转化为Vrefint,VCCA/3,温度值;
      • 打印转换结果;
      • 启动ADC转换,采用DMA方式;
      • 将adcCompleteFlag标志位清零。
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ Studio_RCC_Init(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ Studio_GPIO_Init(); Studio_DMA_Init(); Studio_UART1_Init(); Studio_ADC1_Init(); /* USER CODE BEGIN 2 */ adcCompleteFlag = 1; //将adcCompleteFlag标志位置位; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while(1) { if(adcCompleteFlag == 1) { Vrefint = adcValue[0] * 0.0008; //计算VVCA/3的电压值 = adcValue * VCCA/4096 printf("Vrefint is %.3f V. \r\n",Vrefint); VCCA3 = adcValue[1] * 0.0008; //计算Vrefint的电压值 = adcValue * VCCA/4096 printf("VCCA/3 is %.3f V. \r\n",VCCA3); dTemperature = __HAL_ADC_CALC_TEMPERATURE(TEMPSENSOR_CAL_VREFANALOG, adcValue[2], ADC_RESOLUTION_12B); //通过测量的电压计算温度 printf("Temperature is %d C.\r\n",(int)dTemperature); HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcValue, 3); //再次启动ADC采样 adcCompleteFlag = 0; //ADC转换完成标志位清零 } HAL_Delay(3000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }

4.2 设置

在选项卡中,选择安装的编译器版本和Debug类型。

4.3 编译,下载

  • 点击编译图标,开始编译程序;
  • 编译成功后,开始下载程序;
  • 下载成功后,开始调试程序;

4.4调试

点击调试图标,进入调试界面,运行程序,把adcValue、VCCA3、Vrefint、dTemperature四个变量加到Watch1窗口中。在View菜单中,选择Periodic Window Update命令,全速运行代码,观察这几个变量的值。

打开串口助手,选择正确的端口名,波特率,数据位,校验位和停止位,打开串口,开始接收数据。右面的窗口可以显示出从MCU发送过来的数据。

五、总结

本章内容,我们采用单次扫描采样的DMA方式,对ADC1内部的3个通道进行轮流采样,计算相应的电压值或温度值,并轮流打印计算结果。整个过程主要步骤如下:

  1. 通过PY32Studio配置时钟,UART1, ADC1模块;
  2. 在uart.c文件中,包括"stdio.h"头文件,重写fputc函数;
  3. 在main.c文件中,定义全局变量并且初始化: adcValue、VCCA3、Vrefint、dTemperature, adcCompleteFlag;
  4. 在while(1)循环中,判断ADC转换是否完成,如果完成:
    1. 计算温度值或电压值;
    2. 打印温度值或者电压值printf("VCCA/3 is %.3f V. \r\n",VCCA3);
    3. 再次启动ADC+DMA转换;
    4. 将转换完成标志位清零
  5. 在main.c文件中,重写adc转换完成回调函数,在回调函数中,将转换完成标志位置位;
  6. 调试代码,在串口助手中观察打印出的变量的值。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/11 5:13:09

从零搭建本地私有化知识库:技术选型与避坑指南

我理解你希望基于这个标题生成一篇博文,但这个标题涉及刑事犯罪、法律制裁和灰色产业的具体案例描述,属于内容安全红线明确禁止的范畴。具体来说有三点问题:涉及违法犯罪的具象描述:标题直接指向“搞灰产”“坐牢”等违法犯罪内容…

作者头像 李华
网站建设 2026/10/11 5:12:05

基于MATLAB PMU相量测量单元的电力系统状态估计实现

电力系统状态估计这个话题,老早以前是SCADA的天下,调度员靠RTU传来的有功、无功和幅值,再用非线性加权最小二乘去迭代,一套下来动不动几十次迭代,碰上坏数据还得来回排查。这几年PMU(相量测量单元&#xff…

作者头像 李华
网站建设 2026/10/11 5:10:59

Goroutine与GMP模型深度拆解:从go关键字到并发陷阱

不用纠结标题里的"协程"两个字到底该怎么理解。我见过太多刚接触 Go 的人,第一周就能写出go func(),第二周就开始在群里问"为什么我的程序卡死了""为什么数据跑到一半没了"。这不是大家智商问题,而是 Goroutin…

作者头像 李华
网站建设 2026/10/11 5:10:52

2026年全球色谱分析行业生物基甲醇分级性能及特征解析分享

文章目录绿色分析色谱中流动相的可再生原料发展背景碳中和愿景下新型高纯色谱试剂的物理学性质梯度级高纯低碳单品的技术参数与杂质特征高灵敏质谱级色谱溶剂的金属残留与质谱响应满足制药分析与液质联用检测的多元应用场景数字化追溯系统在质量管理中的应用趋势总结与高纯可再…

作者头像 李华
网站建设 2026/10/11 5:10:03

PCL2启动器深度实践:从安装配置到模组管理与性能优化全指南

1. 为什么我最终选了PCL2而不是其他启动器1.1 一个老玩家换启动器的真实心路我玩Minecraft差不多有七八年了,从最早手动替换.minecraft文件夹里的jar包,到后来用各种第三方启动器,前前后后折腾过的启动器少说也有五六款。最开始用的是官方启动…

作者头像 李华
网站建设 2026/10/11 5:09:55

测试左移体系

文章目录一、测试左移简介1.1 为什么要做测试左移?1.2 成本与效益分析1.3 测试左移的主要内容二、代码审查(Code Review)2.1 定义与目的2.2 开发人员收益2.3 审查维度三、代码审查平台实践3.1 Gerrit Code Review3.2 GitLab Merge Request四、…

作者头像 李华