Vi điều khiển
movc a, @a+dptr ; Vào bảng lấy mã theo trị của a, lấy xong mã cho cất vào a
Đếm giờ,phút,giây
* Nút K1 dùng chọn các mode chỉnh: Mode chỉnh giờ, mode chỉnh giờ mở, mode chỉnh giờ tắt.
* Nút K2 dùng để chỉnh phần giờ.
* Nút K3 dùng để chỉnh phần phút.
* Nút K4 cho đồng hồ trở lại hoạt động bình thường.
Trong
mạch dùng 6 Led số mã 7 đoạn, có chân anode chung. Chúng ta dùng 2 số
cho hiển thị giờ, 2 số cho hiển thị phút và 2 số cho hiển thị giây.
Trong
mạch cũng dùng các Led đơn để chỉ trạng thái hoạt động của đồng hồ. Một
Led (trên chân p3.7) dùng chỉ trạng thái báo giờ. Dùng 2 Led (trên
chân p0.0, p0.1) chỉ trạng thái mode chỉnh và 2 Led nữa (trên chân
p3.0, p3.1) dùng chỉ trang thái đang điều chỉnh.
Trong câu hỏi em nói dùng 10 Led để chỉ thị trạng thái chỉnh, quả thật tôi không hiểu em nói gì? Trạng thái chỉnh gì?
Ở mạch
này, em có thể chỉnh hẹn giờ báo mở (Timer ON) và chỉnh hẹn giờ báo tắt
(Timer OFF) trạng thái báo với Led gắn trên chân p3.7.
Nhưng
thôi - theo tôi nghĩ - dù sao đi nữa khi các em đã hiểu thật rõ chương
trình đồng hồ này rồi thì việc cho nó biến hóa ra các dạng thức khác,
sẽ không còn là công việc quá phức tạp nữa, phải không?
Mong
các em đọc kỹ bài viết soạn lại này, tôi nghĩ trên phương diện dùng nó
để học hỏi làm quen với công việc lập trình với ic vi điều khiển cũng
rất đáng công. Chúc các em học hành tấn bộ, càng học càng giỏi, muốn là
làm được. Chào! (VKH)
Khái quát về ic vi điều khiển AT89C51.
Muốn lập trình cho ic vi điều khiển nào (hay cả các ic vi xử lý nữa),
trước tiên Bạn phải hiểu rõ các đặc tính của ic đó. Với ic vi điều
khiển AT89C51 cũng không ngoại lệ. Trong phần này chúng ta sẽ vắn tắt về
cấu trúc nội tại của loại ic này. Với ic AT89C51, chúng ta cần biết 4 điều về nó, đó là:
(1) Công dụng các chân của ic. Các chân cơ bản và nhất là các chân cảng xuất nhập dữ liệu.
(2) Cấu trúc các khối chức năng bên trong để hiểu sự vận hành của nó.
(3) Cách tổ chức các bộ nhớ, và nhất là phải hiều thật rõ các thanh nhớ đặc dụng.
(4) Tập lệnh mà ic đó hiểu và chấp hành.
(1) Công dụng các chân của ic. Các chân cơ bản và nhất là các chân cảng xuất nhập dữ liệu
Hình vẽ cho thấy, ic AT89C51 có 40 chân. Các chân chia ra làm 2 nhóm:
Nhóm chân cơ bản
gồm có chân 20 nối masse và chân 40 nối vào đường nguồn 5V. Chân 18, 19
gắn thạch anh để định tần cho mạch dao động, do một lệnh cần 12 phân
đoạn, nên tần số xung nhịp sẽ là 1MHz hay chu kỳ lệnh sẽ 1us.
Chân số 9 dùng làm chân reset, nó tạo ra tác dụng reset với mức volt
cao. Chân 31 dùng chọn định làm việc với bộ nhớ trong hay cả với bộ nhớ
ngoài. Các chân 29, 30 sẽ dùng khi chi ic AT89C51 làm việc với các bộ
nhớ ngoài.
Nhóm các chân dùng làm cảng xuất nhập dữ liệu.
IC AT89C51 có 4 cảng, mỗi cảng 8 bit, vậy có 32 chân dùng xuất nhập
bit. Người ta đã dùng tập tin định nghĩa đặt tên cho cảng và đặt tên cho
các chân này. Đó là:
* Các
chân 39, 38, 37, 36, 35, 33, 32 đã được đặt tên là p0.0, p0.1, p0.2,
p0.3, p0.4, p0.5, p0.6, p0.7 và cả 8 chân gôm lại gọi là p0 (hay gọi là
cảng port 0).
* Các
chân 1, 2, 3, 4, 5, 6, 7, 8 đã được đặt tên là p1.0, p1.1, p1.2, p1.3,
p1.4, p1.5, p1.6, p1.7 và cả 8 chân gôm lại gọi là p1 (hay gọi là cảng
port 1).
* Các
chân 21, 22, 23, 24, 25, 26, 27, 28 đã được đặt tên là p2.0, p2.1, p2.2,
p2.3, p2.4, p2.5, p2.6, p2.7 và cả 8 chân gôm lại gọi là p2 (hay gọi
là cảng port 2).
* Các
chân 10, 11, 12, 13, 14, 15 , 16, 17, 18 đã được đặt tên là p3.0, p3.1,
p3.2, p3.3, p3.4, p3.5, p3.6, p3.7 và cả 8 chân gôm lại gọi là p3 (hay
gọi là cảng port 3).
Với các tên đã đặt như vậy, nên khi viết các câu lệnh, Bạn có thể dùng trực tiếp các tên gọi này, nhờ vậy cũng rất tiện. Bên
cạnh hình trên là một sơ đồ mạch điện cơ bản, khi Bạn dùng ic AT89C51
Bạn có thể ráp theo sơ đồ mạch điện này. Các chương trình điều khiển của
Bạn sẽ phải thông quả 4 cảng này để điều khiển các thiết bị, do đó việc
hiểu rõ tác dụng của các cảng này là rất quan trọng.
(2) Cấu trúc các khối chức năng bên trong để hiểu sự vận hành của nó.
Từ sơ
đồ khối chức năng trên, Bạn sẽ thấy cách vận hành bên trong của ic vi
điều khiển AT89C51. Trong ic có khối xử lý phép toán ALU, ALU kết hợp
với thanh ghi acc (còn gọi là thanh a) và thanh b, đây là khối toán
thuật quan trong của ic. Bộ lấy câu lệnh của chương trình trong khối nhớ
Flash để chấp hành, cách chạy
chương trình theo thanh đếm PC và địa chỉ thì theo thanh ghi con trỏ
dptr. Bộ nhớ RAM trong đó có các thanh ghi đặc dụng dùng điều khiển các
cơ phận của ic. Ngoài ra là sự điều hành 4 cảng p0, p1, p2, p3 dùng để
xuất nhập dữ liệu dạng bit. Cuối cùng là khối dao động tạo xung nhịp
theo thạch anh gắn thêm từ bên ngoài.
(3) Cách tổ chức các bộ nhớ, và nhất là phải hiểu thật rõ các thanh nhớ đặc dụng (SFR).
Hình vẽ
cho thấy các bộ nhớ trong của ic AT89C51. Với bộ nhớ RAM ,ngoài 128
thanh dùng làm các thanh nhớ đặc dụng (SFR) còn lại 128 thanh ở vùng
thấp có thể cho ghi đọc tùy ý. Với bộ nhớ EEPROM, có 4K thanh nhớ, tức
1024x4 số thanh nhớ nội. Khi Bạn chỉ muốn chạy chương trình có trong bộ
nhớ nội thì cho chân /EA ở mức áp cao (nối vào nguồn 5V), trường hợp Bạn
còn muốn chạy các chương trình có trong bộ nhớ ngoài thì cho chân /EA
xuống mức áp thấp, tức nối xuống masse.
Khi Bạn
cho ghi các chương trình từ file .hex vào bộ nhớ này, thì chân /EA phải
nhận đủ mức áp Vpp=12V (chuyện này hộp nạp sẽ làm).
Do ic
AT89C51 chỉ có thể xử lý bộ địa chỉ 16 bit (8 bit x2), nên nó chỉ có thể
truy cập các bộ nhớ ngoài RAM hay ROM có dung lượng là 65536 thanh nhớ
(quen gọi là bộ nhớ 64K).
Hình vẽ
cho thấy cách sắp xếp của bộ nhớ RAM của ic AT89C51. Trong ic vi điều
khiển nào cũng vậy, việc hiểu rõ cấu trúc của bộ nhớ RAM là rất quan
trọng, Ở đây nó có 256 thanh nhớ, được chia ra làm 2 phần. Phần 128
thanh nhớ vùng trên có nhiều thanh dùng làm thanh nhớ đặc dụng (SFR), ở
vùng này cũng còn lại nhiều thanh không dùng, nó có công dụng dự phòng
tăng tính khả tin cho ic và Phân 128 thanh nhớ ở vùng dưới dùng làm các
thanh nhớ ghi đọc tùy ý. Đây chính là các thanh nhớ "sân khấu" dùng điều
hành các hoạt động của ic, các thanh nhớ ghi đọc được này càng nhiều
thì hoạt động của ic càng linh động và nhanh. Cái đặc sắc của ic AT89C51
là trong một số thanh nhớ (Bạn xem hình), người ta còn tạo ra địa chỉ
cho từng bit nhớ. Vậy chúng ta có thể truy cập các thanh nhớ bằng địa
chỉ thanh và còn có thể truy cập từng bit nhớ bằng địa chỉ bit.
Hình
trên đây, tôi vẽ lại vùng các thanh nhớ có cho bố trí các bit nhớ. Có
Bạn hỏi làm sao phân biệt được việc truy cập địa chỉ của bit và địa chỉ
của thanh. Vấn đề này được qui định rất rõ ràng, nó tùy theo tác vụ của
câu lệnh.
Một thí dụ:
mov 00h, #10 ; Lệnh này cho nạp trị thập phân 10 vào thanh ghi 00h (tức thanh r0)
clr 00h ;
Lệnh này cho xóa bit 00h (hay đặt 0 vào địa chỉ 00h), nhìn bảng chúng
ta thấy bit đầu của thanh nhớ 20h có địa chỉ bit là 00h (Bạn xem hình)
.
Trong 2
câu lệnh trên, cũng đều có địa chỉ là 00h. Nhưng khi dùng cho các câu
lệnh có tác vụ trên thanh thì nó là địa chỉ thanh, như lệnh mov (move)
trên. Và khi dùng với câu lệnh có tác vụ trên bit thì đó là địa chỉ
bit, như lệnh clr (clear bit)
Để
tiện dùng, người ta đã đặt tên cho 8 thanh nhớ trong bank0 là: r0, r1,
r2, r3, r4, r5, r6, r7, khi ở bank 0 nó có địa chỉ tương ứng là 00h,
01h, 02h, 03h, 04h, 05h, 06h, 07h. Bạn có thể cho dời 8 thanh này vào
bank1, bank2 hay bank3 bằng các set bit trong thanh ghi trạng thái PSW
với 2 bit RS1, RS0.
Nếu Bạn chọn:
RS1 = 0 và RS0 = 0 , có nghĩa là 8 thanh r0, r1, r2, r3, r4, r5, r6, r7 nằm ở bank0 (mặc định).
RS1 = 0 và RS0 = 1 , có nghĩa là 8 thanh r0, r1, r2, r3, r4, r5, r6, r7 cho nằm ở bank1.
RS1 = 1 và RS0 = 0 , có nghĩa là 8 thanh r0, r1, r2, r3, r4, r5, r6, r7 cho nằm ở bank2.
RS1 = 1 và RS0 = 1 , có nghĩa là 8 thanh r0, r1, r2, r3, r4, r5, r6, r7 cho nằm ở bank3.
Trong 8 thanh r0,
r1, r2, r3, r4, r5, r6, r7 chỉ có 2 thanh r0, r1 cho Bạn truy cập địa
chỉ gián tiếp rất hay với ký hiệu là @r0, @r1. Bạn xem các câu lệnh sau:
mov r0, #20h ; Câu này là nạp trị 20h vào thanh ghi r0 (r0 có địa chỉ mặc định là 00h trong RAM).
mov
@r0, #20h ; Trong câu lệnh này là Bạn cho nạp trị 20h vào thanh nhớ có
địa chỉ là 20h ( vì trong r0 đã có trị 20h, @r0 không phải là địa chỉ
00h).
Các thanh khác như r2, r3, r4, r5, r6, r7 không có tác vụ này.
(4) Tập lệnh mà ic đó hiểu và chấp hành (Bảng liệt kê các câu lệnh dùng cho AT89C51).
Sơ đồ mạch điện: Đồng hồ có chỉnh giờ dùng ic vi điều khiển AT89C51
(Sơ đồ này tôi dùng OrCAD vẽ lại theo các câu lệnh trong chương trình nguồn ở bên dưới)
Còn đây
là bài thực hành đồng hồ đã tìm được trên mạng tiếng Hoa (Tương ứng với
chương trình dưới. Hình này và sơ đồ mạch điện cho nhiều chi tiết cụ
thể hơn. Bạn hãy tham khảo hình theo các câu lệnh)
(Hình chụp bo thực hành: Đồng hồ có hẹn giờ chạy với ic AT89C51)
Sơ đồ gốc của bài thực hành này, tư liệu lấy từ trang Web tiếng Hoa (Hình khá mờ):
Giải thích mạch điện (Tôi tách sơ đồ trên ra làm 5 phần như sau):
Hình 1: Cho thấy mạch điện cơ bản của ic AT89C51 .
Chân 20
nối masse, chân 40 nối nguồn 5V. Chân 18, 19 gắn thạch anh định tần
(Mạch dùng thạch anh có tần số 6MHz). Chân 9 nối vào mạch reset, khi cấp
điện tụ c1 (10uF) nạp dòng qua R4 (10K), tạm thời đưa chân 9 lên mức áp
cao để tạo tác dụng reset, lúc này chương trình sẽ quay lại từ thanh
00h của bộ nhớ ROM (trong AT89C51). Chân 31 cho nối vào nguồn 5V là muốn
chỉ dùng bộ nhớ ROM trong.
Hình 2: Gắn các nút chỉnh và các Led chỉ thị trên port 3.
Led chỉ thị trên chân P3.1, P3.0 dùng chỉ trạng thái mode
đang chỉnh. Led trên chân p3.7 dùng báo mạch đã đến đúng giờ mở hay
đúng giờ tắt, Bạn có thể dùng bit này để điều khiển một TRIAC, đóng mở
các thiết bị ngoài. Theo chương trình nguồn thì
Khóa điện K1 là chọn mode.
Khóa điện K2 là chỉnh số chỉ giờ
Khóa điện K3 là chỉnh số chỉnh giây
Khóa điện K4 là trở lại chức năng đồng hồ.
Hình 3: Công dụng của port2.
Dùng 6
chân trên port 2 để đóng mở các transistor 8050, nhầm cấp 5V cho chân
anode chung của các đèn số. Dùng chân p2.6 làm tắt mở Led chỉ thị và
dùng tín hiệu trên chân p2.7 qua tầng khuếch đại với transistor 8550 để
kích thích loa, báo bằng âm thanh.
Hình 4: Mạch kiểm soát các thiết bị ngoài với bit trên chân p3.7.
Khi
chân p3.7 lên mức áp cao (đúng giờ mở, ON), nó qua bộ ghép quang điện
cấp áp cho cực G của TRIAC, TRIAC dẫn điện và đèn sẽ được cấp điện nên
phát sáng.
... và đến khi chân p3.7 xuống mức áp thấp (đúng giờ tắt OFF), nó qua bộ ghép quang điện sẽ làm tắt TRIAC và đèn sẽ tắt.
Đúng giờ hẹn (ON) thì đèn sáng và sau đó... đúng giờ hẹn (OFF) thì đèn sẽ tắt và qui trình sẽ lập lại.
Hình 5: Dùng port2 và port 1 để điều khiển bảng đèn số với các Led theo mã 7 đoạn.
Sơ đồ
cho thấy: Mã hiện số 7 đoạn cho xuất ra trên các chân của port 1. Nó cấp
dòng cho các chân cathode của đèn số và port 2 dùng tắt mở các
transistor 8050 (pnp) để mỗi lần chỉ cấp 5V cho một chân anode chung của
một đèn số. Với cách làm việc đủ nhanh này, Bạn sẽ luôn thấy giờ - phút
- giây hiện ra trên 6 đèn số 7 đoạn trên (nhưng thật ra mỗi lần chỉ mở
có một đèn số).
Để hiểu rõ hơn về cách hiện số trên đèn số Led 7 đoạn, Bạn xem hình động sau:
Trong
đó mã nhị phân xuất ra để làm các chân cathode của các Led trong đèn
thông masse được cho xuất ra trên cảng port 1. Bạn thấy với mã hiện số
xuất ra, nếu chúng ta sắp các Led theo hàng ngang thì chẳng thấy gì lạ
cả, chỉ thấy các Led nhấp nháy, nhưng khi sắp các Led này theo dạng hình
chữ Nhật (日) thì vấn đề lại khác, nó chính là các con số từ 0...9.
Chương trình nguồn.
;; 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
(Bạn
có thể cho cắt file nguồn này dán vào trình MIDE để cho biên dịch ra
file .hex và cho nạp file này vào ic AT89C51, nạp xong gắn ic này vào bo
mạch điện trên, khi mạch được cấp điện các Led số sẽ hiện ra
Giờ-Phút-Giây)
Sau khi
biên dịch xong, trình MIDE báo không lỗi (no errors), lúc này Bạn sẽ có
file mã lấy họ .hex, trong file này, Bạn thấy các hàng số viết theo hệ
đếm 16, khi nạp vào ic nó sẽ được cho đổi ra dạng nhị phân và nạp vào bộ
nhớ EEP-ROM của ic vi điều khiển AT89C51.
:060000000200300201C9FC
:03000B000200EB05
:10003000758150C20075210075220075230075245A
:1000400000752500752600752700752800752900A4
:10005000758C05758A05758902D2AFD2A8C2A9C26E
:100060008CC288E523B5260AE524B52705D2B70258
:10007000007EE523B52807E524B52902C2B7300084
:10008000E212009080DDC0F9A4B0999282F88090CD
:10009000A823900086E8C4540F93F590C2A01201E3
:1000A000AFD2A0E8540F93F590C2A11201AFD2A134
:1000B000A924E9C4540F93F590C2A21201AFD2A2B1
:1000C000E9540F93F590C2A31201AFD2A3AA25EA77
:1000D000C4540F93F590C2A41201AFD2A4EA540FF6
:1000E00093F590C2A51201AFD2A522C0E0C0D00501
:1000F00021E521B5C8387521000522E522B40A2E74
:10010000752200B280B28174012525D4F525B46032
:100110001D75250074012524D4F524B460107524C0
:100120000074012523D4F523B42403752300D0D013
:10013000D0E032A826900086E8C4540F93F590C210
:10014000A01201AFD2A0E8540F93F590C2A1120102
:10015000AFD2A1A927E9C4540F93F590C2A212010E
:10016000AFD2A2E9540F93F590C2A31201AFD2A36C
:1001700022A828900086E8C4540F93F590C2A012DC
:1001800001AFD2A0E8540F93F590C2A11201AFD2F3
:10019000A1A929E9C4540F93F590C2A21201AFD2CC
:1001A000A2E9540F93F590C2A31201AFD2A3227516
:1001B00030027531FFD531FDD530F72275326475C7
:1001C00033FAD533FDD532F722C0E0C0D0C2A8C281
:1001D0008CC2A9119020B2FB119030B2FBD2B1D2E7
:1001E000B0119020B413119030B4FBA823740128EF
:1001F000D4F523B424EB75230020B313119030B34E
:10020000FBA824740128D4F524B460D575240020FB
:10021000B508119030B5FB02029820B2C41190309D
:10022000B2FBC2B0D2B1313320B413313330B4FB9E
:10023000A826740128D4F526B424EB75260020B333
:1002400013313330B3FBA827740128D4F527B460E9
:10025000D575270020B2CF313330B2FBD2B0C2B156
:10026000317120B413317130B4FBA828740128D443
:10027000F528B424EB75280020B313317130B3FB9B
:10028000A829740128D4F529B460D575290020B2B5
:10029000CF317130B2FB21DDD2A8D28CD200D2A9ED
:0702A000D2B7D0D0D0E0324C
:00000001FF
:03000B000200EB05
:10003000758150C20075210075220075230075245A
:1000400000752500752600752700752800752900A4
:10005000758C05758A05758902D2AFD2A8C2A9C26E
:100060008CC288E523B5260AE524B52705D2B70258
:10007000007EE523B52807E524B52902C2B7300084
:10008000E212009080DDC0F9A4B0999282F88090CD
:10009000A823900086E8C4540F93F590C2A01201E3
:1000A000AFD2A0E8540F93F590C2A11201AFD2A134
:1000B000A924E9C4540F93F590C2A21201AFD2A2B1
:1000C000E9540F93F590C2A31201AFD2A3AA25EA77
:1000D000C4540F93F590C2A41201AFD2A4EA540FF6
:1000E00093F590C2A51201AFD2A522C0E0C0D00501
:1000F00021E521B5C8387521000522E522B40A2E74
:10010000752200B280B28174012525D4F525B46032
:100110001D75250074012524D4F524B460107524C0
:100120000074012523D4F523B42403752300D0D013
:10013000D0E032A826900086E8C4540F93F590C210
:10014000A01201AFD2A0E8540F93F590C2A1120102
:10015000AFD2A1A927E9C4540F93F590C2A212010E
:10016000AFD2A2E9540F93F590C2A31201AFD2A36C
:1001700022A828900086E8C4540F93F590C2A012DC
:1001800001AFD2A0E8540F93F590C2A11201AFD2F3
:10019000A1A929E9C4540F93F590C2A21201AFD2CC
:1001A000A2E9540F93F590C2A31201AFD2A3227516
:1001B00030027531FFD531FDD530F72275326475C7
:1001C00033FAD533FDD532F722C0E0C0D0C2A8C281
:1001D0008CC2A9119020B2FB119030B2FBD2B1D2E7
:1001E000B0119020B413119030B4FBA823740128EF
:1001F000D4F523B424EB75230020B313119030B34E
:10020000FBA824740128D4F524B460D575240020FB
:10021000B508119030B5FB02029820B2C41190309D
:10022000B2FBC2B0D2B1313320B413313330B4FB9E
:10023000A826740128D4F526B424EB75260020B333
:1002400013313330B3FBA827740128D4F527B460E9
:10025000D575270020B2CF313330B2FBD2B0C2B156
:10026000317120B413317130B4FBA828740128D443
:10027000F528B424EB75280020B313317130B3FB9B
:10028000A829740128D4F529B460D575290020B2B5
:10029000CF317130B2FB21DDD2A8D28CD200D2A9ED
:0702A000D2B7D0D0D0E0324C
:00000001FF
Phân tích chương trình nguồn.
;; ---------------------------------------------------------------------------------------
;; Bạn cho định nghĩa các bit, các thanh nhớ bằng chữ cho dễ nhớ dễ dùng trong câu lệnh.
;;----------------------------------------------------
;; Dong ho co nut chinh mo chinh tat
;;----------------------------------------------------
k1 bit p3.2 ; Định nghĩa chữ K1 là chân p3.2
k2 bit p3.4 ; Định nghĩa chữ K2 là chân p3.4
k3 bit p3.3 ; Định nghĩa chữ K3 là chân p3.3
k4 bit p3.5 ; Định nghĩa chữ K4 là chân p3.5
;; Dùng tên đặt cho các thanh địa chỉ để sau này dùng trong các câu lệnh sẽ dễ nhớ hơn.
c_hour equ 23h ; Lấy thanh nhớ 23h để nhớ số đếm giờ
c_minute equ 24h ; Lấy thanh nhớ 24h để nhớ số đếm phút
c_second equ 25h ; Lấy thanh nhớ 25h để nhớ số đếm giây
on_hour equ 26h ; Lấy thanh nhớ 26h để nhớ số đếm giờ hẹn mở
on_minute equ 27h ; Lấy thanh nhớ 27h để nhớ số đếm phút hẹn mở
off_hour equ 28h ; Lấy thanh nhớ 28h để nhớ số đếm giờ hẹn tắt
off_minute equ 29h ; Lấy thanh nhớ 29h để nhớ số đếm phút hẹn tắt
;; Khởi đầu chương trình đồng hồ từ địa chỉ thanh 0000h tức thanh reset.
org 0000h ; Khởi từ địa chỉ của thanh reset.
jmp main ; Cho nhẩy qua các thanh nhớ đã dùng cho chức năng ngắt
org 0003h ; Nơi chạy trình ngắt ngoài theo bit 0 trên chân p3.2.
jmp wint0 ; Chương trình ngắt theo phím nhấn gắn trên p3.2
org 000bh ; Nơi chạy trình ngắt theo bit tràn tf0 của timer T0.
jmp wt0 ; Chương trình ngắt theo bit tràn tf0 của timer T0
org 0030h
; ------------Khởi đầu chương trình chính----------------
main: ; Tên nhãn chương trình chính
mov sp, #50h ; Xác định địa chỉ chọn vùng làm ngăn xếp
;; Các trị khởi đầu, tất cả cho về trị 0.
clr 00h ; Cho xóa bit kiểm tra lấy ở địa chỉ 00h
mov 21h, #0 ; Cho xóa sạch thanh nhớ có địa chỉ là 21h
mov 22h, #0 ; Cho xóa sạch thanh nhớ có địa chỉ là 22h
mov c_hour, #0 ; Cho xóa sạch thanh nhớ dùng đếm giờ
mov c_minute, #0 ; Cho xóa sạch thanh nhớ dùng đếm phút
mov c_second, #0 ; Cho xóa sạch thanh nhớ dùng đếm giây
mov on_hour, #0 ; Cho xóa sạch thanh nhớ dùng hẹn giờ mở
mov on_minute, #0 ; Cho xóa sạch thanh nhớ dùng hẹn phút mở
mov off_hour, #0 ; Cho xóa sạch thanh nhớ dùng hẹn giờ tắt
mov off_minute, #0 ; Cho xóa sạch thanh nhớ dùng hẹn phút tắt
;;----------------Đặt mode đồng hồ T0 và đặt trị khởi đầu vào thanh th0, tl0 của timer T0--------------
;;Dùng đồng hồ timer 0, mode 2, mode tự nạp lại để cho đếm thời gian
mov th0, #05 ; Đặt trị khởi đầu cho thanh th0.
mov tl0, #05 ; ; Đặt trị khởi đầu cho thanh tl0.
mov tmod, #00000010b ;02h (Chọn đồng hồ T0, chạy theo mode 2, mode 8 bit, tự nạp lại).
;;---------------Đặt các ngắt và điều kiện làm việc của đồng hồ-----------------
;;
setb ea ; Cho mở tất cả 6 ngắt của AT89C51
setb ex0 ; Đặt ngắt cho /INT0 (Cho mở ngắt ngoài /INT0, trên chân p3.2)
clr et0 ; Tắt ngắt theo bit tràn của T0
clr tr0 ; Cho ngưng chạy đồng hồ T0
clr it0 ; Cho xóa tính ưu tiên của ngắt /INT0
;---------------- Khởi đầu cho đếm giờ-----------------
;-----------Kiểm tra đúng giờ để báo mở (ON).
m:
mov a, c_hour ; Chuyển trị trong thanh đếm giờ vào a
cjne a, on_hour, off_time ; So sánh trị trong a với trị trong on_hour, qua so với off_time
mov a, c_minute ; Chuyển trị trong thanh đếm phút vào a
cjne a, on_minute, off_time ; So sánh trị trong a với trị trong on_minute, qua so với off_time
setb p3.7 ; Đặt p3.7 lên mức cao để báo giờ mở
jmp next ; Nhẩy về tên nhãn next để tiếp tục phần đồng hồ
;-----------Kiểm tra đúng giờ để báo tăt (OFF).
off_time:
mov a, c_hour ; chuyển trị trong c_hour vào thanh a.
cjne a, off_hour, next ; So sánh trị của a với trị trong off_hour.
mov a, c_minute ; chuyển trị trong c_minute vào thanh a.
cjne a, off_minute, next ; So sánh trị của a với trị trong off_minute
clr p3.7 ; Đặt p3.7 xuống mức áp thấp để báo giờ tắt
next: jnb 00h, m ; Kiểm tra bit 00h, nếu nó ở bit 0 thì nhẩy đến tên nhãn m
call disp1 ; Gọi chương trình cho hiển thị đồng hồ
jmp m ; nhẩy trở lại tên nhãn m tiếp tục kiểm tra giờ mở giờ tắt
;;-------------Bảng chứa các mã hiện số trên Led 7 đoạn--------
tab:
db 0c0h (0), 0f9h (1), 0a4h (2), 0b0h (3), 99h (4), 92h (5), 82h (6), 0f8h (7), 80h (8), 90h (9)
;; Ghi chú: Bảng mã này sẽ làm sáng các Led trên đèn số, tùy theo sự sắp xếp của Bạn.
;; Bạn có thể chõn định lại cho đúng. Nếu đưa về dạng hệ cơ 2 sẽ dễ thấy hơn.
;; 0c0h (0), 1100-0000
;; 0f9h (1), 1111-1001
;; 0a4h (2), 1010-0100
;; 0b0h (3), 1011-0000
;; 99h (4), 1001-1001
;; 92h (5), 1001-0010
;; 82h (6), 1000-0010
;; 0f8h (7), 1111-1000
;; 80h (8), 1000-0000
;; 90h (9) 1001-0000
,, Nhìn các dãy số nhị phân, Bạn thấy khi cho xuất bit 0 là Led sáng và cho xuất bit 1 là Led tắt
;; Vậy theo bảng số này, bố trí trên port 1 cho 7 chân cathode của đèn số sẽ là:
;; a (p1.0), b(p1.1), c(p1.2), d(p1.3), e(p1.4), f(p1.5), g(p1.6), (p1.7 không và là dấu chấm).
;;-----------Chương trình cho hiện số lúc đấm giờ bình thường----------------------
disp1:
; Cho hiện số ở 2 số chỉ giờ (hour)
mov r0, c_hour ; chuyển trị trong c_hour vào thanh r0
mov dptr, #tab ; Đặt địa chỉ bảng vào thanh ghi con trỏ
mov a, r0 ; Chuyển trị trong r0 vào thanh a
swap a ; hoán đổi vị trí 4 bit cao 4 bit thấp trong thanh a
anl a, #0fh ; Lấy logic AND để che 4 bit cao, giữ nguyên 4 bit thấp
movc a, @a+dptr ; Vào bảng lấy mã theo trị của a, mã này cất vào a
mov p1, a ; Cho xuất mã hiện số lấy trong bảng ra trên cảng port1
clr p2.0 ; Cho mở số giờ (hàng đơn vị ) bằng cách cấp +5V cho đèn số 7 đoạn
call dl ; Cho làm trễ để đèn số đủ sáng
setb p2.0 ; tắt đèn hiện giờ (đv) để tránh lem số
mov a, r0 ; Chuyển trị có trong thanh r0 vào lại a
anl a, #0fh ; Lấy logic AND để che 4 bit cao, giữ nguyên 4 bit thấp
movc a, @a+dptr ; Vào bảng lấy mã theo trị của a, mã này cất vào a
mov p1, a ; Cho xuất mã hiện số lấy trong bảng ra trên cảng port1
clr p2.1 ; Cho mở số giờ (hàng chục) bằng cách cấp +5V cho đèn số 7 đoạn
call dl ; Cho làm trễ để đèn số đủ sáng
setb p2.1 ; tắt đèn hiện giờ (h chục) để tránh lem số
;; Cho hiện số ở 2 số chỉ phút (minute)
mov r1, c_minute ; Chuyển trị trong c_minute vào thanh r1
mov a, r1 ; Chuyển trị trong r1 vào thanh a
swap a ; hoán đổi vị trí 4 bit cao 4 bit thấp trong thanh a
anl a, #0fh ; Lấy logic AND để che 4 bit cao, giữ nguyên 4 bit thấp
movc a, @a+dptr ; Vào bảng lấy mã theo trị của a, mã này cất vào a
mov p1, a ; Cho xuất mã hiện số lấy trong bảng ra trên cảng port1
clr p2.2 ; Cho mở số phút (hàng đơn vị ) bằng cách cấp +5V cho đèn số 7 đoạn
call dl ; Cho làm trễ để đèn số đủ sáng
setb p2.2 ; tắt đèn hiện phút (h đơn vị) để tránh lem số
mov a, r1 ; Lại chuyển trị trong r1 vào thanh a
anl a, #0fh ; Lấy logic AND để che 4 bit cao, giữ nguyên 4 bit thấp
movc a, @a+dptr ; Vào bảng lấy mã theo trị của a, mã này cất vào
mov p1, a ; Cho xuất mã hiện số lấy trong bảng ra trên cảng port1
clr p2.3 ; Cho mở số phút (hàng chục ) bằng cách cấp +5V cho đèn số 7 đoạn
call dl ; Cho làm trễ để đèn số đủ sáng
setb p2.3 ; tắt đèn hiện phút (h chục) để tránh lem số
;; Cho hiện số ở 2 số chỉ giây (second)
mov r2, c_second ; Chuyển trị trong c_second vào thanh r2
mov a, r2 ; Chuyển trị trong r2 vào thanh a
swap a ; hoán đổi vị trí 4 bit cao 4 bit thấp trong thanh a
anl a, #0fh ; Lấy logic AND để che 4 bit cao, giữ nguyên 4 bit thấp
movc a, @a+dptr ; Vào bảng lấy mã theo trị của a, mã này cất vào a
mov p1, a ; Cho xuất mã hiện số lấy trong bảng ra trên cảng port1
clr p2.4 ; Cho mở số giây (hàng đơn vị ) bằng cách cấp +5V cho đèn số 7 đoạn
call dl ; Cho làm trễ để đèn số đủ sáng
setb p2.4 ; tắt đèn hiện giây (h đơn vị) để tránh lem số
mov a, r2 ; Lại chuyển trị trong r2 vào thanh a
anl a, #0fh ; Lấy logic AND để che 4 bit cao, giữ nguyên 4 bit thấp
movc a, @a+dptr ; Vào bảng lấy mã theo trị của a, mã này cất vào
mov p1, a ; Cho xuất mã hiện số lấy trong bảng ra trên cảng port1
clr p2.5 ; Cho mở số giây (hàng chục ) bằng cách cấp +5V cho đèn số 7 đoạn
call dl ; Cho làm trễ để đèn số đủ sáng
setb p2.5 ; tắt đèn hiện giây (h đơn vị) để tránh lem số
ret ; Quay lại sau câu lệnh CALL DISP1
;; -------------Chương trình đếm thời gian----------------
wt0:
push acc ; Tạm cất trị của thanh a vào ngăn xếp.
push psw ; Tạm cất thanh trạng thái vào ngăn xếp
inc 21h ; cho tăng trị trong thanh 21h theo bước +1.
mov a, 21h ; Chuyển trị trong thanh 21h vào thanh a
cjne a, 0c8h, t0reti ; 200d=0c8h 0.5ms*200=100ms. Cho so sánh a với trị 0c8h để nhẩy
mov 21h, #0 ; Trả trị trong thanh 21h về trị 0
inc 22h ; cho tăng trị trong thanh 22h theo bước +1
mov a, 22h ; Chuyển trị trong thanh 22h vào thanh a
cjne a, #10, t0reti ; 100ms*10=1s. Cho so sánh a với trị 10 để nhẩy
mov 22h, #0 ; Trả trị trong thanh 22h về trị 0
cpl p0.0 ; Lấy bù bit p0.0
cpl p0.1 ; Lấy bù bit p0.0
;;------------Cho đếm Giờ - Phút – Giây theo bước tăng +1 -------------
;; Đếm giây
mov a, #01h ; Cho chuyển trị 01h vào thanh a
add a, c_second ; Cho cộng trị trong thanh c_second với a, kết quả cất vào a
da a ; Đổi về dạng số thập phân ở 4 bit cao và 4 bit thấp
mov c_second, a ; Chuyển trị trong a trở lại thanh c-second
cjne a, #60h, t0reti ; So sánh trị trong a là 60 chưa để nhẩy
mov c_second, #0 ; là 60 rồi thì trả thanh c_second trở lại trị 0
;; Đếm phút
mov a, #01h ; Cho chuyển trị 01h vào thanh a
add a, c_minute ; Cho cộng trị trong thanh c_minute với a, kết quả cất vào a
da a ; Đổi về dạng số thập phân ở 4 bit cao và 4 bit thấp
mov c_minute, a ; Chuyển trị trong a trở lại thanh c-minute
cjne a, #60h, t0reti ; So sánh trị trong a là 60 chưa để nhẩy
mov c_minute, #0 ; là 60 rồi thì trả thanh c_minute trở lại trị 0
;; Đếm giờ
mov a, #01h ; Cho chuyển trị 01h vào thanh a
add a, c_hour ; Cho cộng trị trong thanh c_hour với a, kết quả cất vào a
da a ; Đổi về dạng số thập phân ở 4 bit cao và 4 bit thấp
mov c_hour, a ; Chuyển trị trong a trở lại thanh c-hour
cjne a, #24h, t0reti ; So sánh trị trong a là 24 chưa để nhẩy
mov c_hour, #0 là 24 rồi thì trả thanh c_hour trở lại trị 0
;; Chương trình dừng ngắt timer 0
t0reti:
pop psw
pop acc
reti
;;---------------Cho hiện giờ - phút lúc chỉnh ON-----------------
;; Viết giống như đoạn disp1
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
;;------------------Cho hiện giờ - phút lúc chỉnh OFF----------------------
;; Viết giống như đoạn disp1
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
;;--------------------Chương trình làm trễ để giữ cho Led đủ sáng ------------------
dl:
mov 30h, #02h
dl1: mov 31h, #0ffh
djnz 31h, $
djnz 30h, dl1
ret
;;----------------------Chương trình làm trễ------------------------
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
;----------------------Chương trình kiểm tra phím nhấn -------------------
k1_11:
call disp1 ; Vẫn cho hiển thị đồng hồ với giờ - phút - giây
jb k1, k1_11 ; Kiểm tra phím nhấn K1, chờ nhấn phím để có bit 0
;---------------Kiểm tra phím nhấn K1, chờ bỏ phím
k11_1:
call disp1 ; Vẫn cho hiển thị đồng hồ với giờ - phút - giây
jnb k1, k11_1 ; Kiểm tra phím nhấn K1, chờ bỏ nhấn phím để có bit 1
;;
ph4:
setb p3.1 ; Đặt chân p3.1 lên mức áp cao
setb p3.0 ; Đặt chân p3.0 lên mức áp cao
ph0: call disp1 ; Vẫn cho hiển thị đồng hồ với giờ - phút - giây
jb k2, ph01 ; Kiểm tra phím nhấn K2, chờ nhấn phím để có bit 0
;;
k2_1:
call disp1 ; Vẫn cho hiển thị đồng hồ với giờ - phút - giây
jnb k2, k2_1 ; Kiểm tra phím nhấn K2, chờ bỏ nhấn phím để có bit 1
mov r0, c_hour ; Cho chuyển trị trong c_hour vào thanh r0
mov a, #01h ; Đặt trị 01h vào thanh ghi a
add a, r0 ; Cho cộng trị trong a với 1 và cất vào a
da a ; Thập phân hóa 4 bit cao và 4 bit thấp
mov c_hour, a ; Cho chuyển trị trong a ra thanh c-hour
cjne a, #24h, ph0 ; Cho so sánh a với số 24 để nhẩy
mov c_hour, #0 ; Trả trị trong c-hour về 0
ph01:
jb k3, ph1 ; Kiểm tra phím nhấn K3, chờ nhấn phím để có bit 0
k3_1:
call disp1 ; Vẫn cho hiển thị đồng hồ với giờ - phút - giây
jnb k3, k3_1 ; Kiểm tra phím nhấn K3, chờ bỏ nhấn phím để có bit 1
mov r0, c_minute ; Cho chuyển trị trong c_minute vào thanh r0
mov a, #01h ; Đặt trị 01h vào thanh ghi a
add a, r0 ; Cho cộng trị trong a với r0 và cất vào a
da a ; Thập phân hóa 4 bit cao và 4 bit thấp
mov c_minute, a ; Cho chuyển trị trong a ra thanh c-minute
cjne a, #60h, ph0 ; Cho so sánh a với số 60 để nhẩy
mov c_minute, #0 ; Trả trị trong c-minute về 0
ph1:
jb k4, ph10 ; Kiểm tra phím nhấn K4, chờ nhấn phím để có bit 0
k4_1:
call disp1 ; Vẫn cho hiển thị đồng hồ với giờ - phút - giây
jnb k4, k4_1 ; Kiểm tra phím nhấn K4, chờ bỏ nhấn phím để có bit 1
jmp tend ; Nhẩy không điều kiện đến tên nhãn tend (kết thúc Timer End)
;---------------Vào mode chỉnh giờ - phút cho mode ON---------
ph10:
jb k1, ph0 ; Kiểm tra phím nhấn K1, chờ nhấn phím để có bit 0
k1_1:
call disp1 ; Vẫn cho hiển thị đồng hồ với giờ - phút - giây
jnb k1, k1_1 ; Kiểm tra phím nhấn K1, chờ bỏ nhấn phím để có bit 1
clr p3.0 ; Đặt p3.0 ở mức áp thấp.
setb p3.1 ; Đặt p3.1 ở mức áp cao
;;--------------------------------
ph2:
call disp2 ; Cho hiển thị giờ - phút ở mode ON
jb k2, ph201 ; Kiểm tra phím nhấn K2, chờ nhấn phím để có bit 0
k22_1:
call disp2 ; Vẫn cho hiển thị giờ - phút ở mode ON
jnb k2, k22_1 ; Kiểm tra phím nhấn K2, chờ bỏ nhấn phím để có bit 1
mov r0, on_hour ; Chuyển trị trong on_hour vào thanh r0
mov a, #01h ; Đặt trị 01h vào thanh ghi a
add a, r0 ; Cho cộng trị trong a với r0 và cất vào a
da a ; Thập phân hóa 4 bit cao và 4 bit thấp
mov on_hour, a ; Cho chuyển trị trong a ra thanh on_hour
cjne a, #24h, ph2 ; Cho so sánh a với số 24 để nhẩy
mov on_hour, #0 ; Trả trị trong on-hour về 0
ph201:
jb k3, ph210 ; Kiểm tra phím nhấn K3, chờ nhấn phím để có bit 0
k22_2:
call disp2 ; Vẫn cho hiển thị giờ - phút ở mode ON
jnb k3, k22_2 ; Kiểm tra phím nhấn K3, chờ bỏ nhấn phím để có bit 1
mov r0, on_minute ; Chuyển trị trong on_minute vào thanh r0
mov a, #01h ; Đặt trị 01h vào thanh ghi a
add a, r0 ; Cho cộng trị trong a với r0 và cất vào a
da a ; Thập phân hóa 4 bit cao và 4 bit thấp
mov on_minute, a ; Cho chuyển trị trong a ra thanh on_minute
cjne a, #60h, ph2 ; Cho so sánh a với số 60 để nhẩy
mov on_minute, #0 ; Trả trị trong on-minute về 0
ph210: jb k1, ph2 ; Kiểm tra phím nhấn K1, chờ nhấn phím để có bit 0
k22_3:
call disp2 ; Vẫn cho hiển thị giờ - phút ở mode ON
jnb k1, k22_3 ; Kiểm tra phím nhấn K1, chờ bỏ nhấn phím để có bit 1
setb p3.0 ; Đặt bit p3.0 lên mức áp cao
clr p3.1 ; Đặt bit p3.1 xuống mức áp thấp
;;----------------------------------------
ph3:
call disp3 ; Cho hiển thị giờ - phút ở mode OFF
jb k2, ph301 ; Kiểm tra phím nhấn K2, chờ nhấn phím để có bit 0
k33_1:
call disp3 ; Vẫn cho hiển thị giờ - phút ở mode OFF
jnb k2, k33_1 ; Kiểm tra phím nhấn K2, chờ bỏ nhấn phím để có bit 1
mov r0, off_hour ; Chuyển trị trong off_hour vào thanh r0
mov a, #01h ; Đặt trị 01h vào thanh ghi a
add a, r0 ; Cho cộng trị trong a với r0 và cất vào a
da a ; Thập phân hóa 4 bit cao và 4 bit thấp
mov off_hour, a ; Cho chuyển trị trong a ra thanh off_hour
cjne a, #24h, ph3 ; Cho so sánh a với số 24 để nhẩy
mov off_hour, #0 ; Trả trị trong off-hour về 0
ph301:
jb k3, ph310 ; Kiểm tra phím nhấn K3, chờ nhấn phím để có bit 0
k33_2:
call disp3 ; Vẫn cho hiển thị giờ - phút ở mode OFF
jnb k3, k33_2 ; Kiểm tra phím nhấn K2, chờ bỏ nhấn phím để có bit 1
mov r0, off_minute ; Chuyển trị trong off_minute vào thanh r0
mov a, #01h ; Đặt trị 01h vào thanh ghi a
add a, r0 ; Cho cộng trị trong a với r0 và cất vào a
da a ; Thập phân hóa 4 bit cao và 4 bit thấp
mov off_minute, a ; Cho chuyển trị trong a ra thanh off_minute
cjne a, #60h, ph3 ; Cho so sánh a với số 60 để nhẩy
mov off_minute, #0 ; Trả trị trong off-minute về 0
ph310: jb k1, ph3 ; Kiểm tra phím nhấn K1, chờ nhấn phím để có bit 0
k33_3:
call disp3 ; Vẫn cho hiển thị giờ - phút ở mode OFF
jnb k1, k33_3 ; Kiểm tra phím nhấn K1, chờ bỏ nhấn phím để có bit 1
jmp ph4 ; Nhẩy không điều kiện về tên nhãn ph4
;;----------------------------------------
tend:
setb ex0 ; Set lại bit ex0, cho mở ngắt ngoài trên chân p3.2
setb tr0 ; Set lại bit tr0, cho chạy đồng hồ T0
setb 00h ; Set lại bit kiểm tra ở vị trí 00h
setb et0 ; Set lại bit et0, cho mở ngắt theo bit tràn của timer T0
setb p3.7 ; Đặt chân p3.7 lên mức áp cao
pop psw ; Từ ngắn xếp hoàn trả lại trị cho thanh trạng thái psw
pop acc ; Từ ngăn xếp hoàn trả lại trị cho thanh a
reti ; Dừng chương trình ngắt
end
Khi viết đoạn chương trình trên, Bạn cần hiểu rõ một số vấn đề sau:
* Cách dùng ngắt theo bit báo tràn tf0 để đếm thời gian. Cứ mỗi khi xuất hiện bit tràn tf0=1 là nhẩy về chạy chương trình ngắt ở địa chỉ 000bh, ở đây có lệnh nhẩy vào chương trình ngắt với tên nhãn là wt0 để đếm thời gian và khi đếm xong thì nhẩy đến tên nhãn là toreti và khi gặp câu lệnh reti thì dừng ngắt.
* Chú ý cách dùng câu lệnh da <thanh nhớ (chứa trị nhị phân)>
* Lệnh nhẩy jb <bit>, jnb <bit>. Lệnh nhẩy sau khi kiểm tra các bit của các phím nhấn.
* Lệnh cjne a, <trị>, tên nhãn. Lệnh nhẩy sau phép so sánh để định trị giới hạn của mỗi số đếm, số đếm có thể là 24 (cho giờ), hay là 60 (cho giây, cho phút).
* Để lấy trị liện kê trong bảng nạp vào thanh a thì Bạn dùng câu lệnh:
mov dptr, #tab ; Đặt địa chỉ của bảng vào thanh ghi con trỏ dptr.
Ở đây Bạn xác định trị cho số a, rồi dùng câu lệnh sau để lấy trị trong bảng.
Previous article
Next article
Leave Comments
Đăng nhận xét