(028) 66844775 - 0902760910 banhang@phuclanshop.com
Danh mục sản phẩm

Ứng dụng ic lập trình AT89C51: Đồng hồ có hẹn giờ mở và giờ tắt

29 Tháng Tám 2015

Mạch điện đồng hồ có hẹn giờ dùng ic lập trình AT89C51

 

 

  

 

Trước hết hãy tìm hiểu cách cho hiển thị các số dùng mã quét trên các chân Anode của các đèn số dùng mã 7 đoạn và sơ đồ mạch điện đồng hồ dùng để chạy đoạn chương trình nguồn sau đây:

 

 

 

 

 

Tất cả các linh kiện cho ráp trên một bảng mạch in nhỏ. Trên đó dùng 6 đèn số mã 7 đoạn để hiển thị giờ - phút - giây.

 

 

 

Sơ đồ mạch điện cho thấy, chúng ta dùng các xung ra ứng với bit 0, tuần tự cho ra trên các chân của các chân p2.0, p2.1, p2.2, p2.3, p2.4 và p2.5 để lần lượt cho chân anode của các đèn số nối lên nguồn 5V, như vậy trong một lúc chỉ có một đèn số phát sáng, với nhịp xung quay vòng nhanh và do mắt có hiện tượng lưu ảnh, chúng ta có cảm tưởng là 6 đèn Led cùng được kích sáng.

 

Chúng ta dùng 7 chân của cảng p1 để cho xuất các con số theo dạng mã 7 đoạn. Muốn Led nào sáng, chúng ta đặt bit 0 vào chân cathode của nó, vậy bit 1 tắt Led và bit 0 cấp dòng cho Led sáng. Theo sơ đồ chúng ta thấy:

 

Chân p1.0 kiểm soát dòng cấp cho Led-a trong đèn số. 

Chân p1.1 kiểm soát dòng cấp cho Led-b trong đèn số. 

Chân p1.2 kiểm soát dòng cấp cho Led-c trong đèn số. 

Chân p1.3 kiểm soát dòng cấp cho Led-d trong đèn số. 

Chân p1.4 kiểm soát dòng cấp cho Led-e trong đèn số. 

Chân p1.5 kiểm soát dòng cấp cho Led-f trong đèn số. 

Chân p1.6 kiểm soát dòng cấp cho Led-g trong đèn số. 

 

Sau khi đã chọn định phân cứng như sơ đồ mạch điện trên, chúng ta sẽ định ra được các dạng mã bit để tuần tự cho hiện các con số: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 trên các đèn số mã 7 đoạn.

 

 

tab:    ; Các mã dùng để hiện số trên đèn 7 đoạn đặt trong bảng có tên nhãn là tab:

db 0c0h, 0f9h, 0a4h, 0b0h, 99h, 92h, 82h, 0f8h, 80h, 90h    ; các mã hiện số viết theo dạng hệ 16.

 

 

 

Để dễ thấy ý nghĩa vật lý chúng ta sẽ viết lại các mã hệ 16 ở dạng mã hệ cơ 2 theo trọng giá  8-4-2-1.

 

 

* 0c0h,   viết lại ở dạng mã hệ cơ 2: 1100 0000b ứng với số 0

* 0f9h,    viết lại ở dạng mã hệ cơ 2: 1111 1001b ứng với số 1

* 0a4h,   viết lại ở dạng mã hệ cơ 2: 1010 0100b ứng với số 2

* 0b0h,   viết lại ở dạng mã hệ cơ 2: 1011 0000b ứng với số 3

* 99h,     viết lại ở dạng mã hệ cơ 2: 1001 1001b ứng với số 4

* 92h,     viết lại ở dạng mã hệ cơ 2: 1001 0010b ứng với số 5

* 82h,     viết lại ở dạng mã hệ cơ 2: 1000 0010b ứng với số 6

* 0f8h,    viết lại ở dạng mã hệ cơ 2: 1111 1000b ứng với số 7

* 80h,     viết lại ở dạng mã hệ cơ 2: 1000 0000b ứng với số 8

* 90h,     viết lại ở dạng mã hệ cơ 2: 1001 0000b ứng với số 9

 

 

 

 Tìm hiểu tác dụng của các nút nhấn và các led chỉ thị trạng thái:

 

 

 

 

 

Dùng hình động để giải thích hoạt động của đèn số dùng mã 7 đoạn:

 

 

Cách cho xuất số liệu trên mã 7 đoạn, để hiện các số 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.

 

 

 

Cách dùng mã quét quay vòng, mỗi lần chỉ có một đèn số phát sáng:

 

 

 

 

 

 

 

Cách dùng MIDE-51 cho biên dịch đoạn chương trình nguồn sau đây ra dạng mã lệnh:

 

 

 

 

 

 

 

Sau khi biên dịch thành công, chúng ta có các dòng mã lệnh như sau: 

 

