การแปลง ADC STM32 โดยใช้ HAL


10

ฉันพยายามเรียนรู้วิธีใช้ไลบรารี่ HAL "ใหม่" จาก stm32
เมื่อฉันพยายามแปลง ADC อย่างง่ายมันใช้งานได้เพียงครั้งเดียว แต่ก็หยุดการแปลง ฉันคิดว่าไม่ได้ตั้งค่าสิ้นสุดการแปลง ฉันกำลังใช้บอร์ดค้นพบ STM32f429I ซึ่งมีบอร์ด STM32f429ZI อยู่
โปรดทราบว่าฉันรู้ว่า sprintf เป็นการฝึกที่ไม่ดีและการทำ adc ด้วยการขัดจังหวะนั้นดีกว่าฉันรู้ว่าโปรดอย่าชี้ให้เห็นว่านี่ไม่เกี่ยวข้องกับคำถามฉันแค่ทดสอบ HAL ที่นี่
ดังนั้นคำถามคือทำไมไม่ตั้งค่าสถานะ EOC หรือฉันต้องทำอย่างไรเพื่อให้ใช้งานได้ Googling ไม่ได้ช่วยอะไรมากมายเนื่องจากมีเนื้อหาที่ดีเกี่ยวกับ 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;
      }
    }

คำตอบ:


6

ในรหัสดั้งเดิมของคุณตั้งค่าการสิ้นสุดการเลือกการแปลงเป็นปิดใช้งาน

 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


หืมม ... การปิดใช้งาน EOCSelection ทำให้ใช้งานได้ แต่จากคำจำกัดความที่ระบุ - ระบุว่าตั้งค่าสถานะ EOC ไว้ที่ส่วนท้ายของการแปลงแชนเนลเดียวหรือเมื่อสิ้นสุดการแปลงทั้งหมด การปิดใช้งานนี้ไม่ควรช่วยตามคำจำกัดความ .. แต่ช่วย .... ทำให้สับสน คุณรู้หรือไม่ว่าทำไมการปิดใช้งานสิ่งนี้จึงทำให้ทำงานได้ ขอบคุณสำหรับคำตอบต่อไป
ScienceSamovar

ฉันแค่เรียนรู้ HAL ด้วยดังนั้นฉันยังไม่รู้เหตุผล มันเป็นเพียงประสบการณ์ ฉันพบว่า HAL สามารถให้รางวัลได้หลายครั้ง
Bence Kaulics

ฉันได้ตรวจสอบค่ากำหนดและ#define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)เหมือนกันว่าเป็นคนพิการดังนั้นคนพิการจริง ๆ แล้วคือ ADC_EOC_SEQ_CONV
Bence Kaulics

1
โอ้ตกลงดังนั้นจึงไม่ได้ปิดใช้งานอย่างแท้จริง มันสมเหตุสมผลแล้วก่อนหน้านี้คือ ADC_EOC_SINGLE_CONV ซึ่งอาจหมายถึงเพียงแค่นั้น - มันแปลงเพียงครั้งเดียวและ ADC_EOC_SEQ_CONV เป็นการแปลงอย่างต่อเนื่อง แก้ปริศนาอีกหนึ่งข้อแล้ว :) ขอบคุณ!
ScienceSamovar

ใช่ว่าควรเป็นกรณี :)
Bence Kaulics

2

หืมมม ... ฉันพบบทเรียนที่ใช้ 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);

  }

สวัสดีฉันพบปัญหากับวิธีนี้มัน จำกัด อัตราตัวอย่างสูงสุดที่คุณสามารถทำได้โดย A LOT ไม่แนะนำให้ใช้วิธีนี้หากคุณต้องการแปลง ADC อย่างรวดเร็ว
Richard Bamford

2

ฉันต้องการเพิ่มสิ่งนั้นสำหรับการตั้งค่าของฉัน (nucleo-h743) มันไม่เพียงพอที่จะตั้งค่า:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

ฉันต้องเปิดใช้งานการตั้งค่า overrun ด้วย:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

หากไม่มีสิ่งนี้ HAL_ADC_PollForConversion ยังคงปิดกั้น ฉันไม่เข้าใจว่าทำไมสิ่งนี้ถึงมีความจำเป็น แต่มันทำให้ฉันสามารถสำรวจในโหมดต่อเนื่อง


0

มันใช้งานได้สำหรับฉันหวังว่ามันจะช่วย:

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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.