Đồng hồ có hẹn giờ chạy với ic vi điều khiển at89c51

84
Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51 Dẫn nhập Một e-mail gửi về tôi viết như sau : Họ tên: Khánh Huy Địa chỉ: Sinh viên Đại Học ĐÀ Lạt Điện thoại: 0979825351 Email: [email protected] Em chào phuclanshop.com và các Thầy !!! Em vô tình tìm tài liệu mới biết Thầy Em xin tự giới thiệu, em tên Huy là sinh viên Trường Đại học Đà lạt, khoa Điện Tử - Viễn Thông Nhóm chúng em đang làm Đồ Án 1 về vi điều khiển dùng IC 89c51, nhóm em được thầy chia nhóm làm đề tài về đồng hồ số dùng IC 89c51, nhưng cả bọn em mới học hợp ngữ chưa đầy nữa tháng nên cũng gặp nhiều khó khăn, nhiệm vụ chúng em là phải làm được đồng hồ chỉnh được giờ, chỉnh phút, hẹn giờ, có một điều khó khăn nữa là thầy cho tụi em 10 led đơn,tương ứng với 10 trạng thái (yêu cầu khi thầy chỉnh đúng giờ hẹn thì 1 đèn sáng,cứ lần 2 thì 2 đèn sáng) tụi em tìm tài liệu nhưng hầu như không có vấn đề liên quan đó,thầy gợi y giùm tụi em, có tài liệu liên quan mong thầy share bọn em, em là nhóm trưởng xin đại diện cả nhóm 6 người cám ơn thầy -Sinh viên Đại Học Đà Lạt Trả lời :

Upload: trungnb22

Post on 29-Jul-2015

559 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

 

 

 

 

 

 

 

Dẫn nhập 

 

Một e-mail gửi về tôi viết như sau: 

Họ và tên: Khánh HuyĐịa chỉ: Sinh viên Đại Học ĐÀ LạtĐiện thoại: 0979825351Email: [email protected] chào phuclanshop.com và các Thầy !!! Em vô tình tìm tài liệu mới biết Thầy Em xin tự giới thiệu, em tên Huy là sinh viên Trường Đại học Đà lạt, khoa Điện Tử - Viễn Thông Nhóm chúng em đang làm Đồ Án 1 về vi điều khiển dùng IC 89c51, nhóm em được thầy chia nhóm làm đề tài về đồng hồ số dùng IC 89c51, nhưng cả bọn em mới học hợp ngữ chưa đầy nữa tháng nên cũng gặp nhiều khó khăn, nhiệm vụ chúng em là phải làm được đồng hồ chỉnh được giờ, chỉnh phút, hẹn giờ, có một điều khó khăn nữa là thầy cho tụi em 10 led đơn,tương ứng với 10 trạng thái (yêu cầu khi thầy chỉnh đúng giờ hẹn thì 1 đèn sáng,cứ lần 2 thì 2 đèn sáng) tụi em tìm tài liệu nhưng hầu như không có vấn đề liên quan đó,thầy gợi y giùm tụi em, có tài liệu liên quan mong thầy share bọn em, em là nhóm trưởng xin đại diện cả nhóm 6 người cám ơn thầy -Sinh viên Đại Học Đà Lạt 

 

Trả lời: 

Chào Huy và cả nhóm 6 em. Tôi đã xem thư Huy và lục tìm lại trong kho dữ liệu cũ thấy có một bài viết có thể đáp ứng được yêu cầu của nhóm em. Trong bài này có 4 nút, dùng chỉnh trạng thái của đồng hồ có hẹn giờ. 

* 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.

Page 2: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

* 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à: 

Page 3: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

(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

Page 4: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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ó. 

 

Page 5: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

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. 

 

Page 6: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

(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

Page 7: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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ự

Page 8: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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

Page 9: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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). 

Page 10: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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). 

 

Page 11: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51
Page 12: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51
Page 13: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51
Page 14: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51
Page 15: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

  

 

Sơ đồ mạch điện:  Đồng hồ có chỉnh giờ dùng ic vi điều khiển AT89C51 

 

Page 16: Đồng hồ có hẹn giờ chạy với 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) 

Page 17: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

(Hình chụp bo thực hành: Đồng hồ có hẹn giờ chạy với ic AT89C51)

Page 18: Đồng hồ có hẹn giờ chạy với ic vi điều khiển 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 .  

Page 19: Đồng hồ có hẹn giờ chạy với ic vi điều khiển 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.

Page 20: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

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âyKhóa điện K4 là trở lại chức năng đồng hồ. 

 

Hình 3: Công dụng của port2. 

Page 21: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

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.

Page 22: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

 

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.

 

Page 23: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

 

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: 

Page 24: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

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 29horg 0000h        jmp main

Page 25: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

org 0003h        jmp wint0org 000bh        jmp wt0org 0030hmain:        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 it0m:        mov a, c_hour        cjne a, on_hour, off_time        mov a, c_minute        cjne a, on_minute, off_time        setb p3.7        jmp nextoff_time:        mov a, c_hour        cjne a, off_hour, next        mov a, c_minute        cjne a, off_minute, next        clr p3.7next:   jnb 00h, m        call disp1        jmp m;;tab:db 0c0h, 0f9h, 0a4h, 0b0h, 99h, 92h, 82h, 0f8h, 80h

Page 26: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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

Page 27: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        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 ;;

Page 28: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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

Page 29: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        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, #02hdl1:    mov 31h, #0ffh        djnz 31h, $        djnz 30h, dl1        ret;;del:        mov 32h, #100del1:   mov 33h, #250        djnz 33h, $        djnz 32h, del1

Page 30: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        ret;;wint0:        push acc        push psw        clr ex0        clr tr0        clr et0k1_11:        call disp1        jb k1, k1_11k11_1:        call disp1        jnb k1, k11_1;;ph4:        setb p3.1        setb p3.0ph0:    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, #0ph01:        jb k3, ph1k3_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, #0ph1:        jb k4, ph10k4_1:

Page 31: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        call disp1        jnb k4, k4_1        jmp tendph10:        jb k1, ph0k1_1:        call disp1        jnb k1, k1_1        clr p3.0        setb p3.1;;--------------------------------ph2:        call disp2        jb k2, ph201k22_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, #0ph201:        jb k3, ph210k22_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, #0ph210:  jb k1, ph2k22_3:        call disp2        jnb k1, k22_3        setb p3.0        clr p3.1;;----------------------------------------ph3:        call disp3        jb k2, ph301

Page 32: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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, #0ph301:        jb k3, ph310k33_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, #0ph310:  jb k1, ph3k33_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        retiend 

 

(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) 

Page 33: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

 

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

Page 34: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

: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

Page 35: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        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ắtorg 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.2org 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 T0org 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ờ

Page 36: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        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ồ 

Page 37: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

;-----------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----------------------

Page 38: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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

Page 39: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        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

Page 40: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        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

Page 41: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        pop acc        reti ;;---------------Cho hiện giờ - phút lúc chỉnh ON-----------------;; Viết giống như đoạn disp1disp2:        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

Page 42: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 ;;------------------Cho hiện giờ - phút lúc chỉnh OFF----------------------;; Viết giống như đoạn disp1disp3:        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 

Page 43: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

;;--------------------Chương trình làm trễ để giữ cho Led đủ sáng ------------------dl:        mov 30h, #02hdl1:    mov 31h, #0ffh        djnz 31h, $        djnz 30h, dl1        ret ;;----------------------Chương trình làm trễ------------------------del:        mov 32h, #100del1:   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ímk11_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 

Page 44: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

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)

Page 45: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 ;---------------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

Page 46: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        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

Page 47: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

        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ắtend 

 

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ớitê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. 

Page 48: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

* 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. 

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 

 

 

 

 

 

 