:020000000130CD
:0200030021B921
:02000B0001E30F
:10003000758150C20075210075220075230075245A
:1000400000752500752600752700752800752900A4
:10005000758C05758A05758902D2AFD2A8C2A9C26E
:100060008CC288E523B52609E524B52704D2B7015B
:100070007DE523B52807E524B52902C2B73000E3A2
:10008000118E0163C0F9A4B0999282F88090A823E0
:10009000900084E8C4540F93F590C2A0319FD2A081
:1000A000E8540F93F590C2A1319FD2A1A924E9C4CD
:1000B000540F93F590C2A2319FD2A2E9540F93F549
:1000C00090C2A3319FD2A3AA25EAC4540F93F590FE
:1000D000C2A4319FD2A4EA540F93F590C2A5319FD8
:1000E000D2A522C0E0C0D00521E521B4C8387521D1
:1000F000000522E522B40A2E752200B280B2817476
:10010000012525D4F525B4601D752500740125242D
:10011000D4F524B4601075240074012523D4F5238C
:10012000B42403752300D0D0D0E032A826900084F8
:10013000E8C4540F93F590C2A0319FD2A0E8540FA9
:1001400093F590C2A1319FD2A1A927E9C4540F937E
:10015000F590C2A2319FD2A2E9540F93F590C2A3A9
:10016000319FD2A322A828900084E8C4540F93F5AD
:1001700090C2A0319FD2A0E8540F93F590C2A13154
:100180009FD2A1A929E9C4540F93F590C2A2319F2F
:10019000D2A2E9540F93F590C2A3319FD2A3227546
:1001A00030027531FFD531FDD530F72275326475D7
:1001B00033FAD533FDD532F722C0E0C0D0C2A8C291
:1001C0008CC2A9118E20B2FB118E30B2FBD2B1D2FB
:1001D000B0118E20B413118E30B4FBA82374012803
:1001E000D4F523B424EB75230020B313118E30B360
:1001F000FBA824740128D4F524B460D5752400200C
:10020000B507118E30B5FB418720B2C5118E30B2D3
:10021000FBC2B0D2B1312B20B413312B30B4FBA8C8
:1002200026740128D4F526B424EB75260020B313D8
:10023000312B30B3FBA827740128D4F527B460D53F
:1002400075270020B2CF312B30B2FBD2B0C2B13112
:100250006520B413316530B4FBA828740128D4F5A7
:1002600028B424EB75280020B313316530B3FBA804
:1002700029740128D4F529B460D575290020B2CF9E
:10028000316530B2FB21CDD2A8D28CD200D2A9D216
:06029000B7D0D0D0E0322F
:00000001FF

 

 

 

Bây giờ Bạn dùng hộp nạp, cho nạp các dòng mã lệnh này vào bộ nhớ EEPROM của ic lập trình AT89C51, gắn IC này vào mạch điện, Bạn sẽ có một đồng hồ có chức năng chỉnh giờ mở giờ tắt và có thể dùng chân p3.7 để điều khiển các thiết bị điện tử kh́ac.

 

 

Đây là chương trình nguồn của mạch điện đồng hồ có hẹn, Bạn có thể cắt chương trình này dán vào vùng soạn thảo của MIDE-51 gõ phím F9 để cho dịch ra file .hex, và nạp các dòng mã lệnh này vào bộ nhớ EEPROM nằm trong ic lập trình AT89C51 để làm mạch điện đồng hồ có hẹn. Bạn xem phần giải thích cách dùng các câu lệnh ở phần bên dưới. 

 

 

;; Dong ho co nut chinh mo chinh tat

;;------------------------------------------

k1 bit p3.2

k2 bit p3.4

k3 bit p3.3

k4 bit p3.5

c_hour equ 23h

c_minute equ 24h

c_second equ 25h

on_hour equ 26h

on_minute equ 27h

off_hour equ 28h

off_minute equ 29h

org 0000h

jmp main

org 0003h

jmp wint0

org 000bh

jmp wt0

org 0030h

main:

mov sp, #50h

clr 00h

mov 21h, #0

mov 22h, #0

mov c_hour, #0

mov c_minute, #0

mov c_second, #0

mov on_hour, #0

mov on_minute, #0

mov off_hour, #0

mov off_minute, #0

;;

mov th0, #05

mov tl0, #05

mov tmod, #00000010b ;02h

;;

setb ea

setb ex0

clr et0

clr tr0

clr it0

m:

mov a, c_hour

cjne a, on_hour, off_time

mov a, c_minute

cjne a, on_minute, off_time

setb p3.7

jmp next

off_time:

mov a, c_hour

cjne a, off_hour, next

mov a, c_minute

cjne a, off_minute, next

clr p3.7

next: jnb 00h, m

call disp1

jmp m

;;

tab:

db 0c0h, 0f9h, 0a4h, 0b0h, 99h, 92h, 82h, 0f8h, 80h

db 90h

;;

disp1:

mov r0, c_hour

mov dptr, #tab

mov a, r0

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.0

call dl

setb p2.0

mov a, r0

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.1

call dl

setb p2.1

;;

mov r1, c_minute

mov a, r1

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.2

call dl

setb p2.2

mov a, r1

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.3

call dl

setb p2.3

;;

mov r2, c_second

mov a, r2

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.4

call dl

setb p2.4

mov a, r2

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.5

call dl

setb p2.5

ret

;;

wt0:

push acc

push psw

inc 21h

mov a, 21h

cjne a, 0c8h, t0reti ; 200d=0c8h 0.5ms*200=100ms

mov 21h, #0

inc 22h

mov a, 22h

cjne a, #10, t0reti ; 100ms*10=1s

mov 22h, #0

cpl p0.0

cpl p0.1

;;

mov a, #01h

add a, c_second

da a

mov c_second, a

cjne a, #60h, t0reti

mov c_second, #0

;;

mov a, #01h

add a, c_minute

da a

mov c_minute, a

cjne a, #60h, t0reti

mov c_minute, #0

;;

mov a, #01h

add a, c_hour

da a

mov c_hour, a

cjne a, #24h, t0reti

mov c_hour, #0

;;

t0reti:

pop psw

pop acc

reti

;;

disp2:

mov r0, on_hour

mov dptr, #tab

mov a, r0

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.0

call dl

setb p2.0

mov a, r0

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.1

call dl

setb p2.1

;;

mov r1, on_minute

mov a, r1

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.2

call dl

setb p2.2

mov a, r1

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.3

call dl

setb p2.3

ret

;;

disp3:

mov r0, off_hour

mov dptr, #tab

mov a, r0

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.0

call dl

setb p2.0

mov a, r0

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.1

call dl

setb p2.1

;;

mov r1, off_minute

mov a, r1

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.2

call dl

setb p2.2

mov a, r1

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.3

call dl

setb p2.3

ret

;;

dl:

mov 30h, #02h

dl1: mov 31h, #0ffh

