You are on page 1of 31

CHƯƠNG 1: HỆ THỐNG VI XỬ LÝ VÀ VI ĐIỀU KHIỂN

1.1. Kiến trúc bộ vi xử lý


- Vi xử lý - microprocessor (viết tắt là μP hay uP) là một linh kiện điện tử được chế tạo từ các
tranzitor thu nhỏ tích hợp lên trên một vi mạch tích hợp đơn.
- Vi xử lý có thể là một máy tính nhỏ hoặc CPU (Central Processing Unit) được sử dụng để tính
toán, thực hiện phép toán logic, kiểm soát hệ thống và lưu trữ dữ liệu. Vi xử lý sẽ xử lý các dữ liệu
đầu vào/đầu ra thiết bị ngoại vi và đưa ra kết quả trở lại để chúng hoạt động
- Vi xử lý có các dòng 4bit-64bit. Hiện này các dòng vi xử lý thông dụng từ 8 bit trở lên.
- Vi xử lý hoạt động cần có chương trình điều khiển các mạch logic và từ đó vi xử lý xử lý các
dữ liệu cần thiết theo yêu cầu.
1.2. Hệ thống vi xử lý
Khi sử dụng vi xử lý thì phải thiết kế một hệ thống gồm có:Vi xử lý, có bộ nhớ, các ngoại vi.

Hình 1.1: Hệ thống vi xử lý.


Address bus được sử dụng để truyền địa chỉ của bộ nhớ hoặc các thiết bị ngoại vi đến CPU. Độ
rộng của address bus xác định số lượng địa chỉ được hỗ trợ bởi CPU. Ví dụ một đường truyền địa
chỉ 32-bit có thể mã hóa tối đa 2^32 địa chỉ khác nhau.
Data bus được sử dụng để truyền dữ liệu giữa CPU và bộ nhớ hoặc các thiết bị ngoại vi. Độ
rộng của data bus xác định số lượng bit có thể truyền qua từ CPU sang bộ nhớ hoặc thiết bị ngoại vi
trong một chu kỳ hoạt động.
Control bus được sử dụng để điều khiển hoạt động của CPU, bao gồm các tín hiệu như các tín
hiệu đồng hồ, tín hiệu chọn địa chỉ, tín hiệu điều khiển đọc/ghi, v.v.
I/O interface đại diện cho các phần cứng được kết nối với hệ thống, chẳng hạn như card mạng,
card âm thanh, hiển thị, v.v. Các thiết bị này được kết nối với hệ thống thông qua các cổng I/O khác
nhau và giao tiếp với CPU thông qua I/O interface.
Vì vậy, các thành phần này có mối liên hệ chặt chẽ với nhau trong việc truyền và nhận dữ liệu
trong hệ thống. Address bus, Data bus và Control bus hỗ trợ cho việc truyền và nhận dữ liệu giữa
CPU và RAM, ROM hoặc các thiết bị ngoại vi. RAM và ROM lưu trữ dữ liệu và mã hệ thống, trong
khi I/O interface giúp kết nối các thiết bị ngoại vi với hệ thống.
1.3. Bộ nhớ
- Bộ nhớ chính:
+ ROM: Bộ nhớ ROM (read only memory), thường tổ chức chương trình hoặc các dữ liệu
người dùng cố định. ROM không bay hơi được. Nếu nguồn được rút ra và sau đó cắm lại, các dữ
liệu ban đầu sẽ vẫn ở đó. Bộ nhớ ROM được lập trình trong quá trình sản xuất, và người dùng
không thể thay đổi nội dung của nó. Bộ nhớ ROM là chỉ hữu ích nếu có phát triển một chương trình
và muốn tạo ra một vài nghìn bản sao của nó.
+ RAM: Bộ nhớ RAM, bộ nhớ truy cập ngẫu nhiên, là một mục đích chung thường lưu trữ dữ
liệu người dùng trong một chương trình. Bộ nhớ RAM dễ bay hơi trong. nghĩa là nó không thể giữ
lại dữ liệu khi không có. Hầu hết các vi điều khiển có một số lượng bộ nhớ RAM.

Hình 1.2: Cấu trúc RAM 64x4