Nhắn Bạn 

 Bạn click vào các dòng dưới để xem các đề tài có liên quan đến ic vi điều kiển:

 

Trả lời thư: Làm bảng đèn quang báo ma trận Led 8x8 chạy chữ chỉ dùng 1 ic AT89C51 

Viết cho các Bạn mới làm quen với ic vi điều khiển, họ AT89C51, ic làm việc theo câu lệnh. 

  Kể chuyện: Tôi dùng bo khiển AT89C2051, 12 đường ra để ráp đèn hào quang cho tượng Phật Bà trên đất Mỹ 

Giới thiệu sản phẩm: Dùng bo vi điều khiển họ AT89... 16 đường ra làm bảng đèn quảng cáo.  

  Hướng dẫn Bạn viết 10 chương trình ứng dụng cơ bản cho ic vi điều khiển AT89C51

Page 49: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

 Giới thiệu cách dùng hộp nạp ic vi điều khiển TOP853 

 

 

 

 

Tạm kết 

Dùng ic vi điều khiển AT89C51 hay AT89C2051 để viết về mạch điện đồng hồ trên mang có rất nhiều, nhất là mang tiếng Hoa. 

Sau đây tôi ghi lại tư liệu tìm được trên mạng, một chương trình dùng ic vi điều khiển AT89C2051 dùng làm đồng hồ có tính chuyên nghiệp hơn, để Bạn tham khảo.

 

Sơ đồ mạch điện: 

Page 50: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

 

 

Sơ đồ cho thấy, mạch dùng ic vi điều kiển AT89C2051 làm mạch điêu khiển cho hiển thị số chữ trên bảng đèn LCD loại 14 chân có nút chỉnh mức sáng và ic đồng hồ DS1307 chạy thạch anh 32768Hz (tức 2 lũy thừa 15). Mạch điện này chuyên nghiệp hơn, một thời làm ra kinh tế khi dùng nó làm bảng đèn đồng hồ số 

 

Chương trình nguồn: 

;* FILENAME:     AT1307.ASM

;* DISPLAY:      16X2 LCD 4-BIT OPERATION

;* MICRO:        ATMEL AT89C2051 FLASH BASED MICRO

Page 51: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

;* PROJECT:      ALARM CLOCK 

;* DATE:         06/10/98

;* TIMEKEEPER:   DS1307 SERIAL TIMEKEEPER I.C.

;

;

;

$MOD51

SCL       BIT    P1.0

SDA       BIT    P1.1

DS1307W   EQU    0D0H     ; SLAVE ADDRESS 1101 000 + 0 TO WRITE

DS1307R   EQU    0D1H     ; SLAVE ADDRESS 1101 000 + 1 TO READ

FLAGS     DATA   20H

LASTREAD  BIT    FLAGS.0

ACK       BIT    FLAGS.5

BUS_FLT   BIT    FLAGS.6

_2W_BUSY  BIT    FLAGS.7

BITCNT    DATA   21H

BYTECNT   DATA   22H

SECS      DATA   24H      ;   '   SECONDS STORAGE RAM

MINS      DATA   25H      ;   '   MINUTES   '     '

HRS       DATA   26H      ;   '   HOURS     '     '

DAY       DATA   27H      ;   '   DAY       '     '

DATE      DATA   28H      ;   '   DATE      '     '

MONTH     DATA   29H      ;   '   MONTH     '     '

YEAR      DATA   2AH      ;   '   YEAR      '     '

CONTROL   DATA   2BH      ; FOR STORAGE OF CONTROL REGISTER WHEN READ.

ALM_HOUR  DATA   2CH      ; INTERNAL (ALARM HOURS) STORAGE.

ALM_MIN   DATA   2DH      ; INTERNAL (ALARM MINUTES) STORAGE.

ALM_CNTRL DATA   2EH      ; INTERNAL STORAGE FOR ALARM (ON) TIME.

ALM_STORE EQU    08H      ; DS1307 RAM, ALARM STORAGE, BEGINNING.

; ***LCD CONTROL***

LCD_DATA  EQU    090H

LCD_DB4   EQU    094H     ; P1.4 HIGH NIBBLE OF PORT 1 IS USED FOR DATA

LCD_DB5   EQU    095H     ; P1.5 HIGH NIBBLE OF PORT 1 IS USED FOR DATA

LCD_DB6   EQU    096H     ; P1.6 HIGH NIBBLE OF PORT 1 IS USED FOR DATA

LCD_DB7   EQU    097H     ; P1.7 HIGH NIBBLE OF PORT 1 IS USED FOR DATA

LCD_RS    EQU    0B3H     ; P3.3 LCD REGISTER SELECT LINE

LCD_RW    EQU    0B4H     ; P3.4 LCD READ / WRITE LINE

LCD_E     EQU    0B5H     ; P3.5 LCD ENABLE LINE

; ***USER INPUT KEYS***

UP_BTTN   BIT    0B0H     ; P3.0  UP

DOWN_BTTN BIT    0B1H     ; P3.1  DOWN

ENTER     BIT    0B2H     ; P3.2  ENTER

ALARM_SET BIT    092H     ; P1.2  ALARM TIME SET SELECT

; ***SYSTEM INSTRUCTIONS***

CONFIG    EQU    28H      ; 4-BIT DATA,2 LINES,5X7 MATRIX LCD

ENTRYMODE EQU    6        ; INCREMENT CURSOR DON'T SHIFT DISPLAY

; ***CURSOR CONTROL INSTRUCTIONS***

OFFCUR    EQU    0CH

BLINKCUR  EQU    0DH

; ***DISPLAY CONTROL INSTRUCTIONS***

CLRDSP    EQU    01H

Page 52: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

ONDSP     EQU    0EH

; ***MACRO'S***

SCL_HIGH  MACRO

          SETB   SCL      ; SET SCL HIGH

          JNB    SCL,$    ; LOOP UNTIL STRONG 1 ON SCL

          ENDM

CSEG     AT      0        ; RESET VECTOR

         JNB     ENTER,INIT_YEAR

         AJMP    START

INIT_YEAR:

         JNB     ENTER,INIT_YEAR

         MOV     YEAR,#97H; INITIALIZE YEAR IF NEW 1307 TO 1997

         ACALL   SET_CLOCK; ELSE GO ON.

; **********************************************************

; RESET GOES HERE TO START PROGRAM

; **********************************************************

START:

         MOV         YEAR,#97H  ; SET YEAR TO 1997 ON BOOT

         ACALL       OFF        ; ALARM OFF ON BOOT

         MOV         SP,#2FH    ; POSITION STACK ABOVE BUFFER

         MOV         IE,#0      ; DISABLE INTERUPTS

         SETB        SDA        ; ENSURE SDA HIGH

         SCL_HIGH               ; ENSURE SCL HIGH

         CLR         ACK        ; CLEAR STATUS FLAGS

         CLR         BUS_FLT

         CLR         _2W_BUSY

                                

; **********************************************************

; SUB SETS THE DS1307 OSCILLATOR

; **********************************************************

OSC_CONTROL:

         ACALL       SEND_START ; GENERATE START CONDITION

         MOV         A,#DS1307W ; 1101 0000 ADDRESS + WRITE-BIT

         ACALL       SEND_BYTE  ; SEND BYTE TO 1307

         MOV         A,#00H     ; ADDRESS BYTE TO REGISTER 00H

         ACALL       SEND_BYTE  ; SECONDS REGISTER, ALWAYS LEAVE

         SETB        LASTREAD   ; REG 00H-BIT #7 = 0 (LOW)

         ACALL       SEND_STOP  ; IF REG 00H-BIT #7 = 1 CLOCK

         ACALL       SEND_START ; OSCILLATOR IS OFF.

         MOV         A,#DS1307R ; 1101 0001 ADDRESS + READ-BIT

         ACALL       SEND_BYTE  ;

         ACALL       READ_BYTE  ; READ A BYTE FROM THE 1307

         CLR         ACC.7      ; CLEAR REG 00H-BIT #7 TO ENABLE