djnz 31h, $

djnz 30h, dl1

ret

;;

del:

mov 32h, #100

del1: mov 33h, #250

djnz 33h, $

djnz 32h, del1

ret

;;

wint0:

push acc

push psw

clr ex0

clr tr0

clr et0

k1_11:

call disp1

jb k1, k1_11

k11_1:

call disp1

jnb k1, k11_1

;;

ph4:

setb p3.1

setb p3.0

ph0: call disp1

jb k2, ph01

;;

k2_1:

call disp1

jnb k2, k2_1

mov r0, c_hour

mov a, #01h

add a, r0

da a

mov c_hour, a

cjne a, #24h, ph0

mov c_hour, #0

ph01:

jb k3, ph1

k3_1:

call disp1

jnb k3, k3_1

mov r0, c_minute

mov a, #01h

add a, r0

da a

mov c_minute, a

cjne a, #60h, ph0

mov c_minute, #0

ph1:

jb k4, ph10

k4_1:

call disp1

jnb k4, k4_1

jmp tend

ph10:

jb k1, ph0

k1_1:

call disp1

jnb k1, k1_1

clr p3.0

setb p3.1

;;--------------------------------

ph2:

call disp2

jb k2, ph201

k22_1:

call disp2

jnb k2, k22_1

mov r0, on_hour

mov a, #01h

add a, r0

da a

mov on_hour, a

cjne a, #24h, ph2

mov on_hour, #0

ph201:

jb k3, ph210

k22_2:

call disp2

jnb k3, k22_2

mov r0, on_minute

mov a, #01h

add a, r0

da a

mov on_minute, a

cjne a, #60h, ph2

mov on_minute, #0

ph210: jb k1, ph2

k22_3:

call disp2

jnb k1, k22_3

setb p3.0

clr p3.1

;;----------------------------------------

ph3:

call disp3

jb k2, ph301

k33_1:

call disp3

jnb k2, k33_1

mov r0, off_hour

mov a, #01h

add a, r0

da a

mov off_hour, a

cjne a, #24h, ph3

mov off_hour, #0

ph301:

jb k3, ph310

k33_2:

call disp3

jnb k3, k33_2

mov r0, off_minute

mov a, #01h

add a, r0

da a

mov off_minute, a

cjne a, #60h, ph3

mov off_minute, #0

ph310: jb k1, ph3

k33_3:

call disp3

jnb k1, k33_3

jmp ph4

;;----------------------------------------

tend:

setb ex0

setb tr0

setb 00h

setb et0

setb p3.7

pop psw

pop acc

reti

end

 

 

 

 

Phân tích ý nghĩa và cách dùng của các câu lệnh trong chương trình nguồn:

 

 

 

1. Khởi đầu Bạn dùng các định nghĩa bit và equ để đặt tên cho các bit và thanh ghi để tiện dụng.

 

;; Dong ho co nut chinh mo chinh tat

;;------------------------------------------

 

; đặt tên cho các nút nhấn

k1 bit p3.2   ; đặt tên chân p3.2 là k1

k2 bit p3.4   ; như trên

k3 bit p3.3   ; như trên 

k4 bit p3.5   ; như trên

 

 

; đặt tên các thanh nhớ dùng cất các con số chỉ giờ-phút- giây 

c_hour equ 23h     ; đặt tên cho thanh nhớ có địa chỉ 23h là c_hour

c_minute equ 24h  ; làm như trên

c_second equ 25h ; làm như trên 

 

 

; đặt tên cho các thanh nhớ dùng cất số giờ cho mở

on_hour equ 26h   ; làm như trên

on_minute equ 27h ; làm như trên

 

 

; đặt tên cho các thanh nhớ dùng cất số giờ cho tắt

off_hour equ 28h  ; làm như trên

off_minute equ 29h  ; làm như trên

 

 

 

2. Cho chương trình khởi đầu từ thanh reset, có địa chỉ 0000h. 

 

; Vào chương trình 

org 0000h

jmp main  ; cho nhẩy đến tên nhãn main, nhẩy qua các thanh dùng cho ngắt

 

 

3. Đặt các chương trình cho các dạng ngắt

 

org 0003h ; ngắt theo bit trên INT0

jmp wint0  ; nhẩy đến tên nhãn wint0

org 000bh ; ngắt theo bit TF0, bit trang của Timer10

jmp wt0   ; nhẩy đến tên nhãn wt0

 

 

org 0030h  ; Các chương trình điều khiển đồng hồ khởi từ địa chỉ này

main:   ; tên nhãn dùng cho lệnh nhẩy

mov sp, #50h  ; định địa chỉ cho ngăn xếp

clr 00h     ; cho xóa bit có địa chỉ 00h

 

 

; Đặt trị khởi đầu cho các thanh ghi dùng hiển thị giờ-phút-giây

mov 21h, #0   ; trị khởi đầu đặt số 0 vào thanh ghi 21h

mov 22h, #0  ; làm như trên

mov c_hour, #0 ; làm như trên

mov c_minute, #0  ; làm như trên

mov c_second, #0  ; làm như trên

mov on_hour, #0  ; làm như trên

mov on_minute, #0 ; làm như trên

mov off_hour, #0  ; làm như trên

mov off_minute, #0 ; làm như trên

 

 

; Khai báo các trị cho Timer 0

mov th0, #05 ; nạp trị khởi đầu cho thanh đếm 8 bit th0

mov tl0, #05  ; nạp trị khởi đầu cho thanh đếm 8 bit tl0

mov tmod, #00000010b ; chọn định cho timer 0 làm việc ở mode 2

 

Để hiểu rõ hơn hoạt động của các timer trong AT89C51, Bạn xem hình sau:

 

 

  

 

Trong thanh tmod, có 2 bit dùng để chọn mode cho các đồng hồ timer trong AT89C51.

 

Nếu Bạn chọn:

 

