You are on page 1of 90

TRƯỜNG ĐẠI HỌC GIAO THÔNG VẬN TẢI KHOA

ĐIỆN ĐIỆN TỬ
BỘ MÔN ĐIỀU KHIỂN HỌC
***********

BÁO CÁO MÔN: HỆ THỐNG

ĐIỀU KHIỂN NHÚNG

NHÓM 4
Giáo viên hướng dẫn :TS Nguyễn Văn Tiềm

Nhóm thực hiện :4

Hà Nội – 16/4/2024
LỜI NÓI ĐẦU
Với quá trình công nghiệp hóa hiện đại hóa như hiện nay thì việc áp dụng
các công nghệ vi xử lý là một vấn đề khá là quan trọng. Ở học kỳ trước chúng ta
đã có học qua môn Vi Xử Lý và ở kỳ này là môn Điều Khiển Nhúng. Với mức độ
tiếp cận sâu hơn và tính thực tế cao hơn thì đây là một trong những môn rất
quan trọng với các sinh viên của ngành Tự Động Hóa. Với mỗi dòng chip khác
nhau thì datasheet của nó lại khác nhau hoàn toàn vì vậy khi chúng ta có thể tìm
hiểu vài ba dòng chip rồi thì chúng ta không còn gặp phải khó khăn khi tiếp cận
với một dòng chip nào mới cả. Sau một thời gian khá dài học về dòng điều khiển
PIC16877A và các bài toán lập trình nhúng thì hôm nay nhóm chúng em đã tổng
hợp được những bài lập trình có liên quan để viết nên bài báo cáo này. Trong
quá trình làm gặp phải khá nhiều khó khăn nhưng với sự giúp đỡ nhiệt tình của
thầy Tiềm thì chúng em cũng đã hoàn thành được bản báo cáo này. Tuy vậy
nhưng trong bản báo cáo này không thể không có sai sót do kiến thức của chúng
em còn hạn chế. Rất mong được sự đóng góp của quý thầy cô để bản báo cáo
tốt hơn.

Chúng em xin chân thành cảm ơn!


Mục lục

LỜI NÓI ĐẦU................................................................................................................................2


Phần I: Khái quát về VXL PIC16F877A........................................................................................5
Giới thiệu.......................................................................................................................................5
Sơ đồ khối.......................................................................................................................................6
b. Sơ đồ chân và chức năng các chân.................................................................................7
Phần II: CODE – Mô phỏng các bài của nhóm........................................................................11
Bài 1 : Chớp tắt Led ( Huân).......................................................................................................11
Bài 2: ADC Đo nhiệt độ bằng LM35 (Huân)...............................................................................15
Bài 3:TEST ĐỘNG CƠ(DUY + Lê Quý Công )..........................................................................18
BÀI 4:COUNTER0(DUY)............................................................................................................22
Bài 5: Đo điện áp ( nếu điện áp lớn hơn 2.5v thì đèn sáng) (Trần Văn Đạt + Dương Văn Minh
+ Minh Thắng).............................................................................................................................25
Bài 6: Sử dụng timer0 để nháy led với chu kì 2ms (Đạt )............................................................32
Bài 7: HIỂN THỊ LCD DÙNG MODULE I2C PCF8574............................................................34
BÀI 8: Điều khiển bật tắt động cơ sử dụng UART (THẮNG + Đạt)...........................................42
BÀI 9 : Sử dụng vi điều khiển pic 16F877A để thiết kế hệ thống sau: Đọc và hiển thị nhiệt độ
lên led 7 thanh Điều chỉnh tốc độ của động cơ bằng PWM: - Nhiệt độ <=25 độ rộng xung 0% -
Nhiệt độ >25&<35 độ rộng xung 25% - Nhiệt độ >=35 độ rộn xung 35% (Nguyễn Văn
Chung)..........................................................................................................................................49
Bài 10: Cảnh báo khí gas và truyền dữ liệu qua UART(Hoàng Anh Thế-Nguyễn Văn Mạnh)...57
Bài 11: Giám sát nhiệt độ, độ ẩm, tưới cây tự động và truyền dữ liệu qua UART( Hoàng Anh
Thế + Nguyễn Văn Mạnh +Dương Văn Minh)............................................................................71
Bài 12: Truyền thông UART kết nối 2 pic sử dụng counter0 đếm sản phẩm hiển thị lên LED 7
thanh và điều khiển LED.( Dương Văn Minh + Nguyễn Văn Mạnh + Trân Văn Đạt)...............79
BÀI 13 : Cảm Biến Nhiệt Độ (Thanh An + Lương An)...............................................................83
Phần I: Khái quát về VXL
PIC16F877A
Giới thiệu
PIC16F877A có 40/44 chân với cấu trúc như sau:
 Có 5 PORT xuất/ nhập.
 Có 8 kênh chuyển đổi A/D.
 Được bổ sung các port tử song song.
 Có các bộ nhớ gap nối so với các PIC16F873A/PIC16F874A.

Tóm tắt đặc điểm của PIC16F877A


Sơ đồ khối
Sơ đồ khối của PIC gồm các khối.
 Khối ALU.
 Khối bộ nhớ chứa chương trình.
 Khối bộ nhớ chứa dữ liệu EPROM.
 Khối bộ nhớ file thanh ghi RAM.
 Khối giải mã lệnh và điều khiển.
 Khối thanh ghi đặc biệt.
 Khối ngoại vi timer.
 Khối giao tiếp nối tiếp.
 Khối chuyển đổi tín hiệu tương tự sang tín hiệu số.
 Khối các PORT xuất nhập.
b. Sơ đồ chân và chức năng các chân.

 Chân OSC1/CLKI (13): là ngõ vào kết nối với mạch dao động thạch
anh hoặc ngõ vào nhận xung clock bên ngoài.
 OSC1: ngõ vào dao động thạch anh hoặc ngõ vào nguồn xung
bên ngoài. Ngõ có mạch Schmitt Trigger nếu sử dụng dao động
RC.
 CLKI: ngõ vào nguồn xung bên ngoài.
 Chân OSC2/CLKO (14): ngõ ra dao động thạch anh hoặc ngõ ra
cấp xung clock.
 OSC2: ngõ ra dao động thạch anh. Kết nối với thạch anh hoặc
bộ cộng hưởng.
 CLKO: ở chế độ RC, ngõ ra của OSC2 bằng ¼ tần số của OSC1
và chính là tốc độ của chu kỳ lệnh.
 Chân MCLR/ Vpp (1): có 2 chức năng.
 MCLR: là ngõ vào reset tích cực ở mức thấp.
 Vpp: khi lập trình cho PIC thì đóng vai trò là ngõ vào nhận
