蓝桥杯-嵌入式-5-ADC

ADC基本功能

基本功能框图

STM32G431内部集成了2个最高12位的ADC(ADC1和ADC2)。在对这两个ADC配置的时候,其精度可以配置为:六位、八位、十位、十二位。
转换电压的范围是:0~Vref+;(一般都是接到3.3v电压上)。
一共有19个转换通道:分别为16个外部通道(IO引脚)和3个内部通道。
其采样时间、扫描方向都可以进行软件配置。
在这里插入图片描述

ADC的两个通道

在使用的开发板上,某外部引脚可以选择用ADC1或者是ADC2进行转换。ADC1和ADC2对应的通道和引脚如下图所示:
在这里插入图片描述ADC通道一共分为两种,一种是规则通道,另外一种是注入通道。规则通道就是像字面意思一样,规规矩矩的按着顺序来转换,我们平时用到的也是这种通道。注入通道就相当于优先级更高的通道,他的原理和规则通道是一样的,只是在转换的过程中,它可以“插队”在规则通道当中。
在这里插入图片描述

通道转换时序

通道转换的时序图如下所示:
在这里插入图片描述

触发源

在底层配置的时候,对于触发源来说;
使用控制寄存器启动时,很简单,为ADON位写1开始转换;写0停止转换。
使用外部事件来触发转换,
这个触发包括内部定时器触发和外部I0触发。

触发源的选择由ADC_ CFGR的EXTSEL[3:0]和ADC_ JSQR的JEXTSEL[3:0]位 来控制,

EXTSEL[3:0]用于规则通道的触发源,
JEXTSEL[3:0]用于选择注入通道的触发源。

选择好触发源后,控制EXTTRIG和JEXTTRIG这两位来激活触发源。

采样和转换的时间

ADC_ SMPR1和ADC_ SMPR2的SMP[2:0]位设置每个通道可以分别设置成不同的时间进行采样
采样的周期最小是3个
周期等于1/ADC _CLK
TCONV=采样时间+12个周期

当ADC _CLK=30MHz,ADC为3周期,那么总的转换时间为: TCONV=3+12=15个周期=0.5uS。

数据寄存器

注入数据寄存器是4*16位,规则数据寄存器是16位,这就意味着,规则数据寄存器要一个转换结果一个转换结果的等待,而注入数据寄存器就可以一次性存四个转换结果。
对于转换结果来说,是12位的,这样的话在寄存器中就出现了左对齐和右对齐。

模拟看门狗和中断

此部分具体内容如下图所示:
在这里插入图片描述

ADC工作模式

ADC的工作模式大体上可以分为八种;
1.单次转换模式:在单词转换模式下,ADC执行一次转换。
2.不连续采样模式(触发一次,n个转换)
对于这种模式示例如下所示:
在这里插入图片描述
3.常规扫描模式(连续采样)
每次转换结果后,会自动转换该组中的下一个通道。

4.注入转换扫描模式
在这里插入图片描述
5.DMA应用模式
在这里插入图片描述
6.多重ADC同时模式(一次触发,多个ADC同时转换通道数据)
在这里插入图片描述
7.多重ADC交替模式(两个/三个ADC交替对一个通道采样)
在这里插入图片描述
8.多重ADC交替触发模式(两个/三个ADC交替对序列采样)
在这里插入图片描述

ADC程序设计

在本次的ADC程序设计中,是改变电位器组织,使得电位器两侧电压值发生改变。

//ADC1和ADC2的初始化程序
void ADC1_Init(void)
{

  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.GainCompensation = 0;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_11;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

}

void ADC2_Init(void)
{

  ADC_ChannelConfTypeDef sConfig = {0};

  hadc2.Instance = ADC2;
  hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
  hadc2.Init.Resolution = ADC_RESOLUTION_12B;
  hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc2.Init.GainCompensation = 0;
  hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc2.Init.LowPowerAutoWait = DISABLE;
  hadc2.Init.ContinuousConvMode = DISABLE;
  hadc2.Init.NbrOfConversion = 1;
  hadc2.Init.DiscontinuousConvMode = DISABLE;
  hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc2.Init.DMAContinuousRequests = DISABLE;
  hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc2.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc2) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_15;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}
static uint32_t HAL_RCC_ADC12_CLK_ENABLED=0;

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(adcHandle->Instance==ADC1)
  {
    HAL_RCC_ADC12_CLK_ENABLED++;
    if(HAL_RCC_ADC12_CLK_ENABLED==1){
      __HAL_RCC_ADC12_CLK_ENABLE();
    }

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**ADC1 GPIO Configuration
    PB12     ------> ADC1_IN11
    */
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  }
  else if(adcHandle->Instance==ADC2)
  {

    HAL_RCC_ADC12_CLK_ENABLED++;
    if(HAL_RCC_ADC12_CLK_ENABLED==1){
      __HAL_RCC_ADC12_CLK_ENABLE();
    }
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**ADC2 GPIO Configuration
    PB15     ------> ADC2_IN15
    */
    GPIO_InitStruct.Pin = GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  }
}

初始化完成后,需要对两个通道的电压值进行采集,然后进行转换显示在液晶屏上。

// 获取通道采集值
uint16_t getADC1(void)
{
	uint16_t adc = 0;
	HAL_ADC_Start(&hadc1);
	adc = HAL_ADC_GetValue(&hadc1);
	
	return adc;
}

uint16_t getADC2(void)
{
	uint16_t adc = 0;
	HAL_ADC_Start(&hadc2);
	adc = HAL_ADC_GetValue(&hadc2);
	
	return adc;
}

//液晶屏显示
	sprintf((unsigned char *)Lcd_Disp_String,"R38_Vol:%6.3fV",getADC1()*3.3/4096);
	LCD_DisplayStringLine(Line5,Lcd_Disp_String);
	sprintf((unsigned char *)Lcd_Disp_String,"R37_Vol:%6.3fV",getADC2()*3.3/4096);
	LCD_DisplayStringLine(Line6,Lcd_Disp_String);

需要注意的是,在时钟配置时需要加上如下代码,在STM32CubeMx中直接会生成

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_ADC12;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
  PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢小施恶霸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值