Download as pdf or txt
Download as pdf or txt
You are on page 1of 68

TRƯỜNG ĐẠI HỌC KỸ THUẬT - CÔNG NGHỆ CẦN THƠ

KHOA KỸ THUẬT CƠ KHÍ

TÀI LIỆU THỰC HÀNH


VI ĐIỀU KHIỂN PIC16F877A

PIC 16F877A

Cần Thơ, 2023


Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Phần 1: GIỚI THIỆU CHUNG


Mục tiêu:
- Giới thiệu các phần mềm lập trình MPLAB IDE.
- Giới các phần mềm nạp chương trình Pickit2/Pickit3.
- Giới thiệu phần mềm mô phỏng Proteus.
- Giới thiệu board BOOK1.
- Tạo một project trên phần mềm MPLAB IDE.
- Dịch và nạp một chương trình thực hiện mô phỏng và trên phần cứng board BOOK1.
Yêu cầu:
- Sinh viên thực hiện tạo một project bằng phần mềm MPLAB.
1.1 MPLAB IDE, Pickit2/Pickit3, Proteus và BOOK1
MPLAB IDE (Integrated Development Environment) cung cấp cho người dùng một
chương trình để phát triển các ứng dụng cho vi điều khiển Microchip nhúng. Thông qua môi
trường phát triển, người dùng có thể viết mã cho hệ thống nhúng. Họ cũng có thể chỉnh sửa
và gỡ lỗi mã, để đảm bảo rằng các ứng dụng sẽ được tích hợp vào vi điều khiển sẽ thực thi
mà không bị lỗi. Về cơ bản, người dùng được cung cấp với công cụ mà sẽ cho phép họ thiết
kế các mạch vi điều khiển, dựa trên vi điều khiển cụ thể sẽ được sử dụng bởi các nhà phát
triển. Khi mạch đã được tạo ra, sau đó người dùng có thể tiếp tục phát triển các chương trình
cơ sở, đó là chương trình sẽ kiểm soát như thế nào phần cứng sẽ thực hiện các ứng dụng tích
hợp. IDE cũng cung cấp một nhà lắp ráp mã và trình biên dịch, có thể chuyển đổi các script
vào mã truy cập dễ nhận biết bởi phần cứng. Khi các mã đã được thử nghiệm và sửa lỗi, nó
có thể được tích hợp vào vi điều khiển. MPLAB IDE là cross-platform, có nghĩa là nó có thể
thực hiện trên Windows, Mac OS X và các hệ thống Linux.

PICKit Programmer/ Debugger là một công cụ phát triển giá rẻ nhưng tính năng và độ ổn
định cao, dễ dàng để sử dụng để nạp và gỡ lỗi PIC Microcontrollers Flash. Ngoài ra còn có
thể sử dụng như một thiết bị đầu cuối truyền dữ liệu với PC qua chức năng UART Tool và
Logic Tool Analyzer. sử dụng software PICKit 2/3 hoặc MPLAB IDE.

Phần mềm Proteus là một phần mềm thiết kế mạch in được phát minh bởi Labcenter
Electronics. Nó được sử dụng để thiết kế các mạch khác nhau trên PCB (bo mạch in) và mô
phỏng các mạch khác nhau. Việc sử dụng proteus cho bất kỳ dự án mạch điện tử nào làm cho
dự án đó tiết kiệm chi phí và ít sai sót hơn do cấu trúc sơ đồ trên proteus. Năm 1988, phiên
bản Proteus đầu tiên được gọi là PCB-B được tạo ra bởi John Jameson, chủ tịch của công ty.

1
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

BOOK1 không phải là một cuốn sách, mà BOOK1 là một bo mạch phát triển giúp người
mới học PIC làm quen với các tính năng cũng như các công cụ làm việc với PIC. BOOK1 là
một dự án nằm trong chương trình tài trợ cho các trường đại học, và phổ biến PIC cho sinh
viên kỹ thuật. Khác với cách xây dựng các bài giảng trước đây về vi điều khiển, người ta cố
gắng trang bị các ngoại vi phổ biến càng nhiều càng tốt, nhưng xem ra, các ngoại vi này chỉ
đều là các chức năng I/O thông thường như: LED, nút bấm, LED ma trận, LED 7 đoạn, màn
hình LCD segment, ADC ngoài, các thanh ghi dịch,… Chúng tôi lại nhận thấy một cách nhìn
khác khi làm việc với vi điều khiển, đó là vi điều khiển, trên cơ bản có thể thực hiện được 3
nhóm nhiệm vụ: Điều khiển, Giao tiếp và Xử lý. Bên cạnh đó, ngày nay, với hướng đi SoC
(System on Chip), người ta càng tích hợp nhiều hơn các tính năng cho vi điều khiển, và cũng
không nằm ngoài 3 nhóm nhiệm vụ trên. Chính vì thế, chúng tôi xây dựng một mô hình bài
giảng và sản phẩm BOOK1 nhằm tập trung làm rõ và chứng minh năng lực của 3 nhóm nhiệm
vụ này trong vi điều khiển, đồng thời khai thác một cách tối đa các tính năng được tích hợp
sẵn trong vi điều khiển PIC16F877A.

Hình 1. Mạch thực hành BOOK1.

Trong phần thực hành này, chúng ta sẽ thực hiện các bài tập sử dụng phần mềm MPLAB
để lập trình, gỡ lỗi và nạp chương trình vào PIC microcontrollers bằng phần mềm Pickit2/3.

2
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

1.2 TẠO PROJECT TRÊN MÔI TRƯỜNG MPLAB IDE


Double Click vào biểu tượng MPLAB trên Desktop hoặc theo cách sau: Start >> All
Programs >> Microchip >> MPLAB IDE v6.15 >> MPLAB IDE.
Từ thanh Menu, click chọn tab File >> New Project Wirazd.

Cửa sổ New Project hiện lên và bạn chọn Microchip Embedded >> Standalone Project
>> Next.

Chọn PIC cần sử dụng và tool để Debug >> Next.

3
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Chọn Compiler Tool XC8 >> Next.

Đặt tên project và chọn folder để lưu project >> Next.

4
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Sau đó cửa số lệnh hiện lên project mà bạn đã tạo chứa các nguồn folder như sau:

Một project đơn giản nhất phải gồm có 2 thành phần Source files và Hearder Files. Thư
mục Source files chứa file text *.asm hoặc file *.c chứa code lập trình. Thư mục Hearder Files
chứa file *.h hoặc *.INC: file có sẵn của microchip. User khai báo dùng loại chip gì >> add
vào thư mục này.
Bắt đầu tạo file main.c từ Source files để lập trình cho PIC thực thi chương trình.

>>>

Đặt tên file và chọn vị trí lưu file (default).

5
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

1.3 NẠP FILE .hex CHO VI ĐIỀU KHIỂN PIC


Sau khi viết xong chương trình bạn mong muốn vi điều khiển thực hiện. Tiến hành tạo
gỡ lỗi và tạo file .hex để nạp vào vi điều khiển.
Ví dụ 1: nạp chương trình sau đây
/*
* File: led_main.c
* Author: Thethinh
*
* Created on September 6, 2023, 1:46 PM
*/
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 20000000
#include <xc.h>
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming
Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code
protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off;
all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
void GPIO_init (void);
//void Anode (void);
void Cathode (void);
void main (void)
{

6
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

GPIO_init();
while(1)
{
__delay_ms(100);
// Anode();
Cathode();
__delay_ms(100);
}
}
void GPIO_init(void)
{
TRISBbits.TRISB0 = 0; // RB0 LÀ OUTPUT
TRISBbits.TRISB7 = 0; // RB7 LÀ OUTPUT
PORTBbits.RB0 = 1; // ON LED RB0
PORTBbits.RB7 = 0; // OFF LED RB7
}
/*
void Anode (void)
{
PORTBbits.RB0 = 0;
__delay_ms(500);
PORTBbits.RB0 = 1;
}
*/
void Cathode (void)
{
PORTBbits.RB7 = 1;
__delay_ms(500);
PORTBbits.RB7 = 0;}

Chọn Production >> Clean and Build Project.

Sau khi trình biên dịch phát hiện không có lỗi và build project thành công. Dưới cửa sổ
thực thi sẽ hiển thị như sau:

7
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Vị trí file .hex được tạo

1.3.1 Nạp vào phần mềm mô phỏng Proteus


Double Click vào biểu tượng Proteus trên Desktop.
Tạo tên project và chọn vị trí lưu bằng click vào browse >> Next.

Sau đó cửa sổ hiện thị chọn schematic chọn Default >>Next.

8
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Chọn PCB layout là Do not create a PCB layout >> Next.

Chọn Create Firmware Project cho mạch được thiết kế cần mô phỏng. Khi sử dụng phần
mềm trình biện dịch nào cho file .hex chúng ta cần chọn firmware tương ứng. Ở đây sử dụng
MPLAB XC 8 compiler >> Next.

