STM32基于固件库学习笔记(13)ADC读取电压值

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43993734/article/details/101515218

ADC简介

  • STM32f103 系列有 3 个 ADC(STM32F101/102 系列只有 1 个 ADC),精度为 12 位,每个 ADC 最多有 16 个外部通道。其中ADC1和 ADC2 都有 16个外部通道,ADC3根据 CPU 引脚的不同通道数也不同,一般都有8 个外部通道。
  • ADC 可以独立使用,也可以使用双重模式(提高采样率)。STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
  • STM32F103 系列最少都拥有 2 个 ADC,我们选择的 STM32F103ZET 包含有 3 个 ADC。
  • STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降。
  • STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。

1. 输入电压范围
   ADC 输入范围为:V REF- ≤ V IN ≤ V REF+ 。由 V REF- 、V REF+ 、V DDA 、V SSA 、这四个外部引脚决定。在设计原理图的时候一般把 V SSA 和 V REF- 接地,把 V REF+ 和 V DDA 接 3V3,得到ADC 的输入电压范围为:0~3.3V。
2. 输入通道
STM32F103ZET6 ADC 通道
3. 转换顺序
   分别为 SQR3、SQR2、SQR1。SQR3 控制着规则序列中的第一个到第六个转换,对应的位为:SQ1[4:0]~SQ6[4:0],第一次转换的是位 4:0 SQ1[4:0],如果通道 16想第一次转换,那么在 SQ1[4:0]写 16即可。SQR2 控制着规则序列中的第 7到第12个转换,对应的位为:SQ7[4:0]~SQ12[4:0],如果通道 1想第 8 个转换,则 SQ8[4:0]写 1即可。SQR1控制着规则序列中的第 13到第 16个转换,对应位为:SQ13[4:0]~SQ16[4:0],如果通道 6 想第 10 个转换,则 SQ10[4:0]写 6 即可。具体使用多少个通道,由 SQR1 的位L[3:0]决定,最多 16个通道。
在这里插入图片描述
4. 触发源
  ADC 转换可以由ADC 控制寄存器 2: ADC_CR2 的 ADON 这个位来控制,写 1 的时候开始转换,写 0 的时候停止转换。
  ADC 还支持触发转换,这个触发包括内部定时器触发和外部 IO 触发。触发源有很多,具体选择哪一种触发源,由 ADC 控制寄存器 2:ADC_CR2 的EXTSEL[2:0]和 JEXTSEL[2:0]位来控制。EXTSEL[2:0]用于选择规则通道的触发源,JEXTSEL[2:0]用于选择注入通道的触发源。选定好触发源之后,触发源是否要激活,则由ADC 控制寄存器 2:ADC_CR2 的EXTTRIG 和 JEXTTRIG 这两位来激活。
5. 转换时间
   ADC 输入时钟 ADC_CLK由 PCLK2经过分频产生,最大是 14M,分频因子由 RCC时钟配置寄存器 RCC_CFGR 的位 15:14 ADCPRE[1:0]设置,可以是 2/4/6/8 分频,注意这里没有 1分频。一般设置 PCLK2=HCLK=72M。经过 ADC 预分频器能分频到最大的时钟只能是 12M,采样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us,这个才是最常用的
  ADC 使用若干个 ADC_CLK 周期对输入的电压进行采样,采样的周期数可通过 ADC采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMP[2:0]位设置,ADC_SMPR2 控制的是通道 0~9,ADC_SMPR1 控制的是通道 10~17。每个通道可以分别用不同的时间采样。其中采样周期最小是 1.5 个,即如果我们要达到最快的采样,那么应该设置采样周期为 1.5个周期,这里说的周期就是 1/ADC_CLK。
  ADC 的转换时间跟 ADC 的输入时钟和采样时间有关,公式为:Tconv = 采样时间 +12.5 个周期。当 ADCLK = 14MHZ (最高),采样时间设置为 1.5 周期(最快),那么总的转换时间(最短)Tconv = 1.5 周期 + 12.5 周期 = 14 周期 = 1us。
6. 数据寄存器
  规则组的数据放在 ADC_DR寄存器,注入组的数据放在 JDRx。
7. 中断
   中断分为三种:规则通道转换结束中断,注入转换通道转换结束中断,模拟看门狗中断。
8. 电压转换
  模拟电压经过 ADC转换后,是一个 12 位的数字值,如果通过串口以 16进制打印出来的话,可读性比较差,那么有时候我们就需要把数字电压转换成模拟电压,也可以跟实际的模拟电压(用万用表测)对比,看看转换是否准确。

ADC正常工作的一般配置步骤

1. 开启 ADC用到的 GPIO的时钟和 ADC1 时钟置 ,初始 ADC用到的 GPIO。

//挂载时钟  
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1|RCC_APB2Periph_AFIO,ENABLE);
//GPIO初始化
  GPIO_InitTypeDef GPIO_InitTypeDef_PA;
  GPIO_InitTypeDef_PA.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitTypeDef_PA.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
  GPIO_Init(GPIOA,&GPIO_InitTypeDef_PA);