M1 = 0 , M0 = 0 là cho timer chạy ở mode 0, mode dùng thanh đếm 13 bit

M1 = 0 , M0 = 1 là cho timer chạy ở mode 1, mode dùng thanh đếm 16 bit

M1 = 1 , M0 = 0 là cho timer chạy ở mode 2, mode dùng thanh đếm 8 bit

M1 = 1 , M0 = 1 là cho timer chạy ở mode 3, mode hổn hợp.

 

Với dòng khai báo trong thanh tmod là 00000010b thì chúng ta chọn timer 0 cho làm việc ở mode 2, tức dùng thanh tl0 làm thanh đếm 8 bit. Khi thanh tl0 đếm đến tràn số, bit báo tràn tf0sẽ nhẩy lên 1. Nó sẽ có 2 tác dụng.

 

* Tác dụng thứ nhất: là cho trị trong tl0 về 0 và đồng thời lấy trị có trong th0 cho nạp vào thanh tl0.

* Tác dụng thứ hai: là nhẩy ngắt theo bit tf0. Chương trình nhẩy về địa chỉ 000bh của bộ nhớ 

 

 

Hình vẽ trên cho thấy hoạt động của Timer 0 (giải thích tương tự cho Timer 1) như sau: Trong AT89C51 có mạch dao động tạo ra xung nhịp, tần số xung lấy theo thạnh anh trên chân 18, 19. Xung này có thể đưa vào bộ đếm của các timer, Bạn cũng có thể lấy xung ngoài đưa vào thanh đếm trên chân T0 hay chân p3.4. Để cho xung nhịp đưa vào thanh đếm, Bạn hãy định  bit cho C/T đảo, nếu định nó là bit 1 thì mạch đếm sẽ lấy xung ngoài đưa vào trên chân T0, nếu định là bit 0 thì mạch đếm sẽ lấy xung của mạch dao động nội. Xung nhịp trước khi vào bộ đếm còn phải qua một khóa điện, khóa điện này chịu điều khiển theo các bit sau:

 

* Bit tr0, nếu cho tr0 được định ở bit 1, khóa điện sẽ đóng lại và nếu tr0 ở bit 0 nó sẽ làm hở khóa điện và cắt xung nhịp không cho vào thanh đếm.

 

* Bit INT0 đảo, khi bit Gate chọn ở bit 1 thì ngắt ngoài INT0 sẽ có tác dụng đến mạch đếm, khi INT0 là bit 1 nó cho đếm và khi INT0 ở bit 0, nó sẽ ngắt mạch đếm. Khi bit Gate chọn ở bit 0 thì ngắt ngoài trên chân INT0 sẽ mất tác dụng.

 

Tóm lại, nếu Bạn không dùng ngắt ngoài INT0 thì đặt bit Gate ở mức bit 0. Lúc này dùng bit tr0 để đóng mở mạch đếm. Nghĩa là:

 

setb tr0 là cho xung nhịp vào bộ đếm của timer 0

clr tr0 là ngắt xung nhịp không cho vào bộ đếm của timer0

  

 

; Khai báo chọn dạng ngắt và điều khiển hoạt động của timer 0.

 setb ea  ; bit ea dùng tắt/mở 6 dạng ngắt trong AT89C51, set cho dùng ngắt

setb ex0 ; đặt ex0 = 1 là cho dùng ngắt ngoài trên chân INT0

clr et0   ; tạm thời cho tắt ngắt theo bit báo tràn tf0

clr tr0    ; tạm thời cho tắt xung nhịp vào bộ đếm tl0, tắt time 0

clr it0    ; chọn hình thức ngắt theo mức volt thấp của ngắt ngoài INT0

 

Muốn hiều rõ vai trò của các ngắt trong AT89C51, chúng ta xem hình vẽ sau:

 

 

 

Chức năng Ngắt là gì?

 

Ngắt là một chức năng rất hay của các ic lập trình, khi Bạn đã chọn dấu hiệu nhẩy ngắt, tức chọn kiểu ngắt, không cần biết chương trình của Bạn lúc này đang làm gì, mỗi khi xuất hiện dấu hiện báo ngắt, chương trình đang chạy sẽ dừng lại và cho nhẩy đến địa chỉ đã qui định của các ngắt để chạy chương trình ngắt, cho đến khi gặp câu lệnh reti thì kết thúc chương trình ngắt và quay trở lại tiếp tục làm công việc đã tạm dừng trước đó. Thí dụ:

 

Bạn đã chọn dạng ngắt theo bit báo tràn của timer 0, đó là bit tf0. Khi timer 0 đang đếm xung nhịp, xung vào các thanh đếm tl0, th0, bit tf0 đã cho ở bit 0 với câu lệnh clr tf0, khi các thanh đếm tràn số thì bit tf0 sẽ nhẩy lên bit 1 và lúc này ngắt tf0 sẽ bị kích hoạt, nó tạm dừng chương trình đang chạy, nhẩy về địa chỉ 000bh và chạy chương trình có ở địa chỉ này, cho đến khi gặp câu lệnh reti, nó sẽ ngưng chạy chương trình ngắt và quay lại tiếp tục chạy chương trình đã tạm dừng trước đó.

 

 

 

4. Cho kiểm tra với các trị đã định trước

 

; Cho kiểm tra trị trong các vùng nhớ off_timer và on_timer

m:  ; đặt tên nhãn m:

mov a, c_hour ; chuyển trị trong c_hour vào a

cjne a, on_hour, off_time ; cho so sánh trị trong on_hour và a để chọn kiểu nhẩy

mov a, c_minute ; chuyển trị trong c_minute vào a

cjne a, on_minute, off_time ; cho so sánh trị trong on_minute với a để chọn kiểu nhẩy

setb p3.7 ; đặt bit điều khiển trạng thái trên chân p3.7 lên mức áp cao

jmp next ; cho nhẩy đến tên nhãn next:

off_time: ; đặt tên nhãn off_time

mov a, c_hour ; chuyển trị trong c_hour vào a

cjne a, off_hour, next ; cho so sánh trị trong off_hour và a để chọn kiểu nhẩy

mov a, c_minute ; chuyển trị trong c_minute vào a

cjne a, off_minute, next ; so sánh trị trong off_minute và a để chọn kiểu nhẩy

clr p3.7 ; đặt bit trên chân p3.7 xuống mức áp thấp

next: jnb 00h, m ; cho nhẩy theo bit kiểm tra 00h

call disp1  ; cho gọi trình hiển thị số

jmp m  ; nhẩy về tên nhãn m:

 

 

Ý nghĩa của đoạn chương trình trên là cho kiểm tra trị có trong c_hour và c_minute với các trị đã có trong on_hour, on_minute và off_hour, off_minute để điều khiển trạng thái bit p3.7. Ở đây Bạn chú ý cách dùng câu lệnh cjne (compare jump no equal), một câu lệnh dùng phép so sánh 2 trị xem bằng hay không bằng để chọn kiểu nhẩy, đây là một lệnh rất hay. Cũng chú ý đến bit kiểm tra có địa chỉ bit được chọn là 00h

 

 ; tạo bảng để cất các trị dùng làm hiện các số mã thập phân trên các Led 7 đoạn 

tab:   ; đặt tên nhãn

db 0c0h, 0f9h, 0a4h, 0b0h, 99h, 92h, 82h, 0f8h, 80h, 90h  ; mã hiện số khi cho xuất trên cảng p1

 

 

Bạn xem phần giải thích cách cho hiện các số trên các đèn số dùng mã 7 đoạn

 

 

5. Viết chương trình hiển thị số 

 

; đây là đoạn chương trình dùng hiển thị số lên bảng đèn số

 

; Viết chương trình hiển thị giờ (hour)

disp1:   ; đặt tên nhãn hiện số là disp1:

mov r0, c_hour ; chuyển trị trong c_hour vào r0

mov dptr, #tab ; đặt bảng tra mã con số vào thanh ghi con trỏ

mov a, r0  ; chuyển trị trong r0 vào a

swap a  ; cho đảo vị trí 4 bit cao / thấp trong thanh a

anl a, #0fh  ; lấy logic and để che 4 bit cao, giữ nguyên trị ở 4 bit thấp

movc a, @a+dptr  ; lấy trị trong bảng hiện số gắn vào a

mov p1, a  ; cho xuất trị trong a ra cảng p1 để hiện số

clr p2.0  ; đặt chân p2.0 xuống mức thấp để mở đèn số này

call dl  ; gọi chương trình làm chậm dl: để tạo mức sáng cho con số

setb p2.0  ; tắt đèn số đã mở trước khi mở qua đèn số khác

mov a, r0 ; chuyển trị còn trong r0 vào a

anl a, #0fh  ; dùng logic and để che 4 bit cao, giữ nguyên 4 bit thấp

movc a, @a+dptr  ; truy bảng lấy mã hiện số chuyển vào a

mov p1, a  ; lại cho xuất mã con số trong a ra cảng p1

clr p2.1  ; đặt chân p2.1 xuống mức áp thấp để mở đèn số

call dl  ; cho làm chậm để có mức sáng tốt

setb p2.1 ; đặt chân p2.1 lên cao để tắt đèn số này tránh lem số

 

 

; Viết chương trình hiển thị các con số chỉ phút (minute)

; Bạn xem cách viết tương tự như phần trên

mov r1, c_minute

mov a, r1

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.2

call dl

setb p2.2

mov a, r1

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.3

call dl

setb p2.3

 

 

; Viết chương trình cho hiển thị giây ̣(second)

; Bạn xem cách viết tương tự như phần trên. 

mov r2, c_second

mov a, r2

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.4

call dl

setb p2.4

mov a, r2

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.5

call dl

setb p2.5

ret

 

Trong các câu lệnh trên có nhiều câu lệnh dùng rất hay, như:

 

* Trong thanh đếm 8 bit, 4 bit cao có thể là hàng chục và 4 bit thấp là hàng đơn vị, trong trường hợp này Bạn dùng lệnh swap  a để chuyển đổi vị trí của 4 bit thấp lên cao và cao qua thấp.

 

* Muốn lấy trị thập phân có trên 4 bit thấp chúng ta có thể cho 4 bit cao đều bằng 0, và cho bảo toàn trị của 4 bit thấp, muốn vậy, chúng ta dùng logic and, câu lệnh anl a, #0fh (00001111b). 

 

* Để lấy các số mã có trong bảng với tên nhãn là tab: , chúng ta dùng câu lệnh: movc a, @a+dptr. Trước đó trong a chứa trị thập phân ở dạng cơ 2, từ trị này sẽ tìm ra được mã của con số có trong bảng tra tab:, và mã này được lấy ra và rồi cũng cho cất vào a, để sau đó sẽ cho xuất ra trên cảng p1.

 

 

6. Đoạn chương trình dùng cho mạch đếm theo bước tăng 1

 

; đây là chương trình ngắt mỗi khi xuất hiện bit báo tràn tf0

wt0:   ; đặt tên nhã wt0

push acc  ; tạm cho cất trị của a vào ngăn xếp, để mượn dùng a

push psw  ; tạm cho cất trị trong thanh psw vào ngăn xếp

inc 21h  ; cho tăng trị có trong thanh 21h lên +1

mov a, 21h  ; cho chuyển trị của thanh 21h vào a

cjne a, 0c8h, t0reti ; 200d=0c8h 0.5ms*200=100ms ; so sánh trị trong a bằng 0c8h chưa để nhẩy đến tắt ngắt

mov 21h, #0 ; trả trị trong thanh 21h trở về 0

inc 22h  ; bây giờ cho tăng trị trong thanh 22h