- Bộ nhớ lưu trữ: Bằng từ, USB, đĩa mềm.
1.4. Một số chuẩn giao tiếp
- Vi điều khiển có thể hoạt động độc lập, tương với các thiết bị ngoại vi như ADC, các chân IO,
các chuẩn giao tiếp I2C, SPI... trong khi vi xử lý chỉ có thể tiếp nhận thông tin, phân tích và điều
khiển qua các bus dữ liệu.
- Vi điều khiển là sự tích hợp của vi xử lý và nhiều các thành phần khác nhau nữa như bộ nhớ,
ngoại vi, bộ định thời,... Đối với vi xử lý, để hoạt động được chúng cần có các bộ nhớ ngoài như
RAM, ổ cứng,.... các bộ định thời như RTC...
1.5. Một số loại vi xử lý, vi điều khiển
- Họ vi điều khiển AMCC (do tập đoàn "Applied Micro Circuits Corporation" sản xuất). Từ
tháng 5 năm 2004, họ vi điều khiển này được phát triển và tung ra thị trường bởi IBM: 403
PowerPC CPU, PPC 403GCX, 405 PowerPC CPU, PPC 405EP, PPC 405GP/CR, PPC 405GPr,
PPC NPe405H/L, 440 PowerPC Book-E CPU, PPC 440GP, PPC 440GX, PPC 440EP/EPx/GRx.
- Họ vi điều khiển Atmel
+ Dòng 8051 (8031, 8051, 8751, 8951, 8032, 8052, 8752, 8952)
+ Dòng Atmel AT91 (Kiến trúc ARM THUMB)
+ Dòng AT90, Tiny & Mega – AVR (Atmel Norway design)
+ Dòng Atmel AT89 (Kiến trúc Intel 8051/MCS51)
+ Dòng MARC4
- Họ vi điều khiển Cypress MicroSystems CY8C2xxxx (PSoC)
- Họ vi điều khiển Freescale Semiconductor. Từ năm 2004, những vi điều khiển này được phát
triển và tung ra thị trường bởi Motorola.
+ Dòng 8-bit: 68HC05 (CPU05), 68HC08 (CPU08), 68HC11 (CPU11)
+ Dòng 16-bit: 68HC12 (CPU12), 68HC16 (CPU16), Freescale DSP56800 (DSPcontroller)
+ Dòng 32-bit: Freescale 683XX (CPU32), MPC500
MPC 860 (PowerQUICC), MPC 8240/8250 (PowerQUICC II), MPC
8540/8555/8560(PowerQUICC III)
- Họ vi điều khiển Fujitsu( F2MC Family (8/16 bit), FR Family (32 bit), FR-V Family (32 bit
RISC).
- Họ vi điều khiển Intel.
- Họ vi điều khiển Microchip (PIC).
- Họ vi điều khiển National Semiconductor (COP8, CR16).
- Họ vi điều khiển STMicroelectronics (ST 62, ST7STM8, STM32 (Cortex-Mx).
- Họ vi điều khiển Philips Semiconductors.
1.6. Ứng dụng của vi xử lý và vi điều khiển
- Xây dựng bộ não trung tâm của các hệ thống tự động.
- Ứng dụng mục đích đặc biệt bao gồm kiểm soát, giao tiếp, thiết bị đo đạc, tự động hóa, thông tin
liên lạc.
- Xây dựng các hệ thống điện tử có tính mở và dễ dàng tiếp cận.
- Vi điều khiển thuộc họ PIC hoặc họ 8051... được dùng trong các ứng dụng như trong các hệ thống
nhúng nhỏ như hệ thống điều khiển tín hiệu giao thông hoặc một loại hệ thống robot.
1.7. Cấu trúc vi điều khiển PIC 16F887
Hình 1.3: Cấu trúc vi điều khiển PIC 16F887.

Hình 1.4: Sơ đồ cấu trúc bên trong của vi điều khiển PIC 16F887.
Vi điều khiển PIC 16F887 được thiết kế với các tính năng và chức năng sau:
- Ổ đĩa bởi nguồn 5V DC và có thể hoạt động ở tần số đồng hồ lên đến 20 MHz.
- Bộ chọn mã 14 bit với 35 lệnh cơ bản và 10 lệnh mở rộng.
- Có bộ nhớ EEPROM program 256 x 14-bit cho phép lưu trữ dữ liệu được giữ lại khi hệ thống
không còn cung cấp nguồn.
- Ứng dụng hỗ trợ nhiều nguồn tín hiệu như A/D Converter, USART/SCI, MSSP (SPI/I2C), CCP
(Capture/Compare/PWM) và 2 bộ Timer.
- Có 3 bộ đếm dòng như Timer0, Timer1 và Timer2 được tích hợp kèm với Prescaler cho phép bóp
giãn tần số đồng hồ và làm chậm CPU.
- Được tích hợp sẵn với các chức năng bảo vệ quá dòng và nhiệt độ cho các ứng dụng có tính đáp
ứng cao.
- Hỗ trợ ngắt nội (Internal Interrupt) và ngắt ngoài (External Interrupt), bao gồm các Trigger cơ bản
như INT, TMR0, CCP1, RB/INT external interrupts.
-Được tích hợp 4 cổng I/O Analog để đo dấu hiệu từ các cảm biến.
Cấu trúc vi điều khiển PIC 16F887 bao gồm các thành phần chính như CPU (Central Processing
Unit), Oscillator, Reset Circuit, Memory và các Peripheral Interface. CPU bao gồm bộ xử lý ALU
(Arithmetic Logic Unit), bộ đếm và bộ điều khiển (Controller). Oscillator là thành phần cung cấp
xung dao động nội hoặc bên ngoài cho CPU. Reset Circuit gồm nhiều mạch reset bảo vệ CPU khỏi
các lỗi hoạt động khác nhau. Memory có chức năng chứa dữ liệu đệm và lưu trữ trạng thái của CPU.
Peripheral Interface có chức năng kết nối với thiết bị ngoại vi và truyền dữ liệu giữa CPU và các
thiết bị ngoại vi, bao gồm các target như EEPROM, Timer, UART/USART, MSSP, v.v.
1.8. Thông số vi điều khiển PIC 16F887

Hình 1.5: Hình ảnh mô phỏng của vi điều khiển PIC 16F887.
- Kiến trúc RISC (Reduced Instruction Set Computing) 8-bit.
- Bộ chọn mã 14 bit (14-bit instruction word).
- Tần số dao động đồng hồ tối đa 20 MHz cho phép xử lý nhanh chóng các tác vụ.
- Bộ nhớ chương trình 8K x 14 bit với khả năng xóa và lập trình lại.
- Bộ nhớ dữ liệu RAM 368 x 8 bit cho phép lưu trữ dữ liệu tạm thời.
- Bộ chuyển đổi Analog/Digital (A/D) 10-bit với 8 kênh vào Analog.
- Các kênh Timer/Counter: Timer0, Timer1, Timer2.
- Các chức năng bổ sung: Capture/Compare/PWM (CCP), USART/SCI, MSSP (SPI/I2C).
- Tích hợp bộ đếm sự kiện để đáp ứng cực nhanh các tín hiệu Input.
- Bộ chuyển đổi A/D bên trong vi điều khiển với khả năng tăng thêm module để xử lý nhiều kênh
hơn.
- Số ngõ vào/ra (I/O): 35 dòng ví dụ như nút nhấn bấm (button) hay đèn ( led)...
- Có mạch bảo vệ quá dòng, nhiệt độ và khả năng kháng nhiễu tốt.
- Công nghệ Flash-based, cho phép lập trình và xóa trực tiếp trong hệ thống.
- Điện áp đầu vào từ 2V-5.5V DC.
- Bộ điều khiển Reset và Oscillator được tích hợp có chức năng bảo vệ CPU khỏi các lỗi hoạt động.

Hình 1.6: Sơ đồ chân của PIC 16F887.


1.9. Tổ chức bộ nhớ và thanh ghi

Hình 1.7: Bộ nhớ của PIC 16F887.


1.9.1. Kiến trúc bộ nhớ
Có 2 loại kiến trúc bộ nhớ cơ bản là kiến trúc Von Neumann và Harvard.
Hình 1.8: Kiến trúc Von Neumann và Harvard.
PIC16F887 được tổ chức phần cứng theo kiến trúc Harvard và sử dụng tập lệnh RISC (Reduced
Instruction Set Computer), với hai bộ nhớ riêng biệt cho chương trình và dữ liệu. Kiến trúc Harvard
cho phép xử lý song song trên hai bộ nhớ, tăng tốc độ xử lý và hiệu suất của vi điều khiển.
Vì bộ nhớ chương trình và bộ nhớ dữ liệu đã được tách riêng biệt, PIC16F887 có khả năng truy
cập vào cả hai bộ nhớ một cách độc lập. Điều này giúp tối ưu hóa tập lệnh trong kiến trúc Harvard,
giảm chi phí xử lý, tăng tốc độ xử lý và giảm tiêu thụ năng lượng.
Một trong những đặc trưng của kiến trúc RISC là tập lệnh đơn giản, rút ngắn độ dài của mã máy
so với kiến trúc CISC (Complex Instruction Set Computer). Điều này giúp tăng tốc độ xử lý và giảm
chi phí vận hành của vi điều khiển PIC16F887. Tập lệnh của PIC16F887 sử dụng độ dài 14-bit, giúp
tối ưu hóa kích thước dòng lệnh và giảm bộ nhớ cần thiết cho lưu trữ tập lệnh của vi điều khiển.
Kiến trúc Von Neumann: với kiến trúc này thì bộ nhớ giao tiếp với CPU thông qua 1 bus dữ liệu
8 bit, bộ nhớ có các ô nhớ chứa dữ liệu 8 bit, bộ nhớ vừa lưu trữ chương trình và dữ liệu.
Ưu điểm: kiến trúc đơn giản.
Khuyết điểm: do chỉ có 1 bus nên tốc độ truy suất chậm, khó thay đổi dung lượng lưu trữ của ô
nhớ
1.9.2. Tổ chức bộ nhớ
Bộ nhớ trong vi điều khiển PIC16F887 được tổ chức thành 3 loại chính bao gồm:
Bộ nhớ chương trình (Program Memory): Đây là nơi lưu trữ các lệnh chương trình mà vi điều
khiển sẽ thực hiện. Trong PIC16F887, bộ nhớ chương trình được tổ chức dưới dạng các block 2KB
(kilobyte), có thể lưu trữ tối đa 8192 lệnh. Nó được lưu trữ trong các thanh ghi có tên là Program
Counter (PC) và Instruction Register (IR).
Bộ nhớ dữ liệu (Data Memory): Đây là nơi lưu trữ các biến, bộ đệm và các thanh ghi trong quá
trình thực thi chương trình. Trong PIC16F887, bộ nhớ dữ liệu được chia thành 4 group và có kích
thước là 368 byte, trong đó:
 Registers File (RAM): Là 128 thanh ghi, được xếp thành 4 group gồm thanh ghi để lưu trữ dữ
liệu, thanh ghi giành cho bộ lựa chọn trang (bank select), và thanh ghi lệnh (register for indirect
addressing). Mỗi thanh ghi có độ rộng 8 bit.
 Banked Register File: Là 16 thanh ghi được phân bổ cho mỗi group (GPR) và mỗi thanh ghi có
độ rộng 8 bit. Dùng để lưu trữ các biến và dữ liệu trung gian.
 Special Function Registers (SFRs): Là 36 thanh ghi đặc biệt, được sử dụng để cấu hình và điều
khiển các chức năng của vi điều khiển.
 Extended RAM (ERAM): Là 80 byte bộ nhớ dùng để lập trình chương trình tùy chỉnh.
Bộ nhớ EEPROM (Electrically Erasable Programmable Read-Only Memory): Đây là bộ nhớ
lưu trữ các giá trị dữ liệu có thể được lưu giữ sau khi chương trình dừng lại hoặc sau khi vi điều
khiển tắt. Bộ nhớ EEPROM có kích thước 256 byte và được sử dụng để lưu trữ các thông số cấu
hình, dữ liệu và các biến có thể được lưu trữ vĩnh viễn.
1.9.3. Bộ nhớ chương trình

Hình 1.9: Sơ đồ bộ nhớchương trình và ngăn xếp.


Bộ nhớ chương trình của PIC16F8xx có dung lượng 8K được chia làm 4 trang bộ nhớ, mỗi
trang 2K.
Thanh ghi bộ đếm chương trình PC (Program Counter) sẽ quản lý địa chỉ của bộ nhớ chương
trình, thanh ghi PC có độ dài 13 bit sẽ quản lý 8192 ô nhớ tương đương với 8K ô nhớ. Mỗi ô nhớ
chương trình lưu 14 bit dữ liệu.
Khi PIC bị reset thì thanh ghi PC có giá trị là 0000H và PIC sẽ bắt đầu thực hiện chương trình
tại địa chỉ 0000H.
Khi có bất kỳ ngắt nào tác động thì PIC sẽ thực hiện chương trình phục vụ ngắt tại địa chỉ
0004H.
Mỗi trang của bộ nhớ chương trình có địa chỉ xác định, việc phân chia theo trang bộ nhớ chỉ có
tác dụng đối với lệnh nhảy và lệnh gọi chương trình con. Khi nơi nhảy đến hoặc khi gọi chương
trình con nằm trong cùng 1 trang thì lệnh sẽ viết ngắn gọn hơn, mã lệnh ít hơn so với trường hợp
nằm khác trang.
Trong các họ vi điều khiển khác thì bộ nhớ ngăn xếp dùng chung với bộ nhớ dữ liệu, ưu điểm là
cấu trúc đơn giản, khuyết điểm là việc dùng chung nếu không biết giới hạn sẽ lấn chiếm lẫn nhau và
làm mất dữ liệu lưu trong bộ nhớ ngăn xếp và chương trình thực thi sai.
Ở vi điều khiển PIC thì nhà thiết kế tách bộ nhớ ngăn xếp độc lập với bộ nhớ dữ liệu và chỉ để
dùng lưu địa chỉ trở về khi thực hiện lệnh gọi chương trình con và khi thực hiện ngắt. Dung lượng
bộ nhớ bộ nhớ ngăn xếp chỉ có 8 ô nhớ từ stack level 1 đến stack level 8 -xem hình 1.9. Do chỉ có 8
ô nhớ nên khi thực hiện các chương trình con lồng vào nhau tối đa là 8 cấp. Do lưu địa chỉ trở về
trong thanh ghi PC, mà thanh ghi PC có chiều dài 13 bit nên mỗi ô nhớ ngăn xếp có số bit là 13.
Khi không sử dụng ngắt thì chương trình có thể viết bắt đầu và liên tục tại địa chỉ 0000H, nhưng
nếu sử dụng ngắt thì nên dùng lệnh nhảy để tránh vùng nhớ bắt đầu tại địa chỉ 0004H - vì vùng nhớ
này dùng để viết chương trình con phục vụ ngắt.
Bộ nhớ chương trình có chức năng lưu trữ chương trình. Chương trình sau khi viết xong trên
máy tính, dịch ra số nhị phân sẽ được nạp vào bộ nhớ chương trình để vi điều khiển thực hiện.
1.9.4. Mã lệnh 14bit
Với các vi điều khiển 8 bit của các hãng khác thì bộ nhớ chương trình tổ chức theo đơn vị là
byte, mỗi ô nhớ lưu trữ dữ liệu 1 byte–xem hình 1.10. Nếu mã lệnh 2 byte (gồm 1 byte mã lệnh và 1
byte dữ liệu hay địa chỉ) thì dùng 2 ô nhớ liên tiếp để lưu và khi CPU đọc mã lệnh để thực hiện lệnh
thì CPU phải thực hiện 2 lần đọc -mỗi lần 1 byte.
Với vi điều khiển PIC thì mỗi ô nhớ của bộ nhớ chương trình có thể lưu trữ dữ liệu nhiều bit
bao gồm cả mã lệnh và dữ liệu –xem hình 1.11. Khi CPU đọc mã lệnh để thực hiện thì CPU chỉ
thực hiện 1 lần đọc cả mã lệnh và dữ liệu.
Vậy với tổ chức bộ nhớ của PIC thì tiết kiệm được 1 chu kỳ đọc dữ liệu vì thế PIC sẽ có tốc độ
thực hiện chương trình nhanh hơn.
Tập lệnh của PIC là tập lệnh rút gọn nên chỉ dùng có 6 bit nhị phân để mã hóa các lệnh, cùng
với dữ liệu xử lý là byte -8 bit nên tổng cộng là 14 bit.
Hình 1.10: Tổ chức bộ nhớ theo byte.

Hình 1.11: Tổ chức bộ nhớ chứa cả mã lệnh và dữ liệu.


1.9.5. Bộ nhớ dữ liệu

Hình 1.12: Bộ nhớ dữ liệu của PIC 16F887.


Bộ nhớ dữ liệu được phân chia thành 4 Bank, mỗi bank có 128byte bao gồm một số thanh ghi
chức năng đặc biệt, còn lại là các ô nhớ thông dụng có chức năng lưu trữ dữ liệu.
Toàn bộ các ô nhớ của bộ nhớ dữ liệu được gọi là File thanh ghi.
Các thanh ghi có chức năng đặc biệtnằm ở vùng địa chỉ thấp, các ô nhớ còn lại không có gì đặc
biệt nằm ở cùng địa chỉ bên trên các thanh ghi chức năng đặc biệt–xem như các ô nhớ RAM dùng
để lưu dữ liệu. Tất cả các bank thanh ghi đềuchứa những thanh ghi đặc biệt -xem hình 1.11.
Theo hình 1.11 thì bộ nhớ dữ liệu được chia làm 4 bank thanh ghi, mỗi bank có 128, tổng cộng
là 512 ô nhớ, nhưng do có 1 số thanh ghi có chức năng đặc biệt ở bank nào cũng có nên làm giảm số
lượng. Ví dụ thanh ghitrạng thái (status) ở 4 bank đều có, thay vì 4 thanh ghi thì chỉ xem là 1, tương
tự cho các thanh ghi khác. Số lượng thực chỉ còn 368 ô nhớ. Có 2 cách truy xuất bộ nhớ dữ liệu:
truy xuất trực tiếp và truy xuất gián tiếp.
Khi truy xuất trực tiếp: thì các lệnh chỉ được phép truy xuất 1 bank, muốn truy xuất các ô nhớ
hay thanh ghi nằm ở bank khác thì phải đổi bank. Có 2 bit chọn bank là RP1 và RP0 nằm trong
thanh ghi trạng thái.
Khi truy xuất gián tiếp: thì các lệnh truy xuất được phép truy xuất 2 bank: bank 0, 1 hoặc bank
2, 3. Khi đang ở bank 0, 1 nếu muốn truy xuất các ô nhớ ở bank 2, 3 thì phải đổi bank. Có 1 bit chọn
bank 0, 1 hoặc bank 2, 3 là IRP nằm trong thanh ghi trạng thái.
1.9.6. Thanh ghi trạng thái
Thanh ghi trạng thái (STATUS register) là một thanh ghi đặc biệt trong vi điều khiển
PIC16F887, được sử dụng để lưu trữ các cờ (flag) trạng thái của vi điều khiển sau mỗi lệnh thực
hiện. Thanh ghi này có kích thước 8 bit và được định nghĩa như sau:

Hình 1.13: Thanh ghi trạng thái.


- Bit 7 (IRP): Chỉ số trang bộ nhớ trung gian (0 hoặc 1) khi sử dụng bộ nhớ dữ liệu trung gian.
- Bit 6-5 RP1:RP0: các bit lựa chọn thanh ghi (dùng địa chỉ trực tiếp)
11 = bank 3 (180h-1FFh)
10 = bank 2 (100h-17Fh)
01 = bank 1 (80h-FFh)
00 = bank 0 (00h-7Fh)
- Bit 4 TO: Time-out bit (Bit thời gian chờ)
- Bit 3 PD: Power-down bit (bit tắt nguồn)
1= sau khi mở nguồn hoặc bằng lệnh CLRWDT
0= thực thi lệnh SLEEP
- Bit 2 Z: Zero bit (bit 0)
1 = khi kết quả bằng 0.
0 = khi kết quả khác 0.
- Bit 1 DC: Digit carry/borrowbit (các lệnh ADDWF, ADDLW, SUBLW, SUBWF) (bit tràn /
mượn)
1 = khi cộng 4 bit thấp bị tràn.
0 = khi cộng 4 bit thấp không bị tràn.
- Bit 0 C: Carry/borrowbit (các lệnh ADDWF, ADDLW, SUBLW, SUBWF)
1 = khi kết quả phép toán có tràn.
0 = khi kết quả phép toán không bị tràn.
Các bit của thanh ghi trạng thái sẽ được xác định qua các phép toán, hoặc các điều kiện trạng
thái cụ thể của vi điều khiển. Các cờ này được sử dụng để kiểm tra kết quả của các phép toán, quản
lý các tín hiệu bên ngoài, hoặc để điều khiển hoạt động của chương trình và của vi điều khiển nói
chung. Các phần mềm lập trình sẽ sử dụng các bit của thanh ghi này để đọc các cờ trạng thái và thực
hiện các quyết định cho phù hợp với hoạt động của chương trình.
1.9.7. Bộ nhớ EEPROM
Bộ nhớ EEPROM (Electrically Erasable Programmable Read - Only Memory) là một loại bộ
nhớ không giống với bộ nhớ RAM hoặc ROM. Bộ nhớ EEPROM có khả năng lưu trữ dữ liệu lâu
dài mà không cần nguồn điện liên tục đến như bộ nhớ RAM, và cũng cho phép người sử dụng ghi
lại dữ liệu mới vào bộ nhớ này nhiều lần.
Vi điều khiển PIC16F887 có một bộ nhớ EEPROM có kích thước 256 byte, được tổ chức thành
64 từ (độ dài của mỗi từ là 4 byte). Bộ nhớ EEPROM có thể được sử dụng để lưu trữ các thông số
cấu hình, hoặc dữ liệu quan trọng mà cần được lưu trữ lâu dài. Trong quá trình thực hiện chương
trình, người lập trình có thể sử dụng lệnh để ghi các giá trị vào bộ nhớ EEPROM, hoặc đọc các giá
trị đã được lưu trữ trước đó trong bộ nhớ EEPROM.
Tuy nhiên, việc sử dụng bộ nhớ EEPROM thường có tốc độ thấp hơn so với bộ nhớ RAM hay
FLASH, và như vậy, không thể được sử dụng để lưu trữ dữ liệu tạm thời hoặc các dữ liệu liên tục
phải được truy cập nhanh chóng như các bộ nhớ khác. Bên cạnh đó, việc ghi dữ liệu vào bộ nhớ
EEPROM cũng đòi hỏi tiêu thụ năng lượng cao hơn so với việc truy cập và ghi dữ liệu vào bộ nhớ
FLASH hoặc RAM.
CHƯƠNG 2: VI ĐIỀU KHIỂN PIC 16F887 NGÔN NGỮ LẬP TRÌNH C
2.1. Giới thiệu
2.1.1. Ngôn ngữ bậc thấp
- Ngôn ngữ máy (machine language): Là các chỉ thị dưới dạng nhị phân, can thiệp trực tiếp vào
trong các mạch điện tử. Chương trình được viết bằng ngôn ngữ máy thì có thể được thực hiện ngay
không cần qua bước trung gian nào. Tuy nhiên chương trình viết bằng ngôn ngữ máy dễ sai sót,
cồng kềnh và khó đọc, khó hiểu vì toàn những con số 0 và 1.
- Hợp ngữ (assembly language): Bao gồm tên các câu lệnh và quy tắc viết các câu lệnh đó. Tên
các câu lệnh bao gồm hai phần: phần mã lệnh (viết tựa tiếng Anh) chỉ phép toán cần thực hiện và
địa chỉ chứa toán hạng của phép toán đó.
- Các ngôn ngữ lập trình bậc thấp thường được chia thành hai loại:
+ Thế hệ thứ nhất (1GL): ngôn ngữ duy nhất mà bộ vi xử lý có thể hiểu.
+ Thế hệ thứ hai (2GL): ngôn ngữ assembly, lập trình viên cần phải hiểu về kiến trúc của bộ vi
xử lý mới có thể thực hiện được.
2.1.2. Ngôn ngữ bậc cao
Ra đời và phát triển nhằm phản ánh cách thức người lập trình nghĩ và làm. Rất gần với ngôn
ngữ con người (Anh ngữ) nhưng chính xác như ngôn ngữ toán học. Cùng với sự phát triển của các
thế hệ máy tính, ngôn ngữ lập trình cấp cao cũng được phát triển rất đa dạng và phong phú, việc lập
trình cho máy tính vì thế mà cũng có nhiều khuynh hướng khác nhau: lập trình cấu trúc, lập trình
hướng đối tượng, lập trình logic, lập trình hàm... Một chương trình viết bằng ngôn ngữ cấp cao được
gọi là chương trình nguồn (source programs). Để máy tính "hiểu" và thực hiện được các lệnh trong
chương trình nguồn thì phải có một chương trình dịch để dịch chuơng trình nguồn (viết bằng ngôn
ngữ cấp cao) thành dạng chương trình có khả năng thực thi. Có thể kể đến các ngôn ngữ như C,
Basic, Pascal, sử dụng trình biên dịch CCS, MikroC, keli C, Arduino...
2.1.3. Đặc điểm của ngôn ngữ C
- C giúp thuận tiện để viết các chương trình lớn với số lỗi giảm tối đa và đơn giản hóa cấu trúc
lập trình.
- Một ngôn ngữ cốt lõi đơn giản với các chức năng quan trọng. Các hàm xử lý có thể được chia
sẻ dưới dạng các bộ thư viện, rút ngắn chương trình.
- Mức thấp của ngôn ngữ cho phép dùng tới bộ nhớ máy tính qua việc sử dụng kiểu dữ liệu con
trỏ.
- Các tham số được đưa vào các hàm bằng giá trị, không bằng địa chỉ. Hàm các con trỏ cho
phép hình thành một nền tảng ban đầu cho tính đóng và tính đa hình.
- Hỗ trợ các bản ghi hay các kiểu dữ liệu kết hợp thông qua cấu trúc struct cho phép các dữ liệu
liên hệ nhau có thể được tập hợp lại và được điều chỉnh như là toàn bộ.
2.2. các thành phần cơ cản của C
2.2.1. Cấu trúc lập trình C cho vi điều khiển
#include: khai báo Bao gồm tất cả các
thư viện sẵn file dùng trong
Ví dụ: chương trình.
#include <File.h> - Nếu dùng
#include “File.c” <file.x> thì chương
trình compile sẽ
tìm trong thư mục
bạn đang viết.
- Nếu dùng “file.x”
thì chương trình sẽ
tìm thêm trong ổ
đĩa c/keilc.
#define: khai báo - Ở đây ta đã định
biến hằng nghĩa chân RD1 là
Ví dụ: #Define swich, sau này ta
swich RD1 chỉ cần viết swich
là chương trình sẽ
hiểu là bit RD1.
Unsigned char x,y; - Gồm các biến sẽ
Long n; dùng trong chương
trình.
Void - Gồm các chương
program_1(void) trình con viết để
{ gọi trong chương
int trình main.
temp=0;//biến cục
bộ
// write code
here
}
Void program_2();
Void main() // Hàm chương tình
Chương trình chính chính
{ - Void main() {}
Khai báo biến - Chương trình sẽ
cụ bộ; chạy ở đây cho nên
Mã chương bắt buộc phải viết
trình chính; hàm này.
While(True) - Các mã lệnh, cấu
{ trúc không lặp lại
//biên cục bộ được đặt ngoài
//gọi hàm vòng While
//xử lý vòng - Các cấu trúc điều
lặp khiển, mã lệnh đọc
} dữ liệu tuần tự
} được đặt trong
While.
- Các hàm, cấu trúc
ngoài while chỉ
được gọi lại khi
cấu hình ngắt
(timer, ngắt
ngoài...)

Bảng 2.1: Cấu trúc lập trình C cho vi điều khiển.


- Các câu lệnh trong hàm chính có thể gọi các hàm con đã khai báo hoặc không.
- Hàm chính và hàm con chỉ có thể gọi các hàm được khai báo phía trên nó.
- Các câu lệnh trong C kết thúc bằng dấu ;
- Khi có lời gọi hàm con nào thì chương trình sẽ nhảy đến thực hiện hàm con đó.
- Sau khi thực hiện xong sẽ nhảy về thực hiện tiếp các hàm hoặc câu lệnh trong chương trình chính.
- Đặt các lời giải thích bằng dấu // hoặc /* ...*/
- Một ưu điểm nổi bật của C là có thể tạo ra các bộ thư viện .
2.2.2. Biến và hằng số
- Biến số dùng để lưu trữ giá trị có thể thay đổi, hằng số lưu trữ giá trị cố định. Mỗi loại chiếm
kích thước bộ nhớ khác nhau.
- Kiểu biến trên CCS:
Ví dụ: ѕigned int8 dem;
=> biến đếm là 8bit, Bit ѕố 7 ѕẽ quу định dấu. nếu là ѕố “1” thì mang dấu “-” còn lại 7 bit nên chỉ
còn 2^7 = 128 giá trị.

Hình 2.1: Các kiểu dữ liệu của phần mềm PIC-C.

* Có 2 kiểu khai báo hằng số: biến toàn cục (global variable) và biến cục bộ (local variable)
- Biến toàn cục:
+ Biến toàn cục được khai báo bên ngoài tất cả các hàm kể cả hàm main.
+ Nó thể được khai báo bất kì nơi nào. Thời gian tồn tại nó tồn tại từ lúc chương trình chạy đến
khi dừng. Các biến toàn cục không được khai báo trùng nhau.
- Biến cục bộ:
+ Biến cục bộ là những biến được khai báo trong hàmvà chỉ có tác dụng trong hàm này, kể cả
các biến trong hàm main chỉ có tác dụng trong hàm main. Điều này tương ứng với các biến có thể
có tên chùng nhau trong các hàm. Các biến này tự động sinh ra khi hàm hoạt động và tự mất khi ra
khỏi hàm.
Ví dụ : Int x; //Biến toàn cục
Void main(){
Int y; //Biến cục bộ
y = 10;
} //ra khỏi main y sẽ bị hủy.
* Khai báo biến
- Khai báo biến thường có 4 dạng:
+ int1 a1; //biến a1 là kiểu dữ liệu 1bit chỉ có hai giá trị là 0 ᴠà 1
+ ѕigned int8 a2; //biến a2 là kiểu ѕố nguуên giá trị 8bit ᴠà có dấu
+ unѕigned int8 a3; // biến a3 là kiểu ѕố nguуên giá trị 8bit không dấu có thể viết thành int8 a3;
+ float a4; //biến a4 là kiểu ѕố thực tức có dấu “,”
Ví dụ: Khai báo các biến
Int1TT; //khai báo biến trạng thái thuộc kiểu dữ liệu bit.
Unsigned char dem; //khai báo biến đếm (dem) thuộc kiểu kí tự không dấu 8 bit.
- Tất cả các kiểu ngoại trừ float, được mặc định là không dấu. Tuy nhiên có thể không dấu hoặc có
dấu bằng cách khai báo Unsigned hoặc Signed .
- SHORT là một kiểu đặc biệt sử dụng rất hiệu quả khi lập trình cho bit thao tác vào ra, mảng của
các bit (INT1) thì RAM được hỗ trợ ngay lập tức.
- Chú ý:
+ Biến phải được khai báo trước khi sử dụng.
+ Để biểu diễn một dãy số hay một bảng dữ liệu, ta có dữ liệu kiểu mảng.
+ Mảng là một tập hợp nhiều phần tử có cùng kiểu giá trị, cùng một tên. Mỗi phần tử được truy
cập bằng chỉ số của phần tử đó. Chỉ số mảng bắt đầu tính từ 0.
+ Khai báo mảng như sau: Loại mảng Vùng chứa Tên mảng [Kích thước]...[Kích thước]
2.2.3. Hàm số học
- Abs (): lấy trị tuyệt đối
- Ceil(): làm tròn theo hướng tăng
- Floor(): làm tròn theo hướng giảm
- Pow(): lũy thừa
- Sqrt(): lấy căn
Nếu muốn tìm hiểu nhiều hơn về chức năng của các hàm số học thì tra chi tiết trong help CCS :
trong tab contents, chọn Built-In-Function
Hình 2.2: Hình ảnh của help trong CCS.
2.2.4. Các toán tử
T Toá Ví
T n tử Chứ dụ
c
năng
1 + Toá
n tử
cộng
2 += Toá x+=y
n tử tươn
cộng g
và đươn
gán g với
x=x+
y
3 &= Toá x&=
n tử y
and tươn
và g
gán đươn
g với
x=x
&y
4 @ Toá
n tử
địa
chỉ
5 & Toá
n tử

6 ^= Toá x^=y
n tử tươn
ex- g
or đươn
và g với
gán. x=x^
y
7 ^ Toá
n tử
ex-
or
8 |= Toá x|=y
n tử tươn
or g
và đươn
gán. g với
x=x|
y.
9 | Toá Ví
n tử dụ or
or nhiề
nhiề u bit
u đại trong
lƣợ 1
ng byte
với với
nhau nhau
thàn
h1
1 -- Giả
0 m
1 /= Toá x/=y
1 n tử tươn
chia g
và đươn
gán g với
x=x/
y
1 / Toá
2 n tử
chia
1 == Toá
3 n tử
dùn
g để
so
sánh
1 > Toá
4 n tử
loén
hơn
1 >= Toá
5 n tử
lớn
hơn
hay
bằng
1 ++ Tăn
6 g
1 * Toá
7 n tử
truy
xuất
gián
tiếp,
đi
trướ
c
con
trỏ
1 != Toá
8 n tử
khô
ng
bằng
1 << Toá x <<
9 = n tử =y
dịch tươn
trái g
và đươn
gán g với
x=x<
<y
2 < Toá
0 n tử
nhỏ
hơn
2 << Toá
1 n tử
dịch
trái
2 <= Toá
2 n tử
nhỏ
hơn
hay
bằng
2 && Toá
3 n tử


2 ! Toá
4 n tử
phủ
định
(not)
2 || Toá
5 n tử
or
2 %= Toá x %=
6 n tử y
chia tươn
lấy g
số đươn
dư g với
và x=x
gán %y
2 % Toá
7 n tử
mod
ule
2 *= Toá x *=
8 n tử y
nhân tươn
và g
gán đươn
g với
x=x*
y
2 * Toá
9 n tử
nhân
3 ~ Toá
0 n tử
bù 1
3 >> Toá x
1 = n tử >>=
dịch y
phải tươn
và g
gán đươn
g với
x=x>
>y
3 >> Toá
2 n tử
dịch
phải
3 -> Toá
3 n từ
con
trỏ
cấu
trúc
3 -= Toá x -=
4 n tử y
trừ tươn
và g
gán đươn
g với
x=x-
y
3 - Toá
5 n tử
trừ
3 Siz Xác
6 eof định
kích
thướ
c
theo
byte
của
toán
tử

Bảng 2.2: Các toán tử phổ biến trong ngôn ngữ C.


a. Toán tử gán (=)
Dùng để gán một giá trị nào đó cho một biến
Ví dụ: A = 5; Gán biến A bằng 5
A = 2+ (B= 5); Có chức năng gán biến b bằng 5 rồi cộng với 2 và gán cho biến A, kết quả
B= 5 và A= 7
b. Toán tử số học(+, -, *, /, %)
Có 5 toán tử để thực hiện các phép toán cộng, trừ, nhân, chia và chia lấy phần dư.
Ví dụ: A = 24; B = A % 5;
Gán A bằng 24, B gán số dư của A chia cho 5, kết quả B bằng 4
c. Toán tử gán phức hợp (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=)
Tổng quát cho toán tử gán phức hợp: biến += giá_trị tương đương với biến = biến + giá_trị.
Ví dụ:
A+=5; tương đương với A = A +5;
A /= 5;tương đương A = A / 5;
B*= X + 1;tương đương B = B * (X+1);
d. Toán tử tăng và giảm(++, --)
Tổng quát cho toán tử gán phức hợp: biến += giá_trị tương đương với biến = biến + giá_trị
Ví dụ:
A++; tương đương với A = A +1 hay A+=1;
B = 3; gán B bằng 3
A=++B; kết quả A bằng 4, B bằng 4
B = 3; gán B bằng 3
A=B++; kếtquả A bằng B và bằng 3, B tăng lên 1 bằng 4
Sự khác nhau là “++” đặt trước thì tính trước rồi mới gán, đặt sau thì gán trước rồi mới tính.
e. Toán tử quan hệ(==,!=, > , <, >=, <=)
- Các toán tử quan hệ dùng để so sánh các biểu thức, kết quả so sánh là đúng hoặc sai.
- Các toán tử trên tương ứng là bằng, khác, lớn hơn, nhỏ hơn, lớn hơn hay bằng, nhỏ hơn hay
bằng.
Ví dụ: if (X<100) X+=1;
Lệnh trên kiểm tra nếu X còn nhỏ hơn 100 thì tăng X lên 1.
f. Toán tử logic(!, && ,||)
Các toán tử trên tương đương là NOT, AND và OR.
Ví dụ: !true sẽ cho kết quả là false
((5==5) && (6>4)) and 2 điều kiện lại với nhau và kết quả là true.
Phân biệt toán tử & với &&, | với ||:
+ Toán tử &, |: toán tử logic theo bit.
+ Toán tử &&, ||: toán tử trả về kết quả True hoặc False.
g. Toán tử xử lý bit (&, |,^, ~, <<, >>)
Các toán tử xử lý bit với bit, các toán tử trên tương đương là AND, OR, XOR, NOT, SHL (dịch
trái), SHR (dịch phải).
Ví dụ 1:
A=0x77; //gán A =0111 0111B
B=0XC9; //gán B =11001001B
X = A & B; // X bằng A and với B, kết quả X = 0100 0001B = 0X41
Y = A | B; // Y bằng A or với B, kết quả Y = 1111 1111B = 0XFF
Z = A ^ B;// Z bằng A xor với B, kết quả Z = 1011 1110B = 0XBE
W = ~A;// W bằng not A, kết quả W= 10001000B = 0X88
Ví dụ 2:
A=0x01; //gán A =0000 0001B
A= (A<<1); //dịch A sang trái 1 bit, kết quả A= 00000010B
A= (A<<1); //dịch A sang trái 1 bit, kết quả A= 00000100B
Khi dịch trái thì bit bên trái mất, bit 0 thêm vào bên phải.
h. Toán tử lấy kích thước chuỗi theo bye ()
Ví dụ: A = sizeof (charac); kết quả là A sẽ chứa số byte của chuỗi charac.
k. Bài tập về hàm và toán tử
Bài tập 1:
Viết câu lệnh dưới dạng ngôn ngữ C mô tả:
Khai báo biến x và biên y dưới dạng số thực và:
y = | x3 + 4.(x-3)|
Giải:
float x = 0, y = 0;
y = Abs (pow (x, 3) + 4 * (x-3));
Bài tập 2: Viết câu lệnh dưới dạng ngôn ngữ C mô tả: z2
Khai báo biến x, y, z kiểu số nguyên dương 8 bit
y−1
y = √x -
Z∗Z +1

Giải:
Int8 x = 0, y = 0, z = 0;
y = sqrt (x) - (y -1) / (pow (z, 2) + 1);
2.2.5. Các lệnh C cơ bản
a. Cấu trúc điều kiện If:
- Cấu trúc: if(biểu thức điều kiện)
{
Lệnh hoặc khối lệnh;
}
- Ý nghĩa: Nếu biểu thức điều kiện cho kết quả đúng thì thực hiện lệnh hoặc khối lệnh.
Ví dụ:
if (x == 100) y=50; // nếu x==100 thì gán y=50
if (swich == 1) // nếu swich tác động
{
led_on(); // bật led
motor_on(); // gọi hàm motor_on.
}
b. Cấu Trúc Điều Kiện If và else:
- Cấu trúc: if (biểu thức điều kiện)
{
< Lệnh hoặc khối lệnh1>;
}
Else
{
< Lệnh hoặc khối lệnh2>;
}
- Ý nghĩa: Nếu biểu thức điều kiện cho kết quả đúng thì thực hiện lệnh hoặc khối lệnh1, ngược lại sẽ
thực hiện lệnh hoặc khối lệnh2.
- Chức năng: kiểm tra điều kiện nếu thỏa thì làm.
Ví dụ:
if (x == 100) y=50;
else y=100; //nếu x==100 thì gán y=50, nếu x!=100 gán y=100;
c. Cấu trúc While:
- Cấu trúc: while (bieu_thuc)
{
<lệnh hoặc khối lệnh>;
}
- Ý nghĩa:
Bước 1: Kiểm tra giá trị bieu_thuc
Bước 2: Nếu bieu_thuc cho giá trị đúng: thực hiện <lện hoặc khối lệnh> và quay về bước 1.
Nếu bieu_thuc cho giá trị sai: thoát khỏi vòng lặp
- Chức năng: lặp lại một thao tác với một số lần nhất định hoặc khi còn thỏa 1 điều kiện nào đó.
Ví dụ: while(x> 0)
{x=x-1;}
d. Cấu Trúc Do...While:
- Cấu trúc: Do
{
<Lệnh hoặc khối lệnh>;
}
while (bieu_thuc)
- Ý nghĩa: Bước 1: thực hiện <Lệnh hoặc khối lệnh>
Bước 2: Kiểm tra giá trị bieu_thuc
Nếu bieu_thuc cho giá trị đúng: quay về bước 1.
Nếu bieu_thuc sai: thoát khỏi vòng lặp
- Chức năng: làm các lệnh trong dấu ngoặc và thoát nếu điều kiện theo sau lệnh while không đúng.
Ví dụ: Do
{x=x+10;}
while(x <100)
Thực hiện lệnh x bằng x cộng với10, làm cho đến khi x nhỏ hơn 100
e. Cấu Trúc Vòng Lặp For:
- Cấu trúc: for (giá_trị_bắt_đầu; điều_kiện_kết_thúc; tăng_giá_trị )
{
Lệnh 1;
Lệnh 2;
...
}
- Chức năng: làm các lệnh trong dấu ngoặc một số lần nhất định.
Ví dụ: For (int n = 0; n <100; n++)
{x=x+10;}
Vòng lặp thực hiện với biến n bằng 0 cho đến khi n bằng 100 thì ngừng.
f. Lệnh Break:
Sử dụng break có thể thoát khỏi vòng lặp ngay cả khi điều kiện để nó kết thúc chưa được thoả
mãn. Lệnh này có thể được dùng để kết thúc một vòng lặp không xác định hay buộc nó phải kết
thúc giữa chừng thay vì kết thúc một cách bình thường.
g. Lệnh Continue:
Làm cho chương trình thực hiện tiếpvòng lặp mới, bỏ qua các câu lệnh khác nằm sau lệnh
continue này.Chỉ được dùng trong các vòng lặp.
i. Lệnh Go:
Lệnh này cho phép nhảy vô điều kiện tới bất kì điểm nào trong chương trình. Nói chung bạn
nên tránh dùng nó trong chương trình C++. Tuy nhiên chúng ta vẫn có một ví dụ dùng lệnh goto để
đếm ngược.
h. Lệnh Swich...Case:
- Cấu trúc: switch (biểu thức)
{
Case constant1: Lệnh a1;
Lệnh a2;
Break;
Case constant2: Lệnh b1;
Lệnh b2;
Break;
Default: Lệnh c1;
Lệnh c2;
Break;
}
- Chức năng: thực hiện 1 công việc tùy thuộc vào hàm.
2.2.6. Một số hình khối trong thuật toán

Hình 2.3: một số hình khối trong thuật toán.


2.3. Trình biên dịch CCS
Trình biên dịch PIC-C dùng để biên dịch tập tin mã nguồn C cho vi điều khiển PIC với nhiều
chủng loại khác nhau, để lập trình C có thể sử dụng phần mềm biên dịch PIC-C, cách cài đặt, lập
trình, biên dịch.
Khi lập trình cho vi điều khiển PIC dùng PIC-C thì các thành phần cơ bản cũng giống nh ư các
loại vi điều khiển khác, sự khác biệt chủ yếu ở phần cứng của từng vi điều khiển. Các lệnh liên quan
đến phần cứng được trình bày theo
phần cứng đó, khi khảo sát port thì có các lệnh PIC-C liên quan đến port, khi khảo sát timer/counter
thì có các lệnh PIC-C liên quan đến timer/counter.
Khi dùng phần mềm PIC-C lập trình cho vi điều khiển PIC16F887 thì phải khai báo thư viện
<PIC16F887.h>. Trong file này đã định nghĩa tên các thành phần của vi điều khiển, nếu các tên
trong file này không có thì có thể định nghĩa thêm, trong phần mềm PIC-C có rất nhiều thư viện hổ
trợ cho các ứng dụng giúp viết chương trình gọn hơn.
* Cách tạo dự án
Vào New >> New Project>> “Nhập đường dẫn” >> “Nhập tên” >> Save
Hình 2.4: mô tả cách tạo dự án.
Family -> Pic16
Device -> PIC16F887

Hình 2.5: mô tả cách cài đặt PIC 16F887 trên CCS.


Giao diện lập trình cho PIC của phần mềm CCS
(1): Check lỗi và biên dịch tạo file HEX
(2): Chọn chủng loại PIC
(3): Khu vực lập trình
(4): Khu vực theo dõi kết quả biên dịch
Hình 2.6: mô tả giao diện lập trình cho PIC của phần mềm CCS.

You might also like