6/16/2018
CHƯƠNG 3
NGÔN NGỮ LẬP TRÌNH
VI ðIỀU KHIỂN
GV: Vũ Thị Hồng Nga
Khoa Công Nghệ Điện Tử
1. TỔNG QUAN LẬP TRÌNH CHO VI ĐIỀU KHIỂN
• Vi điều khiển truyền thông với con người thông qua ngôn ngữ lập trình
• Ngôn ngữ lập trình: cấp thấp hoặc cấp cao
• Ngôn ngữ lập trình được sử dụng trong bài học này là ngôn ngữ C.
2
1
6/16/2018
1. TỔNG QUAN LẬP TRÌNH CHO VI ĐIỀU KHIỂN
• Hợp ngữ là một tập các qui luật (lệnh) được dùng để viết
chương trình cho vi điều khiển
• Để vi điều khiển có thể hiểu một chương trình được viết bằng
hợp ngữ thì nó cần phải được biên dịch thành ngôn ngữ máy.
• Assembly: là một tập các qui luật (lệnh) được dùng để viết
chương trình cho vi điều khiển
• Assembler: là một chương trình trên máy tính dùng để dịch các
phát biểu hợp ngữ sang ngôn ngữ của các con số 0 hoặc 1.
3
• Chương trình (Program) / Mã nguồn (Source Code):
• Là tập tin dữ liệu được lưu trên máy tính
• Được thể hiện bằng hợp ngữ (hoặc các ngôn ngữ khác: ngôn ngữ C)
• Định dạng tập tin là .ASM và .C( ngôn ngữ C).
4
2
6/16/2018
• Thực thi (Executive) / Mã máy (Machine Code):
• Là tập tin dữ liệu được lưu trên máy tính hoặc nạp PIC
• Được thể hiện bằng các con số 0 hoặc 1
• Định dạng tập tin là .HEX (Ví dụ: Program.hex).
5
• Chương trình sau khi biên dịch sẽ được nạp vào vi điều khiển
bằng các bộ lập trình (Programmer) chuyên dụng dành cho PIC.
6
3
6/16/2018
• Vi điều khiển sau khi được lập trình sẽ được gắn vào bo mạch
chủ để điều khiển toàn hệ thống hoạt động theo chương trình
mà không cần sự can thiệp của con người.
7
2. Nhắc lại kiến thức ngôn ngữ lập trình C
Các thành phần chính của chương trình
- Khai báo thư viện
- Chương trình chính có tên là main, chương trình sẽ bắt
đầu chạy tại chỗ này.
- Chương trình bắt đầu bằng dấu { và kết thúc bằng dấu }
4
6/16/2018
Kiểu số nguyên có dấu
• Miền giá trị (số n-bit): -2n-1 .. +2n-1 – 1
Kiểu
(Type)
ðộ lớn
(Byte)
Miền giá trị
(Range)
char
1
–128 … +127
int
2
4
–32.768 … +32.767
–2.147.483.648 … +2.147.483.647
short
2
–32.768 … +32.767
long
4
–2.147.483.648 … +2.147.483.647
long long
8
–9,223,372,036,854,775,808
… 9,223,372,036,854,775,807
Một số môi trường lập trình ñồng nhất kiểu long long với kiểu long
cho nên kiểu này ít ñược sử dụng trong lập trình ứng dụng.
9
Kiểu số nguyên không dấu
• Miền giá trị (số n-bit): 0 .. 2n – 1
Kiểu
(Type)
ðộ lớn
(Byte)
Miền giá trị
(Range)
unsigned char
1
0 … 255
unsigned int
2
4
0 … 65535
0 … 4.294.967.295
unsigned short
2
0 … 65535
unsigned long
4
0 … 4.294.967.295
unsigned long long
8
0…
18,446,744,073,709,551,615
Một số môi trường lập trình ñồng nhất kiểu unsigned long long với kiểu
unsigned long cho nên kiểu này ít ñược sử dụng trong lập trình ứng dụng.
10
5
6/16/2018
• Hằng số nguyên có thể biểu diễn ở 4 dạng
• Bát phân: viết bắt đầu bằng số 0
• Nhị phân: viết bắt đầu bằng số 0B
• Thập phân: viết bắt đầu bằng số từ 1 đến 9
• Thập lục phân: viết đầu bằng 0x
VD: PORTA = 0X4A = 0B01001010
• Các phép toán số học
• Phép cộng: +, phép trừ: –, phép nhân: *
• Phép chia lấy phần nguyên: /
• Phép chia lấy phần dư: %
11
Toán tử trên bit
12
6
6/16/2018
VD: phép toán trên bit cho số nguyên không dấu
#include <stdio.h>
void main()
{
unsigned char a = 45;
00101101
//
unsigned char b = 58;
00111010
//
int c1, c2, c3, c4, c5, c6;
c1 = a & b;
// 00101000
c2 = a | b;
// 00111111
c3 = a ^ b;
// 00010111
c4 = ~a;
// 11010010
c5 = a >> 4;
// 11010000
c6 = a << 4;
// 00000010
}
13
Toán tử quan hệ
7
6/16/2018
Phép toán luận lý
Có 3 kiểu phép toán luận lý trong ngôn ngữ C, ñó là AND, OR và
NOT. Phép toán logic trả về kết quả true (1) nếu kết quả của biểu thức
khác 0, trả về kết quả false (0) nếu kết quả của biểu thức bằng 0.
Phép gán
• Việc tính toán trong chương trình được thực hiện bằng cách
tính toán và chép kết quả tính toán vào một biến nằm bên
trái của phép gán.
• Ví dụ:
sum = A + B;
sum = A + 2;
sum = A + n;
// chép tổng A + B vào biến sum
// chép tổng A + 2 vào biến sum
// chép tổng A + n vào biến sum
16
8
6/16/2018
Định dạng dữ liệu nhập xuất
•Đối với NNLT C
•Nhập xuất số nguyên (kiểu char, int)
• Có dấu dạng thập phân: %d hay %i
• Không dấu:
• Dạng thập phân: %u
• Dạng thập lục phân: %x hay %X
• Dạng bát phân: %o
•Trường hợp nhập xuất số nguyên kiểu
khác:
• short (16-bit): %hd, %hi, %ho, %hu, %hx, %hX
• long: %ld, %li, %lo, %lu, %lx, %lX
17
ðịnh dạng dữ liệu nhập xuất
• ðối với NNLT C
• Ký tự ñặc biệt: \\ (dấu \) và %% (dấu %)
• Ký tự tab và ký tự xuống dòng: \t, \n, \r
• Nhập xuất ký tự: %c
• Nhập xuất chuỗi ký tự: %s
• Về việc quy ñịnh ñộng rộng và ñộ chính xác (nếu là
số thực) cho dữ liệu xuất ñược ghi ngay sau dấu %
với dạng wid.pre, ví dụ %9.2f nghĩa là ñộ rộng ít nhất
9 ký tự (thêm khoảng trống vào nếu thiếu) và nhiều
nhất là 2 ký tự cho phần lẻ sau dấu chấm thập phân.
18
9
6/16/2018
Biến toàn cục & biến cục bộ
• Biến toàn cục (Global variables): vị trí biến đặt bên ngoài tất
cả các hàm, cấu trúc...Các biến này có ảnh hưởng đến toàn
bộ chương trình. Chu trình sống của nó là bắt đầu chạy
chương trình đến lúc kết thúc chương trình.
• Biến cục bộ (Local variables): Vị trí biến đặt bên trong hàm,
cấu trúc…. Chỉ ảnh hưởng nội bộ bên trong hàm, cấu trúc
đó…. Chu trình sống của nó bắt đầu từ lúc hàm, cấu trúc
được gọi thực hiện đến lúc thực hiện xong.
19
Cấu trúc điều khiển có 2 loại:
Cấu trúc điều khiển rẽ nhánh:
if else
switch
Cấu trúc điều khiển vòng lặp:
for
while
do while
10
6/16/2018
Cấu trúc điều khiển rẽ nhánh if:
if
(biểu_thức_ñiều_kiện)
{
Lệnh 1;
Lệnh 2;
…
Lệnh n;
}
else
{
Lệnh 1;
Lệnh 2;
…
Lệnh n;
}
Cấu trúc điều khiển
rẽ nhánh switch:
if
(biểu_thức_ñiều_kiện)
{
Lệnh 1;
Lệnh 2;
…
Lệnh n;
}
switch (biểu_thức_chọn)
{
case Giá_Trị_1:
Lệnh 1;
..
Lệnh n;
break;
case Giá_Trị_2:
Lệnh 1;
..
Lệnh n;
break;
default:
Lệnh 1;
..
Lệnh n;
break;
}
11
6/16/2018
Cấu trúc điều khiển vòng lặp:
while (điều_kiện_lặp)
{
Lệnh 1;
Lệnh 2;
…
Lệnh n;
}
for (biểu_thức_1;biểu_thức_2;biểu_thức_3)
{
Lệnh 1;
Lệnh 2;
…
Lệnh n;
}
Câu lệnh return
• Trả về dòng điều khiển mà nơi nó gọi, khi lệnh return được
theo sau bởi một biểu thức thì biểu thức đó sẽ được đánh
giá và giá trị này sẽ được trả về cho nơi đã gọi hàm. Khi
return được gọi mà không có biểu thức đi kèm thì giá trị trả
về là không xác định.
• Câu lệnh return không chỉ thoát khỏi vòng lặp mà nó còn
thoát luôn khỏi hàm mà đang chứa nó.
24
12
6/16/2018
Định nghĩa hàm
return-type function_name(param-type param_name,
…, param-type param_name)
{
// statements here…
}
• Trong đó:
• return-type: kiểu của giá trị hàm sẽ trả về, nếu không trả về gì
cả thì kiểu trả về sẽ là void.
• function_name: tên của hàm, thể hiện công việc hàm sẽ làm,
nên bắt đầu bằng một động từ.
• param-name, param-type: tên và kiểu tương ứng của tham số
hình thức (formal parameter).
• Tiếp theo là thân hàm (đặt trong {}) chứa các câu lệnh hàm sẽ
thực hiện (phải có ít nhất một lệnh return nếu kiểu trả về
không phải là void)
25
3. Lưu đồ giải thuật
13
6/16/2018
VD: Giải và biện luận phương trình bậc nhất: ax + b = 0
SV chuẩn bị các phần mềm và tài liệu sau
- phần mềm viết code: MPLAB
- phần mềm mô phỏng : PROTEUS
- Sách Thực hành vi xử lý
14
6/16/2018
Phần mềm viết code MPLAB
Phần mềm mô phỏng proteus
15
6/16/2018
KIT RP hoặc mô hình thí nghiệm vi xử lý
Bộ nạp chip PICKIT 2
VD1: lập trình điều khiển led đơn D4 và D5 chớp tắt với
Ton = Toff = 500ms
C7
Y1
4MHz
OSC2
22p
U2
MCLR
1
OSC2
OSC1
2
3
4
5
6
7
14
13
OSC1
+5V
C6
22p
R2
10K
R49
MCLR
100R
SW1
C10
0.1uF
33
34
35
36
37
38
39
40
BAI TAP UNG DUNG DIEU KHIEN XUAT/NHAP CO BAN
RE3/MCLR/VPP
RC0/T1OSO/T1CKI
RC1/T1OSI/CCP2
RA0/AN0/ULPW U/C12IN0RC2/P1A/CCP1
RA1/AN1/C12IN1RC3/SCK/SCL
RA2/AN2/VREF-/CVREF/C2IN+ RC4/SDI/SDA
RA3/AN3/VREF+/C1IN+
RC5/SDO
RA4/T0CKI/C1OUT
RC6/TX/CK
RA5/AN4/SS/C2OUT
RC7/RX/DT
RA6/OSC2/CLKOUT
RA7/OSC1/CLKIN
RD0
RD1
RB0/AN12/INT
RD2
RB1/AN10/C12IN3RD3
RB2/AN8
RD4
RB3/AN9/PGM/C12IN2RD5/P1B
RB4/AN11
RD6/P1C
RB5/AN13/T1G
RD7/P1D
RB6/ICSPCLK
RB7/ICSPDAT
RE0/AN5
RE1/AN6
RE2/AN7
15
16
17
18
23
24
25
26
19
20
21
22
27
28
29
30
8
9 RE1
10 RE2
RE2
R12
D5
470
LED
RE1
R13
D4
470
LED
PIC16F887
16
6/16/2018
Lưa đồ giải thuật:
Begin
Start
Cấu hình tất cả
Analog Input → Digital I/O
Cấu hình Port E
Output
Loop
ðiều khiển LED
D4, D5 = OFF
Delay 500ms
ðiều khiển LED
D4, D5 = ON
Delay 500ms
#include <htc.h>
#include <math.h>
__CONFIG (FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF &
BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_ON);
#define _XTAL_FREQ 4000000
void main()
{
ANSEL = 0X00;
ANSELH = 0X00;
TRISE = 0X00;
while(1)
{
PORTE = 0X00;
__delay_ms(500); //su dung 5 lan ham __delay_ms(100)
PORTE = 0X06;
__delay_ms(500);
}
}
17
6/16/2018
Bài tập 1: lập trình điều khiển 8 led đơn D1 và D7 nối với PORTD
chớp tắt với Ton = Toff = 300ms
Ví dụ 2: Dựa vào sơ đồ, viết chương trình điều khiển LED sáng dần
D1 → D8. Led nối với port C
18
6/16/2018
• Giải thuật:
Bảng dữ liệu Table
b'00000000
b'00000001
b'00000011
b'00000111
b'00001111
b'00011111
b'00111111
b'01111111
b'11111111
Begin
Start
Cấu hình tất cả
Analog Input → Digital I/O
Cấu hình Port C
Output
Loop
Xóa giá trị ñộ lệch (vị trí) của
dữ liệu trong bảng Table
Loop_1
Lấy giá trị ñộ lệch của
dữ liệu
ðọc dữ liệu nhận ñược từ
bảng Table (tùy thuộc vào
giá trị ñộ lệch)
Xuất dữ liệu nhận
ñược ra Port C
Delay 500ms
Tăng giá trị ñộ lệch
Kiểm tra
ñã lấy ñủ 9 byte từ bảng
Table ?
ð
S
37
Ví dụ 2: Dựa vào sơ đồ, viết chương trình điều khiển LED sáng dần
D1 → D8
• #include <htc.h>
• #include <math.h>
• __CONFIG (FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF &
CPD_OFF & BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_ON);
• #define _XTAL_FREQ 4000000
void main (void)
{
unsigned char i,j,temp;
ANSEL = 0;
ANSELH = 0;
TRISC = 0x00;
while(1)
{
PORTC = 0x00;
__delay_ms(500);
temp = 0x01;
for(j=1;j<=8;j++)
{
PORTC = temp;
__delay_ms(500);
temp = temp | (temp << 1);
}
}
}
38
19
6/16/2018
• Ví dụ 4: Dựa vào sơ đồ, viết chương trình hiển thị số 3 chớp
tắt trên 1 led7SEG (LED4)
39
Hướng dẫn:
- Xác định led 7 đoạn dùng loại nào: anode hay cathode?
- Tìm mà led 7 đoạn cho số 3
- Chọn Ton = ? Toff =?
- Xác định led hien thị nối với port nào?
- Cấu hình port: digital, output
- Xuất dữ liệu ra port
20
6/16/2018
Giải:
- led 7 đoạn dùng loại anode chung 0 sang, 1 tắt
- mã led 7 đoạn cho số 3 là 10110000 = 0XB0
- Chọn Ton = Toff = 500ms
- led hien thị nối với PORTD
- Cấu hình PORTD: digital, output
- Xuất dữ liệu ra portD
Lưu đồ giải thuật
21
6/16/2018
#include <htc.h>
#include <math.h>
__CONFIG (FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF &
BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_ON);
#define _XTAL_FREQ 4000000
void main()
{
PORTD = 0XB0;
ANSEL = 0X00;
__delay_ms(100);
ANSELH = 0X00;
__delay_ms(100);
TRISD = 0X00;
__delay_ms(100);
PORTD = 0X00;
__delay_ms(100);
while(1)
__delay_ms(100);
{
}
}
PORTD = 0XFF;
__delay_ms(100);
__delay_ms(100);
__delay_ms(100);
__delay_ms(100);
__delay_ms(100);
VD 5: viết chương trình điều khiển nút nhấn
Nhấn nút 1 (RB0) : led7seg hiển thị số 12 trong 1s
Nhấn nút 2 (RB1) : led7seg hiển thị số 24 trong 1s
44
22
6/16/2018
Lưu đồ giải thuật
#include <htc.h>
#include <math.h>
__CONFIG (FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF &
BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_ON);
#define _XTAL_FREQ 4000000
#define sw0 RB0
#define sw1 RB1
void khai_bao_port(void)
{
ANSEL = 0X00;
ANSELH = 0X00;
TRISD = 0X00;
PORTD = 0X00;
PORTC = 0X00;
TRISC = 0X00;
TRISB = 0XFF;
PORTB = 0XFF;
nRBPU = 0;
WPUB0 = 1;
WPUB1 = 1;
void delay_1s (void)
{
unsigned char i;
for (i=0;i<10;i++)
{
__delay_ms(100);
}
}
void so_24 (void)
{
PORTD = 0X99;
PORTC = 0XA4;
delay_1s();
}
void so_12 (void)
{
PORTD = 0XA4;
PORTC = 0XF9;
delay_1s();
}
}
23
6/16/2018
void main (void)
{
khai_bao_port();
while (1)
{
if(!sw0)
{
__delay_ms(10);
while(!sw0);
so_12();
PORTC = 0xFF;
PORTD = 0xFF;
}
else if(!sw1)
{
__delay_ms(10);
while(!sw1);
so_24();
PORTC = 0xFF;
PORTD = 0xFF;
}
}
}
Ví dụ 5: viết chương trình hiển thị hình “trái tim” trên led
matrix
48
24
6/16/2018
#include <htc.h>
#include <math.h>
__CONFIG (FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF &
BOREN_OFF & IESO_OFF & FCMEN_OFF & LVP_OFF & DEBUG_ON);
#define _XTAL_FREQ 4000000
const unsigned char a[]= {0xF3,0xE1,0xC1,0x83,0xC1,0xE1,0xF3,0xFF};
void main(void)
{
unsigned char vitri,i;
ANSEL = 0X00;
ANSELH = 0X00;
while(1)
{
vitri = 0x01;
for(i=0;i<=7;i++)
{
PORTC = a[i];
PORTD = vitri;
__delay_ms(3);
PORTD = 0x00;
vitri = vitri << 1;
TRISD = 0X00;
PORTD = 0X00;
TRISC = 0X00;
PORTC = 0X00;
}
}
}
25