mov a, 22h  ; cũng chuyển trị trong thanh 22h vào a

cjne a, #10, t0reti ; 100ms*10=1s  ; lại so sánh trị trong a với trị 10, để nhẩy đến tắt ngắt

mov 22h, #0 ; lại trả trị trong 22h về mức đếm 0

cpl p0.0  ; lấy bù bit trên chân p0.0, có thể gắn led trên chân này để hiển thị trang thái đếm

cpl p0.1 ; lấy bù bit trên chân p0.1, có thể gắn led trên chân này để hiển thị trang thái đếm

 

 

7. Tạo trị tăng trong các thanh nhớ c_second, c_minute, c_hour 

 

 

;;

mov a, #01h ; cho trị 1 vào thanh a

add a, c_second ; cho cộng trị trong a với trị trong c_second, kết quả cất vào a

da a ; biến đổi tạo trị thập phân dạng cơ 2 đặt trong vùng 4 bit thấp, 4 bit cao

mov c_second, a  ; chuyển trị có trong a cất vào c_second

cjne a, #60h, t0reti  ; so sánh trị trong a bằng 60 chưa để chọn hướng nhẩy

mov c_second, #0 ; trả trị trong c_second về lại mức 0.

 

 

;;

mov a, #01h  ; đặt trị 1 vào thanh a

add a, c_minute ; cho cộng trị trong a và trị của c_minute, kết quả cất vào a

da a  ; biến đổi trị trong a ra số hệ thập phân dạng cơ 2, đặt trong 4 bit thấp và 4 bit cao

mov c_minute, a ; chuyển trị trong a vào cất trong c_minute

cjne a, #60h, t0reti  ; cho a so sánh với trị 60 để chọn hướng nhẩy

mov c_minute, #0  ; trả trị trong c_minute về lại mức 0

 

 

;;

mov a, #01h  ; đặt trị 1 vào thanh a

add a, c_hour  ; cho cộng trị trong a và trị của c_hour, kết quả cất vào a

da a  ; biến đổi trị trong a ra dạng số thập phân hệ cơ 2, cất ở vùng 4 bit thấp và 4 bit cao

mov c_hour, a  ; chuyển trị trong a vào cất trong c_hour

cjne a, #24h, t0reti ; so sánh trị trong a với số 24, để chọn hướng nhẩy

mov c_hour, #0  ; trả trị trong c_hour về lại mức 0

 

 

;;

t0reti:   ; đặt tên nhãn để dừng chạy chương trình ngắt

pop psw  ; lấy trị đã cất trong ngăn xếp  trả lại cho thanh psw

pop acc  ; lấy trị đã cất trong ngăn xếp tra lại thanh a

reti   ; dừng chạy chương trình ngắt, quay lại chạy chương trình chính

 

 

8. Viết chương trình hiển thị số cho mode chỉnh giờ

 

 

; Hiện số lúc đang chỉnh định hẹn giờ mở

; Tham khảo chương hình hiện giờ lúc bình thường

;;

disp2:  ; tên nhãn dùng cho lệnh nhẩy

mov r0, on_hour

mov dptr, #tab

mov a, r0

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.0

call dl

setb p2.0

mov a, r0

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.1

call dl

setb p2.1

 

 

;;

mov r1, on_minute

mov a, r1

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.2

call dl

setb p2.2

mov a, r1

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.3

call dl

setb p2.3

ret

 

; Hiện số lúc đang chỉnh định hẹn giờ tắt

; Tham khảo chương hình hiện giờ lúc bình thường

 ;;

disp3:  ; tên nhãn dùng cho lệnh nhẩy

mov r0, off_hour

mov dptr, #tab

mov a, r0

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.0

call dl

setb p2.0

mov a, r0

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.1

call dl

setb p2.1

 

 

;;

mov r1, off_minute

mov a, r1

swap a

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.2

call dl

setb p2.2

mov a, r1

anl a, #0fh

movc a, @a+dptr

mov p1, a

clr p2.3

call dl

setb p2.3

ret

 

̣9. Các đoạn chương trình làm trể

 

 

; Làm trể để có độ sáng rõ

;;

dl:

mov 30h, #02h

dl1: mov 31h, #0ffh

djnz 31h, $

djnz 30h, dl1

ret

 

 

;;

del:

mov 32h, #100

del1: mov 33h, #250

djnz 33h, $

djnz 32h, del1

ret

 

 

10. Chương trình viết cho các nút chỉnh

 

 

 

 

Hình vẽ trên cho thấy công dụng được giao cho các nút chỉnh. Đoạn chương trình sau được viết cho 4 nút chỉnh K1, K2, K3 và K4. Khi Bạn nhất nút K1 sẽ nhẩy ngắt ngoài và vào mode chỉnh.Nhấn K1 lần đầu sẽ cho chỉnh giờ-phút bình thường, lúc này K2 dùng chỉnh giờ và K3 dùng chỉnh phút. Nhấn K4 ra mode chỉnh. Nhấn K1 lần nữa vào vào mode chỉnh giờ-phút cho mode on_timer, lúc này K2 cũng dùng chỉnh giờ và K3 dùng chỉnh phút. Nhấn K4 ra mode chỉnh. Nhấn K1 lần nữa vào mode chỉnh off_timer và lúc này K2 cũng dùng chỉnh giờ, K3 dùng chỉnh phút. Nhấn K4 ra mode chỉnh.

 

 

;;

wint0:   ; đặt tên nhãn cho lệnh ngắt ngoài ứng với nút nhấn K1

push acc  ; tạm cho cất trị trong thanh acc vào ngăn xếp

push psw  ; tạm cho cất trị trong thanh psw vào ngăn xếp

clr ex0   ; tạm cho tắt ngắt ngoài

clr tr0  ; tạm dừng mạch đếm của timer 0

clr et0   ; tạm dừng ngắt theo bit báo tràn tf0

 

