STM32L051使用HAL库操作实例(14)- ADC采集电压

11 篇文章 14 订阅
本文详细介绍了如何在STM32L051C8T6单片机上使用HAL库配置ADC外设,包括MCU选型、时钟配置、串口通信和外部电压测量,以及如何通过内部基准电压校准确保测量精度。
摘要由CSDN通过智能技术生成

目录

一、前言

二、ADC外设简要说明

三、STM32CubeMX配置(本文使用的STM32CubeMX版本为6.1.2)

1.MCU选型

2.时钟使能

3.外部时钟配置

4.串口配置

5.ADC引脚配置

6.配置STM32CubeMX生成工程文件

7.点击GENERATE CODE生成工程文件

四、工程源码

五、运行状态


一、前言

本文主要介绍通过HAL库搭建工程及如何通过STM32L051的ADC外设读取外部电压;

1.MCU:STM32L051C8T6

2.软件平台:KEIL V5.27、STM32CubeMX V6.1.2

3.库类型:HAL

二、ADC外设简要说明

1.STM32L051这款MCU不像F1系列大容量版本的MCU有外置Vref引脚,所以在使用这款单片机时,如果采用外部的3.3V电源电压作为基准,那么在外部电压发生波动时就会影响ADC测量数据的准确性。这里有两种方法:一种是可采用在外部使用如TL431搭建基准电源电路,需要使用2路ADC通道,在ADC进行读取时先使用一路通道进行TL431基准电压的读取进行比较,然后在读取另一外部输入的通道;第二种是采用MCU内部的基准电压作为基准,在ADC进行读取时先获取内部的基准电压值,然后在读取另一外部输入的通道,这里例程采用的是第二种方法。

2.查看datasheet得知,STM32的mcu有一个寄存器VREFINT_CAL的值为厂家存放的基准电压,该值的环境:在温度为25°C时获取的原始VDD = 3V,由下图说明VREFINT内部基准电源为ADC和比较器提供稳定的电压输出。VREFINT内部连接ADC_IN17输入通道,它可以准确的监测VDD值。

3.查看STM32L051参考手册可找到厂家已给出相应的计算公式,如下图:

我们可以看到,手册中已说明,对于不知道VDDA值的应用,必须使用内部参考电压,内部参考电压Vdda=3V,ADC读取电压的计算公式也列出了。那么我们在使用ADC时就需要读取两个通道的值,首先为ADC_IN17的值(即VREFINT_DATA),ADC_DATA是外部ADC引脚通道上测量的值,VREFINT_CAL为内部参考电压校准值,可以直接地址读取。我们使用的这款STM32L051C8T6芯片VREFINT_CAL地址为:0X1FF80078。使用公式直接读取VREFINT_CAL = *(__IO uint16_t *)(0X1FF80078);FULL_SCALE是根据我们设置的ADC分辨率而定,12位ADC分辨率值:2^12 - 1 = 4096 - 1。

三、STM32CubeMX配置(本文使用的STM32CubeMX版本为6.1.2)

思路:使用PA0引脚(ADC_IN0通道)读取外部电压(通过电位器调节),读取后将读出的数值通过串口一打印出来。

1.MCU选型

例程使用的为STM32L051C8T6型号;

2.时钟使能

使用外部时钟

3.外部时钟配置

将时钟选用外部HSE时钟,频率采用32M

4.串口配置

启用USART1,模式为异步通讯模式。波特率采用9600,数据长度8为,无校验,1个停止位。

5.ADC引脚配置

选择使用PA0引脚作为ADC输入端,

ADC参数配置

6.配置STM32CubeMX生成工程文件

1.编辑好文件名称,保存路径,输出工程文件类型。

7.点击GENERATE CODE生成工程文件

四、工程源码

