« 上一篇下一篇 »

STM32——库函数分析:ADC相关

打铁还是得趁热,前几天期末复习去了,几天没碰32,又差点提不起劲了,不过,我岂是这么容易就放弃的人,哈哈。今天我们来学习STM32的ADC(模拟/数字转换器)模块。

在此之前,做几点说明:

1、以后的代码分析全部基于Debug调试,因为这样的确能节约很多的时间,而且代码运行的结果更加准确。

2、之前的文章篇幅实在是太大,所以从这篇文章开始尽量精简篇幅,只分析较重要的知识点与代码。

一、GPIO配置

/**
  * @brief  使能ADC1和DMA1的时钟,初始化PC.01
  * @param  无
  * @retval 无
  */
static void ADC1_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable DMA clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* Enable ADC1 and GPIOC clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
/* Configure PC.01  as analog input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);// PC1,因为是输入模式,所以不用设置速率
}
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

因为DMA1挂载于AHB总线上,所以开启AHB时钟。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);

开启ADC1、GPIOC的时钟,它们挂载于APB2总线上

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);// PC1,因为是输入模式,所以不用设置速率

引脚选为GPIOC->Pin1脚,IO模式为模拟输入。

因为PC1为ADC1的第11输入通道,而我们选择这个通道来实现ADC功能,所以要选中PC1引脚

由上图可知,不管是使用ADC还是DAC功能,其所在引脚均应配置为模拟模式。所以我们将PC1配置为模拟输入。

最后调用库函数GPIO_Init()初始化GPIOC->Pin1脚,IO口配置完毕。

二、ADC配置

/**
  * @brief  配置ADC1的工作模式为DMA模式
  * @param  无
  * @retval 无
  */
static void ADC1_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
/* DMA channel1 configuration */
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //ADC地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;//内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址固定
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;  //内存地址固定
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//半字
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环传输
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* Enable DMA channel1 */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* ADC1 configuration */
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立ADC模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE ;  //禁止扫描模式,扫描模式用于多通道采集
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//开启连续转换模式,即不停地进行ADC转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发转换
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //要转换的通道数目1
ADC_Init(ADC1, &ADC_InitStructure);
/*配置ADC时钟,为PCLK2的8分频,即9MHz*/
RCC_ADCCLKConfig(RCC_PCLK2_Div8); 
/*配置ADC1的通道11为55.5个采样周期,序列为1 */ 
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/*初始化校准寄存器 */   
ADC_ResetCalibration(ADC1);
/*等待校准寄存器初始化完成 */
while(ADC_GetResetCalibrationStatus(ADC1));
/* ADC校准 */
ADC_StartCalibration(ADC1);
/* 等待校准完成*/
while(ADC_GetCalibrationStatus(ADC1));
/* 由于没有采用外部触发,所以使用软件触发ADC转换 */ 
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

先定义结构体ADC_InitStructure,其类型为ADC_InitTypeDef,成员为ADC相关配置:模式、扫描转换、连续转换、外部触发、数据对齐、要转换的通道数目

DMA_DeInit(DMA1_Channel1);

DMA1通道1的参数初始化为缺省值

DMA各参数的定义如下:

#define ADC1_DR_Address    ((u32)0x40012400+0x4c)

因为ADC1的基地址为0x4001 2400,而其数据寄存器相对于基地址的偏移为0x4c,所以外设地址为两者之和(0x4001 2400 + 0x4c)

__IO uint16_t ADC_ConvertedValue;
#define DMA_DIR_PeripheralSRC              ((uint32_t)0x00000000)
#define DMA_PeripheralInc_Disable          ((uint32_t)0x00000000)
#define DMA_MemoryInc_Disable              ((uint32_t)0x00000000)
#define DMA_PeripheralDataSize_HalfWord    ((uint32_t)0x00000100)
#define DMA_MemoryDataSize_HalfWord        ((uint32_t)0x00000400)
#define DMA_Mode_Circular                  ((uint32_t)0x00000020)
#define DMA_Priority_High                  ((uint32_t)0x00002000)
#define DMA_M2M_Disable                    ((uint32_t)0x00000000)

根据上述参数值对DMA进行初始化

DMA_Init(DMA1_Channel1, &DMA_InitStructure);

DMA_Init()函数定义如下:

/**
  * @brief  Initializes the DMAy Channelx according to the specified
  *         parameters in the DMA_InitStruct.
  * @param  DMAy_Channelx: where y can be 1 or 2 to select the DMA and 
  *   x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel.
  * @param  DMA_InitStruct: pointer to a DMA_InitTypeDef structure that
  *         contains the configuration information for the specified DMA Channel.
  * @retval None
  */
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)
{
  uint32_t tmpreg = 0;
  /* Check the parameters */
  assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx));
  assert_param(IS_DMA_DIR(DMA_InitStruct->DMA_DIR));
  assert_param(IS_DMA_BUFFER_SIZE(DMA_InitStruct->DMA_BufferSize));
  assert_param(IS_DMA_PERIPHERAL_INC_STATE(DMA_InitStruct->DMA_PeripheralInc));
  assert_param(IS_DMA_MEMORY_INC_STATE(DMA_InitStruct->DMA_MemoryInc));   
  assert_param(IS_DMA_PERIPHERAL_DATA_SIZE(DMA_InitStruct->DMA_PeripheralDataSize));
  assert_param(IS_DMA_MEMORY_DATA_SIZE(DMA_InitStruct->DMA_MemoryDataSize));
  assert_param(IS_DMA_MODE(DMA_InitStruct->DMA_Mode));
  assert_param(IS_DMA_PRIORITY(DMA_InitStruct->DMA_Priority));
  assert_param(IS_DMA_M2M_STATE(DMA_InitStruct->DMA_M2M));
/*--------------------------- DMAy Channelx CCR Configuration -----------------*/
  /* Get the DMAy_Channelx CCR value */
  tmpreg = DMAy_Channelx->CCR;
  /* Clear MEM2MEM, PL, MSIZE, PSIZE, MINC, PINC, CIRC and DIR bits */
  tmpreg &= CCR_CLEAR_Mask;
  /* Configure DMAy Channelx: data transfer, data size, priority level and mode */
  /* Set DIR bit according to DMA_DIR value */
  /* Set CIRC bit according to DMA_Mode value */
  /* Set PINC bit according to DMA_PeripheralInc value */
  /* Set MINC bit according to DMA_MemoryInc value */
  /* Set PSIZE bits according to DMA_PeripheralDataSize value */
  /* Set MSIZE bits according to DMA_MemoryDataSize value */
  /* Set PL bits according to DMA_Priority value */
  /* Set the MEM2MEM bit according to DMA_M2M value */
  tmpreg |= DMA_InitStruct->DMA_DIR | DMA_InitStruct->DMA_Mode |
            DMA_InitStruct->DMA_PeripheralInc | DMA_InitStruct->DMA_MemoryInc |
            DMA_InitStruct->DMA_PeripheralDataSize | DMA_InitStruct->DMA_MemoryDataSize |
            DMA_InitStruct->DMA_Priority | DMA_InitStruct->DMA_M2M;
  /* Write to DMAy Channelx CCR */
  DMAy_Channelx->CCR = tmpreg;
/*--------------------------- DMAy Channelx CNDTR Configuration ---------------*/
  /* Write to DMAy Channelx CNDTR */
  DMAy_Channelx->CNDTR = DMA_InitStruct->DMA_BufferSize;
/*--------------------------- DMAy Channelx CPAR Configuration ----------------*/
  /* Write to DMAy Channelx CPAR */
  DMAy_Channelx->CPAR = DMA_InitStruct->DMA_PeripheralBaseAddr;
/*--------------------------- DMAy Channelx CMAR Configuration ----------------*/
  /* Write to DMAy Channelx CMAR */
  DMAy_Channelx->CMAR = DMA_InitStruct->DMA_MemoryBaseAddr;
}
  tmpreg = DMAy_Channelx->CCR;

即tmpreg = 0;

  tmpreg &= CCR_CLEAR_Mask;

0与上任何数仍旧为0,所以tmpreg = 0;

  tmpreg |= DMA_InitStruct->DMA_DIR | DMA_InitStruct->DMA_Mode |
            DMA_InitStruct->DMA_PeripheralInc | DMA_InitStruct->DMA_MemoryInc |
            DMA_InitStruct->DMA_PeripheralDataSize | DMA_InitStruct->DMA_MemoryDataSize |
            DMA_InitStruct->DMA_Priority | DMA_InitStruct->DMA_M2M;

即temreg = 0 | 0x0000 0000 | 0x0000 0020 | 0x0000 0000 | 0x0000 0000 | 0x0000 0100 | 0x0000 0400 | 0x0000 2000 | 0x0000 0000 = 0x0000 2520;

  DMAy_Channelx->CCR = tmpreg;

DMA1_Channel1->CCR = 0x0000 2520;由DMA的CCR寄存器描述

