TRƯỜNG ðẠI HỌC KHOA HỌC TỰ NHIÊNTRƯỜNG ðẠI HỌC KHOA HỌC TỰ NHIÊN
KHOA ðIỆN TỬ KHOA ðIỆN TỬ VIỄN THÔNGVIỄN THÔNG
PHẦN 3: LẬP TRÌNH VỚI CCS (tt)
1
ðặngðặng LêLê KhoaKhoa
CHƯƠNG 4: NGẮT VÀ ỨNG DỤNG
• Nguyên tắc hoạt ñộng của ngắt
• Các hàm dùng cho ngắt
•
Các loại ngắt
•
Các loại ngắt
• Ví dụ
2
Nguyên tắc hoạt ñộng của ngắt
• Ứng dụng trong lập trình ưu tiên
• Khi có 1 ngắt xảy ra, VðK sẽ hoàn tất lệnh
ñang thực hiện và chạy chương trình phục
vụ ngắt
vụ ngắt
• Cấp ngắt: ngắt 1 cấp và ngắt 2 cấp
3
Ngắt 1 cấp
• Trên PIC 14 , 12 ,10 ,tất cả các ngắt chỉ có 1 cấp
ưu tiên .
• Khi ngắt nào ñang ñược phục vụ thì không thể
bị ngắt bởi 1 ngắt khác xảy ra .
bị ngắt bởi 1 ngắt khác xảy ra .
• Khi ngắt xảy ra chương trình nhảy ñến ñịa chỉ
ngắt , thường là 004h , sao lưu thanh ghi W,
STATUS , PCLATCH , FSR… thì nhảy ñến hàm
phục vụ ngắt ñó .
• Thực hiện xong thì phục hồi tất cả thanh ghi trên
thoát ngắt .
4
Ngắt 1 cấp…
• Bit cho phép ngắt toàn cục ( GIE ) bị khóa tự
ñộng khi có ngắt.
• Dùng #priority ñể xác ñịnh ưu tiên ngắt. Ngắt ưu
tiên nhất sẽ luôn ñược hỏi vòng trước .Sau khi
tiên nhất sẽ luôn ñược hỏi vòng trước .Sau khi
xác ñịnh cờ ngắt cần phục vụ, nó sẽ thực thi
hàm ngắt tương ứng .Xong thì xoá cờ ngắt ñó
và thoát ngắt . Phục vụ ngắt nào xong thì chỉ
xoá cờ ngắt ñó.
5
Ngắt 2 cấp
• Chỉ có trên PIC 18 ( và dsPIC ) . Có 2 khái niệm:
ngắt ưu tiên thấp (low priority) và ngắt ưu tiên
cao ( high priority ).
•
2 vector thực thi ngắt tương ứng thường là
•
2 vector thực thi ngắt tương ứng thường là
0008h (high) và 0018h ( low ).
• Một ngắt thấp ñang ñược phục vụ sẽ bị ngưng
và phục vụ ngắt cao ở 0008h nếu ngắt cao xảy
ra. Ngược lại, ngắt cao ñang xảy ra thì không
bao giờ bị ngắt bởi ngắt thấp.
6
Ngắt 2 cấp…
• Nếu viết hàm ngắt bình thường, không ñòi hỏi
ưu tiên gì thì CCS sinh mã ñể tất cả hàm ngắt
ñều là ngắt ưu tiên cao. Quy trình thực hiện ngắt
sẽ như ngắt 1 cấp trên.
• ðể sử dụng ngắt 2 cấp, khai báo #device phải
có high_ints=true . Và hàm ngắt nào muốn ưu
tiên cao thì thêm FAST theo sau chỉ thị tiền xử lý
hàm ñó.
• Chỉ có duy nhất 1 ngắt ñược ưu tiên cao.
7
Khai báo ngắt
• Mỗi dòng VDK có số lượng ngắt khác nhau :
PIC 14 có 14 ngắt , PIC 18 có 35 ngắt
• #DEVICE HIGH_INTS= Khai báo ngắt có
mức ưu tiên cao.
mức ưu tiên cao.
• #INT_XXX fast Đây là chỉ thị báo cho trình biên
dịch một ngắt có mức ưu tiên cao.
• Cách khai báo:
#INT_XXX
8
Khai báo ngắt…
• Sau ñây là danh sách 1 số ngắt với chức năng
tương ứng :
• #INT_GLOBAL : ngắt chung
• #INT_AD : chuyển ñổi A /D ñã hoàn tất
• #INT_EXT : ngắt ngoài
•
#INT_EXT1 : ngắt ngoài 1
•
#INT_EXT1 : ngắt ngoài 1
• #INT_EXT2 : ngắt ngoài 2
• #INT_RB : bất kỳ thay ñổi nào trên chân B4 ñến B7
• #INT_RC : bất kỳ thay ñổi nào trên chân C4 ñến C7
• #INT_RDA : data nhận từ RS 232 sẵn sàng
• #INT_RTCC : tràn Timer 0
• #INT_TBE : bộ ñệm chuyển RS 232 trống
• #INT_TIMER0 : một tên khác của #INT_RTCC
• #INT_TIMER1 : tràn Timer 1
• #INT_TIMER2 : tràn Timer 2
• #INT_TIMER3 : tràn Timer 3
• #INT_TIMER5 : tràn Timer 5
• #INT_PWMTB : ngắt cuả PWM time base
9
Relevant Functions:
• disable_interrupts()Disables the specified
interrupt.
• enable_interrupts() Enables the specified
interrupt.
•
ext_int_edge()
Enables the edge on which
•
ext_int_edge()
Enables the edge on which
the edge interrupt should trigger. This can be either
rising or falling edge.
• clear_interrupt() This function will clear
the specified interrupt flag. This can be used if a
global isr is used, or to prevent an interrupt from
being serviced.
10
• ðể cho phép ngắt ñó hoạt ñộng phải dùng lệnh
enable_interrupts ( int_xxxx) và enable_interrupts
( global ) .
•
Khoá FAST theo sau #int_xxx ñể cho ngắt ñó là
•
Khoá FAST theo sau #int_xxx ñể cho ngắt ñó là
ưu tiên cao , chỉ ñược 1 ngắt thôi , chỉ có ở PIC
18 và dsPIC .
11
enable_interrupts ( level )
• level là tên các ngắt ñã cho ở trên hay là GLOBAL ñể
cho phép ngắt ở cấp toàn cục.
• Mọi ngắt của VDK ñều có 1 bit cờ ngắt, 1 bit cho phép
ngắt. Khi có ngắt thì bit cờ ngắt bị set =1, nhưng ngắt có
họat ñộng ñược hay không tuỳ thuộc bit cho phép ngắt
. enable_interrupts (int_xxx ) sẽ bật bit cho phép ngắt .
. enable_interrupts (int_xxx ) sẽ bật bit cho phép ngắt .
Nhưng tất cả các ngắt ñều không thể thực thi nếu bit cho
phép ngắt toàn cục = 0
VD : ñể cho phép ngắt timer0 và timer1 hoạt ñộng:
enable_interrupts (int_timer0);
enable_interrupts (int_timer1 ) ;
enable_interrupts ( global ); // chỉ cần dùng 1 lần trừ
//phi muốn có thay ñổi ñặc biệt
12
disable_interrupts ( level )
• level giống như trên.
• Hàm này vô hiệu 1 ngắt bằng cách set bit cho phép ngắt
= 0.
• disable_interrupts ( global ) set bit cho phép ngắt toàn
cục =0, cấm tất cả các ngắt .
cục =0, cấm tất cả các ngắt .
• Không dùng hàm này trong hàm phục vụ ngắt vì không
có tác dụng, cờ ngắt luôn bị xoá tự ñộng.
13
clear_interupt ( level )
• level không có GLOBAL .
• Hàm này xoá cờ ngắt của ngắt ñược chỉ
ñịnh bởi level .
14
ext_int_edge ( source , edge )
• Hàm này thiết lập nguồn ngắt ngoài EXTx là
cạnh lên hay cạnh xuống.
• source : nguồn ngắt . Trên PIC 18 có 3 nguồn
ngắt trên 3 chân EXT0 , EXT1 , EXT2 ứng với
ngắt trên 3 chân EXT0 , EXT1 , EXT2 ứng với
source = 0 ,1 , 2. Các PIC khác chỉ có 1 nguồn
EXT nên source = 0 .
• edge : chọn cạnh kích ngắt , edge = L_TO_H
nếu chọn cạnh lên ( từ mức thấp chuyển lên
mức cao ) hay H_TO_L nếu chọn cạnh xuống
15
Relevant Interrupts:
• #int_default This directive specifies that the following
function should be called if an interrupt is triggered but no
routine is associated with that interrupt.
• #int_global This directive specifies that the following
function should be called whenever an interrupt is triggered.
function should be called whenever an interrupt is triggered.
This function will replace the compiler generated interrupt
dispatcher.
• #int_xxx This directive specifies that the following
function should be called whenever the xxx interrupt is
triggered. If the compiler generated interrupt dispatcher is
used, the compiler will take care of clearing the interrupt flag
bits.
16
VD: Chương trình đọc dữ liệu từ port b xuất ra port D khi có sự thay đổi từ
RB4 – RB7
#include <16F877.h>
#device *=16
#use delay (clock=20000000)
#byte portb = 0x06
#byte portd = 0x08
#INT_RB
Void RB_LED ()
{
portd=portb;
}
void main ()
{ set_tris_b(0xFF);
set_tris_d(0x00);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
while(true)
{
}
}
17
VD: Viết chương trình ñếm nhị phân và khi có sự thay ñổi từ RB4 ñến RB7 thì mạch ñếm
sẽ reset
#include <16F877.h>
#device *=16
#use delay (clock=20000000)
#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#INT_RB
RB_LED ()
{
portd=portb;
portc = 0;
portc = 0;
}
void main ()
{ set_tris_b(0xF0);
set_tris_c(0x00);
set_tris_d(0x00);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
portc=0;
while(true)
{
portc=portc+1;
delay_ms(500);
}
}
18
VD: Viết chương trình ñếm nhị phân và khi RB0 chuyển từ cao xuống thấp thì mạch ñếm sẽ reset
#include <16F877.h>
#device *=16
#use delay (clock=20000000)
#byte portc = 0x07
#byte portd = 0x08
#INT_EXT
void RB_EXT ()
{
portc=0x0;
}
void main ()
void main ()
{ set_tris_b(0xFF);
set_tris_c(0x00);
set_tris_d(0x00);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
ext_int_edge(0,H_TO_L);
portc =0;
while(true)
{
portc+=1;
delay_ms(500);
}
}
19
VD: Chương trình thực hiện công việc sau:
- Đọc dữ liệu từ port B xuất ra port D khi có sự thay đổi từ bit RB4-RB7
- Nếu bit RB0 = 0 xuất ra port C=0x0f ngược lại thực hiện mạch đếm
#include <16F877.h>
#device *=16
#use delay (clock=20000000)
#byte portb = 0x06
#byte portc = 0x07
#BIT id = portb.0
#byte portd = 0x08
void main ()
{ set_tris_b(0xFF);
set_tris_d(0x00);
set_tris_c(0x00);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
portc=0;
#byte portd = 0x08
#INT_RB
Void RB_LED ()
{
portd=portb;
portc=0;
}
20
portc=0;
while(true)
{
if(id ==0) portc=0x0f;
else
{
portc +=1;
delay_ms(2000);
}
}
}
VD: Chương trình nhận dữ liệu từ cổng COM hiển thị lên port B và dịch Led ở
port D
#include <16F877.h>
#device *=16 ADC=8
#use delay (clock=20000000)
#byte portb = 0x06
#byte portd = 0x08
#use rs232 (uart1, baud=9600,parity=n,xmit=pin_c6, rcv=pin_c7 )
#INT_RDA
uart_handler()
{
portb=getc();
}
void main ()
{
set_tris_b(0x00);
set_tris_d(0x00);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
portd=0;
while(true)
{
portd=portd + 1;
delay_ms(1000);
}
}
21
VD: Chương trình ñọc dữ liệu từ ADC
xuất ra port C dùng ngắt
xuất ra port D không dùng ngắt
#include <16F877.h>
#device *=16
#use delay (clock=20000000)
#byte portb = 0x06
#byte portc = 0x07
#BIT id = portb.0
#byte portd = 0x08
void main ()
{ set_tris_b(0xFF);
set_tris_d(0x00);
set_tris_c(0x00);
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);
setup_adc(ADC_CLOCK_INTERNAL);
#byte portd = 0x08
#INT_AD
Void TEST_AD ()
{
portc=read_adc();
}
22
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(ALL_ANALOG);
set_adc_channel(0);
portd=0;
while(true)
{
portd=read_adc();
delay_ms(2000);
}
}
CHƯƠNG 5: TIMER VÀ ỨNG DỤNG
• Nguyên tắc hoạt ñộng của Timer
• Các hàm dùng cho Timer
•
Ứng dụng Timer
•
Ứng dụng Timer
• Ví dụ
23
• It is very easy to make a digital counter using
flip-flops. Counters can be made which count
up, count down, which can be cleared back to
zero, pre
-
loaded to a certain value, and which
zero, pre
-
loaded to a certain value, and which
by the provision of an overflow output can be
cascaded with other counters.
24
A digital counter made of eight flip-
flops
25