Bài 3: Lập trình ADC STM32

1.ADC là gì

ADC (Analog to Digital Convert) là bộ chuyển đổi tương tự sang số. Điện áp Vin được so sánh với điện áp mẫu Vref (giá trị lớn nhất), sau đó được chuyển đổi thành số .

Giả sử ta cần đo điện áp tối thiểu là 0V và tối đa là 3.3V, trong STM32 điện áp 0 → 3.3V sẽ thành 0 → 4095 khoảng giá trị (do 2^12= 4096), giá trị đo được từ chân IO 0V sẽ là 0, tương ứng với 1.65V là 2047, 3.3V sẽ là 4095.

Các mode hoạt động của ADC:

Single conversion mode: Trong chế độ này, ADC sẽ chỉ thực hiện 1 chuyển đổi cho tới khi người dùng cho phép chuyển đổi tiếp.

Continuous Conversion Mode: Ở chế độ này, ADC sẽ ngay lập tức thực hiện 1 chuyển đổi khác khi chuyển đổi trước vừa kết thúc.

Scan Mode: Chế độ này được sử dụng để quét 1 nhóm các kênh. 1 chuyển đổi duy nhất được thực hiện cho mỗi kênh. Sau khi 1 kênh chuyển đổi xong, kênh tiếp theo sẽ tự động chuyển đổi.

2.Tạo project và cấu hình

Phần tạo project các bạn tham khảo lại bài 2 phần GPIO nhé.

Ở bước tạo project ở bài 2 thì mình sẽ sửa tên lại là “stm32f1-adc-scan-mode” cho bài hướng dẫn hôm nay. Bây giờ mình sẽ bắt đầu:

Mình sẽ dùng chân PC0 có chức năng ADC1_IN10 để đọc ADC giống như sơ đồ nguyên lý dưới

Bước 1: Cấu hình xung clock

Clock Configuration->HCLK . Ở đây mình dùng thach anh nội 8Mhz. Mình sẽ cấu hình chip chạy tốc độ 36Mhz như hình bên dưới bằng cách edit vào ô HCLK sau đó enter phần mềm sẽ tự tính toán phần còn lại cho bạn. Nếu bạn cấu hình vượt quá giới hạn của thạch anh nội 8Mhz phần mềm sẽ báo lỗi.

Bước 2: Cấu hình mạch nạp

System Core→SYS→Debug->Serial Wire

Bước 3: Cấu hình ADC

Click phải chân PC0→ADC1_IN10

Sơ bộ cấu hình cho 1 kênh:

Num of Conversion: 1 (Nếu 1 kênh Scan Conversion mặc định là Disable)

Scan Conversion: Disable

Continuous Conversion Mode: Disable

Rank : Chọn thêm Chanel x, Chọn chu kì lấy mẫu cho mỗi Chanel tại Samping Time

Rank là thứ tự chuyển đổi, cao nhất là 1 lớn nhất là 10, bộ ADC sẽ Scan từ kênh có Rank là 1 đến n với n là số kênh các bạn cần chuyển đổi.

Sau đó chọn Project → Build All để build project

3.Viết code

Một số hàm liên quan đến ADC:

– HAL_ADC_Start(ADC_HandleTypeDef* hadc): cho phép ADC bắt đầu chuyển đổi

– HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout): polling chờ cho chuyển đổi hoàn tất với thời gian timeout.

– HAL_ADC_GetValue(ADC_HandleTypeDef* hadc): trả về giá trị adc của con trỏ hadc.

– HAL_ADC_Stop(ADC_HandleTypeDef* hadc): stop chuyển đổi adc.

Dưới đây là đoạn code chương trình đọc ADC 1 kênh:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint32_t ADC_VAL;
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC1_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	HAL_ADC_Start(&hadc1);
	HAL_ADC_PollForConversion(&hadc1, 1000);
	ADC_VAL = HAL_ADC_GetValue(&hadc1);
	HAL_ADC_Stop(&hadc1);
	HAL_Delay(100);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

Các bạn build và debug thử vào chip của mình

(1)Run→Debug

(2) Vào tab Live Expressions

(3) Add biến ADC_VAL để xem giá trị adc trực tiếp

Note: Biến ADC_VAL phải là biến global mới có thể xem trực tiếp

Bây giờ chúng ta sẽ chỉnh sửa để đọc ADC 2 kênh chế độ Scan mode nhé:

Mở lại file cấu hình và chỉnh sửa:

(1) Click chuột phải vào PC1 chọn thêm ADC1_IN11

(2) Mở tab ADC

(2) Cấu hình :

Scan Conversion Mode :Enable

Continuous Conversion Mode : Enable(cho phép tiếp tục chuyển dổi)

Number Of Conversion :2 (vì mình đang dùng 2 kênh)

Rank1:

channel 10

Sampling Time : 1.5 Cycles

Rank1:

channel 11

Sampling Time : 1.5 Cycles

Sau đó chúng ta sẽ viết 2 hàm chuyển đổi kênh để sử dụng khi chuyển kênh:

void ADC_Select_CH10 (void)
{
 ADC_ChannelConfTypeDef sConfig = {0};
 sConfig.Channel = ADC_CHANNEL_10;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
   Error_Handler();
 }
}
void ADC_Select_CH11 (void)
{
 ADC_ChannelConfTypeDef sConfig = {0};
 sConfig.Channel = ADC_CHANNEL_11;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
   Error_Handler();
 }
}

Đây là chương trình chính:

  while (1)
  {
	ADC_Select_CH10();
	HAL_ADC_Start(&hadc1);
	HAL_ADC_PollForConversion(&hadc1, 1000);
	ADC_VAL = HAL_ADC_GetValue(&hadc1);
	HAL_ADC_Stop(&hadc1);
	HAL_Delay(100);
	ADC_Select_CH11();
	HAL_ADC_Start(&hadc1);
	HAL_ADC_PollForConversion(&hadc1, 1000);
	ADC_VAL2 = HAL_ADC_GetValue(&hadc1);
	HAL_ADC_Stop(&hadc1);
	HAL_Delay(100);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

Trong chương trình chính mình sẽ lần lượt thực hiện: cấu hình channel adc→start adc→ đọc adc→ stop rồi thực hiện đọc kênh kế tiếp.

Các bạn chạy debug và xem giá trị 2 biến ADC như hình dưới

Source code tham khảo: https://github.com/maiminhtien94/stm32f1-tut/tree/main/stm32cubeide/stm32f1-adc-scan-mode

Icons made by Freepik from www.flaticon.com