ADC kontinuierliche Umwandlung STM32F103

Ich stehe vor einem Problem bezüglich der kontinuierlichen Erfassung des ADC-Kanals in STM32F103.

Ich verwende den Interrupt am Ende der Konvertierung, um eine Callback-Funktion aufzurufen, um den erfassten Wert zu speichern.

Das Problem betrifft den Callback, der nur beim ersten Mal aufgerufen wird.

Ich habe mein Projekt mit STM32CubeMx für kontinuierliche Erfassung und Interrupt-Generierung konfiguriert.

Dies ist die ADC-Konfiguration:

hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
    Error_Handler();
}

/**Configure Regular Channel 
*/
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
    Error_Handler();
}

Dies ist meine Akquisitionsfunktion:

ea_ADC_Err_Code_t ea_ADC_n_data_read(Adc_Channel_t channel, adc_eoc_callback adc_cb) 
{
    ea_ADC_Err_Code_t err_code = ADC_ERR;     
    ADC_ChannelConfTypeDef sConfig;

    adc_read_value    = 0;
    adc_eoc_cb        = adc_cb;
    n_adc_acquisition = ADC_MAX_CONS_ACQ;

    /* Deinit ADC */       
    //while(HAL_ADC_DeInit(&adc_handler) != HAL_OK);

    /* Initialize ADC */ 
    //HAL_ADC_Init(&adc_handler);

    /* Configure ADC Channel */
    sConfig.Channel = channel;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
    HAL_ADC_ConfigChannel(&adc_handler, &sConfig);

    /* Set ADC callback */
    HAL_ADC_ConvCpltCallback(&adc_handler);

    /* ADC Calibration */
    //HAL_ADCEx_Calibration_Start(&adc_handler);

    /* Start conversion with interrupt*/
    if (HAL_ADC_Start_IT(&adc_handler) == HAL_OK)
    {
      err_code = ADC_OK;
    }

    return err_code;
}

Und zum Schluss mein Rückruf:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if (n_adc_acquisition)
    {
        adc_read_value += HAL_ADC_GetValue(&adc_handler);
        n_adc_acquisition--;
        edi_Print_L1("ADC Callback %d\n", n_adc_acquisition);
    }
    else
    {
        HAL_ADC_Stop_IT(&adc_handler);
        adc_read_value = adc_read_value >> ADC_DIVIDE_BY_EIGTH;
        adc_eoc_cb(adc_read_value);
    }
}

Habe ich beim Rückruf etwas vergessen?

Hast du den Interrupt irgendwo gelöscht?
@EugeneSh.: Nein. Ich denke, dass im kontinuierlichen Modus die Interrupt-Reinigung nicht benötigt wird. Reinige ich die IT? Danke
Ich habe keine Lust, im Datenblatt zu graben. Aber du solltest. Oder probiere es einfach aus.
Hey, jetzt sehe ich. Sie stellen den Rückruf überhaupt nicht richtig ein. Aber Sie rufen Ihre nur manuell an, HAL_ADC_ConvCpltCallbackdamit Sie sehen, dass sie aufgerufen wird.
Ein Interrupt ist die Information, dass Sie etwas tun sollen, wenn Sie es getan haben, müssen Sie es erneut aktivieren.
@EugeneSh.: Wirklich? Wo habe ich Fehler gemacht?
Siehe Update zum Kommentar
@EugenSch. HAL_ADC_ConvCpltCallback(&adc_handler);
Ach, warte. Ich verstehe. Der STM-Code hat eine schwache Deklaration einer gleichnamigen Funktion, sodass er automatisch als Rückruf festgelegt wird?
@EugenSch. Ja, ich erstelle den Callback "HAL_ADC_ConvCpltCallback" in meiner ADC-Bibliothek.
Aber in jedem Fall sollten Sie es nicht manuell aufrufen, wie Sie es tun
Ich rufe den Rückruf nicht an. Ich definiere es nur in meinem Code neu. Wie st vorschlagen
HAL_ADC_ConvCpltCallback(&adc_handler);Diese Zeile ruft die Funktion auf.
Aber das solltest du dir zeigen main, da der Ablauf unklar ist.
@EugeneSh.: Ops! du hast Recht! Ich denke, das Problem betrifft den Interrupt. Muss ich IT für ADC1 und NVIC konfigurieren?
Nochmals, ich habe keine Zeit, hier tief in eine Recherche einzusteigen, aber vielleicht möchten Sie hier einen Blick darauf werfen

Antworten (1)

Sie haben vergessen, die ADC-Interrupts zu aktivieren, was ungefähr so ​​gemacht werden kann:

HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);

Das nächste Problem bei der Interrupt-Behandlung von HAL ist, dass es zwei schwache Funktionsdeklarationen gibt.

  1. fürvoid ADC_IRQHandler()
  2. fürvoid HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

Sie müssen den ADC_IRQHandler()ersten implementieren, dieser wird aufgerufen, wenn ein Interrupt vom ADC generiert wird. Innerhalb dieser Funktion müssen Sie den aufrufen HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc), Parameter ist der Handler Ihres ADC ( ADC_HandleTypeDef).

void ADC_IRQHandler()
{
    HAL_ADC_IRQHandler(&hadc1);
    //HAL_ADC_IRQHandler(&hadc2); <--- In case of a second ADC
}

Jetzt HAL_ADC_IRQHandler()wird jede Art von Fehler für Sie überprüft (Sie können dies in seiner Implementierung überprüfen) und wenn alles in Ordnung ist, wird die void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc). Da es auch eine schwache Deklaration hat, müssen Sie die Funktion implementieren.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
        int converted_value = HAL_ADC_GetValue(hadc);
        // Do stuff
    }

    //if(hadc->Instance == ADC2)  // <-- In case of a second ADC
    //{
    //
    //}
}

In STM32CubeMX gibt es im ADC1-Konfigurationsfenster eine Registerkarte namens NVIC-Einstellungen . Hier können Sie die globalen Interrupts für ADC1 und ADC2 aktivieren, und wenn Sie dies tun, implementiert STM32Cube die void ADC_IRQHandler(void)in der Datei stm32f1xx_it.c .

/******************************************************************************/
/* STM32F4xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f4xx.s).                    */
/******************************************************************************/

/**
* @brief This function handles ADC1 and ADC2 global interrupts.
*/
void ADC_IRQHandler(void)
{
  /* USER CODE BEGIN ADC_IRQn 0 */

  /* USER CODE END ADC_IRQn 0 */
  HAL_ADC_IRQHandler(&hadc1);
  /* USER CODE BEGIN ADC_IRQn 1 */

  /* USER CODE END ADC_IRQn 1 */
}

Außerdem ist es nur eine kurze Zusammenfassung, also schlage ich vor, das Tutorial durchzulesen , das @Eugene Sh dir gezeigt hat.

Danke! Ich habe den ADC IT mit STM32Cube richtig konfiguriert und jetzt funktioniert der ADC gut!