注:这里使用的ADC1、PA0,其他GPIO时钟具体时钟线
2. 复位 ADC,同时置 ADC 分频因子。

//复位ADC时钟
   ADC_DeInit(ADC1);
//设置 ADC1 分频因子
   RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72/6=12MHz

3. 设置 ADC的工作参数并初始化。

//初始化ADC1参数
   ADC_InitTypeDef ADC1_InitTypeDef_PA;
   ADC1_InitTypeDef_PA.ADC_Mode = ADC_Mode_Independent;  
   ADC1_InitTypeDef_PA.ADC_ScanConvMode = DISABLE; //AD 单通道模式
   ADC1_InitTypeDef_PA.ADC_ContinuousConvMode = DISABLE;//单次模式
   ADC1_InitTypeDef_PA.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
   ADC1_InitTypeDef_PA.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
   ADC1_InitTypeDef_PA.ADC_NbrOfChannel = 1;//顺序进行规则转换的 ADC 通道的数目 1
   ADC_Init(ADC1, &ADC1_InitTypeDef_PA); //根据指定的参数初始化外设 ADCx

ADC_InitTypeDef structure

typedef struct
{
u32 ADC_Mode;//设置 ADC 工作在独立或者双 ADC 模式
/*
ADC_Mode_Independent           ADC1 和 ADC2 工作在独立模式
ADC_Mode_RegInjecSimult         ADC1 和 ADC2 工作在同步规则和同步注入模式
ADC_Mode_RegSimult_AlterTrig    ADC1和ADC2工作在同步规则模式和交替触发模式
ADC_Mode_InjecSimult_FastInterl ADC1和ADC2工作在同步规则模式和快速交替模式
ADC_Mode_InjecSimult_SlowInterl ADC1和ADC2工作在同步注入模式和慢速交替模式
ADC_Mode_InjecSimult            ADC1 和 ADC2 工作在同步注入模式
ADC_Mode_RegSimult              ADC1 和 ADC2 工作在同步规则模式
ADC_Mode_FastInterl             ADC1 和 ADC2 工作在快速交替模式
ADC_Mode_SlowInterl             ADC1 和 ADC2 工作在慢速交替模式
ADC_Mode_AlterTrig              ADC1 和 ADC2 工作在交替触发模式
*/
FunctionalState ADC_ScanConvMode;//模数转换工作在扫描模式(多通道)还是单次(单通道)模式
/*
参数为 ENABLE 或者 DISABLE。
*/
FunctionalState ADC_ContinuousConvMode;//模数转换工作在连续还是单次模式
/*
参数为 ENABLE 或者 DISABLE。
*/
u32 ADC_ExternalTrigConv;//使用外部触发来启动规则通道的模数转换
/*
ADC_ExternalTrigConv_T1_CC1   选择定时器 1 的捕获比较 1 作为转换外部触发
ADC_ExternalTrigConv_T1_CC2   选择定时器 1 的捕获比较 2 作为转换外部触发
ADC_ExternalTrigConv_T1_CC3   选择定时器 1 的捕获比较 3 作为转换外部触发
ADC_ExternalTrigConv_T2_CC2   选择定时器 2 的捕获比较 2 作为转换外部触发
ADC_ExternalTrigConv_T3_TRGO  选择定时器 3 的 TRGO 作为转换外部触发
ADC_ExternalTrigConv_T4_CC4   选择定时器 4 的捕获比较 4 作为转换外部触发
ADC_ExternalTrigConv_Ext_IT11 选择外部中断线 11 事件作为转换外部触发
ADC_ExternalTrigConv_None     转换由软件而不是外部触发启动
*/
u32 ADC_DataAlign;//ADC 数据向左边对齐还是向右边对齐
/*
ADC_DataAlign_Right ADC 数据右对齐
ADC_DataAlign_Left ADC 数据左对齐
*/
u8 ADC_NbrOfChannel;//顺序进行规则转换的 ADC 通道的数目
/*
取值范围是 1 到 16
*/
} ADC_InitTypeDef

4. 使能 ADC 并校准。

//使能ADC   
   ADC_Cmd(ADC1, ENABLE); //使能指定的 ADC1
//复位校准   
   ADC_ResetCalibration(ADC1);
//ADC 校准的
   ADC_StartCalibration(ADC1); //开始指定 ADC1 的校准状态

5. 取读取 ADC 值。

 //设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 ); //通道1
  //规则采样顺序值为 1,采样时间为 239.5 周期
  ADC_SoftwareStartConvCmd(ADC1,ENABLE); //使能指定的 ADC1 的软件转换功能
  while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC ));//等待转换结束
  return ADC_GetConversionValue(ADC1); //返回最近一次 ADC1 规则组的转换结果

完整代码

