本章通过两个例程介绍STM32的模数转换器(ADC),第一个通过ADC采集内部温度传感器通道电压,然后得出MCU内部温度。第二个通过DMA的方式采集两个ADC通道电压。
1.ADC
本章程序在串口printf工程的基础上修改,复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。ADC1外设选择温度传感器通道。
ADC1配置如下,选择默认设置。其Date Alignment设置为数据右对齐。
0
|
|
|
|
生成报告以及代码,编译程序。在adc.c文件中可以看到ADC初始化函数。
在stm32f7xx_hal_adc.h头文件中可以找到如下ADC操作函数。和串口一样,ADC也可以通过三种方式控制。
01 | /** @addtogroup ADC_Exported_Functions_Group2 |
04 | /* I/O operation functions ******************************************************/ |
05 | HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc); |
06 | HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc); |
07 | HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout); |
09 | HAL_StatusTypeDef HAL_ADC_PollForEvent(ADC_HandleTypeDef* hadc, uint32_t EventType, uint32_t Timeout); |
11 | HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc); |
12 | HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc); |
14 | void HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc); |
16 | HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length); |
17 | HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc); |
19 | uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc); |
21 | void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc); |
22 | void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc); |
23 | void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc); |
24 | void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc);
|
|
|
|
|
|
在main()函数前面声明变量保存AD采集的值。
1 | /* USER CODE BEGIN PV */ |
2 | /* Private variables ---------------------------------------------------------*/ |
|
|
|
|
|
在main()函数while(1)循环里面添加函数声明变量保存AD采集的值。
01 | /* USER CODE BEGIN WHILE */ |
04 | /* USER CODE END WHILE */ |
06 | /* USER CODE BEGIN 3 */ |
07 | /*##-1- Start the conversion process #######################################*/ |
08 | HAL_ADC_Start(&hadc1); |
10 | /*##-2- Wait for the end of conversion #####################################*/ |
11 | /* Before starting a new conversion, you need to check the current state of |
12 | the peripheral; if it’s busy you need to wait for the end of current |
13 | conversion before starting a new one. |
14 | For simplicity reasons, this example is just waiting till the end of the |
15 | conversion, but application may perform other tasks while conversion |
16 | operation is ongoing. */ |
17 | HAL_ADC_PollForConversion(&hadc1, 50); |
19 | /* Check if the continous conversion of regular channel is finished */ |
20 | if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC)) |
22 | /*##-3- Get the converted value of regular channel ######################*/ |
23 | AD_Value = HAL_ADC_GetValue(&hadc1); |
24 | printf("MCU Temperature : %.1f¡ærn",((AD_Value*3300/4096-760)/2.5+25)); |
|
|
|
|
|
[color=rgb(0, 130, 0) !important] [size=1em]HAL_ADC_Start(&hadc1)为启动ADC装换,
[color=rgb(0, 130, 0) !important] [size=1em]HAL_ADC_PollForConversion(&hadc1, 50);表示等待转换完成,第二个参数表示超时时间,单位ms.
[color=rgb(0, 130, 0) !important] [size=1em]HAL_ADC_GetState(&hadc1)为换取ADC状态,HAL_ADC_STATE_REG_EOC表示转换完成标志位,转换数据可用。
[color=rgb(0, 130, 0) !important] [size=1em]HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC)就是判断转换完成标志位是否设置。
[color=rgb(0, 130, 0) !important] [size=1em]HAL_ADC_GetValue(&hadc1);读取ADC转换数据,数据为12位。查看数据手册可知,寄存器为16位存储转换数据,数据右对齐,则转换的数据范围为0~2^12-1,即0~4095.
[color=rgb(0, 130, 0) !important] [size=1em]
[color=rgb(0, 130, 0) !important] [size=1em]AD_Value*3300/4096为将转换后的数据转化为电压,单位为mV,参考电压为3.3V。查询数据手册可以电压和温度的关系。经过计算公式装换后等到MCU内部温度值。
|
|
|
|
|
[color=rgb(0, 130, 0) !important] [size=1em]
[color=rgb(0, 130, 0) !important] [size=1em]
|
|
|
|
|
[color=rgb(0, 130, 0) !important] [size=1em][size=1em]
[color=rgb(0, 130, 0) !important] [size=1em]编译程序并下载到开发板。打开串口调试助手。设置波特率为115200。串口助手上会显示MCU温度。
|
|
|
|
|
2.ADC_DMA
[color=#0820 !important]
前面介绍了通过ADC轮询的方式采集单通道的数据。现在介绍一下通过DMA方式采集多通道的数据。
复制串口printf工程的工程,修改文件夹名。点击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置。本实验使用微雪Analog Test Board接到SPI1接口。更具原理图配置PA6,PA7管脚作为ADC1的输入管脚。
|
|
|
|
|
ADC1配置:使能扫描转换模式(Scan Conversion Mode),使能连续转换模式(Continuous Conversion Mode),使能DMA连续请求。ADC***)。其他为默认设置。
|
|
|
|
|
添加DMA设置,设置为连续传输模式,数据长度为字。
|
|
|
|
|
生成报告以及代码,编译程序。在adc.c文件中可以看到ADC初始化函数。
在main函数前面添加变量。其中ADC_Value作为转换数据缓存数组,ad1,ad2存储PA6,PA7的电压值。
1 | /* USER CODE BEGIN PV */ |
2 | /* Private variables ---------------------------------------------------------*/ |
3 | uint32_t ADC_Value[100]; |
|
|
|
|
|
在while(1)前面以DMA方式开启ADC装换。HAL_ADC_Start_DMA()函数第二个参数为数据存储起始地址,第三个参数为DMA传输数据的长度。
[size=1em]
2 | /*##-1- Start the conversion process and enable interrupt ##################*/ |
3 | HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 100); |
|
|
|
|
|
由于DMA采用了连续传输的模式,ADC采集到的数据会不断传到到存储器中(此处即为数组ADC_Value)。ADC采集的数据从ADC_Value[0]一直存储到ADC_Value[99],然后采集到的数据又重新存储到ADC_Value[0],一直到ADC_Value[99]。所以ADC_Value数组里面的数据会不断被刷新。这个过程中是通过DMA控制的,不需要CPU参与。我们只需读取ADC_Value里面的数据即可得到ADC采集到的数据。
其中ADC_Value[0]为通道6(PA6)采集的数据,ADC_Value[1]为通道7(PA7)采集的数据,ADC_Value[2]为通道6采集的数据,如此类推。数组偶数下标的数据为通道6采集数据,数组奇数下标的数据为通道7采集数据。
在while(1)循环中添加应用程序,将采集的数据装换为电压值并输出。
[size=1em]01 | /* USER CODE BEGIN WHILE */ |
04 | /* USER CODE END WHILE */ |
06 | /* USER CODE BEGIN 3 */ |
08 | for(i = 0,ad1 =0,ad2=0; i < 100;) |
10 | ad1 += ADC_Value[i++]; |
11 | ad2 += ADC_Value[i++]; |
16 | printf("rn******** ADC DMA Example ********rnrn"); |
17 | printf(" AD1 value = %1.3fV rn", ad1*3.3f/4096); |
18 | printf(" AD2 value = %1.3fV rn", ad2*3.3f/4096); |
|
|
|
|
|
[size=1em] 程序中将数组偶数下标数据加起来求平均值,实现均值滤波的功能,再将数据装换为电压值,即为PA6管脚的电压值。同理对数组奇数下标数据处理得到PA7管脚的电压值。
编译程序并下载到开发板。打开串口调试助手。设置波特率为115200。串口助手上会显示采集到的电压值,旋转Analog Test Board上电位器,输出的电压值会改变。
|
|
|
|
|
|