👉 Table of Contents
PWM (Pulse Width Modulation) là phương pháp điều chế độ rộng xung
được hiểu là cách điều khiển điện áp tải ra
, dựa trên sự thay đổi độ rộng xung vuông, dẫn đến sự thay đổi điện áp. Hiểu theo cách khác, PWM là tín hiệu được tạo ra từ vi mạch kỹ thuật số, như vi mạch điều khiển.
PWM là gì?
Điều chế độ rộng xung (PWM) là một kỹ thuật điều khiển dòng điện tiện lợi cho phép bạn kiểm soát tốc độ của động cơ, sản lượng nhiệt của máy sưởi và hơn thế nữa theo cách tiết kiệm năng lượng (và thường là êm hơn). Các ứng dụng hiện có cho PWM bao gồm, nhưng không giới hạn:
- Bộ
điều khiển quạt
tản nhiệttốc độ thay đổi
. - Hệ thống truyền động máy nén VRF HVAC.
- Mạch truyền động động cơ xe hybrid và điện.
- Bộ điều
chỉnh độ sáng LED
Điều biến độ rộng xung đã thay đổi thế giới bằng cách cắt giảm mức tiêu thụ điện năng của các thiết bị sử dụng động cơ
như máy điều hòa không khí biến tần, tủ lạnh biến tần, máy giặt biến tần, trong số nhiều thiết bị khác.
Ví dụ, máy điều hòa không khí biến tần có thể tiêu thụ ít hơn một nửa năng lượng so với máy điều hòa không khí biến tần trong một số trường hợp.
Trong thời đại ngày nay, nếu một thiết bị được quảng cáo là có máy nén tốc độ thay đổi hoặc quạt tốc độ thay đổi (điều này không bao gồm hai hoặc ba tốc độ quạt), thì có khả năng đáng kể là nó đang sử dụng PWM.
PWM hoạt động như thế nào?
PWM hoạt động bằng cách tạo xung dòng điện một chiều
và thay đổi khoảng thời gian mà mỗi xung ở trạng thái “bật” để kiểm soát lượng dòng điện chạy đến một thiết bị chẳng hạn như đèn LED. PWM là kỹ thuật số, có nghĩa là nó có hai trạng thái: bật và tắt
(tương ứng với 1
và 0
trong ngữ cảnh nhị phân, sẽ trở nên phù hợp hơn với bạn nếu sử dụng bộ vi điều khiển).
Mỗi xung được bật càng lâu, đèn LED sẽ càng sáng
. Do khoảng thời gian giữa các xung quá ngắn
nên đèn LED không thực sự tắt
. Nói cách khác, nguồn điện của đèn LED bật và tắt quá nhanh (hàng nghìn lần mỗi giây) đến mức đèn LED thực sự vẫn sáng mà không nhấp nháy. Điều này được gọi là làm mờ PWM, và mạch như vậy chỉ được gọi là mạch điều chỉnh độ sáng LED PWM.
Chu kỳ làm việc của PWM
Tỷ lệ phần trăm
thời gian trong đó tín hiệu PWM vẫn ở mức CAO
(đúng giờ) được gọi là chu kỳ hoạt động - Duty Cycle
. Nếu tín hiệu luôn BẬT thì nó ở trong chu kỳ hoạt động 100% và nếu nó luôn tắt thì đó là chu kỳ hoạt động 0%.
Duty Cycle =Turn ON time/ (Turn ON time + Turn OFF time)
Nếu chu kỳ làm việc - Duty Cycle của bộ nguồn PWM được đặt thành 70%, thì xung sẽ bật
trong 70% thời gian
và nó tắt 30% thời gian
. Chu kỳ nhiệm vụ đề cập đến lượng thời gian nó được bật. Ở chu kỳ hoạt động 70%, độ sáng của đèn LED phải gần 70%. Mối tương quan giữa chu kỳ nhiệm vụ và độ sáng không phải là tuyến tính 100%, vì hiệu suất của đèn LED thay đổi theo lượng dòng điện được cung cấp.
Nếu Duty Cycle là 0%, toàn bộ tín hiệu sẽ bằng phẳng. Duty Cycle PWM là 0% có nghĩa là nguồn bị tắt
. Trong trạng thái như vậy, đèn LED sẽ không hoạt động.
Lý do chính khiến các mạch PWM rất hiệu quả là chúng không cố gắng hạn chế một phần dòng điện sử dụng điện trở mà chúng bật và tắt hoàn toàn dòng điện.
Sử dụng 8051 để tạo xung PWM điều khiển động cơ 3 phase
PWM trong STM32F4XX
Trong mỗi timer
của STM32Fxx
các bạn sẽ kiểm tra xem có hỗ trợ PWM hay không?
Timer 1 và Timer 8 trong STM32F407 (DS8626 Rev 9)
Check trong cấu hình Timer bằng phần mềm CubeMX
Hoặc trong datasheet nhà sản xuất Reference manual
STM32F4 RM0090 Reference manual
Sử dụng Board kit nào?
Các bạn có thể sử dụng các loại board kit, chip STM32F407 bất kỳ nào mà các bạn có. Ở đây mình sử dụng board này:
STM32F407VET6 Board 32bit Cortex-M4
Sơ đồ nguyên lý tại đây!!!
Lựa chọn nguồn kênh Timer?
Mình sử dụng luôn Timer 1 cho mạnh mẽ nhé! (Advanced-control timers (TIM1 and TIM8))
Cùng kiểm tra xem Reference manual có gì nhé!
Cấu trúc của TIMER 1/TIMER 8 (RM0090 Rev 19)
Tại Chapter 17 Advanced-control timers (TIM1 and TIM8) nhà sản xuất có nói rằng: Ở Timer 1 là Timer cao cấp nhất của chip luôn đó. Và đặc biệt hỗ trợ luôn PWM.
It may be used for a variety of purposes, including measuring the pulse lengths of input signals (input capture) or generating output waveforms (output compare, PWM, complementary PWM with dead-time insertion).
Hẳn là rất mạnh khi hãng tuyên bố “on the fly”, TIMER 1 hổ trợ đếm lên, xuống, với 16 bit ( tương đương đếm 1 → 65536), hỗ trợ tạo xung PWM theo các mode khác nhau (Chế độ PWM canh theo cạnh -PWM edge-aligned mode, Chế độ PWM canh giữa - PWM center -aligned mode).
PWM của STM32F4XX có gi?
Vào xem nhà sản xuất nói gì về mode PWM của họ ?
Chế độ PWM( điều biến độ rộng xung) cho phép người dùng có thể tạo ra tín hiệu xung vuông
có tần số được định bằng giá trị trong thanh thi TIMx_ARR
và duty định bằng giá trị trong thanh ghi TIMx_CCRx
.
Mỗi kênh của timer có thể cấu hình được chế độ PWM độc lập với nhau.
Mỗi ngõ ra OCx (OutputCapture) có thể cấu hình đươc mức tích cực cao hoặc thấp bằng phần mềm.
Trong chế độ PWM( 1 hoặc 2) giá trị của thanh ghi TIMx_CNT
và thanh ghi TIMx_CCRx
luôn được so sánh với nhau để để xác định IMx_CCRx
≤ TIMx_CNT
hoặc TIMx_CNT
≤ TIMx_CCRx
(phụ thuộc vào chiều đếm của bộ đếm).
Bộ định thời có thể tạo PWM theo 2 chế độ là canh theo cạnh(edge-aligned mode) hoặc canh giữa(center-aligned mode)
Ví dụ với edge-aligned mode
Một số thanh ghi về Timer:
- Counter register (TIMx_CNT) lưu giá trị đếm
- Prescaler register (TIMx_PSC) lưu giá trị chia từ tần số cơ sở cấp cho Timer để tạo ra tần số thích hợp
- Auto-reload register (TIMx_ARR) lưu giá trị đích đếm lên hoặc đếm xuống
- Repetition counter register (TIMx_RCR)
- Thanh ghi compare/capture( TIMx_CCRx) được sử dụng để lưu giá trị đếm hiện tại của bộ đếm ngay sau khi nhận được tín hiệu yêu cầu capture ICx
Với TIMx_ARR = 8 ( tức là bộ đếm từ 0 → 8 sẽ reload lại)
Khi quá trình capture xảy ra cờ tương ứng CCxIF được set và có thể phát sinh yêu cầu ngắt hoặc DMA nếu trước đó đã cho phép chúng. Cờ CCxIF có thể được xóa bằng phần mềm thông qua việc ghi bit ‘0’ vào nó hoặc tự động được xóa bằng phần cứng khi người dùng đọc giá trị capture được lưu trong thanh ghi TIMx_CCRx.
Theo hình dưới bộ đếm được cấu hình ở chế độ đếm lên (ARR 0 → 8):
- Tín hiệu tham chiếu PWM( OCxREF) ở mức cao khi TIMx_CNT < TIMx_CCRx và ngược lại thì tín hiệu này ở mức thấp.
- Nếu giá trị của thanh ghi TIMx_CCRx lớn hơn giá trị tự động nạp lại của thanh ghi TIMx_ARR thì tín hiệu OCxREF luôn ở mức cao
Ví dụ với chế độ edge-aligned mode
- Với CCRx = 4: ta có Duty Cycle = [CCRx /(AAR +1)]100 = [4/(8+1)]100 = 44.4444%
- Với CCRx = 8: ta có Duty Cycle = [CCRx /(AAR +1)]100 = [8/(8+1)]100 = 88.8888%
- Với CCRx > 8: ta có Duty Cycle = 100%
- Với CCRx = 0: ta có Duty Cycle = 0%
Dựa vào ví dụ trên chắc các bạn đã hiểu sơ bộ về các số liệu khi setup độ rộng của xung rồi hen!
Bây giờ vào dự án thực tế nhé
Chúng ta sẽ sử dụng Channel 1 của Timer 1 để tạo PWM:
- Tần số là 60Hz
- Tạo xung với độ rộng 45%
- Thử thay đổi độ rộng tự động
RCC cấp tần số
Bây giờ xem xét RCC cấp tần số bao nhiêu cho TIMER 1?
Dựa vào datasheet của nhà sản xuất ta thấy TIM1 sử dụng APB2 max 84MHz
Với kit sử dụng STM32F407VET chúng ta sử dụng thì có thạch anh ngoài 8MHz → HSE → PLLCLK → HCLK 168MHz → APB2 qua bộ chia, bộ nhân → APB2 timer clock là 168 MHz.
Các công thức tính toán được lấy từ Datasheet nhà sản xuất.
Frequency = ClockFreq / ((PSC + 1) * (ARR + 1))
Dutyin% = (CCRx * 100) / ARR
for the fast PWM- RCR nếu không sử dụng (highlight) thì bỏ qua nhé!!!
- Tool các bạn có thể tham khảo ở link Github: https://github.com/bangnguyendev/STM32-Scaler
Dựa vào công thức trên, ta chọn tần số là 60Hz tương ứng với Update_event = 60 Hz
TIM_CLK = APB2 timer clock là 168 MHz.
Chọn ARR = 999 (đếm từ 0 → 999) tức là 1000 xung.
Vậy theo công thức trên ta được PCS = 2800 - 1 = 2799 (giá trị bộ chia từ xung đầu vào TIM_CLK)
OK! Các thông số cơ bản đã có, bây giờ tạo Project và check xung clock tạo ra từ TIMER 1 nhé!
Tạo Project từ MXCube & KeilC ARM
Mở MXCube → New Project → ACCESS TO MCU SELECTOR
MXCube → New Project → ACCESS TO MCU SELECTOR
→ STM32F407VET6 → START PROJECT
→ STM32F407VET6 → START PROJECT
Cấu hình RCC → mình sử dụng HSE (hoặc gì là do các bạn chọn nhé!)
RCC → mình sử dụng HSE (cấp xung ngoại 8MHz)
Cấu hình mode Debug để nạp code và Debug nè → Serial Wire
Cấu hình mode Debug
Cấu hình TIMER 1 trên MXCube
Theo thông số đã tính toán như trên.
Trong mục Parameter Settings
của TIMER 1
:
- Sử dụng Channel 1 dạng
xuất xung PWM
output (Pin PE9) - Clock Source chọn
Internal Clock
- PSC 2799
- ARR (Counter Period) 999
Phía dưới Parameter Settings
của TIMER 1
có mục PWM Generation Channel 1
:
- Sử dụng PWM
Mode 1
- Counter mode là
UP
đếm lên - Pulse là
450
( bởi vì450 là 45%
của AAR=1000)
Cấu hình xung Clock
ta thấy Timer APB2
sử dụng 168MHz
như chúng ta xác định như trên
Cấu hình xung Clock
Cấu hình mục tạo Project:
Sau khi mở lên thì Project của chúng ta như sau:
Các tham số tính toán đã được phần mềm MXCube tạo sẳn.
Ở file main.c
ta thêm lệnh khởi động PWM ở TIMER 1
& Channel 1
(Pin PE9)
Nạp code và thử thôi
Mình sử dụng Logic port
, Channel 0 sẽ cắm vào Pin PE9
để đo xung đầu ra thử thì thấy đúng 60Hz và Duty 45%
F = 60Hz và Duty 45%
Cùng Debug để xem các giá trị ở thanh ghi nhé!
Trước khi chương trình khởi chạy các giá trị đều là 0x00
Sau khi thực thi lệnh khởi tạo HAL_TIM1_Init() thì các thông số PSC, ARR, CCR1 đã được nạp vào thanh ghi
- PSC
0x0AEF
(2799) - ARR
0x03E7
(999) - CCR1
0x01C2
(450)
Hiện tại, chuẩn bị thực thi hàm Start PWM HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
Để thay đổi độ rộng xung
Để thay đổi độ rộng xung thì chúng ta sử dụng __HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1, xxx);
- Với XXX là giá trị CCR1
Vậy để thay đổi độ rộng xung thành 70% thì sao?
- 70% -> (70% * 1000)/100% = 700 CCR1
__HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1, 700);
Lúc này giá trị CCR1 sẽ được cập nhật thành 0x2BC (700)
Vậy để thay đổi độ rộng xung tăng dần & giảm dần thì sao? Chúng ta sử dụng một biến var_CCR1 để thay đổi.
...
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
int var_CCR1 = 100 ; // Khoi tao PWM voi Duty 10%
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(50);
var_CCR1 = var_CCR1 + 100;
if (var_CCR1 >= 1000)
{
var_CCR1 = 100;
}
__HAL_TIM_SetCompare(&htim1, TIM_CHANNEL_1, var_CCR1);
}
/* USER CODE END 3 */
Độ rộng xung đã được thay đổi từ 10% → 100% → 10% …
Duty 10% → 100% → 10% …
KEIL-C-STM32F407/TIMER1_CN1_PWM
Cám ơn mọi người đã theo dõi bài viết!