Professional Documents
Culture Documents
ĐIỆN ĐIỆN TỬ
BỘ MÔN ĐIỀU KHIỂN HỌC
***********
NHÓM 4
Giáo viên hướng dẫn :TS Nguyễn Văn Tiềm
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â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ã.
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
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
#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
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
}
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++);
}
}
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
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
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_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);
}
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
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;
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);
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;
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
EN = 1;
__delay_us(40);
EN = 0;
Lcd_Port(temp);
EN = 1;
__delay_us(40);
EN = 0; }
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(){
void uart_init() {
SPBRG = 129;//baurate=9600
TXSTAbits.SYNC=0;
RCSTAbits.SPEN=1;
TXSTAbits.TXEN=1;
RCSTAbits.SREN=1;
RCSTAbits.CREN=1;
char UART_Receive()
while(!RCIF);
return RCREG;
TXREG = data;
while (*data) {
TXREG = *data++;
}
void main()
{int get_value;
TRISB1=0;
TRISC6 = 0;
TRISC7 = 1;
TRISD = 0X00;
PORTD = 0X00;
uart_init();
Lcd_Init();
Lcd_Clear();
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);
__delay_ms(10);
if(get_value == 'F')
PORTBbits.RB1=0;
Lcd_Set_Cursor(1, 1);
Lcd_Write_String("OPERATING MODE");
Lcd_Set_Cursor(2, 1);
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;
}
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%
/*
* File: bai7_khigas.c
*/
// CONFIG
#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)
#include "LCD.h"
#include <xc.h>
PORTD = 0X00;
void uart_init() {
TXSTAbits.TXEN = 1;
{
while (*data) {
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) {
Lcd_Set_Cursor(1, 1);
Lcd_Write_String(s1);
Lcd_Write_String(s2);
quat = 0;
} else if (RB0 == 1) {
Lcd_Set_Cursor(1, 1);
Lcd_Write_String(s1);
Lcd_Set_Cursor(2, 1);
Lcd_Write_String(s2);
quat = 1; //
__delay_ms(200);
}
}
File LCD.h
#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)
#include <xc.h>
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
#include <pic.h>
#include <pic16f877a.h>
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
//CONFIG
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) {
EN = 1; //T?o xung nh?p ?? truy?n d? li?u vào sau khi nh?n ??.
void Lcd_Clear() {
Lcd_Cmd(0);
Lcd_Cmd(1); //Xóa hi?n th? và ??a con tr? v? v? trí ban ??u
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?
Lcd_Cmd(z);
Lcd_Cmd(y);
temp = 0xC0 + b - 1;
z = temp >> 4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
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);
void Lcd_Write_Char(char a) {
char temp, y;
y = a & 0xF0;
__delay_us(40);
EN = 0;
Lcd_Port(temp);
EN = 1;
__delay_us(40);
EN = 0;
int i;
void Lcd_Shift_Right() {
Lcd_Cmd(0x01);
Lcd_Cmd(0x0C);
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"
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)
#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_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_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);
}
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 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
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;
}
}
}
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;
}
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 :