Click here to load reader
Upload
jean-okio
View
2.754
Download
1
Embed Size (px)
DESCRIPTION
giao tiếp LCD với 8051
Citation preview
1
ĐIỀU KHIỂN LCD BẰNG 8051 VỚI BUS 8 BIT
Created by Nguyen Duc Minh. 15-04-2009
CƠ BẢN VỀ LCD VÀ 44780
- Giao tiếp với LCD có hai cách 4 bít (cần 7 đường dây) và 8 bít (cần 11 đường
dây). LCD có 3 đường điều khiển: RS, EN và RW.
- Muốn giao tiếp với LCD trước hết cần sử dụng chân EN (enable=cho phép). Chân
này dùng để thông báo với LCD rằng ta đang gửi dữ liệu. Để gửi dữ liệu tới LCD
chương trình của bạn phải bảo đảm chân EN ở mức thấp (low=0),sau đó thiết lập
các chân dữ liệu và 2 chân điều khiển còn lại. Khi các chân này sẵn sàng, thiết lập
mức cao cho chân EN trong một quãng thời gian nhất định tuỳ thuộc vào LCD mà
bạn dùng (xem datasheet của từng LCD cụ thể) sau đó lại đưa chân EN về mức
thấp.
- Đường dây RS (register select=lựa chọn thanh ghi). Khi RS ở mức thấp, dữ liệu
được xem như là một lệnh hoặc một lệnh đặc biệt (ví dụ như xoá màn hình, đặt vị
trí con trỏ, vvv). Khi RS ở mức 1 (cao=high) dữ liệu đang được gửi là dữ liệu dạng
văn bản (text), dữ liệu này có thể được hiển thị lên màn hình LCD. Ví dụ để hiển
thị chữ “M” lên màn hình LCD bạn phải thiết lập cho chân RS ở mức cao “1”.
- Chân RW là đường điều khiển ghi/đọc (read/write). Khi RW ở mức thấp (0),
thông tin trên bus dữ liệu được ghi vào LCD. Khi RW ở mức cao („1‟) chương
trình sẽ đọc LCD. Chỉ duy nhất một lệnh Get LCD status=đọc trạng thái LCD là
lệnh đọc, còn lại tất cả đều là lệnh ghi. Do vậy chân RW gần như luôn luôn ở mức
thấp (0).
- Bus dữ liệu bao gồm 4 hoặc 8 đường dây (tuỳ thuộc vào chế độ hoạt động mà
người dùng lựa chọn). Trong trường hợp bus dữ liệu là 8 bít, các đường dây được
sử dụng là DB0....DB7.
- Ví dụ cấu hình phần cứng: Như chúng ta đã nói ở trên LCD cần 8 hoặc 11 đường
dây để giao tiếp. Chúng ta xét trường hợp sử dụng 8 bít dữ liệu (bus 8 bít DB0-
DB7) do vậy cần 11 đường dây giao tiếp. Dưới đây là sơ đồ đơn giản nhất nối
LCD với 8051.
2
Như thấy trên hình vẽ chúng ta đang thiết lập mối quan hệ 1-1 giữa các chân của
VĐK 8051 với LCD44780. Khi chúng ta viết chương trình assembly để truy cập
LCD chúng ta coi tương đương các chân của cổng 1và 3 của vi điều khiển 8051
bằng với các chân dữ liệu và điều khiển tương ứng của của LCD bằng cách khai
báo:
DB0 EQU P1.0
DB1 EQU P1.1
DB2 EQU P1.2
DB3 EQU P1.3
DB4 EQU P1.4
DB5 EQU P1.5
DB6 EQU P1.6
DB7 EQU P1.7
EN EQU P3.7
RS EQU P3.6
RW EQU P3.5
DATA EQU P1
Với các thiết lập như trên chúng ta có thể chúng ta có thể tham chiếu tới các
đường dây I/O của một cổng của vi điều khiển 8052 với tên của các chân LCD
tương ứng. Ví dụ để thiết lập chân RW lên mức cao chúng ta có lệnh:
SETB RW ; (sét bít cổng P3.5 lên 1)
Cũng như vậy, chúng ta có thể xoá đường dây EN bằng lệnh
CLR EN ;clear EN=P3.7
- Các thao tác với đường dây điều khiển EN (enable)
3
Như đã đề cập ở trên, đường dây EN được dùng để nói với LCD rằng bạn đã sẵn
sàng để thực thi một lệnh mà bạn đã chuẩn bị trên bus dữ liệu và trên các đường
dây điều khiển khác. Chú ý rằng đường dây điều khiển EN phải được lên mức cao
trước khi một lệnh được gửi tới LCD hoặc xuống mức thấp sau khi một lệnh được
gửi tới LCD ngoại trừ trường hợp mà ở đó lệnh là đọc hoặc ghi, văn bản (text)
hoặc lệnh (instruction). Tóm lại, bạn phải luôn luôn xắp xếp EN sao cho khi trao
đổi tin với LCD thì EN là cách mà LCD biết được bạn đang nói chuyện với nó.
Nếu bạn không lập/xoá chân EN một cách phù hợp thì LCD không bao giờ hiểu
được rằng bạn đang nói chuyện với nó.
Do vậy trước khi tương tác với LCD theo bất kỳ cách nào, bạn sẽ luôn phải đưa
chân EN về mức thấp bằng lệnh sau:
CLR EN
Sau đó khi đã hoàn thành việc thiết lập lệnh của chúng ta với các chân điều khiển
khác và bus dữ liệu, chúng ta luôn phải đưa chân EN về mức cao:
SETB EN
Đường dây EN phải giữ ở mức cao trong một khoảng thời gian nhất định tuỳ theo
datasheet của từng loại LCD. Thông thường nó vào khoảng 250 nano giây, nhưng
tốt nhất là nên kiểm tra lại trong datasheet cho chắc ăn. Trong trường hợp 8051
chạy với đồng hồ thạch anh 12MHz một lệnh cần 1,08uS để thực thi do vậy chân
EN có thể thoả mãn điều kiện 280 nano giây ở mức cao chỉ trong 1lệnh. Tuy nhiên
với các vi điều khiển nhanh hơn (ví dụ như DS89C420 thực hiện 1 lệnh trong 90
nano giây với tần số thạch anh 11,0592MHz thì chúng ta cần một số lệnh NOP để
tạo ra độ trễ trong khi EN vẫn giữ ở mức cao). Số lệnh NOP (No-
operation=Không làm gì cả) phải chèn vào tuỳ thuộc vào loại vi điều khiển bạn
dùng và tần số thạch anh mà bạn chọn.
Lệnh này được thực thi bởi LCD tại thời điểm đường dây EN chuyển xuống mức
thấp với lệnh CLR EN cuối cùng.
Chú ý: LCD biên dịch và thực thi lệnh của chúng ta ngay tại thời điểm chân EN được
đưa xuống mức thấp. Nếu bạn không bao giờ đưa chân EN xuống mức thấp thì lệnh của bạn
không bao giờ được thực thi.Hơn nữa khi bạn đưa chân EN xuống mức thấp và LCD thực thi lệnh
của bạn, nó yêu cầu một khoảng thời gian xác định nào đó để thực hiện lệnh. Thời gian cần thiết
để thực thi một lệnh tuỳ thuộc vào lệnh và tốc độ của thạch anh được gắn với lối vào bộ tạo dao
động của LCD 44780.
KIỂM TRA TRẠNG THÁI BẬN CỦA LCD
Như đã biết, LCD phải cần một quãng thời gian để thực hiện lệnh, phương pháp
chờ đợi thì không được “mềm dẻo” lắm, nếu tần số thạch anh được thay đổi thì
4
phần mềm viết trên 8051 cũng phải thay đổi theo, cũng giống như khi thay đổi
một LCD khác tương thích với LCD HD44780.
Nhiều phương pháp lập trình sử dụng lệnh “Get LCD Status” để xác định xem
rằng có phải LCD vẫn đang bận thực thi lệnh cuối cùng nhận được hay không.
Lệnh “Get LCD status” sẽ trả lại cho chúng ta hai bít thông tin (tidbit) hữu
ích.Thông tin hữu ích cho chúng ta bây giờ là bit DB7. Nhìn chung khi chúng ta
đưa ra lệnh “Get LCD Status” thì LCD sẽ ngay lập tức lập bít DB7 hoặc xoá bít
DB7 để thể hiện rằng LCD không bận nữa. Chương trình của chúng ta có thể
“hỏi” LCD một cách liên tục cho tới khi DB7 chuyển xuống mức thấp thể hiện
rằng LCD không còn bận nữa. Khi đó chúng ta có thể tự do tiếp tục và gửi lệnh
tiếp theo. Như vậy chúng ta có thể sử dụng đoạn mã sau đây mỗi khi chúng ta gửi
một lệnh tới LCD. Tốt nhất là viết nó thành một đoản trình như sau:
WAIT_LCD:
CLR EN ;Start LCD command CLR RS ;It's a command
SETB RW ;It's a read command MOV DATA,#0FFh ;Set all pins to FF initially SETB EN ;Clock out command to LCD
MOV A,DATA ;Read the return value JB ACC.7,WAIT_LCD ;If bit 7 high, LCD still busy
CLR EN ;Finish the command CLR RW ;Turn off RW for future commands RET
Bài thực tập của chúng ta sẽ gửi một lệnh đến LCD và gọi chương trình WAIT_LCD cho
tới khi lệnh đó được thực hiện hoàn tất bởi LCD. Điều này cũng sẽ bảo đảm rằng chương
trình của chúng ta phù hợp cho mọi LCD mặc cho nó nhanh hay chậm mức nào.
Chú ý: đoản trình trên thực hiện công việc là “chờ” LCD, nhưng khi sử dụng trong các ứng dụng
thực tế chúng ta cần cải thiện một chút: khi ghi vào LCD, nếu LCD trở nên “Không bao giờ hết bận” thì
chương trình của chúng ta sẽ dẫn đến bị “treo” để chờ DB7 chuyển xuống mức thấp. Nếu điều này không
bao giờ xảy ra (DB7 chuyển xuống mức thấp) thì chương trình sẽ bị đóng băng (rơi vào 1 vòng lặp bất
tận). Tất nhiên là điều này không bao giờ xảy ra và sẽ không xảy ra khi phần cứng làm việc tốt. Nhưng
trong các ứng dụng thực tế sẽ là sáng suốt khi chúng ta đặt một kiểu hạn chế thời gian vào độ trễ. Ví
dụ:một giá trị max bằng 256 để chờ tín hiệu bận chuyển xuống mức thấp. Điều này sẽ bảo đảm rằng ngay
cả khi LCD lỗi chương trình cũng sẽ không bị đóng băng.
KHỞI TẠO LCD
5
Trước khi có thể thực sự sử dụng LCD, chúng ta phải khởi tạo và config nó. Việc này
được thực hiện bằng cách gửi một số lệnh khởi tạo tới LCD.
Lệnh đầu tiên chúng ta gửi tới LCD phải nói cho LCD biết chúng ta trao đổi với LCD
theo chế độ 4 bít hay 8 bít (bus 4 bít hay 8 bít). Chúng ta cũng phải lựa chọn font ký tự
5x8 cho LCD. Hai lựa cọn này được thực hiện bằng việc gửi giá trị 38h tới LCD như là
một lệnh. Ở phần trước chúng ta thấy rằng đường dây RS phải ở mức thấp nếu chúng ta
đang gửi một lệnh tới LCD. Do vậy để gửi lệnh 38h tới LCD chúng ta phải thực hiện lệnh
sau đây của 8051:
CLR RS
MOV DATA,#38h
SETB EN
CLR EN
LCALL WAIT_LCD
Chú ý: Lệnh 38h của LCD thực sự là tổng của một số bít lựa chọn. Bản thân lệnh này là lệnh 20h
(function set). Mặc dầu vậy chúng ta cộng giá trị 10h vào để thể hiện rằng bus dữ liệu là 8 bít, cộng 8h
vào để thể hiện rằng việc hiển thị là hai hàng.
Bây giờ chúng ta đã gửi xong byte đầu tiên của chuỗi công việc khởi tạo. Byte thứ hai
của chuỗi công việc khởi tạo là lệnh 0Eh. Vì vậy chúng ta phải lặp lại đoạn mã trên,
nhưng với lệnh mới. Mã lệnh có dạng:
CLR RS
MOV DATA,#0Eh
SETB EN
CLR EN
LCALL WAIT_LCD
Chú ý:Lệnh 0Eh thực sự là lệnh 08h cộng với 04h để bật LCD lên và cộng thêm 02h để config
LCD sao cho con trỏ được hiển thị.
Byte cuối cùng chúng ta cần phải gửi để config các tham số hoạt động của LCD là 06h.
Lệnh có dạng:
CLR RS
MOV DATA,#06h
SETB EN
CLR EN
LCALL WAIT_LCD
Chú ý:Lệnh 06h thực sự là lệnh 04h cộng với 02h để config LCD sao cho mỗi lần chúng ta gửi tới
nó một ký tự thì vị trí con trỏ phải tự động dịch sang phải một vị trí.
Cuối cùng thì toàn bộ mã lệnh khởi tạo có dạng như sau:
6
INIT_LCD: CLR RS
MOV DATA,#38h
SETB EN
CLR EN
LCALL WAIT_LCD
CLR RS
MOV DATA,#0Eh
SETB EN
CLR EN
LCALL WAIT_LCD
CLR RS
MOV DATA,#06h
SETB EN
CLR EN
LCALL WAIT_LCD
RET
Khi thực thi xong chuỗi lệnh này thì LCD đã được khởi tạo dầy đủ và sẵn sàng cho chúng
ta gửi dữ liệu cần hiển thị lên nó.
XOÁ MÀN HÌNH HIỂN THỊ
Sau khi LCD được khởi tạo lần đầu tiên, màn hình sẽ tự động bị xoá bởi bộ điều khiển
44780. Mặc dầu vậy sẽ tốt hơn nếu chúng ta tự làm điều này sao cho bạn có thể hoàn toàn
chắc chắn rằng việc hiển thị là theo ý bạn. Do đó tốt nhất là chúng ta xoá màn hình hiển
thị mỗi khi khởi tạo LCD xong.
Một lệnh LCD tồn tại để thực hiện việc này. Không ngạc nhiên gì nếu đây là lệnh 01h.
Khi việc xoá màn hình là một chức năng thường được dùng thì tốt nhất là ta viết nó dưới
dạng một đoản trình con.
Mã lệnh như sau:
CLEAR_LCD:
CLR RS
MOV DATA,#01h
SETB EN
CLR EN
LCALL WAIT_LCD
RET
Từ đây chúng ta có thể xoá màn hình bất kỳ lúc nào bằng việc thực hiện lệnh
LCALL CLEAR_LCD
Chú ý: Sau khi xoá màn hình thì con trỏ sẽ nằm ở góc cao nhất bên tay trái (hàng thứ nhất, cột
thứ nhất).
7
GHI VĂN BẢN (TEXT) RA LCD
Đây là phần việc mong đợi nhất và hay dùng nhất, chúng ta hãy viết nó thành đoản trình
con như sau:
WRITE_TEXT:
SETB RS
MOV DATA,A
SETB EN
CLR EN
LCALL WAIT_LCD
RET
Đoản trình WRITE_TEXT mà chúng ta viết bên trên sẽ gửi ký tự trong thanh ghi tích luỹ
ra LCD và LCD đến lượt mình sẽ hiển thị nó lên. Do vậy để hiển thị text trên LCD, tất cả
những gì chúng ta cần làm là nạp vào thanh ghi tích luỹ byte cần hiển thị và gọi đoản
trình con. Thật dễ phải không nào :-))
MỘT CHƯƠNG TRÌNH “HELLO WORLD”
Bây giờ chúng ta đã có các đoản trình cần thiết để viết một chương trình. Hãy viết một
chương trình hiển thị chữ hello world lên màn hình LCD. Chương trình như sau:
LCALL INIT_LCD
LCALL CLEAR_LCD
MOV A,#'H'
LCALL WRITE_TEXT
MOV A,#'E'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'O'
LCALL WRITE_TEXT
MOV A,#' '
LCALL WRITE_TEXT
MOV A,#'W'
LCALL WRITE_TEXT
MOV A,#'O'
LCALL WRITE_TEXT
MOV A,#'R'
LCALL WRITE_TEXT
8
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'D'
LCALL WRITE_TEXT
Chương trình hello world trên thực hiện việc khởi tạo LCD, xoá màn hình LCD và hiển
thị chữ “Hello world” ở góc cao bên trái màn hình.
VỊ TRÍ CON TRỎ
Trên đây là chương trình hiển thị chữ “hello world” đơn giản lên góc cao bên trái màn
hình. Mặc dầu vậy nếu chúng ta muốn chữ “world” hiển thị ở vị trí dòng 2 cột thứ 10 thì
sao ? Việc này rất đơn giản và thực tế nó cũng đơn giản thôi :-)) Ngoại trừ một vài hiểu
biết về việc thiết kế LCD. 44789 có chứa sẵn một số cố định bộ nhớ dùng cho việc hiển
thị. Tất cả các text gửi tới LCD đều được chứa trong bộ nhớ và 44780 lần lượt đọc bộ
nhớ này để hiển thị dữ liệu lên màn LCD của nó. Bộ nhớ này có thể được biểu diễn dưới
dạng bản đồ bộ nhớ như sau:
Trong bản đồ bộ nhớ ở trên vùng có màu xanh là vùng hiển thị nhìn thấy được. Như bạn
có thể thấy nó bao gồm 2 hàng, mỗi hàng có 16 ký tự. Các con số trong mỗi một ô chính
là địa chỉ bộ nhớ tương ứng với vị trí trên màn hình.
Ký tự đầu tiên ở góc cao bên trái có địa chỉ bộ nhớ là 00, vị trí tiếp theo là 01...vvv cứ
như vậy cho tới ký tự cuối cùng góc cao bên tay phải có địa chỉ là 0F. Mặc dầu vậy ký tự
ở dòng thứ hai có địa chỉ 40h. Nó có nghĩa rằng nếu chúng ta ghi một ký tự tới vị trí cuối
cùng của dòng đầu tiên và sau đó ghi một ký tự thứ hai, thì ký tự thứ hai này sẽ không
xuất hiện trên dòng thứ hai. Đó là vì ký tự thứ hai sẽ được ghi vào địa chỉ 10h trong khi
đó dòng thứ hai lại bắt đầu ở địa chỉ 40h.
Vì thế chúng ta cần phải gửi một lệnh tới LCD để nói với nó về vị trí của con trỏ trên
dòng thứ hai. Lệnh thiết lập vị trí con trỏ (set cursor position) có giá trị 80h. Với lệnh này
chúng ta phải cộng địa chỉ của vị trí nơi mà chúng ta muốn con trỏ xuất hiện. Trong ví dụ
của chúng ta, ta muốn hiển thị chữ “world” ở dòng 2 vị trí số 10.
Tham chiếu tới bản đồ bộ nhớ, chúng ta thấy rằng vị trí ký tự thứ 10 ở dòng 2 có địa chỉ
4Ah. Do đó trước khi viết từ “world” tới LCD chúng ta phải gửi lệnh thiết lập vị trí con
trỏ “set cursor position”- giá trị lệnh sẽ bằng 80h cộng với địa chỉ 4Ah. 80h+4Ah=CAh.
Do đó chúng ta gửi lệnh CAh tới LCD thì LCD sẽ định vị vị trí con trỏ tại dòng 2 ô số 10.
Mã lệnh như sau:
9
CLR RS
MOV DATA,#0CAh
SETB EN
CLR EN
LCALL WAIT_LCD
Mã trên đây giúp chúng ta hiển thị đúng mong muốn của mình: hiển thị chữ “world” ở
dòng 2 ô số 10. Vậy mã lệnh đầy đủ cho việc hiển thị chữ hello world theo mong muốn
phải có thêm đoạn mã trên chèn vào. Kết quả ta có mã lệnh đầy đủ như sau:
LCALL INIT_LCD
LCALL CLEAR_LCD
MOV A,#'H'
LCALL WRITE_TEXT
MOV A,#'E'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'O'
LCALL WRITE_TEXT
CLR RS
MOV DATA,#0CAh
SETB EN
CLR EN
LCALL WAIT_LCD
MOV A,#'W'
LCALL WRITE_TEXT
MOV A,#'O'
LCALL WRITE_TEXT
MOV A,#'R'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'D'
LCALL WRITE_TEXT
10
KẾT LUẬN
Mã lệnh trên trình bày những vẫn đề cơ bản về việc lập trình hiển thị cho LCD. Rõ ràng
rằng nó không phải là tất cả. 44780 có một số option cho các lệnh mà ta không đề cập ở
đây, cũng như còn rất nhiều lệnh khác truy cập đến các chức năng mà ta chưa nhắc tới ví
dụ như hiển thị các thanh bar..vvv. Mặc dầu vậy hi vọng với những gì trình bày các bạn
sẽ có hướng đi đúng trong việc lập trình cho LCD.
ĐIỀU KHIỂN LCD BẰNG 8051 VỚI BUS 4 BIT
Ở phần trước chúng ta đã nói đến việc điều khiển LCD theo phương pháp bus 8 bít, lần
này chúng ta tiếp tục xem xét phương pháp làm việc với LCD qua bus 4 bít.
Khi làm việc với LCD dựa trên 44780 bằng bus8 bít chúng ta cần 11 đường dây nối,
nhưng với chế độ bus 4 bít chúng ta chỉ cần 7 đường dây nối, trong trường hợp chân R/W
nối đất thì thực tế chỉ có thể dùng 6 đường dây nối mà thôi. Loại cấu hình này chúng ta
rất hay thấy trong các ứng dụng. Thay vì đọc cờ bận (busy flag)-đôi khi tạo khó khăn hơn
cho chúng ta như trong trường hợp bus 8 bít- chúng ta phải sử dụng các vòng lặp trễ. Các
vòng lặp trễ này sẽ phải tính toán lại khi chúng ta sử dụng các tần số thạch anh khác nhau
cho vi điều khiển 8051. Ở đây chúng ta sẽ tìm hiểu một cách mà có vẻ như phức tạp hơn
một chút, đó là sử dụng cờ bận (busy flag) và do đó không phụ thuộc vào tần số thạch
anh được sử dụng. Điều bất lợi duy nhất khi sử dụng phương pháp giao tiếp 4 bít đó là
các lệnh phải được gửi theo từng 2 nibble và do đó sẽ tốn thời gian hơn một chút. Nhưng
trong thực tế vấn đề này không quan trọng và ta không cần quan tâm đến nó nhiều lắm.
CẤU HÌNH PHẦN CỨNG
Sự khác nhau duy nhất giữa phương pháp giao tiếp 4 bít và 8 bít đó là các bít DB0…DB3
trên phía màn hình hiển thị LCD. Các đường dây này không được nối với bộ vi điều
khiển. Hãy thả nổi các đường dây này, không được nối chúng với đất giống như trường
hợp dây R/W. Chúng ta hãy khai báo
DB4 EQU P1.4
DB5 EQU P1.5
DB6 EQU P1.6
DB7 EQU P1.7
EN EQU P3.7
RS EQU P3.6
11
RW EQU P3.5
DATA EQU P1
Để biết về cách điều khiển các chân điều khiển của LCD, hãy đọc phần đầu của tài liệu
này. Trong chế độ làm việc 4 bít chúng ta phải đọc và ghi các byte dữ l iệu và các byte
lệnh trong hai nibble riêng rẽ. Để tạo ra sự thay đổi không đáng kể so với ví dụ ban đầu,
chúng ta tạo ra hai đoản trình con: đoản trình con thứ nhất để đọc hai nibble từ LCD và
đoản trình co thứ hai ghi 2 nibble tới LCD. Thêm vào đó, việc chuyển trạng thái đường
dây EN cũng được thực hiện trong các đoản trình này do chúng ta sẽ phải lật trạng thái của đường dây này sau mỗi khi truyền đi một nibble.
Mã lệnh như sau:
READ_2_NIBBLES:
ORL DATA,#0F0 ;Be sure to release datalines (set
outputlatches
;to '1') so we can read the LCD
SETB EN
MOV A,DATA ;Read first part of the return
value (high nibble)
CLR EN
ANL A,#0F0h ;Only high nibble is usable
PUSH ACC
SETB EN
MOV A,DATA ;Read second part of the return value (low
nibble)
CLR EN
ANL A,#0F0h ;Only high nibble is usable
SWAP A ;Last received is actually low nibble, so
put it in place
MOV R7,A
POP ACC
ORL A,R7 ;And combine it with low nibble
RET
WRITE_2_NIBBLES:
PUSH ACC ;Save A for low nibble
ORL DATA,#0F0h ;Bits 4..7 <- 1
ORL A,#0Fh ;Don't affect bits 0-3
ANL DATA,A ;High nibble to display
SETB EN
CLR EN
POP ACC ;Prepare to send
SWAP A ;...second nibble
ORL DATA,#0F0h ; Bits 4...7 <- 1
ORL A,#0Fh ; Don't affect bits 0...3
12
ANL DATA,A ;Low nibble to display
SETB EN
CLR EN
RET
Như chúng ta thấy trong đoản trình WRITE_2_NIBBLES có một số lệnh logic (ORL,
ANL) các chân I/O từ P1.0 tới P1.3 không bị ảnh hưởng. Các đường dây tương ứng này
tự do vào, ra và không bị ảnh hưởng bởi đoản trình này.
KIỂM TRA TRẠNG THÁI BẬN CỦA LCD
WAIT_LCD:
CLR RS ;It's a command
SETB RW ;It's a read command
LCALL READ_2_NIBBLES ;Take two nibbles from LCD in A
JB ACC.7,WAIT_LCD ;If bit 7 high, LCD still busy
CLR RW ;Turn off RW for future commands
RET
KHỞI TẠO LCD
Trước khi bạn có thể thực sự sử dụng LCD bạn phải khởi tạo và cấu hình cho nó. Việc
này được thực hiện bằng cách gửi một số các lệnh khởi tạo tới LCD.
Lệnh đầu tiên chúng ta gửi phải nói cho LCD biết rằng chúng ta đang thực hiện trao đổi
thông tin với nó. Chúng ta cũng lựa chọn kiểu phông ký tự là 5x8. Hai option này đwọc
lựa chọn bằng cách gửi giá trị 28h tới LCD như là một lệnh. Sau khi cấp nguồn cho LCD
nó luôn ở trong chế độ làm việc 8 bít. Do chỉ có 4 bít được kết nối (trường hợp mà ta
đang xét), lệnh đầu tiên phải được gửi hai lần: lần đầu tiên để chuyển sang chế độ 4 bít (4
bít thấp của lệnh không nhìn thấy), lần thứ hai để gửi nó như là hai nibble sao cho phần
thấp được nhận.
Mã lệnh như sau:
CLR RS
CLR RW
CLR EN
SETB EN
MOV DATA,#28h
CLR EN
LCALL WAIT_LCD
MOV A,#28h
LCALL WRITE_2_NIBBLES ;Write A as two separate nibbles to LCD
LCALL WAIT_LCD
13
Chú ý: Lệnh 28h của LCD thực ra là tổng của các bít option. Bản thân lệnh có giá trị 20h
(Function set). Mặc dầu vậy chúng ta phải cộng thêm gia strị 0h vào để báo hiệu rằng bus dữ liệu là 4 bít
và sau đó cộng thêm 8h để báo hiệu rằng việc hiển thị là hai hàng.
Chúng ta đã gửi byte đầu tiên của chuỗi lệnh khởi tạo. Byte thứ hai của chuỗi lệnh khởi
tạo là 0Eh. Chúng ta vẫn phải lặp lại mã lệnh khởi tạo như ở trên nhưng có khác một
chút. Mã lệnh có dạng:
MOV A,#0Eh
LCALL WRITE_2_NIBBLES ;Write A as two separate nibbles to LCD
LCALL WAIT_LCD
Chú ý: Lệnh 06h thực ra là lệnh 04h cộng với 02h để config LCD sao cho mỗi lần chúng ta gửi dữ liệu tới
nó thì con trỏ của LCD phải dịch đi 1 vị trí.
Cuối cùng thì mã lệnh khởi tạo có dạng như sau:
INIT_LCD:
CLR RS
CLR RW
CLR EN
SETB EN
MOV DATA,#28h
CLR EN
LCALL WAIT_LCD
MOV A,#28h
LCALL WRITE_2_NIBBLES
LCALL WAIT_LCD
MOV A,#0Eh
LCALL WRITE_2_NIBBLES
LCALL WAIT_LCD
MOV A,#06h
LCALL WRITE_2_NIBBLES
LCALL WAIT_LCD
RET
Khi chạy đoạn mã trên chúng ta đã khởi tạo LCD và thiết lập các chế đô phù hợp để có
thể gửi dữ liệu ra LCD.
XÓA MÀN HÌNH HIỂN THỊ
CLEAR_LCD:
CLR RS
MOV A,#01h
LCALL WRITE_2_NIBBLES ;Write A as two separate nibbles to LCD
LCALL WAIT_LCD
RET
14
GHI VĂN BẢN TEXT RA LCD
WRITE_TEXT:
SETB RS
LCALL WRITE_2_NIBBLES
LCALL WAIT_LCD
RET
CHƯƠNG TRÌNH “HELLO WORLD” LCALL INIT_LCD
LCALL CLEAR_LCD
MOV A,#'H'
LCALL WRITE_TEXT
MOV A,#'E'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'O'
LCALL WRITE_TEXT
MOV A,#' '
LCALL WRITE_TEXT
MOV A,#'W'
LCALL WRITE_TEXT
MOV A,#'O'
LCALL WRITE_TEXT
MOV A,#'R'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'D'
LCALL WRITE_TEXT
Chương trình “”hello world” ở trên khi được thực thi sẽ khởi tạo LCD, xoá LCD và hiển
thị chữ Hello world trên góc cao bên trái của màn hình hiển thị. Như bạn có thể thấy
không có sự khác biệt giữa chương trình làm việc với LCD qua giao tiếp 8 bít và chương
trình làm việc với LCD qua giao tiếp 4 bít.
VỊ TRÍ CON TRỎ
Chúng ta lại viết chường trình để hiển thi chữ “world” trên dòng thứ hai, ô số 10. Mã chương trình như sau:
15
LCALL INIT_LCD
LCALL CLEAR_LCD
MOV A,#'H'
LCALL WRITE_TEXT
MOV A,#'E'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'O'
LCALL WRITE_TEXT
CLR RS
MOV A,#0C9h
LCALL WRITE_2_NIBBLES
LCALL WAIT_LCD
MOV A,#'W'
LCALL WRITE_TEXT
MOV A,#'O'
LCALL WRITE_TEXT
MOV A,#'R'
LCALL WRITE_TEXT
MOV A,#'L'
LCALL WRITE_TEXT
MOV A,#'D'
LCALL WRITE_TEXT
KẾT LUẬN
Trên đây là các kiến thức cơ bản để chúng ta làm việc với LCD khi dùng họ vi điều khiển
8051. Sau đây là một số kiến thức phụ trợ về các loại LCD khác nhau:
The HD44780 or compatible controller is basically designed to build LCDisplays with one or two lines with a maximum of 40 characterpositions each. A single HD44780 is able to display two lines of 8 characters each. If we want more, the HD44780 has to be expanded with one or
more expansion chips, like the HD 44100 (2 x 8 characters expansion) or the HD 66100 (2 x 16 characters expansion). Seen from the HD44780, the first line starts with 00h; the second line
with 40h.
LAYOUT OF DISPLAY MODULES WITHOUT EXPANSION CHIP(S):
1. 8 characters x 1 line
First Line: 00 01 02 03 04 05 06 07
2. The module has to be initialised as a ONE line display.
16
3. 8 characters x 2 lines
First Line:
Second Line: 00 01 02 03 04 05 06 07
40 41 42 43 44 45 46 47
4. To use the second line, don't forget to initialise the display as a TWO lines display. 5. 16 characters x 1 line
First Line: 00 01 02 03 04 05 06 07 40 41 42 43 44 45 46 47
6. In fact, in this case the two lines are placed one after another. So when we want to use the display from the ninth position, it has to be initialised as if it were a TWO lines display!
Mind the ninth position is addressed as 40h, not 08h.
LAYOUT OF DISPLAY MODULES WITH EXPANSION CHIP(S)
1. 16 characters x 1 line
First Line: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
2. On the outside this module looks the same like #3 above, but all characterpositions are
addressed continuously. The module has to be initialised as a ONE-line display. 3. 20 characters x 1 line
First Line: 00 01 02 03 04 05 06 07 08 09 40 41 42 43 44 45 46 47 48 49
4. In fact, from HD44780 point of view, in this case two lines are placed one after another. So when we want to use the display from the eleventh position, it has to be initialised as
if it were a TWO lines display! Mind the eleventh position is addressed as 40h, not 0Ah. 5. 40 characters x 1 line
First Line: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11...27
6. The module has to be initialised as a TWO lines display, if we also want to use the second line.
7. 24 characters x 2 lines
First Line:
Second
Line:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13
14 15 16 17
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53
54 55 56 57
8. The module has to be initialised as a TWO lines display, if we also want to use the second line.
9. 40 characters x 2 lines
17
First Line:
Second Line: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11... 27
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51... 67
10. The module has to be initialised as a TWO lines display, if we also want to use the second line. This is also the maximum configuration which is possible with one HD44780 + extension chips (80 characters).
11. 16 characters x 4 lines
First Line:
Second Line:
Third Line:
Fourth Line:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
12. To use the second and the fourth line, the module has to be initialised as a TWO lines display (strange, no?). In fact, the third line is continuous to the first line, and the fourth
line is continuous two the second line (from addressing point of view). 13. 20 characters x 4 lines
First Line:
Second Line:
Third Line:
Fourth Line:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53
14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27
54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67
14. To use the second and the fourth line, the module has to be initialised as a TWO lines display. In fact, the third line is continuous to the first line, and the fourth line is continuous two the second line (from addressing point of view).
15. 24 characters x 4 lines
First Line:
Second
Line:
Third Line:
Fourth
Line:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13
14 15 16 17
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33
34 35 36 37
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53
54 55 56 57
60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73
74 75 76 77
16. To use the THIRD and the FOURTH line, the module has to be initialised as a TWO lines display. Look out! There is a small 'view'-gap between the address ing of the first and the second line (and the third and fourth line respectively).
17. 40 characters x 4 lines
First Line:
Second
Line:
Third Line:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12...
27
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52...
67
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12...
27
18
Fourth Line: 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52... 67
18. These modules uses two HD44780's (each with expansion chips) and can be seen as two 40 x 2 modules in one. All wiring is common, except for the EN (enable) lines, which are
separate to drive each HD44780 apart.
Tip:If you are not sure what configuration your display has, you can do use the following trick: Imagine you have a 16 characters x 1 line display. You want to know if it has configuration #3 in
the first section or #1 in this section. Just connect the contrast input of your module to GND (= maximum contrast) and apply only power (+5V) to the module. The module will be initialised by an internal routine, which puts it in single line modus. Only the positions that belong to the first
line will be black.
Conclusion: If all positions are black, we have a module as described under #1 of this section. If only the first 8 characters are black, you have a module as described under # of the previous
section.
Not all possible module configurations are described here, but with the help of this information you must be able to work with different modules. Some (functional, not necessary pin-) compatible chips; to help you to determine your module:
Controller: HD44780 (Hitachi) KS0066 (Samsung)
SED1278 (Epson)
Expansion 8 x 2: HD44100 (Hitachi)
KS0061 (Samsung) M5259 (OKI)
Expansion 12 x 2: SED1181 (Epson)
Expansion 16 x 2: HD66100 (Hitachi)
Note: Some modules have black blobs which are chips direct mounted on the pc-board, covered with some resin substantion, so the chips are not recognisable.
19