Sau đó cửa sổ lệnh sẽ xuất hiện như sau. Proteus cho phép viết chương trình cho vi điều
khiển trực tiếp trên phần mềm để mô phỏng. Chúng ta sẽ bỏ qua phần này chỉ quan tâm đến
cách ADD file .hex để mô phỏng.
Đây là giao diện khi đã thiết kế các linh kiện ngoại vi như led, bộ dao động thạch anh
20Mhz, nút nhấn.

9
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Sai

Click vào PIC16F877A sau đó nhấn chuột phải sẽ hiển thị cửa sổ để trỏ thư mục chứa file
.hex vào chương trình mô phỏng.

Edit vị trí ở Program File chỉ dẫn đến file .hex >> click OK.
Có thể copy đường dẫn được hiển thị sau khi biên dịch ở phần mềm MPLAB như sau:

Run chương trình chạy mô phỏng.

10
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Chạy chương trình

1.3.2 Nạp vào vi điều khiển thông qua Pickit3


Bộ nạp Pickit3 cho vi điều khiển thuộc hãng Microchip.

Sơ đồ đấu nối dây giữa Pickit3 và vi điều khiển PIC 16F877A để nạp chương trình.

Nguồn: https://linhkienthanhcong.com/mach-nap-pickit3-kem-giac-icd2

11
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Khi mới sử dụng lần đầu bạn cần nạp firmware, làm theo các bước sau để nạp firmware.

Tải file .hex để nạp vào chương trình bằng Import Hex >> Click vào Write để nạp chương
trình.

1.4 BÀI TẬP


Bài 1: Thực hiện tạo một project để lập trình vi điều khiển PIC16F877A được đặt tên là
tên của mỗi sinh viên thực hiện.
Bài 2: Vẽ lại sơ đồ điều khiển LED trong Proteus ở hình trên và nạp chương trình ở ví dụ
1 vào PIC để chạy mô phỏng.

12
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Phần 2: KHẢO SÁT CỔNG XUẤT NHẬP (I/O)


Mục tiêu:
- Khảo sát các hoạt động của nút nhấn, LED.
- Khảo sát các thanh điều khiển cổng xuất nhập.
- Tính toán thời gian thực thi lệnh, viết chương trình con làm nhiệm vụ delay.
- Viết chương trình đọc giá trị của tổ hợp nút nhấn và điều khiển giá trị hiển thị led.
- Viết chương trình hiển thị LED 7 đoạn đếm từ 0 –> 99 và 99 -> 0.
Yêu cầu:
- Viết chương trình xuất dữ liệu ra 4 LED ở chân RB0 đến RB3 đếm từ 0 -> 15 -> 0.
Thời gian giữa các lần đếm lên 1 đơn vị là 1s.
- Nhập dữ liệu từ nút nhấn R4. Khi nút RA4 được nhấn thì LED đơn RB0 khi không
nhấn RA4 thì LED đơn RB0 tắt.
- Viết chương trình hiện thị LED 7 đoạn đếm ngược từ 0 -> 99 và 99 -> 0.
2.1 KIẾN THỨC LIÊN QUAN
2.1.1 Các thanh ghi điều khiển cổng xuất nhập
Mỗi Port có hai thanh ghi điều khiển hoạt động chính:
- Các bit trong thanh ghi TRIS: thiết lập chân tương ứng là ngõ vào (logic 1) và ngõ ra
(logic 0).
- Các bit trong thanh ghi PORT: đọc mức logic từ chân tương ứng với logic 0 là mức
thấp và logic 1 là mức cao.
2.1.2 Kết nối mạch mô phỏng trên Proteus
a. Output LED
Có hai sơ đồ nối mạch cho ngõ ra LED là Anode và Cathode.
- Common Anode: nối chân anode của led vào nguồn dương (+). Đèn sẽ sáng khi trạng
thái ở cathode là mức thấp.
- Common Cathode: nối chân cathode của led vào nguồn âm (-, GND). Đèn sẽ sáng khi
trạng thái ở Andoe là mức cao.

13
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Theo yêu cầu sơ đồ hiển thị LED có kết nối như sau:

Các chân RB0->RB3 cần được thiết lập là ngõ ra.


b. Kết nối nút nhấn
Có hai dạng kết nối nút nhấn với vi điều khiển: Pull –up resistor và Pull – down resistor.
- Pull – up resistor: thường sử dụng để đặt trạng thái của chân digital là cao cũng như là
để mức logic là cao (5V).
- Pull – down resistor: thì ngược lại với pull – up resistor nghĩa là đặt trạng thái của chân
digital là thấp tương ứng với mức logic là thấp (0V).

14
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Theo yêu cầu nút nhấn có kết nối như sau:

Nút RESET dùng để reset vi điều khiển.


Nút nhấn RA4, RB0 khi được nhấn sẽ làm cho chân tương ứng ở mức logic 0. Cần thiết
lập các chân RA4, RB0 là ngõ vào.
Hiện tượng rung phím:

Khi phím được nhấn, do tác động của hiện tượng rung cơ học, tín hiệu điện tại ngõ ra bị
chuyển trạng thái giữa logic 0 và logic 1. Khi phím được thả, hiện tượng rung cũng xảy ra
tương tự.

c. LED 7 đoạn
Led 7 đoạn gồm 7 đoạn được đánh dấu: a, b, c, d, e, f, g và một ddierm dp được kí tự là
h. Led 7 đoạn có hai loại là Common Anode và Common Cathode, tương ứng các LED nối
chung Anode hay nối chung Cathode.

15
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

2.2 THỰC HIỆN CÁC YÊU CẦU


2.2.1 Các bước thực hiện yêu cầu 1
Bước 1: Tạo project mới giống như hướng dẫn ở Phần 1 lấy tên project là Led_don, tạo file
led_on.c và chọn chip 16F877A trong MPLAB. Ta được hình sau:

Bước 2: Khai báo các cấu hình cho PIC 16F877A. Click vào Window >> trỏ chuột vào Target
Memmory >> chọn Configuration Bits >> Tắt và mở cấu hình các chức năng cần thiết.

16
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Tiếp theo click vào “Generate Source Code to Output” và copy các đoạn mã cấu hình
vào chương trình chính.

Bước 3: Khai báo các thanh ghi của PORTB để thực hiện yêu cầu ngõ ra.
Bước 4: Sử dụng hàm delay có sẵn để làm chương trình delay 1s.
Bước 5: Viết chương trình chính thực hiện yêu cầu.
CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 1:
/*
* File: led_on.c
* Author: Thethinh
*/
// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = OFF

17
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

#pragma config PWRTE = OFF


#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
// Khai báo thư viện
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include "config_uart.h"
// Định nghĩa và khai báo các biến và hàm
#define _XTAL_FREQ 20000000
void set_GPIO(void);
unsigned char count = 0;
unsigned int i,j = 1;
unsigned char status = 0;
const unsigned char LED7Seg[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82,0xF8, 0x80, 0x90};
unsigned int chuc,donvi,ng_dv, ng_c;
void display(unsigned count);
// Chương trình con set up các chân I/O
void set_GPIO(void)
{
TRISB = 0X00; // Định nghĩa ngõ ra của tất cả kênh B
PORTB = 0X00; // Định nghĩa trạng thái ban đầu của tất cả kênh B ở mức thấp
TRISC = 0X00;
PORTC = 0XFF;
TRISAbits.TRISA0 = 0;
TRISAbits.TRISA1 = 0;
ADCON1 = 0x07;
}
// Chương trình chính của hệ thống
void main(void) {
while(1)
{
set_GPIO(); //Gọi chương trình con I/O để thực hiện

if (count < 16 && status == 0) // Điều kiện nếu nhỏ hơn 16 thì đếm từ 0 đến 15
{
PORTB = count;
display(count);
__delay_ms(1000);
count++;
if (count == 15)
{
status = 1;
}
}
else // Ngược lại đếm từ 15 về 0
{
PORTB = count;
display(count);

18
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

__delay_ms(1000);
count--;
if (count == 0)
{
status = 0;
}
}
}
}
// Chương trình con hiển thị LED 7 đoạn
void display (unsigned int count)
{
chuc = count/10;
donvi = count%10;
PORTAbits.RA0 = 0; // LED don vi
PORTC = LED7Seg[donvi];
__delay_ms(50);
PORTAbits.RA0 = 1;
PORTAbits.RA1 = 0; // LED chuc
PORTC = LED7Seg[chuc];
__delay_ms(50);
PORTAbits.RA1 = 1;
}

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

2.2.2 Các bước thực hiện yêu cầu 2


Bước 1 và Bước 2 thực hiện như phần 2.2.1