điện áp lập trình
 Chân RA0/AN0 (2): có 2 chức năng.
 RA0: xuất nhập số.
 AN0: ngõ vào tương tự của kênh thứ 0.
 Chân RA1/AN1 (3): có 2 chức năng.
 RA1: xuất nhập số.
 AN1: ngõ vào tương tự của kênh thứ 1.
 Chân RA2/AN2/VREF-/CVREF (4):
 RA2: xuất nhập số.
 AN2: ngõ vào tương tự của kênh thứ 2.
 VREF- :ngõ vào điện áp chuẩn (thấp) của bộ A/D.
 CVREF: Điện áp tham chiếu VREF ngõ ra bộ so sánh.
 Chân RA3/AN3/VREF+ (5):
 RA3: xuất nhập số.
 AN3: ngõ vào tương tự của kênh thứ 3.
 VREF+: ngõ vào điện áp chuẩn (cao) của bộ A/D.
 Chân RA4/TOCKI/C1OUT (6):
 RA4: xuất nhập số.
 TOCKI: ngõ vào xung clock bên ngoài cho timer 0.
 C1OUT: ngõ ra bộ so sánh 1.
 Chân RA5/AN4/SS/C2OUT (7):
 RA5: xuất nhập số.
 AN4: ngõ vào tương tự của kênh thứ 4.
 SS: ngõ vào chọn lựa SPI phụ.
 C2OUT: ngõ ra bộ so sánh 2.
 Chân RB0/INT (33):
 RB0: xuất nhập số.
 INT: ngõ vào nhận tín hiệu ngắt ngoài.
 Chân RB1 (34): xuất nhập số.
 Chân RB2 (35): xuất nhập số.
 Chân RB3/PGC (36):
 Chân RB3: xuất nhập số.
 PGC: mạch gỡ rối và xung clock lập trình ICSP.
 Chân RB4 (37): xuất nhập số.
 Chân RB5 (38): xuất nhập số.
 Chân RB6/PGC (39):
 RB6: xuất nhập số.
 PGC: mạch gỡ rối và xung clock lập trình ICSP.
 Chân RB7/PGD (40):
 RB7: xuất nhập số.
 PGD: mạch gỡ rối và dữ liệu lập trình ICSP.
 Chân RC0/T1OCO/T1CKI (15):
 RC0: xuất nhập số.
 T1OCO: ngõ vào bộ dao động timer1.
 T1CKI: ngõ vào xung clock bên ngoài timer1.
 Chân RC1/T1OSI/CCP2 (16):
 RC1: xuất nhập số.
 T1OSI: ngõ vào bộ dao động timer 1.
 CCP2: ngõ vào Capture2, ngõ ra Compare2, ngõ ra PWM2.
 Chân RC2/CCP1 (17):
 RC2: xuất nhập số.
 CCP1: ngõ vào Capture1, ngõ ra Compare1, ngõ ra PWM1.
 Chân RC3/SCK/SCL (18):
 RC3: xuất nhập số.
 SCK: ngõ vào xung clock nối tiếp đồng bộ/ ngõ ra chế độ SPI.
 SCL: ngõ vào xung clock nối tiếp đồng bộ/ ngõ ra chế độ I2C.
 Chân RC4/SDI/SDA (23):
 RC4: xuất nhập số.
 SDI: dữ liệu vào SPI.
 SDA: xuất/nhập dữ liệu I2C.
 Chân RC5/SDO (24):
 RC5: xuất nhập số.
 SDO: dữ liệu ra SPI.
 Chân RC6/TX/CK (25):
 RC6: xuất nhập số.
 TX: truyền bất đồng bộ USART.
 CK: xung đồng bộ USART.
 Chân RC7/RX/DT (26):
 RC7: xuất nhập số.
 RX: nhận bất đồng bộ USART.
 DT: dữ liệu đồng bộ USART.
 Chân RD0/PSP0 (19):
 RD0: xuất nhập số.
 PSP0: dữ liệu port tớ song song.
 Chân RD1/PSP1 (20):
 RD1: xuất nhập số.
 PSP1: dữ liệu port tớ song song.
 Chân RD2/PSP2 (21):
 RD2: xuất nhập số.
 PSP2: dữ liệu port tớ song song.
 Chân RD3/PSP3 (22):
 RD3: xuất nhập số.
 PSP3: dữ liệu port tớ song song.
 Chân RD4/PSP4 (27):
 RD4: xuất nhập số.
 PSP4: dữ liệu port tớ song song.
 Chân RD5/PSP5 (28):
 RD5: xuất nhập số.
 PSP5: dữ liệu port tớ song song.
 Chân RD6/PSP6 (29):
 RD6: xuất nhập số.
 PSP6: dữ liệu port tớ song song.
 Chân RD7/PSP7 (30):
 RD7: xuất nhập số.
 PSP7: dữ liệu port tớ song song.
 Chân RE0/RD/AN5 (8):
 RE0: xuất nhập số.
 RD: điều khiển đọc port tớ song song.
 AN5: ngõ vào tương tự của kênh thứ 5.
 Chân RE1/WR/AN6 (9):
 RE1: xuất nhập số.
 WR: điều khiển ghi port tớ song song.
 AN6: ngõ vào tương tự của kênh thứ 6.
 Chân RE2/CS/AN7 (10):
 RE2: xuất nhập số.
 CS: chip chọn lựa điều khiển port tớ song song.
 AN7: ngõ vào tương tự của kênh thứ 7.
 Chân VDD (11,32) và VSS (12,31): là các chân nguồn của PIC.
Phần II: CODE – Mô phỏng các bài của nhóm
Bài 1 : Chớp tắt Led ( Huân)
CODE:
//Khai báo thư viện cần sử dụng
#include <pic.h>
#include <pic16f877a.h>
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
//Định nghĩa tần số xung clock 20MHz.
#define _XTAL_FREQ 20000000
//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 biến toàn cục
int d = 0;
//Hàm hiệu ứng 1. Chớp tắt các led so le nhau.
void hieuung1()
{
PORTD = 0b01010101; //0x55
delay_ms(500);
PORTD = 0b10101010; //0xCC
delay_ms(500);
}
//Hàm hiệu ứng 2. Led sáng ở từng bit của PORTD.
void hieuung2()
{
//Ta có thể sử dụng mảng hoặc dịch bit để đèn sáng.
//char Mang1[] = {0b10000000, 0b01000000, 0b00100000, 0b00010000, 0b00001000,
0b00000100, 0b00000010, 0b00000001};
PORTD = 0b10000000;
delay_ms(500); for(int j = 0; j<7 ;j++)
{
PORTD >>=1;
delay_ms(500);
}
}
//Hàm hiệu ứng 3. Các led 2 bên sáng dồn lại ở giữa.
void hieuung3 ()
{
char Mang2[] = {0b10000001, 0b11000011, 0b11100111, 0xff};
for(int j =0;j<4;j++)
{
PORTD = Mang2[j];
delay_ms (500);
}
}
//Chương trình chính.
void main(void)
{
TRISD = 0x00; //Khai báo PORTD là đầu ra dữ liệu. TRISBbits.TRISB1 = 1; //Khai báo
chân B1 là đầu vào. OPTION_REGbits.INTEDG = 1; //Cho phép ngắt cạnh lên.
INTCONbits.INTE = 1; //Cho phép ngắt ngoài.
INTCONbits.GIE = 1; //Cho phép ngắt toàn cục.

while(1)
{
//Với mỗi d thì sẽ cho chay hiệu ứng tương ứng.
if(d==1)
{
hieuung1();
}
if(d==2)
{
hieuung2();
}
if(d==3)
{
hieuung3();
}
}
}
//Hàm ngắt.
void interrupt NGAT(void)
{
if(INTCONbits.INTF == 1) //Khi có ngắt ngoài xảy ra.
{
d++;
if(d==4) //khi biến đếm = 4 thì trả về 1
{
d=1;
}
INTCONbits.INTF = 0; //Xóa cờ ngắt
}
}
Mô Phỏng

