Conversão ADC STM32 usando HAL


10

Estou tentando aprender como usar a "nova" biblioteca HAL do stm32.
Quando tento fazer uma conversão ADC simples, ele funciona apenas uma vez, mas pára de ser convertido. Suponho que o sinalizador de final de conversão não seja definido. Estou usando a placa Discovery STM32f429I, que possui a placa STM32f429ZI.
Observe que eu sei que o sprintf é uma prática ruim e adc com interrupção é melhor, eu sei que, por favor, não aponte isso, isso não é relevante para a pergunta, estou testando o HAL aqui.
Portanto, a pergunta é por que o sinalizador EOC não está definido ou o que eu poderia fazer para fazê-lo funcionar? O Google não está ajudando muito, já que existem poucos materiais bons sobre o HAL por aí.

Aqui está o código:

__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);
}

Também criei o projeto com o CubeMX, a configuração adc é a seguinte: insira a descrição da imagem aqui

EDIT 1
Tentei depurar tudo e parece que o programa fica preso na verificação do sinalizador EOC - ele vê que não é mostrado e, portanto, emite um temporizador aguardando o EOC aparecer (mas nunca é definido) Aqui está o código em que ele fica preso no depurador:

/* 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;
      }
    }

Respostas:


6

No seu código original, defina a seleção Fim da conversão como desativada.

 hadc1.Init.EOCSelection = DISABLE;

Descobriu-se que o #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)valor é igual a DISABLE. Portanto, na verdade, o EOCSelection deve ser configurado como: para poder pesquisar o ADC várias vezes.insira a descrição da imagem aqui

Então você pode ler o ADC continuamente, sem parar e iniciar o 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);
        }
    }
}

Dessa forma, funcionou bem para mim.

Como o HAL é uma biblioteca bastante nova, não há muitos recursos a serem encontrados, mas não são impossíveis. Aprendi muito com este tutorial , ele demonstra toda a utilização possível do ADC passo a passo; da pesquisa simples ao uso de interrupções e DMA.


hm ... desativar o EOCSelection faz com que funcione, mas, a partir da definição, diz - Especifica se o sinalizador EOC é definido no final da conversão de canal único ou no final de todas as conversões. Desabilitar isso não deve ajudar por definição .. mas ajuda .... confuso. Você sabe por que exatamente desabilitar isso faz funcionar? Obrigado pela resposta de qualquer maneira
ScienceSamovar

Eu também estou aprendendo HAL, então ainda não sei o motivo. É apenas uma experiência. Eu descobri que o HAL pode estar ocorrendo tantas vezes.
Bence Kaulics

Eu verifiquei os valores de definição e #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)é o mesmo que desativado; portanto, desativado é realmente ADC_EOC_SEQ_CONV.
Bence Kaulics

11
ah, ok, então não está literalmente desativado. Faz sentido, anteriormente era ADC_EOC_SINGLE_CONV, o que provavelmente significa exatamente isso - ele converte apenas uma vez e ADC_EOC_SEQ_CONV é uma conversão contínua. Mais um mistério resolvido :) Obrigado!
precisa

Sim, esse deve ser o caso. :)
Bence Kaulics

2

Hm ... Encontrei alguns tutoriais que usavam HAL_ADC_Stop (& hadc1) para finalizar a conversão ... Eu estava olhando esses tutoriais antes e pensei que essa é uma maneira bastante bárbara, parece que desativa completamente o ADC, então acho que deveria haver método diferente. Mas parece que isso realmente funciona bem.
Seja bem-vindo ao postar a resposta, se houver uma maneira mais elegante de fazer isso, pois acho que usar HAL_ADC_Stop () é bastante horrível, mas pode ser usado para fins de aprendizado.

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);

  }

Olá, Encontrei um problema com esse método, ele restringe a taxa máxima de amostragem que você pode atingir por MUITO, não é recomendável usar esse método se você precisar de conversões rápidas de ADC.
Richard Bamford

2

Gostaria de acrescentar que, para minha configuração (nucleo-h743), não foi suficiente definir:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

Eu também tive que habilitar a configuração de saturação também:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

Sem isso, o HAL_ADC_PollForConversion ainda estava bloqueando. Não entendo completamente por que isso era necessário, mas me permite pesquisar no modo contínuo.


0

Isso funciona para mim, espero que ajude:

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);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.