CETut – Part 8: Timer – PWM Mode

Trong bài viết này chúng ta sẽ tìm hiểu thêm về cách điều khiển xung qua chế độ PWM của timer. Kèm theo đó, chúng ta sẽ ứng dụng kỹ thuật lập trình PWM trên vi điều khiển STM32 điều khiển tốc của một motor, một trong những bước đầu trong lập trình robotics
Share

Trong bài viết này chúng ta sẽ tìm hiểu thêm về cách điều khiển xung qua chế độ PWM của timer. Kèm theo đó, chúng ta sẽ ứng dụng kỹ thuật lập trình PWM trên vi điều khiển STM32 điều khiển tốc của một motor, một trong những bước đầu trong lập trình robotics

1. Giới thiệu về xung PWM

PWM là viết tắt của Pulse Width Modulation, là một kỹ thuật điều chỉnh độ rộng xung (duty cycle) của một tín hiệu xung để điều chỉnh công suất hoặc độ chính xác của một hệ thống điện tử. Trong PWM, tần số của xung thường được giữ không đổi, nhưng tỷ lệ thời gian mà xung ở mức cao so với tổng thời gian của chu kỳ xung (cycle time) có thể được điều chỉnh.

Ứng dụng của PWM:
Phương pháp băm xung PWM thường được sử dụng để điều khiển băm xung, điều khiển tốc độ động cơ, các bộ điều áp, xung áp,…

Số lượng kênh pwm của stm32

Trên STM32F103C8T6 các chân timer đều có khả năng tạo xung PWM với mỗi timer gồm 4 channel

2. Những thanh ghi và giá trị quan trọng

Trong STM32, hai thanh ghi quan trọng liên quan đến việc cấu hình chế độ PWM của timer là CCR (Capture/Compare Register) và ARR (Auto-Reload Register):

a. CCR (Capture/Compare Register):

  • Thanh ghi CCR được sử dụng để cài đặt giá trị so sánh cho chế độ Capture và Compare của timer.
  • Trong chế độ PWM, giá trị trong thanh ghi CCR xác định thời điểm mà PWM chuyển từ trạng thái thấp (low) sang trạng thái cao (high) hoặc ngược lại.
  • Có thể cấu hình nhiều thanh ghi CCR cho các kênh PWM khác nhau của cùng một timer.

b. ARR (Auto-Reload Register):

  • Thanh ghi ARR chứa giá trị tối đa của bộ đếm của timer.
  • Trong chế độ PWM, giá trị trong thanh ghi ARR xác định chu kỳ của PWM, tức là thời gian mà timer sẽ đếm từ 0 đến giá trị tối đa trước khi quay lại 0.
  • Khi giá trị bộ đếm đạt đến giá trị trong thanh ghi ARR, timer sẽ tự động reset về 0 và bắt đầu lại quá trình đếm, tạo ra chu kỳ PWM mới.

Công thức để tính được giá trị tương ứng để tạo xung PWM theo nhu cầu:

3. API và FUNCTION

a. HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)

Tham số:

  • htim: Bộ timer sử dụng chức năng PWM, nếu sử dụng Timer 1 thì sẽ là &htim1,…
  • Channel: Channel đã cấu hình cho PWM, nếu là Channel 1 thì gọi TIM_CHANNEL_1 Ví dụ: Sử dụng Kênh 3 của Timer 3 cho chức năng PWM

Ví dụ:
Sử dụng Kênh 3 của Timer 3 cho chức năng PWM:
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);

b. __HAL_TIM_SET_COMPARE(*htim, Channel, Pulse)

Tham số:

  • htim: Bộ timer sử dụng chức năng PWM, nếu sử dụng Timer 1 thì sẽ là &htim1,…
  • Channel: Channel đã cấu hình cho PWM, nếu là Channel 1 thì gọi TIM_CHANNEL_1
  • Pulse: là độ rộng của xung bạn muốn truyền