#include "stm32f10x.h"          
/*
  使用 ADC1 的通道 1 进行 AD 转换
   PA0 模拟输入,测量电池电压
*/
#include "stdio.h"
int fputc(int ch, FILE *f)
{
  while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
  USART_SendData(USART1,(uint8_t)ch);
  return ch;
}
void Usart_Init()
{ 
  GPIO_InitTypeDef GPIO_ITDef1;
  GPIO_InitTypeDef GPIO_ITDef;
  USART_InitTypeDef  USART_ITDef;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
//挂载时钟(复用PA) 串口时钟使能,GPIO 时钟使能,复用时钟使能
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
//PA9 TXD初始化
  GPIO_ITDef.GPIO_Pin = GPIO_Pin_9;//PA9 TXD
  GPIO_ITDef.GPIO_Mode = GPIO_Mode_AF_PP;////复用推挽输出
  GPIO_ITDef.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA,&GPIO_ITDef);
//PA10 TXD初始化
  GPIO_ITDef1.GPIO_Pin = GPIO_Pin_10;//PA10 RXD
  GPIO_ITDef1.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA,&GPIO_ITDef1);
  
//USART初始化
  USART_ITDef.USART_BaudRate = 115200;//波特率
  USART_ITDef.USART_WordLength = USART_WordLength_8b;//发送数据长度
  USART_ITDef.USART_StopBits = USART_StopBits_1; //一个停止位   
  USART_ITDef.USART_Parity = USART_Parity_No; //无奇偶校验位     
  USART_ITDef.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  USART_ITDef.USART_Mode = USART_Mode_Tx| USART_Mode_Rx ;//发送模式 
  USART_Init(USART1,&USART_ITDef);
 
  USART_Cmd(USART1, ENABLE);//使能串口
}

void delay_ms(u16 time)
{    
   u16 i = 0;  
   while(time--)
   {
      i = 12000;  
      while(i--);    
   }
}
//这里使用的PA0可以根据情况修改
void ADC1_Init_PA0(void)
{
//挂载时钟  
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1|RCC_APB2Periph_AFIO,ENABLE);
//GPIO初始化
  GPIO_InitTypeDef GPIO_InitTypeDef_PA;
  GPIO_InitTypeDef_PA.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitTypeDef_PA.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
  GPIO_Init(GPIOA,&GPIO_InitTypeDef_PA);
    
//复位ADC时钟
   ADC_DeInit(ADC1);
//设置 ADC1 分频因子
   RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72/6=12MHz
//初始化ADC1参数
   ADC_InitTypeDef ADC1_InitTypeDef_PA;
   ADC1_InitTypeDef_PA.ADC_Mode = ADC_Mode_Independent;  
   ADC1_InitTypeDef_PA.ADC_ScanConvMode = DISABLE; //AD 单通道模式
   ADC1_InitTypeDef_PA.ADC_ContinuousConvMode = DISABLE;//单次模式
   ADC1_InitTypeDef_PA.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
   ADC1_InitTypeDef_PA.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
   ADC1_InitTypeDef_PA.ADC_NbrOfChannel = 1;//顺序进行规则转换的 ADC 通道的数目 1
   ADC_Init(ADC1, &ADC1_InitTypeDef_PA); //根据指定的参数初始化外设 ADCx
//使能ADC   
   ADC_Cmd(ADC1, ENABLE); //使能指定的 ADC1
//复位校准   
   ADC_ResetCalibration(ADC1);
//ADC 校准的
   ADC_StartCalibration(ADC1); //开始指定 ADC1 的校准状态
//必须等待校验结束
  while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
  while(ADC_GetCalibrationStatus(ADC1)); //等待校 AD 准结束 
}
u16 Get_Adc(u8 ch)
{
  //设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 ); //通道1
  //规则采样顺序值为 1,采样时间为 239.5 周期
  ADC_SoftwareStartConvCmd(ADC1,ENABLE); //使能指定的 ADC1 的软件转换功能
  while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC ));//等待转换结束
  return ADC_GetConversionValue(ADC1); //返回最近一次 ADC1 规则组的转换结果
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
  u32 temp_val=0;
  u8 t;
  for(t=0;t<times;t++)
  {    
    temp_val+=Get_Adc(ch);    
    delay_ms(5);
  }
  return temp_val/times;
}
u16 adcx;
float adcx1=0;
int main(void)
{
  ADC1_Init_PA0();
  Usart_Init();
  delay_ms(1000);
  while(1)
  {
     adcx = Get_Adc_Average(1,100);
     adcx1 = adcx*3.3/4096;
     printf("电压:%3.2f v\n",adcx1);
     delay_ms(500);    
  }     
}
常用资料
  1. STM32F10x_StdPeriph_Lib_V3.5.0(官方固件库)
  2. 链接:《STM32固件库使用手册的中文翻译版》    提取码:4lkx
  3. 链接:(keil5 IAR 等常用助手)           提取码:xzgj
  4. 链接:《STM32中文参考手册V10》         提取码:j748

猜你喜欢

转载自blog.csdn.net/weixin_43993734/article/details/101515218
今日推荐