Chuyển đổi ADC STM32 bằng HAL


10

Tôi đang cố gắng học cách sử dụng thư viện HAL "mới" từ stm32.
Khi tôi cố gắng thực hiện chuyển đổi ADC đơn giản, nó chỉ hoạt động một lần, nhưng sau đó nó dừng chuyển đổi. Tôi cho rằng cờ kết thúc chuyển đổi không được đặt. Tôi đang sử dụng bảng STM32f429I Discovery, có STM32f429ZI trên tàu.
Lưu ý rằng tôi biết về việc chạy nước rút là thực hành tồi và làm cho adc bị gián đoạn là tốt hơn, tôi biết rằng, xin vui lòng không chỉ ra, điều này không liên quan đến câu hỏi, tôi chỉ đang thử nghiệm HAL ở đây.
Vì vậy, câu hỏi là tại sao cờ EOC không được đặt hoặc tôi có thể làm gì để làm cho nó hoạt động? Googling không giúp được gì nhiều vì rất ít tài liệu hay về HAL ngoài kia.

Đây là mã:

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

Tôi cũng đã tạo dự án với CubeMX, cấu hình adc như sau: nhập mô tả hình ảnh ở đây

EDIT 1
Tôi đã cố gắng gỡ lỗi mọi thứ và có vẻ như chương trình bị kẹt khi kiểm tra cờ EOC - nó thấy rằng nó không được hiển thị và do đó vấn đề hẹn giờ chờ EOC xuất hiện (nhưng nó không bao giờ được đặt) Đây là mã nơi nó bị mắc kẹt trong trình gỡ lỗi:

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

Câu trả lời:


6

Trong mã gốc của bạn, đặt Kết thúc lựa chọn chuyển đổi thành bị tắt.

 hadc1.Init.EOCSelection = DISABLE;

Hóa ra #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)giá trị đó bằng DISABLE. Vì vậy, thực sự EOCSelection nên được cấu hình là: để có thể thăm dò ADC nhiều lần.nhập mô tả hình ảnh ở đây

Sau đó, bạn có thể đọc ADC liên tục mà không dừng lại và khởi động 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);
        }
    }
}

Bằng cách này, nó làm việc tốt cho tôi.

Vì HAL là một thư viện khá mới, không có nhiều tài nguyên để tìm nhưng không phải là không thể. Tôi đã học được rất nhiều từ hướng dẫn này , nó chứng minh tất cả các cách sử dụng ADC có thể từng bước; từ bỏ phiếu đơn giản, đến sử dụng ngắt và DMA.


hm ... vô hiệu hóa EOCSelection làm cho nó hoạt động, nhưng từ định nghĩa của nó nói - Chỉ định xem cờ EOC được đặt ở cuối chuyển đổi kênh đơn hay ở cuối tất cả các chuyển đổi. Vô hiệu hóa điều này không giúp ích theo định nghĩa .. nhưng nó giúp .... khó hiểu. Bạn có biết tại sao chính xác vô hiệu hóa điều này làm cho nó hoạt động? dù sao cũng cảm ơn câu trả lời
ScienceSamovar

Tôi cũng đang học HAL, vì vậy tôi chưa biết lý do. Nó chỉ là một kinh nghiệm. Tôi thấy rằng HAL có thể được giao tiếp rất nhiều lần.
Bence Kaulics

Tôi đã kiểm tra các giá trị xác định và giá trị #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)tương tự như bị vô hiệu hóa, vì vậy thực sự bị vô hiệu hóa là ADC_EOC_SEQ_CONV.
Bence Kaulics

1
oh, ok, vì vậy nó không bị vô hiệu hóa theo nghĩa đen. Điều này có ý nghĩa, trước đây nó là ADC_EOC_SINGLE_CONV, có lẽ chỉ có nghĩa là - nó chuyển đổi chỉ một lần và ADC_EOC_SEQ_CONV là chuyển đổi liên tục. Thêm một bí ẩn nữa đã được giải đáp :) Cảm ơn!
ScienceSamovar

Vâng, đó nên là trường hợp. :)
Bence Kaulics

2

Hừm ... Tôi đã tìm thấy một vài hướng dẫn sử dụng HAL_ADC_Stop (& hadc1) để kết thúc sự hội tụ ... Tôi đã xem các hướng dẫn này trước đây và nghĩ rằng đây là cách khá dã man, có vẻ như nó vô hiệu hóa ADC hoàn toàn, vì vậy tôi mặc dù nên có phương pháp khác nhau. Nhưng có vẻ như, điều này thực sự hoạt động tốt.
Hãy hoan nghênh đăng câu trả lời nếu có cách làm thanh lịch hơn, vì tôi nghĩ rằng việc sử dụng HAL_ADC_Stop () là khá khủng khiếp, nhưng có thể được sử dụng cho mục đích học tập.

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

  }

Xin chào, tôi đã tìm thấy một vấn đề với phương pháp này, nó hạn chế tốc độ mẫu tối đa bạn có thể đạt được bằng RẤT NHIỀU, không nên sử dụng phương pháp này nếu bạn cần chuyển đổi ADC nhanh.
Richard Bamford

2

Tôi muốn thêm rằng cho thiết lập của tôi (nucleo-h743), nó không đủ để thiết lập:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

Tôi cũng phải kích hoạt cài đặt vượt mức:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

Không có điều này, HAL_ADC_PollForConversion vẫn bị chặn. Tôi không hoàn toàn hiểu tại sao điều này là cần thiết nhưng nó cho phép tôi thăm dò ý kiến ​​trong chế độ liên tục.


0

Điều này làm việc cho tôi, hy vọng nó sẽ giúp:

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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.