C1 R9
10k
U1
33pF 13 33
RB0/INT
X1 OSC1/CLKIN
OSC2/CLKOUT 34
C2 CRYSTAL 2
RB1
RA0/AN0 RB2
RB3/PGM 35
RA1/AN1
3
33pF RB4 36
RA2/AN2/VREF-/CVREF
4 RB5
RA3/AN3/VREF+
RA4/T0CKI/C1OUT RB6/PGC
15
RA5/AN4/SS/C2OUT
RC0/T1OSO/T1CKI
R10 8
RE0/AN5/RD RC1/T1OSI/CCP2
16
RE1/AN6/WR
10k 9
RE2/AN7/CS RC2/CCP1
17
RC3/SCK/SCL
1
MCLR/Vpp/THV RC4/SDI/SDA
RC5/SDO 18
RC6/TX/CK
RC7/RX/DT
19
RD0/PSP0
RD1/PSP1
20
RD2/PSP2
RD3/PSP3
RD4/PSP4 21
RD5/PSP5
RD6/PSP6 22
RD7/PSP7
PIC16F877A
Bài 2: ADC Đo nhiệt độ bằng LM35 (Huân)
Code
//Khai báo thư viện sử dụng
#include <pic.h>
#include <pic16f877a.h>
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
//Định nghĩa tần số thạch anh
#define _XTAL_FREQ 20000000
//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
//Dinh nghia cac chan su dung trong VXL
#define RS RD2 #define EN RD3 #define D4 RD4 #define D5 RD5 #define D6 RD6
#define D7 RD7
#include "LCD16x2.h" //Lấy thư viện LCD đã viết ở bài 2
//Khai báo biến cục bộ unsigned int value = 0; unsigned int voltage; float f;
//Hàm khởi tạo ADC.
void ADC_Init(void)
{
//Chọn tần số CLOCK cho ADC
ADCON1bits.ADCS2 = 0;
ADCON0bits.ADCS1 = 1;
ADCON0bits.ADCS0 = 0; //FOSC/32 ứng với tần số thạch anh 20MHz
//Chọn kênh đọc ADC
ADCON0bits.CHS2 = 0;
ADCON0bits.CHS1 = 0;
ADCON0bits.CHS0 = 0; // Chọn kênh 0
//Chọn cách lưu dữ liệu đọc được
ADCON1bits.ADFM = 1; //Lưu ở 10 bit thấp của 2 thanh ghi ADRESH và ADRESL
//Cấu hình cổng đầu vào

ADCON1bits.PCFG3 = 1;
ADCON1bits.PCFG2 = 1;
ADCON1bits.PCFG1 = 1;
ADCON1bits.PCFG0 = 0; // Kênh AN0 là tín hiệu tương tự còn các kênh khác là tín hiệu
số.
//Khởi động ADC
ADCON0bits.ADON = 1;
// Rút gọn:
// ADCON0 = 0x81;
// ADCON1 = 0x8E;
}
//Hàm đọc ADC
unsigned int ADC_Read()
{
unsigned int Tempvalue = 0; //Biến lưu giá trị đọc được ADCON0bits.GO_nDONE = 1;
//Cho quá trình chuyển đổi diễn ra while(ADCON0bits.GO_nDONE); //Đợi quá
trình chuyển đổi kết thúc Tempvalue = ((ADRESH<<8)+ADRESL); //Lấy giá trị đọc
được. return Tempvalue; //Trả giá trị về cho hàm
}
//Chương trình chính
void main(void)
{
TRISD = 0x03; //Định nghĩa các chân
PORTD = 0x00; TRISBbits.TRISB0 = 0;
PORTBbits.RB0 = 0;
TRISAbits.TRISA0 = 1;
PORTAbits.RA0 = 1;
Lcd_Init(); ADC_Init(); char str[20]; while(1)
{
value = ADC_Read(); //Lấy giá trị ADC đọc được
voltage = 5000.0f / 1023 * value; //Tính ra giá trị điện áp mV
f = voltage / 10; //Tính ra nhiệt độ
if(f<40) //Nếu nhiệt độ bé hơn 40 độ.
{
RB0 = 0; //Tắt chuông
sprintf(str, "NHIET DO = %g ", f); //Ghi dữ liệu vào chuỗi
Lcd_Set_Cursor(1,1); Lcd_Write_String(str);
Lcd_Write_Char(223); //Là dấu 0 trong bảng mã.

Lcd_Write_String("C"); Lcd_Set_Cursor(2,1); Lcd_Write_String(" GOOD! ");


}
else
{
RB0 = 1; //Bật chuông
Lcd_Set_ Cursor(1,1); Lcd_Write_String(“ WARNING! ”); Lcd_Set_Cursor(2,1)
Lcd_Write_String(“ NHIET DO CAO”);
}
}
}
Mô phỏng
C1 LM016L

pF
X1 U1 LS1
13 33
OSC1/CLKIN RB0/INT
CRYSTAL RB1
14 OSC2/CLKOUT 34
RB2
2
RA0/AN0 35
33pF RB3/PGM SPEAKER
RA1/AN1
3
36
U2 4
RA2/AN2/VREF-/CVREF RB4 RV1
1 RA3/AN3/VREF+ RB5
37
RA4/T0CKI/C1OUT RB6/PGC
5 15
RA5/AN4/SS/C2OUTRC0/T1OSO/T1CKI
39.0 R18 RE0/AN5/RD RC1/T1OSI/CCP2 16
10k 9 RE1/AN6/WR
1k
10
RE2/AN7/CS RC2/CCP1
2 17
VOUT RC3/SCK/SCL
1 RC4/SDI/SDA
MCLR/Vpp/THV 18
RC5/SDO
RC6/TX/CK 23
3 LM35 RC7/RX/DT
19
RD0/PSP0
RD1/PSP1 20
RD2/PSP2
RD3/PSP3 21
RD4/PSP4
RD5/PSP5 22
RD6/PSP6
RD7/PSP7 27
PIC16F877A

Bài 3:TEST ĐỘNG CƠ(DUY + Lê Quý Công )


CODE
#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 = ON // Brown-out Reset Enable bit (BOR enabled)
#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)
#include<xc.h>
#include<stdio.h>
#include<stdlib.h>

#define _XTAL_FREQ 20000000


void main(){
TRISB0=0;
TRISB1=0;
TRISB2=0;
TRISB3=0;
TRISD0=1;
TRISD1=1;
if (RD0==0) {

RB0=1;
RB1=0;
RB2=0;
RB3=0;
__delay_ms(500);
RB0=0;
RB1=1;
RB2=0;
RB3=0;
__delay_ms(500);
RB0=0;
RB1=0;
RB2=1;
RB3=0;
__delay_ms(500);
RB0=0;
RB1=0;
RB2=0;
RB3=1;
__delay_ms(500);

}
if (RD1==0) {

RB0=0;
RB1=0;
RB2=0;
RB3=1;
__delay_ms(500);
RB0=0;
RB1=0;
RB2=1;
RB3=0;
__delay_ms(500);
RB0=0;
RB1=1;
RB2=0;
RB3=0;
__delay_ms(500);
RB0=1;
RB1=0;
RB2=0;
RB3=0;
__delay_ms(500);

}
}
MẠCH MÔ PHỎNG
BÀI 4:COUNTER0(DUY)
CODE
#pragma config FOSC = HS
#pragma config WDTE = ON
#pragma config PWRTE = OFF
#pragma config BOREN = ON
#pragma config LVP = ON

#pragma config CPD = OFF

#pragma config WRT = OFF

#pragma config CP = OFF