可知,DMA1的通道1被配置为:非存储器到存储器模式、通道优先级为高、存储器数据宽度为16位、外设数据宽度为16位、不执行存储器地址增量操作、不执行外设地址增量操作、执行循环操作、从外设读(即外设为数据源)

DMA_Cmd(DMA1_Channel1, ENABLE);

使能DMA1通道1,这里说明一下,ADC1的DMA请求是通过DMA1的通道1来实现的(具体可参考DMA请求映像图)。

ADC各参数的定义如下:

#define ADC_Mode_Independent                       ((uint32_t)0x00000000)
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
#define ADC_ExternalTrigConv_None                  ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */
#define ADC_DataAlign_Right                        ((uint32_t)0x00000000)

根据上述参数值对ADC进行初始化:

ADC_Init(ADC1, &ADC_InitStructure);

库函数ADC_Init()的定义如下:

/**
  * @brief  Initializes the ADCx peripheral according to the specified parameters
  *         in the ADC_InitStruct.
  * @param  ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
  * @param  ADC_InitStruct: pointer to an ADC_InitTypeDef structure that contains
  *         the configuration information for the specified ADC peripheral.
  * @retval None
  */
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct)
{
  uint32_t tmpreg1 = 0;
  uint8_t tmpreg2 = 0;
  /* Check the parameters */
  assert_param(IS_ADC_ALL_PERIPH(ADCx));
  assert_param(IS_ADC_MODE(ADC_InitStruct->ADC_Mode));
  assert_param(IS_FUNCTIONAL_STATE(ADC_InitStruct->ADC_ScanConvMode));
  assert_param(IS_FUNCTIONAL_STATE(ADC_InitStruct->ADC_ContinuousConvMode));
  assert_param(IS_ADC_EXT_TRIG(ADC_InitStruct->ADC_ExternalTrigConv));   
  assert_param(IS_ADC_DATA_ALIGN(ADC_InitStruct->ADC_DataAlign)); 
  assert_param(IS_ADC_REGULAR_LENGTH(ADC_InitStruct->ADC_NbrOfChannel));
  /*---------------------------- ADCx CR1 Configuration -----------------*/
  /* Get the ADCx CR1 value */
  tmpreg1 = ADCx->CR1;
  /* Clear DUALMOD and SCAN bits */
  tmpreg1 &= CR1_CLEAR_Mask;
  /* Configure ADCx: Dual mode and scan conversion mode */
  /* Set DUALMOD bits according to ADC_Mode value */
  /* Set SCAN bit according to ADC_ScanConvMode value */
  tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_Mode | ((uint32_t)ADC_InitStruct->ADC_ScanConvMode << 8));
  /* Write to ADCx CR1 */
  ADCx->CR1 = tmpreg1;
  /*---------------------------- ADCx CR2 Configuration -----------------*/
  /* Get the ADCx CR2 value */
  tmpreg1 = ADCx->CR2;
  /* Clear CONT, ALIGN and EXTSEL bits */
  tmpreg1 &= CR2_CLEAR_Mask;
  /* Configure ADCx: external trigger event and continuous conversion mode */
  /* Set ALIGN bit according to ADC_DataAlign value */
  /* Set EXTSEL bits according to ADC_ExternalTrigConv value */
  /* Set CONT bit according to ADC_ContinuousConvMode value */
  tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_DataAlign | ADC_InitStruct->ADC_ExternalTrigConv |
            ((uint32_t)ADC_InitStruct->ADC_ContinuousConvMode << 1));
  /* Write to ADCx CR2 */
  ADCx->CR2 = tmpreg1;
  /*---------------------------- ADCx SQR1 Configuration -----------------*/
  /* Get the ADCx SQR1 value */
  tmpreg1 = ADCx->SQR1;
  /* Clear L bits */
  tmpreg1 &= SQR1_CLEAR_Mask;
  /* Configure ADCx: regular channel sequence length */
  /* Set L bits according to ADC_NbrOfChannel value */
  tmpreg2 |= (uint8_t) (ADC_InitStruct->ADC_NbrOfChannel - (uint8_t)1);
  tmpreg1 |= (uint32_t)tmpreg2 << 20;
  /* Write to ADCx SQR1 */
  ADCx->SQR1 = tmpreg1;
}
  tmpreg1 = ADCx->CR1;

即tmpreg1 = 0;

  tmpreg1 &= CR1_CLEAR_Mask;

0与上任何数都为0,所以tmpreg1 = 0;

  tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_Mode | ((uint32_t)ADC_InitStruct->ADC_ScanConvMode << 8));

即tmpreg1 = 0 | (0x0000 0000) | (0 << 8) = 0;

  ADCx->CR1 = tmpreg1;

