Để chạy 1 dòng chữ qua ma trận led, bạn sẽ có 1 buffer lưu toàn bộ dòng chữ đó. Buffer này thường là 1 mảng các byte. Chương trình sẽ định kì cắt 1 phần trong buffer này đổ dữ liệu vào buffer nhỏ hơn dùng để quét led. Chương trình quét led sẽ hiển thị ra led ma trận.
Tại thời điểm T1, dữ liệu đổ vào buffer quét led là chữ “H”. Tại thời điểm T2, 1 phần chữ H và E được đổ vào buffer này, và tại thời điểm T3 là chữ “E”. Nếu khoảng cách giữa các thời điểm nhỏ lại, bạn sẽ thấy hiệu ứng dòng chữu chạy qua ma trận led.
Để sinh ra được buffer chứa toàn bộ dòng chữ, bạn phải xử lý dữ liệu đã lưu sẵn (tạm gọi là font chữ), ghép nối chúng sao cho đẹp mắt. Chẳng hạn muốn hiện chữ “HELLO WORLD”,bạn phải làm như sau:
Ø Lấy font của chữ “H”, bỏ những cột trống ở đầu và cuối, phần còn lại bỏ vào buffer.
Ø Lấy font của chữ “E”, bỏ những cột trống ở đầu và cuối,thêm 1 byte 0x00 vào buffer (tạo 1 nét rời giữa H và E) rồi bỏ dữ liệu của E vào.
Ø Tương tự, hết chữ “O”, bạn thêm khoảng 3 byte 0x00.
Tuỳ vào tài nguyên của hệ thống, bạn định nghĩa ra độ dài tối đa của buffer này. Trong quá trình sinh ra buffer, chương trình sẽ cập nhật độ dài hiện tại và sẽ dừng việc ghép chữ nếu độ dài là quá mức cho phép.
9.2 Kết nối phần cứng
Gạt switch 3 lên ON để kích hoạt ma trận led.
9.3 Viết chương trình
Chương trình sẽ gồm 3 group là TIMER, LED MATRIX và MAIN. Các group TIMER và LED MATRIX được dùng lại. Trong file led_matrix.h ta khai báo thêm 1 hàm cung cấp cho người dùng:
void set_message(char strMsg[]);
Hàm này cho phép người dùng thay đổi nội dung chữ chạy qua ma trận led. Ví dụ gọi set_message(“HELLO WORLD”).
Để xử lý chuỗi trong KeilC, bạn include thêm 2 thư viện sau ở đầu file led_matrix.c:
#include <stdlib.h> #include <string.h>
Dữ liệu của buffer lớn gồm có 100 cột, biến total_length dùng để lưu độ dài hiện tại của mảng buffer này:
unsigned char data_buff[100]; int total_length;
Mảng alphabet_upcase_led_matrix là dữ liệu font của các chữ cái in hoa. Trong chương trình này chỉ hiển thị được các chữ cái in hoa, không bao gồm các chữ cái thường và các kí tự số. 9.3.1 Hàm set_message(char strMsg[]) void set_message(char strMsg[]) { int length; int i; int j; int index_char; length = strlen(strMsg); //fill data into data_buff for(i=0;i<length;i++) {
index_char = (strMsg[i] - 'A')*8; //position to get font data if(strMsg[i] != ' ') //is not blank character
{
for(j=index_char;;j++)//remove 0x00 at the begining {
if(alphabet_upcase_led_matrix[j] != 0x00) break;
}
BKIT HARDWARE CLUB www.bkit4u.com 61
data_buff[total_length++]= alphabet_upcase_led_matrix[j];
} }
else //blank character,add 3 bytes 0x00 { if(total_length != 100) data_buff[total_length++] = 0x00; if(total_length != 100) data_buff[total_length++] = 0x00; if(total_length != 100) data_buff[total_length++] = 0x00; } } } 9.3.2 Hàm main() void main() { init_main();
init_timer0(); //use for scan led
init_timer1(); //use for delay_ms() function init_led_matrix(); //initiate led matrix
set_message("HELLO WORLD"); while(1) { delay_ms (300); update_display_led_matrix(); } }
Hàm update_display_led_matrix() tăng con trỏ alphabet_index để lấy dữ liệu trong data_buff bỏ vào red_buff và green buff. Biến alphabet_index được khởi tạo là -8 với ý nghĩa ở trạng thái đầu tiên màn hình led 7 đoạn không hiển thị gì cả. Khi hiện thực hàm này bạn chú ý kiểm tra điều kiện của alphabet_index để lấy dữ liệu cho đúng. Chi tiết của chương trình các bạn tham khảo tại thư mục Bai 9.
Bài 10 : Ngắt ngoài
Mục đích:
Nắm vững kĩ thuật điều khiển ngắt ngoài.
Yêu cầu:
Viết chương trình khi có ngắt ngoài 0 thì tăng biến đếm lên 1, ngắt ngoài 1 thì giảm đi 1, xuất giá trị ra led 7 đoạn.
10.1 Nguyên lý điều khiển ngắt ngoài
Ngắt ngoài có 2 loại : Ngắt cạnh và ngắt mức.
Ø Ngắt cạnh cũng có 2 loại : ngắt cạnh lên xảy ra khi có sự chuyển tín hiệu từ mức thấp lên mức cao ở chân ngắt ngoài. Tương tự ngắt cạnh xuống xảy ra khi có sự chuyển tín hiệu từ mức cao xuống mức thấp.
Ø Ngắt mức cũng có 2 loại : ngắt mức cao và mức thấp. Ngắt mức cao xảy ra khi tín hiệu tại chân ngắt ngoài ở mức cao trong tối thiểu 1 chu kì.
Trong vi điều khiển P89V51RB2, hỗ trợ 2 loại ngắt ngoài : ngắt cạnh xuống và ngắt mức thấp. Việc cấu hình cho ngắt ngoài dựa vào bit ITn trong thanh ghi TCON.
10.2 Kết nối phần cứng
Hai ngắt ngoài được mắc vào nút nhấn, tại chân P3.2 là ngắt ngoài 0 và P3.3 là ngắt ngoài 1.
Gạt switch 4 lên ON để kích hoạt led 7 đoạn.
10.3 Viết chương trình
Module ngắt ngoài khá đơn giản, gồm các hàm khởi tạo được khai báo trong file ext_int.h :
void init_ext_int0(); void init_ext_int1();
Các hàm này được hiện thực trong file ext_int.c cùng với 2 hàm phục vụ ngắt ngắt ngoài. Code xử lý trong bài mẫu này khá đơn giản, chỉ là việc cộng và trừ biến count rồi dùng biến này để hiển thị giá trị tương ứng ra led 7 đoạn.
10.3.1 Hàm init_ext_int0()
void init_ext_int0() {
IE &= ~(0x01);// enable external interrupt 0 IE |= 0x01; IT0 = 1; } 10.3.2 Hàm init_ext_int1() void init_ext_int1() {
BKIT HARDWARE CLUB www.bkit4u.com 63
IE |= 0x04; IT1 = 1; }
10.3.3 Hàm ext0_isr()
Đây là hàm phục vụ ngắt ngoài 0.
void ext0_isr() interrupt 0 {
//Add your code here if(count<9)
count++; }
10.3.4 Hàm ext1_isr()
Đây là hàm phục vụ ngắt ngoài 1.
void ext0_isr() interrupt 1 {
//Add your code here if(count>0)
count--; }
Bài 11 : Điều khiển encoder
Mục đích:
Hiểu được nguyên lý hoạt động của encoder. Nắm vững kĩ thuật điều khiển encoder bằng ngắt ngoài.
Yêu cầu:
Xây dựng chương trình đọc số xung encoder và hiển thị giá trị ra led 7 đoạn.
11.1 Nguyên lý điều khiển encoder
Encoder là thiết bị cảm biến được dùng phổ biến trong các ứng dụng cần đo khoảng cách, vận tốc hoặc trong các ứng dụng cần độ chính xác cao. Hình dạng thực tế của encoder như sau:
Cấu tạo của encoder gồm 1 vòng tròn, trên đó xẻ nhiều rãnh (còn gọi là đĩa), và 1 mạch cảm biến để phát xung
Số rãnh trên đĩa gọi là độ phân giải hay số xung của encoder. Đối với encoder có độ phân giải thấp (dưới 200 xung) thì đĩa này là đĩa thép. Đối với các encoder có độ phân giải cao, cỡ 1000 xung, thì đĩa này được làm bằng đĩa từ, encoder như vậy còn gọi là
BKIT HARDWARE CLUB www.bkit4u.com 65 Tín hiệu trả về của encoder có 3 kênh A, B và Z. Thông thường ta sử dụng 2 kênh A và B là đủ thông tin cho quãng đường và chiều quay của encoder. Tín hiệu trả về trên 2 kênh này như sau :
Như vậy nếu ta đưa tín hiệu A vào chân ngắt ngoài và cấu hình là ngắt cạnh lên, thì khi tín hiệu B ở mức cao là chiều quay thuận của encoder, khi B ở mức thấp là chiều quay ngược lại.
11.2 Kết nối phần cứng
Gạt switch 4 lên ON để kích hoạt led 7 đoạn.
Kết nối với encoder gồm 4 chân : VCC, GND, A và B vào board. Tín hiệu A được nối vào P3.2 gây ra ngắt ngoài 0, tín hiệu B nối với P3.5
11.3 Viết chương trình
Chương trình gồm có 3 group : TIMER dùng để quét led, hiển thị giá trị encoder ra led 7 đoạn; EXT_INT dùng để cập nhật giá trị encoder mỗi khi có ngắt ngoài 0 ở chân P3.2, MAIN chứa file main.c là chương trình chính để chạy.
Chương trình trong bài này hoàn toàn tương tự như bài trước, đoạn code trong hàm phục vụ ngắt ngoài sửa đổi lại như sau:
void ext0_isr() interrupt 0 { if(P3 & (1 << 5)) pulse ++; else pulse --; }
Biến pulse được khai báo là unsigned int, dùng để lưu trữ giá trị của encoder.
Để xuất giá trị encoder ra led 7 đoạn, ta thêm 2 dòng lệnh sau trong hàm phục vụ ngắt timer 0:
set_position(2); put_number(pulse);
Hàm main() chỉ đơn giản là khởi tạo các thông số cần thiết và sau đó loop vô tận. Tất cả mọi công việc sẽ do các hàm phục vụ ngắt quãng thực hiện. Đây là 1 mô hình lập trình cơ bản của vi điều khiển trong các ứng dụng thực tế. Chi tiết code các bạn xem thêm trong thư mục Bài 11.
BKIT HARDWARE CLUB www.bkit4u.com 67
Bài 12 : Giao tiếp UART
Mục đích:
Nắm vững giao tiếp Uart.
Yêu cầu:
Xây dựng ứng dụng giao tiếp giữa board 89 và máy tính thông qua cổng COM.
12.1 Nguyên lý giao tiếp UART
Uart RS232 là chuẩn giao tiếp khá phổ biến và được hỗ trợ ở hầu hết các dòng vi điều khiển vì khoảng cách xa và chi phí thấp. Dòng 8051 hỗ trợ 1 kênh giao tiếp uart.
Dữ liệu được truyền đi trên chân TX gồm 1 start bit (mức 0), data và 1 stop bit (mức 1).
Tốc độ truyền : đơn vị bit per second (bps) còn gọi là Baud (số lần thay đổi tín hiệu trong 1 giây – thường sử dụng cho modem). Đối với đường truyền thì Baud và bps là như nhau.
UART là phương thức truyền nhận bất đồng bộ. nghĩa là bên nhận và bên phát không cần phải có chung tốc độ xung clock (ví dụ : xung clock của vi điều khiển khác xung clock của máy tính) . Khi đó bên truyền muốn truyền dữ liệu sẽ gửi start bit (bit 0) để báo cho bên thu biết để bắt đầu nhận dữ liệu và khi truyền xong dữ liệu thì stop bit (bit 1) sẽ được gửi để báo cho bên thu biết kết thúc quá trình truyền.
Khi có start bit thì cả hai bên sẽ dùng chung 1 xung clock (có thể sai khác một ít) với độ rộng 1 tín hiệu (0 hoặc 1) được quy định bởi baud rate, ví dụ baud rate = 9600bps nghĩa là độ rộng của tín hiệu 0(hoặc 1) là 1/9600 = 104 ms và khi phát thì bên phát sẽ dùng baud rate chính xác (ví dụ 9600bps) còn bên thu có thể dùng baud rate sai lêch 1 ít(9800bps chẳng hạn).
Truyền bất đồng bộ sẽ truyển theo từng frame và mỗi frame có cấu trúc như sau:
Stop bit--B7--B6-- B5-- B4-- B3-- B2-- B1-- B0-- Start bit
Ngoài ra trong frame truyền có thể có thêm bit odd parity (bit lẻ) hoặc even parity (bit chẵn) để kiểm tra lỗi trong quá trình truyền. Bit parity này có đặc điểm nếu sử dụng odd parity thì số các bit 1 + odd parity bit sẽ ra 1 số lẻ còn nếu sử dụng even parity thì số các bit 1 + even parity bit sẽ ra 1 số chẵn.
12.2 Giao tiếp UART với máy tính
Để giao tiếp COM giữa vi điều khiển và máy tính, ta kết nối mạch theo sơ đồ như sau:
Do mức điện áp của tín hiệu logic 1/0 ở cổng COM của máy tính khác với vi điều khiển, nên MAX 232 có tác dụng chuẩn hoá mức điện áp giữa máy tính và điều khiển trong quá trình truyền nhận dữ liệu. Nếu giao tiếp trực tiếp giữa 2 vi điều khiển, ta không cần phải sử dụng MAX 232.
BKIT HARDWARE CLUB www.bkit4u.com 69
12.3 Viết chương trình
12.3.1 Thanh ghi điều khiển truyền nhận nối tiếp
Vi điều khiển 8051 có hai chân dùng trong truyền nhận nối tiếp là RxD(nhận dữ liệu ứng với chân P3.0) và TxD(phát dữ liệu ứng với chân P3.1), ngoài ra còn sử dụng bộ đệm SBUF để lưu dữ liệu thu khi nhận và dữ liệu phát khi truyền và thanh ghi SCON(Serial Control) để truy xuất port nối tiếp.
Bộ đệm SBUF có địa chỉ byte là 99h, thực tế có hai bộ đệm là bộ đệm thu (chi đọc) dùng trong nhận dữ liệu và bộ đệm phát (chỉ ghi) dùng trong phát dữ liệu.
Thanh ghi SCON có địa chỉ byte là 98h là thanh ghi có thể định địa chỉ từng bit dùng để thiết lập chế độ hoạt động của port nối tiếp và các bit trạng thái chỉ sự kết thúc việc thu hoặc phát dữ liệu.
Bit Kí hiệu Chức năng
SCON.7 SM0/FE
Cách dùng của bit này được định nghĩa bằng giá trị của bit SMOD0 trong thanh ghi PCON, nếu SMOD=0, bit này được đọc và viêt là SM0, nó với bit SM1 định nghĩa chế độ hoạt động của cổng nối tiếp. Nếu SMOD0=1, bit này được đọc và viết là FE (khung lỗi). FE được set trong quá trình nhận khi phát hiện bit dừng không hợp lệ, và nó chỉ được xóa bởi phần mềm. (chú ý rằng các chế độ UART nên được lập trình(thông qua SM0 và SM1) khi SMOD0=’0’-chế độ mặc định sau các quá trình RESET)
SM1 Cùng với SM0, xác định chế độ làm việc của cổng nối tiếp
SM0,
SM1 Chế độ UART UART 0 Baud Rate
0 0 0: thanh ghi dịch CCLK/16 (chế độ mặc định sau khi RESET)
0 1 1: UART 8-bit Thay đổi
1 0 2: UART 9-bit CCLK/32 hoặc CCLK/16 SCON.6
1 1 3: UART 9-bit Thay đổi
SCON.5 SM2
Cho phép truyền thông đa xử lý. Ở Mode 2 và 3, nếu SM2 được lập, RI sẽ không tích cực nếu bit dữ liệu nhận thứ 9 (RB8) là ‘0’. Ở Mode 0, SM2 nên bằng ‘0’, ở mode 1, SM2 phải bằng ‘0’.
SCON.4 REN
Cho phép thu ở cổng nối tiếp. Thiết lập bởi phần mềm để cho phép thu. Xóa bởi phần mềm khi không cho phép thu,REN = 1 trong tất cả 4 chế độ tuyền nhận.
SCON.3 TB8 Bit dữ liệu thứ 9 được phát ở mode 2 và 3, lập/xóa bởi phần mềm khi muốn.
SCON.2 RB8
Bit dữ liệu thứ 9 được nhận ở mode 2 và 3. Ở mode 1(SM2=0), RB8 là bit dừng được nhận, ở mode 0, RB8 không được định nghĩa.
SCON.1 TI
Cờ ngắt phát(truyền nối tiếp), lập bởi phần cứng ở cuối bit thứ 8 ở mode 0, hay là ở bit dừng của các chế độ còn lại, phải được xóa bằng phần mềm. (Xem thêm bit INTL0 ở thanh ghi SSTAT)
SCON.0 RI
Cờ ngắt thu, lập bởi phần cứng ở cuối bit thứ 8 trong mode 0, hay khoảng giữa bit dừng ở mode 1. với mode 2 và mode 3, nếu SMOD0=0, nó được lập gần khoảng giữa bit dữ liệu thứ 9 (bit 8). Nếu SMOD0=1, nó được lập gần khỏang giữa bit dừng. Phải được xóa bởi phần mềm.
Các chế độ truyền nối tiếp:
· Chế độ 0: ở chế độ này chân RxD sẽ vửa làm nhiệm vụ thu và phát dữ liệu còn chân TxD làm nhiệm vụ phát xung dịch bit(Shift Clock) vói tốc độ sung bằng 1/12 tốc độ xung của XTAL.Dữ liệu truyền đi gồm 8 bit với bit LSB được truyền hoặc nhận trước. Ứng dụng của chế độ này là mở rộng ngõ ra cho 8051 từ 2 đường TxD,RxD sẽ tạo ra 8 đường mở rộng.
8051 TxD(P3.1)
RxD(P3.0)
CLOCK Shift register
BKIT HARDWARE CLUB www.bkit4u.com 71 · Chế độ 1: là chế độ truyền với mỗi frame có 10 bits (bit start – 8 bits data – bit stop) ,tốc độ baud rate có thể thay đổi được tùy vào cách khởi tạo ban đầu.Có thể nhân đôi tốc độ truyền bằng cách bật PCON.7 = 1.
· Chế độ 2: là chế độ truyền với mỗi frame có 11 bits (bit start – 8 bits data – bit parity – bit stop),bit parity được đặt trong TB8 khi phát và được đặt trong RB8 khi thu, tốc độ baud rate ở chế độ này không thay đổi được và bằng 1/64 dao động của XTAL (1/32 dao động của XTAL nếu PCON.7 = 1).
· Chế độ 3: có chức năng tương tự như chế độ 2 nhưng tốc độ baud rate có thể thay đổi được như ở chể độ 1.
Tốc độ Baud : Tốc độ (Baud) của cổng 8051 phải phù hợp với máy tính: 100, 150, 300, 600, 1200, 2400, 4800, 9600, 19200. Khuyến cáo dùng thạch anh có tần số 11.0592Mhz để có thể tạo ra tốc độ Baud với sai số thấp (gần như là 0).
12.3.2 Dùng Timer1 tạo Baud rate
Timer 1 được dùng để tạo tốc độ baud cho truyền nối tiếp ,cần phải đặt Timer 1 ở Mode 2 – 8 bit tự nạp lại, nếu đặt ở chế độ khác sẽ tốn vài chu kỳ máy cho quá trình thiết lập lại giá trị cho TH1,TL1.
Đặt TH1 theo bảng sao để có tốc độ Baud tương ứng với SMOD = 0 (bit D7 trong thanh ghi PCON, XTAL = 11.0592 MHz) :
Tốc độ Baud TH1 (Thập phân) TH1 (Hexa)
9600 -3 ED
4800 -6 FA
2400 -12 F4
1200 -24 E8
Tốc độ Baud rate sẽ nhân đôi khi SMOD = 1.
12.3.3 Chương trình truyền nhận UART trên 8051
v Hàm init_timer1() sẽ thiết lập Timer1 tạo tốc độ baud cho truyền nối tiếp
void init_timer1() {
TMOD &= ~(0x20);// setup mode for timer 1