k1_11:  ; đặt tên nhãn cho lệnh nhẩy

call disp1  ; cho gọi chương trình hiển thị số

jb k1, k1_11 ; kiểm tra bit 1 của nút nhấn K1

 

k11_1:  ; đặt tên nhãn cho lệnh nhẩy

call disp1  ; tiếp tục cho gọi chương trình hiện số

jnb k1, k11_1 ; kiểm tra bit 0 trên nút nhấn K1

 

; Khi nhất nút K1, sẽ kích nhẩy ngắt ngoài _INT0, chương trình sẽ nhẩy đến tên nhãn WINT0:, ở đây người ta tiếp tục cho kiểm tra trạng thái bit của nút nhấn K1, đồng thời luôn cho gọi chương trình hiển thị để tránh hiển thị số bị gián đoạn trong mode điều chỉnh giờ. Chỉ khi bỏ nút nhất K1 ra, lúc đó sẽ chuyển qua kiểm tra trạng thái bit của các nút nhấn khác, như K2, K3.

 

;;

ph4:   ; đặt tên nhãn cho lệnh nhẩy

setb p3.1 ; cho tắt Led trên chân p3.1

setb p3.0  ; cho tắt Led trên chân p3.0

 

ph0:  ; đặt tên nhãn cho lệnh nhẩy

call disp1  ; tiếp tục cho gọi chương trình hiển thị số

jb k2, ph01 ; kiểm tra bit 1 trên nút nhấn K2

 

 

;;

k2_1:  ; đặt tên nhãn cho lệnh nhẩy

call disp1  ; tiếp tục cho hiển thị số

jnb k2, k2_1  ; kiểm tra bit 0 trên nút nhấn K2

mov r0, c_hour ; chuyển trị trong c_hour vào thanh r0

mov a, #01h  ; đặt trị 1 vào thanh a

add a, r0  ; cho trị trong r0 cộng với trị trong a, kết quả cất vào a

da a  ; biến đổi ra dạng hai số thập phân dạng cơ 2, cất trong 4 bit thấp và 4 bit cao

mov c_hour, a  ; chuyển trị có trong a vào thanh c_hour

cjne a, #24h, ph0  ; so sáng trị trong a với số 24, để định hướng nhẩy

mov c_hour, #0  ; đến đây trả trị trong c_hour về lại mức 0

 

ph01:   ; đặt tên nhãn cho lệnh nhẩy

jb k3, ph1 ; kiểm tra bit 1 trên nút nhấn K3

 

k3_1:  ; đặt tên nhãn cho lệnh nhẩy

call disp1 ; tiếp tục cho hiện số tránh gián đoạn lúc vào mode chỉnh

jnb k3, k3_1 ; kiểm tra bit 0 trên nút nhấn K3

mov r0, c_minute ; chuyển trị có trong c_minute vào thanh r0

mov a, #01h ; đặt trị 1 vào thanh a

add a, r0  ; cho trị trong r0 cộng với trị trong a, kết quả cất vào

da a  ; biến đổi ra dạng số thập phân hệ cơ 2, cất trong 4 bit thấp và 4 bit cao

mov c_minute, a  ; chuyển trị có trong a cất vào thanh c_minute

cjne a, #60h, ph0   ; cho so sánh a với trị 60 để chọn hướng nhẩy

mov c_minute, #0  ; trả trị trong c_minute về mức 0

 

ph1:  ; đặt tên nhãn dùng cho lệnh nhẩy

jb k4, ph10 ; kiểm tra bit 1 trên nút nhất K4

 

k4_1:   ; đặt tên nhãn dùng cho lệnh nhẩy

call disp1  ; tiếp tục gọi trình hiển thị số

jnb k4, k4_1  ; kiểm tra bit 0 trên nút nhấn K4

jmp tend  ; nhẩy đến tên nhãn tend:, kết thục trình đồng hồ

 

ph10:  ; đặt tên nhãn dùng cho lệnh nhẩy

jb k1, ph0 ; kiểm tra bit 1 trên nút nhấn K1

 

k1_1:  ; đặt tên nhãn dùng cho lệnh nhẩy

call disp1  ; tiếp tục gọi trình hiển thị số

jnb k1, k1_1  ; kiểm tra bit 0 trên nút nhấn K1 

clr p3.0   ; làm sáng Led trên chân p3.0

setb p3.1  ; làm tắt Led trên chân p3.1

 

 

;;--------------------------------

ph2:  ; đặt tên nhãn dùng cho lệnh nhẩy

call disp2  ; cho gọi chương trình hiển thị 2 con số

jb k2, ph201  ; kiểm tra bit 1 trên nút nhấn K2

 

k22_1:  ; đặt tên nh̃n dùng cho lệnh nhẩy

call disp2  ; tiếp tục cho gọi trình hiển thị số disp2

jnb k2, k22_1 ; kiểm tra bit 0 trên nút nhấn K2

mov r0, on_hour ; chuyển trị có trong on_hour vào r0

mov a, #01h ; cho trị 1 vào thanh a

add a, r0  ; cho trị trong r0 cộng với trị trong a, kết quả cất vào a

da a ; biến đổi thành hai số thập phân hệ cơ 2, cho cất vào 4 bit thấp và 4 bit cao

mov on_hour, a ; chuyển trị trong a vào cất trong thanh on_hour

cjne a, #24h, ph2 ; cho so sánh trị trong a với số 24 để chọn hướng nhẩy

mov on_hour, #0 ; trả trị trong thanh on_hour về mức 0

 

ph201:  ; đặt tên nhãn dùng cho lệnh nhẩy

jb k3, ph210  ; cho kiểm tra bit 1 trên nút nhấn K3

 

k22_2:  ; đặt tên nhãn dùng cho lệnh nhẩy

call disp2 ; tiếp tục cho hiển thị số với disp2

jnb k3, k22_2  ; kiểm tra bit 0 trên nút nhấn K3