OSC_SET:                        ; OSCILLATOR.

         PUSH        ACC        ; SAVE ON STACK

         ACALL       SEND_STOP  ;

         ACALL       SEND_START ;

         MOV         A,#DS1307W ; SETUP TO WRITE

         ACALL       SEND_BYTE  ;

         MOV         A,#00H     ; REGISTER 00H ADDRESS

         ACALL       SEND_BYTE  ;

         POP         ACC        ; GET DATA TO START OSCILLATOR

         ACALL       SEND_BYTE  ; SEND IT

         ACALL       SEND_STOP

         ACALL       BEGIN

Page 53: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

; **********************************************************

; TIME AND DATE ROUTINE, GET & DISPLAY MONTH/DATE/YEAR

; **********************************************************

GET_TIME:

         ACALL       READ_CLOCK            ; GET TIME,DATE,ALARM DATA

         JNB         ENTER,SET_TIME        ; GOTO SET TIME IF PUSHED

         JNB         ALARM_SET,SET_ALARMS  ; GOTO SET ALARMS ELSE SHOW TIME

         MOV         A,#1       ; LINE #1

         MOV         B,#1       ; COLUMN #1

         ACALL       PLACECUR4  ; PLACE CURSOR FOR DAY

         MOV         A,DAY      ; GET DAY

         ACALL       GET_DAY    ; SHOW DAY OF WEEK

         MOV         A,#1

         MOV         B,#7

         ACALL       PLACECUR4  ; PLACE CURSOR FOR MONTH

         MOV         A,MONTH    ; LOAD MONTH DATA

         ACALL       WRITE_BCD

         MOV         A,#1

         MOV         B,#10      ; PLACE CURSOR FOR DATE

         ACALL       PLACECUR4

         MOV         A,DATE

         ACALL       WRITE_BCD

         MOV         A,#1

         MOV         B,#13

         ACALL       PLACECUR4

         MOV         A,YEAR

         ACALL       WRITE_BCD

; **********************************************************

; NOW GET & DISPLAY TIME

; **********************************************************

         MOV         A,#2

         MOV         B,#4

         ACALL       PLACECUR4

         MOV         A,HRS

         ACALL       WRITE_BCD

         MOV         A,#2

         MOV         B,#7

         ACALL       PLACECUR4

         MOV         A,MINS

         ACALL       WRITE_BCD

         MOV         A,#2

         MOV         B,#10

         ACALL       PLACECUR4

         MOV         A,SECS

         ACALL       WRITE_BCD

         ACALL       CHECK_ALARM_TIME

         SJMP        GET_TIME

SET_ALARMS:

         JNB         ALARM_SET,SET_ALARMS

         ACALL       MDELAY

         AJMP        ALARMS

SET_TIME:

         JNB         ENTER,SET_TIME; HOLDS HERE UNTIL BUTTON IS RELEASED

         ACALL       MDELAY

SET_DAY:

Page 54: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         MOV         A,#1

         MOV         B,#0

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '*',0      ; PRINT '*' BY DAY

WAIT_DAY:                       ; WAIT HERE FOR BUTTON PRESS

         JNB         UP_BTTN,UP_DAY

         JNB         DOWN_BTTN,DOWN_DAY

         JNB         ENTER,ENTER_DAY

         ACALL       UPDATE

         SJMP        WAIT_DAY

REDO_DAY:                       ; RESETS DAY TO SUN

         MOV         A,#1

         MOV         DAY,A

         AJMP        WAIT_DAY

REDO_DAY_DOWN:                  ; RESETS DAY TO SAT

         MOV         A,#7H

         MOV         DAY,A

         AJMP        WAIT_DAY

OK_DAY:                         ; PLACES NEW DAY DATA INTO REGISTER

         MOV         DAY,A

         AJMP        WAIT_DAY

UP_DAY:                         ; CHANGES DAY DATA UP BY 1

         JNB         UP_BTTN,UP_DAY

         ACALL       MDELAY

         MOV         R1,#DAY

         MOV         A,@R1

         INC         A

         CJNE        A,#8H,OK_DAY

         AJMP        REDO_DAY

DOWN_DAY:                       ; CHANGES MONTH DATA DOWN BY 1

         JNB         DOWN_BTTN,DOWN_DAY

         ACALL       MDELAY

         MOV         R1,#DAY

         MOV         A,@R1

         DEC         A

         CJNE        A,#0,OK_DAY

         AJMP        REDO_DAY_DOWN

     

ENTER_DAY:                      ; DONE WITH DAY GO ON TO MONTH

         JNB         ENTER,ENTER_DAY

         ACALL       MDELAY

SET_MONTH:

         MOV         A,#1

         MOV         B,#0

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          ' ',0      ; PRINT '*' FOR MONTH

         MOV         A,#1

         MOV         B,#6

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '*',0

WAIT_MONTH:                     ; WAIT HERE FOR BUTTON PRESS

Page 55: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         JNB         UP_BTTN,UP_MONTH

         JNB         DOWN_BTTN,DOWN_MONTH

         JNB         ENTER,ENTER_MONTH

         ACALL       UPDATE

         SJMP        WAIT_MONTH

REDO_MONTH:                     ; RESETS MONTH TO 1

         MOV         A,#1

         MOV         MONTH,A

         AJMP        WAIT_MONTH

REDO_MONTH_DOWN:                ; RESETS MONTH TO 12

         MOV         A,#12H

         MOV         MONTH,A

         AJMP        WAIT_MONTH

OK_MONTH:                       ; PLACES NEW MONTH DATA INTO REGISTER

         MOV         MONTH,A

         AJMP        WAIT_MONTH

UP_MONTH:                       ; CHANGES MONTH DATA UP BY 1

         JNB         UP_BTTN,UP_MONTH

         ACALL       MDELAY

         MOV         R1,#MONTH

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD

         CJNE        A,#13H,OK_MONTH

         AJMP        REDO_MONTH

DOWN_MONTH:                     ; CHANGES MONTH DATA DOWN BY 1

         JNB         DOWN_BTTN,DOWN_MONTH

         ACALL       MDELAY

         MOV         R1,#MONTH

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD_DOWN

         DEC         A

         CJNE        A,#0,OK_MONTH

         AJMP        REDO_MONTH_DOWN

     

ENTER_MONTH:                    ; DONE WITH MONTH GO ON TO DATE

         JNB         ENTER,ENTER_MONTH

         ACALL       MDELAY

SET_DATE:

         MOV         A,#1

         MOV         B,#6

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          ' ',0      ; ERASE '*' BY MONTH

         MOV         A,#1

         MOV         B,#9

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '*',0      ; PRINT '*' BY DATE

WAIT_DATE:                      ; WAIT HERE UNTIL BUTTON PRESS

         JNB         UP_BTTN,UP_DATE

         JNB         DOWN_BTTN,DOWN_DATE

         JNB         ENTER,ENTER_DATE

         ACALL       UPDATE

Page 56: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         SJMP        WAIT_DATE

REDO_DATE:                      ; RESETS DATE TO 1

         MOV         A,#1

         MOV         DATE,A

         AJMP        WAIT_DATE

REDO_DATE_DOWN:                 ; RESETS DATE TO 31

         MOV         A,#31H

         MOV         DATE,A

         AJMP        WAIT_DATE

OK_DATE:                        ; PLACES NEW DATE DATA INTO REGISTER

         MOV         DATE,A

         AJMP        WAIT_DATE

UP_DATE:                        ; CHANGES DATE DATA UP BY 1

         JNB         UP_BTTN,UP_DATE

         ACALL       MDELAY

         MOV         R1,#DATE

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD

         CJNE        A,#32H,OK_DATE

         AJMP        REDO_DATE

DOWN_DATE:                      ; CHANGES DATE DATA DOWN BY 1

         JNB         DOWN_BTTN,DOWN_DATE

         ACALL       MDELAY

         MOV         R1,#DATE

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD_DOWN

         DEC         A

         CJNE        A,#0,OK_DATE

         AJMP        REDO_DATE_DOWN

ENTER_DATE:                     ; DONE WITH DATE GO ON TO YEAR

         JNB         ENTER,ENTER_DATE

         ACALL       MDELAY

SET_YEAR:

         MOV    A,#1

         MOV    B,#9

         ACALL  PLACECUR4

         ACALL  PRTLCD4

         DB     '-',0           ; PRINT '-' BESIDE DATE

         MOV    A,#1

         MOV    B,#12

         ACALL  PLACECUR4

         ACALL  PRTLCD4

         DB     '*',0           ; PRINT '*' BESIDE YEAR

WAIT_YEAR:                      ; WAIT HERE FOR BUTTON PRESS

         JNB    UP_BTTN,UP_YEAR

         JNB    DOWN_BTTN,DOWN_YEAR

         JNB    ENTER,ENTER_YEAR

         ACALL  UPDATE

         SJMP   WAIT_YEAR

REDO_YEAR:                      ; RESETS YEAR TO 1

         MOV    A,#97H

Page 57: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         MOV    YEAR,A

         SJMP   WAIT_YEAR

REDO_YEAR_DOWN:                 ; RESETS YEAR TO 99

         MOV    A,#99H

         MOV    YEAR,A

         AJMP   WAIT_YEAR

OK_YEAR:                        ; PLACES NEW YEAR DATA INTO REGISTER

         MOV    YEAR,A

         AJMP   WAIT_YEAR

UP_YEAR:                        ; CHANGES YEAR DATA UP BY 1

         JNB    UP_BTTN,UP_YEAR

         ACALL  MDELAY

         MOV    R1,#YEAR

         MOV    A,@R1

         INC    A

         CJNE   A,#9AH,OK_YEAR

         AJMP   REDO_YEAR

DOWN_YEAR:                      ; CHANGES YEAR DATA DOWN BY 1

         JNB    DOWN_BTTN,DOWN_YEAR

         ACALL  MDELAY

         MOV    R1,#YEAR

         MOV    A,@R1

         DEC    A

         CJNE   A,#96H,OK_YEAR

         AJMP   REDO_YEAR_DOWN

ENTER_YEAR:                     ; DONE WITH YEAR GO ON TO HOUR

         JNB    ENTER,ENTER_YEAR

         ACALL  MDELAY

         

SET_HOUR:

         MOV         A,#1

         MOV         B,#12

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '-',0      ; PRINT '-' BESIDE YEAR

         MOV         A,#2

         MOV         B,#3

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '*',0      ; PRINT '*' BESIDE HOUR

         AJMP        WAIT_HOUR

WAIT_HOUR:                      ; WAIT HERE UNTIL BUTTON PRESS

         JNB         UP_BTTN,UP_HOUR

         JNB         DOWN_BTTN,DOWN_HOUR

         JNB         ENTER,ENTER_HOUR

         ACALL       UPDATE

         SJMP        WAIT_HOUR

REDO_HOUR:                      ; RESET HOUR TO 00

         MOV         A,#0

         MOV         HRS,A

         AJMP        WAIT_HOUR

REDO_HOUR_DOWN:                 ; RESET HOUR TO 23

         MOV         A,#23H

         MOV         HRS,A

Page 58: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         AJMP        WAIT_HOUR

OK_HOUR:                        ; PLACE NEW HOUR DATA INTO REGISTER

         MOV         HRS,A

         AJMP        WAIT_HOUR

UP_HOUR:                        ; CHANGES HOUR DATA UP BY 1

         JNB         UP_BTTN,UP_HOUR

         ACALL       MDELAY

         MOV         R1,#HRS

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD

         CJNE        A,#24H,OK_HOUR

         AJMP        REDO_HOUR

DOWN_HOUR:                      ; CHANGES HOUR DATA DOWN BY ONE

         JNB         DOWN_BTTN,DOWN_HOUR

         ACALL       MDELAY

         MOV         R1,#HRS

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD_DOWN

         DEC         A

         CJNE        A,#0F9H,OK_HOUR

         AJMP        REDO_HOUR_DOWN

ENTER_HOUR:                     ; DONE WITH HOUR GO ON TO MINUTES

         JNB         ENTER,ENTER_HOUR

         ACALL       MDELAY

SET_MIN:

         MOV         A,#2

         MOV         B,#3

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          ' ',0      ; ERASE '*' BESIDE HOUR

         MOV         A,#2

         MOV         B,#6

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '*',0      ; PRINT '*' BESIDE MINUTES

WAIT_MIN:                       ; WAIT HERE UNTIL BUTTON PRESS

         JNB         UP_BTTN,UP_MIN

         JNB         DOWN_BTTN,DOWN_MIN

         JNB         ENTER,ENTER_MIN

         ACALL       UPDATE

         SJMP        WAIT_MIN

REDO_MIN:                       ; RESET MINUTES TO 00

         MOV         A,#0

         MOV         MINS,A

         AJMP        WAIT_MIN

REDO_MIN_DOWN:                  ; RESETS MINUTES TO 59

         MOV         A,#59H

         MOV         MINS,A

         AJMP        WAIT_MIN

OK_MIN:                         ; PLACE NEW MINUTE DATA INTO REGISTER

         MOV         MINS,A

Page 59: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         AJMP        WAIT_MIN

UP_MIN:                         ; CHANGES MINUTES DATA UP BY 1

         JNB         UP_BTTN,UP_MIN

         ACALL       MDELAY

         MOV         R1,#MINS

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD

         CJNE        A,#60H,OK_MIN

         AJMP        REDO_MIN

DOWN_MIN:                       ; CHANGES MINUTES DATA DOWN BY 1

         JNB         DOWN_BTTN,DOWN_MIN

         ACALL       MDELAY

         MOV         R1,#MINS

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD_DOWN

         DEC         A

         CJNE        A,#0F9H,OK_MIN

         AJMP        REDO_MIN_DOWN

ENTER_MIN:                      ; DONE WITH MINUTES GO ON TO SECONDS

         JNB         ENTER,ENTER_MIN

         ACALL       MDELAY

SET_SECONDS:

         MOV         A,#2

         MOV         B,#6

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          ':',0      ; PRINT ':' BESIDE MINUTES

         ACALL       MDELAY

         MOV         A,#00000000B ; SECONDS ARE SET TO 00

         MOV         SECS,A

         ACALL       SET_CLOCK

         AJMP        GET_TIME   ; RETURN TO MAIN LOOP

ALARMS:

         ACALL       RESETLCD4

         ACALL       INITLCD4

         MOV         A,#1

         MOV         B,#0

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '-SET ALARM TIME-',0

         ACALL       BEGIN3     ; PRINT HOUR & MINUTE SEPERATORS

         ACALL       UPDATE3    ; DISPLAY ALARM TIME

         AJMP        ALM_A      ; GO TO SET HOURS & MINUTES ROUTINE

                                ; FOR ALARM TIME.

UPDATE:

         MOV         A,#1       ; LINE #1

         MOV         B,#1       ; COLUMN #1

         ACALL       PLACECUR4  ; PLACE CURSOR FOR DAY

         MOV         A,DAY      ; GET DAY DATA

         ACALL       GET_DAY    ; CONVERT BCD TO ASCII FOR LCD

         MOV         A,#1

         MOV         B,#7

         ACALL       PLACECUR4  ; PLACE CURSOR FOR MONTH

         MOV         A,MONTH    ; LOAD DATE MONTH

         ACALL       WRITE_BCD