#include <xc.h>
#include <pic.h>
#include <pic16f877a.h>
#define _XTAL_FREQ 20000000
int chuc,donvi,tram,nghin;
unsigned int a = 0;
unsigned char LED[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
0x7F,0x6F};
void hien_thi()
{
nghin = a/1000;
tram = (a%1000)/100;
chuc = (a%100)/10;
donvi = a%10;
PORTB = LED[nghin];
RC0=0;
__delay_ms(10);
RC0=1;
__delay_ms(10);
PORTB = LED[tram];
RC1=0;
__delay_ms(10);
RC1=1;
PORTB = LED[chuc];
RC2=0;
__delay_ms(10);
RC2=1;
PORTB = LED[donvi];
RC3=0;
__delay_ms(10);
RC3=1;
}
void main(void) {
TRISA4 = 1;
TRISB = 0;
TRISC = 0;
PORTB = 0;
OPTION_REGbits.T0CS=1;
OPTION_REGbits.PSA=1;
while(1){
hien_thi();
a = TMR0;
if(a>=20){
TMR0 = 0;
a = 0;
}
}
}
MẠCH MÔ PHỎNG
Bài 5: Đo điện áp ( nếu điện áp lớn hơn 2.5v thì đèn sáng) (Trần Văn Đạt +
Dương Văn Minh + Minh Thắng)
Code
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <pic.h>
#include <pic16f877a.h>

// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#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
#define _XTAL_FREQ 20000000

#define rs RC0
#define rw RC1
#define en RC2
#define data PORTD

// ad HÀM C? B?N LCD

void cmd(unsigned char a){

rs=0; // ch?n ch? ?? g?i l?nh


rw=0; // ch?n ch? ?? ghi l?nh

data&=0x0F; // tách 4 bit ??u g?i tr??c, phép tính and bit
data|=(a&0xF0);
en=1;
__delay_us(100);
en=0;
__delay_us(100);

data&=0x0f;
data|=(a<<4&0xf0); // tách ???c 4 bit sau g?i tr??c, <<4 d?ch 4 bit sang trai
en=1;
__delay_us(100);
en=0;
__delay_us(100);

}
void lcd_init() //hàm kh?i t?o lcd
{
cmd(0x02);
cmd(0x28); // lcd 4bit 2 dòng
cmd(0x0C); //t?t con tr?
cmd(0x06); // ??a v? trí con tr? ??n v? trí ti?p theo sau khi hi?n th?
cmd(0x80); // ??a con tr? v? ??u dòng 1
}

void dat(unsigned char b){


data=b;
rs=1;
rw=0;

data&=0x0F;
data|=(b&0xF0);
en=1;
__delay_us(100);
en=0;
__delay_us(100);

data&=0x0f;
data|=(b<<4&0xf0);
en=1;
__delay_us(100);
en=0;
__delay_us(100);
}

void show(unsigned char *s) // hàm th?c hi?n g?i liên t?c nhi?u ký t? thành 1 chu?i
{
while(*s){
dat(*s++);
}
}

// TH? VI?N CHO ADC


unsigned int ReadAdc(unsigned char Channel)
{
unsigned int value;
switch(Channel)
{
case 0: CHS0=0; CHS1= 0; CHS2=0; break; // kênh AN0
case 1: CHS0=1; CHS1= 0; CHS2=0; break; // kênh AN1
case 2: CHS0=0; CHS1= 1; CHS2=0; break;
case 3: CHS0=1; CHS1= 1; CHS2=0; break;
case 4: CHS0=0; CHS1= 0; CHS2=1; break;
case 5: CHS0=1; CHS1= 0; CHS2=1; break;
case 6: CHS0=0; CHS1= 1; CHS2=1; break;
case 7: CHS0=1; CHS1= 1; CHS2=1;
}
ADON=1; // B?T ADC
__delay_ms(100);
GO_DONE=1; // b?t ??u ??c adc
while(GO_DONE);
value=((ADRESH<<8) + ADRESL);// GHI D? LI?U ??C VÀO BI?N VALUE
ADON=0; //T?T ADC
return value;
}

void hienthi(int a)
{
int x,y,z,t;
x=a/1000;
y=a%1000/100;
z= a%1000%100/10;
t=a%1000%100%10;

dat(x+0x30);
dat(y+0x30);
dat(z+0x30);
dat(t+0x30);

}
void dienap(float a)
{
int dienap = (a/1023)*500;
int x,y,z;
x=dienap/100;
y=dienap%100/10;
z=dienap%100%10;
dat(x+0x30);

dat('.');
dat(y+0x30);
dat(z+0x30);
}