mov r0, on_minute  ; cho chuyển trị trong on_hour vào thanh r0

mov a, #01h ; đặt trị 1 vào thanh a

add a, r0  ; cho trị trong r0 cộng với trị trong a, kết quả cất vào a

da a  ; biến đổi trị trong a ra hai số thập phân hệ cơ 2, cho cất vào 4 bit thấp và 4 bit cao

mov on_minute, a  ; chuyển trị trong a cất vào thanh on_minute

cjne a, #60h, ph2  ; cho so sánh trị trong a với số 60 để chọn hướng nhẩy

mov on_minute, #0  ; trả trị trong thanh on_minute về mức 0

 

ph210:   ; đặt tên nhãn dùng cho lệnh nhẩy

jb k1, ph2  ; kiểm tra bit 1 trên nút chỉnh K1

 

k22_3:  ; đặt tên nhãn dùng cho lệnh nhẩy

call disp2  ; tiếp tục cho hiển thị số với disp2

jnb k1, k22_3 ; kiểm tra bit 0 trên nút nhấn K1

setb p3.0  ; cho tắt Led trên chân p3.0

clr p3.1   ; cho sáng Led trên chân p3.1

 

 

;;----------------------------------------

ph3:   ; đặt tên nhãn dùng cho lệnh nhẩy

call disp3  ; cho hiển thị số với trình disp3

jb k2, ph301  ; kiểm tra bit 1 trên nút nhấn K2

 

k33_1:   ; đặt tên nhãn dùng cho lệnh nhẩy

call disp3  ; tiếp tục cho hiện số với trình disp3

jnb k2, k33_1  ; kiểm tra bit 0 trên nút nhấn K2

mov r0, off_hour  ; chuyển trị trong off_hour vào thanh r0

mov a, #01h  ; đặt trị 1 vào thanh a

add a, r0  ; cho cộng trị trong r0 với a, kết quả cho cất trong a

da a  ; biến đổi số trong a ra dạng hai số thập phân hệ cơ 2, cất vào 4 bit thấp và 4 bit cao

mov off_hour, a ; chuyển trị trong a cất vào thanh off_hour

cjne a, #24h, ph3  ; cho a so sánh với trị 24, để định hướng nhẩy

mov off_hour, #0  ; trả trị trong off_hour về lại mức 0

 

ph301:  ; đặt tên nhãn dùng cho lệnh nhẩy

jb k3, ph310  ; kiểm tra bit 1 trên nút nhấn K3

 

k33_2:  ; đặt tên nhãn dùng cho lệnh nhẩy

call disp3  ; tiếp tục cho hiện số với trình disp3

jnb k3, k33_2  ; kiểm tra bit 0 trên nút nhấn K3

mov r0, off_minute  ; chuyển trị trong off_minute vào thanh r0

mov a, #01h  ; đặt trị 1 vào thanh ghi a

add a, r0  ; cho trị trong r0 cộng với trị trong a, kết quả cất vào a

da a  ; biến đổi trị trong a ra hai số thập phân hệ cơ 2, cất trong 4 bit thấp và 4 bit cao

mov off_minute, a  ; chuyển trị trong a cất vào thanh off_minute

cjne a, #60h, ph3   ; cho trị trong a so sánh với con số 60, để định hướng nhẩy

mov off_minute, #0  ; trả trị trong thanh off_minute về mức 0

 

ph310:  ; đặt tên nhãn dùng cho lệnh nhẩy

jb k1, ph3  ; kiểm tra bit 1 trên nút nhấn K1

 

k33_3:  ; đặt tên nhãn dùng cho lệnh nhẩy

call disp3 ; tiếp tục cho hiển thị số với trình disp3

jnb k1, k33_3  ; kiểm tra bit 0 trên nút nhấn K1

jmp ph4  ; nhẩy đến tên nhãn ph4

 

 

;;----------------------------------------

tend:  ; đặt tên nhãn dùng cho lệnh nhẩy

setb ex0  ; cho mở lại chức năng ngắt ngoài, ngắt với _INT0

setb tr0  ; cho xung vào mạch đếm của timer 0

setb 00h  ; đặt bit kiểm tra về trạng thái 00h

setb et0 ; cho mở ngắt theo bit báo tràn tf0

setb p3.7  ; đặt chân p3.7 lên mức áp cao

pop psw  ; hoàn trả lại trị trước đó cho thanh psw

pop acc  ; hoàn trả lại trị trước đó cho thanh a

reti  ; dùng chương trình ngắt

end ; dừng biên dịch ra mã lệnh tại đây

 

 

 

 

Tạm kết bài viết này

 

 

Trên đây là một thí dụ về cách dùng ic lập trình AT89C51 40 chân để làm mạch điện đồng hồ có thêm chức năng chỉnh giờ mở (on_timer) và chỉnh giờ tắt (off_timer), nó có thể dùng làm đồng hồ hẹn giờ để đóng mở các thiết bị. Thật ra còn có rất nhiều cách viết các chương trình đồng hồ cho các ic lập trình, tuy nhiên nếu Bạn xem và hiểu kỹ bài viết này Bạn sẽ thấy được nhiều phương hướng để có thể viết được các chương trình khác tương tự, hay hơn và có nhiều tính năng hơn. Khi có dịp chúng ta sẽ trở lại chuyên đề này với các thí dụ hấp dẫn hơn.  

 

 

 

 

 

Chú ý!  Chú ý!

 

 

Nếu Bạn thích tìm hiểu cách viết chương trình nguồn cho Đồng hồ có thêm lịch Vạn Niên bằng Assembler.

 

Bạn hãy click vào dòng này để đến trang web có tư liệu trên  

 

 

 

 

 

 

Vui lòng để lại bình luận
  • online support profile

    vivian.wang.yun

    Kinh doanh linh kiện và thiết bị ngành điện tử và điều khiển điện
Top