BÀI 3. LẬP TRÌNH CÁC ỨNG DỤNG SỬ DỤNG TIMER, PWM Mục đích. Trang bị cho sinh viên các kiến thức hoạt động định thời, điều chế độ rộng xung trong vi điều khiển ARM STM32. Cách lập trình ứng dụng sử dụng Timer, PWM để thiết kế ứng dụng. Yêu cầu. Sinh viên nắm được: Các nguyên tắc hoạt động của Timer, PWM Cách lập trình một chương trình có sử Timer chế độ tạo xung, chế độ đếm xung và tạo xung PWM.
Trang 1BÀI 3 LẬP TRÌNH CÁC ỨNG DỤNG SỬ DỤNG TIMER, PWM
Mục đích
Trang bị cho sinh viên các kiến thức hoạt động định thời, điều chế độ rộng xung trong
vi điều khiển ARM STM32 Cách lập trình ứng dụng sử dụng Timer, PWM để thiết kế ứng dụng
Yêu cầu
Sinh viên nắm được:
- Các nguyên tắc hoạt động của Timer, PWM
- Cách lập trình một chương trình có sử Timer chế độ tạo xung, chế độ đếm xung và tạo xung PWM
1 Nguyên tắc hoạt động của Timer
- Sơ đồ hoạt động chế độ định thời
Hình 1.1: Sơ đồ khối của Timer1
Trang 2Hình 1.2: Sơ đồ khối của Timer 2, 3, 4
1.1 Hoạt động định thời
Hình 1.2: Timer1,2,3,4 chế độ định thời Hình 1.2 mô tả hoạt động của các timer 1, 2, 3, 4 chế độ định thời: Nguồn xung clock được đưa tới timer từ:
- Nguồn xung từ bên ngoài : ETR hoặc TI1FP1, TI2FP2
- Nguồn xung từ bộ tạo dao động của hệ thống RCC - CK_INT
Nguồn xung clock nói trên sẽ được điều khiển để đưa tới khối chia tần PSC, sau đó tới khối thanh ghi đếm CNT
Với chế độ định thời , giá trị lớn nhất mà các timer chứa được là 65535(tương ứng FFFF(H)), khi đếm quá giá trị này sẽ xảy ra tràn bộ đếm , xảy ra sự kiện ngắt Timer Sau khi xảy ra tràn, nếu muốn timer tiếp tục đếm, chương trình phải có câu lệnh nạp lại giá trị khởi tạo sau khi đã dừng timer
Trang 3Để tạo ra xung hoặc định khoảng thời gian, cần nạp giá trị cho PSC và CNT bằng cách nạp giá trị cho 2 thanh ghi Counter register (TIMx_CNT), Prescaler register (TIMx_PSC),
sử dụng công thức sau:
(Prescaler + 1)(Period + 1)Fout: tần số đầu ra (Hz)
Fclk: tần số đầu vào của Timer (Hz)
Prescaler: giá trị nạp bộ chia tần PSC của Timer (0 ÷ 65535)
Period: giá trị nạp bộ đếm CNT của Timer (0 ÷ 65535)
Ví dụ : Sử dụng Timer 1 tạo xung có tần số Fout = 1KHz Bộ tạo dao động chế độ HSI với Fclk = 8MHz
+ Fout = 1000(Hz) ; Fclk = 8000000(Hz)
+ Xác định giá trị của thanh ghi PSC = Prescaler =0;
+ Xác định giá trị của thanh ghi CNT=Period= (Prescaler + 1)Fclk - 1 = 7999
- Ứng dụng hoạt động định thời:
+ Dùng để tạo thời gian trễ
+ Dùng để tạo tần số
+ Kết hợp với chế độ đếm sự kiện để đo tần số vv…
1.2 Hoạt động đếm sự kiện ( Counter )
- Sơ đồ hoạt động (Hình 1.1; 1.2)
- Nguồn xung từ bên ngoài : ETR1 hoặc TI1FP1, TI2FP2
Hình 1.3: Các khối chức năng trong chế độ lấy nguồn xung bên ngoài
- Nguyên tắc hoạt động
Trang 4 Xung clock sẽ được lấy từ bộ tạo xung bên ngoài qua chân ETR hoặc TI1FP1, TI2FP2
Giá trị đếm được lưu trong thanh ghi CNT
Chú ý: Trong chế độ đếm cần thiết lập giá trị thanh ghi PSC =0
- Ứng dụng hoạt động đếm sự kiện:
+ Dùng để đếm sản phẩm
+ Để đếm người qua lại
+ Kết hợp với chế độ định thời để đo tần số vv…
1.3 Điều chế độ rộng xung PWM
Hình 1.4: Timer1chế độ tạo xung PWM
Hình 1.5: Timer 2,3,4 chế độ tạo xung PWM
Trang 5Hình 1.4; 1.5 mô tả hoạt động của các timer 1, 2, 3, 4 chế độ định thời: Nguồn xung clock được đưa tới timer từ:
- Nguồn xung từ bên ngoài : ETR hoặc TI1FP1, TI2FP2
- Nguồn xung từ bộ tạo dao động của hệ thống RCC - CK_INT
Nguồn xung clock nói trên sẽ được điều khiển để đưa tới khối chia tần PSC, sau đó tới khối Capture/Compare, đưa ra xung trên các kênh TIMx_CH1 ÷ TIMx_CH4 Với chế độ tạo xung PWM mỗi 1 bộ Timer có thể tạo ra 4 kênh PWM
- Để tạo ra chu kỳ xung PWM cần nạp giá trị cho PSC và CNT bằng cách nạp giá trị cho
2 thanh ghi Counter register (TIMx_CNT), Prescaler register (TIMx_PSC), sử dụng công thức sau:
(Prescaler + 1)(Period + 1)Fout: tần số đầu ra (Hz)
Fclk: tần số đầu vào của Timer (Hz)
Prescaler: giá trị nạp bộ chia tần PSC của Timer (0 ÷ 65535)
Period: giá trị nạp bộ đếm CNT của Timer (0 ÷ 65535)
- Tạo độ rộng xung PWM cần nạp giá trị cho thanh ghi TIMx_CCRx, cần sử dụng công thức sau:
D = Period+1 Ton *100%
- D: tỉ lệ xung dương so với chu kì
- Ton: Chu kì xung phần dương của xung PWM (Pulse)
- Period: giá trị nạp bộ đếm của Timer (0 ÷ 65535)
Ví dụ : Sử dụng Timer 1 tạo xung PWM có tần số Fpwm = 1KHz, với Ton= 20%Tpwm
Bộ tạo dao động chế độ HSI với Fosc = Fclk=8MHz
+ Dùng điều khiển tốc độ động cơ
+ Dùng điều khiển sợi đốt
+ Dùng điều khiển động cơ không chổi than vv…
2 THIẾT KẾ ỨNG DỤNG SỬ DỤNG TIMER
Trang 6- Dừng DMA của Timer
- Đọc giá trị thanh ghi đếm 2.1.2 Các bước lập trình với Timer trên STM32CubeMX
Bước 1 Thiết lập hệ thống
- Thiết lập xung nhịp hệ thống : SystemClock_Config()
Bước 2 Thiết lập cho các GPIO
- Cho phép GPIO – AFIO tương ứng hoạt động bằng hàm:
HAL_RCC_GPIOx_CLK_ENABLE();
Bước 3 Thiết lập các thông số cho Timer
- Lựa chọn tần số cho Timer
- Lựa chọn hệ số chia tần: Prescaler
- Nạp giá trị cho thanh ghi đếm: Period
- Khởi tạo Timer : HAL_TIM_Base_Start_IT(&htim1);
Bước 4 Viết chương trình con phục vụ ngắt Timer
Trong file "stm32f1xx_it.c“ hoặc trong “main.c”
void TIM2_IRQHandler (void) // Ví dụ ngắt Timer 2
Trang 7B1 Cấu hình nguồn xung của Timer
- Timer 1 – APB2; Timer 2,3,4 – APB1
Ví dụ 1: Sử dụng Timer1 chế độ 1 tạo tần số 1KHz trên chân PA.0
Sơ đồ mạch mô phỏng
-
B2 Cấu hình Timer: Lựa chọn Timer; thiết lập chế độ hoạt động; lựa chọn nguồn xung
- Lựa chọn nguồn xung từ bộ tạo dao động; thiết lập Prescaler, Counter Mode, Period
Trang 8- Lựa chọn nguồn xung từ bộ tạo dao động : Clock Source –> Internal Clock
- Thiết lập Prescaler, Counter Mode, Period
Trang 9B3 Thiết lập ngắt Timer
- Thiết lập TIM1 update interrupts ( với Timer 1)
Thiết lập TIMx global interrupt( với Timer 2,3,4)
Lựa chọn chân chiều vào, chiều ra, mode Thiết lập các thông số trên STM32CubeMX như trong hướng dẫn lập trình với GPIO
Sau đó chọn GENERATE CODE để tạo file Code
- Khung chương trình với Timer 2
#include "main.h"
TIM_HandleTypeDef htim2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
Trang 10Ví dụ 1 : Sử dụng Timer 1 tạo xung có tần số Fout = 1KHz trên chân PA15
Bộ tạo dao động chế độ HSI với Fosc = 8MHz
Chương trình:
#include "main.h"
TIM_HandleTypeDef htim1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
Trang 11if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK){ Error_Handler();}
- Dừng DMA của Timer
- Hàm đọc giá trị thanh ghi đếm
- Hàm set giá trị bộ đếm của counter 2.2.2 Các bước lập trình với Timer trên STM32CubeMX
Trang 12Bước 1 Thiết lập hệ thống
- Thiết lập xung nhịp hệ thống : SystemClock_Config();
Bước 2 Thiết lập cho các GPIO
- Cho phép GPIO – AFIO tương ứng hoạt động bằng hàm:
HAL_RCC_GPIOx_CLK_ENABLE();
Bước 3 Thiết lập các thông số cho Timer
- Lựa chọn tần số cho Timer
- Lựa chọn chế độ hoạt động : External clock source mode 1
- Lựa nguồn xung đầu vào : ETR1; TI1FP1; TI2FP2
- Lựa chọn sườn xung: Rising; Falling
- Lựa chọn lọc – lấy mẫu: 0 ÷ 15
- Lựa chọn hệ số chia tần: Prescaler = 0;
- Lựa chọn chế độ đếm: Counter Mode = Up;
- Nạp giá trị đếm tràn thanh ghi đếm: Period
- Khởi tạo Timer : HAL_TIM_Base_Start(&htim1);
- Đọc giá trị trong bộ đếm của Timer : dem= HAL_TIM_GetCounter(&htim1); Thiết lập trên STMCubeMx
B1 Cấu hình nguồn xung của Timer
- Timer 1 – APB2; Timer 2,3,4 – APB1
Ví dụ 1: Sử dụng Timer1 chế độ 1 tạo tần số 1KHz trên chân PA.0
Sơ đồ mạch mô phỏng
-
Trang 13B2 Cấu hình Timer: Lựa chọn Timer; thiết lập chế độ hoạt động; lựa chọn nguồn xung
Lựa chọn chế độ Slave Mode - External clock source mode 1
Trang 14Lựa chọn nguồn xung đầu vào: ETR1 hoặc TI1FP1; TI2FP2
B3 Cấu hình Timer - Cấu hình các thông số : Prescaler, Counter mode, Counter Period, Trigger Polarity, Trigger Filter
Trang 15 Lựa chọn chân chiều vào, chiều ra, mode Thiết lập các thông số trên STM32CubeMX như trong hướng dẫn lập trình với GPIO
Sau đó chọn GENERATE CODE để tạo file Code
- Khung chương trình với Timer 1
#include "main.h"
TIM_HandleTypeDef htim1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
Trang 16Ví dụ 2 : Sử dụng Timer 1 chế độ đếm – TI1FP1 – PA8, đọc số lần nhấn nút PB1 hiển thị trên 01 Led 7 thanh kết nối như hình bên
Chương trình:
#include "main.h"
TIM_HandleTypeDef htim1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
Trang 17HAL_TIM_PWM_ConfigChannel - Hàm cấu hình kênh PWM HAL_TIM_SetCompare - Hàm thiết lập độ rộng xung Ton 2.3.2 Các bước lập trình với Timer trên STM32CubeMX
Bước 1 Thiết lập hệ thống
- Thiết lập xung nhịp hệ thống : SystemClock_Config()
Bước 2 Thiết lập cho các GPIO
- Cho phép GPIO – AFIO tương ứng hoạt động bằng hàm:
HAL_RCC_GPIOx_CLK_ENABLE();
Bước 3 Thiết lập các thông số tạo xung PWM
- Lựa chọn tần số cho Timer
- Lựa chọn hệ số chia tần: Prescaler ;
- Lựa chọn chế độ đếm: Counter Mode = Up;
- Nạp giá trị cho thanh ghi đếm: Counter Period
- Nạp giá trị thiết lập độ rộng xung Ton: Pulse
- Khởi tạo kênh PWM:
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
- Thiết lập lại độ rộng xung Ton:
HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,DutyCycle);
Trang 18Thiết lập trên STMCubeMx
B1 Cấu hình nguồn xung của Timer
- Timer 1 – APB2; Timer 2,3,4 – APB1
Ví dụ 1: Sử dụng Timer1 chế độ 1 tạo tần số 1KHz trên chân PA.0
Sơ đồ mạch mô phỏng
-
B2 Cấu hình Timer: Lựa chọn Timer; thiết lập chế độ hoạt động; lựa chọn nguồn xung
- Lựa chọn nguồn xung từ bộ tạo dao động
- Lựa chọn kênh đầu ra PWM;
- Thiết lập Prescaler, Counter Mode, Period, Pulse
Trang 19- Lựa chọn kênh PWM: Channel 1 –> PWM Generation CH1
Trang 20- Thiết lập Prescaler, Counter Mode, Counter Period, Pulse
Lựa chọn chân chiều vào, chiều ra, mode Thiết lập các thông số trên STM32CubeMX như trong hướng dẫn lập trình với GPIO
Sau đó chọn GENERATE CODE để tạo file Code
- Khung chương trình tạo xung PWM với Timer 1 – Kênh 1
#include "main.h"
TIM_HandleTypeDef htim1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
Trang 22Chương trình:
#include "main.h"
TIM_HandleTypeDef htim1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM1_Init(void);
Trang 23sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; sBreakDeadTimeConfig.AutomaticOutput =
Trang 24Bài tập 3 Sử dụng ngắt Timer1 và Timer 3, lập trình tạo đồng thời 2 xung: Timer 1 tạo xung có tần số 2KHz trên chân PB0; Timer 3 tạo xung có tần số 4KHz trên chân PB1 Với Fosc=8MHz
Bài tập 4 Sử dụng Timer 1 chế độ đếm – ETR1 – PA12, đọc số lần nhấn nút PB1(PA12) hiển thị giá trị trên 01 Led 7 thanh Khi bắt đầu bật nguồn Led 7 thanh hiển thị số 2 Bài tập 5 Sử dụng Timer 3 chế độ đếm – TI1FP1 – PA6, đọc số lần nhấn nút PB1(PA6)
và hiển thị giá trị trên 02 Led 7 thanh Khi bắt đầu bật nguồn Led 7 thanh hiển thị số 12 Bài tập 6 Sử dụng Timer 3 chế độ đếm – TI2FP2 – PA7, đọc số lần nhấn nút PB1(PA7) hiển thị giá trị trên LCD 16x2
Bài tâp 7 Lập trình điều khiển đèn LED1 – PA8 sáng luân phiên 5 mức tăng dần (lặp lại) bằng xung PWM - TIM1CH1 Với Fosc=8MHz
Bài tâp 8 Sử dụng 2 nút nhất UP, DOWN để tăng giảm 10 mức sáng cho led LED2 – PA9
Bài tập 9 Sử dụng Timer 1, lập trình tạo đồng thời 4 xung PWM có tần số 5KHz, với độ rộng Ton1 10% trên kênh CH1; Ton2 30% trên kênh CH2; Ton3 70% trên kênh CH3; Ton4 90% trên kênh CH4 Với Fosc=8MHz
Trang 25Bài tập 10 Sử dụng Timer 1 chế độ đếm xung, Timer 2 chế độ tạo xung (định thời gian 1s), thiết kế bộ đo tần số hiển thị giá trị trên LCD 16x2
10
OSCIN_PD0 5OSCOUT_PD1 6
PB8 45
PA2
12 PA111 PA3 13 PA4 14
PB9 46
PA5 15 PA6 16 PA7 17 PA8 29 PA9 30
PB10 21
PA10 31
PB0 18 PB1 19 PB2 20 PB3 39
PB11 22
PB4 40 PB5 41 PB6 42 PB7 43
PB12 25
PB13 26
PB14 27
PB15 28
PA11 32 PA12 33
PA13 34
PA14 37
PA15
PC14-OSC32_IN 3PC15-OSC32_OUT 4