https://liu-yaohua.github.io

0%

【STM32基础教程08】STM32的ADC开发基础

STM32的ADC资源概述

STM32F103ZE芯片(144脚)中有ADC1ADC2ADC3共3个12位逐次逼近型模数转换器,具有18个测量通道,可测量16个外部2个内部信号源(内部温度和内部参考电压)。这2个内部信号源只能连接到ADC1
ADC的各个通道的A/D转换可以单次连续扫描间断模式执行。
A/D转换结果以左对齐右对齐的方式,存储在16位规则组或者注入组数据寄存器中。

按照A/D转换的组织形式来划分,ADC的模拟输入通道分为规则组和注入组两种。
ADC可以对一组最多16个通道按照指定的顺序逐个进行转换,这组指定的通道称为规则组
在实际应用中,可能需要中断规则组的转换,临时对某些通道进行转换,好像这些通道注入了原来的规则组,故称注入组,最多由4个通道组成。

ADC启动与停止相关的HAL库函数

1
2
3
4
5
6
7
8
//查询,阻塞方式,启动ADC
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc);
//查询,阻塞方式,停止ADC
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc);
//中断,非阻塞方式,启动ADC
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc);
//中断,非阻塞方式,停止ADC
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc);

ADC转换结果读取的HAL库函数

1
2
3
4
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc);

参数1:hadc,ADC实例指针。
返回值:uint32_t,ADC转换结果。

查询方式,阻塞式A/D转换HAL库函数

1
2
3
4
5
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout);

参数1:hadc,ADC实例指针。
参数2:Timeout,超时时间。
返回值:HAL_StatusTypeDef,函数执行状态。
1
2
3
4
5
6
7
8
9
应用实例:用查询的方式,进行一次A/D采样并将结果读出。
uint16_t ADC_Value = 0;
//以查询的方式启动ADC
HAL_ADC_Start(&hadc);
//等待一次规则组的ADC转换完成,并将结果读出
if(HAL_OK == HAL_ADC_PollForConversion(&hadc1,10))
{
ADC0_Value = HAL_ADC_GetValue(&hadc1);
}

中断方式,非阻塞式A/D转换HAL库函数

1
2
3
4
5
6
7
8
9
应用实例:用中断的方式,进行一次A/D采样并将结果读出。
uint16_t ADC_Value = 0;
//以中断的方式启动ADC
HAL_ADC_Start_IT(&hadc);
//重写ADC转换完成中断回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
ADC0_Value = HAL_ADC_GetValue(&hadc1);
}

实训案例:ADC单次数据采样与电压换算

XMF07AXMF07C开发板上,利用STM32CubeMXKeil5协同开发,完成以下的功能:
【1】将ADC_IN0设置为12位ADC,右对齐,启用中断。
【2】分别用查询中断这2种方式,每隔0.5秒采样一次ADC的数据。
【3】将每次读取到的ADC采样值转换为对应电压值,发送到上位机。
【4】LED1作为采样指示灯,在ADC转换过程中点亮,其余时间熄灭。

1
2
3
4
5
6
7
#include "stdio.h"

#define LED1_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET)
#define LED1_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET)

uint16_t ADC0_Value = 0, ADC0_Volt = 0;
uint8_t str_buff[64];
1
2
3
4
5
void UR1_Send_Info()
{
sprintf((char *)str_buff,"采样值:%d,电压值:%d.%d%dV\r\n",ADC0_Value,ADC0_Volt/100,(ADC0_Volt%100)/10,ADC0_Volt%10);
HAL_UART_Transmit(&huart1,str_buff,sizeof(str_buff),10000);
}

用查询,阻塞的方式来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
void Get_ADC_Value()
{
HAL_ADC_Start(&hadc1);
LED1_ON();
if(HAL_OK == HAL_ADC_PollForConversion(&hadc1,10))
{
ADC0_Value = HAL_ADC_GetValue(&hadc1);
DC0_Volt = ADC0_Value * 330 / 4096;
}
UR1_Send_Info();
LED1_OFF();
HAL_ADC_Stop(&hadc1);
}
1
2
3
4
5
6
7
8
9
10
11
12
//在mian()函数中添加以下代码:
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
Get_ADC_Value(); //启动一个阻塞式的ADC转换并读取数据
UR1_Send_Info(); //向上位机发生采样值和电压值
HAL_Delay(500); //延时0.5秒,再进行下一次ADC采样
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */

用中断,非阻塞的方式来实现

1
2
3
4
5
6
7
8
9
10
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if(hadc->Instance == ADC1)
{
ADC0_Value = HAL_ADC_GetValue(&hadc1); //读取ADC转换结果
ADC0_Volt = ADC0_Value * 330 / 4096; //将采样值换算成电压值
UR1_Send_Info(); //向上位机发生ADC采样信息
LED1_OFF(); //关闭LED1采样指示灯
}
}
1
2
3
4
5
6
7
8
9
10
11
12
//在mian()函数中添加以下代码:
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_ADC_Start_IT(&hadc1); //启动一个非阻塞式的ADC转换并读取数据
LED1_ON(); //点亮LED1采样指示灯
HAL_Delay(500); //延时0.5秒,再进行下一次ADC采样
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */