Vi điều khiển chạy chương trình gồm các lệnh trong bộ nhớ chương trình, địa chỉ của lệnh nằm trong thanh ghi bộ đếm chương trình PC, lúc khởi động PC=0, sau khi thực hiện một lệnh PC=PC+
Trang 11
CHƯƠNG 1: GIỚI THIỆU HỆ THỐNG VI XỬ LÝ VÀ VI ĐIỀU KHIỂN 1.1 Lịch sử phát triển vi xử lý và vi điểu khiển
Vi xử lý (viết tắt là µP hay uP), đôi khi còn được gọi là bộ vi xử lý, là một linh kiện
điện tử được chế tạo từ các tranzito thu nhỏ tích hợp lên trên một vi mạch tích hợp đơn Khối xử lý trung tâm (CPU) là một bộ vi xử lý được nhiều người biết đến nhưng ngoài ra nhiều thành phần khác trong máy tính cũng có bộ vi xử lý riêng của nó, ví dụ trên card màn hình (video card) chúng ta cũng có một bộ vi xử lý Trước khi xuất hiện các bộ vi xử lý, các CPU được xây dựng từ các mạch tích hợp cỡ nhỏ riêng biệt, mỗi mạch tích hợp chỉ chứa khoảng vào chục tranzito Do đó, một CPU có thể là một bảng mạch gồm hàng ngàn hay hàng triệu vi mạch tích hợp Ngày nay, công nghệ tích hợp đã phát triển, một CPU có thể tích hợp lên một hoặc vài vi mạch tích hợp cỡ lớn, mỗi vi mạch tích hợp cỡ lớn chứa hàng ngàn hoặc hàng triệu tranzito Nhờ đó công suất tiêu thụ và giá thành của bộ vi xử lý đã giảm đáng kể
Vi điều khiển (viết tắt là µC hay uC), là một máy tính được tích hợp trên một chíp,
nó thường được sử dụng để điều khiển các thiết bị điện tử Vi điều khiển, thực chất, là một hệ thống bao gồm một vi xử lý có hiệu suất đủ dùng và giá thành thấp (khác với các bộ vi xử lý đa năng dùng trong máy tính) kết hợp với các khối ngoại vi như bộ nhớ, các mô đun vào/ra, các mô đun biến đổi số sang tương tự và tương tự sang số,
Ở máy tính thì các mô đun thường được xây dựng bởi các chíp và mạch ngoài Vi điều khiển thường được dùng để xây dựng các hệ thống nhúng Nó xuất hiện khá nhiều trong các dụng cụ điện tử, thiết bị điện, máy giặt, lò vi sóng, điện thoại, đầu đọc DVD, thiết bị đa phương tiện, dây chuyền tự động, v.v Hầu hết các vi điều khiển ngày nay được xây dựng dựa trên kiến trúc Harvard, kiến trúc này định nghĩa bốn thành phần cần thiết của một hệ thống nhúng Những thành phần này là lõi CPU, bộ nhớ chương trình (thông thường là ROM hoặc bộ nhớ Flash), bộ nhớ dữ liệu (RAM), một hoặc vài bộ định thời và các cổng vào/ra để giao tiếp với các thiết bị ngoại vi và các môi trường bên ngoài - tất cả các khối này được thiết kế trong một vi mạch tích hợp Vi điều khiển khác với các bộ vi xử lý đa năng ở chỗ là nó có thể hoạt động chỉ với vài vi mạch hỗ trợ bên ngoài
Trang 21.2 Một số dòng vi xử lý và vi điều khiển hiện đại
- Thế hệ 1 (1971 - 1973): vi xử lý 4 bit, đại diện là 4004, 4040, 8080 (Intel) hay
IPM-16 (National Semiconductor)
+ Độ dài word thường là 4 bit (có thể lớn hơn)
+ Tốc độ 10 - 60 μs / lệnh với tần số xung nhịp 0.1 - 0.8 MHz
+ Tập lệnh đơn giản và phải cần nhiều vi mạch phụ trợ
- Thế hệ 2 (1974 - 1977): vi xử lý 8 bit, đại diện là 8080, 8085 (Intel) hay Z80
+ Có khả năng làm việc với bộ nhớ ảo
+ Có các cơ chế pipeline, bộ nhớ cache
+ Sử dụng công nghệ HCMOS - Thế hệ 5: vi xử lý 64 bit
1.3 Vi điều khiển Pic
PIC là một họ vi điều khiển RISC được sản xuất bởi công ty Microchip Technology Dòng PIC đầu tiên là PIC1650 được phát triển bởi Microelectronics Division thuộc General Instrument
Trang 33
PIC bắt nguồn là chữ viết tắt của "Programmable Intelligent Computer" (Máy tính khả trình thông minh) là một sản phẩm của hãng General Instrument đặt cho dòng sản phẩm đầu tiên của họ là PIC1650 Lúc này, PIC1650 được dùng để giao tiếp với các thiết bị ngoại vi cho máy chủ 16bit CP1600, vì vậy, người ta cũng gọi PIC với cái tên
"Peripheral Interface Controller" (Bộ điều khiển giao tiếp ngoại vi) CP1600 là một CPU tốt, nhưng lại kém về các hoạt động xuất nhập, và vì vậy PIC 8-bit được phát triển vào khoảng năm 1975 để hỗ trợ hoạt động xuất nhập cho CP1600 PIC sử dụng microcode đơn giản đặt trong ROM, và mặc dù, cụm từ RISC chưa được sử dụng thời bây giờ, nhưng PIC thực sự là một vi điều khiển với kiến trúc RISC, chạy một lệnh một chu kỳ máy (4 chu kỳ của bộ dao động)
Năm 1985 General Instrument bán bộ phận vi điện tử của họ, và chủ sở hữu mới hủy
bỏ hầu hết các dự án - lúc đó đã quá lỗi thời Tuy nhiên PIC được bổ sung EEPROM
để tạo thành 1 bộ điều khiển vào ra khả trình Ngày nay rất nhiều dòng PIC được xuất xưởng với hàng loạt các module ngoại vi tích hợp sẵn (như USART, PWM, ADC ), với bộ nhớ chương trình từ 512 Word đến 32K Word
Hiện nay, tại Việt Nam, đã có một cộng đồng nghiên cứu và phát triển PIC, dsPIC
và PIC32
1.4 Xu hướng ứng dụng của các hệ vi điều khiển
Vi xử lý, chính là chip của các loại máy tính ngày nay, nên hẳn các bạn đã biết rất rõ
nó có những ứng dụng gì Ở đây, tôi chỉ nói đên ứng dụng của vi điều khiển
Vi điều khiển có thể dùng trong thiết kế các loại máy tính nhúng Máy tính nhúng có trong hầu hết các thiết bị tự động, thông minh ngày nay
Chúng ta có thể dùng vi điều khiển để thiết kế bộ điều khiển cho các sản phẩm như:
Trang 4 Điều khiển các thiết bị từ xa (qua điều khiển, qua tiếng vỗ tay, )
Điều tiết hơi ẩm, điều tiết nhiệt độ, điều tiết không khí, gió
Hệ thống vệ sinh thông minh,
o Trong quảng cáo: ƒ
Các loại biển quảng cáo nháy chữ
Quảng cáo ma trận LED (một màu, 3 màu, đa màu)
Điều khiển máy cuốn bạt quảng cáo,
Máy chơi game ƒ
Đầu thu kỹ thuật số, đầu thu set-top-box, ™
o Điều khiển động cơ o Điều khiển số (PID, mờ, )
o Đo lường (đo điện áp, đo dòng điện, áp suất, nhiệt độ, )
o Cân băng tải, cân toa xe, cân ô tô,
o Máy cán thép: điều khiển động cơ máy cán, điều khiển máy quấn thép,
o Làm bộ điều khiển trung tâm cho RoBot o Ổn định tốc độ động cơ
o Đếm sản phẩm của 1 nhà máy, xí nghiệp,…
o Máy vận hành tự động (dạng CNC)
Trang 55
CHƯƠNG 2: CẤU TRÚC VI ĐIỀU KHIỂN PIC 2.1 Cấu trúc bên trong vi điều khiển PIC
Hình 2.1: Cấu trúc chung của vi điều khiển
Cấu tạo của vi điều khiển có thể chia làm 2 phần cơ bản như sau:
- Phần lõi: gồm bộ điều khiển trung tâm có chức năng chạy chương trình (gồm các câu lệnh) đã được nạp vào trong bộ nhớ chương trình (program memory) trước đó
- Phần ngoại vi: gồm có các timer, bộ biến đổi tương tự số ADC và các modun khác Phần lõi của vi điều khiển chịu trách nhiệm chạy chương trình trong vi điều khiển và quản lý toàn bộ các hoạt động khác bao gồm hoạt động của ngoại vi
Trang 6Vi điều khiển chạy chương trình gồm các lệnh trong bộ nhớ chương trình, địa chỉ của lệnh nằm trong thanh ghi bộ đếm chương trình PC, lúc khởi động PC=0, sau khi thực hiện một lệnh PC=PC+1 do đó vi điều khiển chạy lệnh kế tiếp trong chương trình Lệnh
vi điều khiển trong bộ nhớ thực ra đã được mã hóa mỗi lệnh thành 14 bit Quá trình thực hiện một lệnh gồm các bước:
- Lệnh trong bộ nhớ chương trình được đưa vào thanh ghi lệnh (địa chỉ của lệnh nằm trong thanh ghi PC) Sau đó lệnh đưa vào bộ giải mã và điều khiển để giải mã lệnh Trên
cơ sở đó, vi điều khiển biết lệnh đó là lệnh gì, thao tác với dữ liệu nào, phép thao tác v.v.v Trên cơ sở đó, nếu lệnh thao tác với dữ liệu chứa trong các thanh ghi trong RAM,
bộ điều khiển điều khiển đọc dữ liệu trong RAM đưa vào bộ xử lý số học và logic ALU, các phép toán sẽ được thực hiện qua trung gian là thanh ghi làm việc W, quá trình sẽ kết thúc khi kết quả trả dữ liệu về cho chương trình, tiếp theo PC tăng lên 1 đơn vị, vi điều khiển nhảy đến lệnh kế tiếp, tiếp tục 1 chu kì thực hiện lệnh
2.2 Bộ nhớ dữ liệu và các thanh ghi đặc biệt
Bộ nhớ vi điều khiển PIC chia làm 3 phần:
- Bộ nhớ chương trình-FLASH: chứa nội dung của chương trình chạy trong vi điều khiển Bộ đếm chương trình PC (Program counter) sẽ thực hiện các lệnh chứa trong bộ nhớ chương trình này theo thứ tự từ trên xuống
- Bộ nhớ dữ liệu tạm thời- RAM : Gồm 2 phần: các thanh ghi đặc biệt-SFR (Special Function Register) - đây là các thanh ghi chức năng thể hiện hoặc trạng thái, điều khiển của các khối bên trong vi điều khiển PIC (các thanh ghi trạng thái các chân
vi điều khiển như PORTA v.v, Các thanh ghi Status v.vv, TMR0 cho timer v.v ) Các thanh ghi mục đích chung GPR (general purpose register) là nơi lưu các giá trị tạm thời, nơi mà các biến chương trình nằm đây
- Bộ nhớ dữ liệu không mất nội dung- EEPROM cho phép chứa các dữ liệu và dữ liệu này không mất nội dung khi mất điện (phần này xem như thiết bị ngoại vi)
Trang 8- Các thanh ghi mục đích chung GPR (General Purpose Register) dùng để chứa dữ liệu (dùng để đặt biến) từ 20h-7Fh trong bank 0, từ A0h-EFh trong bank 1, từ 120h-16Fh trong bank 2, từ 1A0h-1F0h trong bank 3
Trang 99
Lí do của việc phải chọn bank nhớ giải thích như sau:
Chúng ta xem lại bảng tổng hợp tất cả các lệnh của vi điều khiển PIC và để ý rằng trong các lệnh thao tác với các thanh ghi (các thanh ghi nằm trong bộ nhớ RAM), mỗi thanh ghi được mã hóa bằng 7 bit (tức là đánh số từ 00-7Fh)
Giải thích này cũng tương tự cho các lệnh thao tác trên thanh ghi của bank 1, bank 2 và bank 3
Do đó, nếu khi thực hiện lệnh tiếp theo có thao tác với thanh ghi thuộc bank nhớ khác với bank nhớ đang được tác động hiện tại cần phải có lệnh chọn lại bank nhớ
Địa chỉ gián tiếp
Để hiểu về địa chỉ gián tiếp ta xem địa chỉ trực tiếp như thế nào
Để dễ hiểu ta cho ví dụ:
CLRF 0x30 Câu lệnh này thực hiện việc xóa thanh ghi có địa chỉ 30h trong bộ nhớ Ram Rõ ràng là địa chỉ ở đây là lấy trực tiếp trong RAM, địa chỉ được ghi trực tiếp trong lệnh
Trong một số trường hợp ta dùng đến địa chỉ gián tiếp, cụ thể là: thanh ghi FSR (File Select Register) chứa địa chỉ của thanh ghi trong RAM và thanh ghi INDF sẽ ánh xạ vào thanh ghi RAM có địa chỉ là nội dung của FSR, mọi thao tác trên INDF xem như là thao tác trên thanh ghi của RAM nêu trên
Ví dụ:
Trang 10MOVLW 0x30
MOVWF FSR ; sau lệnh này FSR chứa 0x30 tức là chỉ đến thanh ghi có địa
chỉ 0x30 trong RAM CLRF INDF; xóa INDF tức là xóa nội dụng của thanh ghi địa chỉ 0x30
Hình 2.3: Địa chỉ gián tiếp
Hình vẽ trên cho ta cách mà vi điều khiển xác định thanh ghi nào trong Ram đƣợc thực hiện
Trở lại ví dụ trên:
CLRF 0x30 lệnh này mã hóa nhƣ sau: 00 0001 1 fff ffff
Trong đó fff ffff= mã thanh ghi = 011 0000
Trang 1111
Vi điều khiển dựa vào bit IRP (là bít 7 của thanh ghi STATUS) và bít 7 của FSR để xác định bank nhớ nơi chứa thanh ghi 7 bít còn lại FSR<6-0> xác định chính xác vị trí của thanh ghi đó
Bộ nhớ chương trình là nơi chứa các lệnh đã được mã hóa Quá trình mã hóa đã được
thực hiện trong khâu dịch chương trình trên máy tính ra file hex và nạp chương trình vào
Trang 12Chương trình của vi điều khiển chạy theo thứ tự từ địa chỉ thấp đến địa chỉ cao, địa chỉ lệnh là nội dung của thanh ghi bộ đếm chương trình PC (Program Counter) Đối với pic16f877a, thanh ghi PC có độ dài 13 bit
Nếu dùng 2 bit địa chỉ ta phân biệt được 4 địa chỉ: 00,01,10,11
Nếu dùng 3 bit địa chỉ ta phân biệt được 8 địa chỉ: 000,001,010,011,100,101,110,111 -
Suy ra, PC dùng 13 bit địa chỉ ta phân biệt được 2^13= 2^3 x 2^10=8K địa chỉ
Khi bật nguồn cho vi điều khiển (hay ấn nút reset chương trình), PC được xóa về 0
Sau khi thực hiện xong 1 lệnh nội dung của PC tăng lên 1 đơn vị: PC=PC+1 (trừ 1 số lệnh đặc biệt như gọi chương trình con, goto v.v.v)
Do vi điều khiển sẽ thực hiện lệnh tại địa chỉ chứa trong thanh ghi PC nên theo phân tích
trên có thể nói, vi điều khiển thực hiện lệnh tuần tự từ địa chỉ thấp đến địa chỉ cao
2.3.2 Mã hóa và giải mã lệnh
Như đã nói ở trên, khi chương trình đã nằm trong bộ nhớ (tức là đã được nạp vào), các lệnh đã được mã hóa thành số nhị phân 14 bit chứa trong các thanh ghi của bộ nhớ chương trình
Việc mã hóa này phải tuân theo qui luật của từng loại vi điều khiển mà cụ thể đối với PIC16F877a thì việc mã hóa phải tuân theo qui luật của nhà sản xuất microchip qui định
để trong quá trình thực hiện 1 lệnh, bộ điều khiển bên trong của vi điều khiển PIC có thể giải mã (để hiểu) và thực thi lệnh đó được
Để tiện cho việc theo dõi, ta đưa ra bảng tổng hợp các lệnh vi điều khiển 16f877a như sau:
Trang 1313
Bảng 2.4: Bảng mã hóa các lệnh
Toàn bộ tập lệnh chia làm 3 dạng:
- Lệnh thao tác theo từng byte (Byte-Oriented)
- Lệnh thao tác theo từng bit (Bit-Oriented)
- Lệnh thao tác với hằng số
Trong vi điều khiển pic16f877a không có lệnh thực hiện tương tác giữa 2 thanh ghi, hay giữa thanh ghi và một số (chú ý ở đây, thanh ghi là thanh ghi nằm trong bộ nhớ RAM, ví dụ như PORTA hoặc thanh ghi có địa chỉ 0x21 )
Để giải quyết vấn đề trên, trong vi điều khiển pic 16f877a có thanh ghi đặc biệt làm chức năng trung gian cho các thao tác trên gọi là thanh ghi làm việc W (work register)
Để dễ hiểu:
Giả sử ta có 2 biến a,b (tất nhiên là được khai báo và cấp phát trong bộ nhớ RAM)
Trang 14Ta muốn thực hiện phép toán:
a=a+b Trong PIC không có lệnh thực hiện giữa 2 thanh ghi a và b Để thực hiện lệnh này ta phải qua các bước:
W=0 W= w+b (sau lệnh này w=b) a=w+a (sau lện này a=w+a=b+a) Các lệnh thực hiện chuỗi phép toán trên như sau:
CLRW ADDWF b,0 ADDWF a,1 Phần cụ thể về lệnh sẽ được giới thiệu sau, ta trở lại vấn đề mã hóa lệnh
ADDWF a,0 Câu hỏi đặt ra là khi vi điều khiển đọc mã lệnh trong bộ nhớ gồm các con số nhị phân làm sao nó xác định được đâu là lệnh cộng (ADDWF) đâu là lệnh AND (ANDWF) ? Câu trả lời là trong lúc mã hóa lệnh một số bit đầu tiên của chuỗi 14 bit lệnh dành để
phân biệt các lệnh với nhau hay còn gọi là mã toán tử hay theo tiếng anh là opcode Đối với lệnh theo tác theo byte, vi điều khiển dùng 6 bit để mã hóa opcode
Trang 1515
Để phân biệt khi nào kết quả chứa trong thanh ghi, khi nào thì chứa trong w, vi điều
khiển dành 1 bít hướng d: d=0 kết quả chứa trong thanh ghi w, d=1 kết quả chứa
trong thanh ghi
7 bit còn lại trong để phân biệt lệnh tác động với thanh ghi nào trong bộ nhớ RAM
o Mã lệnh thanh ghi, bit
Các lệnh bao gồm lệnh set 1 bit nào đó của một thanh ghi nào đó lên mức 1 hoặc xóa bít
đó về 0, hoặc kiểm tra 1 bit nào đó của một thanh ghi nào đó bằng 0 hoặc bằng 1 v.v
Từ đây, ta có thể thấy, cần một số bit trong 14 bit của 1 lệnh dành để phân biệt các lệnh với nhau, cụ thể ở đây là 4 bit, cần 3 bít để xác định vị trí bít nào trong thanh ghi bị tác động (vì vị trí bít là 0-7), còn lại 7 bít để xác định thanh ghi nào trong các thanh ghi bộ nhớ RAM bị tác động
Trang 16OPCODE (toán tử) Vị trí bít FILE (địa chỉ thanh ghi)
(opcode-để phân biệt 18 lệnh thao tác byte Nhƣ ta biết với 4 bit chỉ phân biệt đƣợc 2^4
=16 lệnh, làm sao phân biệt đƣợc 18 lệnh
Trang 1717
Thực ra vi điều khiển dùng 14 mã lệnh cho 14 lệnh, 2 mã lệnh còn lại, cụ thể là 00
0001 cùng cho 2 lệnh CLRF (xóa nội dung thanh ghi) CLRW (xóa nội dung thanh ghi W) và mã 00 0000 cùng cho 2 lệnh MOVWF (chuyển nội dung của thanh ghi
w sang thanh ghi F (có địa chỉ cụ thể trong ram) ) và lệnh NOP (lệnh không thực hiện nhiệm vụ gì) Thế làm sao phân biệt được CLRF và CLRW? Đơn giản là khi gặp mã lệnh 00 0001 vi điều khiển kiểm tra tiếp bit hướng d: rõ ràng nếu d=0 (kết quả chứa trong w) thì đây là lệnh CLRW, nếu d=1 (kết quả chứa trong thanh ghi f) thì đây là lệnh CLRF
Khi gặp mã 00 0000, vi điều khiển kiểm tra tiếp bit hướng d, d =1 thì đây là lệnh MOVWF, d=0 là lệnh NOP
- Có 4 lệnh thao tác theo bit 2 bit mã thao tác theo bit là 01, 2 bit còn lại trong OPCODE (xem bên trên) để mã hóa 4 lệnh
- Có 13 lệnh thao tác với hằng số và điều khiển: một số lệnh có 2 bit mã thao tác là
11 hoặc 10 hoặc 00 Kiểm tra các bit còn lại ta thấy đều có cách để vi điều khiển thực hiện phân biệt được các lệnh với nhau
Cấu trúc bộ nhớ và stack:
Trang 18Hình 2.4: Tổ chức bộ nhớ chương trình và Stack
Thanh ghi bộ đếm chương trình:
Tại mỗi thời điểm, vi điều khiển thực hiện 1 lệnh trong bộ nhớ chương trình có địa chỉ cho bởi thanh ghi bộ đếm chương trình PC (Program Counter) gồm 13 bit Nhắc lại là với
độ dài 13 bit, thanh ghi PC có thể phân biệt được tối đa 2^13=8K địa chỉ
Cấu trúc thanh ghi PC gồm 2 phần: phần thấp PCL (Program Counter Low) 8 bit 0-7, phần cao PCH (Program Counter High) 5 bit 8-12
Trong đó các bit trong PCL là các bit có thể đọc ghi được
Trang 1919
Các bit trong PCH<12-8> không thể đọc ghi và được cập nhật thông qua thanh ghi PCLATCH<4-0> Nghĩa là mỗi một lần tác động thay đổi 4 bit PCLATCH sẽ dẫn đến thay đổi nội dung PCH
Nhìn vào tổ chức bộ nhớ chương trình của vi điều khiển ta thấy rằng bộ nhớ chương trình gồm 8 K chia thành 4 bank nhớ, mỗi bank có dung lượng 2 K từ nhớ:
Stack:
Trong khi thực hiện chương trình, sẽ có những đoạn chương trình được thực hiện nhiều lần, người lập trình để đơn giản chương trình sẽ đưa đoạn chương trình đó thành chương trình con, mỗi lần cần thực hiện đoạn chương trình thì đơn giản là gọi chương trình con
đó
Ví dụ chương trình con hay dùng nhất là chương trình delay ví dụ như các chương trình con delay 100ms dưới đây
;************* 1msec Timer Subroutine *****************
t1m movlw d'2' ;(1) Set loop cnt1
movwf cnt1m ;(1) Save loop cnt1
tm1lp1 movlw d'249' ;(1)*2 Set loop cnt2
movwf cnt500u ;(1)*2 Save loop cnt2
Trang 20tm1lp2 nop ;(1)*249*2 Time adjust
nop ;(1)*249*2 Time adjust
decfsz cnt500u,f ;(1)*249*2 cnt500u-1=0 ?
goto tm1lp2 ;(2)*248*2 No, continue
decfsz cnt1m,f ;(1)*2 cnt1m-1=0 ?
goto tm1lp1 ;(2) No Continue
return ;(2) Yes Cnt end
;Total 2501*0.4usec=1msec
;************* 100msec Timer Subroutine ***************
t100m movlw d'100' ;Set loop counter
movwf cnt100m ;Save loop counter
tm2lp call t1m ;1msec subroutine
decfsz cnt100m,f ;cnt100m - 1 = 0 ?
goto tm2lp ;No Continue
return ;Yes Count end
;************* 500msec Timer Subroutine ***************
t500m movlw d'5' ;Set loop counter
movwf cnt500m ;Save loop counter
tm3lp call t100m ;100msec subroutine
decfsz cnt500m,f ;cnt500m - 1 = 0 ?
goto tm3lp ;No Continue
return ;Yes Count end
chương trình chính:
-
Trang 21Qua ví dụ nói trên ta đã hình dung được nhiệm vụ của stack là lưu địa chỉ trở về từ chương trình con, chương trình ngắt (sẽ đề cập sau)
Stack của vi điều khiển pic16f877a có thể quản lý đến 8 mức stack Nếu sử dụng đến mức stack thì 9 thì mức stack 9 này sẽ viết đè lên mức 1
Vector ngắt:
Chưa bàn đến ngắt, nhưng chúng ta hình dung như thế này: mặc định vi điều khiển thực hiện chương trình chính, khi có sự kiện ngắt xảy ra, nếu ngắt đó được cài đặt trước trong
Trang 22chương trình thì vi điều khiển sẽ dừng thực hiện chạy chương trình chính và nhảy vào địa chỉ 0004h, tại đó phần xử lý ngắt này do người lập trình viết chương trình thực hiện
Và địa chỉ 0004h trong bộ nhớ chương trình được gọi là vector ngắt
Trang 24- Khi đặt biến hằng bằng equ ta không thể định nghĩa lại
Ví dụ: viết như thế này là bị lỗi
Count equ 0x20 -
- Count equ 0x23 Nhưng có thể đặt lại giá trị với set
Ví dụ: Viết như thế này không bị lỗi
Count set 0x20 - - Count set 0x23
- Biến hằng đi kèm với set và equ phải được khởi tạo giá trị (gán giá trị) nhưng với variable thì không cần thiết
Ví dụ: Chương trình dịch sẽ báo lỗi:
Count equ Count set
Trang 25Count equ 0x21 ; khai báo hằng số count có giá trị 0x21
Movlw d‟5 ; đưa giá trị 5 vào thanh ghi w: w=5
Movwf count ; chuyển giá trị w cho thanh ghi có địa chỉ bằng count tức thanh ; ghi có địa chỉ 0x21 trong bộ nhớ RAM
Như vậy count đây xem như là một hằng số 0x21
Ví dụ 2:
CBLOCK 0x21
Count1, count2
Endc
Movlw d‟5 ; đưa giá trị 5 vào thanh ghi w: w=5
Movwf count1 ; đưa giá trị w vào thanh ghi count1, tức thanh ghi có địa chỉ ; 0x21 như đã khai báo
Rõ ràng trong trường hợp này count1 là biến, giá trị đưa vào trong lệnh là địa chỉ của count1 không phải là giá trị của count1
- Khi khai báo các biến và hằng này, ta chú ý giá trị khởi tạo Vì thực ra các biến hằng này được sử dụng trong các lệnh như là địa chỉ các thanh ghi nằm trong vùng
Trang 26nhớ RAM Như ta biết địa chỉ dành cho các biến phải ở trong vùng các thanh ghi mục đích chung:
Trong bank 0: 0x20->0x7f
Bank 1: 0xA0->0xEF Bank 2: 0x120->0x16F Bank 3: 0x1A0-0x1EF
Do đó giá trị khởi tạo cho các biến hằng khi khai báo cũng phải nằm trong vùng này
- Khi làm việc với các biến hằng cần phải nhớ địa chỉ của thanh ghi trong lệnh Nếu đang thao tác với thanh ghi thuộc bank nhớ i (i=0-3) chuyển sang lệnh tiếp theo làm việc với một thanh ghi khác thuộc bank nhớ j (j=0-3 và j#i) cần phải có lệnh chuyển bank nhớ như trong chương 2 đã giới thiệu
3.2.2 Chỉ dẫn biên dịch
Cách thức:
ORG địa chỉ 1
Lệnh 1 Lệnh 2 - Lệnh n
ORG địa chỉ 2
Lệnh m Lệnh m+1 -
Miêu tả: chỉ dẫn biên dịch này để điều khiển chương trình dịch MPLAB phân bố các
lệnh nằm sau ORG (ở đây là lệnh 1, lệnh 2, lệnh n) và trước một chỉ dẫn ORG tiếp
theo (ORG địa chỉ 2) vào bộ nhớ chương trình từ địa chỉ bắt đầu là địa chỉ 1
3.2.3 Nhãn
Trang 2727
Nhãn-label: là chuỗi kí tự do người lập trình đánh vào để đánh dấu một chuỗi thao tác lệnh nào đó hoặc 1 chương trình con nào đó Nhãn còn được dùng trong các câu lệnh goto và call:
GOTO nhãn CALL nhãn
- Bắt đầu bằng 2 kí tự gạch dưới (ví dụ: abc là sai)
- Không được bắt đầu bằng các con số 0-9, *, & , giữa các kí tự không có các kí tự đặc biệt
Không được giống các từ đặc biệt của chương trình như ORG, các lệnh v.v
3.3 Khung của một chương trình hợp ngữ
Cấu trúc cơ bản gồm các phần như sau:
Trang 28; DUA FILE LIET KE VAO
#include p16f877a.inc ; chỉ dẫn bao gồm file định nghĩa chip vi điều khiển
; KHAI BAO CAU HINH
CONFIG _HS_OSC & _WDT_OFF &_LVP_OFF
; KHAI BAO BIEN O DAY
; DIA CHI BIEN O VUNG NHO BIEN BANK0
cblock 0x21
vong1, vong2, vong3
endc
variable giatricong=0x25
;CHUONG TRINH VI DIEU KHIEN CHAY TAI DAY
org 0x000; CHI DAN BIEN DICH
; NHAY TOI CHUONG TRINH CHINH
goto main
; chi dan bien dich
; CHUONG TRINH CHINH BAT DAU TU DAY
Trang 30Thực ra chỉ dẫn này ra lệnh cho MPLAB copy toàn bộ nội dung của file
“C:\Program Files\Microchip\MPASM Suite\p16f877a.inc” vào phần đầu của
chương trình vi điều khiển
Nội dung của file này thực ra là định nghĩa các thanh ghi và các cài đặt trong chương trình
Chúng ta xem lệnh trong vi điều khiển như sau:
MOVLW B‟00001111
MOVWF PORTA,1
Vi điều khiển không biết từ “PORTA” là gì cả, nó chỉ biết rằng thanh ghi đặc biệt có địa chỉ 0x05 trong bộ nhớ RAM là nơi lưu trữ trạng thái và điều khiển của các chân trên PORTA
Như vậy để can thiệp đến các chân này người lập trình phải gửi lệnh
MOVLW B‟00001111
MOVWF 0x05,1
Trang 3131
Tuy nhiên, có rất nhiều thanh ghi đặc biệt trong vi điều khiển, người sử dụng không thể nhớ được địa chỉ của nó để mà viết lệnh Để tiện cho người lập trình, chương trình biên dịch MPLAB chuẩn bị sẵn file định nghĩa p16f877a.inc trong đó định nghĩa: PORTA equ h‟00005
Và người lập trình chỉ việc đưa dòng: #include p16f877a.inc
Toàn bộ nội dung của file trên sẽ được đưa vào chương trình và khi đó người dùng viết các dòng lệnh có PORTA thì trình dịch sẽ tự động hiểu là 0x05 (vì PORTA đã định nghĩa bằng 5)
Khi ta dùng vi điều khiển khác ví dụ như pic 18f4431 ta đơn giản thay đổi dòng bao
hàm bằng: #include p18f4431inc
- Phần thứ hai, khai báo cấu hình cho vi điều khiển
CONFIG _HS_OSC & _WDT_OFF &_LVP_OFF
Mục đích của khai báo cấu hình là cài đặt một số chế độ hoạt động của vi điều khiển như chọn nguồn xung dao động, tắt đồng hồ watchdog timer v.v
Các tham số cài đặt cho config xem ở file header
- Phần thứ ba, khai báo biến, sử dụng các phương pháp khai báo như đã giới thiệu
ở các mục trước
- Phần thứ tư, chương trình, kết thúc bởi nhãn END
- Các chương trình con phải đặt trước END, kết thúc chương trình con có lệnh
- Lệnh thao tác với byte
- Lênh thao tác với bit
- Lệnh thao tác với số
Trang 323.4.2 Lệnh thao tác với byte
Dạng lệnh: lệnh f,d
Trừ các lệnh: CLRW ( xóa thanh ghi W)
CLRF f (xóa thanh ghi f) NOP (lệnh không làm gì) Trong đó:
- Lệnh là từ gợi nhớ về phép toán thực hiện Ví dụ: ADDWF là cộng thanh ghi W
- d: chỉ ra kết quả của lệnh chứa ở đâu
o Nếu d=0: kết quả chứa trong w
o Nếu d=1: kết quả chứa trong thanh ghi f
o Mặc định: d=1, kết quả chứa trong thanh ghi f
Ví dụ: ADDWF 0x05,0
W=W+thanh ghi có địa chỉ 0x05 ADDWF 0x05,1
Thanh ghi có địa chỉ 0x05=W+ Thanh ghi có địa chỉ 0x05
3.4.3 Lệnh thao tác với bit
Dạng lệnh: lệnh f,b
Trong đó:
- Lệnh là từ gợi nhớ về phép toán thực hiện
- f: địa chỉ thanh ghi
- b: vị trí của bit 0-7
Ví dụ: BSF 0x23,3
Trang 3333
3.4.4 Lệnh thao tác với số
Dạng lệnh: lệnh số
Trong đó:
- Lệnh là từ gợi nhớ về phép toán thực hiện
- Số là tham số trong phép toán
Chú ý là khi bit =0, lệnh này mất 2 chu kì lệnh, khi bit =1 lệnh này mất 1 chu kì lệnh
3.4.7 Lệnh tăng giảm đồng thời kiểm tra thanh ghi
Có 2 lệnh: DECFSZ, INCFSZ
- Dạng lệnh:
Trang 34DECFSZ địa chỉ thanh ghi,hướng
Lệnh 1
Lệnh 2
Miêu tả: Lệnh này trước hết tự động giảm giá trị của thanh ghi đi 1 đơn vị và sau
đo kiểm tra nếu thanh ghi đó bằng 0 bỏ qua lệnh 1 thực hiện lệnh 2, nếu khác 0 thực hiện lệnh 1 (theo kiểu tuần tự như bình thường)
Chú ý là khi thanhghi =1, lệnh này mất 2 chu kì lệnh, khi thanhghi#1 lệnh này mất 1 chu kì lệnh
- Dạng lệnh:
INCFSZ địa chỉ thanh ghi,hướng
Lệnh 1
Lệnh 2
Miêu tả: Lệnh này trước hết tự động tăng giá trị của thanh ghi đi 1 đơn vị và sau
đo kiểm tra nếu thanh ghi đó bằng 0 bỏ qua lệnh 1 thực hiện lệnh 2, nếu khác 0 thực hiện lệnh 1 (theo kiểu tuần tự như bình thường)
3.4.8 Lệnh nhảy không điều kiện GOTO
Dạng lệnh: GOTO nhãn
Miêu tả: nhảy đến đoạn chương trình bắt đầu bởi nhãn
Để hiểu rõ đoạn chương trình trên ta có ví dụ sau:
Trang 35000D 200F CALL 0xf 34: CALL DELAY
000E 280A GOTO 0xa 35: GOTO START
Cột thứ nhất chứa địa chỉ của lệnh Cột thứ 3 là lệnh thực sự đã được phân giải Ta thấy lệnh nằm ngay sau nhãn là BSF PORTB,1 có địa chỉ là 0x0a trong bộ nhớ chương trình
Vì vậy trong cột 3, ta có lệnh GOTO 0xa
Như vậy dạng lệnh thực sự là GOTO k
Khi gặp lệnh này: PC<10:0>=k; PC<12:11>=PCLATCH<4:3>
Tóm lại có thể giải thích lại như sau:
Khi gặp lệnh: goto nhãn
Trong trường hợp trên là goto start
MPLAB tính ra địa chỉ của lệnh nằm ngay sau nhãn start, giả sử đó là k
Trong trường hợp trên là lệnh BSF PORTB,1 có địa chỉ k=0x0a
MPLAB điều khiển đưa giá trị k vào thanh ghi PC: PC=k
Do đó chương trình vi điều khiển sẽ chạy lệnh BSF PORTB,1
Mã hóa lệnh: 10 1kkk kkkk kkkk
Nhìn vào mã hóa lệnh ta thấy địa chỉ k gồm 11 bit kkk kkkk kkkk
Như vậy thực ra chỉ 11 bit đầu của thanh ghi PC là chứa giá trị k:
PC<10:0>=kkk kkkk kkkk
2 bit cao của thanh ghi PC lấy từ thanh ghi PCLATCH
PC<12:11>=PCLATCH<4:3>
Điều này sẽ dẫn đến một vấn đề!!!
Trang 36Giả sử ta có đoạn chương trình sau:
Như vậy lệnh GOTO UPDATE nằm ở địa chỉ 0x0E
Như vậy khi gặp lệnh này, 2 bit của thanh ghi PCLATCH<4:3>=00
Lệnh nằm sau nhãn UPDATE là MOVLW 0xFF nằm ở địa chỉ 0x800 (do có chỉ dẫn biên dịch ORG 0x800)
Vậy chương trình nhảy đến địa chỉ 0x00!!!!!
Chắc chắn là chương trình sẽ không chạy được đoạn lệnh nằm sau UPDATE
Để chạy đúng, đơn giản là ta phải dùng lệnh cho PCLATCH<4:3>=01
Trang 37và thực hiện lệnh kế tiếp đó
3.4.10 Các toán tử
Các kí hiệu +,-,*, / v.v.v gọi là các toán tử
Chương trình hợp ngữ MPLAB qui định một tập các toán tử như sau:
Trang 38Bảng 3.2: Các toán tử
Qua bảng trên ta dễ dàng hiểu được chức năng của từng toán tử
Ở đây chỉ lưu ý một số toán tử đặc biệt như sau:
- Toán tử $: thường đi kèm với lệnh goto
Goto $ Sau khi thực hiện lệnh này, thanh ghi PC giữ giá trị không đổi: PC=PC
(Thông thường sau khi thực hiện 1 lệnh, PC=PC+1, vi điều khiển thực hiện lệnh tiếp theo)
Goto $-n
Trang 39- Toán tử !: hay được dùng trong câu điều kiện
If(!(a= =b)) nghĩa là nếu a!=b
3.4.11 Chu kì lệnh:
Hình 3.1: Chu kỳ lệnh
Chu kì thực hiện 1 lệnh gồm 4 bước, kí hiệu là Qi, i=1-4:
- Q1: thời gian giải mã lệnh
- Q2: thời gian đọc lệnh
- Q3: thời gian thực thi dữ liệu
- Q4: thời gian viết dữ liệu
Trang 40Mỗi bước tương ứng với 1 chu kì xung của vi điều khiển Xung dao động của vi điều khiển được tạo ra từ mạch dao động bên ngoài như thạch anh, mạch RC hoặc mạch dao động bên trong (Phần cấu hình cho dao động sẽ được đề cập ở mục khác)
Nếu dùng bộ dao động xung thạch anh có tần số f=4MHZ
Chu kì xung =1/tần số xung=1/4MHz
Chu kì lệnh = 4 * chu kì xung= 4/4MHZ= 1us (micro giây)
Hầu như tất cả các lệnh trong 35 lệnh của vi điều khiển PIC16F thực hiện trong 1 chu kì lệnh trừ 1 số lệnh đặc biệt như lệnh CALL, GOTO, RETURN, RETFI,RETLW mất 2 chu
kì lệnh Ngoài ra còn có một số lệnh khi thì thực hiện trong 1 chu kì lệnh khi thì 2
Đó là các lệnh DECFSZ, INCFSZ, BTFSZ, BTFSC (Xem tập lệnh trang 158-datasheet 16f877a)
Ta lấy lệnh DECFSZ để giải thích cho dễ hiểu:
GOTO nhan1 GOTO nhan2
Lệnh đầu tiên DECFSZ giảm thanh ghi bien đi 1 đơn 1: bien=bien-1
Sau đó lệnh này kiểm tra bien:
Nếu bien=0 nhảy qua 1 lệnh, tức là nhảy đến và thực hiện lệnh GOTO nhan2
Nếu bien#0 thì không nhảy tức là thực hiện lệnh GOTO nhan2
Như vậy nếu bien#0 (tức là trước khi gặp lệnh này bien #1)thì vi điều khiển mất một chu
kì lệnh để thực hiện lệnh(để thực hiện thao tác trừ)
Nếu bien=0 (tức là trước khi gặp lệnh này bien=1) thì vi điều khiển mất 2 chu kì lệnh để thực hiện lệnh(1 chu kì lệnh để thao tác trừ + 1 chu kì lệnh để nhảy)
Thời gian thực hiện lệnh INCFSZ, BTFSC,BTFSS cũng tương tự như vậy
3.5 Lập trình tạo trễ, hiển thị led đơn, giao tiếp led 7 đoạn, phím bấm, LCD
3.5.1 Chương trình con tạo thời gian trễ
Trong thực tế viết chương trình điều khiển cho một số thiết bị ta hay tạo một khoảng thời gian trễ