Page 60: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         MOV         A,#1

         MOV         B,#10      ; PLACE CURSOR FOR DATE

         ACALL       PLACECUR4

         MOV         A,DATE     ; LOAD DATE DATA

         ACALL       WRITE_BCD

         MOV         A,#1

         MOV         B,#13

         ACALL       PLACECUR4

         MOV         A,YEAR

         ACALL       WRITE_BCD

; **********************************************************

; NOW GET & DISPLAY TIME

; **********************************************************

UPDATE2:

         MOV         A,#2

         MOV         B,#4

         ACALL       PLACECUR4

         MOV         A,HRS

         ACALL       WRITE_BCD

         MOV         A,#2

         MOV         B,#7

         ACALL       PLACECUR4

         MOV         A,MINS

         ACALL       WRITE_BCD

         MOV         A,#2

         MOV         B,#10

         ACALL       PLACECUR4

         MOV         A,SECS

         ACALL       WRITE_BCD

         MOV         R4,#OFFCUR

         ACALL       WRLCDCOM4  ; TURN OFF CURSOR

         ACALL       BIG_DELAY

         RET

UPDATE3:

         MOV         A,#2

         MOV         B,#6

         ACALL       PLACECUR4

         MOV         A,ALM_HOUR

         ACALL       WRITE_BCD

         MOV         A,#2

         MOV         B,#9

         ACALL       PLACECUR4

         MOV         A,ALM_MIN

         ACALL       WRITE_BCD

         MOV         R4,#OFFCUR

         ACALL       WRLCDCOM4

         ACALL       BIG_DELAY

         RET

CHECK_ALARM_TIME:

         MOV         A,MINS

         CJNE        A,ALM_MIN,OFF

         MOV         A,HRS

         CJNE        A,ALM_HOUR,OFF

         MOV         ALM_CNTRL,#10H ; LOAD VALUE TO TURN ON SQW OUT & ALARM

         ACALL       ALARM_CONTROL

         RET

OFF:     MOV         ALM_CNTRL,#00H

         ACALL       ALARM_CONTROL  ; LOAD VALUE TO TURN OFF ALARM & SQW OUT.

Page 61: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         RET

ALM_A:

         MOV         A,#2

         MOV         B,#5

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '*',0      ; PRINT '*' BESIDE HOUR

WAIT_HOUR1:                     ; WAIT HERE UNTIL BUTTON PRESS

         JNB         UP_BTTN,UP_HOUR1

         JNB         DOWN_BTTN,DOWN_HOUR1

         JNB         ENTER,ENTER_HOUR1

         ACALL       UPDATE3

         SJMP        WAIT_HOUR1

REDO_HOUR1:                     ; RESET HOUR TO 00

         MOV         A,#0

         MOV         ALM_HOUR,A

         AJMP        WAIT_HOUR1

REDO_HOUR_DOWN1:                ; RESET HOUR TO 23

         MOV         A,#23H

         MOV         ALM_HOUR,A

         AJMP        WAIT_HOUR1

OK_HOUR1:                       ; PLACE NEW HOUR DATA INTO REGISTER

         MOV         ALM_HOUR,A

         AJMP        WAIT_HOUR1

UP_HOUR1:                       ; CHANGES HOUR DATA UP BY 1

         JNB         UP_BTTN,UP_HOUR1

         ACALL       MDELAY

         MOV         R1,#ALM_HOUR

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD

         CJNE        A,#24H,OK_HOUR1

         AJMP        REDO_HOUR1

DOWN_HOUR1:                     ; CHANGES HOUR DATA DOWN BY ONE

         JNB         DOWN_BTTN,DOWN_HOUR1

         ACALL       MDELAY

         MOV         R1,#ALM_HOUR

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD_DOWN

         DEC         A

         CJNE        A,#0F9H,OK_HOUR1

         AJMP        REDO_HOUR_DOWN1

ENTER_HOUR1:                    ; DONE WITH HOUR GO ON TO MINUTES

         JNB         ENTER,ENTER_HOUR1

         ACALL       MDELAY

SET_MIN1:

         MOV         A,#2

         MOV         B,#5

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          ' ',0      ; ERASE '*' BESIDE HOUR

         MOV         A,#2

         MOV         B,#8

Page 62: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '*',0      ; PRINT '*' BESIDE MINUTES

WAIT_MIN1:                      ; WAIT HERE UNTIL BUTTON PRESS

         JNB         UP_BTTN,UP_MIN1

         JNB         DOWN_BTTN,DOWN_MIN1

         JNB         ENTER,ENTER_MIN1

         ACALL       UPDATE3

         SJMP        WAIT_MIN1

REDO_MIN1:                      ; RESET MINUTES TO 00

         MOV         A,#0

         MOV         ALM_MIN,A

         AJMP        WAIT_MIN1

REDO_MIN_DOWN1:                 ; RESETS MINUTES TO 59

         MOV         A,#59H

         MOV         ALM_MIN,A

         AJMP        WAIT_MIN1

OK_MIN1:                        ; PLACE NEW MINUTE DATA INTO REGISTER

         MOV         ALM_MIN,A

         AJMP        WAIT_MIN1

UP_MIN1:                        ; CHANGES MINUTES DATA UP BY 1

         JNB         UP_BTTN,UP_MIN1

         ACALL       MDELAY

         MOV         R1,#ALM_MIN

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD

         CJNE        A,#60H,OK_MIN1

         AJMP        REDO_MIN1

DOWN_MIN1:                      ; CHANGES MINUTES DATA DOWN BY 1

         JNB         DOWN_BTTN,DOWN_MIN1

         ACALL       MDELAY

         MOV         R1,#ALM_MIN

         MOV         A,@R1

         MOV         R4,A

         ACALL       CHECK_BCD_DOWN

         DEC         A

         CJNE        A,#0F9H,OK_MIN1

         AJMP        REDO_MIN_DOWN1

ENTER_MIN1:                     ; DONE WITH MINUTES GO ON TO SECONDS

         JNB         ENTER,ENTER_MIN1

         ACALL       MDELAY

SET_SECONDS1:

         MOV         A,#2

         MOV         B,#8

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          ':',0      ; PRINT ':' BESIDE MINUTES

         ACALL       MDELAY

STORE_ALARMS:

         ACALL       SEND_START ; SEND 2-WIRE START CONDITION

         MOV         A,#DS1307W ; SEND 1307 WRITE COMMAND

         ACALL       SEND_BYTE

Page 63: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         MOV         A,#ALM_STORE; POINT TO REGISTER

                                ; 08H ON THE DS1307

         ACALL       SEND_BYTE

         MOV         R1,#ALM_HOUR; START WITH HOURS REGISTER

                                ; IN INTERNAL RAM

SEND_LOOP2:

         MOV         A,@R1      ; LOAD HOURS DATA FOR ALARM

         ACALL       SEND_BYTE  ; SET HOURS

         MOV         R1,#ALM_MIN

         MOV         A,@R1      ; LOAD MINUTES DATA FOR ALARM

         ACALL       SEND_BYTE  ; SET MINUTES

         ACALL       SEND_STOP  ; SEND 2-WIRE STOP CONDITION

         ACALL       BEGIN      ; SETUP DISPLAY AGAIN BEFORE RETURNING.

         AJMP        GET_TIME   ; GO BACK TO SHOWING TIME AFTER

                                ; SETTING ALARM

; **********************************************************

; BCD CONVERSION ROUTINE

; ACC CONTAINS TIME DATA FROM RAM WHEN ROUTINE IS CALLED.

; **********************************************************

WRITE_BCD:

         PUSH        ACC        ; DECODE HIGH DIGIT

         SWAP        A

         ANL         A,#0FH

         ACALL       FIND       ; LOOK IT UP & THEN PRINT IT.

         POP         ACC        ; DECODE LOW DIGIT

         ANL         A,#0FH

         ACALL       FIND

         RET

