Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 56
CHƯƠNG 4: THỰC HÀNH GIAO TIẾP VỚI
CÁC NGOẠI VI CƠ BẢN
BÀI 1: GIAO TIẾP NHẬP XUẤT VỚI
LED ĐƠN VÀ PHÍM ĐƠN
Các bài thực hành trong chương này sử dụng Atmega16
I. Phần cứng.
+Do Atmega16 có khả năng cấp dòng khá cao (khoảng 20mA) nên có
thể mắc trực tiếp led đơn vào chân I/O của các port.
+Phím đơn có thể mắc theo 2 cách, dùng điện trở kéo lên =>mức tác
động thấp hoặc dùng điện trở kéo xuống => mức tác động cao.
Hình 1. Nút nhấn tác động thấp và nút nhấn tác động cao.
Trong chương này chủ yếu sử dụng nút nhấn tác động thấp.
Module giao tiếp phím ấn và led đơn bao gồm 8 phím ấn và 8 led đơn
với 2 cổng kết nối. Module này thích hợp sử dụng với board phát triển đã giới
thiệu ở chương 1.
Sơ đồ của module được giới thiệu ở hình 2.
unsigned char i;
void main(){
DDRA=0xFF;// CẤU HÌNH PORTA LÀ PORT XUẤT
while(1){
for(i=1;i<=255;i++){
PORTA=i;
Delay_ms(500);// TRÌ HOÃN 500ms
SW1
BUTTON
VCC
SW2
BUTTON
SW3
BUTTON
SW4
BUTTON
VCC D1
LED
R5
330
D2
LED
R6
330
D3
LED
R7
330
D4
LED
4
5
6
7
8
9
J1
PORT_8_PIN
1
2
3
4
5
6
7
8
9
10
VCC
J2
PORT_8_PIN
1
2
3
4
5
6
7
8
9
DDRA=0xFF;// Cấu hình PORTA là PORT xuất
while(1){// Vòng lặp vô tận
for(i=0;i<=7;i++){ // Vòng lặp 8 lần
PORTA=0x01<<i; /*Dịch trái từ 0 đến 7 bit*/
delay_ms(500);// Trì hoãn 0.5s
}
}
}
Yêu cầu: các bạn cải tiến chương trình để 1 led sáng chạy sang phải đến biên
rồi chạy trở về bên trái đến biên.
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 59Ví dụ 2: Viết 1 chương trình để 2 led sáng từ 2 biên chạy vào giữa, rồi
chạy trở ra 2 biên.
Bài 1 _ 1 _B: Chương trình dịch led 2
char i;
void main(){
DDRA=0xFF;
while(1){
for(i=0;i<=3;i++){
PORTA=0x01<<i|0x80>>i;
delay_ms(500);
}
for(i=1;i<=2;i++){
PORTA=0x10<<i|0x08>>i;
delay_ms(500);
Bài tập: Viết 1 chương trình điều khiển 8 led sáng chạy dần từ trái sang
phải (tốc độ 250ms/1led), chớp 2 lần mỗi lần cách nhau 1s.
(Xem bài giải trong file BAI1_1_E.c)
Từ các ví dụ trên, nếu thay các led bằng các tầng công suất, ta có thể
ghép nhiều led thành các ký tự, hình vẽ để trang trí, rất thích hợp cho việc
quảng cáo và các hình thức biểu diễn rất phong phú và đa dạng.
III. Giao tiếp phím nhấn đơn.
Phím đơn là 1 ngoại vi cho phép đưa tín hiệu số vào vi điều khiển để xử
lý, vì vậy trước hết ta cần cấu hình PORTx giao tiếp theo hướng nhận dữ liệu.
Dữ liệu nhận vào được lưu trong thanh ghi PINx, và dữ liệu này thay đổi
khi trạng thái các chân nhập xuất thay đổi.
Phím đơn có 1 hạn chế đó là hiện tượng dội cơ khí. Hiện tượng này xảy
ra khi ta ấn phím, phím không lập tức tiếp xúc bền với tiếp điểm mà sẽ dội ra –
dập vào liên tiếp nhiều lần(ta không thể cảm nhận được hiện tượng này). Do
đó, tín hiệu sinh ra do phím nhấn sẽ không phải là xung vuông mà sẽ là 1 chuỗi
xung liên tiếp có độ rộng xung khá bé. Để sử dụng được phím nhấn, ta phải
khắc phục hiện tượng dội cơ khí. Ta sẽ không quan tâm đến các biện pháp
chống dội bằng Smith trigger hay chốt RS mà sẽ nghiên cứu việc chống dội
bằng phần mềm tức là viết chương trình có khả năng chống dội cơ khí.
1. Giao tiếp phím nhấn đơn giản.
Ở phần này chúng ta chưa đề cập đến hiện tượng dội cơ khí mà chỉ xem
xét việc nhận dữ liệu qua thanh ghi PINx.
Thực hành:
- Sử dụng tiếp dự án BAI1, ta tạo file nguồn mới với tên là
BAI1_2_A.c
- Soạn thảo và biên dịch chương trình sau:
Bài 1 _ 2 _A: Đọc PORT đơn giản
DDRC=0x00;
}
void main(){
init();
while(1){
DDRC=0x00;
//Kiểm tra trạng thái chân C0
if(PINC0_bit==0){
i++; // Nếu có ấn thì tăng i 1 đơn vị
delay_ms(100);
}
//Kiểm tra trạng thái chân C0
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 62
if(PINC1_bit==0){
i ;// Nếu có ấn thì tăng i 1 đơn vị
delay_ms(100);
}
PORTA=i;
}
}
Với chương trình trên, ta thực hiện các thử nghiệm sau:
+Bỏ 2 hàm delay sau đó biên dịch và mô phỏng. Ta thấy, Proteus sẽ tự
động kéo giản thời gian để mô phỏng hiện tượng dội phím. Ta ấn phím 1 lần
rồi nhả ra nhưng giá trị PORTA không ngừng tăng(hoặc giảm) cho đến 1
khoảng thời gian nhất định.
Yêu cầu
Chân kết nối với phím phải cấu hình là ngõ vào
Ví dụ
bit oldstate; // Cờ trạng
thái
trước
void main() {
DDC0_bit = 0; // Cấu hình PORTC
0 là ngã
vào
DDRA = 0xFF; //Cấu hình
PORTA là ngã
ra
PORTA = 0xAA; // Tạo giá trị đ
ầu cho
PORTA
oldstate = 0;
do {
if (Button(&PINB, 0, 1, 0)) { // Phát hiện được
phím ấn
oldstate = 1; // Cập nhật cờ -
đặt
3. Chống dội phím bằng phương pháp phát hiện cạnh lên.
Lưu đồ giải thuật chống dội phím:
Có
Có
trí phím bị tác động
(từ 1 đến n) lần nữa.
Có phím bị tác
động hay
không?
Không
Có
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 65
Giải thích:
Bắt đầu chương trình con đọc phím chống dội:
+Gọi hàm đọc phím: hàm này sẽ dùng hàm Button của MikroC để đọc
trạng thái các chân kết nối với phím và trả về vị trí phím(ưu tiên các phím
có thứ tự thấp).
+Nếu hàm trả về 0 nghĩa là hiện tại không có phím bị tác động, ta xét
tiếp:
-Trước đó có phím ấn: báo là lần đọc này không có phím ấn bằng
biến pr (pr=1 thì có phím ấn và bằng 0 là không có phím ấn) và thoát ra mà
không trả về giá trị nào cả.
-Trước đó không có phím ấn: các phím đang ở trạng thái không
bị tác động nên thoát ra mà không trả về giá trị nào cả.
+Nếu hàm trả về vị trí phím bị tác động thì tại trì hoãn 20ms sau đó gọi
hàm đọc phím lần nữa.
+Nếu hàm trả về 0 nghĩa là hiện tại không có phím bị tác động, ta có thể
nói lần đọc trước đó phím bị tác động là do dội cơ khí. Thoát ra mà không
trả về giá trị nào cả.
+ Nếu hàm trả về vị trí phím bị tác động (không thể khác giá trị trước đó
vì 20ms thì người dùng ko đủ thời gian nhả phím và ấn lại phím khác) thì
char temp;
temp=Button_Read();
if(temp==0){
if(pr==1){
pr=0;
return;
}
else {
flag=1;
return;
}
}
else{
delay_ms(50);
temp=Button_Read();
if(temp==0) return;
else{
pr=1;
return temp;
}
}
}
//CHUONG TRINH CHINH
void main(){
DDRA=0xff;
DDRC=0x00;
key= Button_Read_Debounce();
if((pr!=0)&&(flag==1)){
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 67
//HAM DOC PHIM VA CHONG DOI
char Button_Read_Debounce(){
char temp;
temp=Button_Read();
if(temp==0){
if(pr==1){
pr=0;
return;
}
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 68
else {
flag=1;
return;
}
}
else{
delay_ms(50);
temp=Button_Read();
if(temp==0) return;
else{
pr=1;
return temp;
}
}
}
//CHUONG TRINH CHINH
void main(){
DDRA=0xff;
delay_ms(150);
}
break;
}
}
}
}
- Thử bỏ dòng lệnh flag=0 và kiểm tra kết quả.
- Hãy viết thêm vài ứng dụng điều khiển led cho các phím còn lại
III. Thực hành các kiểu dữ liệu.
Việc sử dụng thành thạo các kiểu dữ liệu là khá quan trọng, nó giúp ta
tránh các lỗi thông thường nhưng khó phát hiện (ví dụ như vòng lặp hữu hạn
nhưng lại lặp vô hạn).
a. Tiến hành soạn thảo và biên dịch chương trình sau :
Bai1_3_A : Thực hành các kiểu dữ liệu
// KHAI BAO CAC BIEN KIEU NGUYEN
unsigned char _unsigned_char;
signed char _signed_char;
int _signed_short;
unsigned short _unsigned_short;
unsigned int _unsigned_int;
signed long _signed_int;
char bin[10];
char i;
// KHAI BAO CAC BIEN KIEU SO THUC
float _float;
double _double;
long _long_double;
_unsigned_long
Bảng 2:
Biến Số byte Giá trị
_float
Lập trình vi điều khiển AVR với ngôn ngữ C WWW.EEELABS.ORG
Trần Thừa – 2010 71
_double
_long_double
Các bạn hãy tự thay đổi các giá trị của các biến sau đó tiến hành debug
lại chương trình, quan sát sự thay đổi các giá trị để hiểu về các kiểu dữ liệu cơ
bản.