star twitter facebook envelope linkedin youtube alert-red alert home left-quote chevron hamburger minus plus search triangle x

Bài 7: Input capture & output compare mode


I. Lý thuyết

1.  Output compare mode:

Ở chế độ này, timer sẽ điều khiển xung đầu ra hoặc cho ta biết khi nào một khoảng thời gian trôi qua.

Nguyên lý hoạt động:

 

 

·       Ở đây ta thấy CNT là thanh ghi chứa giá trị đếm của timer, và khi timer đếm tới giá trị được định sẵn trong thanh ghi CCRx (ví dụ timer1 sẽ là CCR1) thì xung đầu ra sẽ đảo mức logic.

·       Và vì như vậy khi ta giữ nguyên giá trị trong thanh ghi CCRx thì mọi xung ở output compare mode đều có duty cycle = 50%, duy chỉ khác nhau tần số xung.

·       Được ứng dụng để tạo ra xung bất kỳ, không theo 1 tần số nhất định.

 

2. Input capture mode:

Ở chế độ này, timer sẽ bắt sự kiện xung từ bên ngoài vào, cụ thể là bắt sườn lên hoặc sườn xuống của xung.

Nguyên lý hoạt động:

 

 

·       Nó hoạt động ngược lại với output compare mode, ở output compare, khi timer đếm đến giá trị định sẵn thì đảo logic xung, còn ở chế độ này, thanh ghi CCRx sẽ lưu giá trị đếm của timer (trong thanh ghi CNT) khi bắt được xung sườn lên hoặc sườn xuống.

·       Vì thế nó được ứng dụng trong việc đo tần số xung, độ rộng xung, …

II. Ví dụ

 

1. Output compare mode:

Ở ví dụ này ta sẽ dùng mode output compare để thay đổi tần số xung xuất ra, áp dụng làm tăng delay nháy led.

Bước 1: Tạo project trên CubeMx (Debug, Clock …), cấu hình APB = 60Mhz.

 

 

Bước 2: Vào timer 3, chọn Output compare cho channel 4, kích hoạt ngắt với mức ưu tiên chính = 2.

 

 

Bước 3: Cấu hình giá trị đếm:

·       PSC = 60000 => tần số timer = 1khz

·       Counter Period = 65535

·       Ở mục Mode chọn Toggle on match.

·       Chọn Pulse = 100.

 

 

Bước 4: cắm mạch theo sơ đồ dưới đây.

 

 

Bước 5: đặt tên project và Gencode

 

2. Lập trình trên Keil C:

Bước 1: Khởi động timer mode output compare ở chế độ ngắt.

Uint16_t capture = 0;

int main(void)
{
 HAL_Init();
 SystemClock_Config();
 MX_GPIO_Init();
 MX_TIM1_Init();
 MX_TIM3_Init();
 // khởi động output compare mode
 HAL_TIM_OC_Start_IT(&htim3, TIM_CHANNEL_4);
 while (1)
 {
 }
}

Bước 2: Thay đổi Giá trị Pulse và reset counter trong hàm xử lý ngắt.

void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
   if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
   {
       capture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);
       __HAL_TIM_SetCompare(htim, TIM_CHANNEL_4, (capture + 100));
       __HAL_TIM_SET_COUNTER(htim, 0);
   }
}

 

Bước 3: Nạp code và xem thành quả. Xung ban đầu kéo dài 100ms, xung tiếp theo sẽ 200ms nhưng với mức logic đảo với xung trước đó, cứ như vậy thì ta đã tạo ra 1 xung không theo 1 chu kỳ nhất định.

 

3. Giải thích các hàm sử dụng trong ví dụ:

  HAL_StatusTypeDef HAL_TIM_OC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)

Khởi động timer mode output compare ở chế độ ngắt.

Tham số:

·       htim: trỏ đến timer được start (&htim1 -> &htim4).

·       Channel: kênh timer, ở STM32F1 mỗi timer sẽ có kênh (TIM_CHANNEL_1 -> TIM_CHANNEL_4).

 

  void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)

Hàm xử lý khi xảy ra sự kiện ngắt output compare

Tham số:

·       htim: trỏ đến timer gây ra ngắt.

 

  uint32_t HAL_TIM_ReadCapturedValue(TIM_HandleTypeDef *htim, uint32_t Channel)

