【WB32库开发】第14章 (上) ADC电压采集——单通道采集

14.1 认识WB32的ADC

WB32有1个ADC,精度为12位,这个ADC有16个外部通道,分别对应着16个不同的IO口,具体可见WB32数据手册中管脚功能描述表。

ADC的输入电压范围为0-3.3V,若输入的电压过高或过低,可以设计一个外部调理电路,把需要转换的输入电压降低或升高到0-3.3V,这样WB32的ADC就可以测量了。

确定好输入电压后,即可通过输入通道检测输入电压了,但我们还需注意这16个外部通道在转换时还分为规则通道和注入通道;
规则通道为我们常用的通道,而注入通道是一种在规则通道转换时强行插入进行转换的通道,也就是说当规则通道转换过程中有注入通道插队,那么就先转换完注入通道,再继续转换规则通道;这和我们的中断有相似之处;

注入通道只会在有规则通道的时候才会存在。

此外,想要用好ADC还需要了解转换顺序、触发源、转换时间、中断(三种情况:转换完成中断、模拟看门狗中断、DMA请求)和电压转换等,老样子,在例程中带大家一起学习。

14.2 ADC中断转换实验

本节使用固件库ADC中ADC_Interrupt工程,讲解如何配置ADC独立模式单通道采集,单通道采集适用AD转换完成中断,在中断服务函数中读取数据(单通道也可通过DMA的方式来读取,本例主要为展示此方法,在日常使用中可多用DMA来完成ADC采集,使用DMA传输数值的方式不会影响MCU正在运行的程序)。

14.2.1 预处理文件、宏定义文件与函数声明

#include "wb32f10x.h"                    
#include <stdio.h>						 //若使用Printf或Scanf函数,必须包含此头文件
#include "bsp_uart1.h" 					 //使用UART1,必须包含其对应头文件

ADC_InitTypeDef ADC_InitStructure;       //将ADC_InitTypeDef宏定义为ADC_InitStructure

void NVIC_Configuration(void);           //中断设置函数,由用户自定义

本节使用到WB32的ADC,就必须配置ADC初始化结构体成员,宏定义名称大家已经见到很多了,请务必习惯这种写法。

14.2.2 ADC结构体配置及其相关配置

这里笔者将有关ADC输出的所有代码全部在这里进行注释。

 /* 初始化UART1 */
  uart1_init(72000000, 115200);

  /* 使能ADC, GPIOA 时钟 */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_BMX1 |RCC_APB1Periph_ADC |RCC_APB1Periph_GPIOA, ENABLE);

  /* 设置PA3 (ADC Channel3) 为模拟模式 */
  GPIO_Init(GPIOA, GPIO_Pin_3, GPIO_MODE_ANA);

  /* 中断配置函数,由用户自定义 ------------------------------------------------------*/
  NVIC_Configuration();

  /* ADC 模拟模式相关配置函数,了解有如下配置即可---------------------------------------*/
  PWR_UnlockANA();
  ANCTL_SARADCCmd(ENABLE);
  PWR_LockANA();
  
  /* ADC结构体成员配置 */
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;                        //ADC扫描模式选择,单通道为DISABLE,多通道为ENABLE
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;				   //ADC单次转换或者连续转换选择,这里DISABLE配置为单次转换
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //ADC转换触发信号选择,一般设置None为软件自动触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;			   //转换结果对齐模式,一般选择右对齐
  ADC_InitStructure.ADC_NbrOfChannel = 1;							   //AD转换通道树木,根据实际设置,本次为单通道,即为1
  ADC_Init(&ADC_InitStructure);         							   //初始化ADC初始化结构体成员

  /* ADC规则通道设置。这里配置为通道三、第一个转换,此采样时间为7.5个时钟周期 */
  ADC_RegularChannelConfig(ADC_Channel_3, 1, ADC_SampleTime_7Cycles5);

  /* ADC转换结束产生中断,在中断服务函数中读取转换值 */
  ADC_ITConfig(ADC_IT_EOC, ENABLE);

  /* 使能ADC外部触发转换 */
  ADC_ExternalTrigConvCmd(ENABLE);

  /* 使能ADC */
  ADC_Cmd(ENABLE);

  /* 开始ADC校准 */
  ADC_StartCalibration();
  /* 检查校准是否完成 */
  while(ADC_GetCalibrationStatus());

  /* 使能ADC复位校准寄存器 */
  ADC_ResetCalibration();
  /* 检查ADC校准寄存器是否复位完成 */
  while(ADC_GetResetCalibrationStatus());

  /* 没有使用外部触发,故使用软件触发ADC转换 */
  ADC_SoftwareStartConvCmd(ENABLE);