void main(void) {

TRISC =0;
TRISD =0;
TRISA=1; // C?NG A NH?N D? LI?U

// CÀI ??T LCD


lcd_init();

// CÀI ??T ADC


ADCON1=0X80; //K?T QU? DÔN SANG PH?I, DÙNG T?T C? KÊNH ADC
ADCS1=1; //OSC N?I
ADCS0=1; // OSC N?I

while(1){
cmd(0x01);
dienap(ReadAdc(0));
__delay_ms(1000);
int a= ReadAdc(0);
if( a >=512 ) // neu dien áp lon hon 2.5 vôn thì dèn sáng

{
RC5=1;
}
else RC5=0;

}
Bài 6: Sử dụng timer0 để nháy led với chu kì 2ms (Đạt )
Code
#include <xc.h>
#include <pic.h>
#include <pic16f877a.h>

// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = ON
#pragma config PWRTE = OFF
#pragma config BOREN = ON
#pragma config LVP = ON
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
#define _XTAL_FREQ 20000000
void delay_timer0_ms(int t)
{

for(int i=0;i<t;i++){
// delay 1ms dùng timer0
TMR0=100;//
while(!TMR0IF);
TMR0IF=0;//xóa c? tràn

}
}

void main()
{
TRISB=0;
T0CS=0;
PSA=0;
PS2=1;
PS1=0;
PS0=0;
while(1)
{
RB1=1;
delay_timer0_ms(2);
RB1=0;
delay_timer0_ms(2);

}
}
Bài 7: HIỂN THỊ LCD DÙNG MODULE I2C PCF8574
( Lê Quý Công )
• CODE:
• Khai báo thư viện i2c.c

#include <xc.h> #include "I2C.h"


unsigned char RS, i2c_add, BackLight_State = LCD_BACKLIGHT;
void I2C Init()
{
SSPCON = 0x28;
SSPCON2 = 0x00;
SSPSTAT = 0x00;
SSPADD = ((_XTAL_FREQ/4)/I2C_BaudRate) - 1; SCL_D = 1;

SDA_D = 1;
}
void I2C Wait()
{
while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}
void I2C Start()
{
I2C Wait();
SEN = 1;

}
void I2C RepeatedStart()
{
I2C Wait();
RSEN = 1;
}
void I2C Stop()
{
I2C Wait();
PEN = 1;
}
void I2C_ACK(void)
{
ACKDT = 0;
I2C Wait();
ACKEN = 1;

}
void I2C_NACK(void)
{
ACKDT = 1;
I2C Wait();
ACKEN = 1;

}
unsigned char I2C Write(unsigned char data)
{
I2C Wait();
SSPBUF = data; while(!
SSPIF); SSPIF = 0;
return ACKSTAT;
}
unsigned char I2C_Read_Byte(void)
{
I2C Wait();
RCEN = 1;

while(!SSPIF);
SSPIF = 0;
I2C Wait(); return
SSPBUF;

}
void LCD_Init(unsigned char I2C_Add)
{
i2c_add = I2C_Add; IO_Expander_Write(0x00);
delay_ms(30);
LCD_CMD(0x03);
delay_ms(5);
LCD_CMD(0x03);
delay_ms(5);
LCD_CMD(0x03);
delay_ms(5); LCD_CMD(LCD_RETURN_HOME);
delay_ms(5);
LCD_CMD(0x20 | (LCD_TYPE << 2));
delay_ms(50);
LCD_CMD(LCD_TURN_ON);
delay_ms(50);
LCD_CMD(LCD_CLEAR);
delay_ms(50); LCD_CMD(LCD_ENTRY_MODE_SET |
LCD_RETURN_HOME);
delay_ms(50);
}
void IO_Expander_Write(unsigned char Data)
{
I2C Start();
I2C Write(i2c_add);
I2C Write(Data | BackLight_State); I2C Stop();

void LCD_Write_4Bit(unsigned char Nibble)


{

Nibble |= RS; IO_Expander_Write(Nibble | 0x04);


IO_Expander_Write(Nibble & 0xFB);
delay_us(50);
}

void LCD_CMD(unsigned char CMD)


{
RS = 0;
LCD_Write_4Bit(CMD & 0xF0); LCD_Write_4Bit((CMD << 4) & 0xF0);
}

void LCD_Write_Char(char Data)


{
RS = 1;
LCD_Write_4Bit(Data & 0xF0); LCD_Write_4Bit((Data << 4) &
0xF0); }
void LCD_Write_String(char* Str)
{ for(int i=0; Str[i]!='\0'; i++)
LCD_Write_Char(Str[i]);
}

void LCD_Set_Cursor(unsigned char ROW, unsigned char COL)


{
switch(ROW)
{
case 2:
LCD_CMD(0xC0 + COL-1);
break;
case 3:
LCD_CMD(0x94 + COL-1);
break;
case 4:
LCD_CMD(0xD4 + COL-1);
break;
// Case 1 default:
LCD_CMD(0x80 + COL-1);
}}
void Backlight()
{
BackLight_State = LCD_BACKLIGHT; IO_Expander_Write(0);
}
void noBacklight()
{
BackLight_State = LCD_NOBACKLIGHT; IO_Expander_Write(0);

}
void LCD_SL()
{
LCD_CMD(0x18);
delay_us(40);
}
void LCD_SR()
{
LCD_CMD(0x1C);
delay_us(40);
}
void LCD_Clear()
{
LCD_CMD(0x01);
delay_us(40);
}

• Khai Báo thư viện i2c.h


#define _XTAL_FREQ 16000000
#define I2C_BaudRate 100000
#define SCL_D TRISC3
#define SDA_D TRISC4 #define
LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00 #define LCD_FIRST_ROW
0x80
#define LCD_SECOND_ROW 0xC0 #define LCD_THIRD_ROW
0x94
#define LCD_FOURTH_ROW 0xD4
#define LCD_CLEAR 0x01
#define LCD_RETURN_HOME 0x02
#define LCD_ENTRY_MODE_SET 0x04 #define
LCD_CURSOR_OFF 0x0C #define
LCD_UNDERLINE_ON 0x0E #define
LCD_BLINK_CURSOR_ON 0x0F #define
LCD_MOVE_CURSOR_LEFT 0x10 #define
LCD_MOVE_CURSOR_RIGHT 0x14 #define LCD_TURN_ON
0x0C
#define LCD_TURN_OFF 0x08
#define LCD_SHIFT_LEFT 0x18
#define LCD_SHIFT_RIGHT 0x1E
#define LCD_TYPE

void I2C Init(); void


I2C Wait(); void I2C
Start(); void
I2C RepeatedStart(); void I2C
Stop(); void I2C_ACK(); void
I2C_NACK();
unsigned char I2C Write(unsigned char data); unsigned
char I2C_Read_Byte(void); void LCD_Init(unsigned char I2C_Add);
void IO_Expander_Write(unsigned char Data); void
LCD_Write_4Bit(unsigned char Nibble); void LCD_CMD(unsigned
char CMD);
void LCD_Set_Cursor(unsigned char ROW, unsigned char COL);
void LCD_Write_Char(char); void LCD_Write_String(char*);
void Backlight(); void
noBacklight(); void LCD_SR();
void LCD_SL(); void
LCD_Clear();

• Chương trình chính:


#include <xc.h> #include
"config.h" #include "I2C.h" void
main(void) {
I2C Init(); LCD_Init(0x4E);
LCD_Set_Cursor(1, 1);
LCD_Write_String("Nice to meet you"); LCD_Set_Cursor(2, 1);
LCD_Write_String("Haha");

delay_ms(2500); while(1)
{ }
return;
}

• MÔ PHỎNG:

BÀI 8: Điều khiển bật tắt động cơ sử dụng UART (THẮNG + Đạt)
#include <xc.h>

#include <pic.h>

#include <pic16f877a.h>

#define RS RD0
#define EN RD1

#define D4 RD4

#define D5 RD5

#define D6 RD6

#define D7 RD7

// 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

#define _XTAL_FREQ 20000000

#define TRISTX TRISCbits.TRISC6

#define TRISRX TRISCbits.TRISC7

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_Init() {

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_Clear() {

Lcd_Cmd(0);

Lcd_Cmd(1);

void Lcd_Set_Cursor(char a, char b) {

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_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;

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() {

Lcd_Cmd(0x01);

Lcd_Cmd(0x0C);
}

void Lcd_Shift_Left() {

Lcd_Cmd(0x01);

Lcd_Cmd(0x08);

void IO_Init(){

TRISTX=0;//TX la dau ra truyen du lieu

TRISRX=1;//RX la chan dau vao nhan du lieu

void uart_init() {

SPBRG = 129;//baurate=9600

TXSTAbits.SYNC=0;

TXSTAbits.BRGH=1; // for high baud_rate

RCSTAbits.SPEN=1;

TXSTAbits.TXEN=1;

RCSTAbits.SREN=1;

RCSTAbits.CREN=1;

TX9 = 0; // 8-bit reception selected

RX9 = 0; // 8-bit reception mode selected

char UART_Receive()

while(!RCIF);

return RCREG;

void putchUART(unsigned char data) {

while (TXIF == 0);

TXREG = data;

void putsUART(unsigned char *data) {

while (*data) {

while (TXIF == 0);

TXREG = *data++;
}

void main()

{int get_value;

TRISB1=0;

TRISC6 = 0;

TRISC7 = 1;

TRISD = 0X00;

PORTD = 0X00;

uart_init();

Lcd_Init();

Lcd_Clear();

putsUART("CHON CHE DO O=ON/F=OFF \r\n ");

while (1) {

get_value = UART_Receive();

if (get_value == 'O')

PORTBbits.RB1=1;

Lcd_Set_Cursor(1, 1);

Lcd_Write_String("OPERATING MODE");

Lcd_Set_Cursor(2, 1);

Lcd_Write_String(" START ");

__delay_ms(10);

putsUART("DONG CO DANG CHAY \r\n ");

if(get_value == 'F')

PORTBbits.RB1=0;

Lcd_Set_Cursor(1, 1);

Lcd_Write_String("OPERATING MODE");

Lcd_Set_Cursor(2, 1);

Lcd_Write_String(" STOP ");


__delay_ms(10);

putsUART("DONG CO DA STOP \r\n ");

Ảnh khi chạy


BÀI 9 : Sử dụng vi điều khiển pic 16F877A để thiết kế hệ thống sau: Đọc và
hiển thị nhiệt độ lên led 7 thanh Điều chỉnh tốc độ của động cơ bằng PWM: -
Nhiệt độ <=25 độ rộng xung 0% - Nhiệt độ >25&<35 độ rộng xung 25% - Nhiệt
độ >=35 độ rộn xung 35% (Nguyễn Văn Chung)
 Code
#include <stdio.h>
#include <stdlib.h>
#include <pic.h>
#include <pic16f877a.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)

// #pragma config statements should precede project file includes.


// Use project enums instead of #define for ON and OFF.
#define _XTAL_FREQ 8000000
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
#include <xc.h>

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;
Lcd_Port(a);
EN = 1;
__delay_ms(4);
EN = 0; }
void Lcd_Init() {
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_Clear(){
Lcd_Cmd(0);
Lcd_Cmd(1);
}
void Lcd_Set_Cursor(char a, char b){
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_Write_Char(char a)
{
char temp,y;
temp = a&0x0F;
y = a&0xF0;
RS = 1;
Lcd_Port(y>>4);
EN = 1;
__delay_us(40);
EN = 0;
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()
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x0C);
}
void Lcd_Shift_Left()
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x08);
}

void ADC_Init()
{
ADCON0 = 0x89;
ADCON1 = 0x80;
}

unsigned int ADC_Read(unsigned char channel)


{
if(channel>7)
return 0;
ADCON0 &= 0xCD;
ADCON0 |= channel<<3;
__delay_ms(2);
GO_nDONE = 1;
while(GO_nDONE);
return((ADRESH<<8)+ADRESL);
}
void main()
{
unsigned int aa;
TRISA = 1;
TRISB = 0;
TRISD = 0;
TRISC = 0;
char s[20];
float nhietdo;
Lcd_Init();
ADC_Init();
while(1){
aa= ADC_Read(0);

nhietdo=(aa*100.0)/1023;
sprintf(s,"NHIET DO: %f",nhietdo);
Lcd_Set_Cursor(1,1);
Lcd_Write_String(s);
if(nhietdo>=30)
{RB0=1;
RC0 = 1;}
else {
RB0=0;
RC0 = 0;
}
}
}
 Chạy Chương Trình :
- Nhiệt độ >25&<35 độ rộng xung 25%

- Nhiệt độ >=35 độ rộn xung 35%


Bài 10: Cảnh báo khí gas và truyền dữ liệu qua UART(Hoàng Anh Thế-
Nguyễn Văn Mạnh)

a. Đặt bài toán


Bài toán: Sử dụng vi điều khiển PIC 16F877A để phát hiện, cảnh báo khi có khí
gas với các yêu cầu sau:
 Khi không có khí gas thì báo đèn xanh và hiển thị “KHONG CO KHI
GAS” / “AN TOAN” trên màn hình LCD.
 Khi có khí gas thì báo đèn đỏ, bật chuông báo động, bật quạt để thổi khí gas
và hiển thị “CO KHI GAS” / “NG.HIEM MO QUAT” đồng thời truyền cảnh
báo qua UART.
b. Các linh kiện sử dụng
Sử dụng các linh kiện:
 Cảm biến khí gas MQ-3
 Màn hình LCD 16x2
 Chuông báo Buzzer
 Motor DC 12V
 Opto quang
 Đèn led
 Điện trở
 Nút nhấn
 Transistor
c. Thiết kế mạch phần cứng

d. Chương trình điều khiển


 File main.c

/*

* File: bai7_khigas.c

* Author: Hoang Anh The

*/

// PIC16F877A Configuration Bit Settings


// 'C' source line config statements

// CONFIG

#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)

#pragma config WDTE = ON // Watchdog Timer Enable bit (WDT enabled)

#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT


disabled)

#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)

#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)

// #pragma config statements should precede project file includes.

// Use project enums instead of #define for ON and OFF.

#include "LCD.h"

#define _XTAL_FREQ 20000000

#include <xc.h>

#define den1 RC0

#define den2 RC1

#define coi RC2

#define quat RC3


void port_init() {

TRISC6 = 0; // chân TX truy?n d? li?u

TRISC7 = 1; // chân RX nh?n d? li?u

TRISD = 0X00; // c?u hình chân lcd

PORTD = 0X00;

// hàm cài ??t ch? ?? truy?n

void uart_init() {

BRGH = 1; //high speed baud rate

TXSTAbits.SYNC = 0; //không ??ng b?

SPBRG = 129; // baurate=Fosc/(16(X+1)) v?i X=SPBRG

TXSTAbits.TXEN = 1;

RCSTAbits.SPEN = 1; // Serial port enable

TXSTAbits.TX9 = 0; // không dùng bit th? 9

PIE1bits.TXIE = 1; // ng?t tràn

INTCONbits.GIE = 1; // ng?t toàn c?c

INTCONbits.PEIE = 1; // ng?t ngo?i vi

void putsUART(unsigned char *data) // ham truyen mot chuoi ky tu

{
while (*data) {

while (TXIF == 0);

TXREG = *data++;

void main(void) {

char s1[20];

char s2[20];

TRISB = 0XFF;

RB0 = 0;

TRISC = 0X00;

TRISD = 0x00;

Lcd_Init();

Lcd_Clear();

port_init();

uart_init();

while (1) {

if (RB0 == 0) {

sprintf(s1, "KHONG CO KHI GAS");

Lcd_Set_Cursor(1, 1);

Lcd_Write_String(s1);

sprintf(s2, " AN TOAN");


Lcd_Set_Cursor(2, 1);

Lcd_Write_String(s2);

den1 = 1; // bat den xanh

den2 = 0; // tat den do

coi = 0; // tat coi bao dong

quat = 0;

if (RB0 == 1) break; // neu RB0=1 thi thoat ra ngoai

} else if (RB0 == 1) {

sprintf(s1, " CO KHI GAS ");

Lcd_Set_Cursor(1, 1);

Lcd_Write_String(s1);

sprintf(s2, " NG.HIEM MO QUAT");

Lcd_Set_Cursor(2, 1);

Lcd_Write_String(s2);

den1 = 0; // tat den xanh

den2 = 1; // bat den do

coi = 1; // bat coi bao dong

quat = 1; //

putsUART("CO KHI GAS - NGUY HIEM - MO QUAT\n\r");

__delay_ms(200);

if (RB0 == 0) break; // neu RB0=0 thi thoat ra ngoai

}
}

 File LCD.h

#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)

#pragma config WDTE = ON // Watchdog Timer Enable bit (WDT enabled)

#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT


disabled)

#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)

#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)

// #pragma config statements should precede project file includes.

// Use project enums instead of #define for ON and OFF.

#include <xc.h>

//??nh ngh?a các chân s? d?ng cho LCD

#define RS RD2

#define EN RD3

#define D4 RD4
#define D5 RD5

#define D6 RD6

#define D7 RD7

//Khai báo th? vi?n c?n s? d?ng

#include <pic.h>

#include <pic16f877a.h>

#include <xc.h>

#include <stdio.h>

#include <stdlib.h>

#define _XTAL_FREQ 20000000

//CONFIG

#pragma config FOSC = HS

#pragma config WDTE = ON

#pragma config PWRTE = OFF

#pragma config BOREN = ON

#pragma config LVP = OFF

#pragma config CPD = OFF

#pragma config WRT = OFF

#pragma config CP = OFF

//Hàm tách 8 bit thành 4 bit sau g?i vào LCD

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;

//hàm g?i l?nh lên LCD

void Lcd_Cmd(char a) {

RS = 0; // Chân RS xu?ng m?c 0 s? là g?i l?nh lên LCD

Lcd_Port(a); //G?i d? li?u vào LCD.

EN = 1; //T?o xung nh?p ?? truy?n d? li?u vào sau khi nh?n ??.

__delay_ms(4); //Tr? ?? LCD th?c thi l?nh


EN = 0;

//hàm xóa màn hình

void Lcd_Clear() {

Lcd_Cmd(0);

Lcd_Cmd(1); //Xóa hi?n th? và ??a con tr? v? v? trí ban ??u

//Hàm thi?t l?p v? trí con tr? v? hàng a và c?t b

void Lcd_Set_Cursor(char a, char b) {

char temp, z, y;

if (a == 1) //N?u là hàng 1

temp = 0x80 + b - 1; //Tính ra ???c l?nh ?? xu?t ??a ch? c?a con tr?

z = temp >> 4; //Tách temp ra 2 d? li?u 4 bit ?? g?i lên LCD.

y = temp & 0x0F;

Lcd_Cmd(z);

Lcd_Cmd(y);

} else if (a == 2) //T??ng t? n?u là hàng 2

temp = 0xC0 + b - 1;

z = temp >> 4;
y = temp & 0x0F;

Lcd_Cmd(z);

Lcd_Cmd(y);

//Hàm kh?i t?o LCD.

void Lcd_Init() {

//Các l?nh th?c hi?n ?? kh?i t?o LCD gi?ng nh? trong datasheet.

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);

//Hàm g?i 1 ký t? lên LCD.

void Lcd_Write_Char(char a) {

char temp, y;

temp = a & 0x0F; //Tách a ra làm 2 hai d? li?u 4 bit

y = a & 0xF0;

RS = 1; //Chân RS = 1. G?i d? li?u lên LCD.

Lcd_Port(y >> 4);

EN = 1; //T?o xung ?? truy?n d? li?u vào LCD.

__delay_us(40);

EN = 0;

Lcd_Port(temp);

EN = 1;

__delay_us(40);

EN = 0;

//Hàm g?i 1 chu?i ký t? lên LCD.

void Lcd_Write_String(char *a) {

int i;

for (i = 0; a[i] != '\0'; i++) //S? d?ng for() ?? xu?t ra t?ng ký t?


Lcd_Write_Char(a[i]);

//Hàm d?ch LCD sang ph?i 1 c?t.

void Lcd_Shift_Right() {

Lcd_Cmd(0x01);

Lcd_Cmd(0x0C);

//hàm d?ch LCD sang trái 1 c?t.

void Lcd_Shift_Left() {

Lcd_Cmd(0x01);

Lcd_Cmd(0x08);

}
e. Kết quả mô phỏng
 TH không có khí gas
 TH có khí gas
Bài 11: Giám sát nhiệt độ, độ ẩm, tưới cây tự động và truyền dữ liệu qua

UART( Hoàng Anh Thế + Nguyễn Văn Mạnh +Dương Văn Minh)
a. Đặt bài toán
Bài toán: Sử dụng vi điều khiển 16F877A dể giám sát và điều khiển nhiệt độ và độ ẩm cho cây
với các chức năng sau:
• Đọc nhiệt độ và độ ẩm từ cảm biến rồi hiển thi lên màn hình LCD.
• Khi nhiệt độ dưới 10oC thì bật đèn để sưởi ấm cho cây đồng thời gửi thông báo qua màn
hình LCD và gửi thông báo qua UART.
• Khi độ ẩm dưới 30% thì bật máy bơm để bổ sung đô ẩm cho cây đồng thời gửi thông báo
qua màn hình LCD và gửi thông báo qua UART.
b. Các linh kiện sử dụng
Sử dụng các linh kiện:
• Màn hình LCD
• Relay
• Motor
• Đèn led
• Cảm biến
• Điện trở
• OPAM
c. Thiết kế mạch phần cứng

d. Code
 File main.c
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 20000000

#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7

#include <pic16f877a.h>
#include <xc.h>
#include "LCD.h"

#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)


#pragma config WDTE = ON // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#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)

unsigned int gtADC;


unsigned int da;
int t=0,d=0;
char s[20], m[20];

void ADC_Init()
{
ADCON0 = 0x81; //kênh AN0 tan so/32, kich ADC
ADCON1 = 0x84;// 6 bits cao khong su dung, sd 3 kenh ADC AN0 AN1 AN3
}
unsigned int ADC_Read(unsigned char channel)
{
if(channel > 7)
return 0;
ADCON0 |= channel<<3;
__delay_ms(2);
GO_nDONE = 1;
while(GO_nDONE);
return ((ADRESH<<8)+ADRESL);
}
void port_init()
{
TRISC6 = 0;// chân TX truyền dữ liệu
TRISC7 = 1; // chân RX nhận dữ liệu
TRISD = 0X00; // cấu hình chân LCD
PORTD = 0X00;
}
void uart_init()
{
BRGH = 1; //high speed baud rate
TXSTAbits.SYNC = 0; //không đồng bộ
SPBRG = 129; // baurate=Fosc/(16(X+1)) với X=SPBRG
TXSTAbits.TXEN = 1;
RCSTAbits.SPEN = 1; // Serial port enable
TXSTAbits.TX9 = 0; // không dùng bit thứ 9
PIE1bits.TXIE = 1; // ngắt tràn
INTCONbits.GIE = 1; // ngắt toàn cục
INTCONbits.PEIE = 1; // ngắt ngoại vi
}
void putchUART(unsigned char data) {
while (TXIF == 0);
TXREG = data;
}
void putsUART(unsigned char *data) {
while (*data) {
while (TXIF == 0);
TXREG = *data++;
}
}

void main(void)
{
ADC_Init();
TRISD = 0x00;
TRISB=0x00;
TRISC=0xFF;
TRISA=0xFF;
Lcd_Init();
Lcd_Clear();
port_init();
uart_init();
RB0=0;
RB1=0;
while(1)
{
gtADC = ADC_Read(0);
t = gtADC*100.f/1023;

if(t<10)
{
Lcd_Clear();
sprintf(s, "ND=%d BAT DEN", t);
Lcd_Set_Cursor(1,1) ;
Lcd_Write_String(s);
RB0=1;
putsUART("NHIET DO THAP BAT DEN SUOI AM\n\r");
__delay_ms(100);

}
else
{
Lcd_Clear();
sprintf(s, "ND=%d TAT DEN", t);
Lcd_Set_Cursor(1,1) ;
Lcd_Write_String(s);
RB0=0;
__delay_ms(100);

}
if(RC0==1)
{
sprintf(m, "DA DUOI 30 T.NC");
Lcd_Set_Cursor(2,1) ;
Lcd_Write_String(m);
RB1=1;
putsUART("DO AM THAP BAT MAY BOM TUOI NUOC\n\r");
__delay_ms(100);
}
else if(RC0==0)
{
sprintf(m, "DA TREN 30 D.NC");
Lcd_Set_Cursor(2,1) ;
Lcd_Write_String(m);
RB1=0;
__delay_ms(100);
}
}
}

 File LCD.h
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = ON // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#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)

// #pragma config statements should precede project file includes.


// Use project enums instead of #define for ON and OFF.

#include <xc.h>
//??nh ngh?a các chân s? d?ng cho LCD
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
//Khai báo th? vi?n c?n s? d?ng
#include <pic.h>
#include <pic16f877a.h>
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 20000000
//CONFIG
#pragma config FOSC = HS
#pragma config WDTE = ON
#pragma config PWRTE = OFF
#pragma config BOREN = ON
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
//Hàm tách 8 bit thành 4 bit sau g?i vào LCD

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;
}
//hàm g?i l?nh lên LCD

void Lcd_Cmd(char a) {
RS = 0; // Chân RS xu?ng m?c 0 s? là g?i l?nh lên LCD
Lcd_Port(a); //G?i d? li?u vào LCD.
EN = 1; //T?o xung nh?p ?? truy?n d? li?u vào sau khi nh?n ??.
__delay_ms(4); //Tr? ?? LCD th?c thi l?nh
EN = 0;
}
//hàm xóa màn hình

void Lcd_Clear() {
Lcd_Cmd(0);
Lcd_Cmd(1); //Xóa hi?n th? và ??a con tr? v? v? trí ban ??u
}
//Hàm thi?t l?p v? trí con tr? v? hàng a và c?t b

void Lcd_Set_Cursor(char a, char b) {


char temp, z, y;
if (a == 1) //N?u là hàng 1
{
temp = 0x80 + b - 1; //Tính ra ???c l?nh ?? xu?t ??a ch? c?a con tr?
z = temp >> 4; //Tách temp ra 2 d? li?u 4 bit ?? g?i lên LCD.
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
} else if (a == 2) //T??ng t? n?u là hàng 2
{
temp = 0xC0 + b - 1;
z = temp >> 4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
}
}
//Hàm kh?i t?o LCD.

void Lcd_Init() {
//Các l?nh th?c hi?n ?? kh?i t?o LCD gi?ng nh? trong datasheet.
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);
}
//Hàm g?i 1 ký t? lên LCD.

void Lcd_Write_Char(char a) {
char temp, y;
temp = a & 0x0F; //Tách a ra làm 2 hai d? li?u 4 bit
y = a & 0xF0;
RS = 1; //Chân RS = 1. G?i d? li?u lên LCD.
Lcd_Port(y >> 4);
EN = 1; //T?o xung ?? truy?n d? li?u vào LCD.
__delay_us(40);
EN = 0;
Lcd_Port(temp);
EN = 1;
__delay_us(40);
EN = 0;
}
//Hàm g?i 1 chu?i ký t? lên LCD.

void Lcd_Write_String(char *a) {


int i;
for (i = 0; a[i] != '\0'; i++) //S? d?ng for() ?? xu?t ra t?ng ký t?
Lcd_Write_Char(a[i]);
}
//Hàm d?ch LCD sang ph?i 1 c?t.

void Lcd_Shift_Right() {
Lcd_Cmd(0x01);
Lcd_Cmd(0x0C);
}
//hàm d?ch LCD sang trái 1 c?t.

void Lcd_Shift_Left() {
Lcd_Cmd(0x01);
Lcd_Cmd(0x08);
}

e. Kết quả mô phỏng

Bài 12: Truyền thông UART kết nối 2 pic sử dụng counter0 đếm sản phẩm hiển thị

lên LED 7 thanh và điều khiển LED.( Dương Văn Minh + Nguyễn Văn Mạnh + Trân

Văn Đạt)

a) Phần cứng
b) Code
 File truyền
#include <xc.h>
#include <pic.h>
#include <pic16f877a.h>
// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = ON
#pragma config PWRTE = ON
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF
#define _XTAL_FREQ 20000000
unsigned int dem = 0,chuc,donvi;
const unsigned char maled[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80,
0x90};
void hien_thi()
{
chuc = dem/10;
donvi = dem%10;
PORTB = maled[chuc];
RD0=0;
__delay_ms(10);
RD0=1;
PORTB = maled[donvi];
RD1=0;
__delay_ms(10);
RD1=1;
}

void UART_Send(unsigned char data) {


while (!TXIF);
TXREG = data;
}

void main()
{
TRISA4=1;
TRISB = 0;
PORTB = 0;
TRISD0 = 0;
TRISD1 = 0;
OPTION_REGbits.T0CS = 1;
OPTION_REGbits.PSA = 1;

TXSTAbits.TXEN = 1;
SPBRG = 31;
RCSTAbits.SPEN = 1;
RCSTAbits.CREN = 1;

while (1)
{
hien_thi();
dem=TMR0;
if(dem>=9)
{
TMR0=0;
dem=0;
}
TXREG = dem;
while (!TXSTAbits.TRMT);
}
}

 File nhận
#include <xc.h>
#include <pic.h>
#include <pic16f877a.h>

// CONFIG
#pragma config FOSC = HS
#pragma config WDTE = ON
#pragma config PWRTE = ON
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF

#define _XTAL_FREQ 20000000

void UART_Init() {
TXSTAbits.TXEN = 0;
TXSTAbits.SYNC = 0;
RCSTAbits.SPEN = 1;
RCSTAbits.CREN = 1;
SPBRG = 31;
TXSTAbits.TXEN = 1;
}

char UART_Read() {
while (!RCIF);
return RCREG;
}

void main() {
unsigned char received_data;
TRISD = 0;

UART_Init();

while (1) {

received_data = UART_Read();
switch (received_data){
case 0:
PORTD = 0;
break;
case 1 ... 8:
PORTD = (1 << received_data) - 1;
break;
default:
break;
}
}
}

c) Kết quả mô phỏng

BÀI 13 : Cảm Biến Nhiệt Độ (Thanh An + Lương An)


 Code
#include <stdio.h>
#include <stdlib.h>
#include <pic.h>
#include <pic16f877a.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)

// #pragma config statements should precede project file includes.


// Use project enums instead of #define for ON and OFF.
#define _XTAL_FREQ 8000000
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
#include <xc.h>

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;
Lcd_Port(a);
EN = 1;
__delay_ms(4);
EN = 0; }
void Lcd_Init() {
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_Clear(){
Lcd_Cmd(0);
Lcd_Cmd(1);
}
void Lcd_Set_Cursor(char a, char b){
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_Write_Char(char a)
{
char temp,y;
temp = a&0x0F;
y = a&0xF0;
RS = 1;
Lcd_Port(y>>4);
EN = 1;
__delay_us(40);
EN = 0;
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()
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x0C);
}
void Lcd_Shift_Left()
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x08);
}

void ADC_Init()
{
ADCON0 = 0x89;
ADCON1 = 0x80;
}

unsigned int ADC_Read(unsigned char channel)


{
if(channel>7)
return 0;
ADCON0 &= 0xCD;
ADCON0 |= channel<<3;
__delay_ms(2);
GO_nDONE = 1;
while(GO_nDONE);
return((ADRESH<<8)+ADRESL);
}
void main()
{
unsigned int aa;
TRISA = 1;
TRISB = 0;
TRISD = 0;
TRISC = 0;
char s[20];
float nhietdo;
Lcd_Init();
ADC_Init();
while(1){
aa= ADC_Read(0);

nhietdo=(aa*100.0)/1023;
sprintf(s,"NHIET DO: %f",nhietdo);
Lcd_Set_Cursor(1,1);
Lcd_Write_String(s);
if(nhietdo>=30)
{RB0=1;
RC0 = 1;}
else {
RB0=0;
RC0 = 0;
}
}
}
 Chạy Chương Trình :

You might also like