19
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Bước 3: Khai báo các thanh ghi của PORTA và PORTB để thực hiện yêu cầu ngõ vào và
ngõ ra.
Bước 4: Viết chương trình chính thực hiện yêu cầu.
CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 2:
/*
* File: led_on.c
* Author: Thethinh
*/
// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
// Khai báo thư viện
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include "config_uart.h"
// Định nghĩa và khai báo các biến và hàm
#define _XTAL_FREQ 20000000
void set_GPIO(void);
unsigned char count = 0;
unsigned int i,j = 1;
unsigned char status = 0;
const unsigned char LED7Seg[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82,0xF8, 0x80, 0x90};
unsigned int chuc,donvi,ng_dv, ng_c;
void display(unsigned count);
// Chương trình con set up các chân I/O
void set_GPIO(void)
{
TRISB = 0X00; // Định nghĩa ngõ ra của tất cả kênh B
PORTB = 0X00; // Định nghĩa trạng thái ban đầu của tất cả kênh B ở mức thấp
TRISAbits.TRISA4 = 1; // Định nghĩa ngõ vào
ADCON1 = 0x07;
}
// Chương trình chính của hệ thống
void main(void) {
set_GPIO(); //Gọi chương trình con I/O để thực hiện
while(1)
{
if (PORTAbits.RA4 == 0) // Nếu nhấn nút bấm thì đèn sẽ sáng
{
PORTBbits.RB0 = 1;
}
else // Nếu không bấm đền sẽ tắt
{

20
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

PORTBbits.RB0 = 0;
}
}
}
// Chương trình con hiển thị LED 7 đoạn
void display (unsigned int count)
{
chuc = count/10;
donvi = count%10;
PORTAbits.RA0 = 0; // LED don vi
PORTC = LED7Seg[donvi];
__delay_ms(50);
PORTAbits.RA0 = 1;
PORTAbits.RA1 = 0; // LED chuc
PORTC = LED7Seg[chuc];
__delay_ms(50);
PORTAbits.RA1 = 1;
}

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

2.2.3 Các bước thực hiện yêu cầu 3


Bước 1 và Bước 2 thực hiện như phần 2.2.1
Bước 3: Khai báo các thanh ghi của PORTA và PORTC để thực hiện yêu cầu ngõ vào và
ngõ ra.

21
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Bước 4: Viết chương trình chính thực hiện yêu cầu.


CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 3:
/*
* File: led_on.c
* Author: Thethinh
*/
// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
// Khai báo thư viện
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
//#include "config_uart.h"
// Định nghĩa và khai báo các biến và hàm
#define _XTAL_FREQ 20000000
void set_GPIO(void);
unsigned char count = 0;
unsigned int i,j = 1;
unsigned char status = 0;
const unsigned char LED7Seg[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82,0xF8, 0x80, 0x90};
unsigned int chuc,donvi;
void display(unsigned count);
void ham_donvi(unsigned donvi);
void ham_chuc(unsigned chuc);
unsigned int dem1 = 0;
unsigned int dem2 = 0;
// Chương trình con set up các chân I/O
void set_GPIO(void)
{
TRISC = 0X00; // Định nghĩa ngõ ra của tất cả kênh C
PORTC = 0XFF; // Định nghĩa trạng thái ban đầu của tất cả kênh C ở mức cao
TRISAbits.TRISA0 = 0; // Định nghĩa chân RA0 là ngõ ra
TRISAbits.TRISA1 = 0; // Định nghĩa chân RA1 là ngõ ra
ADCON1 = 0x07; // Định nghĩa các chân là digital
}
// Chương trình chính của hệ thống
void main(void) {
set_GPIO(); //Gọi chương trình con I/O để thực hiện
int t;
while(1)
{
for (count = 0; count < 100; count ++)
{
t = 0;

22
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

while(t++ < 200)


{
dem1 = count%10;
dem2 = count/10;
ham_donvi(dem1);
ham_chuc(dem2);
}
}
}
}
// Chương trình con hiển thị LED 7 đoạn
void ham_donvi(unsigned int donvi)
{
PORTAbits.RA0 = 0; // Điều khiển LED đơn vị
PORTC = LED7Seg[donvi];
__delay_ms(1);
PORTAbits.RA0 = 1;
}
void ham_chuc(unsigned int chuc)
{
PORTAbits.RA1 = 0; // Điều khiển LED chục
PORTC = LED7Seg[chuc];
__delay_ms(1);
PORTAbits.RA1 = 1;
}

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

23
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

2.3 BÀI TẬP


Bài 1. Viết chương trình để khi nhấn RA4 thì các led sẽ sáng đếm lên, mỗi lần nhấn đếm
lên 1 đơn vị.
Bài 2. Viết chương trình sao cho mỗi lần nhấn RA4 thì 2 led trái và 2 led phải thay nhau
sáng.
Bài 3. Viết chương trình hiển thị LED 7 đoạn đếm từ 99 về 0.
Bài 4. Viết chương trình để khi nhấn RA4 thì đếm lên 1 đơn vị từ 0 đến 99 và hiển thị lên
LED 7 đoạn.

24
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Phần 3: KHẢO SÁT TIMER/COUNTER, GIAO TIẾP LCD


Mục tiêu:
- Khảo sát các chế hoạt động của bộ định thời/bộ đếm.
- Khảo sát các thanh điều bộ định thời/bộ đếm.
- Sử dụng bộ định thời trong chương trình.
- Khảo sát ngắt ngoài của vi điều khiển PIC 16F877A.
- Điều khiển LCD ký tự 2x16.
Yêu cầu:
- Sử dụng bộ timer 1 cứ sau 1s đếm lên 1 đơn vị rồi xuất giá trị ra LED đơn.
- Viết chương trình khởi tạo 2 ngắt:
Ngắt ngoài 0 với độ ưu tiên cao.
Ngắt ngắt timer 0 với độ ưu tiên thấp.
Trong chương trình ngắt ngoài 0 bật 3 LED RB1, RB2, RB3 sáng cùng lúc.
Trong chương trình timer 0 sau 1s khi 3 LED được bật ở trong chương trình ngắt ngoài
sẽ tắt 3 LED đơn RB1, RB2, RB3 cùng lúc.
- Viết chương trình hiển thị kí tự lên LCD.
3.1 KIẾN THỨC LIÊN QUAN
3.1.1 Timer 0
Đây là một trong ba bộ đếm hoặc bộ định thời của vi điều khiển PIC16F877A. Timer 0
là bộ đếm 8 bit được kết nối với bộ chia tần số (prescaler) 8 bit. Sơ đồ khối của Timer 0 như
sau:

Muốn Timer 0 hoạt động ở chế độ Timer ta clear bit TOSC (OPTION_REG<5>), khi đó
giá trị thanh ghi TMR0 sẽ tăng theo từng chu kì xung đồng hồ (tần số vào Timer0 bằng ¼ tần
số oscillator). Muốn Timer 0 hoạt động ở chế độ counter ta set bit TOSC

25
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

(OPTION_REG<5>). Khi đó xung tác động lên bộ đếm được lấy từ chân RA4/TOCK1. Bit
TOSE (OPTION_REG<4>) cho phép lựa chọn cạnh tác động vào bộ đếm. Cạnh tác động sẽ
là cạnh lên nếu TOSE = 0 và cạnh tác động sẽ là cạnh xuống nếu TOSE = 1.

Các thanh ghi điều khiển liên quan đến Timer 0 bao gồm:

Thanh ghi TMR0: địa chỉ 01h, 101h.

Thanh ghi 8 bit chứa giá trị của bộ định thời Timer 0.

Thanh ghi INTCON: địa chỉ 0Bh, 8Bh, 10Bh, 18Bh.

Thanh ghi chứa các bit điều khiển và các bit cờ hiệu khi Timer 0 bị tràn, ngắt ngoại vi
RB0/INT và ngắt interrput-on-change tại các chân của PORTB.

Bit 7 GIE Global Interrupt Enable bit

GIE = 1 cho phép tất cả các ngắt.

GIE = 0 không cho phép tất cả các ngắt.

Bit 6: PEIE Pheripheral Interrupt Enable bit

PEIE = 1 cho phép tất cả các ngắt ngoại vi.

PEIE = 0 không cho phép tất cả các ngắt ngoại vi.

Bit 5: TMR0IE Timer0 Overflow Interrupt Enable bit

TMR0IE = 1 cho phép ngắt Timer0.

TMR0IE = 0 không cho phép ngắt Timer0.

Bit 4: INTE RB0/INT External Interrupt Enable bit


INTE = 1 cho phép ngắt ngoại vi RB0/INT.
INTE = 0 không cho phép ngắt ngoại vi RB0/INT.
Bit 3: RBIE RB Port change Interrupt Enable bit
RBIE = 1 cho phép ngắt RB Port change.
RBIE = 0 không cho phép ngắt RB Port change.

26
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Bit 2: TMR0IF Timer0 Interrupt Flag bit


TMR0IF = 1 thanh ghi TMR0 bị tràn (phải xóa bằng chương trình).
TMR0IF = 0 thanh ghi TMR0 chưa bị tràn.
Bit 1: INTF BR0/INT External Interrupt Flag bit
INTF = 1 ngắt RB0/INT xảy ra (phải xóa cờ hiệu bằng chương trình).
INTF = 0 ngắt RB0/INT chưa xảy ra.
Bit 0: RBIF RB Port Change Interrupt Flag bit
RBIF = 1 ít nhất có một chân RB7:RB4 có sự thay đổi trạng thái. Bit này phải được xóa bằng
chương trình sau khi đã kiểm tra lại các giá trị của các chân tại PORTB.
RBIF = 0 không có sự thay đổi trạng thái các chân RB7:RB4.
Thanh ghi OPTION_REG: địa chỉ 81h, 181h
Thanh ghi này cho phép điều khiển chức năng pull-up của các pin 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.

Bit 7: RBPU PORTB pull-up enable bit

RBPU= 1 không cho phép chức năng pull-up của PORTB

RBPU= 0 cho phép chức năng pull-up của PORTB

Bit 6: INTEDG Interrupt Edge Select bit

INTEDG = 1 ngắt xảy ra khi cạnh dương chân RB0/INT xuất hiện.

INTEDG = 0 ngắt xảy ra khi cạnh âm chân BR0/INT xuất hiện.

Bit 5: TOCS Timer0 Clock Source select bit

TOSC = 1 clock lấy từ chân RA4/TOCK1.

TOSC = 0 dùng xung clock bên trong (xung clock này bằng với xung clock dùng để thực thi
lệnh).

Bit 4: TOSE Timer0 Source Edge Select bit

TOSE = 1 tác động cạnh lên.

27
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

TOSE = 0 tác động cạnh xuống.

Bit 3: PSA Prescaler Assignment Select bit

PSA = 1 bộ chia tần số (prescaler) được dùng cho WDT

PSA = 0 bộ chia tần số được dùng cho Timer 0

Bit 2:0 PS2:PS0 Prescaler Rate Select bit

Các bit này cho phép thiết lập tỉ số chia tần số của Prescaler

3.1.2 Timer 1
Timer 1 là bộ định thời 16 bit, giá trị của Timer 1 sẽ được lưu trong hai thanh ghi
(TMR1H:TMR1L). Tương tự như Timer 0, Timer 1 cũng có hai chế độ hoạt động: chế độ
định thời (timer) với xung kích là xung clock của oscillator (tần số của timer bằng ¼ tần số
của oscillator) và chế độ đếm (counter) với xung kích là xung phản ánh các sự kiện cần đếm
lấy từ bên ngòai thông qua chân RC0/T1OSO/T1CKI (cạnh tác động là cạnh lên).Sau đây là
sơ đồ khối của Timer 1.

Ngoài ra Timer 1 còn có chức năng reset input bên trong được điều khiển bởi một trong hai
khối CCP (Capture/Compare/PWM).

28
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Các thanh ghi liên quan đến Timer1 bao gồm:

Thanh ghi INTCON (địa chỉ 0Bh, 8Bh, 10Bh, 18Bh): cho phép ngắt hoạt động (GIE và
PEIE).

Thanh ghi PIR1: địa chỉ 0Ch

Thanh ghi chứa cờ ngắt của các khối ngoại vi.

Bit 7: PSPIF Parallel Slave Port Read/Write Interrupt Flag bit

PSPIF = 1 vừa hoàn tất thao tác đọc hoặc ghi PSP (phải xóa bằng chương trình).

PSPIF = 0 không có thao tác đọc ghi PSP nào diễn ra.

Bit 6: ADIF ADC Interrupt Flag bit

ADIF = 1 hoàn tất chuyển đổi ADC.

ADIF = 0 chưa hoàn tất chuyển đổi ADC.

Bit 5: RCIF USART Receive Interrupt Flag bit

RCIF = 1 buffer nhận qua chuẩn giao tiếp USART đã đầy.

RCIF = 0 buffer nhận qua chuẩn giao tiếp USART rỗng.

Bit 4: TXIF USART Transmit Interrupt Flag bit

TXIF = 1 buffer truyền qua chuẩn giao tiếp USART rỗng.

TXIF = 0 buffer truyền qua chuẩn giao tiếp USART đầy.

Bit 3: SSPIF Synchronous Serial Port (SSP) Interrupt Flag bit

SSPIF = 1 ngắt truyền nhận SSP xảy ra.

SSPIF = 0 ngắt truyền nhận SSP chưa xảy ra.

Bit 2: CCP1IF CCP1 Interrupt Flag bit

Khi CCP1 ở chế độ Capture

29
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

CCP1IF=1 đã cập nhật giá trị trong thanh ghi TMR1.

CCP1IF=0 chưa cập nhật giá trị trong thanh ghi TMR1.

Khi CCP1 ở chế độ Compare

CCP1IF=1 giá trị cần so sánh bằng với giá trị chứa trong TMR1.

CCP1IF=0 giá trị cần so sánh không bằng với giá trị trong TMR1.

Bit 1: TMR2IF TMR2 to PR2 Match Interrupt Flag bit

TMR2IF = 1 giá trị chứa trong thanh ghi TMR2 bằng với giá trị chứa trong thanh ghi PR2.

TMR2IF = 0 giá trị chứa trong thanh ghi TMR2 chưa bằng với giá trị chứa trong thanh ghi
PR2.

Bit 0: TMR1IF TMR1 Overflow Interrupt Flag bit

TMR1IF = 1 thanh ghi TMR1 bị tràn (phải xóa bằng chương trình).

TMR1IF = 0 thanh ghi TMR1 chưa bị tràn.

Thanh ghi PIE1: địa chỉ 8Ch

Thanh ghi chứa các bit cho phép các ngắt ngoại vi.

Bit 7: PSPIE Parallel Slave Port Read/Write Interrupt Enable bit

PSPIE = 1 cho phép ngắt PSP read/write.

PSPIE = 0 không cho phép ngắt PSP read/write.

Bit 6: ADIE ADC (A/D converter) Interrupt Enable bit

ADIE = 1 cho phép ngắt ADC.

ADIE = 0 không cho phép ngắt ADC.

Bit 5: RCIE USART Receive Interrupt Enable bit

RCIE = 1 cho phép ngắt nhận USART

RCIE = 0 không cho phép gắt nhận USART

30
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Bit 4: TXIE USART Transmit Interrupt Enable bit

TXIE = 1 cho phép ngắt truyền USART

TXIE = 0 không cho phép ngắt truyền USART

Bit 3: SSPIE Synchronous Serial Port Interrupt Enable bit

SSPIE = 1 cho phép ngắt SSP

SSPIE = 0 không cho phép ngắt SSP

Bit 2: CCP1IE CCP1 Interrupt Enable bit

CCP1IE = 1 cho phép ngắt CCP1

CCP1IE = 0 không cho phép ngắt CCP1

Bit 1: TMR2IE TMR2 to PR2 Match Interrupt Enable bit

TMR2IE = 1 cho phép ngắt.

TMR2IE = 0 không cho phép ngắt.

Bit 0: TMR1IE TMR1 Overflow Interrupt Enable bit

TMR1IE = 1 cho phép ngắt.

TMR1IE = 0 không cho phép ngắt.

Thanh ghi TMR1L: địa chỉ 0Eh

Thanh ghi chứa 8 bit thấp của bộ định thời TMR1.

Thanh ghi TMR1H: địa chỉ 0Fh

Thanh ghi chứa 8 bit cao của bộ định thời TMR2.

Thanh ghi T1CON: địa chỉ 10h

Thanh ghi điều khiển Timer 1

Bit 7,6: Không sử dụng và mang giá trị mặc định là 0

31
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Bit 5,4: T1CKPS1:T1CKPS0 Timer1 Input Clock Prescaler Select bit

11 tỉ số chia tần số của prescaler là 1:8

10 tỉ số chia tần số của prescaler là 1:4

01 tỉ số chia tần số của prescaler là 1:2

00 tỉ số chia tần số của prescaler là 1:1

Bit 3: T1OSCEN Timer 1 Oscillator Enable Control bit

T1OSCEN = 1 cho phép Timer1 hoạt động với xung do oscillator cung cấp.

T1OSCEN = 0 không cho phép Timer 1 hoạt động với xung do oscillator cung cấp (tắt bộ
chuyển đổi xung bên trong Timer1).

Bit 2: T1SYNC Timer 1 Iternal Clock Input Synchronization Control bit

Khi TMR1CS = 1

T1SYNC= 1 không đồng bộ xung clock ngoại vi đưa vào Timer 1.

T1SYNC= 0 đồng bộ xung clock ngoại vi đưa vào Timer 1.

Khi TMR1CS = 0

Bit T1SYNC không được quan tâm do Timer1 sử dụng xung clock bên trong.

Bit 1: TMR1CS Timer 1 Clock Source Select bit

TMR1CS = 1 chọn xung đếm là xung ngoại vi lấy từ pin RC0/T1OSC /T1CKI (cạnh tác động
là cạnh lên).

TMR1CS = 0 chọn xung đếm là xung clock bên trong (FOSC/4).

