Đọc ADC trong timer STM32F411

HAL_TIM_Base_Start_IT(&htim2);
 HAL_ADC_Start(&hadc1);

  while (1)
  {

  }
  /* USER CODE END 3 */
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM2)
	{
		if(flag++ == 10)
		{
			value = HAL_ADC_GetValue(&hadc1);
			flag = 0;
		}
	}
}

Mình muốn đọc ADC sau 10s nhưng giá trị value không được cập nhật . Đã chọn Continuous conversion mod . Mọi người xem giúp e với ạ

Hướng dẫn debug:

  • Tình huống: đọc ADC sau 10s nhưng giá trị value không được cập nhật
  • Tự đặt câu hỏi:
    1. Timer đã chạy đúng 10s hay chưa? Làm sao để biết timer đúng 10s?
    2. Tại sao value không được cập nhật?
    • 2.1 Sau 10s thì hàm xử lý có được gọi hay không?
      • 2.1.1 Nếu hàm được gọi -> Hàm lấy giá trị có vấn đề gì? …
        - ADC có bao nhiêu mode, các mode khác nhau như thế nào?
        - Làm sao biết được ADC trả về đúng hay chưa?
      • 2.1.2 Nếu hàm không được gọi -> Hàm thời gian có vấn đề gì? …
        - Config thời gian như thế nào?
        - Config callback như thế nào?
  • Giải quyết vấn đề: Là quá trình tìm ra câu trả lời cho các câu hỏi trên.
2 Likes

1 . Mình tạo timer ngắt sau mỗi 1s và dùng flag check 10s , Theo dõi flag trong cửa sổ live expression
2. Mình đã bật mode này . hadc1.Init.ContinuousConvMode = ENABLE; để chuyển đổi liên tục .
3 Mình để câu lệnh value = HAL_ADC_GetValue(&hadc1); trong while(1) thì dữ liệu được cập nhật liên tục
Nhưng khi đưa vào ngắt TIM2 thì không được hàm không trả về . Đưa thêm HAL_ADC_Start vào TIM2 thì đọc được ADC . bạn giải thích thêm cho mình phần này tại sao được không

Bạn có thể post code config ADC của bạn lên được không?

1 Like

Advise: Bạn nên đưa đầy đủ thông tin câu hỏi ngay từ lúc đầu để mình đánh giá được level của bạn và không đi sâu vào các basic questions như ở trên.

Mình vừa đọc thử User Manual của STM32 tại: https://www.st.com/resource/en/reference_manual/dm00119316-stm32f411xc-e-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf

Theo thông tin trong này thì module ADC cần thời gian để lấy mẫu và convert kết quả qua giá trị có thể đọc được. Như vậy, để có thể có được kết quả chính xác trong Interrupt timer, thì bạn cần:

  • Kiểm tra EOC (end of conversion) flag bằng while loop với timeout.
  • Hoặc gọi hàm polling HAL_ADC_PollForConversion

Theo mình nhận định thì interrupt Timer của bạn có thể rơi vào thời điểm mà ADC chưa convert xong nên không đọc được giá trị chính xác.

Một cách tiếp cận hiệu quả hơn là sử dụng interrupt ADC, khi có cập nhật giá trị mới thì interrupt sẽ lưu giá trị vào 1 biến hoặc 1 mảng và cập nhật ở đó. Interrupt timer sẽ đọc latest value của biến hoặc mảng trên và trả về giá trị ngay lập tức thay vì polling.

2 Likes

Vậy mình muốn sau 30s hoặc 1 phút mới đọc ADC thì interrupt timer khả thi hơn đúng k nhỉ .

Không phải ý như vậy. Thời gian ADC conversation rất ngắn.
image

Nhưng thời điểm bạn đọc rơi vào conversion time thì sẽ không có kể quả.

1 Like

Theo mình nhận định thì bạn có thể trực tiếp Start và đợi kết quả trong timer interrupt ở Single mode.
Hoặc dùng interupt ADC ở continuous mode để lưu kết quả.

Đó là 2 cách sử dụng mà mình thấy hợp lý sau khi đọc User Manual.

Chú ý cuối cùng là do bạn không post code config lên nên mình không biết là bạn có rơi vào trường hợp này không: ``

Injected channels cannot be converted continuously. The only exception is when an injected channel is configured to be converted automatically after regular channels in continuous mode (using JAUTO bit), refer to Auto-injection section).

2 Likes

Theo mình thấy thì hàm HAL_ADC_GetValue() không clear cờ EOC . Đây là cờ bắt buộc cần clear để tiếp tục ADC conversion.
Không có đặc tả nào cho thấy Continuous conversion mode sẽ tự clear cờ này. Do đó đây cũng có thể là nguyên nhân bạn không đọc được giá trị.
Bạn cần tự clear hoặc gọi HAL_ADC_PollForConversion
hoặc HAL_ADC_PollForEvent
để clear nó.

Mình đã chỉ ra tất cả các trường hợp mà mình nhìn thấy. Bạn có thể thử nghiệm tự tìm ra đáp án sau cùng, vì mình không có thiết bị cũng không muốn làm giúp bạn phần kết này. Chúc bạn may mắn.

PS. Nếu bạn có lòng thì sau khi tìm ra đáp án hãy feedback để những người khác có thể tham khảo.

4 Likes

Đúng như bạn dự đoán là mình đã đọc ADC khi chưa conversion xong . Và mình đã fix code trên bằng cách này .

if(flag++ == 10)
{
	flag = 0;
	if(ADC1->SR & (1 << 1))
	{
		value = HAL_ADC_GetValue(&hadc1);
	}
}

Cảm ơn bạn rất nhiều . Mình đã test hết trường hợp bạn đưa và tìm ra cách hợp lý nhất cho yêu cầu của mình là gọi hàm HAL_ADC_PollForConversion trong timer interrupt . Cam ơn bạn nhiều

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?