; **********************************************************

; SUB CONTROLS THE ALARM OUTPUT

; THE DS1307 SQW OUTPUT DRIVES THE ALARM BUZZER @ 1Hz

; **********************************************************

ALARM_CONTROL:

         ACALL       SEND_START

         MOV         A,#DS1307W

         ACALL       SEND_BYTE

         MOV         A,#07H

         ACALL       SEND_BYTE

         MOV         R1,#ALM_CNTRL

         MOV         A,@R1      ; 10H = ALARM ON AT 1HZ

         ACALL       SEND_BYTE  ; 00H = ALARM OFF & SQW OUT = GND

         ACALL       SEND_STOP

         RET

; **********************************************************

; SET UP DISPLAY ON BOOT, AND REDO DISPLAY AFTER CHANGE

; **********************************************************

BEGIN:

         ACALL       RESETLCD4

         ACALL       INITLCD4

         MOV         A,#1

         MOV         B,#7

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '  -  -  ',0

         MOV         A,#2

         MOV         B,#0

Page 64: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '*     :  :     *',0

         MOV         R4,#OFFCUR ; TURN OFF CURSOR

         ACALL       WRLCDCOM4

         RET

BEGIN3:

         MOV         A,#2

         MOV         B,#0

         ACALL       PLACECUR4

         ACALL       PRTLCD4

         DB          '*       :      *',0

         MOV         R4,#OFFCUR ; TURN OFF CURSOR

         ACALL       WRLCDCOM4

         RET

; **********************************************************

; LOOKUP TABLE USED BY WRITE_BCD.

; **********************************************************

FIND:

         SJMP        LOOK_UP

ST:

         RET

LOOK_UP:

         CJNE        A,#0000000B,m1

         LCALL       PRTLCD4

         DB          '0',0

         LJMP        ST

m1:

         CJNE        A,#00000001B,m2

         LCALL       PRTLCD4

         DB          '1',0

         LJMP        ST

m2:

         CJNE        A,#00000010B,m3

         LCALL       PRTLCD4

         DB          '2',0

         LJMP        ST

m3:

         CJNE        A,#00000011B,m4

         LCALL       PRTLCD4

         DB          '3',0

         LJMP           ST

m4:

         CJNE        A,#00000100B,m5

         LCALL       PRTLCD4

         DB          '4',0

         LJMP        ST

m5:

         CJNE        A,#00000101B,m6

         LCALL       PRTLCD4

         DB          '5',0

         LJMP        ST

m6:

         CJNE        A,#00000110B,m7

         LCALL       PRTLCD4

         DB          '6',0

         LJMP        ST

m7:

         CJNE        A,#00000111B,m8

Page 65: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         LCALL       PRTLCD4

         DB          '7',0

         LJMP        ST

m8:

         CJNE        A,#00001000B,m9

         LCALL       PRTLCD4

         DB          '8',0

         LJMP        ST

m9:

         CJNE        A,#00001001B,m10

         LCALL       PRTLCD4

         DB          '9',0

         LJMP        ST

m10:

         LJMP        ST

; **********************************************************

; LOOKUP TABLE FOR DAY

; **********************************************************

GET_DAY:

         CJNE        A,#00000001B,MON

         LCALL       PRTLCD4

         DB          'SUN',0

         RET

MON:

         CJNE        A,#00000010B,TUE

         LCALL       PRTLCD4

         DB          'MON',0

         RET

TUE:

         CJNE        A,#00000011B,WED

         LCALL       PRTLCD4

         DB          'TUE',0

         RET

WED:

         CJNE        A,#00000100B,THU

         LCALL       PRTLCD4

         DB          'WED',0

         RET

THU:

         CJNE        A,#00000101B,FRI

         LCALL       PRTLCD4

         DB          'THU',0

         RET

FRI:

         CJNE        A,#00000110B,SAT

         LCALL       PRTLCD4

         DB          'FRI',0

         RET

SAT:

         CJNE        A,#00000111B,WHAT

         LCALL       PRTLCD4

         DB          'SAT',0

         RET

WHAT:

         RET

; **********************************************************

; SUB SETS THE CLOCK

; **********************************************************

Page 66: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

SET_CLOCK:

         

         ACALL       SEND_START ; SEND 2-WIRE START CONDITION

         MOV         A,#DS1307W ; SEND 1307 WRITE COMMAND

         ACALL       SEND_BYTE

         MOV         A,#00H     ; SET DATA POINTER TO REGISTER

                                ; 00H ON THE DS1307

         ACALL       SEND_BYTE

         MOV         R1,#24H    ; START WITH SECONDS REGISTER

                                ; IN INTERNAL RAM

SEND_LOOP:

         MOV         A,@R1      ; MOVE FIRST BYTE OF DATA TO ACC

         ACALL       SEND_BYTE  ; SEND DATA ON 2-WIRE BUT

         INC         R1         ; LOOP UNTIL CLOCK DATA SENT

         CJNE        R1,#2BH,SEND_LOOP

         ACALL       SEND_STOP  ; SEND 2-WIRE STOP CONDITION

         RET

; **********************************************************

; INITIALIZE THE LCD 4-BIT MODE

; **********************************************************

INITLCD4:

         CLR         LCD_RS     ; LCD REGISTER SELECT LINE

         CLR         LCD_RW     ; READ / WRITE LINE

         CLR         LCD_E      ; ENABLE LINE

         MOV         R4, #CONFIG; FUNCTION SET - DATA BITS,

                                ; LINES, FONTS

         ACALL       WRLCDCOM4

         MOV         R4, #ONDSP ; DISPLAY ON

         ACALL       WRLCDCOM4

         MOV         R4, #ENTRYMODE ; SET ENTRY MODE

         ACALL       WRLCDCOM4  ; INCREMENT CURSOR RIGHT, NO SHIFT

         MOV         R4, #CLRDSP; CLEAR DISPLAY, HOME CURSOR

         ACALL       WRLCDCOM4

         RET

; **********************************************************

; SOFTWARE VERSION OF THE POWER ON RESET

; **********************************************************

RESETLCD4:

         CLR         LCD_RS     ; LCD REGISTER SELECT LINE

         CLR         LCD_RW     ; READ / WRITE LINE

         CLR         LCD_E      ; ENABLE LINE

         CLR         LCD_DB7    ; SET BIT PATTERN FOR...

         CLR         LCD_DB6    ; ... POWER-ON-RESET

         SETB        LCD_DB5

         SETB        LCD_DB4

         SETB        LCD_E      ; START ENABLE PULSE

         CLR         LCD_E      ; END ENABLE PULSE

         MOV         A, #4      ; DELAY 4 MILLISECONDS

         ACALL       MDELAY

         SETB        LCD_E      ; START ENABLE PULSE

         CLR         LCD_E      ; END ENABLE PULSE

         MOV         A, #1      ; DELAY 1 MILLISECOND

         ACALL       MDELAY

         SETB        LCD_E      ; START ENABLE PULSE

         CLR         LCD_E      ; END ENABLE PULSE

         MOV         A, #1      ; DELAY 1 MILLISECOND

         ACALL       MDELAY

         CLR         LCD_DB4    ; SPECIFY 4-BIT OPERATION

Page 67: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         SETB        LCD_E      ; START ENABLE PULSE

         CLR         LCD_E      ; END ENABLE PULSE

         MOV         A, #1      ; DELAY 1 MILLISECOND

         ACALL       MDELAY

         MOV         R4, #CONFIG; FUNCTION SET

         ACALL       WRLCDCOM4

         MOV         R4, #08H   ; DISPLAY OFF

         ACALL       WRLCDCOM4

         MOV         R4, #1     ; CLEAR DISPLAY, HOME CURSOR

         ACALL       WRLCDCOM4

         MOV         R4, #ENTRYMODE  ; SET ENTRY MODE

         ACALL       WRLCDCOM4

         AJMP        INITLCD4