Bit 0: TMR1ON Timer 1 On bit

TMR1ON = 1 cho phép Timer1 hoạt động.

TMR1ON = 0 Timer1 ngưng hoạt động.

3.1.3 Timer 2
Timer 2 là bộ định thời 8 bit và được hỗ trợ bởi hai bộ chia tần số prescaler và postscaler.
Thanh ghi chứa giá trị đếm của Timer 2 là TMR2.

32
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Timer 2 còn được hỗ trợ bởi thanh ghi PR2. Giá trị đếm trong thanh ghi TMR2 sẽ tăng từ
00h đến giá trị chứa trong thanh ghi PR2, sau đó được reset về 00h. Khi reset thanh ghi PR2
được nhận giá trị mặc định FFh. Ngoài ra ngõ ra của Timer2 còn được kết nối với khối SSP,
do đó Timer 2 còn đóng vai trò tạo ra xung clock đồng bộ cho khối giao tiếp SSP.

Các thanh ghi liên quan đến Timer 2 bao gồm:

Thanh ghi INTCON (địa chỉ 0Bh, 8Bh, 10Bh, 18Bh): cho phép tòan

bộ các ngắt (GIE và PEIE).

Thanh ghi PIR1 (địa chỉ 0Ch): chứa cờ ngắt Timer 2 (TMR2IF).

Thanh ghi PIE1 (địa chị 8Ch): chứa bit điều khiển Timer 2 (TMR2IE).

Thanh ghi TMR2 (địa chỉ 11h): chứa giá trị đếm của Timer 2.

Thanh ghi chứa giá trị bộ đếm Timer 2.

Thanh ghi T2CON: địa chỉ 12h

Thanh ghi điều khiển Timer 2.

Bit 7: Không quan tâm và mặc định mang giá trị 0

Bit 6-3: TOUTPS3:TOUTPS0 Timer2 Output Postscaler Select bit

Các bit này điều khiển việc lựa chọn tỉ số chia tần số cho postscaler.

33
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

0000 tỉ số 1:1

0001 tỉ số 1:2

0010 tỉ số 1:3

……………………

1111 tỉ số 1:16

Bit 2: TMR2ON Timer 2 On bit

TMR2ON = 1 bật Timer 2.

TMR2ON = 0 tắt Timer 2.

Bit 1,0: T2CKPS1:T2CKPS0 Timer2 Clock Prescaler Select bit

Các bit này điều khiển tỉ số chi tần số của prescaler

00 tỉ số 1:1

01 tỉ số 1:4

1x tỉ số 1:16

Thanh ghi PR2 (địa chỉ 92h): thanh ghi hỗ trợ cho Timer 2. Thanh ghi dùng để ấn định trước
giá trị đếm cho Timer 2. Khi vi điều khiển được reset, PR2 mang giá trị FFh. Khi ta đưa một
giá trị vào thanh ghi PR2, Timer 2 sẽ đếm từ 00h cho đến khi giá trị bộ đếm của Timer 2 bằng
với giá trị của bộ đếm trong thanh ghi PR2. Như vậy mặc định Timer 2 sẽ đếm từ 00h đến
FFh.
3.1.4 Giao tiếp LCD ký tự 2x16
a. Hình dạng và ý nghĩa các chân

34
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

b. Tổ chức vùng nhớ của LCD


Display Data Ram (DDRAM): lưu trữ mã ký tự hiển thị ra màn hình. Mã này giống với
mã ASCII. Có tất cả 80 ô nhớ DDRAM. Vùng hiển thị tương ứng với cửa sổ gồm 16 ô nhớ
hàng đầu tiên và 16 ô nhớ hàng thứ hai. Chúng ta có thể tạo hiệu ứng dịch chữ bằng cách sử
dụng lệnh dịch (mô tả sau), khi đó cửa sổ hiển thị sẽ dịch đem lại hiệu ứng dịch chữ.

Character Generator Ram (CGRAM): lưu trữ tám mẫu ký tự do người dùng định
nghĩa. Tám mẫu ký tự này tương ứng với các mã ký tự D7-D0 = 0000*D2D1D0 (* mang giá
trị tùy định 0 hay 1).

35
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Character Generator Rom (CGROM): lưu trữ cứng các mẫu ký tự tương ứng với mã
ASCII. Dưới đây là bảng ánh xạ giữa mã ký tự và mẫu ký tự.

Chúng ta muốn hiển thị chữ “CE” ở giữa hàng đầu tiên, giả sử cửa sổ hiển thị đang bắt
đầu từ vị trí đầu tiên (hàng thứ nhất hiển thị dữ liệu của ô nhớ từ 0x00 đến 0x0f, hàng thứ hai
hiển thị dữ liệu của ô nhớ từ 0x40 đến 0x4f, đây là vị trí home). Giá trị của ô nhớ 0x07 là
0x43 (ký tự C), của ô nhớ 0x08 là 0x45 (ký tự E). Chúng ta muốn hiển thị chữ “®” ở giữ hàng
thứ hai, giả sử cử sổ hiển thị đang ở vị trí home. Trong bảng mẫu ký tự chúng ta thấy không
có mẫu “®”. Lúc này chúng ta phải định nghĩa mẫu “®” 5x8 điểm, gồm có 8 byte, sau đó lưu
vào vị trí của mẫu ký tự CGRAM thứ nhất. Lúc này giá trị của ô nhớ 0x47 là 0x00 hoặc 0x08
(vị trí của mẫu ký tự CGRAM thứ nhất “®”).
c. Các lệnh giao tiếp với LCD

36
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Các bit trên bảng tóm tắt các lệnh có ý nghĩa như sau:

Ở thí nghiệm này LCD sẽ hoạt động ở chế độ 4 bit, để đọc hay ghi một byte phải tiến
hành cài dữ liệu hai lần, lần đầu là 4 bit cao, lần thứ hai là 4 bit thấp.
3.2 THỰC HIỆN CÁC YÊU CẦU
3.2.1 Các bước thực hiện yêu cầu 1
Bước 1: Tạo project mới giống như hướng dẫn ở Phần 1 lấy tên project là Timer_LED,
tạo file Timer_led.c và chọn chip 16F877A trong MPLAB. Ta được hình sau:

37
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Bước 2: Khai báo các cấu hình cho PIC 16F877A. Click vào Window >> trỏ chuột vào
Target Memmory >> chọn Configuration Bits >> Tắt và mở cấu hình các chức năng cần thiết.

Tiếp theo click vào “Generate Source Code to Output” và copy các đoạn mã cấu hình
vào chương trình chính.

38
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Bước 3: Khai báo các thanh ghi của PORTB để thực hiện yêu cầu ngõ ra. Cần gán giá trị
cho thanh ghi ADCON1 vì thanh ghi này có chức năng chọn các PORT có chức năng là
input/output digital hay là input Analog. Do đó, trước khi sử dụng các port ta phải kiểm tra
xem thanh ghi ADCON1 đã cấu hình đúng chưa.
Bước 4: Khởi tạo ngắt timer 1 cứ sau 100ms thì vào ngắt một lần. Chọn Prescalar: 8 và
tần số thạch anh là 8 Mhz.
Giá trị thanh ghi ban đầu của timer 1 được tính như sau:
RegValue = 65536-(Delay * Fosc)/(Prescalar*4)) = 65536- ((100ms * 8Mhz)/(8*4)) = 40536
Nên khi ta để giá trị trong các thanh ghi của timer 1 giá trị 40530 thì cứ sau 100ms, timer sẽ
ngắt một lần. Để sau 1s đến lên 1 đơn vị. Ta lặp lại ngắt của timer 1 là 10 lần.
Bước 5: Viết chương trình chính thực hiện yêu cầu.
CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 1:
/*
* File: main.c
* Author: Thethinh
*/
// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = OFF

39
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

#pragma config LVP = OFF


#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define _XTAL_FREQ 8000000
unsigned int Count = 0;
void main(void) {
TRISBbits.TRISB0 = 0;
TMR1 = 40536;
T1CONbits.TMR1CS = 0;
T1CONbits.T1CKPS1 = 1;
T1CONbits.T1CKPS0 = 1;
T1CONbits.T1SYNC = 1;
T1CONbits.TMR1ON = 1;
while (1)
{
if(PIR1bits.TMR1IF == 1)
{
PIR1bits.TMR1IF = 0;
TMR1 = 40536;
Count++;
if(Count==10)
{
Count =0;
PORTBbits.RB0 ^= 1; //toggle the LED
}
}
}}

40
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

3.2.2 Các bước thực hiện yêu cầu 2