在学习时大家看到这么多的代码是很头疼的,但实际上在WB32标准库下,这些代码都是有迹可循的,需要大家不断的学习和总结。

14.2.3 ADC中断服务函数

在上部分的程序中,我们看到了一条代码ADC_ITConfig(ADC_IT_EOC, ENABLE);这条代码的注释已经标明了其功能,即ADC转换完成后,硬件会将ADC_IT_EOC这个中断标志位自动置1,告诉WB32可以执行对应的中断服务函数了:

void ADC_IRQHandler(void)
{
  if(ADC_GetITStatus(ADC_IT_EOC) != RESET)						//判断ADC是否转换完成
  {
    ADC_ClearITPendingBit(ADC_IT_EOC);							//转换完成后清除该中断位
    printf("\rADC Channel 3: %-5d", ADC_GetADValue(ADC->DR));	//通过ADC_GetADValue这个函数将得到的数值打印出来
  }
}

14.2.3 中断初始化结构体成员配置

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

  /* 配置并使能ADC中断 */
  NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

此结构体大家务必熟悉,这个结构体在使用到中断时必须配置。

14.3 实验结果

代码编译烧录到WB32中,连接好串口,打开串口调试助手。

首先在PA3浮空时按下复位按键,接着将PA3接入GND时按下复位按键,最后将PA3接入3.3V时按下复位按键;这三次的得到的数值如图显示:
在这里插入图片描述

我们可以看到PA3浮空时ADC读到的数值为52,PA3接入GND时ADC读到的数值为52,PA3接入3.3V时ADC读到的数值为4093。

解释一下,因为ADC是12位的,那么12位满量程对应的就是3.3V,12位满量程对应的数字值为2^12(即4096),数值0对应的就是0V。

注意:
1)我们读出的数值并没有很完美的达到0与4096,这是由于误差和芯片的固有设计决定的,可以忽略。

2)在引脚浮空时,根据硬件设计的不同有可能读出不同的值,属于正常情况。

14.4 补充实验与结果

本例程读出的数据不太直观,为此我们新建一个变量用来存放ADC读取的值,并将此值通过运算转换为电压进行显示:

仅需修改ADC中断服务函数部分:

void ADC_IRQHandler(void)
{
  float ADC_V_Value = 0;
  
  if(ADC_GetITStatus(ADC_IT_EOC) != RESET)
  {
    ADC_ClearITPendingBit(ADC_IT_EOC);
    ADC_V_Value = ADC_GetADValue(ADC->DR);
    printf("\rADC Channel 3: %5.0f \r\n", ADC_V_Value);
	printf("\rADC Channel 3 Voltage: %1.1f V\r\n",(3.3 * ADC_V_Value) / 4096);	
  }
}

实验结果如下:
在这里插入图片描述
还是按照先测浮空,接着测GND,最后测3.3V的顺序;

可以看到,除了测得的浮空值略有不同(不影响结果),PA3测得的GND的电压值与3.3V的电压值都是十分准确的。

注意:此例程可以测试0-3.3V内的电压值,若超过3.3V,例如需测量的范围为0-10V,则需要通过外部调理电路将其降压为0-3.3V。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值