Hàm trả về giá trị của thanh ghi CCRx.

Tham số:

·       htim: trỏ đến timer cần đọc giá trị.

·       Channel: kênh timer.

 

  __HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__).

Set giá trị cho thanh ghi CCRx.

Tham số:

·       __HANDLE__: trỏ đến timer cần set.

·       __CHANNEL__: kênh của timer đó.

·       __COMPARE__: giá trị cần set.

 

  __HAL_TIM_SET_COUNTER(__HANDLE__, __COUNTER__)

Set giá trị cho thanh ghi CNT.

Tham số:

·       __HANDLE__: trỏ đến timer cần set.

·       __COUNTER__: giá trị cần set.

 

4. Input capture Mode

Ở ví dụ này ta sẽ dùng 1 con STM32 đo khoảng thời gian giữa 2 lần bấm nút (khoảng cách giữa 2 lần bấm không quá lâu.)

Bước 1: Tạo project trên CubeMx (Debug, Clock …). Chọn Clock 60Mhz cho APB

Bước 2: Vào timer 1, chọn input capture direct mode cho channel 4, Kích hoạt capture compare interrupt. Chọn mức ưu tiên = 2.

 

 

Bước 3: Cấu hình input capture mode:

·       Chọn PSC = 60000 => tần số timer = 1kHz vậy chu kì là 1ms.

·       Giá trị counter để max 65535 ~ 65536ms.

·       Chọn Polarity Selection: Falling bắt sườn xuống, vì nút nhất ta nối GND.

 

 

Bước 4: Nối dây theo sơ đồ sau:

 

 

Bước 5: Đặt tên Project và GenCode.

 

5. Lập trình trên Keil C.

Bước 1: Khởi động timer mode input capture ở chế độ ngắt.

uint32_t IC_Val1 = 0;
uint32_t IC_Val2 = 0;
uint32_t Difference = 0;
uint8_t Is_First_Captured = 0;

int main(void)
{
 HAL_Init();
 SystemClock_Config();
 MX_GPIO_Init();
 MX_TIM1_Init();
 MX_TIM3_Init();
 // khởi động timer input capture mode ở chế độ ngắt
 HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_4);
 while (1)
 {
 }
}

Bước 2: Đọc khoảng thời gian bấm nút trong hàm xử lý ngắt.

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
//kiểm tra kênh gây ra ngắt
   if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4) 
   {
// kiếm tra xem có phải lần lấy mẫu đầu tiên
       if (Is_First_Captured==0) 
       {
// lưu giá trị thời gian của lần lấy mẫu đầu
           IC_Val1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4); 
           Is_First_Captured = 1; 
       }
// kiếm tra xem có phải lần lấy mẫu thứ 2
       else if (Is_First_Captured==1)  
       {
// lưu giá trị thời gian của lần lấy mẫu thứ 2
           IC_Val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4); 
           __HAL_TIM_SET_COUNTER(htim, 0); // reset the counter
           if(IC_Val2 > IC_Val1)
           {
// Thời gian giữa 2 lần bấm nút
               Difference = IC_Val2-IC_Val1;
           }
           Is_First_Captured = 0;
       }
   }
}

 

Bước 3: Nạp code và xem thành quả. Nhấn nút kết hợp với xem khoảng thời gian nhấn nút ở chế độ Debug, vì ta đã set chu kỳ đếm là 1ms, nên kết quả ta thấy trong chế độ debug cũng chính là khoảng thời gian bấm nút (đơn vị ms).

 

 

6. Giải thích các hàm sử dụng trong ví dụ:

  HAL_StatusTypeDef HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)

Khởi động timer mode input capture ở chế độ ngắt.

Tham số:

·       htim: trỏ đến timer được start (&htim1 -> &htim4).

·       Channel: kênh timer, ở STM32F1 mỗi timer sẽ có kênh (TIM_CHANNEL_1 -> TIM_CHANNEL_4).

 

  void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)

Hàm xử lý khi có ngắt (khi bắt được sườn của xung).

Tham số:

·       htim: trỏ đến timer được start (&htim1 -> &htim4).

Nguồn :https://deviot.vn/