Bước 1 và Bước 2 thực hiện như phần 3.2.1
Bước 3: Khai báo các thanh ghi của PORTC để thực hiện yêu cầu ngõ ra.
Bước 4: Khởi tạo ngắt timer0 cứ sau 10ms thì vào ngắt một lần. Chọn Prescalar: 128 và
tần số thạch anh là 8 Mhz.
Giá trị thanh ghi ban đầu của timer 1 được tính như sau:
RegValue = 256-(Delay * Fosc)/(Prescalar*4)) = 256- ((10ms * 8Mhz)/(128*4)) = 100
Nên khi ta để giá trị trong các thanh ghi của timer0 giá trị 100 thì cứ sau 10ms, timer sẽ
ngắt một lần. Để sau 1s đến lên 1 đơn vị. Ta lặp lại ngắt của timer0 là 100 lần.
Bước 5: Khai tạo ngắt ngoài và cấu hình các thanh ghi cho phép ngắt ngoài hoạt động.

41
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Bước 6: Viết chương trình chính thực hiện yêu cầu.


CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 2:
/*
* File: main.c
* Author: Thethinh
*/
// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define _XTAL_FREQ 8000000
unsigned int Count = 0;
void set_GPIO(void);
void tat_led(void);
void interrupt external();
void set_GPIO(void)
{
TRISC = 0X00; //Khai báo Kênh C là ngõ ra
PORTC = 0X00; //Khai báo trạng thái ban đầu của Port C là mức thấp
TRISBbits.TRISB0 = 1; //Khai báo chân B0 là ngõ vào
PORTB = 0X00; //Khai báo trạng thái ban đầu của Port B là mức thấp
INTCONbits.GIE = 1; //Cho phép ngắt toàn cục
INTCONbits.INTE = 1; //Cho phép RB0 ngắt ngoài

42
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

OPTION_REGbits.INTEDG = 0; //Ngắt cạnh xuống


TMR0 = 100; //Gắn giá trị ban đầu cho thanh ghi
OPTION_REGbits.PSA = 0; //Gán bộ chia trước cho timer0
OPTION_REGbits.PS2 = 1; //
OPTION_REGbits.PS1 = 1; //
OPTION_REGbits.PS0 = 0;//Bộ chia 128 và tần số thạch anh là 8MHz
OPTION_REGbits.T0CS = 0; //Đếm xung clock nội
ADCON1 = 0x07;
}
void interrupt external()
{
if(INTCONbits.INTF==1)
{
{
PORTC = 0XFF;
INTCONbits.INTF=0;
TMR0 = 100;
Count = 0;
}
}
}
void tat_led(void)
{
PORTC = 0X00;
}
void main(void)
{
set_GPIO();
while(1)
{
if(INTCONbits.TMR0IF == 1)
{

43
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

INTCONbits.TMR0IF = 0;
TMR0 = 100;
Count ++;
if (Count >= 1000)
{
tat_led();
Count = 0;
}
}
}
}

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

3.2.3 Các bước thực hiện yêu cầu 3


Bước 1 và Bước 2 thực hiện như phần 3.2.1
Bước 3: Hàm quan trọng nhất của LCD kí tự chính là hàm khởi tạo LCD. Trước khi sử
dụng được lcd ta phải khởi tạo cho nó theo như giản đồ khởi tạo lcd ở trên phần hướng dẫn
lý thuyết. Ngoài ra do thiết kế mạch, để LCD có thể hiện thị bình thường trước tiên ta phải
bật nguồn của LCD lên, chân nguồn của LCD được điều khiển bởi PortD.7 tích cực mức cao,
nên trước khi muốn sử dụng LCD ta phải bật PortD.7 lên 1.
Bước 4: Viết chương trình chính thực hiện yêu cầu.
CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 2:

44
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Head file – Bao gồm thư viện “my_lcd.h”


#include <xc.h> // include processor files - each processor file is guarded.
//LCD Functions Developed by electroSome
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
void Lcd_Port(char a)
{
if(a & 1)
D4 = 1;
else
D4 = 0;

if(a & 2)
D5 = 1;
else
D5 = 0;

if(a & 4)
D6 = 1;
else
D6 = 0;

if(a & 8)
D7 = 1;
else
D7 = 0;
}
void Lcd_Cmd(char a)
{
RS = 0; // => RS = 0
Lcd_Port(a);
EN = 1; // => E = 1
__delay_ms(4);
EN = 0; // => E = 0
}

void Lcd_Clear(void)
{
Lcd_Cmd(0);
Lcd_Cmd(1);
}

void Lcd_Set_Cursor(char a, char b)


{

45
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

char temp,z,y;
if(a == 1)
{
temp = 0x80 + b - 1;
z = temp>>4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
}
else if(a == 2)
{
temp = 0xC0 + b - 1;
z = temp>>4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
}
}

void Lcd_Init(void)
{
Lcd_Port(0x00);
__delay_ms(20);
Lcd_Cmd(0x03);
__delay_ms(5);
Lcd_Cmd(0x03);
__delay_ms(11);
Lcd_Cmd(0x03);
/////////////////////////////////////////////////////
Lcd_Cmd(0x02);
Lcd_Cmd(0x02);
Lcd_Cmd(0x08);
Lcd_Cmd(0x00);
Lcd_Cmd(0x0C);
Lcd_Cmd(0x00);
Lcd_Cmd(0x06);
}

void Lcd_Write_Char(char a)
{
char temp,y;
temp = a&0x0F;
y = a&0xF0;
RS = 1; // => RS = 1
Lcd_Port(y>>4); //Data transfer
EN = 1;
__delay_us(40);
EN = 0;

46
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Lcd_Port(temp);
EN = 1;
__delay_us(40);
EN = 0;
}

void Lcd_Write_String(char *a)


{
int i;
for(i=0;a[i]!='\0';i++)
Lcd_Write_Char(a[i]);
}

void Lcd_Shift_Right(void)
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x0C);
}

void Lcd_Shift_Left(void)
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x08);
}
Main file - Code chính

* File: main.c

* Author: Thethinh
*/

#include <stdio.h>
#include <stdlib.h>

#define _XTAL_FREQ 8000000

#include <xc.h>

#include "my_lcd.h"

#define RS RD2
#define EN RD3
#define D4 RD4

#define D5 RD5

47
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

#define D6 RD6

#define D7 RD7

// BEGIN CONFIG

#pragma config FOSC = HS


#pragma config WDTE = OFF

#pragma config PWRTE = OFF

#pragma config BOREN = ON

#pragma config LVP = OFF


#pragma config CPD = OFF

#pragma config WRT = OFF


#pragma config CP = OFF

//END CONFIG

void main(void)

{
char s[20];

unsigned int a;
TRISD = 0x00;

Lcd_Init();
while(1)

Lcd_Clear();
Lcd_Set_Cursor(1,1);

Lcd_Write_String(" LCD 16X2 DEMO ");

Lcd_Set_Cursor(2,1);
Lcd_Write_String(" VI DIEU KHIEN ");

48
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

__delay_ms(2000);

Lcd_Clear();

Lcd_Set_Cursor(1,1);

Lcd_Write_String("TRUONG DAI HOC KY THUAT CONG NGHE CAN


THO");

for(a=0;a<15;a++)

__delay_ms(300);
Lcd_Shift_Left();

for(a=0;a<15;a++)

__delay_ms(300);
Lcd_Shift_Right();

Lcd_Clear();
Lcd_Set_Cursor(2,1);

Lcd_Write_String(" THANKS YOU ");

__delay_ms(2000);

}}

49
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

3.3 BÀI TẬP


Bài 1: Viết chương trình hiển thị led đơn chớp tắt với thời gian delay 500ms sử dụng
Timer0.
Bài 2: Viết chương trình hiển thị led đơn chớp tắt với thời gian delay 200ms sử dụng
Timer1.
Bài 3: Viết chương trình tăng từ 00 đến 99 hiển thị trên led 1 và led 2 sử dụng timer 2.
Bài 4: Viết chương trình chạy chữ qua LCD.
Bài 5: Viết chương trình thay đổi chữ hiển thị trên LCD khi nhấn nút.

50
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Phần 4: KHẢO SÁT CÁC KHỐI CHỨC NĂNG


Mục tiêu:
- Khảo sát hoạt động của khối chuyển đổi ADC.
- Khảo sát các thanh ghi điều khiển hoạt động khối chuyển đổi ADC.
- Khảo sát hoạt động của khối chức năng đặt biệt PWM.
- Sử dụng khối chuyển đổi ADC trong chương trình.
Yêu cầu:
- Viết chương trình đọc và hiển thị giá trị điện áp thay đổi bởi biến trở trên LED.
- Viết chương trình sử dụng chức năng PWM điều khiển độ sáng của LED.
4.1 KIẾN THỨC LIÊN QUAN
4.1.1 Bộ chuyển đổi ADC
Để khởi tạo được module ADC ta cần quan tâm các thanh ghi như sau:
- INTCON (địa chỉ 0Bh, 8Bh, 10Bh, 18Bh): cho phép các ngắt (các bit GIE, PEIE).
- PIR1 (địa chỉ 0Ch): chứa cờ ngắt AD (bit ADIF).
- PIE1 (địa chỉ 8Ch): chứa bit điều khiển AD (ADIE).
- ADRESH (địa chỉ 1Eh) và ADRESL (địa chỉ 9Eh): các thanh ghi chứa kết quả chuyển
đổi AD.
- ADCON0 (địa chỉ 1Fh) và ADCON1 (địa chỉ 9Fh): xác lập các thông số cho bộ chuyển
đổi AD.
- PORTA (địa chỉ 05h) và TRISA (địa chỉ 85h): liên quan đến các ngõ vào analog ở
PORTA.
 Thanh ghi ADCON0 (địa chỉ 1Fh)

