Professional Documents
Culture Documents
ORG
2. Ứng dụng.
Hãy tưởng tượng bạn cần thiết kế một mạch điều khiển hoàn chỉnh thực
hiện rất nhiều nhiệm vụ bao gồm: nhận thông tin từ người dùng qua các nút
nhấn, nhận tín hiệu từ cảm biến, xử lí thông tin, xuất tín hiệu điều khiển, hiển
thị thông tin trạng thái…rõ ràng trong các nhiệm vụ này việc nhận thông tin
người dùng, hay tín hiệu cảm biến rất hiếm xảy ra so với các nhiệm vụ khác
nhưng lại rất “khẩn cấp” cần được ưu tiên hàng đầu.
Nhiệm vụ theo dõi các sự kiện “khẩn cấp” có thể thực hiện bằng 1 trong
2 cách:
+Viết 1 hàm thăm dò sự kiện (ví dụ như hàm Button read đã giới thiệu ở
bài 1) và phải gọi hàm này ra liên tục. Tuy nhiên, nếu chương trình chính có
quá nhiều nhiệm vụ như đã nói ở trên thì cách này không hiệu quả. Lý do đưa
ra là mỗi hàm cần 1 thời gian thực thi nhất định, nếu đang thực thi 1 hàm khác
mà xảy ra sự kiện thì hàm thăm dò trở nên vô dụng và vi điều khiển bắt sót sự
kiện.
+Sử dụng ngắt, lúc này vi điều khiển sẽ không tốn thời gian cho hàm
thăm dò nữa. Vi điều khiển sẽ thực thi nhiệm vụ xử lý sự kiện khi mà có ngắt
xảy ra, khi đó mọi công việc khác được gác lại cho đến khi xử lý xong công
việc mà ngắt giao cho(trình phục vụ ngắt).
Một ví dụ khác cho ứng dụng của ngắt là bộ định thời (ngắt tràn
timer/counter), cứ sau 1 khoảng thời gian cố định thì xảy ra 1 ngắt, ta ứng dụng
vào nhiệm vụ quét led chẳng hạn, khi đó hàm quét led sẽ là trình phục vụ ngắt
và nó sẽ được gọi ra theo 1 chu kỳ xác định với mức ưu tiên cao nhất. Như vậy
sẽ không có hiện tượng led bị chớp do vi điều khiển thực hiện quá nhiều công
việc(thời gian giữa 2 lần quét bị giãn ra).
Tóm lại, nếu thực hiện các đoạn lệnh thì vi điều khiển thực hiện công
việc 1 cách tuần tự ( từng dòng lệnh được thực thi), nếu sử dụng ngắt thì vi
xử điều khiển thực hiện công việc 1 cách ngẫu nhiên (thực hiện công việc
khi có sự kiện ngẫu nhiên).
Hình 1 minh họa cách tổ chức ngắt thông thường trong các chip
AVR. Số lượng ngắt trên mỗi dòng chip là khác nhau, ứng với mỗi ngắt sẽ có
vector ngắt, vector ngắt là các thanh ghi có địa chỉ cố định được định nghĩa
trước nằm trong phần đầu của bộ nhớ chương trình.
Bảng 1 tóm tắt các vector ngắt có trên vi điều khiển Atmega16
STT Địa chỉ Nguồn ngắt Mô tả
vector
$000 RESET Chân ngoài, Power-on Reset, Brown-out
1 Reset, Watchdog Reset,và JTAG AVR
Reset
2 $002 INT0 Ngắt ngoài 0
3 $004 INT1 Ngắt ngoài 1
4 $006 TIMER2 COMP So sánh bộ định thời 2 trùng khớp
5 $008 TIMER2 OVF Tràn bộ định thời 2
6 $00A TIMER1 CAPT Định thời 1 bắt sự kiện
7 $00C TIMER1 COMPA So sánh bộ định thời 1 trùng khớp A
8 $00E TIMER1 COMPB So sánh bộ định thời 1 trùng khớp B
9 $010 TIMER1 OVF Tràn bộ định thời 1
10 $012 TIMER0 OVF Tràn bộ định thời 0
11 $014 SPI, STC Truyền thông nối tiếp hoàn tất
12 $016 USART, RXC USART, nhận hoàn tất
Do MikroC không hỗ trợ thư viện Interrupt nên việc khai báo không
giống như các trình biên dịch khác. Để biết cách khai báo của trình biên dịch
khác, các bạn có thể tra cứu trong file Help của trình biên dịch đó với từ khóa
Interrupt library.
Mức cao
PD2
Cạnh
Cạnh lên
PD3 xuống
Mức thấp
PB2
Giả sử chúng ta kết nối các ngắt ngoài trên Atmega16 như hình 2,
các nút nhấn dùng tạo ra các ngắt. Có 4 khả năng có thể xảy ra khi chúng ta
nhấn và thả các nút nhấn. Nếu không nhấn, trạng thái (logic) các chân INT là
cao do điện trở kéo lên, khi vừa nhấn 1 nút, sẽ có sự chuyển trạng thái từ cao
sang thấp, chúng ta gọi là cạnh xuống - Falling Edge, khi nút được nhấn và giữ,
trạng thái các chân INT được xác định là thấp và cuối cùng khi thả các nút,
trạng thái chuyển từ thấp sang cao, gọi là cạnh lên – Rising Edge. Trong những
trường hợp cụ thể, 1 trong 4 khả năng trên đều hữu ích, ví dụ trong các ứng
dụng đếm xung (đếm encoder của servo motor chẳng hạn) thì 2 khả năng
“cạnh” phải được dùng.
Thanh ghi MCUCR chứa các bits cho phép chúng ta chọn 1 trong 4 khả
trên để kích hoạt ngắt ngoài INT0 và INT1. Dưới đây là cấu trúc thanh ghi
MCUCR được trích ra từ datasheet của chip Atmega16.
MCUCR là một thanh ghi 8 bit nhưng đối với hoạt động ngắt ngoài,
chúng ta chỉ quan tâm đến 4 bit thấp của nó (4 bit cao dùng cho Power manager
và Sleep Mode).
Bốn bit thấp là các bit Interrupt Sense Control (ISC) trong đó 2 bit
ISC11:ISC10 dùng cho INT1 và 2 bit ISC01:ISC00 dùng cho INT0. Hãy nhìn
vào bảng tóm tắt bên dưới để biết chức năng của các bit trên, đây là bảng sự
thật của 2 bit ISC11, ISC10. Bảng sự thật cho các bit ISC01, ISC00 hoàn toàn
tương tự.
Trong Atmega 16 còn có ngắt thứ 3 là INT2. Chế độ của ngắt này được xác lập
qua thanh ghi MCUSR, cụ thể là bit 6 – ISC2
Nếu ISC2 được xóa (=0) thì ngắt xảy ra khi có cạnh xuống tại chân INT2.
Nếu ISC2 được đặt (=1) thì ngắt xảy ra khi có cạnh lên tại chân INT2.
Xung cấp cho INT2 phải có độ rộng lớn hơn 50ns thì mới xuất hiện ngắt,
nếu nhỏ hơn thì không đảm bảo có ngắt xảy ra. Khi thay đổi bit ISC2, một ngắt
có thể xảy ra, vì vậy trước khi thay đổi bit này, để tránh sai sót, ta cần vô hiệu
hóa chức năng ngắt ngoài INT2 trong thanh ghi GICR sau đó mới thay đổi bit
ISC2, cuối cùng, cờ ngắt INTF2 phải được xóa trong thanh ghi GIFR trước khi
kích hoạt lại ngắt INT2.
Bit 7: Điều khiển ngắt INT1, khi nó được đặt (=1) thì ngắt INT1 được cho
phép hoạt động, ngược lại, nếu nó được xóa thì ngắt INT1 bị vô hiệu hóa.
Bit 6: Tương tự bit 7, nó điều khiển ngắt INT0.
Bit 5: Tương tự bit 7, nó điều khiển ngắt INT1.
c. Thanh ghi cờ ngắt chung – GIFR (General Interrupt Flag Register)
Đây là thanh ghi trạng thái (cờ) của các ngắt INT0, INT1 và INT2. Nếu có 1
sự kiện ngắt phù hợp xảy ra trên chân INT0, bit INTF0 được tự động đặt (=1).
Sau khi trình phục vụ ngắt kết thúc công việc thì cờ ngắt sẽ tự động xóa. Tương
tự cho trường hợp của INTF1 và INTF2, chúng ta có thể sử dụng các bit này để
nhận ra các ngắt, tuy nhiên điều này là không cần thiết nếu chúng ta cho phép
ngắt tự động, vì vậy thanh ghi này thường không được quan tâm khi lập trình
ngắt ngoài. Cấu trúc thanh ghi GIFR được trình bày trong hình dưới.
Sau khi đã thiết lập xong các bit của các thanh ghi điều khiển ngắt ngoài,
việc sau cùng là cho phép ngắt toàn cục thông qua việc đặt bit 7(bit I) của thanh
ghi trạng thái chung(SREG) đã giới thiệu ở chương 1. Xin được nhắc lại cấu
trúc thanh ghi này ở hình dưới.
Chú ý: Các chân ngắt PD2, PD3, PB2 khi sử dụng là các chân ngắt ngoài
thì phải thiết lập các chân này là ngõ vào thông qua thanh ghi DDRx.
+Bước 2: Khởi động ngắt ngoài thông qua thanh ghi GICR.
+Bước 3: Cho phép ngắt toàn cục thông qua bit 7 của thanh ghi SREG.
Lưu ý: Nếu không biết MikroC định nghĩa các bit của các thanh ghi điều
khiển ngắt như thế nào, ta có thể làm theo cách sau:
+Thao tác byte trực tiếp trên các thanh ghi (1 hoặc nhiều byte) bằng các
toán tử logic.
+Chọn Start debugger (F9) để gọi trình gỡ rối, sau đó trong ô search for
variable by assembly name ta gõ tên của bit cần thao tác, tên này chính là
tên được định nghĩa trong datasheet. Ví dụ ta tìm bit INT0 của thanh ghi
GICR thì ta gõ INT0. Lập tức trong cửa sổ sổ xuống sẽ gợi ý cho ta kết quả
tên định nghĩa của bit cần tìm trong MikroC. Cách tìm này áp dụng cho tất
cả các bit, thanh ghi và biến của AVR trong MikroC.
2. Timer/Counter0.
a/. Các thanh ghi điều khiển T/C0:
Đây là thanh ghi thiết lập các chế độ làm việc của T/C0
Bit 0-2: (CS-Clock Select) là 3 bit dùng để chọn nguồn xung đếm cho T/C0,
chức năng của 3 bit này được tóm tắt qua bảng sau:
CS02 CS01 CS00 Mô tả
0 0 0 Không dùng nguồn xung (T/C) không làm việc
0 0 1 Lấy trực tiếp nguồn xung nuôi chip
0 1 0 Lấy tần số của nguồn xung nuôi chip chia 8
0 1 1 Lấy tần số của nguồn xung nuôi chip chia 64
1 0 0 Lấy tần số của nguồn xung nuôi chip chia 256
1 0 1 Lấy tần số của nguồn xung nuôi chip chia 1024
1 1 0 Lấy nguồn xung ngoài tại chân T0, tác động bằng
cạnh xuống
1 1 1 Lấy nguồn xung ngoài tại chân T0, tác động bằng
cạnh lên
Bit 3 và 6 (WGM): Là 2 bit điều khiển chế độ tạo dạng sóng Waveform
Generation Mode (WGM). Các bit này giúp ta chọn giá trị TOP của bộ đếm
và dạng sóng tạo ra. Các chế độ làm việc mà 2 bit này hỗ trợ bao gồm: Chế độ
thông thường, chế độ xóa bộ đếm khi so sánh trùng khớp(CTC), và 2 chế độ
điều biến bề rộng xung (PWM). Bảng sau tóm tắt các chế độ làm việc được
thiết lập bởi 2 bit này.
Cập nhật vào Ảnh hưởng
STT WGM01 WGM00 Chế độ làm việc TOP
thanh ghi ORC0 đến cờ tràn
Bit 4 và 5 (COM): Các bit này điều khiển vận hành của chân OC0. Nếu 1
trong 2 bit này được đặt thì chân OC0 không hoạt động như là 1 chân I/O mà
phục vụ cho việc xuất tín hiệu. Tuy nhiên, lưu ý rằng thanh ghi hướng dữ liệu
(DDR) phải thiết lập sao cho chân OC0 là ngã ra.
Sau đây là các bảng thiết lập tùy chọn tương quan giữa các bit COM và
WGM.
Khi các bit WGM được thiết lập với chế độ CTC (WGM01=1,
WGM00=0) ta có bảng thiết lập các bit COM sau:
COM01 COM00 Mô tả
0 0 Chế độ nhập xuất thông thường.
0 1 Đảo trạng thái chân OC0 khi có so sánh trùng khớp.
Xóa bit OC0 khi có so sánh trùng khớp. Chân OC0
1 0
xuống mức thấp.
Đặt bit OC0 khi có so sánh trùng khớp. Chân OC0 lên
1 1
mức cao.
Khi các bit WGM được thiết lập với chế độ PWM tốc độ cao
(WGM01=0, WGM00=1) ta có bảng thiết lập các bit COM sau:
COM01 COM00 Mô tả
0 0 Chế độ nhập xuất thông thường.
0 1 Reserved.
Xóa bit OC0 khi so sánh trùng khớp. Đặt OC0 tại
1 0
BOTTOM. Chế độ thuận.
Đặt bit OC0 khi so sánh trùng khớp. Xóa OC0 tại
1 1
BOTTOM. Chế độ nghịch.
Khi các bit WGM được thiết lập với chế độ PWM pha chính xác
(WGM01=1, WGM00=1) ta có bảng thiết lập các bit COM sau:
COM01 COM00 Mô tả
0 0 Chế độ nhập xuất thông thường.
0 1 Reserved.
Xóa OC0 khi so sánh trùng khớp và đang đếm lên. Đặt
1 0
OC0 khi so sánh trùng khớp và đang đếm xuống.
Đặt OC0 khi so sánh trùng khớp và đang đếm lên. Xóa
1 1
OC0 khi so sánh trùng khớp và đang đếm xuống.
Bit7 – FOC0: Đây là bit so sánh trùng khớp cưỡng bức, bit này chỉ hoạt động
khi WGM00 được xóa (chế độ không PWM). Tuy nhiên, để đảm bảo khả năng
tương thích với các thiết bị trong tương lai, khi chọn chế độ PWM, ta phải xóa
bit này.
Khi ghi 1 vào bit này thì lập tức có 1 so sánh trùng khớp (trong chế độ PWM).
Thanh ghi giá trị bộ đếm, định thời: Timer Counter Registor – TCNT0
Thanh ghi này chứa giá trị hiện tại của bộ đếm, với T/C0 thì nó có độ rộng là 8
bit nên có giá trị đếm từ 0 đến 255. Ta có thể ghi trực tiếp giá trị vào thanh ghi
này.
Thanh ghi này chứa giá trị để so sánh với giá trị của bộ đếm chứa trong thanh
ghi TCNT0, do đó nó có độ rộng bằng với độ rộng của thanh ghi TCNT0.
Đây là thanh ghi dùng chung cho 3 bộ đếm và nó có đủ các bit cờ ngắt thể hiện
trạng thái của từng bộ đếm.
Bit1- Output Compare Flag 0 – OCF0: bit này được đặt khi có sự so sánh
trùng khớp xuất hiện giữa giá trị thanh ghi của bộ đếm và giá trị chứa trong
thanh ghi so sánh.
Khi muốn có 1 ngắt xảy ra khi có sự so sánh trùng khớp(OCF0=1), ta phải set
bit I trong SREG và bit OCIE0 trong thanh ghi TIMSK.
Bit 2 –Timer/Counter0 Overflow Flag – TOV0: đây là cờ tràn của bộ đếm,
tràn là hiện tượng khi bộ đếm đếm đến giá trị cao nhất và đếm thêm 1 lần nữa.
Khi đó cờ tràn sẽ được đặt.
Khi muốn có 1 ngắt xảy ra khi có cờ tràn, ta phải set bit I trong SREG và bit
TOIE0 trong thanh ghi TIMSK.
Trên đây là những giới thiệu sơ qua về các thanh ghi có liên quan đến
việc điều khiển T/C0. Đối với T/C1 và T/C2, các bit và thanh ghi có chức năng
tương tự sẽ không được nhắc lại.
Phần sau ta sẽ tìm hiểu kỹ hơn về chức năng của các chế độ hoạt động
chính của T/C0
Nguyên tắc hoạt động của bộ định thời thực chất vẫn là việc đếm, bộ
đếm sẽ đếm xung, xung được cấp bởi nguồn xung, nguồn xung của T/C0 được
chọn bởi 3 bit CS00, CS01, CS02 của thanh ghi TCCR0. Như vậy, chọn nguồn
xung là chọn khoảng giá trị thời gian cho bộ đếm.
Giả sử nguồn xung clock “nuôi” chip của chúng ta là clkI/O=1MHz tức
là 1 nhịp mất 1us. Để tạo khoảng thời gian dài hơn, ta chia bớt tầng số này cho
1 hệ số định sẵn. Nếu chúng ta lấy trực tiếp nguồn xung nuôi chip làm xung
đếm, tức là tần số của T/C0 (tạm gọi là fT/C0) cũng bằng clkI/O=1MHz, cứ
1us T/C0 được kích và TCNT0 sẽ tăng 1 đơn vị. Khi đó giá trị lớn nhất mà
T/C0 có thể đạt được là 256 x 1us=256us, giá trị này nhỏ hơn 10ms mà ta
mong muốn. Nếu lấy nguồn xung nuôi chip chia 64, nghĩa là cứ sau 64 nhịp
(64us) thì TCNT0 mới tăng 1 đơn vị, khả năng lớn nhất mà T/C0 đếm được là
256 x 8us=16384us=16ms, lớn hơn 10ms, vậy ta hoàn toàn có thể sử dụng
nguồn xung của chip đã chia 64 làm nguồn xung cho bộ đếm.
Mặc định, bộ đếm sẽ đếm từ 0 đến giá trị cao nhất, trong trường hợp
T/C0, do thanh ghi chứa giá trị của nó có 8 bit nên bộ đếm sẽ đếm từ 0-255. Ta
có 2 cách đặt số nhịp đếm:
+Cách 1: Dùng ngắt tràn, cách này đơn giản, ta chỉ việc đặt trước 1 giá
trị cho bộ đếm và ghi vào thanh ghi TCNT0. Khi đó bộ đếm sẽ đếm từ giá trị
này đến 255 sẽ xảy ra ngắt, trong trình phục vụ ngắt ta sẽ khởi tạo lại giá trị ban
đầu cho TCNT0 sau đó mới thực hiện công việc cần làm. Như vậy, số nhịp
đếm sẽ bằng 255 trừ đi giá trị khởi tạo ban đầu.
Tóm lại:
prescaler
T 255 TCNT 0
f XTAL
Với prescaler là hệ số chia, f XTAL là tần số thạch anh dùng cho chip, TCNT0
là giá trị đặt trước, T là chu kỳ lặp lại công việc (chu kỳ này không thể chính xác hoàn
toàn do sai số phép tính và thời gian quét led…).
+Cách 2: Dùng bộ so sánh (ngắt so sánh trùng khớp), ta sẽ ghi giá trị số
nhịp cần đếm vào thanh ghi so sánh ORC0, khi đếm từ 0 đến giá trị so sánh
trùng khớp thì sẽ xảy ra 1 ngắt giúp ta thực hiện 1 công việc nào đó.
Tóm lại:
prescaler
T TCNT 0
f XTAL
Trong mạch này, ta cần thiết lập lại thông số thạch anh cần dùng là 1
Mhz trong trình biên dịch MikroC và trình mô phỏng ISIS.
PORTD=0x00;
}
Các linh kiện cần 1 khoảng thời gian để chuyển từ mức thấp sang mức
cao mà vi điều khiển có tốc độ xử lý rất cao. Vì vậy để đảm bảo các linh kiện
hoạt động bình thường, ta có thể tạo 1 khoảng delay tương đối nhỏ để khắc
phục độ trễ truyền của linh kiện.
Lưu ý: Khi dùng ngắt tràn để gọi chương trình quét led 7 đoạn, nếu số
lượng led nhiều (nhiều hơn 2) thì ta không quét 1 lần tất cả các led mà mỗi
lần có ngắt chỉ quét 1 led (xuất dữ liệu và cấp địa chỉ) và lần ngắt sau sẽ quét
led tiếp theo. Như vậy sẽ đảm bảo thời gian thực hiện trình phục vụ ngắt
không quá lâu cũng như đảm bảo thời gian đáp ứng cho các linh kiện mà
không cần dùng hàm delay.
Bai3_2_B : Thực hành Timer – Ngắt so sánh trùng khớp.
Sử dụng file mô phỏng BAI3_2.DSN
//MÃ LED 7 ĐOẠN LOẠI ANODE CHUNG, A LÀ LSB
const char table[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
char var=0;
void main(){
// KHAI BÁO HƯỚNG DỮ LIỆU CHO PORTC VÀ PORTD LÀ NGÕ RA
DDRC=0xFF;
DDRD=0xFF;
//CHỌN NGUỒN XUNG LẤY TỪ XUNG NHỊP CẤP CHO CHIP CHIA 64 HAY PRESCALER =64
CS00_bit=1;
CS01_bit=1;
CS02_bit=0;
//CHỌN CHẾ ĐỘ CTC – BỘ ĐẾM SẼ BỊ XÓA MỖI LẦN CÓ NGẮT TRÙNG KHỚP
WGM00_bit=0;
WGM01_bit=1;
//CHO PHÉP NGẮT KHI SO SÁNH TRÙNG KHỚP
OCIE0_bit=1;
//CHO PHÉP NGẮT TOÀN CỤC
SREG_I_bit=1;
// THIẾT LẬP GIÁ TRỊ SO SÁNH
OCR0=96;
while(1){
var++;
if(var>99) var=0;
delay_ms(100);
}
}
Các bước cơ bản sử dụng ngắt do hoạt động của bộ T/C bao gồm:
+Chọn nguồn xung theo khoảng thời gian cần thiết, thông qua 3 bit CS của
thanh ghi TCCR.
+Chọn loại ngắt phù hợp thông qua thanh ghi mặt nạ ngắt.
+Cho phép ngắt toàn cục ở thanh ghi SREG.
+Viết trình phục vụ ngắt theo địa chỉ ngắt tương ứng. (Xem lại trang 95 - 96).
Ngoài ra nếu dùng ngắt tràn thì phải khởi tạo lại giá trị đầu sau mỗi lần
có ngắt. Nếu dùng ngắt so sánh thì phải chọn chế độ CTC (xóa bộ đếm mỗi lần
xảy ra ngắt – xem lại trang 103) hoặc xóa bộ đếm thủ công trong trình phục vụ
ngắt.
Hai ví dụ về sử dụng bộ định thời sử dụng file mô phỏng BAI3_2.DSN
Viết chương trình sử dụng sơ đồ trên sao cho khi nhấn nút thì giá trị hiển thị
tăng 1 đơn vị.
Trong chương trình trên, ta hoàn toàn có thể sử dụng ngắt tràn hoặc ngắt
so sánh trùng khớp, tùy theo mục đích sử dụng.
Ví dụ bạn muốn đếm số người đi vào 1 phòng, khi đếm đủ 10 người thì
phát 1 thông báo. Để thực hiện việc này, ta chỉ cần mắc cảm biến vào chân T0,
sau đó thiết lập giá trị so sánh của thanh ghi OCR0, cuối cùng là cho phép ngắt
so sánh trùng khớp và ngắt toàn cục, thông báo sẽ được thực hiện bằng trình
phục vụ ngắt.
Lưu ý, các bạn có thể thiết lập chế độ CTC(Clear Timer on Compare
Match) bởi các bit WGM của thanh ghi TCCR0 (xem lại trang 103). Khi đó, bộ
đếm sẽ khởi tạo lại mỗi khi có ngắt so sánh trùng khớp.
Người ta thay biến trở bằng 1 nút nhấn, khi ta nhấn thì động cơ quay,
khi thôi nhấn thì động cơ dừng. Khi tần số nhấn-nhả cao thì động cơ quay như
được cấp dòng liên tục. Ta tiếp tục thử nghiệm với thời gian nhấn và nhả khác
nhau. Khi thời gian nhấn dài hơn thời gian nhả thì động cơ quay nhanh hơn khi
thời gian nhả dài hơn thời gian nhấn, ta thấy thời gian nhấn chính là bề rộng
của xung tạo ra. Bề rộng xung càng lớn thì công suất cấp cho động cơ càng lớn.
Đó là ý tưởng cơ bản để sử dụng PWM điều khiển vận tốc động cơ (và điều
khiển nhiều thứ khác nữa). Trong thực tế, nút nhấn được thay bằng khóa điện
tử ( transistor, thường là FET), việc còn lại là tạo xung có bề rộng thay đổi
được. Nhiệm vụ này thực hiện dễ dàng với vi điều khiển thông qua việc sử
dụng chế độ PWM của các bộ Timer/Counter có hỗ trợ.
Hình 6. Mô tả các phương pháp điều khiển công suất động cơ.
Trong điều chế độ rộng xung, ta cần chú ý các thông số sau:
+Tần số hoặc chu kỳ (Time Period) của xung.
+Độ rộng xung (Duty Cycle).
Như vậy, để tạo xung PWM, ta sẽ thay đổi các thông số trên bằng các chức
năng trong chế độ PWM của AVR.
Ta trở lại các khái niệm ban đầu của bộ đếm và liên kết sự tương quan của các
khải niệm này với PWM.
BOTTOM: là giá trị nhỏ nhất của bộ đếm, luôn bằng 0.
MAX: là giá trị lớn nhất của bộ đếm, MAX=255(0xff) đối với bộ đếm 8 bit như
T/C0 và T/C2, MAX=65535 với bộ đếm 16 bit như T/C1.
TOP: trong các ứng dụng PWM, giá trị này là cố định đối với T/C0 và T/C2
(TOP=0xFF), riêng T/C1 giá trị này có thể cố định(0x00FF, 0x01FF, hoặc
0x03FF) hoặc do người dùng tự định nghĩa thông qua thanh ghi OCR1A hoặc
ICR1. Tham khảo thêm tại trang 83, 112 và 128 datasheet của
ATMEGA16.
OUTPUT COMPARE(OC) là giá trị so sánh chứa trong thanh ghi OCRx, nó có
thể tạo ra ngắt so sánh hoặc tạo sự thay đổi mức logic ở chân OCx(x có thế là
0, 1A,1B hoặc 2)
Các giá trị trên chính là các mốc thời gian mà mức logic thay đổi trên chân tạo
xung của vi điều khiển. Các bạn có thể theo dõi hình sau để có sự liên tưởng.
Hình 8. So sánh hình dạng xung và các mốc thời gian của T/C.
Có thể giải thích sự tương quan giữa các mốc thời gian của T/C và dạng của
xung PWM như sau: Trong chu kỳ đếm từ BOTTOM đến TOP, khi giá trị
thanh ghi TCNTx của bộ đếm tăng đến giá trị OC thì có sự thay đổi mức logic
tại chân OCx(x có thế là 0, 1A,1B hoặc 2). Khi đếm đến TOP thì lại có sự thay
đổi mức logic ở chân OCx lần nữa và lại bắt đầu chu kỳ mới.
Như vậy: từ BOTTOM đến TOP là chu kỳ của 1 xung PWM, từ TOP đến OC
là độ rộng của xung. Đây là tương quan theo chế độ PWM thuận. Chế độ PWM
nghịch sẽ được giới thiệu sau.
Ta bắt đầu tìm hiểu cách sử dụng chức năng PWM của T/C mà cụ thể là T/C0.
Đặt bit OC0 khi so sánh trùng khớp. Xóa OC0 tại
1 1
BOTTOM. Chế độ nghịch.
Ví dụ: Viết chương trình điều khiển độ rộng xung. Có 2 nút nhấn nối với 2
chân ngắt ngoài INT0 và INT1. Khi nhấn nút nối với INT0 thì độ rộng xung
tăng, khi nhấn nút nối với INT1 thì độ rộng xung giảm.
Chương trình tham khảo:
Bai3_2_D : Thực hành Timer – Fast PWM với T/C0.
Sử dụng file mô phỏng BAI3_2_C.DSN
void main(){
//CẤU HÌNH HƯỚNG DỮ LIỆU
DDRB=0xFF;
DDRD=0x00;
//SỬ DỤNG ĐIỆN TRỞ NỘI KÉO LÊN
PORTD=0xFF;
//KHAI BÁO CHẾ ĐỘ NGẮT – NGẮT TÁC ĐỘNG BẰNG CẠNH LÊN TẠI CÁC CHÂN INTx
ISC00_bit=0;
ISC01_bit=1;
ISC10_bit=0;
ISC11_bit=1;
//CHO PHÉP NGẮT NGOÀI
INT0_bit=1;
INT1_bit=1;
//CHO PHÉP NGẮT TOÀN CỤC
SREG_I_bit=1;
//CHỌN NGUỒN XUNG ĐẾM - PRESCALER = 1024
//FREQUENCY=16MHz/(256*1024)=61HZ
CS00_bit=1;
CS01_bit=0;
CS02_bit=1;
//CHỌN CHẾ ĐỘ FAST PWM CHO T/C0
WGM00_bit=1;
WGM01_bit=1;
//CHỌN DẠNG XUNG TẠI CHÂN OC0 – PWM THUẬN
COM01_bit=1;
COM00_bit=0;
//ĐẶT GIÁ TRỊ ĐỘ RỘNG XUNG BAN ĐẦU LÀ 50%
OCR0=127;
while(1){
//VÒNG LẶP VÔ TẬN
}
}
//TRÌNH PHỤC VỤ NGẮT INT0 – TĂNG ĐỘ RỘNG XUNG 10%
void Interrupt() org 0x02 {
OCR0+=25;
if(OCR0>=225) OCR0=225;//GIỚI HẠN ĐỘ RỘNG XUNG TỐI ĐA
}
//TRÌNH PHỤC VỤ NGẮT INT1 – GIẢM ĐỘ RỘNG XUNG 10%
void Interrupt1() org 0x04 {
OCR0-=25;
if(OCR0<=50) OCR0=50;//GIỚI HẠN ĐỘ RỘNG XUNG TỐI THIỂU
}
Nhắc lại : Chân Ocx phải được khai báo là ngã ra mới có thể xuất được tín
hiệu PWM.
Phase correct PWM: PWM với pha chính xác.
Phase correct PWM cung cấp một chế độ tạo xung PWM có độ phân
giải cao (high resolution) nên được gọi là Phase correct PWM. Về cách điều
khiển, Phase correct hầu như giống fast PWM, nghĩa là nếu bạn đã biết cách sử
dụng các mode của fast PWM thì bạn sẽ hoàn toàn điều khiển được Phase
correct PWM. Khác nhau cơ bản của 2 chế độ này là trong cách hoạt động, nếu
Fast PWM có chu kỳ hoạt động trong 1 single-slope (một sườn) thì Phase
correct PWM lại dual-slope (hai sườn).
Trong chế độ Fast PWM, T/C đếm từ 0 đến giá trị OC (chứa trong thanh
ghi OCR) thì đảo trạng thái ngã ra chân OC. T/C tiếp tục đếm đến giá trị TOP
thì chân OC lại đảo trạng thái lần nữa đồng thời bộ đếm được xóa về 0.
Trong chế độ Phase correct PWM, Trong chế độ Fast PWM, T/C đếm từ
0 đến giá trị OC (chứa trong thanh ghi OCR) thì đảo trạng thái ngã ra chân OC.
T/C tiếp tục đếm đến giá trị TOP, lúc này chân OC không đảo trạng thái và bộ
đếm cũng không được xóa về 0 mà bắt đầu đếm ngược từ TOP. Khi đếm ngược
về đến giá trị OC thì chân OC mới đảo trạng thái lần nữa, bộ đếm tiếp tục đếm
về 0 để hoàn tất chu kỳ đếm. Để dễ so sánh 2 kiểu PWM, ta hãy quan sát sơ đồ
sau:
Nhắc lại:
BOTTOM: là giá trị nhỏ nhất của bộ đếm, luôn bằng 0.
MAX: là giá trị lớn nhất của bộ đếm, MAX=255(0xff) đối với bộ đếm 8 bit như
T/C0 và T/C2, MAX=65535 với bộ đếm 16 bit như T/C1.
TOP: trong các ứng dụng PWM, giá trị này là cố định đối với T/C0 và T/C2
(TOP=0xFF), riêng T/C1 giá trị này có thể cố định(0x00FF, 0x01FF, hoặc
0x03FF) hoặc do người dùng tự định nghĩa thông qua thanh ghi OCR1A hoặc
ICR1 (tùy theo chế độ mà ta chọn qua các bit WGM).
3. Timer/Counter 1
Nhìn chung cách điều khiển T/C1 khá giống với T/C0. Khác nhau cơ
bản là các thanh ghi chứa dữ liệu như bộ đếm TCNT hoặc OCR có độ rộng 16
bit. Các bit điều khiển cũng có nhiều hơn do T/C1 có rất nhiều chế độ hoạt
động. Sau đây xin giới thiệu các thanh ghi điều khiển T/C1.
Thanh ghi điều khiển: Gồm có 2 thanh ghi TCCRA và TCCRB
Ta có thể thấy các bit quen thuộc như CS, WGM, COM với chức năng tương tự
T/C0:
Bit 0-2 của TCCT1B: Các bit chọn nguồn xung cho bộ đếm (CS-Clock
Select)
CS12 CS11 CS10 Mô tả
0 0 0 Không dùng nguồn xung (T/C) không làm việc
0 0 1 Lấy trực tiếp nguồn xung nuôi chip
0 1 0 Lấy tần số của nguồn xung nuôi chip chia 8
0 1 1 Lấy tần số của nguồn xung nuôi chip chia 64
1 0 0 Lấy tần số của nguồn xung nuôi chip chia 256
1 0 1 Lấy tần số của nguồn xung nuôi chip chia 1024
1 1 0 Lấy nguồn xung ngoài tại chân T1, tác động bằng
cạnh xuống
1 1 1 Lấy nguồn xung ngoài tại chân T1, tác động bằng
cạnh lên
Bit 3 và 4 của TCCR1B và bit 0 và 1 của TCCT1A: Các bit chọn dạng
sóng (chọn chế độ làm việc của T/C1) (WGM-WAVE FORM
GENERATION MODE)
T/C1 có đến 15 chế độ tạo dạng sóng, nhưng thực chất nếu sử dụng hết chức
năng của T/C1 ta chỉ cần 7 chế độ. Bảng sau liệt kê tất cả các chế độ tạo dạng
sóng của T/C1.
Trong đó, khi dùng chế độ PWM ta chỉ cần nắm chế độ 10, 14 (hoặc 11, 15).
Khi dùng chế độ CTC có thể dùng chế độ 4 hoặc 12.
Bit 6-7 và bit 4-5: Các bit này điều khiển sự vận hành của chân OC1A và
OC1B. Do T/C1 có 2 kênh PWM độc lập nhau và việc xuất dữ liệu của 2 kênh
sẽ do 2 chân tương ứng là OC1A và OC1B đảm nhiệm nên khi dùng kênh nào
thì phải cấu hình chân OCR1x tương ứng làm ngã ra.
Sau đây là các bảng thiết lập tùy chọn tương quan giữa các bit COM và WGM.
Chế độ không dùng PWM
COM1A1/COM1B1 COM1A0/COM1B0 Mô tả
0 0 Chế độ nhập xuất thông thường.
Đảo trạng thái chân OC1A/OC1B
0 1
khi có so sánh trùng khớp.
Xóa bit OC1A/OC1B khi có so
1 0 sánh trùng khớp. Chân
OC1A/OC1B xuống mức thấp.
Đặt bit OC1A/OC1B khi có so
1 1 sánh trùng khớp. Chân
OC1A/OC1B lên mức cao.
xuống.
Đặt bit OC1A/OC1B khi so sánh trùng
khớp và đang đếm lên. Xóa OC1A/OC1B
1 1
khi so sánh trùng khớp và đang đếm
xuống.
Thanh ghi giá trị bộ đếm : TCNT1 – 16 bit gồm 1 byte cao (TCNT1H) và 1
byte thấp(TCNT1L).
Thanh ghi so sánh kênh A: OCR1A – 16bit gồm 1 byte cao (OCR1AH) và
1 byte thấp(OCR1AL).
Hai byte này truy xuất độc lập, chứa giá trị so sánh kênh A.
Thanh ghi so sánh kênh B: OCR1B – 16bit gồm 1 byte cao (OCR1BH) và 1
byte thấp(OCR1BL).
Hai byte này truy xuất độc lập. chứa giá trị so sánh kênh B.
Thanh ghi bắt sự kiện vào - ICR1 (InputCapture Register 1): ICR1 - 16bit
gồm 1 byte cao (ICR1H) và 1 byte thấp(ICR1L).
Hai byte này truy xuất độc lập. Khi có 1 sự kiện trên chân ICP1, thanh ghi
ICR1 sẽ ghi lại giá trị của thanh ghi đếm TCNT1. Một ngắt có thể xảy ra trong
trường hợp này, vì thế Input Capture có thể được dùng để cập nhật giá trị
“TOP” của T/C1.
Ghi chú :
Trong MikroC, các thanh ghi 16 bit được chia thành 2 byte độc lập và
có tên gọi giống như trong datasheet.
Ví dụ : thanh ghi ICR1 sẽ được chia thành ICR1L (byte thấp) và
ICR1H (byte cao).
+Để ghi dữ liệu vào thanh ghi 16 bit, ta cần chia dữ liệu ra thành 2
phần 8 bit và ghi dữ liệu vào 8 bit cao trước, 8 bit thấp sau.
Ví dụ : Ghi dữ liệu 0x1387 vào thanh ghi ICR1 ta làm như sau :
ICR1H=0x13 ;
ICR1L=0x87 ;
+Để đọc dữ liệu từ thanh ghi 16 bit, ta chỉ cần thao tác như sau :
unsigned int bien16bit;
bien16bit = (( thanh_ghi_16bitH * 256) + thanh_ghi_16bitL);
Trên đây là những giới thiệu sơ qua về các thanh ghi có liên quan đến
việc điều khiển T/C1. Do T/C1 có rất nhiều chế độ làm việc, các bạn có thể
tham khảo thêm datasheet để sử dụng hết chức năng của bộ T/C này.
Trong phần tiếp theo tôi sẽ giới thiệu ứng dụng quan trọng của bộ T/C1
là tạo PWM với việc điều khiển cả độ rộng xung và tần số (T/C0 và T/C2
không điều khiển được tần số chính xác do giá trị TOP cố định).
Nhắc lại:
BOTTOM: là giá trị nhỏ nhất của bộ đếm, luôn bằng 0.
MAX: là giá trị lớn nhất của bộ đếm, MAX=255(0xff) đối với bộ đếm 8 bit như
T/C0 và T/C2, MAX=65535 với bộ đếm 16 bit như T/C1.
TOP: trong các ứng dụng PWM, giá trị này là cố định đối với T/C0 và T/C2
(TOP=0xFF), riêng T/C1 giá trị này có thể cố định(0x00FF, 0x01FF, hoặc
0x03FF) hoặc do người dùng tự định nghĩa thông qua thanh ghi OCR1A hoặc
ICR1 (tùy theo chế độ mà ta chọn qua các bit WGM).
Điều khiển servo với Phase correct PWM của bộ T/C1:
Servo là một tổ hợp gồm 1 động cơ DC công suất nhỏ, hộp giảm tốc và
bộ điều khiển góc quay. Có 2 loại chính là Servo thường và digital Servo, trong
ví dụ này tôi giới thiệu Servo thường (phổ biến). Servo thường có 3 dây, dây
màu đen là dây GND, dây đỏ là dây nguồn (thường là 5V) và 1 dây trắng hoặc
vàng và dây tín hiệu (có một số loại Servo có màu dây khác, bạn cần tham khảo
datasheet của chúng). Vì các Servo đã có sẵn mạch điều khiển góc quay bên
trong nên chúng ta không cần bất cứ giải thuật gì mà chỉ cần cấp tín hiệu PWM
thích hợp cho dây điều khiển là Servo có thể xoay đến 1 vị trí nào đó (chú ý là
Servo thường chỉ xoay nữa vòng, điều khiển servo là điều khiển góc xoay chứ
không phải điều khiển vận tốc xoay). Hình 11 là hình ảnh servo và cách điều
khiển servo.
Ví dụ: Viết chương trình điều khiển 2 servo với 2 ngắt ngoài INT0, INT1 kết
hợp chế độ Fast PWM của T/C1. Khi có ngắt ngoài tại INT0 thì servo 1 đổi vị
trí (độ rộng xung thay đổi từ 1.5ms đến 2ms và xoay vòng). Khi có ngắt ngoài
tại INT4 thì servo 2 đổi vị trí (độ rộng xung thay đổi từ 1.5ms đến 2ms và xoay
vòng). Chu kỳ xung điều khiển servo là 20ms. Xem lại công thức tính tần số
PWM ở hình 10 trang 116.
duty1+=125;
if(duty1>499) duty1=249;
PWM_change_duty(duty1,1);
}
void EX_INT01() org 0x04 {
duty2+=125;
if(duty2>499) duty2=249;
PWM_change_duty(duty2,2);
}
//HÀM THAY ĐỔI ĐỘ RỘNG XUNG
void PWM_change_duty(int duty,char channel ){
switch(channel){
case 1:
OCR1AH=duty>>8;
OCR1AL=duty;
break;
case 2:
OCR1BH=duty>>8;
OCR1BL=duty;
break;
}
}
Hàm thay đổi độ rộng xung PWM_change_duty được xây dựng dựa trên
cách ghi dữ liệu vào thanh ghi 16 bit đã giới thiệu ở trang 120.
MikroC cung cấp cho ta 2 thư viện PWM dành cho T/C 8 bit và T/C 16
bit. Riêng với thư viện PWM 16 bit, hàm khởi tạo chế độ PWM chỉ khởi tạo
được các chế độ định sẵn nên rất khó có thể thay đổi tần số PWM như ý muốn.
Do đó khuyến khích các bạn nắm vững cách khởi tạo thủ công, tuy hơi phức
tạp nhưng sẽ khai thác được hết các tính năng của T/C 16 bit. Các bạn có thể
tham khảo 2 thư viện này trong file help của Mikroc ( ấn F1).