这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 有奖活动 » STM32C0116DK开发探索记(2)

共1条 1/1 1 跳转至

STM32C0116DK开发探索记(2)

菜鸟
2026-06-11 12:34:47     打赏

4.A/D数据采集

在开发板上,没有配置常规的按键,取而代之的则是一个方向键,并以模拟信号的方式来进行识别,其电路见图16所示。

由图可知,该方向键所使用的硬件为PA8,是A/D检测的8#通道。此外,它还给出了各键作用下的电压检测值,以供对比分析,见红色框内的内容。

image.png

16 方向键电路

它之所以这样设计,可有效地解决引脚资源占用过多的问题,也为A/D检测提供了硬件方面的方便。 

有了硬件的支持,那软件呢?

对不起,在例程方面没有提供相应的支持。

现在,OLED屏的作用又可以派上用场了,借助它可以观察程序设计的正确性。

经反复的探索和尝试,终于有了可信的结果。

其中,A/D的初始化函数为:

static void MX_ADC1_Init(void)
{
  LL_ADC_InitTypeDef ADC_InitStruct = {0};
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_SYSCLK);
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC);
  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
  GPIO_InitStruct.Pin = LL_GPIO_PIN_8;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  #define ADC_CHANNEL_CONF_RDY_TIMEOUT_MS ( 1U)
  #if (USE_TIMEOUT == 1)
  uint32_t Timeout ;
  #endif 
  ADC_InitStruct.Clock = LL_ADC_CLOCK_SYNC_PCLK_DIV4;
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
  ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
  LL_ADC_Init(ADC1, &ADC_InitStruct);
  LL_ADC_REG_SetSequencerConfigurable(ADC1, LL_ADC_REG_SEQ_FIXED);
  ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
  ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;
  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
  LL_ADC_REG_SetSequencerScanDirection(ADC1, LL_ADC_REG_SEQ_SCAN_DIR_FORWARD);
  LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE);
  LL_ADC_SetTriggerFrequencyMode(ADC1, LL_ADC_CLOCK_FREQ_MODE_HIGH);
  LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_8);  //LL_ADC_CHANNEL_4
  #if (USE_TIMEOUT == 1)
  Timeout = ADC_CHANNEL_CONF_RDY_TIMEOUT_MS;
  #endif /* USE_TIMEOUT */
  while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0)
  {
     #if (USE_TIMEOUT == 1)
     if (LL_SYSTICK_IsActiveCounterFlag())
     {
          if(Timeout-- == 0)
         {
             Error_Handler();
         }
     }
     #endif
  }
  LL_ADC_ClearFlag_CCRDY(ADC1);
  LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_79CYCLES_5);
  LL_ADC_DisableIT_EOC(ADC1);
  LL_ADC_DisableIT_EOS(ADC1);
  LL_ADC_EnableInternalRegulator(ADC1);
  uint32_t wait_loop_index;
  wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
  while(wait_loop_index != 0)
  {
       wait_loop_index--;
  }
  LL_ADC_EnableIT_EOC(ADC1);
  LL_ADC_EnableIT_OVR(ADC1);
}


激活A/D采集的函数为:

void ADC_Activate(void)
{
  __IO uint32_t wait_loop_index = 0U;
  __IO uint32_t backup_setting_adc_dma_transfer = 0U;
  #if (USE_TIMEOUT == 1)
  uint32_t Timeout = 0U; 
  #endif
  if (LL_ADC_IsEnabled(ADC1) == 0)
  {
    LL_ADC_EnableInternalRegulator(ADC1);
    wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
    while(wait_loop_index != 0)
    {
      wait_loop_index--;
    }
    backup_setting_adc_dma_transfer = LL_ADC_REG_GetDMATransfer(ADC1);
    LL_ADC_REG_SetDMATransfer(ADC1, LL_ADC_REG_DMA_TRANSFER_NONE);
    LL_ADC_StartCalibration(ADC1);
    #if (USE_TIMEOUT == 1)
    Timeout = ADC_CALIBRATION_TIMEOUT_MS;
    #endif
    while (LL_ADC_IsCalibrationOnGoing(ADC1) != 0)
    {
    #if (USE_TIMEOUT == 1)
      if (LL_SYSTICK_IsActiveCounterFlag())
      {
        if(Timeout-- == 0)
        {
          Error_Handler();
        }
      }
    #endif
    }
    LL_ADC_REG_SetDMATransfer(ADC1, backup_setting_adc_dma_transfer);
    wait_loop_index = (ADC_DELAY_CALIB_ENABLE_CPU_CYCLES >> 1);
    while(wait_loop_index != 0)
    {
      wait_loop_index--;
    }
    LL_ADC_Enable(ADC1);
    #if (USE_TIMEOUT == 1)
    Timeout = ADC_ENABLE_TIMEOUT_MS;
    #endif 
    while (LL_ADC_IsActiveFlag_ADRDY(ADC1) == 0)
    {
    #if (USE_TIMEOUT == 1)
      if (LL_SYSTICK_IsActiveCounterFlag())
      {
        if(Timeout-- == 0)
        {
          Error_Handler();
        }
      }
    #endif
    }
  }
}

实现A/D采集和显示的主程序为:

int main(void)
{
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
  NVIC_SetPriority(SysTick_IRQn, 3);
  SystemClock_Config();
  MX_GPIO_Init();
  OLED_config();
  OLED_Init();
  OLED_Clear();
  OLED_ShowString(0,0," STM32C0116_DK",16);
  OLED_ShowString(0,2," U =        mv",16);
  OLED_ShowString(0,4," A/D= ",16);
  MX_ADC1_Init();
  ADC_Activate();
  while (1)
  {
    ConversionStartPoll_ADC_GrpRegular();
    uhADCxConvertedData = LL_ADC_REG_ReadConversionData32(ADC1);
    uhADCxConvertedData_Voltage_mVolt = __LL_ADC_CALC_DATA_TO_VOLTAGE(VDDA_APPLI, uhADCxConvertedData, LL_ADC_RESOLUTION_12B);
OLED_ShowNum(48,4, uhADCxConvertedData,4,16);
    OLED_ShowNum(48,2, uhADCxConvertedData_Voltage_mVolt,4,16);
    LED_On();
    LL_mDelay(LED_BLINK_SLOW);
    LED_Off();
    LL_mDelay(LED_BLINK_SLOW);
  }
}

经程序的编译和下载,其测试结果见图17至图22所示,经与图16的电压输出值的比对,说明其结果正确。 

image.png

17 悬空状态

image.png

18 按选取键

image.png

19 按向左键

image.png

20 按向下键

image.png

21 按向上键

image.png

22 按向右键

下面将重点解决串口通信的问题,以实现最终的目标。



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]