51
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

 Thanh ghi ADCON1 (địa chỉ 9Fh)

 Lựa chọn clock chuyển đổi AD

 Xác định cấu hình chân

52
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Quy trình chuyển đổi tín hiệu số sang tín hiệu tương tự:
1. Thiết lập các thông số cho bộ chuyển đổi ADC:
• Chọn điện áp mẫu (dựa trên các thông số của thanh ghi ADCON1)
• Chọn kênh chuyển đổi AD (thanh ghi ADCON0)
• Chọn xung clock cho kênh chuyển đổi AD (thanh ghi ADCON0)
• Cho phép bộ chuyển đổi AD hoạt động (thanh ghi ADCON0).
2. Thiết lập các cờ ngắt cho bộ AD
• Clear bit ADIF, ADIE, PEIE, GIE.
3. Đợi cho tới khi quá trình lấy mẫu hoàn tất.
4. Bắt đầu quá trình chuyển đổi (set GO/DONE bit ).
5. Đợi cho tới khi quá trình chuyển đổi hoàn tất bằng cách 1 trong 2 cách:
• Kiểm tra bit GO/DONE. Nếu GO/DONE=0, quá trình chuyển đổi đã hoàn tất
• Kiểm tra cờ ngắt.
6. Đọc kết quả chuyển đổi và xóa cờ ngắt, set bit GO/DONE (nếu cần tiếp tục chuyển
đổi ).
7. Tiếp tục thực hiện các bước 1 và 2 cho quá trình chuyển đổi tiếp theo.
4.1.2 Khối chức năng đặt biệt PWM
PWM (Pulse-width modulation) là một kỹ thuật được sử dụng rất nhiều trong hệ thống
truyền thông và nhiều ứng dụng khác như điều khiển vận tốc của động cơ DC hoặc điều khiển
cường độ (intensity).
Sơ đồ khối chức năng PWM của Pic16F877A:

53
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

 Công thức tính chu kỳ PWM

 Công thức tính hệ số chu kỳ

 Thanh ghi liên quan

54
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

 Các bước cấu hình PWM


1. Cấu hình module CCP1 bằng cách cấu hình bit 0:3 của CCP1CON.
2. Chọn chu kỳ PWM bằng cách tính PR2.
3. Chọn PWM duty cycle bằng cách tính CCPR1L và bit 4,5 của CCP1CON.
4. Cho chân CCP1 làm đầu ra bằng cách TRISC=0.
5. Set giá trị cho T2CON để có giá trị Prescaler và enable Timer 2.
4.2 THỰC HIỆN CÁC YÊU CẦU
4.2.1 Các bước thực hiện yêu cầu 1
Bước 1 và Bước 2 thực hiện như phần 3
Bước 3: Để khởi tạo được module ADC ta chỉ cần quan tâm chủ yếu tới các thanh ghi
ADCCON1, ADCCON0, ADCON2. Như chương trình khởi tạo trên ta thấy đầu tiên phải cấu
hình cho các pin tương ứng phải là chân AN0, mặc định của các chân này có chức năng là
Input/Output digital. Sau đó ta phải chọn kênh ADC tương ứng, ở đây ta sử dụng kênh AD0.
Và một điểm quan trọng nữa chính là bit GO trong thanh ghi ADCON0, khi bít này được bật
lên thì module AD mới bắt đầu chuyển đổi tín hiệu. Khai báo chân ra ở PORTB và PORT C.
B ước 4: Viết chương trình chính thực hiện yêu cầu.
CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 1:
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _XTAL_FREQ 8000000
// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
void ADC_Init()

55
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

{
ADCON0 = 0b01000001; //0x41
ADCON1 = 0b11000000; //0xC0
}
unsigned int ADC_Read(unsigned char channel)
{
if(channel > 7)
return 0;
ADCON0 &= 0xC5;
ADCON0 |= channel<<3;
__delay_ms(2);
GO_nDONE = 1;
while(GO_nDONE);
return ((ADRESH<<8)+ADRESL);
}
void main()
{
unsigned int a;
TRISB = 0x00;
TRISC = 0x00;
ADC_Init();
do
{
a = ADC_Read(0);
PORTB = a;
PORTC = a>>8;
__delay_ms(100);
}while(1);
}

56
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

4.2.2 Các bước thực hiện yêu cầu 2


Bước 1 và Bước 2 thực hiện như phần 3
Bước 3: Để khởi tạo chức năng pwm, đầu tiên ta phải cấu hình cho PORTC2 là output.
Tiếp theo khởi tạo chu kì của PWM thông qua việc cấu hình thanh ghi PR2. Sau đó ta khởi
tạo duty cycle của xung pwm bằng cách cấu hình thanh ghi CCPR1L. Khai báo chân ra ở
RC2.
Bước 4: Viết chương trình chính thực hiện yêu cầu.
CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 2:
/*
* File: main.c
* Author: Thethinh
* Created on October 20, 2023, 10:03 AM
*/
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)

57
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = ON
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
#define _XTAL_FREQ 20000000
#define TMR2PRESCALE 4
#include <xc.h>
long PWM_freq = 5000;
void PWM_Initialize();
void PWM_Duty(unsigned int duty);
void PWM_Initialize()
{
PR2 = (_XTAL_FREQ/(PWM_freq*4*TMR2PRESCALE)) - 1; //Setting the PR2
formulae using Datasheet // Makes the PWM work in 5KHZ
CCP1M3 = 1; CCP1M2 = 1; //Configure the CCP1 module
T2CKPS0 = 1;T2CKPS1 = 0; TMR2ON = 1; //Configure the Timer module
TRISC2 = 0; // make port pin on C as output
}
void PWM_Duty(unsigned int duty)
{
if(duty<1023)
{
duty = ((float)duty/1023)*(_XTAL_FREQ/(PWM_freq*TMR2PRESCALE)); // On
reducing //duty = (((float)duty/1023)*(1/PWM_freq)) / ((1/_XTAL_FREQ) *
TMR2PRESCALE);
CCP1X = duty & 1; //Store the 1st bit
CCP1Y = duty & 2; //Store the 0th bit
CCPR1L = duty>>2;// Store the remining 8 bit
}
}
void ADC_Initialize()

58
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

{
ADCON0 = 0b01000001; //ADC ON and Fosc/16 is selected
ADCON1 = 0b11000000; // Internal reference voltage is selected
}
unsigned int ADC_Read(unsigned char channel)
{
ADCON0 &= 0x11000101; //Clearing the Channel Selection Bits
ADCON0 |= channel<<3; //Setting the required Bits
__delay_ms(2); //Acquisition time to charge hold capacitor
GO_nDONE = 1; //Initializes A/D Conversion
while(GO_nDONE); //Wait for A/D Conversion to complete
return ((ADRESH<<8)+ADRESL); //Returns Result
}
void main()
{
int adc_value;
TRISC = 0x00; //PORTC as output
TRISA = 0xFF; //PORTA as input
TRISD = 0x00;
ADC_Initialize(); //Initializes ADC Module
PWM_Initialize(); //This sets the PWM frequency of PWM1
do
{
adc_value = ADC_Read(4); //Reading Analog Channel 0
PWM_Duty(adc_value);
__delay_ms(50);
}while(1); //Infinite Loop
}

59
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

4.3 BÀI TẬP


Bài 1: Viết chương trình đọc giá trị nhiệt độ hiển thị LCD từ cảm biến Lm35.
Bài 2: Viết chương trình điều khiển tốc độ động cơ bằng xung PWM.

60
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Phần 5: KHẢO SÁT KHỐI GIAO TIẾP


Mục tiêu:
- Khảo sát hoạt động của khối giao tiếp nối tiếp UART, SPI.
- Khảo sát các thanh ghi điều khiển hoạt động của khối giao tiếp nối tiếp UART, SPI.
- Sử dụng khối khối giao tiếp nối tiếp UART, SPI trong chương trình.
Yêu cầu:
- Viết chương trình giao tiếp giữa hai PIC 16F877A điều khiển LED thông qua UART.
- Viết chương trình giao tiếp giữa hai PIC 16F877A điều khiển LED thông qua SPI.
5.1 KIẾN THỨC LIÊN QUAN
5.1.1 UART
 TRUYỀN BẤT ĐỒNG BỘ (ASYNCHRONOUS).
