Professional Documents
Culture Documents
Bai Giang VXL Pic16f877a
Bai Giang VXL Pic16f877a
Address bus
Data bus
P Control bus
(CPU)
RAM ROM I/O Interface
Peripheral Devices
Hình 1.1
P (Microprocessor): Vi xử lý
CPU (Central Processing Unit): Đơn vị xử lý trung tâm
Address bus: Bus địa chỉ
Data bus: Bus dữ liệu
Control bus: Bus điều khiển
RAM (Random Access Memory): Bộ nhớ truy xuất ngẫu nhiên
ROM (Read-Only Memory): Bộ nhớ chỉ đọc
I/O Interface: Khối giao tiếp nhập/xuất
Peripheral Devices: Thiết bị ngoại vi
3.1. Sơ đồ khối tiêu biểu của Hệ thống vi xử lý: (hệ thống vi xử lý có kiến trúc 3-bus)
3.2. Một Hệ thống vi xử lý gồm có các thành phần chính sau:
- P (microprocessor hay còn gọi là CPU): đọc mã lệnh từ bộ nhớ (được ghi dưới dạng các bit 0
và 1), sau đó giải mã và thực thi lệnh.
- Bộ nhớ (Memory): chứa các chương trình điều khiển hoạt động của toàn hệ và các dữ liệu,
kết quả trung gian. Có hai loại bộ nhớ: RAM (Random Access Memory) là loại bộ nhớ truy xuất
ngẫu nhiên và ROM (Read-Only Memory) là loại bộ nhớ chỉ đọc.
- Khối giao tiếp nhập/xuất (Input/Output - I/O): tạo ra khả năng giao tiếp giữa Hệ thống vi xử
lý với các thiết bị ngoại vi như bàn phím, chuột … (thiết bị nhập), màn hình, máy in, loa … (thiết
bị xuất), các ổ đĩa… (thiết bị xuất/nhập)
- Bus: ba khối chức năng trên liên hệ với nhau thông qua một tập các đường dây để truyền
thông tin gọi là bus. Trong hệ thống vi xử lý thường bao gồm 3 loại bus: bus địa chỉ, bus dữ liệu
và bus điều khiển.
3.3. Tổng kết lại các điểm quan trọng:
1. Hệ thống vi xử lý có 3 khối chính:
o Bộ nhớ
o CPU
o Phối ghép (giao tiếp) vào/ra (I/O)
2. CPU đọc thông tin từ bộ nhớ và ghi thông tin vào bộ nhớ
3. Các thiết bị đầu vào đưa thông tin từ bên ngoài vào Hệ thống vi xử lý
4. Các thiết bị đầu ra đưa thông tin từ CPU đến các đối tượng bên ngoài
5. Thông tin không chạy trực tiếp từ bộ nhớ đến các phối ghép vào/ra (I/O) và ngược lại,
trước tiên thông tin phải đi qua CPU
Có thể thấy rằng vi xử lý chỉ trao đổi thông tin với bộ nhớ và các phối ghép vào/ra I/O. Dù hệ
thống sau này phức tạp như thế nào hoặc chương trình có dài đến đâu thì vi xử lý chỉ làm
những việc sau:
1. Đọc từ bộ nhớ
2. Ghi vào bộ nhớ
3. Đọc từ các đầu vào
4. Ghi vào các đầu ra
5. Thực hiện các lệnh nội bộ như lệnh cộng (ADD), lệnh trừ (SUB) …
II. CÁC LOẠI BUS
1. Bus địa chỉ
- Có chức năng chuyển tải các thông tin về địa chỉ.
- Khi đọc/ghi bộ nhớ hay thiết bị I/O, P sẽ đưa ra các bit địa chỉ trên bus địa chỉ để chọn chính xác
một ngăn nhớ (word) hay một thiết bị I/O cụ thể nào đó sẽ được giao tiếp với nó.
- Số lượng địa chỉ mà P có thể quản lý phụ thuộc vào số bit (số đường dây) của bus địa chỉ (16,
20, 24, 32 … bit).
Ví dụ: Một P có số đường dây của bus địa chỉ là N = 16
→ có khả năng quản lý: 2N = 216 = 26.210 = 64.210 = 64 K = 65356 địa chỉ.
- Bus địa chỉ là loại bus một chiều (xuất phát từ P).
Đệm bus địa chỉ
Do tất cả các thiết bị ngoại vi và bộ nhớ đều được nối với bus địa chỉ nên về mặt điện có thể vượt
quá tính chịu tải (fan-out) của vi xử lý. Trong trường hợp các mạch nối vào bus địa chỉ tiêu thụ
dòng điện lớn hơn khả năng chịu tải của vi xử lý thì hệ thống sẽ không hoạt động hay hoạt động
không ổn định. Để giải quyết vấn đề này ta sử dụng các bộ đệm trung gian được gọi là bộ đệm địa
chỉ.
Ví dụ: Đệm địa chỉ cho CPU có bus địa chỉ 16-bit:
Hình 1.2
2. Bus dữ liệu
- Có chức năng chuyển tải các thông tin về dữ liệu đến/từ P.
- Số lượng đường dây của bus này quyết định số bit dữ liệu mà P có khả năng xử lý cùng một lúc
(8, 16, 32, 64 … bit).
- Bus dữ liệu là loại bus hai chiều.
Tuy nhiên tại một thời điểm nhất định thì dữ liệu chỉ được truyền theo một hướng duy nhất.
Data Bus
CPU
Path 2(Khoâ
ng chọn)
Hình 1.4
Đệm bus dữ liệu
- Tương tự như bus địa chỉ, bus dữ liệu cũng cần được đệm để tăng fan-out khi cần thiết. Lưu ý là
cần dùng kỹ thuật đệm 2 chiều (hình 1.5) (IC 74LS245).
Hình 1.5
nhất định. Khi hoạt động, P có thể đưa tín hiệu điều khiển đến các khối khác nhau trong hệ, đồng
thời nó cũng có thể nhận các tín hiệu từ các khối khác để phối hợp hoạt động của toàn hệ.
Lưu ý: Bus điều khiển ở khối I/O vẽ dạng 2 chiều để chỉ tính 2 chiều của cả nhóm tín hiệu, chứ
không phải của mỗi tín hiệu.
- Có 6 loại truyền thông tiêu biểu mà bus điều khiển phải xác đinh bằng tín hiệu điện:
(i) Đọc từ bộ nhớ
(ii) Ghi vo bộ nhớ
(iii) Đọc từ phối ghép đầu vào (Input)
Internal bus
Hình 1.6
Execution Unit: Khối thực thi
Control Unit: Khối điều khiển
Registers: Các thanh ghi
ALU (Arithmetic & Logic Unit): Khối logic - số học
Sequencer: Bộ điều khiển tuần tự
Instruction Register: Thanh ghi lệnh
Instruction Decoder: Bộ giải mã lệnh
Program Counter: Bộ đếm chương trình
Internal bus: Bus nội
Bus interface: Giao tiếp bus
Data bus driver: Bộ điều khiển bus dữ liệu
Control bus driver: Bộ điều khiển bus điều khiển
Address bus driver: Bộ điều khiển bus địa chỉ
- Bộ điều khiển tuần tự (Sequencer): nhận lệnh từ bộ nhớ, sau đó giải mã lệnh và truyền lệnh đã
giải mã đến khối thực thi.
+ Bộ đếm chương trình (Proram Counter): là một thanh ghi lưu giữ địa chỉ của lệnh kế tiếp
sẽ được thực thi. Mỗi khi một lệnh được thực thi, bộ đếm chương trình sẽ được tăng lên 1 để chỉ
ra địa chỉ của lệnh kế tiếp sẽ được thực thi. Nội dung của bộ đếm chương trình được đặt lên bus
địa chỉ để tìm và nhận lệnh mong muốn. Như vậy, P thực hiện các lệnh của chương trình một
cách tuần tự, trừ khi gặp các lệnh chuyển điều khiển (lệnh nhảy, gọi chương trình con …) làm thay
đổi nội dung PC. Trong một số vi xử lý, bộ đếm chương trình còn được gọi là con trỏ lệnh IP
(Instruction Pointer).
+ Bộ giải mã lệnh (Instruction Decoder): thông dịch (diễn dịch) các lệnh được nhận vào P.
Có thể xem bộ giải mã lệnh như một từ điển lưu trữ nghĩa của mỗi lệnh và các bước mà P cần
thực hiện đối với mỗi lệnh được nhận vào. Giống như từ điển nếu có càng nhiều trang thì có thể
định nghĩa được nhiều từ hơn, một P có thể hiểu càng nhiều lệnh hơn nếu có bộ giải mã lệnh
càng lớn.
+ Thanh ghi lệnh (Instructin Register): lưu giữ mã nhị phân của lệnh đang được thực thi.
- Khối thực thi (Execution Unit): thực thi và ghi kết quả câu lệnh. Các toán hạng (operand) liên
quan có mặt ở các thanh ghi (registers) hoặc có từ bus nội (internal bus).
+ ALU (Arithmetic Logic Unit): là một mạch điện tử có khả năng thực hiện các phép toán số
học (+, -, *, / …) và logic (AND, OR, NOT, XOR…).
+ Thanh ghi (Register): là một bộ nhớ cực nhanh, có dung lượng hạn chế nằm bên trong P.
Các thanh ghi thường được dùng để lưu trữ các thông tin tạm thời. Mỗi thanh ghi có một địa chỉ
để truy xuất tới nó. Các thanh ghi được nối với nhau hoặc đến các phần tử khác của P hay nối với
bus ngoài nhờ bus nội. Độ rộng của các thanh ghi có thể là 8-bit, 16-bit, 32-bit hay 64-bit tùy thuộc
vào loại P. Thông tin có thể là 2 giá trị cần được xử lý hay địa chỉ chứa giá trị cần được xử lý nhận
từ bộ nhớ (hay I/O). P có càng nhiều thanh ghi và độ rộng càng lớn thì càng tốt vì lúc này chương
trình không phải thực hiện nhiều phép truyền thông tin giữa P và bộ nhớ do có thể truy xuất trực
tiếp từ thanh ghi, từ đó làm giảm thời gian truy xuất cũng như độ dài lệnh.
+ Khối điều khiển: tạo ra các tín hiệu điều khiển hoạt động của các bộ phận bên trong và
bên ngoài P (tùy theo mã lệnh).
- Giao tiếp bus (Bus Interface): gồm ba bộ điều khiển bus để giao tiếp với bus bên ngoài tương
ứng: bus dữ liệu, bus điều khiển và bus địa chỉ.
Việc tìm nạp lệnh từ bộ nhớ là một trong các thao tác cơ bản nhất mà P thực hiện, gồm các bước
như sau:
- Nội dung của PC được đặt lên bus địa chỉ.
- Tín hiệu điều khiển READ được xác lập (chuyển sang trạng thái tích cực).
- Mã lệnh được đọc từ bộ nhớ và đưa lên bus dữ liệu.
- Mã lệnh được chốt vào thanh ghi lệnh IR bên trong.
- PC được tăng lên để chuẩn bị tìm nạp lệnh kế từ bộ nhớ.
Hình 1.7 minh họa luồng thông tin cho việc tìm nạp lệnh.
Hình 1.7
IV. BỘ NHỚ (MEMORY)
❖ Nhắc lại các đơn vị bit, nibble, byte, word
o 1 nibble = 4 bit
o 1 byte = 8 bit
o Word là một nhóm gồm nhiều byte. Theo qui ước 1 word = 2 byte và 1 word dài = 4
byte (theo thế Hệ thống vi xử lý 16-bit, 32-bit …)
1. Phân loại
+ Bộ nhớ thường được chia làm hai loại: bộ nhớ cơ bản (hay bộ nhớ chính – main memory) và bộ
nhớ lưu trữ (storage memory).
- Bộ nhớ chính: ROM và RAM.
- Bộ nhớ lưu trữ: băng từ, đĩa mềm, đĩa cứng…
+ Thông thường bộ nhớ lưu trữ được xem như là thiết bị I/O.
a. Bộ nhớ chỉ đọc – ROM (Read-Only Memory)
- Là bộ nhớ chỉ đọc, không thể sửa đổi thông tin trong các hoạt động thông thường.
- Thông tin ghi trong ROM sẽ không bị mất đi khi mất nguồn cung cấp.
- ROM được ghi bằng thiết bị chuyên dụng.
- ROM thường được dùng để chứa các chương trình và dữ liệu cố định (chương trình khởi
động, dữ liệu tra bảng …)
- Các loại ROM:
o ROM: thông tin được ghi lúc chế tạo.
o PROM (Programable ROM): là ROM trắng, chỉ cho phép ghi thông tin một lần duy nhất.
o EPROM (Erasable ROM): có thể ghi và xóa thông tin nhiều lần. Loại này được xóa bằng
cách rọi tia cực tím vào cửa sổ thủy tinh trên bề mặt.
o EEPROM (Electrically EPROM): còn gọi là ROM điện, có thể ghi và xóa thông tin bằng
xung điện.
o Flash ROM: tương tự EEPROM.
b. Bộ nhớ truy xuất ngẫu nhiên – RAM (Random Access Memory)
- Cho phép đọc/ghi thông tin bất kỳ lúc nào trong quá trình làm việc mà không cần thiết bị
đặc biệt.
- Thông tin trong RAM sẽ bị mất khi mất nguồn cung cấp.
- Có hai loại RAM chính:
o RAM động – DRAM (Dynamic RAM): có cấu tạo từ các transistor MOSFET và tụ điện (1
phần tử nhớ), lưu trữ thông tin bằng điện tích trong tụ nên thông tin có thể mất đi (rò
rĩ hết) nếu không có biện pháp duy trì thích hợp. Do đó cần có quá trình làm tươi
(refresh) định kì để phục hồi nội dung của các ô nhớ trước khi nó mất đi (rò rĩ hết).
DRAM có thể tích hợp với dung lượng lớn.
o RAM tĩnh – SRAM (Static RAM): cấu tạo từ những Flipflop (FF) (1 phần tử nhớ), mỗi FF
lưu trữ một bit thông tin nên SRAM không cần quá trình làm tươi để duy trì nội dung.
Tuy nhiên, nó khó tích hợp với dung lượng lớn.
2. Cấu trúc bên trong tiêu biểu của bộ nhớ
- Bộ nhớ gồm các phần tử nhớ hay ô nhớ (memory cell) được tổ chức dưới dạng ma trận.
Mỗi ô nhớ chứa một bit thông tin.
- Mảng nhớ được phân chia thành một chuỗi các ngăn nhớ hay từ nhớ (word).
- Mỗi ngăn nhớ đều có một địa chỉ duy nhất.
- Một ngăn nhớ có thể có 4-bit, 8-bit, 16-bit …
+ OE (Output Enable): tín hiệu cho phép xuất dữ liệu (nhận xung kích RD từ P).
+ WE (Write Enable): tín hiệu cho phép ghi dữ liệu (nhận xung kích WR từ P).
+ Address: các tín hiệu địa chỉ (từ bus địa chỉ) để chọn ngăn nhớ cần thao tác.
+ Data: các tín hiệu dữ liệu đọc ra (data output) hay ghi vào (data input), được nối với bus
dữ liệu.
3. Truy xuất bộ nhớ
* Các quy ước trên giản đồ thời gian: Hình 1.9
bus dữ liệu.
3. CPU đợi 1 khoảng thời gian ngắn gọi là thời gian truy cập để vi mạch nhớ giải mã địa chỉ
và xuất dữ liệu ra đường dữ liệu. CPU xuất xung nhịp nạp dữ liệu vào thanh ghi bên trong.
4. Tín hiệu chọn chip được đặt ở mức không tích cực và xóa dữ liệu từ ROM vào CPU.
Địa chỉ từ CPU đến ROM
CS
2
Bus dữ liệu
Dữ liệu của
ROM ở trên
bus dữ liệu
Hình 1.10
b. Truy xuất RAM
Giới thiệu RAM 6264
Đây là IC nhớ cho phép đọc ghi tùy ý, 28 chân 8K (8192 x 8) với 13 đường địa chỉ và 8
đường dữ liệu.
Quy trình đọc RAM: tương tự như đọc dữ liệu từ ROM.
A0 – A12 Đường địa chỉ
D0 – D7 Đường dữ liệu
/CE Chọn chip
/OE Cho phép xuất
/WE Cho phép ghi
Hình 1.11
Read/Write tín
hiệu logic để
truy cập RAM
Dữ liệu xuất ra có giá trị
Bus dữ liệu
TACC
Hình 1.12
Quy trình ghi RAM:
(i) Các đường địa chỉ được kết nối với RAM xác định ngăn nhớ nào trong RAM sẽ được kết nối.
(ii) Dữ liệu cần ghi vào RAM được xuất đến các đường dữ liệu vào của RAM.
(iii) Hệ thống phải đợi một khoảng thời gian nhỏ. Trong khoảng thời gian này RAM sẽ giải mã địa
chỉ và chọn ngăn nhớ mang địa chỉ nhận được. Khoảng thời gian này gọi là thời gian ghi vào
RAM.
(iv) Đường dẫn R/W sẽ được đặt ở mức logic tương ứng với thao tác ghi vào RAM. Tín hiệu này
cho phép dữ liệu được ghi vào RAM
(v) Chú ý rằng ở đây ta nói về các đường dẫn dữ liệu ra từ RAM và các đường dẫn dữ liệu vào
RAM. Trong thực tế vì rằng trong một khoảng khắc nhất định thì ta chỉ thực hiện một thao
tác l đọc hoặc ghi, nên cả hai loại đường dẫn trên được thực hiện bằng một đường dẫn hai
chiều chung.
Địa chỉ từ CPU đến RAM
Read/Write
xuống lên để
nạp dữ liệu
vàp RAM
Hình 1.13
Bảng bộ nhớ
MSB LSB
Các bit địa chỉ
2m
……
m bit n bit
vùng
đến bộ đến các
giải mã chip nhớ 2n
địa chỉ
địa chỉ
Hình 1.14 Quan hệ giữa giải mã địa chỉ và bảng bộ nhớ:
Ví dụ: P có 16 đường địa chỉ (A15 → A0) → có thể quản lý 216 = 26.210 = 64 K = 65536 địa chỉ: + 3
bit cao (A15 → A13) được đưa đến bộ giải mã (ở đây dùng IC 74LS138). + 13 bit thấp (A12 → A0)
được đưa đến các chip nhớ. → có 23 = 8 vùng, mỗi vùng có 213 = 23.210 = 8 K = 8192 địa chỉ.
0000 → 1FFF
2000 → 3FFF Đưa đến các
4000 → 5FFF chân chọn
6000 → 7FFF
8000 → 9FFF
chip của các
A000 → BFFF chip nhớ
C000 → DFFF
E000 → FFFF
Hình 1.16
- P cung cấp hai đường điều khiển đọc và ghi riêng cho I/O: IOR và IOW .
- Giải mã địa chỉ cho I/O tương tự như giải mã địa chỉ cho bộ nhớ.
Hình 1.20 Định địa chỉ I/O theo kiểu trực tiếp
Lưu ý: Một số thiết bị I/O có thể không có các tín hiệu địa chỉ.
Ví dụ: Giải mã địa chỉ cho I/O:
Ví dụ 1: Giả sử P có 16 đường địa chỉ, tín hiệu đọc/ghi I/O tích cực mức 0:
Trong ví dụ này đường địa chỉ A15 được dùng như là bit chọn đọc/ghi bộ nhớ hay I/O. Nếu
A15 = 1, ngõ ra IOR và IOW luôn là mức 1 nên thao tác được chọn là đọc/ghi bộ nhớ. Ngược lại
khi A15 = 0, ngõ ra IOR hay IOW sẽ là mức 0 khi có tín hiệu RD hay WR tương ứng từ bộ xử
lý.
Ví dụ 2: Mức tích cực của các tín hiệu đọc/ghi I/O là mức 1:
CSx : tín hiệu chọn thiết bị I/O từ mạch giải mã địa chỉ.
3. Các phương pháp điều khiển I/O
Có 3 phương pháp cơ bản: hỏi vòng hay kiểm tra tuần tự (polling), điều khiển ngắt
(interrupt) và DMA (Direct Access Memory). Ngoài ra cũng có thể kết hợp các phương pháp trên.
a. Polling (Hỏi vòng)
- P lần lượt kiểm tra từng I/O xem có yêu cầu dịch vụ không thông qua các cờ (flag).
- Tất cả các việc chuyển dữ liệu đến và từ các thiết bị I/O được thực hiện bằng chương trình →
polling là cơ chế đồng bộ (synchronous) với việc thực thi chương trình.
- Kỹ thuật polling có các hạn chế:
+ Mất thời gian của P (do kiểm tra trạng thái của tất cả các ngoại vi thường xuyên).
+ Chậm trong các hệ thống thời gian thực (real-time), không thỏa mãn cho các thiết bị yêu
cầu tốc độ đáp ứng nhanh.
+ Người sử dụng có thể gặp khó khăn trong trong vấn đề lập trình vì phải luôn canh chừng
I/O.
b. Interrupt (Ngắt)
+ Ngắt là một quá trình xử lý thông tin của vi xử lý tương tự như con người xử lý thông tin.
Ví dụ khi bạn đang nói chuyện với một người. Người thứ ba đến và gọi tên bạn. Đây là dấu
hiệu rằng có một người khác yêu cầu sự quan tâm của bạn. Người thứ ba này có thể được coi như
là một yêu cầu ngắt bên ngoài (external interrupt request). Người này yêu cầu bạn ngắt cuộc nói
chuyện của mình. Bạn có thể xử lý yêu cầu nầy bằng các cách như sau:
1. Bạn có thể bỏ qua yêu cầu và coi như người thứ ba là không tồn tại.
2. Bạn có thể dừng một cách thích hợp đối thoại đang diễn ra, rồi bắt đầu quan tâm đến
người thứ ba. Lúc này bạn bắt đầu nói chuyện với người này chứ không nói chuyện với
người đầu tiên nữa.
3. Bạn tức khắc dừng nói chuyện với người thứ nhất và bắt đầu nói chuyện ngay với người
thứ ba.
Khi bạn nói chuyện xong với người thứ ba, bạn muốn quay lại tiếp tục cuộc đối thoại với
người thứ nhất tại điểm mà yêu cầu ngắt xuất hiện.
+ Quá trình này diễn ra tương tự với kỹ thuật ngắt trong hệ thống vi xử lý. Lúc này CPU
đóng vai trị của bạn. Người thứ nhất là chương trình chính đang được thực hiện. Người thứ ba là
một yêu cầu ngắt bên ngoài. Đây là một thiết bị phần cứng bên ngoài yêu cầu CPU quan tâm đến
nó. CPU phải xử lý yêu cầu ngắt nầy bằng cách nào đó. Có nhiều cách xử lý ngắt, các cách được
nêu ở ví dụ trên là các cách xử lý thơng dụng nhất.
+ Ví dụ như ta có một cảm biến báo cháy. Thông thường khi không có lửa thì cảm biến xuất
ra số 1, khi có lửa thì cảm biến xuất số 0 báo cho vi xử lý kích hoạt chương trình báo động. Vi xử lý
có thể luôn luôn đọc trạng thi của cảm biến bằng lệnh IN từ cổng nối với cảm biến. Sau đó vi xử lý
kiểm tra trạng thi cảm biến và gọi chương trình báo động khi trạng thi cảm biến là 0. Tuy vậy đây là
một thao tác lặp đi lặp lại nhiều lần một cách không hiệu quả, vì phần lớn thời gian cảm biến
không báo cháy. Một cách xử lý hiệu quả hơn là đưa tín hiệu của cảm biến vào yêu cầu ngắt của vi
xử lý. Chỉ khi nào yêu cầu ngắt này được kích hoạt thì vi xử lý mới gọi chương trình báo động.
Ngắt là cơ chế bất đồng bộ (asynchronous) với việc thực thi chương trình. Nó được dùng
với mục đích là tránh tối đa hoặc loại bỏ hẳn cơ chế hỏi vòng để kiểm tra trạng thái thiết bị.
- Mỗi thiết bị I/O hay bộ điều khiển của nó được nối với một đường interrupt.
- Khi I/O có yêu cầu trao đổi dữ liệu nó sẽ phát ra một tín hiệu báo cho P. Tín hiệu đó được gọi
là tín hiệu yêu cầu ngắt IRQ (interrupt request). Khi P nhận được yêu cầu ngắt đó, nếu đồng ý
trao đổi thông tin với I/O, nó sẽ trả lời với bộ điều khiển nhập/xuất bằng tín hiệu chấp nhận ngắt
INTA (interrupt acknownledge) đồng thời ngừng chương trình đang làm và gọi chương trình
phục vụ ngắt cho I/O. Sau khi phục vụ xong, nó quay về tiếp tục thực hiện chương trình đang
làm tại nơi bị ngắt.
- Khi có nhiều I/O yêu cầu ngắt đồng thời → cần có mạch điều khiển ưu tiên ngắt.
- Lưu đồ hoạt động của ngắt:
- Thủ tục interrupt về nguyên tắc tương tự với gọi chương trình con, ngoại trừ:
(i) Interrupt được khởi động từ 1 tín hiệu bên trong hoặc bên ngoài thay vì từ những thực thi
lệnh.
(ii) Địa chỉ của chương trình phục vụ interrupt được xác định bằng thủ tục hardware thay vì từ
vùng địa chỉ của lệnh. (bảng vector ngắt được xác định trước của từng loại vi xử lý).
(iii) Khi đáp ứng 1 interrupt cần lưu tất cả các thông tin định nghĩa trạng thái hiện hành của hệ
thống thay vì chỉ lưu trữ bộ đếm chương trình PC.
c. DMA (Direct Memory Access)
- Thông thường khi chương trình muốn chuyển một byte dữ liệu từ ngoại vi vào bộ nhớ, nó phải
thực hiện thông qua P gồm một thao tác nhập và sau đó là thao tác ghi bộ nhớ. Hoặc ngược lại,
khi muốn đưa thông tin từ bộ nhớ ra ngoại vi, P phải làm thao tác đọc bộ nhớ rồi xuất ra ngoại vi.
Trong trường hợp này, chức năng của P chỉ là chuyển dữ liệu mà không xử lý gì cả. Điều này lặp
đi lặp lại nhiều lần sẽ làm lãng phí việc sử dụng P vì chức năng chủ yếu của P là xử lý dữ liệu.
- DMA là cơ chế điều khiển cho phép truy xuất bộ nhớ trực tiếp, không thông qua P.
- Cơ chế DMA được thực hiện bởi một mạch phần cứng được gọi là bộ điều khiển DMA
(DMAC - DMA Controller).
- DMA giúp rút ngắn thời gian truy xuất giữa bộ nhớ và I/O. Cơ chế này rất tiện dụng cho
các thiết bị ngoại vi có khối lượng thông tin trao đổi lớn (trao đổi một khối dữ liệu lớn trong một
thời gian ngắn) ví dụ như card màn hình, đĩa cứng … trong máy tính.
- Quá trình DMA bắt đầu khi có tín hiệu yêu cầu DMA (DRQ) từ thiết bị I/O đến DMAC.
DMAC tiếp tục gởi tín hiệu yêu cầu P nhường bus (HRQ) đến chân HOLD của P để nó thực thi
việc trao đổi dữ liệu trực tiếp giữa bộ nhớ và I/O. Khi P đồng ý nhường bus, nó trả lời cho DMAC
bằng tín hiệu chấp nhận nhường bus (HLDA) đồng thời tạm ngưng mọi hoạt động, tự tách ra khỏi
hệ thống. Đến lượt DMAC gởi tín hiệu thông báo cho phép trao đổi dữ liệu theo kiểu DMA (DACK)
đến thiết bị I/O. Khi DMAC chuyển hết dữ liệu, nó trả quyền điều khiển các bus lại cho P, quá
trình DMA kết thúc.
- Trong thực tế, việc sử dụng cơ chế DMA khá phức tạp và qua nhiều công đoạn vì DMAC
không thi hành bất kì lệnh nào, chương trình nào (không thực thi phần mềm) để chuyển dữ liệu
mà nó thực hiện hoàn toàn bằng phần cứng nên cần phải có trước đầy đủ các thông tin về vị trí dữ
liệu của I/O, vị trí bộ nhớ chứa dữ liệu và số lượng byte cần chuyển để P nạp cho DMAC. Ngoài
ra, DMAC còn phải có khả năng tạo ra các tín hiệu điều khiển cần thiết giống như các tín hiệu của
P.
***
+ Control Unit (CU) tạo ra tất cả các tín hiệu điều khiển trong CPU. Nó khởi tạo các thanh
ghi khi ở nguồn, tạo ra các tín hiệu để lấy lệnh cho ALU. Khối điều khiển có thể được thực hiện
hoàn toàn bởi phần cứng (điều khiển cứng, ví dụ như sử dụng một bộ đếm trạng thái và một mảng
logic khả lập triình) hay kết hợp giữa các lệnh phần mềm (vi lệnh được lưu trữ trong CPU) và phần
cứng (bộ điều khiển vi chương trình. Cả hai họ vi xử lý Intel 8086 và Motorola 68000 đều sử dụng
các bộ điều khiển vi chương trình.
+ Registers – là các bộ nhớ nhỏ, nhanh, thường được sử dụng để lưu dữ liệu và địa chỉ gắn
với (tương ứng với) các mã lệnh của chương trình.
+ ALU thực hiện các phép toán số học và logic
2.2. Cấu trúc bên trong và sự hoạt động
+ Trong sơ đồ khối, ta thấy trong CPU 8086 có hai khối chính: khối phối ghép bus (bus
interface unit, BIU) và khối thực hiện lệnh (execution unit, EU). Việc chia CPU thành hai phần
đồng thời có liên hệ với nhau qua đệm lệnh làm tăng đáng kể tốc độ xử lý của CPU. Các bus bên
trong CPU có nhiệm vụ chuyển tải tín hiệu của các khối khác. Trong số các bus có bus dữ liệu 16 bit
của ALU, bus các tín hiệu điều khiển ở EU và bus trong của hệ thống ở BIU. Trước khi đi ra bus
ngoài hoặc đi vào bus trong của bộ vi xử lý, các tín hiệu truyền trên bus thường được cho đi qua
các bộ đệm để nâng cao tính tương thích cho nối ghép hoặc nâng cao khả năng phối ghép.
+ BIU có nhiệm vụ đưa ra địa chỉ, đọc mã lệnh từ bộ nhớ, đọc/ghi dữ liệu từ/vào cổng hoặc
bộ nhớ. Bên trong BIU còn có bộ nhớ đệm lệnh (còn gọi là hàng đợi lệnh) dùng để chứa các lệnh
đã đọc được nằm sẵn chờ EU xử lý.
+ EU có nhiệm vụ cung cấp địa chỉ cho BIU để khối này đọc lệnh và dữ liệu, còn bản thân nó
thì giải mã lệnh và thực hiện lệnh. Mã lệnh đọc vào từ bộ nhớ được đưa đến đầu vào của bộ giải
mã (nằm trong khối điều khiển CU), các thông tin thu được từ đầu ra của bộ giải mã sẽ được đưa
đến mạch tạo xung điều khiển để tạo ra các dãy xung khác nhau (tùy từng lệnh) điều khiển hoạt
động của các bộ phận bên trong và bên ngoài CPU. Trong EU còn có khối tính toán số học và logic
ALU dùng để thực hiện các thao tác khác nhau với các toán hạng của lệnh.
2.3. Sơ đồ khối bên trong của 8086
+ Đơn vị giao tiếp Bus (BIU)
BIU bao gồm các thanh ghi đoạn (segment registers: CS, DS, SS, ES), con trỏ lệnh IP
(instruction pointer) và bộ điều khiển logic bus (bus control logic, BCL). Đơn vị giao diện BIU còn có
bộ nhớ đệm cho mã lệnh. Bộ nhớ này có chiều dài 4 byte (trong 8088) và 6 byte (trong 8086). Bộ
nhớ đệm mã lệnh được nối với khối điều khển CB (control block) của đơn vị thực hiện lệnh EU. Bộ
nhớ này lưu trữ tạm thời mã lệnh trong một dãy gọi là hàng đợi lệnh. Hàng đợi lệnh cho phép bộ
vi xử lý có khả năng xử lý xen kẽ liên tục dòng mã lệnh (pipelining). Hoạt động của bộ CPU được
chia làm ba giai đoạn: đọc mã lệnh (operation code fetching), giải mã lệnh (decording) và thực
hiện lệnh (execution).
BIU đưa ra địa chỉ, đọc mã lệnh từ bộ nhớ, đọc/ghi dữ liệu từ các cổng vào hoặc bộ nhớ.
Nói cách khác BIU chịu trách nhiệm đưa địa chỉ ra bus và trao đổi dữ liệu với bus.
(220B = 1.048.576B = 1Mbyte). Vì vậy trong chế độ thực (real mode) bộ nhớ được chia làm nhiều
đoạn để một thanh ghi con trỏ 16 bit có thể quản lý được. Các thanh ghi đoạn 16 bit sẽ chỉ ra địa
chỉ đầu của 4 đoạn trong bộ nhớ, dung lượng lớn nhất của mỗi đoạn nhớ sẽ dài 216 = 64 Kbyte và
tại một thời điểm nhất định bộ vi xử lý chỉ làm việc được với 4 đoạn nhớ 64Kbyte này. Việc thay
đổi giá trị của các thanh ghi đoạn làm cho các đoạn có thể dịch chuyển linh hoạt trong không gian
1 Mbyte, vì vậy các đoạn có thể nằm cách nhau khi thông tin cần lưu trong chúng đòi hỏi dung
lượng đủ 64 Kbyte hoặc cũng có thể nằm chồng nhau do có những đoạn không dùng hết độ dài 64
Kbyte và vì thế các đoạn khác có thể bắt đầu nối tiếp ngay sau đó. Địa chỉ của ô nhớ nằm ở đầu
đoạn được ghi trong một thanh ghi đoạn 16 bit, địa chỉ này gọi là địa chỉ cơ sở. Mười sáu bit này
tương ứng với các đường dây địa chỉ từ A4 đến A20. Như vậy giá trị vật lý của địa chỉ đoạn là giá trị
trong thanh ghi đoạn dịch sang trái 4 vị trí. Điều này tương đương với phép nhân với 24 = 16. Địa
chỉ của các ô nhớ khác nằm trong đoạn tính được bằng cách cộng thêm vào địa chỉ cơ sở một giá
trị gọi là địa chỉ lệch hay độ lệch (offset), gọi như thế vì nó ứng với khoảng lệch của toạ độ một ô
nhớ cụ thể nào đó so với ô đầu đoạn. Độ lệch này được xác định bởi các thanh ghi 16 bit khác
đóng vai trò thanh ghi lệch (offset register).
d. Thanh ghi cờ
Các cờ chỉ thị tình trạng của bộ vi xử lý cũng như điều khiển sự hoạt động của chính nó.
Một thanh ghi cờ là 1 flip-flop mà nó chỉ thị một số tình trạng được tạo bởi việc thực thi 1 lệnh
hay các hoạt động điều khiển cụ thể của EU. Thanh ghi cờ 16-bit trong EU có 9 cờ.
o Các cờ điều kiện - conditional flags: Có 6 cờ được gọi là cờ điều kiện. Chúng được lập hay
xoá là bởi EU, dựa trên kết quả của các phép toán số học.
o Cờ điều khiển - control flags: 3 cờ còn lại trong thanh ghi cờ được sử dụng để điều khiển
một số hoạt động của vi xử lý. Chúng được gọi là các cờ điều khiển
a) Carry Flag (CF)- set by carry out of MSB.
b) Parity Flag (PF)- set if result has even parity.
c) Auxiliary carry Flag (AF)- for BCD
d) Zero Flag (ZF)- set if results = 0
e) Sign Flag (SF) = MSB of result
f) TF- single step trap flag
g) IF- interrupt enable flag
h) DF- string direction flag
i) Overflow Flag (OF)- overflow flag
-Timer 2: bộ đếm 8 bit với thanh ghi chu kì 8 bit, bộ đếm8 bit của hệ số tỉ lệ trước, hệ số tỉ
lệ sau.
- Có hai bộ bắt giữ/so sánh/điều rộng xung.
- Các cổng giao tiếp nối tiếp đồng bộ (SSP) với SPI phương thức chủ và I2C (chủ/tớ).
- Bộ truyền nhận nối tiếp đồng bộ, không đồng bộ (UASRT/SCL) có khả năng phát hiện 9 bit
địa chỉ.
- Cổng phụ song song với 8 bit mở rộng, với các chân điều khiển RD, WR, CS.
- Các đặc tính analog:
▪ Bộ chuyển đổi tương tự-số 10 bit trên chip với 8 kênh vào.
▪ Hai bộ so sánh,
+ Bên cạnh đó là một vài đặc tính của vi điều khiển như:
- Bộ nhớ Flash với khả năng ghi xóa được 100000 lần.
- Bộ nhớ dữ liệu EEPROM với khả năng ghi xóa được 1000000 lần.
- Dữ liệu bộ nhớ EEPROM có thể lưu trữ được 40 năm.
- Khả năng tự nạp chương trình với sựđiều khiển của phần mềm.
- Nạp được chương trình ngay trên mạch điện ISP (in circuit programming) thông qua 2
chân.
- Bộ đếm xung thời gian (WDT-Watch dog timer) với dao động RC bên trong.
- Có mã chương trình bảo vệ (chức năng bảo mật mã chương trình).
- Có thể hoạt động hiều dạng dao động khác nhau.
- Chếđộ sleep (phương thức cất giữ) tiết kiệm năng lượng.
- Công nghệ CMOS Flash/ eeprom với nguồn mức thấp, tốc độ cao.
- Dãi điện thế hoạt động rộng: 2V -> 5,5 V.
- Công suất tiêu thụ thấp: <0,6 mA với 5V, 4Mhz. 20 μA với nguồn 3V, 32 Khz. <1 μA với
nguồn dự phòng.
- Khả năng ngắt: lên tới 14 nguồn ngắt trong và ngắt ngoài.
- Ngăn xếp được chia làm 8 mức.
- Truy cập bộ nhớ bằng địa chỉ trực tiếp hay gián tiếp.
- Nguồn khởi động lại (POR-Power on reset).
o Sơ đồ cấu trúc của VĐK PIC 16F8xx 8 bit
o Khảo sát sơ đồ chân, chức năng các chân, port của VĐK PIC 16F8xx 8 bit
▪ RC6/TX/CK: nó có thể được lập trình để dung chân này phát xung nhịp (serial clock) dung
cho truyền bit dạng nối tiếp. Đây còn là chân phát TX (transmit data). Hai chân này dung
cho thu phát bất đồng bộ và đồng bộ (USART), có thể định địa chỉ.
▪ RC7/RX/DT: nó có thể được lập trình để dung chân này trao đổi dữ liệu (serial data). Đây
còn là chân thu dữ liệu (receive data).
▪ RA3/AN3/Vref+, RA2/AN2/Vref-/Cref: là các chân điện áp tham chiếu cho bộ chuyển đổi
tương tự-số (ADC) 10 bit.
▪ RC3/SCK/SCL: chân 18, còn là xung clock nối tiếp (Serial clock-SCK) cho SPI, và là chân clock
nối tiếp cho I2C.
▪ RC4/SDI/SDA: chân 23, còn là chân dữ liệu nối tiếp (serial data).
▪ RC5/SDO: chân 24, còn là chân xuất dữ liệu nối tiếp (serial data out).
▪ Môđun nối tiếp đồng bộ chủ (Master synchronous serial port-MSSP) có thể hoạt động ở hai
chếđộ: SPI và I2C
▪ SPI (serial peripheral interface): giao tiếp ngoại vi nối tiếp. SPI dùng 3 chân SDO, SDI, SCK.
▪ I2C: (inter-integrated circuit): mạch tích hợp lien kết, dung 2 chân: SCL, SDA, có thể ở chế
độ chủ hoàn toàn (full master mode) hay chế độ tớ (slave mode) (với gọi địa chỉ tổng quát).
▪ RD0, RD1, RD2, RD3: chân 19-22, và RD4, RD5, RD6, RD7: chân 27-30: là các chân xuất
nhập của PORT D.
▪ VDD: chân 11, 32: là nguồn dương Vcc từ 2V đến 6V (5,5 V).
▪ VSS: chân 12, 31, là chân đất (mass, GND, 0V).
3.2. Tổ chức bộ nhớ thanh ghi
3.2.1. Giới thiệu.
+ Thanh ghi là một bộ nhớ dung lượng nhỏ và rất nhanh, được sử dụng để tăng tốc độ xử lý
của các chương trình máy tính bằng cách cung cấp các truy cập trực tiếp đến các giá trị cần dùng.
Hầu hết, nhưng không phải tất cả, các máy tính hiện đại hoạt động theo nguyên lý chuyển dữ liệu
từ bộ nhớ chính vào các thanh ghi, tính toán trên chúng, sau đó chuyển kết quả vào bộ nhớ chính.
3.2.2. Các loại kiến trúc bộ nhớ.
+ Kiến trúc Harvard được dùng để chỉ những kiến trúc máy tính mà trong đó phân biệt rõ
ràng bộ nhớ dữ liệu và bộ nhớ chương trình, chúng có những đường truyền (bus) riêng để truy cập
vào bộ nhớ dữ liệu và bộ nhớ chương trình (ngược lại, kiến trúc von Neumann có bộ nhớ và bộ
nhớ chương trình chung).
+ Trong một máy tính sử dụng kiến trúc von Neumann, CPU có thể đọc một lệnh, hoặc
đọc/ghi dữ liệu từ bộ nhớ. Tuy vậy, cả hai quá trình tương tác với lệnh hoặc với dữ liệu, không thể
thực hiện cùng lúc, vì nó sử dụng chung một đường truyền và bộ nhớ. Trong một máy tính kiến
trúc Harvard, CPU có thể vừa đọc một lệnh, vừa truy cập dữ liệu từ bộ nhớ cùng lúc. Một máy tính
kiến trúc Harvard có thể chạy nhanh hơn, bởi vì nó có thể thực hiện ngay lệnh tiếp theo khi vừa
kết thúc lệnh trước đó. Tốc độ được tăng lên nhưng phải trả giá bằng sự thiết kế phần cứng phức
tạp hơn (cụ thể nhất mà chúng ta thấy, đó là việc phải thiết kế 2 bus khác nhau cho dữ liệu và
chương trình).
+ Những năm gần đây, tốc độ CPU tăng lên rất nhiều lần so với tốc độ truy cập vào bộ nhớ
chính. Người ta cần quan tâm đến việc giảm số lần truy cập vào bộ nhớ để đảm bảo tốc độ hoạt
động của CPU. Nếu, trong cùng một lúc, mỗi lệnh của CPU cần phải truy cập vào bộ nhớ 1 lần, vậy
thì việc tăng tốc độ CPU chẳng còn ý nghĩa gì nữa, bởi vì nó luôn luôn bị giới hạn bởi việc truy cập
vào bộ nhớ.
+ Bộ nhớ có thể được thiết kế để có tốc độ truy cập cao, nhưng nó đồng nghĩa với việc giá
sản xuất sẽ cao. Giải pháp là cung cấp một dung lượng nhỏ bộ nhớ đệm, với tốc độ truy cập rất
cao, và chúng ta gọi đó là cache (bộ nhớ đệm). Khi bộ nhớ CPU cần tương tác đang nằm trong
cache, vì việc tương tác vào đó tốn ít thời gian hơn rất nhiều lần so với khi cache phải thay đổi và
lấy dữ liệu từ bộ nhớ chính đưa vào. Việc điều chỉnh cache là một vấn đề quan trọng trong việc
thiết kế máy tính.
+ Những thiết kế chip CPU tốc độ cao ngày này thường kết hợp hai kiến trúc Harvard và
von Neumann. Bộ nhớ cache trên chip được phân thành cache chương trình và cache dữ liệu. Kiến
trúc Harvard được dùng khi CPU truy cập vào cache. Tuy nhiên, trong trường hợp không có cache,
dữ liệu được lấy từ bộ nhớ chính, mà bộ nhớ chính không được chia thành vùng nhớ chương trình
và vùng nhớ dữ liệu. Như vậy, kiến trúc von Neumann được dùng ở tầm vực truy cập bộ nhớ chính.
+ Kiến trúc Harvard cũng thường được dùng trong một số DSP chuyên dụng, thường dùng
trong các sản phẩm xử lý âm thanh, hình ảnh.
+ Thêm vào đó, hầu hết các vi điều khiển thông dụng được dùng trong các ứng dụng điện
tử như là PIC được sản xuất bởi Microchip Technology Inc và AVR của hãng Atmel Corporation,
được phát triển dựa trên kiến trúc Harvard. Những vi xử lý này có đặc tính là có lượng bộ nhớ dữ
liệu và bộ nhớ chương trình nhỏ, rất phù hợp với kiến trúc Harvard và tập lệnh RISC để đảm bảo
hầu hết các lệnh được thực hiện trong 1 chu kỳ máy. Việc phân chia bộ nhớ ra thành bộ nhớ
chương trình và bộ nhớ dữ liệu có thể làm cho bus dữ liệu và bus chương trình có kích thước băng
truyền khác nhau. Ví dụ như các vi điều khiển PIC có bus dữ liệu 8-bit (phụ thuộc vào dòng PIC),
nhưng bus chương trình có thể là 12-bit, 14-bit hoặc 16-bit word. Điều này cho phép mỗi một
lệnh đơn có đủ chỗ chứa cho một giá trị hằng. Những CPU RISC khác, ví dụ như ARM, thường cần
ít nhất 2 lệnh để load một hằng số đủ kích thước.
3.2.3. Tổ chức bộ nhớ của VĐK PIC 16F8xx 8 bit
o Tổ chức bộ nhớ.
+ Cấu trúc bộ nhớ của vi điều khiển PIC16F877A bao gồm bộ nhớ chương trình (Program
Memory) và bộ nhớ dữ liệu (Data Memory).
o Khảo sát bộ nhớ chương trình.
- Bộ nhớ chương trình của vi điều khiển PIC16F877A là bộ nhớ flash, dung lượng bộ nhớ 8K
word (1 word = 14 bit) và được phân thành nhiều trang (từ page0 đến page 3). Như vậy bộ nhớ
chương trình có khả năng chứa được 8*1024 = 8192 lệnh (vì một lệnh sau khi mã hóa sẽ có dung
lượng 1 word (14 bit).
- Để mã hóa được địa chỉ của 8K word bộ nhớ chương trình, bộ đếm chương trình có dung
lượng 13 bit (PC<12:0>).
- Khi vi điều khiển được reset, bộ đếm chương trình sẽ chỉ đến địa chỉ 0000h (Reset vector).
- Khi có ngắt xảy ra, bộ đếm chương trình sẽ chỉ đến địa chỉ 0004h (Interrupt vector).
- Bộ nhớ chương trình không bao gồm bộ nhớ stack và không được địa chỉ hóa bởi bộ đếm
chương trình. Bộ nhớ stack sẽ được đề cập cụ thể trong phần sau.
▪ Thanh ghi OPTION_REG (81h, 181h): thanh ghi này cho phép đọc và ghi, cho phép điều
khiển chức năng pull-up của các chân trong PORTB, xác lập các tham số về xung tác động,
cạnh tác động của ngắt ngoại vi và bộ đếm Timer0.
▪ Thanh ghi INTCON (0Bh, 8Bh,10Bh, 18Bh): thanh ghi cho phép đọc và ghi, chứa các bit điều
khiển và các bit cờ hiệu khi timer0 bị tràn, ngắt ngoại vi RB0/INT và ngắt interrputon-
change tại các chân của PORTB.
▪ Thanh ghi PIE1 (8Ch): chứa các bit điều khiển chi tiết các ngắt của các khối chức năng ngoại
vi.
▪ Thanh ghi PIR1 (0Ch) chứa cờ ngắt của các khối chức năng ngoại vi, các ngắt này được cho
phép bởi các bit điều khiển chứa trong thanh ghi PIE1.
▪ Thanh ghi PIE2 (8Dh): chứa các bit điều khiển các ngắt của các khối chức năng CCP2, SSP
bus, ngắt của bộ so sánh và ngắt ghi vào bộ nhớ EEPROM.
▪ Thanh ghi PIR2 (0Dh): chứa các cờ ngắt của các khối chức năng ngoại vi, các ngắt này được
cho phép bởi các bit điều khiển chứa trong thanh ghi PIE2.
▪ Thanh ghi PCON (8Eh): chứa các cờ hiệu cho biết trạng thái các chế độ reset của vi điều
khiển.
▪ Thanh ghi mục đích chung GPR: Các thanh ghi này có thể được truy xuất trực tiếp hoặc gián
tiếp thông qua thanh ghi FSG (File Select Register). Đây là các thanh ghi dữ liệu thông
thường, người sử dụng có thể tùy theo mục đích chương trình mà có thể dùng các thanh
ghi này để chứa các biến số, hằng số, kết quả hoặc các tham số phục vụ cho chương trình.
▪ Thanh ghi PC (13 bit): bao gồm 2 thanh ghi PCL và PCH, trong đó PCH không truy cập được
trực tiếp mà truy cập gián tiếp thông qua 5 bit thấp trong thanh ghi PCLATH. Có 2 kiểu truy
cập đến PC (chỉ tác động đến PCL; chọn BANK 2K trong ROM rồi dùng lệnh GOTO, CALL)
*** Stack không nằm trong bộ nhớ chương trình hay bộ nhớ dữ liệu mà là một vùng nhớ đặc
biệt không cho phép đọc hay ghi. Khi lệnh CALL được thực hiện hay khi một ngắt xảy ra làm
chương trình bị rẽ nhánh, giá trị của bộ đếm chương trình PC tự động được vi điều khiển cất vào
trong stack. Khi một trong các lệnh RETURN, RETLW hat RETFIE được thực thi, giá trị PC sẽ tự động
được lấy ra từ trong stack, vi điều khiển sẽ thực hiện tiếp chương trình theo đúng qui trình định
trước. Bộ nhớ Stack trong vi điều khiển PIC họ 16F87xA có khả năng chứa được 8 địa chỉ và hoạt
động theo cơ chế xoay vòng. Nghĩa là giá trị cất vào bộ nhớ Stack lần thứ 9 sẽ ghi đè lên giá trị cất
vào Stack lần đầu tiên và giá trị cất vào bộ nhớ Stack lần thứ 10 sẽ ghi đè lên giá trị cất vào Stack
lần thứ 2. Cần chú ý là không có cờ hiệu nào cho biết trạng thái stack, do đó ta không biết được khi
nào stack tràn. Bên cạnh đó tập lệnh của vi điều khiển dòng PIC cũng không có lệnh POP hay PUSH,
các thao tác với bộ nhớ stack sẽ hoàn toàn được điều khiển bởi CPU.
3.3. Lệnh hợp ngữ
3.3.1 Giới thiệu.
- Chương trình: là chuỗi các câu lệnh báo cho máy phải làm gì, làm như thế nào và khi nào phải làm.
- Ngôn ngữ máy: là chuỗi các số 0/1 mà CPU thực hiện. Ngôn ngữ máy được giải quyết trực tiếp
bởi mạch điện tử
GV: Ong Mẫu Dũng – Khoa CNĐT 41
Bài giảng KỸ THUẬT VI XỬ LÝ
Chương trình
Ngôn ngữ
Trình biên dịch hướng đối
Assembly
tượng
▪ Viết chương trình theo ngôn ngữ assembly (hợp ngữ) sử dụng các điều đã cho để giải
quyết bài toán theo yêu cầu đầu ra.
▪ Nhập chương trình vào máy tính.
▪ Chuyển mã ngữ cho chương trình (assembling-biên dịch).
▪ Cho chạy chương trình.
▪ Đánh giá kết quả.
▪ Bảo trì.
Ví dụ: Vẽ lưu đồ giải thuật nhập một số và in ra trị số tuyệt đối của số đó:
Một lệnh trong ngôn ngữ assembly (hợp ngữ) trong chương trình gồm có 4 khu vực sau:
Nhãn Mã lệnh Các toán hạng Ghi chú
▪ Nhãn (label field): là một tên, dùng các chữ cái (a-z), số (0-9) và dấu gạch dưới. Nhãn dùng
cho tham khảo, làm địa chỉ, gọi chương trình con.
▪ Mã lệnh (Op-code): là những chữ viết tắt, dễ gợi nhớ được dùng đối với lệnh của PIC
16F877A. Ví dụ: movf, movlw, addwf, subwf vv…
▪ Toán hạng (operand): lệnh có thể là một toán hạng hoặc hai toán hạng. Trường hợp 2 toán
hạng thì toán hạng thứ 2 gọi là toán hạng đến (destination operand) và toán hạng thứ 1 gọi
là toán hạng nguồn (source operand)
▪ Ghi chú (comment): là những lời chú thích cho cho lệnh đó bắt đầu bằng dấu (;). Chương
trình sẽ bỏ qua
❖ Các kiểu định địa chỉ của VĐK PIC 16F8xx 8 bit
- Địa chỉ số lập tức (tức thời): Số thao tác và số lập tức, có thể nhận được trực tiếp từ trong mã
lệnh. Thí dụ: MOVLW <CONSTANT>
- Địa chỉ trực tiếp: Có thể phỏng vấn truy cập tìm kiếm địa chỉ trực tiếp với bất kì bộ nhớ nào, tức
là trong mã lệnh đã bao gồm địa chỉ của bộ nhớ bị truy cập. Thí dụ: ADDWF <DATA_ADDRESS>,<D>
- Gián tiếp bộ nhớ: Phương thức tìm loại này thực hiện thong qua INDF bộ nhớ và FSR. Địa chỉ
thực tế trước tiên đặt vào trong FSR thông qua việc truy cập INDF để thực hiện gián tiếp đọc và
viết số liệu bộ nhớ. Phương pháp tìm địa chỉ gián tiếp chủ yếu dùng để viết các chương trình các
“bảng tra” hoặc là bảng trị số thực hết sức tiện lợi. Thí dụ: ADDWF INDF,<D>
- Địa chỉ byte/bit: Có thể trực tiếp truy cập tìm kiếm một bit bất kì nào trong bộ nhớ bất kì tức là
trong mã lệnh đã bao gồm địa chỉ của bộ nhớ bị truy cập đồng thời bao gồm địa chỉ hằng số trong
bộ nhớ đó. Thí dụ: SETB PORTB,<CONSTANT>.
❖ Khảo sát chi tiết tập lệnh của VĐK PIC 16F8xx 8 bit
+ Tập lệnh của PIC bao gồm 35 lệnh. Một lệnh thực thi trong 1 chu kì máy, trừ các lệnh nhảy
là 2 chu kì máy. Nhiều nhất (đa số) trong các lệnh bao gồm việc sử dụng thanh ghi làm việc
(working register) hay W. Thanh ghi W là ở trung tâm (trái tim) của vi điều khiển PIC. Để di chuyển
dữ liệu từ ô nhớ A (file A) sang ô nhớ B, bạn phải di chuyển nó từ ô nhớ A sang W và sau đó từ W
sang ô nhớ B, khá giống hệ thống điện thoại dẫn hướng một cuộc gọi tới nơi khác thông qua tổng
đài.Thanh ghi W cũng vận hành phép toán logic và số học trên dữ liệu.
+ Để liên lạc (giao tiếp) với vi điều khiển PIC bạn phải học cách lập trình nó sử dụng tập lệnh
của PIC. PIC 16F877A có 8kx14 bit word bộ nhớ chương trình Flash, 368x8 bit thanh ghi đa năng và
35 lệnh làm nên ba nhóm lệnh: bit, byte và tác vụ điều khiển và số.
+ Lệnh bit: Dạng tổng quát của lệnh: Tác vụ thanh ghi file hướng bit
- Lệnh bit tác động trên bit cụ thể trong một ô nhớ, vì vậy lệnh có thể được theo sau bởi dữ
liệu mà chỉ ra số ô nhớ và số bit. Thí dụ BSF 6,3. Mã này không có nhiều thong tin để chúng ta có
thể sử dụng điều gì đó giống như BSF PORTB,BUZZER trong đó PORTB là ô nhớ 6 và BUZZER được
nối với bit 3 của port ngõ ra. Trong phần tương đương chúng ta sẽ thấy PORTB equ 6 và BUZZER
equ 3.
+ Lệnh byte:
- Lệnh byte làm việc trên tất cả 8 bit trong ô nhớ. Vì vậy một lệnh byte sẽđược theo sau bởi
số ô nhớ phù hợp. Thí dụ: DECF 0Ch; lệnh này không có nhiều thông tin để chúng ta sẽ chỉ ra tên
của ô nhớ như là DECF COUNT. Dĩ nhiên chúng ta sẽ cần khai báo phần tương đương mà COUNT là
ô nhớ 0Ch bằng lệnh COUNT equ 0Ch.
+ Lệnh tác vụ điều khiển và số:
- Tác vụ số và điều khiển vận hành dữ liệu và thực hiện nhảy (rẽ nhánh) chương trình.
Những lệnh này làm việc chủ yếu trên 2 thanh ghi 8 bit-thanh ghi làm việc W và ô nhớ F mà có thể
là một trong 15 thanh ghi đặc biệt của 368-byte RAM của 16F877A. Vi điều khiển PIC là thiết bị 8
bit-điều này có nghĩa là số cực đại mà có thể lưu trữ trong bất kì vị trí nhớ là 255.
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_OFF & _HS_OSC &
_WRT_OFF & _LVP_OFF & _CPD_OFF
;**********************************************************************
ORG 0x000 ; processor reset vector
BANKSEL TRISB
CLRF TRISB
BANKSEL PORTB
CLRF PORTB
+ Ta nhận thấy rằng không có sự khác biệt lớn trong cấu trúc của một chương trình
Assembly viết cho vi điều khiển PIC so với vi điều khiển khác, chỉ có sự khác biệt về các lệnh sử
dụng trong chương trình. Dấu “;” được dùng để đưa một ghi chú vào chương trình và chỉ có hiệu
lực trên một hàng của chương trình. Hình trên là ví dụ về một chương trình đơn giản với các bước
khởi tạo cơ bản ban đầu, ngoài ra nếu cần thiết ta vẫn có thể khai báo thêm các biến, hằng và các
tham số khác trước chương trình chính (label “Main”).
+ Trong trường hợp cần sử dụng đến chương trình ngắt, ta cần một cấu trúc chương trình
phức tạp hơn với nhiều bước khởi tạo phức tạp và phải tuân theo một thứ tự lệnh nhất định. Tuy
nhiên nếu sử dụng trình biên dịch MPLAB, cấu trúc của chương trình dành cho một vi điều khiển
PIC nhất định đã được viết sẵn, ta chỉ việc viết đoạn chương trình điều khiển vào các vị trí thích
hợp trên mẫu chương trình được viết trước đó. Đây là một lợi thế rất lớn khi sử dụng MPLAB để
soạn thảo các chương trình viết cho vi điều khiển PIC.
***
+ Các lệnh thao tác trên một thanh ghi bất kì đều thực hiện cơ chế Read-Modify-Write, tức là
thanh ghi sẽ được đọc, dữ liệu được thao tác và kết quả được đưa vào thanh ghi chứa kết quả (nơi
chứa kết quả tùy thuộc vào lệnh thực thi và tham số d). Ví dụ như khi thực thi lệnh “CLRF PORTB”,
vi điều khiển sẽ đọc giá trị thanh ghi PORTB, xóa tất cả các bit và ghi kết quả trở lại thanh ghi
PORTB.
4.1.2. Các thành phần cơ bản
a. Các kiểu dữ liệu của biến
b. Các toán tử
c. Các lệnh cơ bản (bao gồm cả kiểu dữ liệu và các toán tử)
Lệnh ADDLW
Cú pháp: ADDLW k (0 ≤ k≤255)
Tác dụng: cộng giá trị k vào thanh ghi W, kết quả được chứa trong thanh W
Lệnh ADDWF
Cú pháp: ADDWF f,d (0≤f≤255, d∈¸[0,1]).
Tác dụng: cộng giá trị hai thanh ghi W và thanh ghi f. Kết quả được chứa trong thanh ghi W
nếu d = 0 hoặc thanh ghi f nếu d =1.
Bit trạng thái: C, DC, Z
Lệnh ANDLW
Cú pháp: ANDLW k (0≤k≤255)
Tác dụng: thực hiện phép toán AND giữa thanh ghi W và giá trị k, kết quả được chứa trong
thanh ghi W.
Bit trạng thái: Z
Lệnh ANDWF
Cú pháp: ANDWF f,d (0≤f≤127, d ∈¸[0,1]).
Tác dụng: thực hiện phép toán AND giữa các giá trị chứa trong hai thanh ghi W và f. Kết
quả được đưa vào thanh ghi W nếu d=0 hoặc thanh ghi f nếu d = 1.
Bit trạng thái: Z
Lệnh BCF
Cú pháp: BCF f,b (0≤f≤127, 0≤b≤7)
Tác dụng: xóa bit b trong thanh ghi f về giá trị 0.
Bit trạng thái: không có.
Lệnh BSF
Lệnh COMF
Cú pháp: COMF f,d (0≤f≤127, d∈¸[0,1]).
Tác dụng: đảo các bit trong thanh ghi f. Kết quả được đưa vào thanh ghi W nếu d=0 hoặc
thanh ghi f nếu d=1.
Bit trạng thái: Z
Lệnh DECF
Cú pháp: DECF f,d (0≤f≤127, d∈¸[0,1]).
Tác dụng: giá trị thanh ghi f được giảm đi 1 đơn vị. Kết quả được đưa vào thanh ghi W nếu
d = 0 hoặc thanh ghi f nếu d = 1.
Bit trạng thái: Z
Lệnh DECFSZ
Cú pháp: DECFSZ f,d (0≤f≤127, d∈¸[0,1])
Tác dụng: gía trị thanh ghi f được giảm 1 đơn vị. Nếu kết quả sau khi giảm khác 0, lệnh tiếp
theo được thực thi, nếu kết quả bằng 0, lệnh tiếp theo không được thực thi và thay vào đó
là lệnh NOP. Kết quả được đưa vào thanh ghi W nếu d = 0 hoặc thanh ghi f nếu d = 1.
Bit trạng thái: không có
Lệnh GOTO
Cú pháp: GOTO k (0≤k≤2047)
Tác dụng: nhảy tới một label được định nghĩa bởi tham số k và 2 bit PCLATH<4:3>.
Bit trạng thái: không có.
Lệnh INCF
Cú pháp: INCF f,d (0≤f≤127, d ∈¸[0,1])
Tác dụng: tăng giá trị thanh ghi f lên 1 đơn vị. Kết quả được đưa vào thanh ghi W nếu d = 0
hoặc thanh ghi f nếu d = 1.
Bit trạng thái: Z
Lệnh INCFSZ
Cú pháp: INCFSZ f,d (0≤f≤127, d∈¸[0,1])
Tác dụng: tăng giá trị thanh ghi f lên 1 đơn vị. Nếu kết quả khác 0, lệnh tiếp theo được thực
thi, nếu kết quả bằng 0, lệnh tiếp theo được thay bằng lệnh NOP. Kết quả sẽ được đưa vào
thanh ghi f nếu d=1 hoặc thanh ghi W nếu d = 0.
Bit trạng thái: không có.
Lệnh IORLW
Lệnh SUBWF
Cú pháp: SUBWF f,d (0≤f≤127, d∈¸[0,1])
Tác dụng: lấy giá trị trong thanh ghi f đemtrừ cho thanh ghi W. Kết quả được lưu trong
thanh ghiaW nếu d=0 hoặc thanh ghi f nếu d=1.
Bit trạng thái: C, DC, Z
Lệnh SWAP
Cú pháp: SWAP f,d (0≤f≤127, d∈¸[0,1])
Tác dụng: đảo 4 bit thấp với 4 bit cao trong thanh ghi f. Kết quả được chứa trong thanh ghi
W nếu d=0 hoặc thanh ghi f nếu d=1.
Bit trạng thái: không có
Lệnh XORLW
Cú pháp: XORLW k (0≤k≤255)
Tác dụng: thực hiện phép toán XOR giữa giá trị k và giá trị trong thanh ghi W. Kết quả được
lưu trong thanh ghi W.
Bit trạng thái: Z
Lệnh XORWF
Cú pháp: XORWF f,d
Tác dụng: thực hiện phép toán XOR giữa hai giá trị chứa trong thanh ghi W và thanh ghi f.
Kết quả được lưu vào trong thanh ghi W nếu d=0 hoặc thanh ghi f nếu d=1.
Bit trạng thái: Z
Ngoài các lệnh trên còn có một số lệnh dùng trong chương trình như:
Lệnh #DIFINE
Cú pháp: #DEFINE <text1> <text2>
Tác dụng: thay thế một chuỗi kí tự này bằng một chuỗi kí tự khác, có nghĩa là mỗi khi chuỗi
kí tự text1 xuất hiện trong chương trình, trình biên dịch sẽ tự động thay thế chuỗi kí tự đó
bằng chuỗi kí tự <text2>.
Lệnh INCLUDE
Cú pháp: #INCLUDE <filename> hoặc #INCLUDE “filename”
Tác dụng: đính kèm một file khác vào chương trình, tương tự như việc ta copy file đó vào vị
trí xuất hiện lệnh INCLUDE. Nếu dùng cú pháp <filename> thì file đình kèm là file hệ thống
(system file), nếu dùng cú pháp “filename” thì file đính kèm là file của người sử dụng.
Thông thường chương trình được đính kèm theo một “header file” chứa các thông tin định
nghịa các biến (thanh ghi W, thanh ghi F,..) và các địa chỉ cảu các thanh ghi chức năng đặc
biệt trong bộ nhớ dữ liệu. Nếu không có header file, chương trình sẽ khó đọc và khó hiểu
hơn.
Lệnh CONSTANT
Cú pháp: CONSTANT <name>=<value>
Tác dụng: khai báo một hằng số, có nghĩa là khi phát hiện chuỗi kí tự “name” trong chương
trình, trình biên dịch sẽ tự động thay bằng chuỗi kí tự bằng giá trị “value” đã được định
nghĩa trước đó.
Lệnh VARIABLE
Cú pháp: VARIABLE <name>=<value>
Tác dụng: tương tự như lệnh CONSTANT, chỉ có điểm khác biệt duy nhất là giá trị “value”
khi dùng lệnh VARIABLE có thể thay đổi được trong quá trình thưc thi chương trình còn
lệnh CONSTANT thì không.
Lệnh SET
Cú pháp: <name variable> SET <value>
Tác dụng: gán giá trị cho một tên biến. Tên của biến có thể thay đổi được trong quá trình
thực thi chương trình.
Lệnh EQU
Cú pháp: <name constant> EQU <value>
Tác dụng: gán giá trị cho tên của tên của hằng số. Tên của hằng số không thay đổi trong
quá trình thực thi chương trình.
Lệnh ORG
Cú pháp: ORG <value>
Tác dụng: định nghĩa một địa chỉ chứa chương trình trong bộ nhớ chương trình của vi điều
khiển.
Lệnh END
Cú pháp: END
Tác dụng: đánh dấu kết thúc chương trình.
Lệnh __CONFIG
Cú pháp: __CONFIG “0xxxxx”
Tác dụng: thiết lập các bit điều khiển các khối chức năng của vi điều khiển được chứa trong
bộ nhớ chương trình (Configuration bit).
Lệnh PROCESSOR
Cú pháp: PROCESSOR <processor type>
Tác dụng: định nghĩa vi điều khiển nào sử dụng chương trình.
4.2. Lập trình Hi_tech C (SV tự ôn tập các lệnh trong ngôn ngữ C)
4.2.1. Giới thiệu.
4.2.2. Các thành phần cơ bản của ngôn ngữ lập trình Hi_tech C
4.3. Phần mềm MPLAP, MPLABX (xem file hướng dẫn phần phụ lục).
4.3.1. Cách cài đặt.
4.3.2. Sử dụng cho các ứng dụng
Hitech C template:
#define _XTAL_FREQ 4000000 //Khai báo dùng Thạch anh 4 MHz
unsigned char variable1 = 1; //Khai báo biến toàn cục kiểu char số dương(8bit)
signed char variable2 = 1; //Khai báo biến toàn cục kiểu char số nguyên(8bit)
unsigned int variable3 = 1; //Khai báo biến toàn cục kiểu int số dương (16bit)
unsigned long variable4 = 1; //Khai báo biến toàn cục kiểu long số dương (32bit)
+ Để điều khiển I/O, sử dụng thanh ghi tên TRIS tương ứng với Port cần dùng (đã trình bày
ở 5.2). Như vậy, có các cặp thanh ghi tương ứng: PORTA-TRISA; PORTB-TRISB; PORTC-TRISC;
PORTD-TRISD và PORTE-TRISE.
5.4. Lập trình điều khiển các chức năng xuất nhập
+ Thanh ghi PIC gồm có 4 BANK độc lập. Khi sử dụng thanh ghi nào, trước hết ta cần chọn
BANK chứa thanh ghi tương ứng. Trong ngôn ngữ ASM, câu lệnh BANKSEL <tên thanh ghi> cần
được thực hiện trước khi dùng thanh ghi. Tuy nhiên trong ngôn ngữ Hitech-C, người lập trình
không cần quan tâm đến các BANK thanh ghi, nó sẽ được thực hiện tự động.
+ Có 2 trường hợp đưa dữ liệu vào/ra Port: theo từng bit và theo 1 Byte.
5.5 Ứng dụng ghép nối với ngoại vi
+ Do những ưu điểm vượt bậc của ngôn ngữ C so với ASM, tác giả chỉ chú trọng sử dụng
ngôn ngữ C cho tất cả các ví dụ trong bài giảng.
Ví dụ 1:
Thực hiện điều khiển đồng thời tắt, mở các led ở PORTB theo Ton=Toff=500 ms.
__CONFIG(0x3FFA);
void main(void)
{
TRISB = 0x00; // PORTB là Output
PORTB = 0x00; // Cho 8 chân PORTB xuống mức 0 – các Led OFF
GV: Ong Mẫu Dũng – Khoa CNĐT 57
Bài giảng KỸ THUẬT VI XỬ LÝ
void interrupt isr(void) // Chương trình con ngắt – không dùng tới
{ }
Ví dụ 2:
Thực hiện điều khiển tắt, mở các led ở PORTB từ chân PORTB.0 đến PORTB.7 theo chu kỳ lặp lại
với Ton=Toff=500 ms.
#define _XTAL_FREQ 4000000
#include <htc.h>
__CONFIG(0x3FFA);
void main(void)
{
TRISB = 0x00; // PORTB là Output
PORTB = 0b00000001; // Led ON tại chân PORTB.0
while(1)
{ __delay_ms(500); // Tạo trễ chính xác 500ms, dùng thư viện của Hitech-C
PORTB = PORTB<<1; // Dịch các bit của PORTB sang trái 1 đơn vị
if (PORTB == 0x00) // Kiểm tra đã dịch trái 8 đơn vị hay không
{PORTB = 0b00000001;} //nếu đúng thì gán lại giá trị cho PORTB
}
}
Ví dụ 3:
Thực hiện hiển thị Led 7 đoạn anode chung các số từ 0 đến 9. Thời gian hiển thị mõi số là 1s.
Dựa vào kết nối từ sơ đố mạch, ta xây dựng bảng mã cho Led 7 đoạn. Chú ý, Led 7 đoạn
cực dương chung, và segment-a nối với chân trọng số thấp nhất (PORTB.0), segment-dp nối với
chân trọng số cao nhất (PORTB.7).
#include <htc.h>
__CONFIG(0x3FFA);
const uchar seg7led[]={0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
uchar val=0;
//*************** main ********************
void main(void)
{
TRISB=0x00;
PORTB=0xFF;
while(1)
{
if (val==10) { val=0; }
else
{
PORTB = seg7led[val];
__delay_ms(1000);
val ++;
}
}
}
Ví dụ 4:
Thực hiện hiển thị đồng thời 2 Led 7 đoạn anode chung các số từ 00 đến 59. Thời gian hiển thị
mỗi số là 1s. Tần số lưu ảnh của mắt: 25 hình/s → với 2 led thì mỗi led sẽ sáng trong 20ms.
#include <htc.h>
__CONFIG(0x3FFA);
const uchar seg7led[]={ 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90 };
uchar val1=0;
uchar val2=0;
//*************** main ********************
void main(void)
{
TRISB=0x00;
PORTB=0xFF;
TRISC1 = 0;
TRISC2 = 0;
while(1)
{
for (val1=0 ; val1<6 ; val1++)
{
for (val2=0 ; val2<10 ; val2++)
GV: Ong Mẫu Dũng – Khoa CNĐT 60
Bài giảng KỸ THUẬT VI XỬ LÝ
{
for (uchar count=25; count>0; count--)
{
PORTB = seg7led[val1];
RC1 = 0;
RC2 = 1;
__delay_ms(20);
RC1 = 1;
RC2 = 1;
PORTB = seg7led[val2];
RC1 = 1;
RC2 = 0;
__delay_ms(20);
RC1 = 1;
RC2 = 1;
}
}
}
}
}
Ví dụ 5:
Thực hiện lại ví dụ 3 khi Led 7 đoạn dùng thêm IC chốt song song (74LS373; 74LS374)
Do có IC chốt song song, dữ liệu từng Led 7 đoạn sẽ được chốt vào từng Led tương ứng mà
không cần phải quét các led theo chu kỳ để lưu ảnh. Phương pháp dùng IC chốt có ưu điểm cho
Led sáng không nhấp nhấy, ổn định và lập trình cho vi điều khiển nhẹ nhàng hơn.
Chúng ta chỉ thay đổi một chút cho đoạn code trong ví dụ 4 như sau:
for (val1=0 ; val1<6 ; val1++)
{
for (val2=0 ; val2<10 ; val2++)
{
PORTB = seg7led[val1];
RC1 = 1;
RC1 = 0; // Chốt giá trị val1 cho Led 1
PORTB = seg7led[val2];
RC2 = 1;
RC2 = 0; // Chốt giá trị val2 cho Led 2
__delay_ms(1000);
}
}
Ví dụ 6:
Hiển thị ký tự A lên Led ma trận.
+ Trước hết, chúng ta phải xem xét kết nối port anode và port cathode của Led ma trận với
vi điều khiển. Port anode (dương chung) kết nối đến port C, Port cathode (âm chung) kết nối đến
port B. Như vậy, Port C dùng để xuất tuần tự dữ liệu cột, và Port B dùng cho việc chọn cột dữ liệu
đồng bộ với dữ liệu của Port C.
+ Trong ví dụ này chúng ta cần tạo bảng mã hiển thị ký tự ‘A’ theo dạng ma trận 8x8.
RC0=A[0][i];
RC1=A[1][i];
RC2=A[2][i];
RC3=A[3][i];
RC4=A[4][i];
RC5=A[5][i];
RC6=A[6][i];
RC7=A[7][i];
__delay_ms(5);
Ví dụ 7:
Hiển thị các ký tự lên màn hình LCD16x2 sử dụng giao tiếp mode 4 bit.
+Các thanh ghi : HD44780 có 2 thanh ghi 8 bit quan trọng : Thanh ghi lệnh IR (Instructor Register)
và thanh ghi dữ liệu DR (Data Register)
- Thanh ghi IR : Để điều khiển LCD, người dùng phải “ra lệnh” thông qua tám đường bus
DB0-DB7. Mỗi lệnh được nhà sản xuất LCD đánh địa chỉ rõ ràng. Người dùng chỉ việc cung cấp địa
chỉ lệnh bằng cách nạp vào thanh ghi IR. Nghĩa là, khi ta nạp vào thanh ghi IR một chuỗi 8 bit, chíp
HD44780 sẽ tra bảng mã lệnh tại địa chỉ mà IR cung cấp và thực hiện lệnh đó.
- Thanh ghi DR : Thanh ghi DR dùng để chứa dữ liệu 8 bit để ghi vào vùng RAM DDRAM
hoặc CGRAM (ở chế độ ghi) hoặc dùng để chứa dữ liệu từ 2 vùng RAM này gởi ra cho MPU (ở chế
độ đọc). Nghĩa là, khi MPU ghi thông tin vào DR, mạch nội bên trong chíp sẽ tự động ghi thông tin
này vào DDRAM hoặc CGRAM. Hoặc khi thông tin về địa chỉ được ghi vào IR, dữ liệu ở địa chỉ này
trong vùng RAM nội của HD44780 sẽ được chuyển ra DR để truyền cho MPU.
=> Bằng cách điều khiển chân RS và R/W chúng ta có thể chuyển qua lại giữ 2 thanh ghi này
khi giao tiếp với MPU. Bảng sau đây tóm tắt lại các thiết lập đối với hai chân RS và R/W theo mục
đích giao tiếp.
RS R/W Chức năng
0 0 Ghi vào thanh ghi IR để ra lệnh cho LCD
0 1 Đọc cờ bận ở DB7 và giá trị của bộ đếm địa chỉ ở DB0-DB6
1 0 Ghi vào thanh ghi DR
1 1 Đọc dữ liệu từ DR
+ Cờ báo bận BF: (Busy Flag) Khi thực hiện các hoạt động bên trong chíp, mạch nội bên trong cần
một khoảng thời gian để hoàn tất. Khi đang thực thi các hoạt động bên trong chip như thế, LCD bỏ
qua mọi giao tiếp với bên ngoài và bật cờ BF (thông qua chân DB7 khi có thiết lập RS=0, R/W=1)
lên để báo cho MPU biết nó đang “bận”. Dĩ nhiên, khi xong việc, nó sẽ đặt cờ BF lại mức 0.
+ Vùng RAM hiển thị DDRAM : (Display Data RAM) Đây là vùng RAM dùng để hiển thị, nghĩa là ứng
với một địa chỉ của RAM là một ô kí tự trên màn hình và khi bạn ghi vào vùng RAM này một mã 8
bit, LCD sẽ hiển thị tại vị trí tương ứng trên màn hình một kí tự có mã 8 bit mà bạn đã cung cấp.
Hình sau đây sẽ trình bày rõ hơn mối liên hệ này :
+ Vùng ROM chứa kí tự CGROM: Character Generator ROM: Vùng ROM này dùng để chứa các
mẫu kí tự loại 5x8 hoặc 5x10 điểm ảnh/kí tự, và định địa chỉ bằng 8 bit. Tuy nhiên, nó chỉ có 208
mẫu kí tự 5x8 và 32 mẫu kí tự kiểu 5x10 (tổng cộng là 240 thay vì 2^8 = 256 mẫu kí tự). Người
dùng không thể thay đổi vùng ROM này.
+ Vùng RAM chứa kí tự đồ họa CGRAM : (Character Generator RAM) : Như trên bảng mã kí tự, nhà
sản xuất dành vùng có địa chỉ byte cao là 0000 để người dùng có thể tạo các mẫu kí tự đồ họa
riêng. Tuy nhiên dung lượng vùng này rất hạn chế: Ta chỉ có thể tạo 8 kí tự loại 5x8 điểm ảnh, hoặc
4 kí tự loại 5x10 điểm ảnh.
+ Tập lệnh điều khiển LCD:
Tên lệnh Hoạt động
Clear Mã lệnh: DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
Display DBx = 0 0 0 0 0 0 0 1
Lệnh Clear Display (xóa hiển thị) sẽ ghi một khoảng trống-blank (mã hiện kí tự
GV: Ong Mẫu Dũng – Khoa CNĐT 67
Bài giảng KỸ THUẬT VI XỬ LÝ
20H) vào tất cả ô nhớ trong DDRAM, sau đó trả bộ đếm địa AC=0, trả lại kiểu
hiển thị gốc nếu nó bị thay đổi. Nghĩa là : Tắt hiển thị, con trỏ dời về góc trái
(hàng đầu tiên), chế độ tăng AC.
Return Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
home DBx = 0 0 0 0 0 0 1 *
Lệnh Return home trả bộ đếm địa chỉ AC về 0, trả lại kiểu hiển thị gốc nếu nó bị
thay đổi. Nội dung của DDRAM không thay đổi.
Entry Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
S : Khi S=1 toàn bộ nội dung hiển thị bị dịch sang phải (I/D=0) hoặc sang trái
(I/D=1) mỗi khi có hành động ghi vùng DDRAM. Khi S=0: không dịch nội dung
hiển thị. Nội dung hiển thị không dịch khi đọc DDRAM hoặc đọc/ghi vùng
CGRAM.
Display Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
control D: Hiển thị màn hình khi D=1 và ngược lại. Khi tắt hiển thị, nội dung DDRAM
không thay đổi.
B: Nhấp nháy kí tự tại vị trí con trỏ khi B=1 và ngược lại.
Chu kì nhấp nháy khoảng 409,6ms khi mạch dao động nội LCD là 250kHz.
Cursor Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
display Lệnh Cursor or display shift dịch chuyển con trỏ hay dữ liệu hiển thị sang trái mà
không cần hành động ghi/đọc dữ liệu. Khi hiển thị kiểu 2 dòng, con trỏ sẽ nhảy
shift xuống dòng dưới khi dịch qua vị trí thứ 40 của hàng đầu tiên. Dữ liệu hàng đầu
và hàng 2 dịch cùng một lúc. Chi tiết sử dụng xem bảng bên dưới:
0 0 Dịch vị trí con trỏ sang trái (Nghĩa là giảm AC một đơn vị).
0 1 Dịch vị trí con trỏ sang phải (Tăng AC lên 1 đơn vị).
1 0 Dịch toàn bộ nội dung hiển thị sang trái, con trỏ cũng dịch theo.
1 1 Dịch toàn bộ nội dung hiển thị sang phải, con trỏ cũng dịch
theo.
Function Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
DL: Khi DL=1, LCD giao tiếp với MPU bằng giao thức 8 bit (từ bit DB7 đến DB0).
Ngược lại, giao thức giao tiếp là 4 bit (từ bit DB7 đến bit DB0). Khi chọn giao thức
4 bit, dữ liệu được truyền/nhận 2 lần liên tiếp. với 4 bit cao gởi/nhận trước, 4 bit
thấp gởi/nhận sau.
N : Thiết lập số hàng hiển thị. Khi N=0 : hiển thị 1 hàng, N=1: hiển thị 2 hàng.
F : Thiết lập kiểu kí tự. Khi F=0: kiểu kí tự 5x8 điểm ảnh, F=1: kiểu kí tự 5x10 điểm
ảnh.
Set Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
address Lệnh này ghi vào AC địa chỉ của CGRAM. Kí hiệu [ACG] chỉ 1 bit của chuỗi dữ liệu
6 bit. Ngay sau lệnh này là lệnh đọc/ghi dữ liệu từ CGRAM tại địa chỉ đã được chỉ
định.
Set Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
address Lệnh này ghi vào AC địa chỉ của DDRAM, dùng khi cần thiết lập tọa độ hiển thị
mong muốn. Ngay sau lệnh này là lệnh đọc/ghi dữ liệu từ DDRAM tại địa chỉ đã
được chỉ định.
Khi ở chế độ hiển thị 1 hàng: địa chỉ có thể từ 00H đến 4FH. Khi ở chế độ hiển thị
2 hàng, địa chỉ từ 00h đến 27H cho hàng thứ nhất, và từ 40h đến 67h cho hàng
thứ 2.
Read BF Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
and DBx =[BF] [AC] [AC] [AC] [AC] [AC] [AC] [AC] (RS=0,R/W=1)
address Như đã đề cập trước đây, khi cờ BF bật, LCD đang làm việc và lệnh tiếp theo (nếu
có) sẽ bị bỏ qua nếu cờ BF chưa về mức thấp. Cho nên, khi lập trình điều khiển,
phải kiểm tra cờ BF trước khi ghi dữ liệu vào LCD.
Khi đọc cờ BF, giá trị của AC cũng được xuất ra các bit [AC]. Nó là địa chỉ của
Write Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
CG or Khi thiết lập RS=1, R/W=0, dữ liệu cần ghi được đưa vào các chân DBx từ mạch
DDRAM ngoài sẽ được LCD chuyển vào trong LCD tại địa chỉ được xác định từ lệnh ghi địa
chỉ trước đó (lệnh ghi địa chỉ cũng xác định luôn vùng RAM cần ghi)
Sau khi ghi, bộ đếm địa chỉ AC tự động tăng/giảm 1 tùy theo thiết lập Entry
mode.
Read Mã lệnh : DBx = DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
from CG Khi thiết lập RS=1, R/W=1,dữ liệu từ CG/DDRAM được chuyển ra MPU thông qua
or các chân DBx (địa chỉ và vùng RAM đã được xác định bằng lệnh ghi địa chỉ trước
đó).
DDRAM
Sau khi đọc, AC tự động tăng/giảm 1 tùy theo thiết lập Entry mode, tuy nhiên nội
dung hiển thị không bị dịch bất chấp chế độ Entry mode.
#define rs RB0
#define rw RB1
GV: Ong Mẫu Dũng – Khoa CNĐT 70
Bài giảng KỸ THUẬT VI XỬ LÝ
#define en RB2
#include <htc.h>
__CONFIG(0x3FFA);
//*************** main ********************
void main(void)
{
dport_out ;
lcd1602_write_com(0x28);
//DL=0 (Data Line 4bit mode);N=1 (Number of display line=2);F=0 (Char font 5x7)
lcd1602_write_com(0x0F);
//D=1 (Display on);C=1 (Cursor on);B=1 (Blink on);
lcd1602_write_com(0x80);
lcd1602_write_string("DH CN TP.HCM");
lcd1602_write_com(0xC0);
lcd1602_write_string("Khoa CNDT- DTMT");
__delay_ms(3000);
lcd1602_write_com(0x01);
//clear lcd creen
lcd1602_write_com(0x80);
lcd1602_write_string("Ky thuat VXL");
lcd1602_write_com(0xC0);
lcd1602_write_string("PIC 17F877A");
__delay_ms(3000);
while(1)
{
}
}
rw=0;
en=1;
en=0;
__delay_us(10);
// Make some delay for LCD ready for the next nibble bit, otherwise it will loose data
temp = (lcd_dat << 4) & 0xF0 ;
dport=temp;
rs=1;
rw=0;
en=1;
en=0;
}
uchar temp;
temp = *cy & 0xF0;
dport=temp;
rs=1;
rw=0;
en=1;
en=0;
__delay_us(10);
cy++; //Get the next char until end of string (will get 0 at that time)
}
__delay_ms(50);
}
uchar temp;
dport=temp;
rs=0;
rw=0;
en=1;
en=0;
__delay_us(10);
Ví dụ 9:
Nút bấm đơn và nút bấm ma trận
+ Nút bấm đơn: ở trạng thái nút hở, chân vđk được cấp mức logic-1 thông qua điện trở kéo lên
nguồn 5V, trong khi ở trạng thái nút ấn, chân vđk là mức logic-0 do nối xuống GND thông qua nút
được ấn.
+ Khi ấn nút phát sinh tình trạng gai xung do nút nhấn vật lý không có chống rung.
+ Chúng ta sẽ thêm vào những đoạn mã giúp MCU bỏ qua những tín hiệu không mong muốn
bằng cách thêm vào những khoảng thời gian Delay sau khi nhấn phím, hệ thống sẽ chờ đến khi
tín hiệu ổn định rồi mới lấy và xử lý tín hiệu.
+ Có một vài cách thêm vào như sau:
if(Button_pressed?)
{
Delay(TimeDebounce); //This value about (ms)
Pressed_State;
}
else Not_Pressed;
Giải thích: Sau khi kiểm tra có tín hiệu nhấn phím, chúng ta để cho hệ thống Delay 1 khoảng thời
gian (Tạm dừng chưa lấy tín hiệu). Khoảng thời gian này khá lớn (Cỡ vài chục ms).
Đặc điểm: Khi bạn nhấn phím lâu hơn thời gian Delay thì hệ thống sẽ lại thực thi 1 hoặc nhiều lần
nữa. Khiến cho hàm trong mệnh đề IF sẽ được thực hiện hơn 1 lần.Chúng ta có thể ứng dụng việc
này vào việc tăng hoặc giảm giá trị nào đó chẳng hạn….
if(Button_pressed?)
{
While(Button_pressed?) Delay(TimeDebounce); //This value about (ns)
Pressed;
}
else Not_Pressed;
Giải thích: Sau khi hệ thống kiểm tra có tín hiệu nhấn phím hay không, nếu có thì hệ thống sẽ
nhảy vào trong mệnh đề IF, tại đây hệ thống sẽ kiểm tra tiếp xem phím có đang được nhấn hay
không tại mệnh đề WHILE, nếu có thì sẽ Delay 1 khoảng thời gian. (Giá trị Delay này bạn có thể
đặt cỡ vài chục ns – Ít hơn nhiều so với cách phía trên)
Đặc điểm: phương pháp này sẽ Delay liên tục cho đến khi phím được nhả ra thì mới thực thi
chương trình xử lý. Tiết kiệm thời gian hơn so với phương pháp trước.
#define _XTAL_FREQ 4000000
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define rs RB0
#define rw RB1
#define en RB2
#include <htc.h>
#include "matrix_PIC16F877A.h"
__CONFIG(0x3FFA);
//*************** main ********************
void main(void)
{
dport_out ;
lcd1602_write_com(0x28);
lcd1602_write_com(0x0F);
GV: Ong Mẫu Dũng – Khoa CNĐT 75
Bài giảng KỸ THUẬT VI XỬ LÝ
lcd1602_write_com(0x01);
while(1)
{
uchar key;
key = read_matrixkey();
if (key!=0)
{
lcd1602_write_dat(key);
__delay_ms(20);
}
key = read_PORTE();
if (key==1)
{
lcd1602_write_com(0x18);
__delay_ms(20);
}
else if (key ==2)
{
lcd1602_write_com(0x1C);
__delay_ms(20);
}
else if (key ==3)
{
lcd1602_write_com(0x01);
__delay_ms(20);
}
key = read_PORTC();
if (key!=0)
{
lcd1602_write_dat(idx_to_str[key]);
__delay_ms(20);
}
}
}
__delay_ms(100);
key = PORTC & 0xFF;
if (key != 0xFF)
{
switch (key)
{
case 0B11111110:
{return 1;break;}
case 0B11111101:
{return 2;break;}
case 0B11111011:
{return 3;break;}
case 0B11110111:
{return 4;break;}
case 0B11101111:
{return 5;break;}
case 0B11011111:
{return 6;break;}
case 0B10111111:
{return 7;break;}
case 0B01111111:
{return 8;break;}
default:
{return 0;break;}
}
}
else return 0;
}
return 0;
}
6.1 Timer-Counter
6.1.1 Giới thiệu
Tất cả vi điều khiển có mạch định thời trên chip; một số có 4 timer khác nhau. Vi điều khiển
16F8xx gồm 3 Timers (0,1,2). Các timer này chạy ở tốc độ 1/4 của xung đồng hồ hệ thống (fosc).
Như vậy nếu chúng ta sử dụng thạch anh 32,768 Khz, các timer bên trong sẽ chạy ở ở tần số 8192
Hz. Nếu chúng ta muốn bật led sáng trong 1 giây chẳng hạn thì chúng ta cần đếm 8192 xung. Đây
là rất nhiều xung. Thật là may mắn bên trong vi điều khiển có 1 thanh ghi gọi là thanh ghi OPTION,
mà cho phép chúng ta làm giảm (chậm) những xung này bằng các hệ số chia: 2, 4, 8, 16, 32, 128 và
256. Thanh ghi OPTION được thảo luận trong phần tập lệnh dùng cho Timer0. Thiết lập bộ tỉ lệ
trước , ví dụ như nó được gọi để chia 256 trong thanh ghi OPTION nghĩa là xung định thì của
chúng ta bây giờ là 8192/256=32 Hz, nghĩa là 32 xung trong 1 giây. Như vậy để bật led sáng trong 1
giây, chúng ta chỉ cần đếm 32 xung trong các timer hay 16 xung cho 0,5 giây, hay 160 xung cho 50
mili-giây (ms),v.v...
6.1.2 Timer/counter của VĐK PIC 16f8xx
a. Khảo sát các timer
+ Timer 0 có các đặc điểm sau:
o Là bộ đếm 8 bit (thanh ghi đếm TMR0: chạy từ 0x00 đến 0xFF)
o Có thể đọc/ghi thanh ghi đếm TMR0
o Có bộ chia trước tỉ lệ (prescale) 4bit
o Cho phép lựa chọn nguồn xung clock từ bên trong (xung clock hệ thống) hoặc từ bên
ngoài (thông qua chân T0CKI)
o Có thể phát sinh ngắt khi báo tràn (0xFF về 0x00), đồng thời cờ tràn được set
o Bộ đếm tự khởi động chạy khi vđk được cấp nguồn
6.2. Ngắt
6.2.1 Tổng quan về ngắt của VĐK PIC 16f8xx
+ Có 2 phương pháp nhận ngắt: thứ nhất khi chúng ta liên tục kiểm tra gọi là ngắt bằng
phần mềm (hỏi vòng-polling), thứ hai khi chuông reo gọi là tương đương ngắt phần cứng
(interrupt). Khi xảy ra ngắt chúng ta cần nhớ nội dung của file là gì, nghĩa là thanh ghi trạng thái
STATUS, thanh tích lũy W, Timers và thiết lập PORT v.v., để mà khi trở về từ ngắt, các thiết lập
được lưu trở lại (restored). Chúng ta cần lưu lại các thiết lập, các giá trị trước khi bị ngắt, bởi vì
ngắt các nội dung thanh ghi có thể thay đổi trong chương trình phục vụ ngắt.
6.2.3 Các ứng dụng dùng ngắt của VĐK PIC 16f8xx
INTERUPT AT PIN RB0 AND PORTB(PINS RB4,5,6,7)
T0IF=0; T0IF=0;
GIE=1; TRISD=0;
T0IE=1; PORTD=0x00;
TRISD=0; while(1)
PORTD=0x00; {
while (!TMR0IF) ;
while(1)
{ TMR0IF = 0;
// prescaler with 256 times (not use in this case) // Internal Clock Source
// PS2=1; PS1=1; PS0=1; T0CS=0;
GIE=1; TMR1IF=0;
PEIE=1; TMR1ON=1; // start TMR1
TMR1IE=1;
TRISD=0;
TMR1IF=0; PORTD=0x00;
TMR1ON=1; // start TMR1
while(1)
TRISD=0; {
PORTD=0x00; while(!TMR1IF) ;
while(1) TMR1IF=0;
{
TMR1L=(65536-12500)%256;
} TMR1H=(65536-12500)/256;
}
PORTD=PORTD+1;
void interrupt isr(void) // Timer1 = 12500 cycle * 8 prescaler
{ }
if(TMR1IE&&TMR1IF) }
{
TMR1IF=0;
TMR1L=(65536-12500)%256;
TMR1H=(65536-12500)/256;
PORTD=PORTD+1;
}
}
#include <htc.h>
__CONFIG(0x3FFA);
void main(void)
{
TRISD=0x00;
PORTD=0x00;
// no prescaler
T1CKPS0=0;
T1CKPS1=0;
// Initial value = 10
TMR1L=(65536-10)%256;
TMR1H=(65536-10)/256;
TMR1IF=0;
TMR1ON=1; // start counter
while(1)
{
while (!TMR1IF);
TMR1IF=0;
PORTD=~PORTD;
// Count up 1 times after received 10 pulse from T1CKI pin
}
}
TOUTPS3=0; TOUTPS3=0;
TOUTPS2=1; TOUTPS2=1;
TOUTPS1=0; TOUTPS1=0;
TOUTPS0=0; // post-scale 1:6 TOUTPS0=0; // post-scale 1:6
// TMR2 ends to PR2 (250 cycle in this case) // TMR2 ends to PR2 (250 cycle in this case)
PR2=250-1; PR2=250-1;
GIE=1; TMR2IF=0;
PEIE=1; TMR2ON=1; // TMR2 starts
TMR2IE=1;
TRISD=0;
TMR2IF=0; PORTD=0x00;
TMR2ON=1; // TMR2 starts
uchar count=1;
TRISD=0;
PORTD=0x00; while(1)
{
while(1) while (!TMR2IF) ;
{
} TMR2IF=0;
}
void interrupt isr(void) PR2=250-1;
{ // TMR2 ends to PR2 (250 cycle in this case)
uchar count=1;
if(++count>=25)
if(TMR2IF&&TMR2IE) { count=1;
{ PORTD=PORTD+1; }
TMR2IF=0;
if(++count>=25) }
{ count=1; }
PORTD=PORTD+1; } // total timer = TMR2 * count * precsaler *
} postscaler
} // = 250*25*4*6=150 ms
// total timer = TMR2 * count * precsaler * postscaler
- Trình bày được cấu trúc và tập lệnh của VĐK PIC và các thanh ghi lien quan đến các Modul CCP
của VĐK PIC
- Trình bày được nguyên lý hoạt động và điều khiển Modul CCP ở các chế độ cơ bản của VĐK PIC.
- Xây dựng mô hình, phân tích và thiết kế, vẽ lưu đồ và lập trình ứng dụng được được Modul CCP
cho các ứng dụng
7.1 CCP
+ Mỗi Module Bắt giữ/So sánh/PWM (CCP -Capture/Compare/PWM) chứa một thanh ghi 16 bit
mà có thể hoạt động như:
+ Cả hai Module CCP1 và CCP2 là giống nhau về hoạt động. Riêng Module PWM hoạt động dựa
trên Timer2.
+ Module CCP1: Thanh ghi bắt giữ/So sánh/Điều rộng xung (PWM) thứ 1 (CCPR1) gồm hai thanh
ghi 8 bit: CCPR1L (byte thấp) và CCP1RH (byte cao). Thanh ghi CCP1CON điều khiển hoạt động của
CCP1. Trigger sự kiện đặc biệt có thể được cấu hình để tạo bởi bộ khớp so sánh và sẽ reset timer 1
và bắt đầu chuyển đổi A/D (nếu môđun A/D được cho phép).
+ Tương tự, Module CCP2: Thanh ghi bắt giữ/so sánh/PWM số 2 (CCPR2) gồm có 2 thanh ghi 8 bit:
CCPR2L (byte thấp) và CCPR2H (byte cao). Thanh ghi CCP2CON điều khiển hoạt động của CCP2.
Chế độ bắt giữ (Capture) được dùng cho chức năng lặp thời gian hay xác định độ dài của xung
PWM. Khi đo thời gian xung PWM, clock TMR1 phải đủ nhanh để lấy giá trị có ý nghĩa với độ phân
giải đủ cao mà có sự thể hiện chính xác của định thời.
CCPxM3:CCPxM0: CCPx Mode Select bits trong thanh ghi CCPxCON được sử dụng:
Ngoài ra, Capture sử dụng Timer1 nên tất cả các thanh ghi lien quan đến Timer1 cũng dùng cho
việc thực hiện chế độ Capture.
+ Tín hiệu capture được đưa vào chân CCPx của vđk sau khi đã chuẩn hóa tín hiệu theo mức logic-
0 và logic-1. Chú ý, chân CCPx của vđk phải được cấu hình là INPUT.
+ Tùy theo cấu hình CCPx Mode Select bits, tín hiệu capture được phát hiện sau khi qua bộ chia tỉ
lệ và bộ phát hiện cạnh. Timer 1 được bật chạy để đếm số lượng xung hệ thống.
+ Sau khi capture, vđk thực hiện 2 tác vụ: bật cờ báo CCPxIF và lưu giá trị Timer1 vào thanh ghi
16bit của CCPx là CCPRxH:CCPRxL. Như vậy, người lập trình cần chú trọng đến giới hạn số xung
đếm của Timer1. Trong trường hợp độ rộng xung cần capture quá dài, có thể kết hợp Timer1 với
bộ chia tỉ lệ trước (prescale) hoặc kết hợp với thanh ghi lưu lại số lần Timer1 đếm tràn.
+ Người lập trình dựa vào cờ báo CCPxIF hoặc dựa vào ngắt do CCP để thực hiện các bước tiếp
theo (ví dụ tính toán độ rộng xung …)
Ví dụ 1:
Sử dụng nút bấm tạo xung tác động vào chân RC2 (CCP1). Vđk thực hiện chức năng Capture từ
chân CCP1 và đánh dấu kết quả capture được ra PORTD thông qua Led.
__CONFIG(0x3FFA);
void main(void)
{
// Configure Capture mode for Timer 1
// 0100 [every falling edge] 0101 [every rising edge]
// 0110 [every 4 rising edge] 0111 [every 16 rising edge]
CCP1M3 = 0 ;
CCP1M2 = 1 ;
CCP1M1 = 1 ;
CCP1M0 = 0 ;
TMR1H = 0;
TMR1L = 0;
TMR1ON = 1;
while(1)
{
while (!CCP1IF);
CCP1IF = 0;
PORTD = PORTD+1;
TMR1H = 0;
TMR1L = 0;
}
}
+ Chế độ so sánh (Compare) được dùng cho chức năng lặp thời gian. Chế độ so sánh thay đổi trạng
thái của chân CCPx của vi điều khiển PIC khi nội dung của TMR1 khớp giá trị trong các thanh ghi
CCPRxH và CCPRxL. Chế độ này được dùng kích khởi hay điều khiển phần cứng bên ngoài sau một
trì hoãn cụ thể. Hoặc là dùng để kích hoạt (trigger) một sự kiện đặc biệt bên trong vi điều khiển
(Timer1 và ADC).
CCPxM3:CCPxM0: CCPx Mode Select bits trong thanh ghi CCPxCON được sử dụng:
▪ 1000 = compare mode, when a match occurs, the RC2/CCP1 pin is driven HIGH and CCPxIF =1.
▪ 1001 = compare mode, when a match occurs, the RC2/CCP1 pin is driven LOW and CCPxIF =1.
▪ 1010 = compare mode, when a match occurs, the RC2/CCP1 pin remains unchanged, and
CCPxIF =1, and generate software interrupt.
▪ 1011 = compare mode, when a match occurs, the RC2/CCP1 pin remains unchanged, and
CCPxIF =1 and ADC convers (if ADC was enable).
Ngoài ra, Compare sử dụng Timer1 nên tất cả các thanh ghi liên quan đến Timer1 cũng dùng cho
việc thực hiện chế độ Capture.
+ Giá trị cần so sánh với Timer1 được ghi vào thanh ghi 16 bit: CCPR1H:CCPR1L. Chú ý, chân CCPx
của vđk phải được cấu hình là OUTPUT. Timer 1 được bật chạy để bắt đầu so sánh.
+ Tùy theo cấu hình CCPx Mode Select bits, sau khi compare bằng nhau, vđk có thể báo hiệu thông
qua thay đổi chân CCPx hoặc thông qua các sự kiện đặc biệt. Trong tất cả trường hợp, cờ CCPxIF
luôn được set.
+ Người lập trình dựa vào cờ báo CCPxIF hoặc dựa vào ngắt do CCP để thực hiện các bước tiếp
theo (ví dụ: thực hiện ADC, kích hoạt thiết bị khác, …)
Ví dụ 2:
Dùng chức năng so sánh của CCP, tạo ra xung tuần hoàn có Ton=Toff=60 ms trên 1 chân VĐK. Biết
rằng, vđk thực hiện chương trình ngắt (Interrupt) khi phát hiện compare bằng nhau.
TMR1H = 0;
TMR1L = 1;
}
+ Chế độ PWM là chế độ chiều chế độ rộng xung (Pulse Width Modulator) sử dụng Timer2.
Phương pháp điều xung là phương pháp điều chỉnh điện áp ra tải, hay nói cách khác, là phương
pháp điều chế dựa trên sự thay đổi độ rộng của chuỗi xung vuông, dẫn đến sự thay đổi điện áp ra.
Các PWM khi biến đổi thì có cùng 1 tần số và khác nhau về độ rộng của sườn dương hay sườn âm.
+ PWM được ứng dụng nhiều trong điều khiển. Điển hình nhất mà chúng ta thường hay
gặp là điều khiển động cơ và các bộ xung áp, điều áp... Sử dụng PWM điều khiển độ nhanh chậm
của động cơ hay cao hơn nữa, nó còn được dùng để điều khiển sự ổn định tốc độ động cơ. + Ngoài
lĩnh vực điều khiển hay ổn định tải thì PWM còn tham gia và điều chế các mạch nguồn như: boot,
buck, nghịch lưu 1 pha và 3 pha... + PWM còn gặp nhiều trong thực tế ở các mạch điện điều khiển.
Điều đặc biệt là PWM chuyên dùng để điều khiển các phần tử điện tử công suất có đường đặc tính
là tuyến tính khi có sẵn 1 nguồn 1 chiều cố định. Như vậy PWM được ứng dụng rất nhiều trong các
thiết bị điện- điện tử.
+Chu kỳ PWM (Period): được xác định bởi độ lớn của Timer2 kết hợp với 2 bit prescale.
PWM_Period = (PR2+1)*4*Tosc*Timer2_prescale_value
Thông thường, với Thạch anh 4 Mhz, ta có: PWM_period = (PR2+1)* Timer2_prescale_value (uS)
+ Chu kỳ nhiệm vụ (Duty Cycle) : là chu kỳ Ton của PWM, được xác định bởi 10 bit, trong đó 8bit
trọng số cao là thanh ghi CCPR1L, 2bit trọng số thấp còn lại là CCP1CON<5:4>.
+ Độ phân giải (Resolution): là số lượng bit có thể dùng cho việc tạo ra tín hiệu PWM
▪ Cài đặt PWM_Period bằng cách ghi giá trị tương ứng vào thanh ghi PR2
▪ Cài đặt PWM_Duty_Period bằng cách ghi giá trị tương ứng vào thanh ghi CCPR1L và 2 bit
CCP1CON<5:4> (còn có tên gọi là <CCP1X: CCP1Y>)
▪ Cài đặt chân CCP1 là OUTPUT thông qua bit TRISC<2>.
▪ Cài đặt giá trị cho TMR2-Prescale và cho phép TMR2 đếm (TMR2ON)
▪ Cài đặt chế độ PWM cho module CCP.
Ví dụ 3:
Hãy tạo xung PWM trên ngõ ra CCP2, biết rằng PWM có tần số xung 5000 Hz và chu kỳ nhiệm vụ
là 5% chu kỳ xung.
__CONFIG(0x3FFA);
void main(void)
{
//Define PWM_period and PWM_duty
unsigned int PWM_freq = 5000 ;
unsigned int PWM_period = 1000000/PWM_freq ;
unsigned char PWM_duty = 5 ;
unsigned int PWM_ON = (PWM_period*PWM_duty)/100 ;
switch (CCPR2L_remain)
{
case (0b00):
{
CCP2X=0; // bit CCPxCON<5>
CCP2Y=0; // bit CCPxCON<4>
break;
}
case (0b01):
{
CCP2X=0;
CCP2Y=1;
break;
}
case (0b10):
{
CCP2X=1;
CCP2Y=0;
break;
}
case (0b11):
{
CCP2X=1;
CCP2Y=1;
break;
}
}
// Make the CCPx pin an output by clearing the appropriate TRIS bit
TRISC1=0;
// Establish the TMR2 prescale value and enable Timer2 by writing to T2CON.
T2CKPS1 =0 ;
T2CKPS0 =0 ; // pre-csale 1:1
TMR2ON = 1; // start Timer2 (means PWM)
while(1)
{
}
}
Ví dụ 4:
Hãy tạo xung PWM trên ngõ ra CCP2, biết rằng PWM có tần số xung 5000 Hz và chu kỳ nhiệm vụ
là xx% chu kỳ xung. Với giá trị xx thay đổi được bằng 2 nút ấn trong khoãng 1% đến 99%.
void main(void)
{
// Define PWM_period and PWM_duty
unsigned int PWM_freq = 5000 ;
unsigned int PWM_period = 1000000/PWM_freq ;
unsigned char PWM_duty = 5 ;
unsigned int PWM_ON = (PWM_period*PWM_duty)/100 ;
label_setupPWM:
// Establish the PWM_ON by writing to the DCxB9:DCxB0 bits
// PWM_ON = (DCxB9:DCxB0 bits value) • Tosc • (TMR2 prescale value)
// because (Tosc =1/4) and (TMR2 prescale value =1),
// PWM_ON = (DCxB9:DCxB0 bits value)/4
// CCPRxL = DCxB9:DCxB2 >> 2 = PWM_ON
// and DCxB1:DCxB0 = CCPxCON<5:4> = <CCP1X: CCP1Y> = PWM_ON % 4 ;
CCPR2L=(char)PWM_ON ;
switch (CCPR2L_remain)
{
case (0b00):
{
CCP2X=0; // bit CCPxCON<5>
CCP2Y=0; // bit CCPxCON<4>
break;
}
case (0b01):
{CCP2X=0; CCP2Y=1; break;}
case (0b10):
// Make the CCPx pin an output by clearing the appropriate TRIS bit
TRISC1=0;
// Establish the TMR2 prescale value and enable Timer2 by writing to T2CON.
T2CKPS1 =0 ;
T2CKPS0 =0 ; // TMR2 pre-scale 1:1
TMR2ON = 1; // start Timer2 (means PWM)
while(1)
{
unsigned char key =read_PORTB();
if (key ==8)
{
PWM_duty ++;
if (PWM_duty >=99)
PWM_duty=99;
PWM_ON = (PWM_period*PWM_duty)/100 ;
goto label_setupPWM;
}
else if (key ==7)
{
PWM_duty --;
if (PWM_duty <= 1)
PWM_duty=1;
PWM_ON = (PWM_period*PWM_duty)/100 ;
goto label_setupPWM;
}
}
}
if (key != 0B11000000)
{
__delay_ms(50);
key = PORTB & 0B11000000;
if (key != 0B11000000)
{
switch (key)
{
case 0B10000000:
{PORTD = 7; return 7; break; }
case 0B01000000:
{PORTD = 8; return 8; break; }
default:
{return 0; break; }
}
}
else return 0;
}
return 0;
}
7.2 ADC
+ Để thực hiện đo lường analog thì ta phải cấu hình PIC16F877A thay đổi để làm cho 8 ngõ
I/O số trở thành Analog INPUT từ PORT A và PORT E, để hiển thị giá trị trên led hoặc LCD ta cần
cấu hình 1 PORT B hoặc PORTD là OUTPUT.
+ Độ phân giải lớn nhất của bộ ADC là 10bit. Giả sử rằng ta sử dụng Vref+ Vref- là 5V thì độ
phân giải của ADC là: 4,88 mV.
+ Để cấu hình 16F877A cho đo lường A/D, 3 thanh ghi cần được thiết lập:
▪ ADCON0.
▪ ADCON1.
▪ ADRESH và ADRESL
+ Thanh ghi điều khiển A/D: ADCON0, địa chỉ 1FH, ADCON0 có các chức năng sau:
▪ Bật lên chuyển đổi A/D với ADCON0, bit 0 (ADON). Bit này bật chuyển đổi A/D khi nó được
bật lên 1 và tắt A/D khi nó bị xóa về 0. Khi A/D được bật, nó có thể được để ON (bật) suốt
thời gian nhưng nó lái dòng 90μA, so sánh với phần còn lại của vi điều khiển mà lái dòng
15μA.
▪ Ra lệnh vi điều khiển thực thi chuyển đổi bằng cách bật bit GO/DONE, bit 2. Khi bit
GO/DONE=’1’ thì vi điều khiển thực hiện chuyển đổi A/D. Khi chuyển đổi hoàn thành, phần
cứng xóa bit GO/DONE. Bit này có thể được đọc dùng để chỉ thị kết quả chuyển đổi đã sẵn
sàng để vđk lấy giá trị.
▪ Thiết lập kênh cụ thể (ngõ vào) để thực hiện đo lường. Điều này được thực hiện với 3 bit
chọn kênh CHS0, CHS1 và CHS2, bit 3,4, và 5.
▪ Bit 7 và 6, ADCS1 và ADCS0: 2 bit này được kết hợp thêm với bit ADCS2 trong thanh ghi
ADCON1 dùng cho việc chọn tốc độ clock chuyển đổi A/D.
+ Thanh ghi điều khiển A/D 1: ADCON1, địa chỉ 9FH. Trong ADCON1 có các chức năng sau:
▪ Các bit 0,1,2, và 3 được dùng cấu hình port. <PCFG0, PCFG1, PCFG2 và PCFG3> xác định
chân nào của port A sẽ là ngõ vào analog và chân nào là I/O.
GV: Ong Mẫu Dũng – Khoa CNĐT 108
Bài giảng KỸ THUẬT VI XỬ LÝ
▪ Bit 7, ADFM : bit chọn khuôn dạng kết quả A/D. ADFM =1 kết quả chỉnh phải, 6 bit trong số
cao nhất của ADRESH là đọc là ‘0’. ADFM =0 kết quả chỉnh trái, 6 bit trọng số thấp nhất của
ADRESH là đọc là ‘0’.
▪ Bit 6, ADCS2: bit kết hợp vớ ADCS1, ADCS0 trong ADCON0 dùng chọn clock chuyển đổi A/D.
+ ADRES, thanh ghi kết quả A/D. Đây là các ô nhớ mà kết quả chuyển đổi A/D được lưu trữ. Nếu
nhiều đo lường yêu cầu lưu trữ thì số trong ADRES cần được chuyển tới ô nhớ người dùng trước
khi nó bị đè bởi đo lường kế tiếp. PIC 16F877A có A/D 10 bit, với 8 bit cao được lưu trong ADRESH
và 2 bit thấp hơn được lưu trong ADRESL. Chú ý, bit 7, ADFM trong thanh ghi ADCON1 cấu hình
định dạng kết quả định trái hoặc định phải.
(1) Lựa chọn xung Clock cho quá trình A/D thông qua ADCS2:ADCS1:ADCS0
(2) Cấu hình chân Analog ngõ vào: chọn chân analog INPUT và sử dụng Vref+, Vref- bên trong hay
bên ngoài vđk thông qua PCFG3:PCFG0
(3) Set bit GO\DONE để kích hoạt quá trình chuyển đổi A/D
(4) Đợi 1 khoãng thời gian để quá trình chuyển đổi hoàn thành
Ví dụ 5:
Giả thiết có 2 nguồn tín hiệu analog (sóng SIN) đưa vào 2 chân AN1 và AN2.
Hãy dùng module ADC chuyển đổi và hiển thị giá trị mV lên LCD.
#define rs RB0
#define rw RB1
#define en RB2
void adc_init(void);
void adc_channel(uchar channel);
uint adc_converter(void);
void decimal_bcd_16bit(uint cnt);
uchar num_to_char[10]="0123456789";
uchar disbuf[4];
uint count=0;
#include <htc.h>
__CONFIG(0x3FFA);
lcd1602_write_com(0x80);
lcd1602_write_string("AN1 value: xxxx mV");
lcd1602_write_com(0xC0);
lcd1602_write_string("AN1 value: xxxx mV ");
__delay_ms(3000);
while(1)
{
lcd1602_write_com(0x01); //clear lcd creen
//Display Channel 1
lcd1602_write_com(0x80);
adc_init();
adc_channel(1);
count = adc_converter();
decimal_bcd_16bit(count);
uchar index;
index = disbuf[0];
lcd1602_write_dat(num_to_char[index]);
index = disbuf[1];
lcd1602_write_dat(num_to_char[index]);
index = disbuf[2];
lcd1602_write_dat(num_to_char[index]);
index = disbuf[3];
lcd1602_write_dat(num_to_char[index]);
//Display Channel 2
lcd1602_write_com(0xC0);
adc_init();
adc_channel(2);
count = adc_converter();
decimal_bcd_16bit(count);
index = disbuf[0];
lcd1602_write_dat(num_to_char[index]);
index = disbuf[1];
lcd1602_write_dat(num_to_char[index]);
index = disbuf[2];
lcd1602_write_dat(num_to_char[index]);
index = disbuf[3];
lcd1602_write_dat(num_to_char[index]);
}
}
void adc_init(void)
{
//AD configure analog INPUT and Vref+, Vref-
PCFG3=0; PCFG2=0; PCFG1=0; PCFG0=0;
// PCF<3..0>: AN7 AN6 AN5 AN4 AN3 AN2 AN1 AN0 VERF+ VREF-
// 0 1 0 0 : A A A A A A A A VDD VSS
ADCS2=0;
ADCS1=0;
ADCS0=0; //AD Clock Source --> 1.25 MHz
ADFM=1; //AD result mode: Right Justify [[ADRESH:9,8+ADRESL:7..0]]
adc_result=ADRESH<<8;
adc_result|=ADRESL; // Combine ADRESH and ADRESL together to adc_result
// Conver adc_result into Voltage value with 5000 mV, 10bit resolution
adc_result=(adc_result*5000)>>10
(TXSTA<2>). Chẵn lẻ (parity) không được hỗ trợ bởi phần cứng nhưng có thể hiện thực bằng phần
mềm (và được lưu như là bit dữ liệu thứ 9). Mode bất đồng bộ bị dừng trong khi Sleep. Mode bất
đồng bộ được chọn bằng cách xóa bit SYNC (TXSTA<4>). Môđun bất đồng bộ USART gồm có các
phần tử quan trọng sau đây:
▪ Bộ tạo tốc độ baud.
▪ Mạch lấy mẫu.
▪ Bộ phát bất đồng bộ .
▪ Bộ thu bất đồng bộ.
+ Khi thiết lập sự phát bất đồng bộ, bạn theo các bước sau:
▪ Khởi động thanh ghi SPBRG cho tốc độ baud phù hợp. Nếu tốc độ baud tốc độ cao là
mong muốn thì ta bật (lên 1) bit BRGH.
▪ Cho phép port nối tiếp bất đồng bộ bằng cách xóa bit SYNC và bật bit SPEN.
▪ Nếu ngắt là mong muốn, thì ta bật bit cho phép TXIE.
▪ Nếu sự truyền 9 bit là mong muốn, thì ta bật bit truyền TX9.
▪ Cho phép truyền bằng cách bật bit TXEN mà sẽ bật bit TXIF.
▪ Nếu sự truyền 9 bit được chọn, bit thứ 9 sẽ được nạp vào bit TX9D.
▪ Kiểm tra bộ nhớ đệm (thanh ghi dịch – bit TRMT)đang trống trước khi nạp dữ liệu truyền
▪ Nạp dữ liệu vào thanh ghi TXREG (bắt đầu truyền).
▪ Nếu dùng ngắt, đảm bảo rằng GIE và PEIE (bit 7 và 6) của thanh ghi INTCON được bật.
+ Các thanh ghi được dùng trong phát bất đồng bộ USART:
+ Dữ liệu được nhận trên chân RC7/RX/DT và đến khối phục hồi dữ liệu. Khối khôi phục dữ liệu
thực chất là bộ dịch tốc độ cao, hoạt động ở 16x tốc độ baud, trong khi bộ dịch nối tiếp thu chính
hoạt động ở tốc độ bit hay Fosc.
+ Khi thiết lập sự thu bất đồng bộ, bạn theo các bước sau:
▪ Khởi động thanh ghi SPBRG cho tốc độ baud phù hợp. Nếu tốc độ baud tốc độ cao được
chọn, thì ta bật bit BRGH.
▪ Cho phép port nối tiếp bất đồng bộ bằng cách xóa bit SYNC và bật bit SPEN.
▪ Nếu ngắt là mong muốn, thì ta bật bit cho phép RCIE.
▪ Nếu sự nhận 9 bit là mong muốn, thì ta bật bit RX9.
▪ Cho phép nhận bằng cách bật bit CREN.
▪ Bit cờ RCIF được bật (=1) khi sự nhận hoàn thành và ngắt sẽ tạo ra nếu bit cho phép RCIE
được bật.
▪ Đọc thanh ghi RCSTA để nhận bit thứ 9 (nếu cho phép) và xác định xem có lỗi nào xảy ra
trong quá trình nhận (thu).
▪ Đọc dữ liệu nhận 8 bit bằng cách đọc thanh ghi CRREG.
▪ Nếu có lỗi xảy ra, xoá lỗi bằng cách xóa bit cho phép CREN.
▪ Nếu dùng ngắt, đảm bảo rằng GIE và PEIE (bit 7 và 6) của thanh ghi INTCON được bật.
+ Các thanh ghi được dung trong phát bất đồng bộ USART:
#include <htc.h>
__CONFIG(0x3FFA);
sendstring_uart("***string 1****\r\n");
sendstring_uart("***STRING 2****\r\n");
sendstring_uart("***STRING 3****\r\n");
sendstring_uart("\r\n"); // \r\n means new lines
while(1)
{
}
}
TRISD = 0;
PORTD = cd; // display received byte to 8 led
}
}
d. Giao tiếp truyền dữ liệu giữa máy tính và VĐK theo kiểu truyền UART.
+ Sử dụng lại chương trình truyền/nhận ký tự như trên để giao tiếp UART với máy tính.
+ Như đã giới thiệu, Module MSSP của PIC có 2 thanh ghi chức năng Truyền/Nhận là Thanh
ghi-dịch SSPSR và thanh ghi đệm SSPBUF. SSPSR sẽ dịch chuyển data vào hoặc ra khỏi thiết bj, bit
MSB trước. SSPBUF sẽ giữ dữ liệu mà dữ liệu này đã được ghi vào SSPSR cho đến khi nhận được
byte dữ liệu kế tiếp. Nếu SSPBUF đã nhận đủ 8 bit dữ liệu thì bit BF (Buffer Full detect bit) và SSPIF
(Interrupt Flag bit) của thanh ghi SSPSTAT được set. Bất cứ việc ghi/đọc dữ liệu trong thanh ghi
SSPBUF trong qua trình truyền/nhận đều bị cấm và bit WCOL sẽ được set lên 1. Bit này cần được
xóa để nếu dữ liệu tiếp theo được ghi vào SSPBUF hoàn tất thành công.
+ Cần phải đọc dữ liệu trong SSPBUF ngay sau khi nhận về để cho phép các dữ liệu tiếp
theo được ghi vào. Bit BF sẽ cho biết khi nào SSPBUF đầy dữ liệu (quá trình truyền hoàn tất). Khi ta
đọc giá trị trong thanh ghi SSPBUF, bit BF sẽ được xóa.
+ Một cách tổng quát, Ngắt của Module MSSP thường dùng để xét xem quá trình truyền/
nhận xong hay chưa. Nếu bit SSPIF = 1 thì chứng tỏ quá trình truyền nhận đã hoàn tất. Ngược lại,
nếu bit SSPIF = 0 thì quá trình chưa hoàn thành.
* Tập hợp các thanh ghi liên quan đến module SPI:
+ Cực tính của xung SCK được chọn bằng cách thao tác lên bit CKP (SSPCON1). Dạng sóng của giao
tiếp SPI được biểu diễn như hình bên dưới với bit MSB được truyền đi trước. Ở Master Mode, tốc
độ xung SCK của giao tiếp SPI được chọn một trong số 4 tùy chọn sau:
▪ Fosc/4 ( hoặc Tcy)
▪ Fosc/16 (hoặc 4 - Tcy)
▪ Fosc/64 (hoặc 16 – Tcy)
▪ Timer2 output/2
+ Hình sau cho thấy dạng sóng của SPI Master Mode.
GV: Ong Mẫu Dũng – Khoa CNĐT 130
Bài giảng KỸ THUẬT VI XỬ LÝ
0x04). Khi chân SS được đưa xuống mức thấp, sự truyền/ nhận dữ liệu được cho phép và
chân SDO sẽ được thúc để tải dữ liệu. Khi chân SS được đưa lên mức cao, chân SDO sẽ
không được thúc nữa, dữ liệu sẽ không được lưu thông.
- Nếu SPI Slave Mode có chân SS điều khiển được kích hoạt, thì mô-đun SPI sẽ reset khi chân
SS được đưa lên Vdd. Lúc này bit counter bị xóa về ‘0’. Ta cũng có thể xóa bit counter bằng
cách xóa bit SSPEN.
- Cần phải sử dụng chân SS nếu như SPI Slave Mode được dùng với bit CKE được set.
uchar byte_send = 0;
void spi_send_byte(uchar dd);
//*************** main ********************
void main(void)
{
SSPM3=0;
SSPM2=0;
SSPM1=0;
SSPM0=0; // SPI rate = Fosc/4
TRISC3=0; // RC3/SCK
TRISC4=1; // RC4/SDI
TRISC5=0; // RC5/SDO
while(1)
GV: Ong Mẫu Dũng – Khoa CNĐT 134
Bài giảng KỸ THUẬT VI XỬ LÝ
{
spi_send_byte(byte_send);
byte_send ++;
__delay_ms(500);
}
}
Chú ý: Việc thiết lập các thông số SPI cho vđk phụ thuộc vào giản đồ xung 74LS595 như sau:
Ví dụ 3:
Gửi ký tự từ PIC SPI master đến PIC SPI slave, ký tự Slave thu được sẽ truyền đi qua kênh truyền
UART để hiển thị (ví dụ UART monitor)
TRISC3=1; // RC3/SCK
TRISC4=1; // RC4/SDI
TRISC5=0; // RC5/SDO
while(1)
{ }
}
//********************* INTTERUPT *****************
void interrupt isr(void)
{
if(SSPIE&&SSPIF) // map with SSP Int
{
SSPIF=0;
recv_byte = SSPBUF;
senddata_uart (recv_byte);
}
}
//****************** UART send Subroutin *******************
void senddata_uart(uchar cdd)
{
while(!TRMT); // wait until writing complete
TXREG=cdd;
}
//************************UART send one string**************
void sendstring_uart(const uchar *dd)
{
while((*dd)!=0)
{
senddata_uart(*dd);
dd++;
}
}
//****************** SPI send Subroutin *******************
void spi_send_byte(uchar dd)
{
while (WCOL) ; //Check the SSPBUF collision
SSPBUF=dd;
}
8.3.2. I2C
a. Giới thiệu.
+ Viết tắt của Inter-Intergrated Circuit – là một bus nối tiếp do Philip phát triển. Trước đây
I2C chủ yếu được dùng trong việc chế tạo các hệ thống điện tử sử dụng chip của Philip. Ngày nay
I2C được sử dụng rộng rãi trong việc kết nối các thiết bị ngoại vi tốc độ thấp vào các mạch tích hợp.
b. Tổng quan về truyền dữ liệu I2C.
+ I2C sử dụng 2 đường truyền tín hiệu 2 chiều (một đường clock và một đường data), sử dụng
hiệu điện thế 5V và cùng được kéo lên cao (pull-ups) bằng điện trở. Hai chân được dung cho
truyền dữ liệu:
▪ Clock nối tiếp (SCL)-RC3/SCK/SCL.
▪ Dữ liệu nối tiếp (SDA)-RC4/SDI/SDA.
+ I2C hoạt động theo nhiều mode: mode chuẩn (standard mode) hoạt động ở tốc độ 100kbit/s,
mode tốc độ thấp (low-speed mode) hoạt động ở tốc độ 10kbit/s. Tần số clock có thể cho xuống 0.
+ I2C có sử dụng 7 bit để định địa chỉ, do đó trên một bus có thể có 112 nút (16 địa chỉ được sử
dụng vào mục đích riêng).
+ Điểm mạnh của I2C là ở chỗ, một vi điều khiển có thể dùng để điều khiển cả một mạng thiết
bị mà chỉ tốn 2 chân của vi điều khiển. Chính vì nguyên nhân đó mà I2C và SPI là hai chuẩn giao
tiếp được sử dụng nhiều nhất trong các IC đặc biệt là các VĐK 8 bít.
+ Giao tiếp I2C hỗ trợ các chế độ sau trong phần cứng:
▪ Chế độ chủ (master mode).
▪ Chế độ đa (nhiều) chủ (multi master mode).
▪ Chế độ tớ (slave mode).
c. Quy trình truyền dữ liệu I2C.
+ Để truyền và nhận dữ trong I2C tạo thành khối, người ta dùng các bít Stop, Start, Restart,
ACK, NACK.
+ Quá trình hoạt động các bit này khá giống nhau đẻ bắt đầu phát đi: ta phải set bit tưong
ứng trong thanh ghi đó đi (VD: muốn gửi bít Stop đi ta chỉ cần PEN =1), tương tự với các bit còn lại
và khi đã truyền xong rồi thì các bit đó sẽ tự động chuyển về 0 ( thông qua Hardware).
+ Lưu ý, quá trình hoạt động này chỉ có tác dụng khi mà I2C đã hoàn thành xong nhiệm vụ
trước đó. Như vậy ta cần phải biết được lúc nào chương trình đã hoàn thành xong nhiệm vụ và
đây chính là vai trò của cờ SSPIF trong thanh ghi PIR1, SSPIF báo cho vđk biết là hoạt động đã kết
thúc bằng cách Set từ 0 lên 1 và ta phải xoá cờ này băng phần mềm cho các hoạt động tiếp theo.
Do yêu cầu I2C là: khi hoạt động này kết thúc, thì mới cho phép hoạt động kia bắt đầu chính yêu
cầu này đặt ra chúng ta phải có một chương trình con báo hiệu khi kết thúc một hoạt động.
+ Quá trình truyền một byte dữ liệu từ Master qua slave ( transmit), để truyền một byte dữ
liệu gồm có các bước cơ bản:
▪ Gửi bít Start từ Master tới slave, đợi cho đến khi truyền xong.
▪ Gửi địa chỉ của slave lên đường truyền. Dùng để chọn Slave nào hoạt động. Đợi cho đến khi
truyền xong.
▪ Gửi địa chỉ cần lưu dữ liệu tới, đợi cho đên khi truyền xong.
▪ Gửi dữ liệu cần truyền tới Slave, đợi cho đến khi truyền xong.
▪ Tiếp tục gửi dữ liệu ......
▪ Khi muốn kết thúc gửi bít Stop lên đường truyền.
+ Quá trình nhận dữ liệu từ slave phải tuân thủ theo các bước sau:
▪ Gửi bít Start từ Master tới slave. Đợi cho đến khi truyền xong
▪ Gửi địa chỉ của slave (chú ý: bit 0 = 0 ) lên đường truyền. Dùng để chọn Slave nào hoạt
động, Đợi cho đến khi truyền xong
▪ Gửi địa chỉ của dữ liệu cần nhận Đợi cho đên khi truyền xong
▪ Gửi bit Restart, Đợi cho đến khi truyền xong
▪ Gửi địa chỉ của slave lên đường truyền ( chú ý, bit 0 =1 báo rằng hoạt động sắp tới là read).
Đợi cho đến khi truyền xong
▪ Đọc dữ liệu từ Slave . Đợi cho đên khi đọc xong
▪ Phát bít ACK báo tiếp tục nhận dữ liệu . Đợi cho đến khi truyền xong
▪ Đọc dữ liệu từ Slave . Đợi cho đên khi đọc xong
▪ Phát bít ACK báo tiếp tục nhận dữ liệu . Đợi cho đên khi truyền xong
▪ ........(Lập lại đến khi đủ dữ liệu cần đọc)...........
▪ Đọc dữ liệu từ Slave . Đợi cho đên khi đọc xong
▪ Phát bít NACK báo rằng qua trình nhận dữ liệu đã kết thúc . Đợi cho đên khi truyền xong
▪ Phát bít Stop để kết thúc
d. Khảo sát dạng sóng truyền dữ liệu I2C.
▪ SMP chọn Speed chuẩn (SMP =1: 100kHz, 1MHz; SMP =0: 400KHz)
▪ R/W báo rằng quá trình truyền vẫn đang diễn ra
▪ BF báo rằng SSPBUF vẫn đang đầy ( trong cả hai trường hợp Transmit, Receive )
▪ ACKSTAT: Bít ACK được nhận từ Slave ( =0, chỉ dùng trong Transmit )
▪ ACKDT, ACKEN: dùng để phát bít ACK hay NACK từ Master ( trong chế độ Receive ACKDT =0
là ACK, ACKDT =1 là NACK )
▪ RCEN : tín hiêu báo hiệu quá trình nhân ( chỉ dùng trong Receive: khi RCEN = 1, Master
nhận tín hiệu từ Slave )
▪ PEN, RSEN, SEN: bit khởi tạo quá trình truyền Stop, Restart, Start
+ Để điều khiển tốc độ baud của chế độ, người ta sử dụng thanh ghi SSPADD. I2C làm việc ở 3
chế độ chuẩn ( tất nhiên chỉ tương đối ) : 100Kb, 400Kb, 1Mb. Nếu ta dùng thạch anh 4M, và cần
sử dụng tốc độ 100Kb ta phải nạp giá trị vào thanh ghi SSPADD là: 28H với tốc độ 400Kb ta cần giá
trị là 0AH. Còn để lưu và nhận dữ liệu người ta dùng thanh ghi SSPBUF.
+ Như vây tổng cộng có cả thẩy 5 thanh ghi được dùng đến : SSPSTAT, SSPCON1, SSPCON2
( chọn chế độ và đỉều khiển đường truyền ) SSPADD ( khởi tạo tốc độ Baud ) và SSPBUF dùng để
lưu dữ liệu trong hai quá trình Receive, và Transmister.
GV: Ong Mẫu Dũng – Khoa CNĐT 143
Bài giảng KỸ THUẬT VI XỬ LÝ
void WaitMSSP(void);
void STARTBit(void);
void RESTARTBit(void);
void STOPBit(void);
void ACKBit(void);
void NACKBit(void);
uchar LC01CTRLIN=0xA0 ; // I2C value for CONTROL BYTE when Writing 24c02
uchar LC01CTRLOUT=0xA1 ; // I2C value for CONTROL BYTE when Reading 24c02
uchar LC01ADDR=0x00 ; // Sample value for ADDRESS BYTE
uchar LC01DATA=0x10 ; // Sample data to write to EEPROM
uchar write_iic_return;
uchar read_iic_return;
//*************** main ********************
void main(void)
{
SYNC=0; // uart mode
BRGH=1; // hi-speed mode
SPBRG=25; // 9600 bps with 4Mhz crytal
SPEN=1; // Enable serial port
TRISC7=1; // Rx - Input
TRISC6=0; // Tx - Output
TXEN=1; // Enable Tx
CREN=1; // Enable Continue Receive
GIE=1;
PEIE=1;
RCIE=1;
__delay_ms(1000);
while(1)
{
write_iic_return = write_iic_24c02(LC01ADDR,LC01DATA);
if (write_iic_return == 0)
sendstring_uart("Write IIC pass \r\n");
else if (write_iic_return == 1)
sendstring_uart("Write IIC fail at Write_command \r\n");
else if (write_iic_return == 2)
read_iic_return = read_iic_24c02(LC01ADDR);
LC01ADDR ++;
LC01DATA ++;
if (LC01ADDR == 0xFF)
{
sendstring_uart("Write and Read all data to IIC ...\r\n");
while (1);
}
}
}
void STARTBit(void)
{
SEN = 1 ;
WaitMSSP ();
}
void RESTARTBit(void)
{
RSEN = 1 ;
WaitMSSP ();
}
void STOPBit(void)
{
PEN = 1 ;
WaitMSSP ();
}
void ACKBit(void)
{
ACKDT = 0 ;
ACKEN = 1 ;
WaitMSSP ();
}
void NACKBit(void)
{
ACKDT = 1;
ACKEN = 1;
WaitMSSP ();
}
ddt = SSPBUF;
return ddt;
}
+ 5V Power Supply
+ LCD1602 with 4bit mode interface
+ RS232 interface
+ IC Driver motor interface
+ Single button and single Led interface
9.2. Tiểu luận
….