; **********************************************************

; SUB WRITES A COMMAND WORD TO THE LCD

; COMMAND MUST BE PLACED IN R4 BY CALLING PROGRAM

; **********************************************************

WRLCDCOM4:

         CLR         LCD_E

         CLR         LCD_RS     ; SELECT SEND COMMAND

         CLR         LCD_RW     ; SELECT WRITE OPERATION

         PUSH        ACC        ; SAVE ACCUMULATOR

         MOV         A, R4      ; PUT DATA BYTE IN ACC

         MOV         C, ACC.4   ; LOAD HIGH NIBBLE ON DATA BUS

         MOV         LCD_DB4, C ; ONE BIT AT A TIME USING...

         MOV         C, ACC.5   ; BIT MOVE OPERATOINS

         MOV         LCD_DB5, C

         MOV         C, ACC.6

         MOV         LCD_DB6, C

         MOV         C, ACC.7

         MOV         LCD_DB7, C

         SETB        LCD_E      ; PULSE THE ENABLE LINE

         CLR         LCD_E

         MOV         C, ACC.0   ; SIMILARLY, LOAD LOW NIBBLE

         MOV         LCD_DB4, C

         MOV         C, ACC.1

         MOV         LCD_DB5, C

         MOV         C, ACC.2

         MOV         LCD_DB6, C

         MOV         C, ACC.3

         MOV         LCD_DB7, C

         ACALL       PULSEEWAIT4; PULSE THE ENABLE LINE...

                                ; AND WAIT FOR BUSY FLAG TO CLEAR

         POP         ACC

         RET

; **********************************************************

; SUB TO WRITE A DATA WORD TO THE LCD

; DATA MUST BE PLACED IN R4 BY CALLING PROGRAM

; **********************************************************

WRLCDDATA:

         CLR         LCD_E

         SETB        LCD_RS     ; SELECT SEND DATA

         CLR         LCD_RW     ; SELECT WRITE OPERATION

         PUSH        ACC        ; SAVE ACCUMULATOR

         MOV         A, R4      ; PUT DATA BYTE IN ACC

         MOV         C, ACC.4   ; LOAD HIGH NIBBLE ON DATA BUS

         MOV         LCD_DB4, C ; ONE BIT AT A TIME USING...

         MOV         C, ACC.5   ; BIT MOVE OPERATOINS

Page 68: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         MOV         LCD_DB5, C

         MOV         C, ACC.6

         MOV         LCD_DB6, C

         MOV         C, ACC.7

         MOV         LCD_DB7, C

         SETB        LCD_E      ; PULSE THE ENABLE LINE

         CLR         LCD_E

         MOV         C, ACC.0   ; SIMILARLY, LOAD LOW NIBBLE

         MOV         LCD_DB4, C

         MOV         C, ACC.1

         MOV         LCD_DB5, C

         MOV         C, ACC.2

         MOV         LCD_DB6, C

         MOV         C, ACC.3

         MOV         LCD_DB7, C

         ACALL       PULSEEWAIT4; PULSE THE ENABLE LINE...

                                ; AND WAIT FOR BUSY FLAG TO CLEAR

         POP         ACC

         RET

; **********************************************************

; GENERATES A POSITIVE PULSE ON THE LCD ENABLE LINE.

; WAITS FOR THE BUSY FLAG TO CLEAR BEFORE RETURNING.

; **********************************************************

PULSEEWAIT4:

         CLR         LCD_E

         SETB        LCD_E      ; PULSE THE ENABLE LINE

         CLR         LCD_E

         MOV         LCD_DATA, #0FFH ; PREPARE PORT FOR INPUT

         SETB        LCD_RW     ; PREPARE R/W FOR READ OPERATION

         PUSH        ACC        ; SAVE ACCUMULATOR CONTENTS

PEW:

         SETB        LCD_E      ; START THE ENABLE PULSE

         MOV         A, LCD_DATA; READ STATUS NIBBLE

         CLR         LCD_E      ; END ENABLE PULSE

         SETB        LCD_E      ; PRETEND READING STATUS LOW NIBBLE

         CLR         LCD_E

         JB          ACC.7, PEW ; LOOP WHILE BUSY FLAG IS SET

         POP         ACC        ; RESTORE ACCUMULATOR

         RET

; **********************************************************

; SUB TAKES THE STRING IMMEDIATELY FOLLOWING THE CALL AND

; DISPLAYS ON THE LCD. STRING MUST BE TERMINATED WITH A

; NULL (0).

; **********************************************************

PRTLCD4:

         POP         DPH        ; POP RETURN ADDRESS INTO DPTR

         POP         DPL

PRTNEXT:

         CLR         A          ; SET OFFSET = 0

         MOVC        A, @A+DPTR ; GET CHR FROM CODE MEMORY

         CJNE        A, #0, CHROK; IF CHR = 0 THEN RETURN

         SJMP        RETPRTLCD

CHROK:

         MOV         R4, A

         ACALL       WRLCDDATA  ; SEND CHARACTER

         INC         DPTR       ; POINT AT NEXT CHARACTER

         AJMP        PRTNEXT    ; LOOP TILL END OF STRING

RETPRTLCD:

Page 69: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         MOV         A,  #1H    ; POINT TO INSTRUCTION AFTER STRING

         JMP         @A+DPTR    ; RETURN WITH A JUMP INSTRUCTION

; **********************************************************

; SUB SETS THE CURSOR POSITION.

; **********************************************************

PLACECUR4:

         DEC         ACC        ; ACC=0 FOR LINE=1

         JNZ         LINE2      ; IF ACC=0 THEN FIRST LINE

         MOV         A, B

         ADD         A, #080H   ; CONSTRUCT CONTROL WORD FOR LINE 1

         SJMP        SETCUR

LINE2:

         MOV         A, B

         ADD         A, #0C0H   ; CONSTRUCT CONTROL WORD FOR LINE 2

SETCUR:

         MOV         R4, A      ; PLACE CONTROL WORD

         ACALL       WRLCDCOM4  ; ISSUE COMMAND

         RET

SETCGRAM:

         PUSH        B

         MOV         B, #8

         MUL         AB          ; multiply character number by 8

         POP         B           ; b holds row number

         ADD         A,B         ; a holds CGRAM address

         ADD         A,#40h      ; convert to instruction

         MOV         R4,A        ; place instruction

         ACALL       WRLCDCOM4   ; issue command

         RET

; **********************************************************

; 1 MILLISECOND DELAY ROUTINE

; **********************************************************

MDELAY:

         PUSH        ACC

         MOV         A,#0A6H

MD_OLP:

         INC         A

         NOP

         NOP

         NOP

         NOP

         NOP

         NOP

         NOP

         NOP

         JNZ         MD_OLP

         NOP

         POP         ACC

         RET

BIG_DELAY:

         MOV         R3,#1      ; DELAY ROUTINE.

X0B:     MOV         R2,#0FFH

X1B:     MOV         R5,#0FFH

X2B:     DJNZ        R5,X2B

         DJNZ        R2,X1B

         DJNZ        R3,X0B

         RET

Page 70: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

; **********************************************************

; THIS SUB READS ONE BYTE OF DATA FROM THE DS1307

; **********************************************************

READ_BYTE:

         MOV         BITCNT,#08H; SET COUNTER FOR 8-BITS DATA

         MOV         A,#00H

         SETB        SDA        ; SET SDA HIGH TO ENSURE LINE

                                ; FREE

