拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

9. 利用PY32Studio+HAL库开发ADC模拟采用功能

9. 利用PY32Studio+HAL库开发ADC模拟采用功能

一、功能

通过PY32Studio可视化配置,实现芯片内部温度传感器(Temperature)、内部参考电压(Vrefint)、1/3的VCC的单次ADC采样,无需外接任何硬件电路,最后通过串口printf实时打印芯片内部结温、内部参考电压、1/3的VCC。

本练习采用单次转换模式,非扫描、非DMA,配置简单、代码轻量化,适合新手学习。

二、硬件

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

Startkit 开发板

USB转TTL模块

Tx(PA0)

Rx

Rx(PA1)

Tx

GND

GND

三、PY32Studio配置

3.1 创建一个新工程

首先用PY32Studio创建一个F032_ADC1的新工程。

3.2 配置时钟

在芯片视图中,点击时钟视图,在时钟视图中:

    • 选择HSI为时钟源
    • 配置PLL_MUL:x9
    • SYS_SEL:PLL
    • 系统时钟为72MHz.

3.3 配置UART1

配置UART1的参数:

  • 激活UART1
  • 配置UART1的参数:波特率:115200,停止位:1,数据长度:8位,奇偶校验:无。

3.4 配置ADC的参数

第一步:配置ADC的内部通道:

第二步:配置ADC的参数:

  • Scan Conversion Mode:Disable(关闭扫描模式,单次单通道采样)
  • Continuous Conversion Mode:Disable(关闭连续转换,单次触发单次采样)
  • Discontinuous Conversion Mode:Disable

第三步:配置ADC的转换参数:

第四步:配置ADC的转换时间,转换时间长一点,避免采样波动:

第五步:点击生成工程

四、理解HAL库函数

4.1 py32f032_hal_adc.c

PY32 HAL 库中与ADC相关的核心函数主要分为初始化配置、ADC转换、中断控制、回调函数等几类。以下为核心函数详解及使用示例:

一、 初始化与配置函数

1.使能ADC外设

前提:必须在RCC层配置ADC时钟。

两项时钟配置是强制的:

ADC内核时钟(也可作为转换时钟)

示例:

在 HAL_ADC_MspInit()(推荐位置)或者其他外设时钟配置代码中:

__HAL_RCC_ADC_CLK_ENABLE();(必须调用)

ADC时钟源与分频系数,在ADC初始化阶段通过HAL_ADC_Init()的 ClockPrescaler 参数配置。

2. ADC引脚配置

  • 使能ADC所用GPIO的时钟

使用宏__HAL_RCC_GPIOx_CLK_ENABLE()

  • 将ADC引脚配置为模拟模式

使用函数HAL_GPIO_Init()

3. 可选:ADC使用中断场景

  • 配置ADC的NVIC中断

使用HAL_NVIC_EnableIRQ(ADCx_IRQn)

  • 在对应的中断向量服务函数内调用HAL_ADC_IRQHandler()

4. 可选:ADC使用DMA场景

  • 配置DMA(DMA通道、Normal/Circular模式等)

使用HAL_DMA_Init()

  • 配置DMA的NVIC中断

使用HAL_NVIC_EnableIRQ(DMAx_Channelx_IRQn)

  • 在DMA中断向量函数内调用HAL_ADC_IRQHandler()

二、ADC、规则组、通道参数配置

1. 配置ADC基础参数(分辨率、数据对齐等)和规则组参数(转换触发源、序列器等)

  • HAL_ADC_Init()

2. 配置规则组通道参数(通道号、在序列中的Rank序号等)

  • HAL_ADC_ConfigChannel()

3. 可选:配置模拟看门狗(监控通道、高低阈值)

  • HAL_ADC_AnalogWDGConfig()

三、ADC转换

1. 可选:执行ADC自动校准提升转换精度

使用HAL_ADCEx_Calibration_Start()

2. ADC驱动支持3种工作模式:查询轮询、中断、DMA传输

  • 轮询模式(Polling):
    • 启动ADC并开始转换:HAL_ADC_Start()
    • 等待转换完成:HAL_ADC_PollForConversion()
    • 读取转换结果:HAL_ADC_GetValue()
    • 停止转换,关闭ADC:HAL_ADC_Stop()
  • 中断模式(IT):
    • 启动ADC并开始转换:HAL_ADC_Start_IT()
    • 转换完成触发回调HAL_ADC_ConvCpltCallback(),该函数需要用户自行重写
    • 读取转换结果:HAL_ADC_GetValue()
    • 停止ADC:HAL_ADC_Stop_IT()
  • DMA模式:
    • 启动ADC+DMA:HAL_ADC_Start_DMA()
    • 转换完成回调HAL_ADC_ConvCpltCallback()

或DMA半传输回调HAL_ADC_ConvHalfBlockCpltCallback()

回调由用户实现

    • DMA自动把采样结果搬运到目标内存,CPU无需手动读取DR寄存器
    • 停止ADC+DMA:HAL_ADC_Stop_DMA()

四、回调函数

