Konversi STM32 ADC menggunakan HAL

10

Saya mencoba mempelajari cara menggunakan perpustakaan HAL "baru" dari stm32.
Ketika saya mencoba melakukan konversi ADC sederhana, ia berfungsi hanya satu kali, tetapi kemudian berhenti konversi. Saya kira Bendera akhir konversi tidak disetel. Saya menggunakan papan Discovery STM32f429I, yang memiliki board STM32f429ZI.
Perhatikan bahwa saya tahu tentang sprintf menjadi praktik buruk dan membuat adc dengan interupsi lebih baik, saya tahu bahwa, tolong jangan tunjukkan, ini tidak relevan dengan pertanyaan, saya hanya menguji HAL di sini.
Jadi pertanyaannya adalah mengapa bendera EOC tidak disetel atau apa yang bisa saya lakukan untuk membuatnya berfungsi? Googling tidak banyak membantu karena sangat sedikit materi bagus tentang HAL di luar sana.

Ini kodenya:

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

Saya juga membuat proyek dengan CubeMX, konfigurasi adc adalah sebagai berikut: masukkan deskripsi gambar di sini

EDIT 1
Saya mencoba men-debug semuanya dan tampaknya program macet untuk memeriksa bendera EOC - ia melihat bahwa itu tidak ditampilkan dan karena itu mengeluarkan timer menunggu EOC muncul (tetapi tidak pernah disetel) Berikut adalah kode di mana ia macet di debugger:

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

Jawaban:

6

Dalam kode asli Anda, atur Seleksi Akhir Konversi ke dinonaktifkan.

 hadc1.Init.EOCSelection = DISABLE;

Ternyata #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)nilainya sama dengan DISABLE. Jadi sebenarnya pemilihan EOC harus dikonfigurasi sebagai: untuk dapat polling ADC beberapa kali.masukkan deskripsi gambar di sini

Kemudian Anda dapat membaca ADC secara terus menerus tanpa berhenti dan memulai 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);
        }
    }
}

Dengan cara ini bekerja dengan baik untuk saya.

Karena HAL adalah perpustakaan yang cukup baru, tidak banyak sumber daya yang dapat ditemukan tetapi bukan tidak mungkin. Saya belajar banyak dari tutorial ini , ini menunjukkan semua kemungkinan penggunaan ADC langkah demi langkah; dari polling sederhana, hingga menggunakan interupsi dan DMA.

Bence Kaulics
sumber
hm ... menonaktifkan EOCSeleksi membuatnya berfungsi, tetapi dari definisi itu dikatakan - Menentukan apakah bendera EOC ditetapkan pada akhir konversi saluran tunggal atau pada akhir semua konversi. Menonaktifkan ini seharusnya tidak membantu secara definisi .. tetapi ini membantu .... membingungkan. Tahukah Anda mengapa sebenarnya menonaktifkan ini membuatnya bekerja? terima kasih atas jawabannya
ScienceSamovar
Saya baru belajar HAL juga, jadi saya belum tahu alasannya. Itu hanya pengalaman. Saya menemukan bahwa HAL dapat consfuing berkali-kali.
Bence Kaulics
Saya telah memeriksa nilai define dan #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)yang sama dengan dinonaktifkan, jadi dinonaktifkan sebenarnya adalah ADC_EOC_SEQ_CONV.
Bence Kaulics
1
oh, ok, jadi itu tidak benar-benar dinonaktifkan. Masuk akal, sebelumnya itu ADC_EOC_SINGLE_CONV yang mungkin berarti hanya itu - itu mengkonversi hanya satu kali, dan ADC_EOC_SEQ_CONV adalah konversi berkelanjutan. Satu lagi misteri yang terpecahkan :) Terima kasih!
ScienceSamovar
Ya, seharusnya begitu. :)
Bence Kaulics
2

Hm ... Saya menemukan beberapa tutorial yang menggunakan HAL_ADC_Stop (& hadc1) untuk mengakhiri konversi ... Saya melihat tutorial ini sebelumnya dan berpikir bahwa ini adalah cara yang agak biadab, sepertinya ini menonaktifkan ADC sepenuhnya, jadi saya pikir seharusnya ada metode yang berbeda. Tapi sepertinya, ini benar-benar berfungsi dengan baik.
Selamat datang untuk mengirim jawaban jika ada cara yang lebih elegan untuk melakukan ini, karena saya pikir menggunakan HAL_ADC_Stop () cukup buruk, tetapi dapat digunakan untuk tujuan pembelajaran.

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

  }
ScienceSamovar
sumber
Hai, saya menemukan masalah dengan metode ini, ini membatasi laju sampel maksimum yang dapat Anda capai dengan BANYAK, tidak disarankan untuk menggunakan metode ini jika Anda memerlukan konversi ADC cepat.
Richard Bamford
2

Saya ingin menambahkan bahwa untuk pengaturan saya (nucleo-h743) itu tidak cukup untuk mengatur:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

Saya juga harus mengaktifkan pengaturan overrun juga:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

Tanpa ini, HAL_ADC_PollForConversion masih memblokir. Saya tidak sepenuhnya mengerti mengapa ini perlu tapi itu memungkinkan saya untuk polling dalam mode berkelanjutan.

biglotusturtle
sumber
0

Ini bekerja untuk saya, semoga akan membantu:

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);
yaniv maor
sumber