điều khiển 16 BIT cho PIC 16F877A
- Có rất nhiều phần mềm dùng để soạn thảo và biên dịch ngôn ngữ C cho vi điều khiển PIC: MPLAB C18, Hitech C Compiler,.... Ở chuyên đề này, chúng ta sẽ sử
Các bƣớc tạo một Project trong PIC C Compiler.
- Khởi động PIC C Complier:
- Giao diện CCS PCWHD 4.105
Hình 1.50: Giao diện CSS
Bƣớc 1: Chọn PIC Wizard và lưu Project vào vị trí chỉ định như Hình 1.50 và Hình 1.51
Hình 1.51: Lƣu chƣơng trình vào thƣ mục Bƣớc 2: Chọn chip model theo Hình 1.52, sau đó nhấn OK
- Bƣớc 3: Cửa sổ soạn thảo mã lệnh trong c (file.c) như Hình 1.53
Hình 1.53: Giao diện biên soạn chƣơng trình
- Bƣớc 4: Sau khi biên soạn xong, vào menu Compile -> Build All sẽ được giao diện như Hình 1.54
Hình 1.54 Cửa sổ thông báo kết quả biên dịch
Lƣu ý:Các cảnh báo Warning có thể bỏ qua, nhưng các Errors phải sửa hoàn tất thì quá trình biên dịch mới hoàn tất và tạo ra file.hex
- Bƣớc 5: Nạp file.hex ở bước 4 vào PIC và quan sát hoạt động chương trình trên phần mềm Proteus và phần cứng.
Các tiền xử lý Chƣơng trình
Chƣơngtrình nạp ( Pickit2 V2.61)
Đây là chương trình thực hiện online cùng với kit EASYPIC_PRO. Sau khi
thực hiện kết nối như Hình 1.54, ta có giao diện như Hình 1.55
Hình 1.55 Kết nối onboard của PICkit2 trên DTVT03
Nạp chƣơng trình vào PIC dùng PICkit 2 Programmer
- Khởi động PICkit 2:
- Vào Menu File chọn Import Hex, chọn file hex vừa biên dịch xong. Nhấn
1.3.1.5. CHƢƠNG TRÌNH MẪU
Thực hiện biên dịch chƣơng trình mẫu nạp vào vi điều khiển 8 bit
Main: MOV P1,#0FFh ; Sáng 8 Led CALL Delay MOV P1,#0 ; Tắt 8 Led CALL Delay SJMP main Delay: PUSH 07h PUSH 06h MOV R6,#255 Delay1: MOV R7,#255 DJNZ R7,$ DJNZ R6,Delay1 POP 06h POP 07h RET END
- Yêu cầu: Biên dịch đoạn chương trình trên dưới dạng file HEX nạp vào vi điều khiển 8 bit AT89S52. Quan sát 8 Led đơn được kết nối với Port 1
Thực hiện biên dịch chƣơng trình mẫu nạp vào vi điều khiển 16 bit
- Biên soạn và biên dịch chương trình sau sang file.HEX và kiểm chứng trên phần mềm Proteus và phần cứng board thí nghiệm PIC
//*********************************************************** ***/
#include<16f887.h>
#fuses HS,NOLVP,NOWDT,PUT
#use delay(clock=8000000) // defind crystal = 8MHz // main program start here
void main() { char i,count; while(TRUE) { count=1; for (i=0;i<=6;i++) { output_A(count); delay_ms(100); count=count<<1; } output_A(0xff); delay_ms(100); output_A(0x00); delay_ms(100); output_A(0xff); delay_ms(100); output_A(0x00); delay_ms(100); }}
a. Vẽ lưu đồ thực hiện chương trình trên
b. Thay đổi lệnh xuất dữ liệu để thực hiện đoạn chương trình trên
1.3.2 TIỀN TRÌNH THÍ NGHIỆM
1. Thực hiện cài đặt phần mềm Proteus và Keil C 2. Thiết kế mạch ON/OFF trên phần mềm Proteus
3. Thực hiện biên dịch chương trình mẫu nạp vào vi điều khiển 8 bit và 16 bit và kiểm chứng trên phần mềm Proteus và phần cứng bộ kit thí nghiệm vi xử lý
1.3.3 BÀI TẬP THÍ NGHIỆM
1. Hãy xem chƣơng trình mẫu điều khiển 16 led chóp tắt dùng 2 port 0 và 1 và hãy viết chƣơng trình sáng tắt 3 port 0, 1 và 3.Biên dịch và nạp vào vi điều
khiển 8 bit AT89S52
2. Hãy viết chƣơng trình sáng tắt 4 port: port 0, port 1, port 2, port 3. Biên dịch và nạp vào vi điều khiển 8 bit AT89S52.
Bài thí nghiệm số 2:
CÁC LỆNH CƠ BẢN CỦA 89S52 VÀ PIC 16F887A
Thời lƣợng: 12 giờ
1.1. MỤC TIÊU
- Thực hiện lệnh điều khiển xuất dữ liệu ra các port trong vi điều khiển 8 bit
- Phân tích được các lệnh cơ bản trong 89C51/C52 và PIC 16F877A.
- Phân biệt được cấu trúc lệnh SET port ngõ vào, ngõ ra của vi điều khiển PIC.
- Nạp và thực thi được các ứng dụng cơ bản trong điều khiển vào ra.
- Đảm bảo an toàn cho người và thiết bị, tự tin trong việc sử dụng và ứng dụng các phần mềm khi lập trình.
1.2. DỤNG VỤ, HỌC CỤ SỬ DỤNG
- Board Kit thí nghiệm Vi Xử Lý.
- Máy tính, phần mềm mô phỏng Proteus, Keil C
- Vi điều khiển 89S52 và PIC 16F877A
1.3. NỘI DUNG
1.3.1 CƠ SỞ LÝ THUYẾT
1.3.1.1. CẤU TRÚC CÁC LỆNH CƠ BẢN TRONG VI ĐIỀU KHIỂN 8
BIT AT89S52
A. Lệnh di chuyển dữ liệu MOV
Lệnh MOV: di chuyển dữ liệu
VD: MOV A,30h ; chuyển nội dung của ô nhớ 30h vào thanh ghi A
MOV A,#30h ; chuyển giá trị 30h vào thanh ghi A
MOV A,R0 ; chuyển nội dung của thanh ghi R0 vào thanh ghi A
MOV A,@R0 ; chuyển nội dung của ô nhớ vào thanh ghi A, địa chỉ của ô nhớ chứa trong thanh ghi R0 (nếu R0 = 30h thì lệnh này tương đương lệnh
MOV A,30h)
Lệnh MOVC: Lệnh chuyển Byte
- Chuyển giá trị hằng sốvào thanh ghi A, thường dùng cho mục đích tra bảng
VD: Lấy phần tử thứ 2 của bảng MaLed7:
MOV DPTR,#MaLed7 MOV A,#2
MOVC A,@A+DPTR
Lệnh MOVX: Lệnh truy xuất dữ liệu ngoài
Ví dụ: Chuyển nội dung 34h vào địa chỉ 1234h ở RAM ngoài
MOV A, #34h ; (A) = 34h
MOV DPTR, #1234h ; (DPTR) = 1234h MOVX @DPTR, A ; ((DPTR)) = (A) B. Lệnh xoay BIT
Lệnh dịch trái RL ( Rotate Left )
Ví dụ: MOV A, #11111110B ; (A) = 11111110b RL A ; (A) = 11111101b
Lệnh dịch phải RR ( Rotate Right )
Ví dụ: MOV A, #01111111B ; (A) = 01111111b RR A ; (A) = 10111111b
Lệnh dịch trái thanh ghi A qua cờ Carry (Rotate Left Carry: RLC) Ví dụ: MOV A, #11111110B ; (A) = 11111110b
MOV C, ACC.0 ; (C) = 0
RLC A ; (A) = 11111100b ; và (C) = 1
Lệnh dịch phải thanh ghi A qua cờ Carry (Rotate Right Carry: RRC) Ví dụ: MOV A, #01111111B ; (A) = 01111111b
MOV C, ACC.7 ; (C) = 0 RRC A ; (A) = 00111111B ; và (C) = 1 C. Lệnh Logic
Lệnh AND Byte (ANL)
Ví dụ : Thực hiện phép AND logic giữa 2 Byte 54h và 67h MOV A, #54h ; (A) = 54h
ANL A, #67h ; (A) = 54h AND 67h = 44h
Lệnh OR Byte (ORL)
Ví dụ: Thực hiện phép OR logic giữa 2 Byte 55h và 0A5h
MOV A, #55h ; (A) = 55h
Lệnh X-OR Byte (XRL)
Ví dụ: Thực hiện hàm khác dấu giữa 2 Byte 67h và 78h
MOV A, #67h ; (A) = 67h
XRL A, #78h ; (A) = 67h XOR 78h = 1Fh
Lệnh AND Bit
Ví dụ : Thực hiện cổng AND Logic với 2 đầu vào (P1.0 và P1.1) và 1 đầu ra (P1.2)
MOV C, P1.0 ; (C) = (P1.0)
ANL C, P1.1 ; (C) = (P1.0) AND (P1.1) MOV P1.2, C ; (P1.2) = (C)
Lệnh OR Bít
Ví dụ: Thực hiện cổng OR Logic với 2 đầu vào (P1.0 và P1.1) và 1 đầu ra (P1.2) MOV C, P1.0 ; (C) = (P1.0)
ORL C, P1.1 ; (C) = (P1.0) OR (P1.1) MOV P1.2, C ; (P1.2) = (C)
D. Một số lệnh cơ bản khác - Lệnh INC: tăng giá trị lên 1 - Lệnh INC: tăng giá trị lên 1
- Lệnh DEC: giảm giá trị xuống 1
- Lệnh SJMP: lệnh nhảy không điều kiện
- Lệnh DJNZ: giảm và nhảy khi giá trị khác 0. Lệnh DJNZ thường dùng để tạo vòng lặp và có dạng sau:
MOV R7,#số_lần_lặp
loop: …… ……
DJNZ R7,loop
- Lệnh CJNE: so sánh và nhảy nếu không bằng
VD: CJNE A,#10,Khac ; Đoạn chương trình xử lý khi nội dung thanh ghi A là 10 SJMP Tiep
Khac: JC Lonhon ; Đoạn chương trình xử lý khi nội dung thanh ghi A < 10
SJMP Tiep
Lonhon: ; Đoạn chương trình xử lý khi nội dung thanh ghi A > 10 Tiep: …
- Lệnh CALL: gọi chương trình con
- Lệnh RET, RETI: lệnh trả về từ chương trình con hay chương trình phục vụ ngắt
- Lệnh DIV AB: chia nội dung thanh ghi A cho thanh ghi B, thương số chứa trong A và số dư chứa trong B.
- Lệnh PUSH: lưu trữ nội dung thanh ghi vào stack
- Lệnh POP: lấy nội dung từ stack.
E. Viết chƣơng trình con tạo trễ
Trong thực tế, để điều khiển các ngoại vi, các thao tác điều khiển luôn cần phải tuân theo một trình tự nhất định với khoảng thời gian giữa chúng là xác định. Do đó, các chương trình con tạo trễ luôn là một phần rất quan trọng của chương trình điều khiển.
Ví dụ như ta cần bật/tắt 1 LED để báo hiệu là chương trình đang hoạt động. Nếu LED bật/tắt quá nhanh, ta sẽ có cảm giác là LED luôn sáng. Vì vậy, giữa 2 lần sáng/tắt cần có 1 thời gian trễ để mắt người có thể cảm nhận được, thường thời gian
này là 1s.
Có nhiều cách để có thể viết được chương trình con tạo trễ.
Lập trình tạo trễ dùng các câu lệnh tạo thành vòng lặp.
Mỗi vi điều khiển luôn sử dụng một tín hiệu xung clock để đồng bộ các hoạt động trong hệ thống (8051 trên kit sử dụng clock với tần số 11.059MHz). Một câu lệnh được thực thi sẽ cần một số xung clock xác định thường được đo bằng chu kỳ máy (một chu kỳ máy của 8051 mất 12 xung clock).
Như vậy, một câu lệnh được thực thi sẽ tiêu hao một khoảng thời gian xác định. Ví dụ lệnh MOVcủa 8051 có thể mất1 hoặc 2 chu kỳ máy, tức là 12 hoặc 24 xung clock, nghĩa là khoảng 1us hoặc 2us (bỏ qua sai số).
Trong tập lệnh của vi điều khiển luôn có lệnh NOP. Lệnh này thường được dùng chỉ để tiêu tốn 1 chu kỳ máy mà không thực thi thao tác gì cả. Do đó, để tạo ra thời gian trễ ngắn, người lập trình có thể dùng vài lệnh NOP. Trong trường hợp thời gian tạo trễ dài, cần nhiều chu kỳ máy, người lập trình có thể dùng vòng lặp để tạo trễ
MOV R7, #n DJNZ R7, $
Vòng lặp này sử dụng (2n+1) chu kỳ máy, với n có độ rộng 1 byte nên số chu kỳ máy tối đa là (2*256+1)=513 chu kỳ máy. Trong thực tế, người lập trình có thể tính gần đúng là 2n chu kỳ máy. Với thời gian dài hơn, có thể lồng nhiều vòng lặp vào nhau
MOV R7, #n
LOOP: MOV R6, #m
DJNZ R6, $ DJNZ R7, LOOP
Vòng lặp này mất (2m+3)*n+1 chu kỳ máy, và tính gần đúng là 2mn chu kỳ.
Lƣu ý là khi tính gần đúng thì vòng lặp bên trong phải có số lần lặp lớn thì mới đảm bảo đƣợc sai số nhỏ.
Lập trình tạo trễ dùng Timer trong vi điều khiển AT89S52.
Timer là ngoại vi on-chip của 8051, để cấu hình và điều khiển ngoại vi này, người lập trình có thể truy xuất vào các thanh ghi tương ứng trong vùng SFR (địa chỉ 80h đến FFh). Đối với Timer đó là các thanh ghi TMOD, THx, TLx, TCON. Trong đó, THx và
TLx chứagiá trị hiện thời của bộ đếm xung.
Ví dụ, để cấu hình Timer0 hoạt động ở chế độ 8-bit
MOV TMOD, #02h
Để khởi tạo giá trị đầu cho Timer0
MOV TH0, #HIGH(-50000) ; giá trị khởi động là -50000
MOV TL0, #LOW(-50000)
Để chờ hết khoảng thời gian đã định trước, người lập trình có thể quan sát cờ TFx.
Cờ này sẽ lên 1 mỗi khi Timerx bị tràn, tức là giá trị bộ đếm xung quay trở lại giá trị 0
(zero)
JNB TF0, $ ; chờ Timer0 tràn sau 50000 chu kỳ máy
Nếu timer hoạt động ở chế độ 16 bit, sau khi timer tràn ta phải nạp lại giá trị đầu
cho timer.
Khi Timer chạy ở chế độ 2, thanh ghi đếm TLx sẽ được tự nạp lại khi timer tràn, vì vậy chương trình không cần dừng timer để nạp lại giá trị đầu .
Ví dụ, để cấu hình Timer0 hoạt động ở chế độ 8-bit:
1.3.1.2. CẤU TRÚC CÁC LỆNH CƠ BẢN TRONG VI ĐIỀU KHIỂN 16 BIT PIC 16F877A BIT PIC 16F877A
A. Phân biệt cấu trúc lệnh SET PORT
Output_tên port(giá trị); //tên port là A,B,C,D,E ; giá trị nằm trong ngoặc là số hex cần nạp vào port.
Output_high(chân port); // xuất mức logic 1 sang một chân port nằm trong ngoặc
Output_low(chân port); // xuất mức logic 0 sang một chân port nằm trong ngoặc
Delay_ms(giá trị); // gọi chương trình tạo trễ, giá trị tạo trễ là ms
Thiết kế sơ đồ nguyên lý mạch hiển thị LED đơn
Hình 2.1: Sơ đồ mạch điều khiển PIC
Điều khiển bất kỳ led nào trong dãy 16 led ở port B và port C theo sơ đồ
Ta có 16 led đơn được điều khiển bởi PORT B và PORT C. 8 LED ở từng port có công tắt chọn riêng biệt, Port nào được chọn thì công tắt đặt ở vị trí ON.
B. Viết chương trình điều khiển 8 led đơn
Viết chương trình điều khiển 1 led đơn ở chân RC7 sáng tắt trong 1s, tần số xung
clock là 8Mhz.
Sơ đồ nguyên lý
Biên soạn chƣơng trình trong CCS Cách 1:
#include<16f887.h>
#use delay(clock=8000000) // defind crystal = 8MHz void main() { while(1) { output_c(0x80); delay_ms (1000); output_c(0x00); delay_ms (1000); } } Cách 2: #include<16f887.h>
void main() { while(1) { output_high(PIN_C7); delay_ms (1000); output_low(PIN_C7); delay_ms (1000); } }
Bài tập nâng cao
1. Viết chương trình điều khiển bật/tắt LED RB1, RB3, RB5, RB7 trong 1s, xung clock có tần số 20MHz.
2. Viết chương trình điều khiển bật/tắt 4 LED RB0, RB2, RB4, RB6 trong 2 s, xung clock có tần số 10MHz
3. Lặp lại yêu cầu 1,2 với port C
4. Vẽ lưu đồ thực hiện chương trình trên
5. Thay đổi lệnh xuất dữ liệu để thực hiện đoạn chương trình trên
Bài tập mẫu:
Viết chƣơng trình điều khiển 8 led đơn ở port B 1 điểm sáng di chuyển từ RB7 - >RB0, tạo trễ 0.5s ở mỗi trạng thái, xung clock là 8MHz
a. Vẽ sơ đồ nguyên lý mạch hiển thị trên phần mềm Proteus b. Lập lưu đồ chương trình cho yêu cầu trên
c. Chương trình tham khảo
#include<16f887.h>
#use delay(clock=8000000) // defind crystal = 8MHz void main()
{
while(1) {
delay_ms (500); output_b(0x40); delay_ms (500); output_b(0x20); delay_ms (500); output_b(0x10); delay_ms (500); output_b(0x08); delay_ms (500); output_b(0x04); delay_ms (500); output_b(0x02); delay_ms (500); output_b(0x01); delay_ms (500); } } 1.3.1.3. NHỮNG SAI HỎNG THƢỜNG GẶP
- Gọi sai tên chương trình con do đánh dấu chữ in hoa, chữ thường phần mềm báo lỗi.
- Lỗi trong lập trình theo cú pháp.
- Lỗi biên dịch chương trình
- Yêu cầu sinh viên kiểm tra các cú pháp từng câu lệnh: dấu phẩy, chấm phẩy, khoảng trắng và các công cụ hỗ trợ mô phỏng trên Proteus.
- Vấn đề an toàn cho thiết bị khi giao tiếp với máy tính cần ngắt nguồn thiết bịtrước khi cắm bus vào bộ thí nghiệm đa năng ĐTVT03
1.3.2 TIẾN HÀNH THỰC HIỆN THÍ NGHIỆM
1. Vẽ sơ đồ mạch hiển thị led đơn trên phần mềm Proteus
2. Viết chương trình điều khiển led đơn chớp tắt 3. Viết chương trình con tạo trễ
1.3.3 BÀI TẬP THÍ NGHIỆM Bài tập 1:
Viết chương trình điều khiển 8 led đơn ở port B 1 điểm tối di chuyển từ RB7 ->RB0, tạo trễ 0.5s ở mỗi trạng thái, xung clock là 8MHz
a. Vẽ sơ đồ nguyên lý mạch hiển thị trên phần mềm Proteus (nếu cần) b. Lập lưu đồ chương trình cho yêu cầu trên
c. Chương trình tham khảo
Sinh viên tự thực hiện yêu cầu này dựa vào chương trình tham khảo ở bài tập mẫu
Bài tập 2:
Viết chương trình điều khiển 8 led đơn ở port C: 2 điểm sáng di chuyển từ ngoài vào trong sau đó di chuyển từ trong ra ngoài. Có tạo trễ 0.3s ở mỗi trạng thái, tần số xung
clock là 20MHz.
a. Vẽ sơ đồ nguyên lý
b. Lập lưu đồ chương trình
c. Viết và thực thi dụng trên phần mềm và nạp trên board thí nghiệm
Bài tập 3:
Viết chương trình điều khiển 8 led đơn ở port B: 2 điểm sáng di chuyển từ RB0 -> RB7
sau đó di chuyển từ RB7 -> RB0. Có tạo trễ 0.4s ở mỗi trạng thái, tần số xung clock là
8MHz
a. Vẽ sơ đồ nguyên lý b. Lập lưu đồ chương trình
c. Viết và thực thi chương trình trên phần mềm và nạp trên board thí nghiệm PIC
Bài tập 4:
Viết chương trình điều khiển 8 led đơn ở port C: 2 điểm tối di chuyển từ trong ra ngoài
sau đó di chuyển từ ngoài vào trong. Có tạo trễ 0.3s ở mỗi trạng thái, tần số xung clock