STM32 ADC 转换使用 HAL

电器工程 微控制器 ADC stm32 stm32f4 图书馆
2022-01-30 15:00:06

我正在尝试学习如何使用 stm32 中的“新”HAL 库。
当我尝试进行简单的 ADC 转换时,它只工作一次,但随后停止转换。我想没有设置转换结束标志。我正在使用 STM32f429I Discovery 板,板上有 STM32f429ZI。
请注意,我知道 sprintf 是不好的做法,并且使用中断制作 adc 更好,我知道,请不要指出,这与问题无关,我只是在这里测试 HAL。
所以问题是为什么没有设置 EOC 标志或者我可以做些什么来使它工作?谷歌搜索没有多大帮助,因为关于 HAL 的好材料很少。

这是代码:

__IO uint16_t ADCValue=0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc);

int main(void)
{
  char str[15];

  /* Various initializations */

  HAL_ADC_Start(&hadc1);
  while (1)
  {

        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
            sprintf(str, "%d", ADCValue);
            BSP_LCD_DisplayStringAt(130,30, (uint8_t*)str, LEFT_MODE);
        }

  }

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    ADCValue = HAL_ADC_GetValue(&hadc1);
}

我还用CubeMX创建了项目,adc配置如下: 在此处输入图像描述

编辑 1
我试图调试一切,似乎程序陷入检查 EOC 标志 - 它看到它没有显示,因此发出计时器等待 EOC 出现(但它永远不会被设置) 这是它的代码卡在调试器中:

/* Check End of conversion flag */
  while(!(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)))
  {
    /* Check for the Timeout */
    if(Timeout != HAL_MAX_DELAY)
    {
      if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
      {
        hadc->State= HAL_ADC_STATE_TIMEOUT;
        /* Process unlocked */
        __HAL_UNLOCK(hadc);
        return HAL_TIMEOUT;
      }
    }
4个回答

在您的原始代码中,将“转换结束选择”设置为禁用。

 hadc1.Init.EOCSelection = DISABLE;

原来,#define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)值等于DISABLE所以实际上EOCSelection应该配置为: 能够多次轮询ADC。在此处输入图像描述

然后您可以在不停止和启动 ADC 的情况下连续读取 ADC:

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    ConfigureADC();

    HAL_ADC_Start(&hadc1);
    while(1)
    {
        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
        }
    }
}

这种方式对我来说效果很好。

由于 HAL 是一个相当新的库,因此可以找到的资源并不多,但并非不可能。我从本教程中学到了很多东西,它逐步演示了所有可能的 ADC 用法;从简单的轮询到使用中断和 DMA。

我想为我的设置(nucleo-h743)添加它是不够的:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

我还必须启用溢出设置:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

没有这个,HAL_ADC_PollForConversion 仍然阻塞。我不完全理解为什么这是必要的,但它确实允许我以连续模式进行轮询。

嗯...我发现了几个使用 HAL_ADC_Stop(&hadc1) 来结束转换的教程...我之前在看这些教程并认为这是相当野蛮的方式,似乎它完全禁用了 ADC,所以我虽然应该有不同的方法。但看起来,这实际上运作良好。
如果有更优雅的方法,欢迎发布答案,因为我认为使用 HAL_ADC_Stop() 非常糟糕,但可以用于学习目的。

while (1)
  {
        HAL_ADC_Start(&hadc1);
        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
                        sprintf(str, "%d", ADCValue);
                        BSP_LCD_DisplayStringAt(130,30, (uint8_t*)str, LEFT_MODE);
        }
        HAL_ADC_Stop(&hadc1);

  }

这对我有用,希望它会有所帮助:

if (HAL_ADC_Start(&hadc) != HAL_OK)
{
    /* Start Conversation Error */
    // Error_Handler();
}
if (HAL_ADC_PollForConversion(&hadc, 500) != HAL_OK)
{
    /* End Of Conversion flag not set on time */
    // Error_Handler();
    ADCValue=-1;
}
else
{
    /* ADC conversion completed */
    /*##-5- Get the converted value of regular channel ########################*/
    ADCValue = HAL_ADC_GetValue(&hadc);
}
HAL_ADC_Stop(&hadc);