Ví dụ: Sử dụng Channel 3 của Timer 3 cho chức năng PWM với pulse = 500 
__HAL_TIM_SET_COMPARE (&htim3,TIM_CHANNEL_3,500);

c. HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)

Hàm này khởi động PWM bằng cách sử dụng ngắt.

Tham số:

  • htim: Bộ timer sử dụng chức năng PWM, nếu sử dụng Timer 1 thì sẽ là &htim1,…
  • Channel: Channel đã cấu hình cho PWM, nếu là Channel 1 thì gọi TIM_CHANNEL_1

d. HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)

Hàm callback này được gọi mỗi khi một xung PWM hoàn thành (tức là, khi ngắt của PWM được kích hoạt). Đây là nơi bạn có thể xử lý sự kiện hoàn thành của xung PWM, chẳng hạn như tính toán tần số mới, thay đổi chiều dài xung, hoặc thực hiện các nhiệm vụ khác dựa trên sự kiện này.

4. Thực hành

a. Linh Kiện

Các linh kiện được sử dụng:

  • Chúng ta không thể sử dụng xung để điều khiển động cơ một cách trực tiếp được, vì vậy chúng ta sẽ sử dụng mạch cầu H để điều khiển và cấp nguồn 5v cho động cơ thông qua mạch cầu H này.
  • Điện trở dùng để hạn dòng để tránh những tình huống chập cháy
  • Nút nhấn dùng để điều chỉnh các Mode của động cơ. Những mode này sẽ được thiết lập trong phần code bên dưới. Chúng ta có thể sử dụng nút nhấn 2 chân vẫn được.
  • Và không thể thiếu là testboard và bẹ dây.

b. Set up

Bước 1: Cấu hình các chân, đầu tiên chúng ta sẽ setup trong System Core → SYS. Ở mục Debug, ta chọn Serial Wire. Vì chúng ta dùng ST-Link để flash code nên đây là bước cần thiết để khi flash những lần sau không bị lỗi.

Bước 2: Chúng ta sẽ xem và config giá trị xung clock của Timer. Timer 2,3,4 sẽ dùng của mục APB2 nên ta chỉ quan tâm phần này. Ta thấy xung clock có giá trị là 8MHz.

  • Tiếp đến, sẽ config những thông số của Timer 2, ở đây ta chọn Channel 2 làm chân cấp xung PWM.
  • Có 2 thông số ta nên quan tâm là prescaler và counter. Ta có thể set 2 thông số này theo ý thích, miễn sao cho F(timer) ≥ 100 Hz (phù hợp với datasheet của TB6612).
  • Ở đây có 1 lưu ý nhỏ, giới hạn counter chính là giới hạn của độ rộng xung. Nếu ta set counter = 999 thì Pulse sẽ không thể vượt quá con số này. Tức là khi Pulse = 999 thì Duty cycle = 100%

Bước 3: Kế tiếp chúng ta sẽ set chân GPIO Output theo kiến thức của bài trước. Tên các chân được đặc theo chức năng của nó.

Kết quả cuối cùng:

Sơ đồ kết nối chân:

Chúng ta sẽ chia phần linh kiện đã chuẩn bị phía trên thành 4 phần chính như hình:

  • Nút nhấn: Ta sẽ kết nối một đầu nút nhấn (1) vào chân GPIO Input (Button) và đầu còn lại (4) vào chân GND. Nhìn hình ta có thể thấy, khi ta nhấn nút, chân 1 và 4, 2 và 3 sẽ được nối với nhau. Những chân 1 và 2, 3 và 4 được nối với nhau dù không có nhấn. Nên các bạn nhớ mắc so le các chân nút nhấn.
  • Cầu H: Ở đây là mạch điều khiển động cơ TB6612. Ta kết nối chân theo tên các cân chức năng được đặc tên sẵn. Chúng ta sẽ cấp nguồn 5V và chân Vm. Chân này có tác dụng cấp nguồn cho động cơ không phụ thuộc vào điện áp cấp vào chân Vcc.
  • Động cơ: Ta nối 2 chân Out_A của TB6612 vào 2 đầu của động cơ (muốn nối vào động cơ theo hướng nào cũng được, không cần lo âm, dương). Lưu ý nhỏ, chúng ta cấp xung vào chân PWA và cân A_IN nên theo datasheet của TB6612, nên chân Out sẽ là Out_A, nếu nối sai sẽ không có điện để động cơ hoạt động và theo bảng điều khiển (ở phần giải thuật) thì chân STBY phải ở mức cao, đó là lý do nó được nối với nguồn 3V3.
  • Và cuối cùng là STM32F103C8T6 chúng ta kết nối như bên dưới.

