Xin chào các bạn!
Trong bài viết này, tôi xin hướng dẫn cho các bạn sử dụng một chế độ mới trong các bộ TIMER của AVR, đó là tạo xung điều rộng PWM. Ở đây tôi dùng Timer1 của Atmega8, trình biên dịch CodeVisionAVR.
Chú ý : Source code bài viết dưới đây được biên dịch bằng phần mềm CodeVisionAVR để biên dịch code không lỗi xin vui lòng Download bảnCodeVisionAVR Tại Đây
I.CÁC KHÁI NIỆM TRONG ĐIỀU CHẾ PWM.
1.Điều chế PWM là gì?
Các bạn có thể hiểu đơn giản điều chế PWM là thay đổi duty cycle (khoảng thời gian tín hiệu ở mức cao) trong một chu kỳ (Time period) cố định, qua đó làm thay đổi điện áp trung bình cấp ra tải (sử dụng để thay đổi vận tốc động cơ DC,…).
Ta có:
–T: chu kỳ của xung.
–T1: là thời gian xung ở mức cao.
Hệ số điều chỉnh D(%): D = T1/T.
-Điện áp lớn nhất cấp cho tải: Udmax
-Điện áp trung bình cấp cho tải khi có PWM: Ud = Udmax.D
2.Điều chế PWM với Atmega8.
Bộ Timer1 của Atmega8 cung cấp cho chúng ta 2 kênh tạo xung điều rộng PWM:
- Kênh A: tín hiệu ra ở OC1A (PORTB.1)
- Kênh B: tín hiệu ra ở OC1B (PORTB.2)
Cùng nhiều chế độ tạo PWM (các bạn tham khảo thêm ở Datasheet) ở đây tôi sẽ nói rõ cho các bạn chế độ Fast PWM, mode 14 (Kênh A).
- Các bạn thiết lập dạng tín hiệu PWM ra trên thanh ghi TCCR1A .
- Khi hoạt động, ban đầu chân OC1A ở mức cao (tùy vào dạng tín hiệu PWM ra bạn chọn ở trên), TCNT1 tăng giá trị từ 0 cho đến khi bằng giá trị trên thanh ghi OCR1A thì chân OC1A được xóa về 0. TCNT1 vẫn tiếp tục tăng đến khi bằng giá trị trong thanh ghi ICR1 thì TCNT1 reset về 0 và chân OC1A được kéo lên mức cao.
Vì vậy ở đây, các bạn có thể thiết lập:
- Giá trị của ICR1: là chu kỳ xung.
- Giá trị của OCR1A: là thời gian xung ở mức cao
Như vậy các bạn đã tạo ra được xung điều rông PWM với hệ số điều chỉnh tùy ý.
II.BÀI TOÁN VÍ DỤ
Để các bạn hiểu rõ hơn, tôi xin đưa ra bài toán:
Tạo PWM trên kênh A của vi điều khiển Atmega8 có chu kỳ 20ms, D1 = 50%:
- Khi có ngắt ngoài 0, PWM có D2 = 75%.
- Khi có ngắt ngoài 1, PWM có D3 =25%.
Với bài toán này, tôi cấu hình tần số Timer1 để sau 1us thì TCNT1 tăng 1 đơn vị:
- Chu kỳ T = 20ms = 20000us à ICR1 = 20000.
- D1 = 50% à Thời gian trên mức 1 là 10us à OCR1A = 10000.
- D2 = 25% à OCR1A = 5000.
- D3 = 75% à OCR1A = 15000.
Cấu hình tạo PWM với CodeVision:
Tạo Project mới à chọn CodeWizardAVR à chọn Timers à Chọn Timer1
Các bạn chọn:
-Chế độ tạo PWM ở Mode
-Dạng xung PWM xuất ra ở Out. A
-Giá trị của OCR1A ở Comp.A
-Giá trị của ICR1 ở Inp Capture
Code:
#include <main.h>
// TRINH PHUC VU NGAT CHO NGAT NGOAI 0
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
OCR1A = 15000; // 5ms, D =75%
}
// TRINH PHUC VU NGAT CHO NGAT NGOAI 1
interrupt [EXT_INT1] void ext_int1_isr(void)
{
OCR1A = 5000; // 5ms, D =25%
// Place your code here
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=Out Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=0 State0=T
PORTB=0x00;
DDRB=0x02;
// KHOI TAO TIMER1
// Clock source: System Clock
// Clock value: 1000.000 kHz
// Mode: Fast PWM top=ICR1
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x82; // CAU HINH CHO CAC CHE DO CHO TIMER
TCCR1B=0x1A;
TCNT1H=0x00;
TCNT1L=0x00;
// PWM KENH A =====================================================
//ICR1H=0x00;
//ICR1L=0x00;
ICR1 = 20000;
/*
Bo chia Timer: sau 1us, TCNT1 tang 1 don vi
ICR1 = 20000 --> CHU KY cua xung tin hieu T = 20000us = 20ms
*/
//OCR1AH=0x00;
//OCR1AL=0x00;
OCR1A = 10000;
/*
OCR1 = 10000 --> Thoi gian tin hieu o muc 1 T1 = 10000us =10000ms
Vay D = T1/T = 50%
*/
// PWM KENH B =====================================================
OCR1BH=0x00;
OCR1BL=0x00;
// KHOI TAO NGAT NGOAI
// INT0: On
// INT0 Mode: Rising Edge // Ngat canh xuong
// INT1: On
// INT1 Mode: Rising Edge
GICR|=0xC0;
MCUCR=0x0F;
GIFR=0xC0;
// Global enable interrupts
#asm("sei") // Cho phep ngat toan cuc
while (1)
{
// Place your code here
}
}
// ------------------END OF FILE-------------------
// ------------------------------------------------