Documentos de Académico
Documentos de Profesional
Documentos de Cultura
ORG
R1 SW2
10k BUTTON
SW1 R2
BUTTON 8k2
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.
1
R13 D2
R6
10k 330 LED
D3
R7
330 LED
9
8
7
6
5
4
3
2
J1 J2
SW1
BUTTON
1 1 D4
R8
2 2 330 LED
SW2
BUTTON 3 3
4 4
5 5 D5
SW3 R9
BUTTON 6 6 330 LED
7 7
8 8
SW4
BUTTON 9 9 D6
R10
10 10 330 LED
SW5
BUTTON
PORT_8_PIN PORT_8_PIN D7
R11
330 LED
SW6
BUTTON
D8
SW7 R12
BUTTON 330 LED
SW8
BUTTON
}
}
}
- Tiến hành biên dịch và nạp xuống board hoặc mô phỏng bằng proteus.
Hàm trì hoãn bao gồm 2 loại:
Delay_ms(đối số vào); /*trì hoãn với đơn vị mili giây và đối số vào là thời gian
cần thiết */
Delay_us(đối số vào); /*trì hoãn với đơn vị micro giây và đối số vào là thời
gian cần thiết */
Các bạn hãy tìm hiểu thêm về 2 hàm này bằng công cụ help(F1).
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.
Ví 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.
Từ các ví dụ trên, ta có thể thấy sự tương quan dữ liệu của thanh ghi
PORTA và các chân PORTA. Các led chính là mô hình của các bit có giá trị 0
và 1 được thay đổi liên tục thông qua các toán tử.
Các trường hợp trên, ta đã tìm ra quy luật của sự thay đổi trạng thái của
các led như yêu cầu. Thực tế đôi khi ta chưa tìm ra quy luật vận động của dữ
liệu, trong trường hợp đó ta có thể dùng phương pháp lựa chọn và gán các dữ
liệu cần thiết vào mảng.
Ví dụ 3: Viết lại chương trình của ví dụ 2.
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.
- Chương trình trên là chương trình đọc phím đơn giản, nó đọc giá trị
nhận được ở PORTC và xuất ra led để hiển thị trạng thái của PORTC.
- Chạy mô phỏng chương trình và xem kết quả. Ta thấy, thời gian đáp
ứng rất nhanh, trong ứng dụng này ta không cảm nhận được hiện tượng dội
cơ khí.
- Chương trình tiếp theo có yêu cầu là: khi nhấn phím 1( kết nối với
PORTC0) thì giá trị PORTA tăng 1 đơn vị, ấn phím 2 ( kết nối với PORTC1)
thì giá trị phím giảm 1 đơn vị (PORTA hiển thị giá trị nhị phân).
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
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.
+Thay đổi giá trị thời gian trì hoãn của 2 hàm delay, ta thấy thời gian trì
hoãn có tác dụng nhất định, nó bỏ qua giai đoạn xuất hiện các chuỗi xung
không mong muốn.
Chương trình trên vẫn chưa sử dụng được vì phím không nhạy (cần thời
gian trì hoãn nhiều) và nếu ấn giữ thì phím sẽ thực hiện công việc liên tục.
Ta sẽ nghiên cứu thêm về phương pháp chống dội phím ở phần sau.
Để truy xuất từng bit (từng chân) của các PORT ta xử lý các biến sau:
+Nhận dữ liệu: PINxy_bit với x là tên PORT, y là tên chân .
+Xuất dữ liệu : PORTxy_bit với x là tên PORT, y là tên chân .
Ví dụ : PORTA1_bit=PINC1_bit ;
2. Chống dội phím với thư viện có sẵn của MikroC.
MikroC cung cấp cho chúng ta 1 thư viện phím (nút nhấn - button). Để
sử dụng thư viện này, ta phải khai báo bằng cách dùng công cụ Library
manager(View>Library Manager).
Sau đây là bảng tóm tắt về hàm button trong thư viện này:
Mô tả -port: tên thanh ghi PINx của port mà phím đang kết nối vào
-pin: Chân của port mà phím kết nối có giá trị từ 0-7
-time: thời gian trì hoãn để chống dội phím (khoảng 100ms)
Yêu cầu Chân kết nối với phím phải cấu hình là ngõ vào
bit oldstate; // Cờ trạng thái
Ví dụ trước
void main() {
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
}
if (oldstate && Button(&PINB, 0, 1, 0)) {
//Trước đó có phím ấn và bây giờ có phím ấn thì thực
hiện
PORTC = ~PORTC; // Đảo PORTC
oldstate = 0; // Cập nhật cờ -
xóa
}
} while(1); // Vòng lặp mãi
mãi
}
Hãy biên dịch và chạy mô phỏng ví dụ trên, đã có sự cải tiến khi dùng
biến oldstate (trạng thái cũ) để kiểm tra xem tín hiệu nhận vào đã ổn định chưa
rồi mới thực thi. Tuy nhiên, khi bỏ qua thời gian delay (thời gian delay trong
chương trình trên = 1 xem như bỏ qua) thì công việc thực thi quá nhanh khiến
người dùng không kiểm soát được. Vì vậy ta tiến hành xây dựng 1 chương
trình chống dội phím khác với yêu cầu đặt ra là:
+ Thực thi công việc 1 lần ngay sau khi ấn phím.
+ Công việc chỉ thực hiện lần nữa khi nhả phím và ấn lại lần nữa.
+Khi giữ phím thì các công việc khác(các đoạn lệnh khác của chương
trình) vẫn hoạt động bình thường.
Từ các yêu cầu trên, ta tham khảo giải thuật chống dội phím ở phần tiếp
theo.
3. Chống dội phím bằng phương pháp phát hiện cạnh lên.
Có
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ì
khẳng định đã có phím được ấn. Thoát khỏi hàm đọc phím – chống dội và
trả về vị trí phím đọc được.
Chương trình chính sẽ lấy giá trị phím đọc được đem đi xử lý. Điều kiện
xử lý là:
Vị trí phím mới nhận được là số liệu mới(đã nhả phím và ấn phím).
Phải có điều kiện này là do nếu lần sau không có phím nhấn, số liệu cũ
vẫn còn nên chương trình sẽ xử lý tiếp gây sai yêu cầu.
Điều kiện số liệu nhận được là số liệu mới ta thực hiện như sau:
+Sau khi thực hiện công việc xong thì xóa biến flag để báo là xử lý xong
không cho phép xử lý tiếp.
+Nếu không có phím ấn nữa thì đặt lại flag để báo là đã nhả phím.
+Trước khi xử lý công việc thì kiểm tra là có phím nhấn(pr=1) và trước
đó đã nhả phím (flag=1).
Sau đây là code tham khảo:
char Button_Read(){
if(Button(&PINC,0,10,0)) return 1;
if(Button(&PINC,1,10,0)) return 2;
if(Button(&PINC,2,10,0)) return 3;
if(Button(&PINC,3,10,0)) return 4;
return 0;
}
//HAM DOC PHIM VA CHONG DOI
char Button_Read_Debounce(){
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)){
flag=0;
công việc ;
}
}
Thực hành kết hợp ứng dụng đọc phím và điều khiển led.
Tạo file nguồn mới với tên là BAI1_TH1. Soạn thảo và biên dịch
chương trình với yêu cầu sau :
+Dùng 2 phím nhấn điều khiển 8 led.
+Khi ấn phím thứ nhất các led sáng dần từ trái sang phải rồi tắt dần từ trái sang
phải.
+Khi ấn phím thứ hai thì led sáng từ 2 biên vào rồi tắt từ biên vào.
Bài tham khảo :
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;
while(1){
key= Button_Read_Debounce();
if((pr==1)&&(flag==1)){
flag=0;
switch(key){
case 1:
PORTA=0x00;
for(i=0;i<=7;i++){
PORTA=0x01<<i|PORTA;
delay_ms(50);
}
for(i=0;i<=7;i++){
PORTA=0xFE<<i&PORTA;
delay_ms(50);
}
break;
case 2:
PORTA=0x00;
for(i=0;i<=3;i++){
PORTA=0x01<<i|0x80>>i|PORTA;
delay_ms(150);
}
for(i=0;i<=3;i++){
PORTA=0x7F>>i&0xFE<<i&PORTA;
delay_ms(150);
}
break;
}
}
}
}
Dùng công cụ debuger (F9) để chạy mô phỏng chương trình rồi điền kết quả
vào bảng sau :
Bảng 1 :
_unsigned_char
_signed_char
_signed_short
_unsigned_short
_signed_int
_unsigned_int
_signed_long
_unsigned_long
Bảng 2:
_float
_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.