READ_BITS:

         SCL_HIGH               ; TRANSITION SCL LOW-TO-HIGH

         MOV         C,SDA      ; MOVE DATA BIT INTO CARRY

         RLC         A          ; ROTATE CARRY-BIT INTO ACC.0

         CLR         SCL        ; TRANSITION SCL HIGH-TO-LOW

         DJNZ        BITCNT,READ_BITS

                                ; LOOP FOR 8-BITS

         JB          LASTREAD,ACKN

                                ; CHECK TO SEE IF THIS IS

                                ; THE LAST READ

         CLR         SDA        ; IF NOT LAST READ SEND ACK-BIT

ACKN:

         SCL_HIGH               ; PULSE SCL TO TRANSMIT ACKNOWLEDGE

         CLR         SCL        ; OR NOT ACKNOWLEDGE BIT

         RET

; **********************************************************

; SUB SENDS START CONDITION

; **********************************************************

SEND_START:

         SETB        _2W_BUSY   ; INDICATE THAT 2-WIRE

         CLR         ACK        ; OPERATION IS IN PROGRESS

         CLR         BUS_FLT    ; CLEAR STATUS FLAGS

         JNB         SCL,FAULT

         JNB         SDA,FAULT

         SETB        SDA        ; BEGIN START CODITION

         SCL_HIGH

         CLR         SDA

         ACALL       DELAY

         CLR         SCL

         RET

FAULT:

         SETB        BUS_FLT

         RET

; **********************************************************

; SUB SENDS STOP CONDITION

; **********************************************************

SEND_STOP:

         CLR         SDA

         SCL_HIGH

         SETB        SDA

         CLR         _2W_BUSY

         RET

; **********************************************************

; SUB DELAYS THE BUS

; **********************************************************

Page 71: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

DELAY:

         NOP                    ; DELAY FOR BUS TIMING

         RET

; **********************************************************

; THIS SUB SENDS 1 BYTE OF DATA TO THE DS1307

; CALL THIS FOR EACH REGISTER SECONDS TO YEAR

; ACC MUST CONTAIN DATA TO BE SENT TO CLOCK

; **********************************************************

SEND_BYTE:

         MOV         BITCNT,#08H; SET COUNTER FOR 8-BITS

SB_LOOP:

         JNB         ACC.7,NOTONE; CHECK TO SEE IF BIT-7 OF

         SETB        SDA        ; ACC IS A 1, AND SET SDA HIGH

         JMP         ONE

NOTONE:

         CLR         SDA        ; CLR SDA LOW

ONE:

         SCL_HIGH               ; TRANSITION SCL LOW-TO-HIGH

         RL          A          ; ROTATE ACC LEFT 1-BIT

         CLR         SCL        ; TRANSITION SCL LOW-TO-HIGH

         DJNZ        BITCNT,SB_LOOP; LOOP FOR 8-BITS

         SETB        SDA        ; SET SDA HIGH TO LOOK FOR

         SCL_HIGH               ; ACKNOWLEDGE PULSE

         CLR         ACK

         JNB         SDA,SB_EX  ; CHECK FOR ACK OR NOT ACK

         SETB        ACK        ; SET ACKNOWLEDGE FLAG FOR

                                ; NOT ACK

SB_EX:

         ACALL       DELAY      ; DELAY FOR AN OPERATION

         CLR         SCL        ; TRANSITION SCL HIGH-TO-LOW

         ACALL       DELAY      ; DELAY FOR AN OPERATION

         RET

; **********************************************************

; SUB READS THE CLOCK AND WRITES IT TO THE SCRATCHPAD MEMORY

; ON RETURN FROM HERE DATE & TIME DATA WILL BE STORED IN THE

; DATE & TIME REGISTERS FROM 24H (SECS) TO 2AH (YEAR)

; ALARM SETTINGS IN REGISTERS 2CH(HRS) AND 2DH(MINUTES).

; **********************************************************

READ_CLOCK:

         MOV         R1,#24H    ; SECONDS STORAGE LOCATION

         MOV         BYTECNT,#00H

         CLR         LASTREAD

         ACALL       SEND_START

         MOV         A,#DS1307W

         ACALL       SEND_BYTE

         MOV         A,#00H

         ACALL       SEND_BYTE

         ACALL       SEND_STOP

         ACALL       SEND_START

         MOV         A,#DS1307R

         ACALL       SEND_BYTE

READ_LOOP:

         MOV         A,BYTECNT

         CJNE        A,#09H,NOT_LAST

         SETB        LASTREAD

Page 72: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

NOT_LAST:

         ACALL       READ_BYTE

         MOV         @R1,A

         MOV         A,BYTECNT

         CJNE        A,#00H,NOT_FIRST

         MOV         A,@R1

         CLR         ACC.7      ; ENSURE OSC BIT=0 (ENABLED)

         MOV         @R1,A

NOT_FIRST:

         INC         R1

         INC         BYTECNT

         MOV         A,BYTECNT

         CJNE        A,#0AH,READ_LOOP

         ACALL       SEND_STOP

         RET

; **********************************************************

; MOST OF THE REAL WORK IS DONE IN THE ADJUST ROUTINE

; THIS ROUTINE SIMPLY CHECKS TO SEE IF THE NUMBER IS

; ZERO OR ENDS IN NINE.

; **********************************************************

CHECK_BCD:

         MOV         A,R4       ; SAVES THE NUMBER TO R4

         CLR         C          ; CLEARS CARRY BIT

         ADD         A,#67H     ; CHECKS TO SEE IF EQUAL 99

         JC          ZERO       ; IF EQUAL THEN BECOMES 0

         MOV         A,R4       ; GETS ORIGINAL NUMBER

         ANL         A,#0FH     ; GETS RID OF UPPER 4 BITS

         CLR         C          ; CLEARS CARRY BIT

         ADD         A,#0F7H    ; CHECKS TO SEE IF NUMBER ENDS IN 9

         JC          ADJUST     ; IF LARGER ADJUST IT

         MOV         A,R4       ; GET ORIGINAL NUMBER

         INC         A          ; ITS UNDER 9 AND NOT 0 SO INCREASE

         RET                    ; BY 1 AND GO BACK.

; **********************************************************

; BCD CONVERSION ROUTINE.

; **********************************************************

ADJUST:

         MOV         A,R4       ; GET ORIGINAL NUMBER

         SWAP        A          ; CHANGE UPPER BITS TO LOWER BITS

         ANL         A,#0FH     ; GET RID OF WHAT WAS LOWER BITS

         INC         A          ; INCREASE BY ONE

         SWAP        A          ; SWITCH THE UPPER AND LOWER BITS BACK

         RET                    ; GO BACK WITH NEW NUMBER

ZERO:                           ; IF NUMBER IS ZERO SEND BACK A ZERO

         MOV         A,#00000000B

         RET

; **********************************************************

; THIS ROUTINE CHECKS TO SEE IF THE LOWER 4 BITS ARE

; EQUAL TO ZERO. IF THEY ARE THEN A STRAIGHT DECREASE

; CAN BE DONE. IF NOT THEN CONVERT.

; **********************************************************

CHECK_BCD_DOWN:

         MOV         A,R4       ; SAVE ORIGINAL NUMBER

         ANL         A,#0FH     ; GET RID OF UPPER FOUR BITS

         CJNE        A,#00000000B,GO_ON_BACK ;DO LOWER BITS =0 ?

         MOV         A,R4       ; GET ORIGINAL NUMBER

Page 73: Đồng hồ có hẹn giờ chạy với ic vi điều khiển AT89C51

         SUBB        A,#06H     ; CONVERT IT TO A BINARY NUMBER

         RET

; **********************************************************

; IF THE NUMBER ENDS IN NUMBER LESS THAN 9 THEN

; GO BACK AND, DO A NORMAL DECREMENT.

; **********************************************************

GO_ON_BACK:

         MOV         A,R4       ; GET ORIGINAL NUMBER

         RET                    ; GO BACK

; **********************************************************

; END OF PROGRAM

; **********************************************************

  END