ADC1->CR1 = 0;由ADC的CR1寄存器描述

可知,ADC1被配置为:独立模式、关闭扫描模式

  tmpreg1 = ADCx->CR2;

即tmpreg1 = 0;

  tmpreg1 &= CR2_CLEAR_Mask;

即tmpreg1 = 0;

  tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_DataAlign | ADC_InitStruct->ADC_ExternalTrigConv |
            ((uint32_t)ADC_InitStruct->ADC_ContinuousConvMode << 1));

即tmpreg1 = 0 | 0x0000 0000 | 0x000E 0000 | (0x01 << 1) = 0x000E 0002;

  ADCx->CR2 = tmpreg1;

ADC1->CR2 = 0x000E 0002;由ADC的CR2寄存器描述

可知,ADC1被配置为:选择SWSTART为触发事件、连续转换模式

  tmpreg1 = ADCx->SQR1;

即tmpreg1 = 0;

  tmpreg1 &= SQR1_CLEAR_Mask;

即tmpreg1 = 0;

  tmpreg2 |= (uint8_t) (ADC_InitStruct->ADC_NbrOfChannel - (uint8_t)1);

即tmpreg2 = 0 | (1 - 1) = 0;

  tmpreg1 |= (uint32_t)tmpreg2 << 20;

即tmpreg1 = 0 | (0 << 20) = 0;

  ADCx->SQR1 = tmpreg1;

ADC1->SQR1 = 0;由ADC的SQR1寄存器描述

可知,ADC1被配置为:1个转换

RCC_ADCCLKConfig(RCC_PCLK2_Div8);
/**
  * @brief  Configures the ADC clock (ADCCLK).
  * @param  RCC_PCLK2: defines the ADC clock divider. This clock is derived from 
  *   the APB2 clock (PCLK2).
  *   This parameter can be one of the following values:
  *     @arg RCC_PCLK2_Div2: ADC clock = PCLK2/2
  *     @arg RCC_PCLK2_Div4: ADC clock = PCLK2/4
  *     @arg RCC_PCLK2_Div6: ADC clock = PCLK2/6
  *     @arg RCC_PCLK2_Div8: ADC clock = PCLK2/8
  * @retval None
  */
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2)
{
  uint32_t tmpreg = 0;
  /* Check the parameters */
  assert_param(IS_RCC_ADCCLK(RCC_PCLK2));
  tmpreg = RCC->CFGR;
  /* Clear ADCPRE[1:0] bits */
  tmpreg &= CFGR_ADCPRE_Reset_Mask;
  /* Set ADCPRE[1:0] bits according to RCC_PCLK2 value */
  tmpreg |= RCC_PCLK2;
  /* Store the new value */
  RCC->CFGR = tmpreg;
}

根据上述RCC_ADCCLKConfig()函数定义及Debug调试

可得:RCC->CFGR = 0x001D C40A;由RCC的CFGR寄存器描述

可知,ADC时钟被配置为:PCLK2的8分频(72 / 8 = 9 MHz)

ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);

ADC_RegularChannelConfig()函数定义如下:

void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
{
  uint32_t tmpreg1 = 0, tmpreg2 = 0;
  /* Check the parameters */
  assert_param(IS_ADC_ALL_PERIPH(ADCx));
  assert_param(IS_ADC_CHANNEL(ADC_Channel));
  assert_param(IS_ADC_REGULAR_RANK(Rank));
  assert_param(IS_ADC_SAMPLE_TIME(ADC_SampleTime));
  /* if ADC_Channel_10 ... ADC_Channel_17 is selected */
  if (ADC_Channel > ADC_Channel_9)
  {
    /* Get the old register value */
    tmpreg1 = ADCx->SMPR1;
    /* Calculate the mask to clear */
    tmpreg2 = SMPR1_SMP_Set << (3 * (ADC_Channel - 10));
    /* Clear the old channel sample time */
    tmpreg1 &= ~tmpreg2;
    /* Calculate the mask to set */
    tmpreg2 = (uint32_t)ADC_SampleTime << (3 * (ADC_Channel - 10));
    /* Set the new channel sample time */
    tmpreg1 |= tmpreg2;
    /* Store the new register value */
    ADCx->SMPR1 = tmpreg1;
  }
  else /* ADC_Channel include in ADC_Channel_[0..9] */
  {
    /* Get the old register value */
    tmpreg1 = ADCx->SMPR2;
    /* Calculate the mask to clear */
    tmpreg2 = SMPR2_SMP_Set << (3 * ADC_Channel);
    /* Clear the old channel sample time */
    tmpreg1 &= ~tmpreg2;
    /* Calculate the mask to set */
    tmpreg2 = (uint32_t)ADC_SampleTime << (3 * ADC_Channel);
    /* Set the new channel sample time */
    tmpreg1 |= tmpreg2;
    /* Store the new register value */
    ADCx->SMPR2 = tmpreg1;
  }
  /* For Rank 1 to 6 */
  if (Rank < 7)
  {
    /* Get the old register value */
    tmpreg1 = ADCx->SQR3;
    /* Calculate the mask to clear */
    tmpreg2 = SQR3_SQ_Set << (5 * (Rank - 1));
    /* Clear the old SQx bits for the selected rank */
    tmpreg1 &= ~tmpreg2;
    /* Calculate the mask to set */
    tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 1));
    /* Set the SQx bits for the selected rank */
    tmpreg1 |= tmpreg2;
    /* Store the new register value */
    ADCx->SQR3 = tmpreg1;
  }
  /* For Rank 7 to 12 */
  else if (Rank < 13)
  {
    /* Get the old register value */
    tmpreg1 = ADCx->SQR2;
    /* Calculate the mask to clear */
    tmpreg2 = SQR2_SQ_Set << (5 * (Rank - 7));
    /* Clear the old SQx bits for the selected rank */
    tmpreg1 &= ~tmpreg2;
    /* Calculate the mask to set */
    tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 7));
    /* Set the SQx bits for the selected rank */
    tmpreg1 |= tmpreg2;
    /* Store the new register value */
    ADCx->SQR2 = tmpreg1;
  }
  /* For Rank 13 to 16 */
  else
  {
    /* Get the old register value */
    tmpreg1 = ADCx->SQR1;
    /* Calculate the mask to clear */
    tmpreg2 = SQR1_SQ_Set << (5 * (Rank - 13));
    /* Clear the old SQx bits for the selected rank */
    tmpreg1 &= ~tmpreg2;
    /* Calculate the mask to set */
    tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 13));
    /* Set the SQx bits for the selected rank */
    tmpreg1 |= tmpreg2;
    /* Store the new register value */
    ADCx->SQR1 = tmpreg1;
  }
}

Debug调试得:

ADC1->SMPR1 = 0x0000 0028;由SMPR1寄存器描述

可知,ADC1被配置为:采样时间为55.5个周期

ADC1->SQR3 = 0x0000 000B;由SQR3寄存器描述

可知,ADC1被配置为:规则序列中的第1个转换

ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);

使能ADC1的DMA模式、使能ADC1。

/*初始化校准寄存器 */   
ADC_ResetCalibration(ADC1);
/*等待校准寄存器初始化完成 */
while(ADC_GetResetCalibrationStatus(ADC1));
/* ADC校准 */
ADC_StartCalibration(ADC1);
/* 等待校准完成*/
while(ADC_GetCalibrationStatus(ADC1));

注意在开始ADC转换之前,建议对ADC进行校准,上面即为校准代码,限于篇幅不再详细介绍。

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

ADC_SoftwareStartConvCmd()函数定义如下:

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_ADC_ALL_PERIPH(ADCx));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  if (NewState != DISABLE)
  {
    /* Enable the selected ADC conversion on external event and start the selected
       ADC conversion */
    ADCx->CR2 |= CR2_EXTTRIG_SWSTART_Set;
  }
  else
  {
    /* Disable the selected ADC conversion on external event and stop the selected
       ADC conversion */
    ADCx->CR2 &= CR2_EXTTRIG_SWSTART_Reset;
  }
}

ADC1->CR2 = 0x005E 0103(这里的调试结果(0x001E 0103)我觉得有问题,前面是我自己的结果),再由CR2描述

可知,ADC1被配置为:使用外部触发信号启动转换、开始转换规则通道

ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*3.3;

最后计算AD转换的结果,它是以参考电压值(这里是3.3V)为一个单位,即把3.3V等分成4096份来计算的

注意

ADC输入电压范围:VREF- <= VIN <= VREF+

VREF+电压范围:   2.4V <= VREF+ <= VDDA

VDDA电压范围:    2.4V <= VDDA <= VDD(3.6V)

故:ADC输入电压最高不超过3.6V。

到此为止,STM32的ADC功能就配置完成了,我们可以对从PC1脚输入的电压进行测量并通过串口或LCD来显示电压的具体数值(可测量电压范围:0 ~ 3.3V)。

由于作者学识有限,文中的错误及疏漏之处敬请读者批评指正。


原创作品