如果启用中断,用户必须重写的回调函数:

  • HAL_ADC_ErrorCallback()ADC错误回调
  • HAL_ADC_LevelOutOfWindowCallback()模拟看门狗超限回调
  • HAL_ADC_ConvCpltCallback()转换完成回调
  • HAL_ADC_ConvHalfBlockCpltCallbackDMA半满回调

五、编写应用代码

5.1 应用代码

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

首先定义几个全局变量,要把变量放在Private Variables下面的USER CODE段内;

在uart.c文件中加入以下代码:

  • 包括“stdio.h”文件:
/* USER CODE BEGIN Includes */ #include "stdio.h" /* USER CODE END Includes */
  • 重写fputc函数:
/* 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()函数中

  • 在USER CODE BEGIN 1中,加入ADC通道配置的结构体变量。
  • 在while(1)循环中,加入以下代码:
    • 配置ADC转换通道
    • 配置ADC转换通道的转换序号
    • 配置ADC转换时间
    • ADC启动ADC转换
    • 等待ADC转换完成
    • 读取ADC转换结果
    • 停止ADC转换
    • 将转换的结果转化为温度值,Vrefint,VCCA/3
    • 打印转换结果。
int main(void) { /* USER CODE BEGIN 1 */ ADC_ChannelConfTypeDef sConfig = {0}; //定义ADC通道配置的结构体 /* 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_UART1_Init(); Studio_ADC1_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while(1) { sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; //配置ADC转换的通道 sConfig.Rank = ADC_REGULAR_RANK_1; //配置ADC转换的序号 sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; //配置ADC转换的时间 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) //配置ADC的通道参数 { Error_Handler(); } HAL_ADC_Start(&hadc1); //启动ADC转换 HAL_ADC_PollForConversion(&hadc1,10); //等待转换完成 adcValue = HAL_ADC_GetValue(&hadc1); //读取转换结果 HAL_ADC_Stop(&hadc1); //停止转换 dTemperature = __HAL_ADC_CALC_TEMPERATURE(TEMPSENSOR_CAL_VREFANALOG, adcValue, ADC_RESOLUTION_12B); //通过测量的电压计算温度 printf("Temperature is %d C.\r\n",(int)dTemperature); HAL_Delay(2000); sConfig.Channel = ADC_CHANNEL_VREFINT; //配置ADC转换的通道 sConfig.Rank = ADC_REGULAR_RANK_1; //配置ADC转换的序号 sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; //配置ADC转换的时间 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) //配置ADC的通道参数 { Error_Handler(); } HAL_ADC_Start(&hadc1); //启动ADC转换 HAL_ADC_PollForConversion(&hadc1,10); //等待转换完成 adcValue = HAL_ADC_GetValue(&hadc1); //读取转换结果 HAL_ADC_Stop(&hadc1); //停止转换 Vrefint = adcValue * 0.0008; //计算Vrefint的电压值 = adcValue * VCCA/4096 printf("Vrefint is %.3f V \r\n",Vrefint); HAL_Delay(2000); sConfig.Channel = ADC_CHANNEL_1_3VCCA; //配置ADC转换的通道 sConfig.Rank = ADC_REGULAR_RANK_1; //配置ADC转换的序号 sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; //配置ADC转换的时间 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) //配置ADC的通道参数 { Error_Handler(); } HAL_ADC_Start(&hadc1); //启动ADC转换 HAL_ADC_PollForConversion(&hadc1,10); //等待转换完成 adcValue = HAL_ADC_GetValue(&hadc1); //读取转换结果 HAL_ADC_Stop(&hadc1); //停止转换 VCCA3 = adcValue*0.0008; //计算VVCA/3的电压值 = adcValue * VCCA/4096 printf("VCCA/3 is %.3f V. \r\n",VCCA3); HAL_Delay(2000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }

5.2 设置

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

5.3 编译,下载

  1. 点击编译图标,开始编译程序;
  2. 编译成功后,开始下载程序;
  3. 下载成功后,开始调试程序;

5.4调试

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

打开串口助手,选择正确的端口名,波特率,数据位,校验位和停止位,打开串口,开始接收数据。右面的窗口可以显示出从MCU发送过来的数据。Vrefint和VCCA的值都是基于VCCA=3.3V计算得出的。实际测量VCCA的电压为3.36V。

六、总结

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

  1. 通过PY32Studio配置时钟,UART1, ADC1模块;
  2. 在uart.c文件中,包括"stdio.h"头文件,重写fputc函数;
  3. 在main.c文件中,定义全局变量并且初始化: adcValue、VCCA3、Vrefint、dTemperature;
  4. 在while(1)循环中,调用以下几个函数:
    • HAL_ADC_ConfigChannel(&hadc1, &sConfig)//配置ADC转换参数
    • HAL_ADC_Start(&hadc1);//启动ADC转换
    • HAL_ADC_PollForConversion(&hadc1,10);//等待转换完成
    • adcValue = HAL_ADC_GetValue(&hadc1);//读取转换结果
    • HAL_ADC_Stop(&hadc1);
  5. 计算温度值或电压值;
  6. 打印温度值或者电压值printf("VCCA/3 is %.3f V. \r\n",VCCA3);
  7. 调试代码,在串口助手中观察打印出的变量的值。
返回列表