c. Code

Bước 1: Chúng ta sẽ đặt 3 mode cho động cơ, những mode này đặt chỉ để biểu thị pulse thông qua các mode:

typedef enum
{
	Mode1 = 350,
	Mode2 = 700,
	Mode3 = 999,
	Stop = 0
}Mode;

Bước 2: Chúng ta sẽ bật timer với chế độ PWM và các chân GPIO như hình bên dưới:

  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
  HAL_GPIO_WritePin(GPIOA, AIN1_Pin, 1);
  HAL_GPIO_WritePin(GPIOA, AIN2_Pin, 0);
  /* USER CODE END 2 */
  • Để bật chế độ PWM ta sử dụng hàm HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_X)
  • Set chân AIN1 và AIN2 lần lượt là 1 và 0 để điều khiển động cơ quay về phía trước. Nhìn bảng điều khiển dưới đây

Bước 3: Chúng ta sẽ code trong hàm While như hình bên dưới:

 /* USER CODE BEGIN WHILE */
  while (1)
  {
	  if(HAL_GPIO_ReadPin(GPIOA, Button_Pin) == GPIO_PIN_RESET)
	  {
		  countMode++;
		  if(countMode > 3){
			  countMode = 0;
		  }
		  switch(countMode)
			  {
			  case 1:
				  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, Mode1);
				  break;
			  case 2:
				  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, Mode2);
				  break;
			  case 3:
				  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, Mode3);
				  break;
			  default:
				  __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, Stop);
				  break;
			  }
	    }
	  HAL_Delay(300);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

Giải thích code

  • Vòng lặp vô hạn (while (1)):Chương trình bắt đầu bằng một vòng lặp vô hạn, tức là nó sẽ thực hiện mã lệnh bên trong vô hạn lần.
  • Điều kiện kiểm tra chân GPIO (HAL_GPIO_ReadPin(GPIOA, Button_Pin) == GPIO_PIN_RESET)):
    • Chương trình kiểm tra trạng thái của chân Button_Pin. Nếu chân này ở trạng thái LOW (GPIO_PIN_RESET) tức là nút nhấn đã được nhấn, biến countMode sẽ được tăng lên.
    • Nếu countMode vượt quá giá trị 3, nó sẽ được đặt lại về 0. Mục để là để tạo tuần hoàn cho các mode, các bạn có thể thay bằng chia lấy phần dư cũng được.
  • Câu lệnh switch-case dùng để xem biến countMode đang ở chế độ nào:
    • Dựa vào giá trị của biến countMode , chúng ta sẽ thay đổi độ rộng xung của timer tùy theo mode mà chúng ta cài đặt.
  • Hàm delay(300) ở dưới giúp chống dội nút nhấn:
    • Khi ta nhấn nút, nút nhấn sẽ có 1 khoảng giao động trạng thái ở chính giữa. Do vi điều khiển của chúng ta xử lý những câu lệnh rất nhanh. Nên sẽ đọc nhầm những trạng thái giao động không mong muốn này của nút nhấn (bị nhiễu).
    • Có nhiều cách chống dộinút nhấn nhưng trong bài này sẽ sử dụng cách đơn giản nhất là bỏ qua khoảng nhiễu ấy bằng hàm Delay. Và số 300 là trạng thái ước lượng.

d. Video demo