独家干货:本课程对应视频的B站链接:
https://www.bilibili.com/video/av87017878?p=9
STM32的ADC资源概述
STM32F103ZE芯片(144脚)中有ADC1、ADC2、ADC3共3个12位逐次逼近型模数转换器,具有18个测量通道,可测量16个外部和2个内部信号源(内部温度和内部参考电压)。这2个内部信号源只能连接到ADC1。
ADC的各个通道的A/D转换可以单次、连续、扫描或间断模式执行。
A/D转换结果以左对齐或右对齐的方式,存储在16位规则组或者注入组数据寄存器中。
按照A/D转换的组织形式来划分,ADC的模拟输入通道分为规则组和注入组两种。
ADC可以对一组最多16个通道按照指定的顺序逐个进行转换,这组指定的通道称为规则组。
在实际应用中,可能需要中断规则组的转换,临时对某些通道进行转换,好像这些通道注入了原来的规则组,故称注入组,最多由4个通道组成。
ADC启动与停止相关的HAL库函数
//查询,阻塞方式,启动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库函数
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc);
参数1:hadc,ADC实例指针。
返回值:uint32_t,ADC转换结果。
查询方式,阻塞式A/D转换HAL库函数
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout);
参数1:hadc,ADC实例指针。
参数2:Timeout,超时时间。
返回值:HAL_StatusTypeDef,函数执行状态。
应用实例:用查询的方式,进行一次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库函数
应用实例:用中断的方式,进行一次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单次数据采样与电压换算
在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能:
【1】将ADC_IN0设置为12位ADC,右对齐,启用中断。
【2】分别用查询和中断这2种方式,每隔0.5秒采样一次ADC的数据。
【3】将每次读取到的ADC采样值转换为对应电压值,发送到上位机。
【4】LED1作为采样指示灯,在ADC转换过程中点亮,其余时间熄灭。
#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];
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);
}
用查询,阻塞的方式来实现
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);
}
//在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 */
用中断,非阻塞的方式来实现
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采样指示灯
}
}
//在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 */