int main(void)
{
  /* USER CODE BEGIN 1 */
	uint16_t i;
	uint32_t SUM[3];
	uint16_t ADC_DATA[101];
	uint16_t VREFINT_DATA[101];
	ADC_ChannelConfTypeDef sConfig;
	uint16_t VREFCAL = 0;
	float V_CHANNEL = 0;
	int16_t ADC_value;
  /* 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 */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	/*获取内部校准电压参考值*/
	VREFCAL = *(__IO uint16_t *)(0x1FF80078);
	printf("\r\nSTM32L051C8T6 开发板ADC读取实验\r\n");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		SUM[0] = 0;
		SUM[1] = 0;
		for(i=0; i<100; i++)
		{
			/*获取PA0引脚电压值*/
			ADC_DATA[i] = 0;
			/*开启ADC校准,使用的为单端校准模式*/
			HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
			/*寄存器数据清零*/
			hadc.Instance->CHSELR=0;
			/*转换通道配置*/
			sConfig.Channel = ADC_CHANNEL_0;
			/*配置所选通道*/
			HAL_ADC_ConfigChannel(&hadc, &sConfig);
			/*启动转换*/
			HAL_ADC_Start(&hadc);
			/*等待转换结束,1000为times*/
			HAL_ADC_PollForConversion(&hadc,1000);
			/*读取结果*/
			ADC_DATA[i] = HAL_ADC_GetValue(&hadc);
			/*停止ADC读取*/
			HAL_ADC_Stop(&hadc);
			SUM[0] += ADC_DATA[i];
			
			/*获取内部基准电压值*/
			VREFINT_DATA[i] = 0;
			HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
			/*寄存器数据清零*/
			hadc.Instance->CHSELR=0;
			/*转换通道配置*/
			sConfig.Channel = ADC_CHANNEL_VREFINT;
			/*配置所选通道*/
			HAL_ADC_ConfigChannel(&hadc, &sConfig);
			/*启动转换*/
			HAL_ADC_Start(&hadc);
			/*等待转换结束*/
			HAL_ADC_PollForConversion(&hadc,1000);
			/*读取结果*/
			VREFINT_DATA[i] = HAL_ADC_GetValue(&hadc);
			/*停止ADC读取*/
			HAL_ADC_Stop(&hadc);
			SUM[1] += VREFINT_DATA[i];
		}
		/*计算外部输入电压平均值*/
		ADC_DATA[100] = SUM[0] / 100;
		/*计算内部基准电压平均值*/
		VREFINT_DATA[100] = SUM[1] / 100;
		/*计算公式V_channelx = 3V *VREFINT_CAL*ADC_DATAx/(VREFINT_DATA*FULL_SCALE)*/
		/*V_channel为计算后的值,VREFCAL为内部基准值、FULL_SCALE为12位分辨率即4096-1*/
		/*ADC_DATA为外部采集电压值,VREFINT_DATA为通道17采集的值*/
		/*计算校准后的电压值*/
		V_CHANNEL = (float)(3*VREFCAL*ADC_DATA[100])/(VREFINT_DATA[100]*4095);
		/*电压值放大1000倍*/
		ADC_value = V_CHANNEL * 1000;
		/*通过打印ADC_value值*/
		printf("ADC数据:%dmv",ADC_value);
		/*延时*/
		HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

五、运行状态

运行状态如下,ADC读取数据还是蛮准的。

万用表读取数据,ADC读取数据与万用表基本差不多。

工程源码链接:STM32L051C8T6_ADC读取例程源码

  • 21
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用STM32F103C8T6的ADC(模数转换器)进行采集的简单实例。 首先,我们需要在STM32CubeMX中配置ADC。在“Pinout & Configuration”选项卡中,选择ADC1并将其配置为“Regular Conversion Mode”。选择要使用的通道(例如PA0),并将采样时间设置为适当的值。然后,确保在“Clock Configuration”选项卡中启用了ADC时钟。 接下来,我们需要在代码中初始化ADC并启动采样。以下是一个示例函数,它将初始化ADC并连续采样通道0,然后返回ADC值: ``` uint16_t adc_read(void){ ADC_HandleTypeDef hadc; hadc.Instance = ADC1; hadc.Init.ScanConvMode = DISABLE; hadc.Init.ContinuousConvMode = ENABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.NbrOfConversion = 1; HAL_ADC_Init(&hadc); ADC_ChannelConfTypeDef sConfig; sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5; HAL_ADC_ConfigChannel(&hadc, &sConfig); HAL_ADC_Start(&hadc); HAL_ADC_PollForConversion(&hadc, 100); uint16_t value = HAL_ADC_GetValue(&hadc); HAL_ADC_Stop(&hadc); return value; } ``` 我们将使用HAL库来初始化ADC并进行采样。在这个函数中,我们首先初始化了ADC的配置结构体,并设置了采样模式为连续采样,通道为0,数据对齐方式为右对齐,转换数量为1。然后我们通过调用`HAL_ADC_Init()`函数来初始化ADC。 接下来,我们配置了通道0的采样时间和排名,并通过调用`HAL_ADC_ConfigChannel()`函数来配置ADC通道。 然后,我们启动ADC并等待转换完成,这可以通过调用`HAL_ADC_Start()`和`HAL_ADC_PollForConversion()`函数来完成。最后,我们获取ADC值并停止ADC转换。 在主函数中,我们可以调用`adc_read()`函数来读取ADC值,并将其打印到串口: ``` int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); MX_ADC1_Init(); while (1){ uint16_t value = adc_read(); printf("ADC Value: %d\n", value); HAL_Delay(1000); } } ``` 现在,我们已经成功地使用STM32F103C8T6的ADC模块进行了采集。我们可以将该模块与其他传感器一起使用,例如光敏电阻或温度传感器,以测量环境参数并执行控制操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值