Khởi tạo truyền dữ liệu bất đồng bộ thực hiện theo các bước sau:
- Tạo xung truyền baud bằng cách đưa các giá trị cần thiết vào thanh ghi RSBRG và bit
điều khiển mức tốc độ baud BRGH.
- Cho phép cổng giao diện nối tiếp nối tiếp bất đồng bộ bằng cách clear bit SYNC và set
bit PSEN.  Set bit TXIE nếu cần sử dụng ngắt truyền.
- Set bit TX9 nếu định dạng dữ liệu cần truyền là 9 bit.
- Set bit TXEN để cho phép truyền dữ liệu (lúc này bit TXIF cũng sẽ được set).
- Nếu định dạng dữ liệu là 9 bit, đưa bit dữ liệu thứ 9 vào bit TX9D.
- Đưa 8 bit dữ liệu cần truyền vảo thanh ghi TXREG.
- Nếu sử dụng ngắt truyền, cần kiểm tra lại các bit GIE và PEIE (thanh ghi INTCON).
Các thanh ghi liên quan đến quá trình truyền dữ liệu bằng giao diện USART bất đồng bộ:
- Thanh ghi INTCON (địa chỉ 0Bh, 8Bh, 10Bh, 18Bh): cho phép tất cả các ngắt.
- Thanh ghi PIR1 (địa chỉ 0Ch): chứa cờ hiệu TXIF.
- Thanh ghi PIE1 (địa chỉ 8Ch): chứa bit cho phép ngắt truyền TXIE.
- Thanh ghi RCSTA (địa chỉ 18h): chứa bit cho phép cổng truyền dữ liệu (hai pin
RC6/TX/CK và RC7/RX/DT).
- Thanh ghi TXREG (địa chỉ 19h): thanh ghi chứa dữ liệu cần truyền.
- Thanh ghi TXSTA (địa chỉ 98h): xác lập các thông số cho giao diện.
- Thanh ghi SPBRG (địa chỉ 99h): quyết định tốc độ baud.

61
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

 NHẬN BẤT ĐỒNG BỘ (ASYNCHRONOUS).


Khởi tạo nhận dữ liệu bất đồng bộ thực hiện theo các bước sau:
- Thiết lập tốc độ baud (đưa giá trị thích hợp vào thanh ghi SPBRG và bit BRGH.
- Cho phép cổng giao tiếp USART bất đồng bộ (clear bit SYNC và set bit SPEN).
- Nếu cần sử dụng ngắt nhận dữ liệu, set bit RCIE.
- Nếu dữ liệu truyền nhận có định dạng là 9 bit, set bit RX9.
- Cho phép nhận dữ liệu bằng cách set bit CREN.
- Sau khi dữ liệu được nhận, bit RCIF sẽ được set và ngắt được kích hoạt (nếu bit RCIE
được set).
- Đọc giá trị thanh ghi RCSTA để đọc bit dữ liệu thứ 9 và kiểm tra xem quá trình nhận
dữ liệu có bị lỗi không.
- Đọc 8 bit dữ liệu từ thanh ghi RCREG.
- Nếu quá trình truyền nhận có lỗi xảy ra, xóa lỗi bằng cách xóa bit CREN.
- Nếu sử dụng ngắt nhận cần set bit GIE và PEIE (thanh ghi INTCON).
Các thanh ghi liên quan đến quá trình nhận dữ liệu bằng giao diện USART bất đồng bộ:
- Thanh ghi INTCON (địa chỉ 0Bh, 8Bh, 10Bh, 18Bh): chứa các bit cho phép toàn bộ
các ngắt (bit GIER và PEIE).
- Thanh ghi PIR1 (địa chỉ 0Ch): chứa cờ hiệu RCIE.

62
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

- Thanh ghi PIE1 (địa chỉ 8Ch): chứa bit cho phép ngắt RCIE.
- Thanh ghi RCSTA (địa chỉ 18h): xác định các trang thái trong quá trình nhận dữ liệu.
- Thanh ghi RCREG (địa chỉ 1Ah): chứa dữ liệu nhận được.
- Thanh ghi TXSTA (địa chỉ 98h): chứa các bit điều khiển SYNC và BRGH.
- Thanh ghi SPBRG (địa chỉ 99h): điều khiển tốc độ baud.

 Thanh ghi điều khiển tốc độ truyền Baud

63
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

 Cách tính tốc độ baud.


Bộ sinh tốc độ baud (BRG) là 1 timer 8 hoặc 16 bit dùng để hỗ trợ cho cả 2 chế độ đồng
bộ và không đồng bộ. 2 thanh ghi SPBRGH và SPBRG ghi giá trị phục vụ tính toán cho tốc
độ baud như sau: với n là giá trị thập phân của cặp thanh ghi <SPBRGH:SPBRG>.

Ví dụ, mình muốn tốc độ truyền là 9600 bit/s ở chế độ bất đồng bộ 8 bit, tần số thạch anh nội
của PIC16F877A là 8MHz :

<SPBRGH:SPBRG> = Fosc /(64*baudrate) - 1 = 8(Mhz)/ (64*9600) - 1 = [12.02 ] = 12

Vì thế ta sẽ ghi giá trị 12 vào cặp thanh ghi <SPBRGH:SPBRG> để có được tốc độ thỏa mãn
yêu cầu.
5.1.2 SPI
5.2 THỰC HIỆN CÁC YÊU CẦU
5.2.1 Các bước thực hiện yêu cầu 1
Bước 1 và Bước 2 thực hiện như phần 3
Bước 3: Cấu hình 2 chân RC6 là chân TX, RC7 là RX, thanh ghi SPBRG để xác định tốc
độ baudrate và chọn mode tốc độ cao chọn chế độ bất đồng bộ, truyền nhận 8 bit.
Bước 4: Viết chương trình chính thực hiện yêu cầu.
CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 1:
Head file – Bao gồm thư viện “uart.h”
#include <xc.h>
#define _XTAL_FREQ 8000000
void UART1_Init(int Baud_rate)
{
// cau hinh chan uart
TRISCbits.TRISC6 = 0; // TX Pin set as output
TRISCbits.TRISC7 = 1; // RX Pin set as input
SPBRG = ((_XTAL_FREQ / 16) / Baud_rate) - 1;
BRGH = 1; // baudrate toc do cao
SYNC = 0; // Asynchronous
SPEN = 1; // cho phep cong noi tiep
TXEN = 1; // cho phep truyen
CREN = 1; // cho phep nhan
// chon che do truyen nhan 8 bits

64
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

TX9 = 0;
RX9 = 0;
}
void UART_sendChar(char bt)
{
while (!TXIF); //lam tre he thong khi bo dem TX dang trong
TXREG = bt; // ghi gia tri truyen vao thanh ghi TXREG
}
char UART1_Read()
{
if (OERR) // check Error
{
CREN = 0; //If error -> Reset
CREN = 1; //If error -> Reset
}
while (!RCIF); // lam tre he thong khi bo dem RX dang trong
return RCREG;
}
void UART1_Write(char* str)
{
while (*str)
{
UART_sendChar(*str++);
}
}
Code chính cho PIC truyền
// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config BOREN = OFF
#pragma config LVP = ON
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
#include <xc.h>
#include "uart.h"
#define _XTAL_FREQ 8000000
void main()
{
TRISB = 0xFF;
PORTB = 0x00;
UART1_Init(9600); // Initialize UART module at 9600bps
__delay_ms(100); // Wait for UART module to stabilize
while (1)
{ // Endless loop
UART_sendChar(PORTB); // and send data via UART
__delay_ms(500);
}
}
Code chính cho PIC nhận

65
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config BOREN = OFF
#pragma config LVP = ON
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
#include <xc.h>
#include "uart.h"
#define _XTAL_FREQ 8000000
void main()
{
TRISB = 0;
PORTB = 0;
UART1_Init(9600); // Initialize UART module at 9600bps
__delay_ms(100); // Wait for UART module to stabilize
while (1)
{// Endless loop
PORTB = UART1_Read(); // read the received data,
}
}

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

5.2.1 Các bước thực hiện yêu cầu 2


Bước 1 và Bước 2 thực hiện như phần 3
Bước 3: Thực hiện theo hướng dẫn sau link.

66
Trường Đại học Kỹ thuật – Công nghệ Cần Thơ Tài liệu thực hành vi điều khiển

Bước 4: Viết chương trình chính thực hiện yêu cầu.


CHƯƠNG TRÌNH CHÍNH THỰC HIỆN YÊU CẦU 2:
Tải code tại đây

SƠ ĐỒ MẠCH MÔ PHỎNG TRÊN PROTEUS

5.3 BÀI TẬP


Bài 1: Viết chương trình đọc giá trị nhiệt độ từ cảm biến Lm35 trên PIC thứ nhất và truyền
giá trị nhiệt độ qua PIC thứ hai bằng giao thức UART và hiển thị giá trị nhiệt độ lên LCD ở
PIC thứ hai.
Bài 2: Viết chương trình điều khiển động cơ dùng giao thức SPI. Tham khảo.

67

You might also like