8.2.4. Ghi kí tự lên LCD để hiển thị
Sau khi thực hiện quá trình khởi tạo để gửi các lệnh cài đặt chế độ làm
việc cùa LCD, kí tự sẽ đƣợc hiển thị lên LCD bất kì khi nào vi điều khiển muốn
gửi.
Quá trình gửi kí tự gồm các bƣớc sau:
Cho chân R/W=0 để xác định đây là ghi xuống LCD (thông thƣờng chân
này đƣợc nối đất, nên mặc định chân này ở mức 0, ta không cần quan tâm đến
nữa)
Cho chân RS=1 để xác định đây là kí tự mà vi điều khiển gửi xuống LCD
(phân biệt với RS=0, gửi lệnh)
Gửi mã ascii của kí tự cần hiển thị xuống LCD theo các đƣờng dữ liệu
(RD0-RD7 nếu dùng chế độ 8 bit, R4-R7 nếu dùng chế độ 4 bit)
Đƣa chân E (chân cho phép- Enable) lên mức cao, mức 1
Tạo trễ vài chu kì lệnh
Đƣa chân E xuống mức thấp, mức 0
115 trang |
Chia sẻ: linhmy2pp | Ngày: 21/03/2022 | Lượt xem: 378 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Bài giảng Kỹ thuật lập trình vi điều khiển - Phạm Trường Tùng, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
_OFF );
b. Thiết lập những chân ADC có sẵn để chuyển từ tín hiệu tương tự sang
tín hiệu số
Cú pháp:
setup_adc_ports (value)
- Thông số: value Một hằng số đƣợc định nghĩa trong tập tin .h của thiết
bị
- Trả về: Không đƣợc định nghĩa
- Chức năng:Cài đặt những chân ADC là tín hiệu tƣơng tự,tín hiệu số
hoặc một sự kết hợp và điện áp tham chiếu để sử dụng khi tính tóan giá trị
ADC.Sự kết hợp các chân tín hiệu tƣơng tự đã đƣợc cho phép thay đổi phụ thuộc
vào con chip và đƣợc định nghĩa bằng cách sử dụng từng bit OR để ghép những
chân đã đƣợc chọn cùng với nhau.Kiểm tra thiết bị bao gồm tập tin các chân và
điện áp tham chiếu đã đƣợc sắp đặt trong danh sách hòan chỉnh.
- Hằng số:
ALL_ANALOG và NO_ANALOG là hợp lý cho tất cả con chip.
Một vài ví dụ khác định nghĩa chân là:
ANALOG_RA3_REF Kích họat tất cả các chân tín hiệu tƣơng tự và
chân RA3 là điện áp tham chiếu
RA0_RA1_RA3_ANALOG Chỉ có chân RA0,RA1,RA3 là tín hiệu
tƣơng tự
- Tiện lợi: Chức năng này có sẵn trong các thiết bị với phần cứng
Analog/Digital
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 57
- Yêu cầu: Những hằng số đã đƣợc định nghĩa trong tập tin .h của thiết bị
Ví dụ:- Tất cả các chân analog
setup_adc_ports( ALL_ANALOG );
- Chân A0,A1,A3 là analog,và tất cả các chân còn lại là digital. Điện áp
+5V đƣợc sử dụng nhƣ điện áp tham chiếu
setup_adc_ports( RA0_RA1_RA3_ANALOG );
- Chân A0,A1 là analog,chân A3 đƣợc sử dụng cho điện áp tham chiếu và
tất cả các chân còn lại là digital
setup_adc_ports( A0_RA1_ANALOGRA3_REF );
c. Chỉ rõ những kênh dung để sử dụng cho việc gọi Analog/Digital
Cú pháp:
set_adc_channel (chan);
- Thông số: Chân là số kênh đƣợc chọn.Số chân bắt đầu tại 0 và đã đƣợc
đặt nhãn trong datasheet AN0,AN1
Trả về:Không đƣợc định nghĩa
- Chức năng: Chỉ rõ những kênh đƣợc sử dụng cho việc gọi lệnh
READ_ADC().Hãy biết rằng bạn phải chờ 1 khoảng thời gian ngắn sau khi thay
đổi kênh trƣớc khi bạn có thể nhận đƣợc giá trị đọc hợp lý.Thời gian thay đổi
phụ thuộc vào trở kháng của nguồn đầu vào.Khỏang 10us nói chung là tốt cho
hầu hết các ứng dụng.Bạn không cần thay đổi kênh trƣớc mỗi lần đọc nếu kênh
không thay đổi
- Tiện lợi: Chức năng này có sẵn trong các thiết bị với phần cứng
Analog/Digital
- Yêu cầu: Không cần thứ gì
Ví dụ:
set_adc_channel(2);
delay_us(10);
value = read_adc();
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 58
d. Bắt đầu quá trình chuyển đổi và đọc giá trị.Chế độ này có thể cũng
điều khiển chức năng.
Cú pháp:
value = read_adc ([mode])
- Thông số: mode là một thông số không bắt buộc.Nếu đƣợc sử dụng giá
trị có thể:
ADC_START_AND_READ (Liên tục đọc,và đây là mặc định)
ADC_START_ONLY (Bắt đầu quá trình chuyển đổi và trả về giá trị)
ADC_READ_ONLY (Đọc kết quả chuyển đổi cuối cùng)
- Trả về: 8 bit hoặc 16 bit số nguyên phụ thuộc vào #DEVICE ADC=
directive (directive:lời chỉ dẫn,8 hoặc 16).
- Chức năng: Đây là chức năng đọc giá trị số từ bộ chuyển đổi tín hiệu
tƣơng tự sang tín hiệu số. Gọi lệnh setup_adc(), setup_adc_ports() and
set_adc_channel() nên đƣợc làm vài lần trƣớc khi chức năng này đƣợc gọi. Dãy
giá trị trả về phụ thuộc vào số lƣợng bit bộ chuyển đổi Analog/Digital trong con
chip và sự sắp đặt trong DEVICE ADC= directive nhƣ sau:
#DEVICE 8 bit 10 bit 11 bit 12 bit 16 bit
ADC=8 00-FF 00-FF 00-FF 00-FF 00-FF
ADC=10 x 0-3FF X 0-3FF x
ADC=11 x x 0-7FF x x
ADC=16 0-FF00 0-FFC0 0-FFEO 0-FFF0 0-FFFF
Lƣu ý: X không đƣợc định nghĩa
Tiện lợi: Chức năng này có sẵn trong các thiết bị với phần cứng
Analog/Digital
Yêu cầu: Những chân cố định đã đƣợc định nghĩa trong tập tin .h của thiết
bị
Ví dụ:
setup_adc( ADC_CLOCK_INTERNAL );
setup_adc_ports( ALL_ANALOG );
set_adc_channel(1);
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 59
while ( input(PIN_B0)
{
delay_ms( 5000 );
value = read_adc();
printf("A/D value = %2x\n\r", value);
}
read_adc(ADC_START_ONLY);
sleep();
value=read_adc(ADC_READ_ONLY);
ADC_done():Trả về 1 nếu bộ chuyển đổi đã hòan thành việc chuyển đổi
của nó
Tiền xử lý có liên quan:
#DEVICE ADC=xx : Định hình thể read_adc rồi trả về kính thƣớc.Ví dụ,
sử dụng 1 con PIC với 10 bit A/D bạn có thể sử dụng 8 hoặc 10 cho xx- 8 sẽ trả
về bye có trọng số cao nhất,10 sẽ trả về tòan bộ giá trị đọc A/D 10 bit
Các ngắt có liên quan:
INT_AD: Ngắt xảy ra khi quá trình chuyển đổi đã hòan tất
INT_ADOF: Ngắt xảy ra khi quá trình chuyển đổi trong thời gian chờ
Các tập tin có liên quan:
Không có,tất cả chức năng đƣợc cài đặt sẵn
Các thông số getenv() có liên quan:
ADC_CHANNELS Số kênh Analog/Digital
ADC_RESOLUTION Số lƣợng bit trả về bởi lệnh read_adc
6.2. MÔ ĐUN ĐIỀU CHẾ ĐỘ RỘNG XUNG
6.2.1. Giới thiệu
PWM là một bộ điều chế độ rộng xung. Có hai thông số (tạm gọi đơn
giản nhƣ vậy, và có lẽ cũng chỉ quan tâm đến hai thông số này với PWM) quan
trọng của PWM là chu kỳ xung T và thời gian t1 của mức logic 0, trong ví dụ
này thì t1 tƣơng ứng với value. Để "điều chế độ rộng xung" thì chúng ta sẽ giữ
nguyên T và thay đổi t1, theo yêu cầu của bài toán cụ thể. Value trong ví dụ sau
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 60
lấy đƣợc từ đầu vào anlaog, chu kỳ (hay tần số) của xung đƣợc chọn lựa từ PC
thông qua cổng truyền thông nối tiếp RS232.
Có nhiều ứng dụng cho PWM, ví dụ truyền thông, điều khiển các van bán
dẫn trong các biến tần, làm bộ nguồn chuyển mạch,...
- Đầu ra PWM (hình 2) có hai tham số, đó là chu kỳ xung và độ rộng
xung.
PWM
6.2.2. Chu kỳ xung và độ rộng xung
Chu kỳ xung đƣợc xác định bằng cách ghi vào thanh ghi PR2. Giá trị chu
kỳ xung đƣợc xác định theo công thức
+ Tần số đƣợc xác định nhƣ sau
f= 1/TPWM
Khi giá trị TMR2 = giá trị thanh ghi PR2, 3 sự kiện sau đây sẽ xảy ra
trong chu kỳ tiếp theo
- TMR2 đƣợc xóa
- CCP1 sẽ đƣợc set nếu độ rộng xung đang thiết lập là khác 0 %.
- Giá trị độ rộng xung đang đƣợc lƣu trong CCPR1L sẽ đƣợc đƣa vào
CCPR1H.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 61
6.2.3. Độ rộng xung
Độ rộng xung đƣợc xác định bằng cách ghi vào thanh ghi CCPR1L và hai
bít 5 và 4 của thanh ghi CCP1CON. Độ phân giải của độ rộng xung lên đến 10
bít. CCPR1L chứa 8 bít có trọng số cao nhất và CCP1CON (5:4) chứa 2 bít có
trọng số thấp nhất. Đẳng thức sau đƣợc xác định độ rộng xung.
PWM duty cycle =(CCPR1L:CCP1CON) •TOSC • (TMR2 prescale
value)
Giá trị thanh ghi CCPR1L và CCP1CON có thể đƣợc ghi vào bất kỳ
thời điểm nào. nhƣng giá trị độ rộng xung không đƣợc chốt vào CCPR1H cho đê
khi PR2 = TMR2. trong chế đọ PWM thì thanh fhi CCPR1H là thanh ghi chỉ
đọc.
6.2.4. chƣơng trình demo
BÀI TẬP CHƢƠNG 6
Bài 1: Viết chƣơng trình trên CCS sử dụng bộ A/D của vi điều khiển
PCI18F4431 để đọc nhiệt độ từ IC nhiệt LM35 và hiển thị ra led 7 đoạn (phần
cứng tự thiết kế).
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 62
Bài 2: Viết chƣơng trình trên CCS sử dụng các module PWM trên vi điều
khiển PIC18F4431 để điều khiển tốc độ động cơ DC.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 63
CHƢƠNG 7 CÁC GIAO TIẾP CƠ BẢN
Mục tiêu: Giới thiệu các giao tiếp cơ bản
Sinh viên hiểu được các khái niệm trong các giao tiếp RS232/485; giao
tiếp I2C; giao tiếp SPI, USB.
7.1. GIAO TIẾP RS232/RS485
7.1.1. Phần cứng giao tiếp
Phần cứng giao tiếp RS232
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 64
Cáp RS232
.7.1.2. Truyền thông với RS232 với trình biên dịch CCS
Trình biên dịch CCS cung cấp cho chúng ta các cách thức rất đơn giản
đển giao tiếp thông qua RS232. Nó ẩn tất cả các thiết lập thanh ghi. Chúng ta chỉ
cần cung cấp một vài thông tin, những thứ còn lại đƣợc thực hiện bởi chƣơng
trình biên dịch
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
- Chỉ thị tiền xữ lý #use delay(clock=20000000) cung cấp cho trình biên
dịch thông tin về tốc độ thạch anh mà vi điều khiển PIC đƣợc chạy, do ví dụ này
sử dụng thạch anh 20Mhz, nên ta khai báo Clock=20000000.
- Chỉ thị #use rs232 cung cấp cho trình biên dịch thông tin về các tham số
cấu hình RS232 sẽ sử dụng để giao tiếp:
- baud=9600 : khai báo tốc độ baud sử dụng là 9600.
- parity = N : khai báo có sử dụng bit kiểm tra chẳn lẻ hay không, ở đây ta
không kiểm tra nên thiết lập parity = N.
- xmit =PIN_C6 : Chân truyền dữ liệu là PIN C6
- rcv=PIN_C7 : Chân nhận dữ liệu là PIN C7
- bits=8 : Số bit dữ liệu là 8 bít
Các hàm hỗ trợ truyền dữ liệu:
int value = 1;
putc('A'); /* gửi một ký tự thông qua RS232 */
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 65
puts("Test-String"); /* gửi một chuỗi thông qua RS232 */
printf("Transmit a value: %d", value); /* gửi một chuỗi theo định dạng qua
RS232 */
Các hàm hỗ trợ nhận dữ liệu:
char ch;
char string[32];
ch = getc(); /* nhận 1 ký tự đơn */
gets(string); /* nhận 1 chuỗi */
Ngắt nhận của RS232
#INT_RDA /*Ngắt khi nhận dữ liệu*/
void Ngat_Nhan
{
//Hàm xữ lý sự kiện ngắt nhận
//Tại đây ta có thể xữ lý dữ liệu vừa nhận được
}
Dƣới đây là chƣơng trình viết cho PIC.
#include
#fuses HS,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
//============================
void main()
{
char c;
Set_tris_D(0x00); // thiết lập cổng I/O của port D là cổng xuất
Output_D(0xFF); // tắt tất cả các LED kết nối đến port D
while(1)
{
c = getc();
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 66
if(c=='0')
{
output_d(0b11111111);
}
if(c=='1')
{
output_d(0b11111110);
}
if(c=='2')
{
output_d(0b11111101);
}
if(c=='3')
{
output_d(0b11111100);
}
}
}
7.2. GIAO TIẾP I2C
Khai báo PIN giao tiếp
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
Mặc dù PIC 16F887 dành riêng RC3 và RC4 để giao tiếp i2c, tuy nhiên ta
có thể khai báo lại với hai chân bất kỳ khác.
Quy trình đọc dữ liệu từ thiết bị ngoài
- Start i2c
- Gửi địa chỉ thiết bị
- Gửi địa chỉ dữ liệu
- Gửi lại địa chỉ thiết bị và lệnh read
- Đọc dữ liệu
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 67
- Stop i2c
Code ví dụ sau để đọc dữ liệu từ eeprom 24c02
BYTE read_ext_eeprom(int16 add)
{
BYTE data;
i2c_start(); // bao hieu bat dau giao tiep i2c
i2c_write(0xA0); // dia chi thiet bi nhan
i2c_write(add>>8); // gui den dia chi cao cua thiet bi nhan (dia chi cot)
i2c_write(add); // gui den dia chi thap cua thiet bi nhan (dia chi hang)
i2c_start();
i2c_write(0xA1);//đia chi thiết bi nhan +1 (chỉ thị read)
data=i2c_read(0); // No Ack
i2c_stop();
return(data);
}
Quy trình ghi dữ liệu vào thiết bị ngoài
- Start i2c
- Gửi địa chỉ thiết bị
- Gửi địa chỉ dữ liệu
- ghi dữ liệu
- Stop i2c
- Code ví dụ sau để đọc dữ liệu từ eeprom 24c02
void write_ext_eeprom(int16 add, BYTE data)
{
short int status;
i2c_start(); // bao hieu bat dau giao tiep i2c
i2c_write(0xA0); // dia chi thiet bi nhan
i2c_write(add>>8); // gui den dia chi cao cua thiet bi nhan (dia chi cot)
i2c_write(add); // gui den dia chi thap cua thiet bi nhan (dia chi hang)
i2c_write(data); // ghi data vao dia chi tren cua thiet bi nhan
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 68
i2c_stop(); // bao hieu ngung ghi
i2c_start(); // bao hieu bat dau giao tiep
status=i2c_write(0xA0); // kiem tra trang thai cua thiet bi nhan
while(status==1) // lap lai cho den khi thiet bi da nhan xong (No Ack)
{
i2c_start();
status=i2c_write(0xa0);
}
Đối với chip không hỗ trợ phần cứng i2c, dĩ nhiên không thể khai báo
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)
Nhƣ vậy không dùng đƣợc các hàm i2c_read và i2c_write có sẵn trong
CCS, để sử dụng ta phải viết riêng hàm thƣ viện cho nó:
ví dụ sau được viết cho pic 16f88
#define PIN_SCL PIN_B4
#define PIN_SDA PIN_B1
#bit TRISB1 =0x86.1#bit TRISB4 =0x86.4
#bit RB1 =0x06.1
#bit RB4 =0x06.4
#define CHK_SCL RB4
#define CHK_SDA RB1
#define TRIS_SCL TRISB1
#define TRIS_SDA TRISB4
//==================
///prototype
//===================
void _i2c_start();
void _i2c_stop();
byte _i2c_read(BYTE ack);
//ack = 1 -> send not ack signal (NACK)
//ack = 0 -> send ack signal (ACK)
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 69
void _i2c_write(int16 data_send);
//==========================================
// I2C Start
//==========================================\
void _i2c_start()
{
TRIS_SCL=0;
TRIS_SDA=0;
output_high(PIN_SDA);
output_high(PIN_SCL);
output_low(PIN_SDA);
output_low(PIN_SCL);
}
//===========================================
// I2C Stop
//===========================================
void _i2c_stop()
{
TRIS_SDA=0;
TRIS_SCL=0;
output_low(PIN_SDA);
output_high(PIN_SDA);
output_high(PIN_SCL);
}
//===========================================
/ I2C write
//===========================================
void _i2c_write(int16 data_send)
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 70
{
BYTE i;
TRIS_SDA=0;
TRIS_SCL=0;
for(i=0;i<=8;i++)
{
if(data_send & 0x80) // MSB fist -> LSB last
output_high(PIN_SDA);
else
output_low(PIN_SDA);
output_high(PIN_SCL);
data_send <<=1;
output_low(PIN_SCL);
}
}
//===========================================
// I2C read
//===========================================
byte _i2c_read(BYTE ack)
{
BYTE get_data,i;
output_low(PIN_SCL);
TRIS_SDA=1; //set PIN_SDA as input
for(i=0;i<8;i++)
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 71
{
get_data<<=1;
output_high(PIN_SCL);
if(CHK_SDA==1)
get_data |=1;
output_low(PIN_SCL);
}
TRIS_SDA=0; //set PIN_SDA as output
if(ack)
output_high(PIN_SDA); //ack=1 -> send not ack signal (NACK)
else
output_low(PIN_SDA); //ack=0 -> send ack signal (ACK)
output_high(PIN_SCL);
output_low(PIN_SCL);
return get_data;
}
7.3. GIAO TIẾP SPI
Giao tiếp SPI đƣợc hãng motorola giới thiệp ở giữa năm 1980 và đƣợc sử
dụng trong các dòng vi điều khiển của họ. Ngày nay giao tiếp SPI đƣợc sử dụng
phổ biến để giao tiếp với các vi điều khiển, eeprom, IC thời gian thực...
SPI là giao thức nối tiếp đồng bộ đa mục đích (general-purpose
synchronous serial interface), trong khi thực hiện giao tiếp SPI dữ liệu truyền và
nhận đƣợc diễn ra một các đồng thời. Một xung clock đồng bộ dùng để dịch và
lấy mẫu thông tin trên hai đƣờng dữ liệu.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 72
Thiết bị giao tiếp SPI sử dụng mối quan hệ master- slaver (chủ-tớ), do
thiết bị tớ không đƣợc định địa chỉ nên khi giao tiếp một master với nhiều slaver
ta cần đƣờng chọn chíp CS, để chọn slave nào cần truyền nhận dữ liệu. Vậy số
bus cho giao tiếp này là 3 + (1....n) dây.
7.3.1. Các cách kết nối cơ bản
Kết nối cơ bản SPI
7.3.2. Tên và chức năng của các chân
MOSI (Master Output Slave Input.):Chân này đƣợc sử dụng để truyền
dữ liệu khi thiết bị đƣợc cấu hình là master và là chân nhận dữ liệu khi cấu hình
là slave
MISO (Master Input Slave Output): Chân này đƣợc sử dụng để nhận dữ liệu khi
khi thiết bị đƣợc cấu hình là Master và truyền dữ liệu khi cấu hình bởi slave
SS: Tín hiệu này đƣợc tạo bởi Master để lựa chọn thiết bị slave muốn truyền
nhận, Đối với thiết bị master chân này đƣợc cấu hình là chân xuất (output) và là
chân nhập (input) với slave
SCK: Chân SCK cấp xung đồng bộ để truyền nhận dữ liệu với một Slave
nào đó đƣợc chọn
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 73
Truyền dữ liệu
Cả Master và Slave đều có thanh ghi dịch nối tiếp ở bên trong. Thiết bị
Master bắt đầu việc trao đổi dữ liệu bằng cách truyền đi một Byte vào thanh ghi
dịch của nó, sau đó Byte dữ liệu sẽ đƣợc đƣa sang Slave theo đƣờng tín hiệu
MOSI (SDI), Slave sẽ truyền dữ liệu nằm trong thanh ghi dịch của chính nó
ngƣợc trở về Master thông qua đƣờng tín hiệu MISO (SDO). Bằng cách này, dữ
liệu của hai thanh ghi sẽ đƣợc trao đổi với nhau. Việc đọc và ghi dữ liệu vào
Slave diễn ra cùng một lúc nên tốc độ trao đổi dữ liệu diễn ra rất nhanh. Do đó,
giao thức SPI là một giao thức rất có hiệu quả.
Trong giao thức chủ-tớ, chỉ có thiết bị Master mới có thể điều khiển (phát
ra) xung SCK. Dữ liệu sẽ không đƣợc truyền đi nếu nhƣ Master không cung cấp
xung SCK và tất cả các thiết bị Slave đều đƣợc điều khiển bởi xung nhịp phát ra
từ Master trong khi đó, Slave lại không có khả năng phát xung.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 74
7.3.3. Các kiểu kết nối trong SPI
7.3.3.1. Kết nối song song nhiều slave
Kết nối song song nhiều slave
7.3.3.2. Kết nối Daisy chain
Kết nối Daisy chain
7.3.3.3. Các mode trong giao tiếp SPI
Tùy thuộc vào các cạnh đồng hồ sử dụng cho việc dịch có 4
mode SPI khác nhau:
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 75
SPI Mode SCK (Cạnh bắt đầu) SCK (cạnh kết thúc)
0 Lấy mẫu dữ liệu tại cạnh lên
Truyền dữ liệu mới tại cạnh
xuống
1
Truyền dữ liệu mới tại cạnh
lên
Lấy mẫu dữ liệu tại cạnh xuống
2
Lấy mẫu dữ liệu tại cạnh
xuống
Truyền dữ liệu mới tại cạnh lên
3
Truyền dữ liệu mới tại cạnh
xuống
Lấy mẫu dữ liệu tại cạnh lên
Hình bên dƣới là các dạng sóng minh họa:
Các dạng sóng
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 76
Dạng sóng của SPI mode 0 và Mode 2
7.4. CÁC GIAO TIẾP KHÁC
7.4.1. Giao tiếp USB
7.4.1.1. Giới thiệu
Universal Serial Bus (USB) là một trong những giao thức phổ biến nhất
đƣợc sử dụng trong sản phẩm điện tử tiêu dùng hiện nay, bao gồm máy tính,
máy ảnh, thiết bị GPS, máy MP3, modem, máy in, máy scan,.... Các chuẩn USB
ban đầu đƣợc phát triển bởi Compaq, Microsoft, Intel, và NEC, và sau đó bởi
Hewlett-Packard, Lucent và Philips. Các công ty này cuối cùng hình thành tổ
chức phi lợi nhuận USB Implementers Forum Inc. tổ chức này phát triển và
công bố các thông số kỹ thuật của USB.
USB là một giao thức nối tiếp tốc độ cao, nó có thể cung cấp điện cho các
thiết bị kết nối với nó. Một bus USB hỗ trợ kết nối lên đến 127 thiết bị (giới hạn
bởi các trƣờng địa chỉ 7-bit, lƣu ý rằng địa chỉ 0 không đƣợc sử dụng vì nó có
một mục đích đặc biệt) đƣợc kết nối thông qua dây cáp với chiều dài lên đến ba
hoặc thậm chí năm mét. Nhiều thiết bị USB có thể đƣợc kết nối với bus thông
qua Hub, Hub này có thể có 4, 8, hoặc thậm chí 16 cổng. Một thiết bị có thể
đƣợc cắm vào một Hub mà Hub này kết nối đến các Hub khác, và nhƣ vậy. Số
lƣợng tối đa cho phép là sáu tầng. Theo các đặc điểm kỹ thuật, khoảng cách tối
đa của một thiết bị đến máy chủ của nó là khoảng ba mƣơi mét, thực hiện bằng
cách sử dụng 5 hub. Đây là khoảng cách dài nhất. Nếu cho khoảng cách dài hơn
ta có thể dùng chuẩn truyền Ethernet.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 77
hub usb
7.4.1.2. Đặc điểm kỹ thuật
Các đặc điểm kỹ thuật bus USB có hai phiên bản: phiên bản trƣớc đó
là USB1.1, hỗ trợ tốc độ 11Mbps, trong khi phiên bản mới là USB 2.0, hỗ trợ
tốc độ lên đến 480Mbps. Các đặc điểm kỹ thuật USB định nghĩa ba tốc độ dữ
liệu:
Low speed—1.5Mb/sec (Tốc độ thấp)
Full speed—12Mb/sec (Tốc độ đầy đủ)
High speed—480Mb/sec (Tốc độ cao)
Nguồn tối đa cho một thiết bị bên ngoài kết nối sử dụng điện áp cấp bởi
cổng USB đƣợc giới hạn trong khoảng 100mA tại điện áp 5.0V.
Có hai loại đầu kết nối đƣợc sử dụng đó là kiểu A và kiểu B:
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 78
Các đầu nối USB
Đầu nối kiểu A Đầu nối kiểu B
Chân số Tên Màu sắc
1 + 5.0 V Đỏ
2 - Data Trắng
3 + Data Xanh lá cây
4
Ground (đất) Đen
Thông số kỹ thuật còn đề cập loại đầu cắm mini kiểu B, sử dụng cho các
thiết bị điện sách tay chẳng hạn nhƣ camera và các thiết bị cầm tay khác. Loại
đầu cắm này có thêm chân thứ 5 gọi là chân ID, mặt dù chân này không đƣợc sử
dụng.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 79
Cấu tạo các dây data
Hai dây Data + và Data -, tạo thành 1 cặp xoắn và mang tín hiệu vi sai và
trạm dữ liệu kết thúc đơn.
Chân số Tên Màu sắc
1 + 5.0 V Đỏ
2 - Data Trắng
3 + Data Xanh lá cây
4 Không sử dụng -
5 Ground (đất) Đen
Các chân USB
Tín hiệu USB là lƣỡng pha, và tín hiệu đƣợc gửi từ máy chủ bằng cách sử
dụng kỹ thuật mã hóa dữ liệu NRZI (non-return to zero inverted). Trong kỹ thuật
này, hai logic 0 kế tiếp nhau sẽ bị đảo ngƣợc mức tín hiệu. Mức tín hiệu cho mức
logic 1 là không thay đổi. Một bit 0 đƣợc "nhồi" sau mỗi sáu bit 1 liên tiếp trong
dòng dữ liệu để làm dữ liệu động ( đƣợc gọi là bit nhồi vì kéo dài dòng dữ
liệu thêm một chút). Hình 8.3 cho thấy cách thức thực hiện NRZI .
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 80
Dữ liệu NRZI
Một gói dữ liệu truyền bởi máy chủ gửi đến mỗi thiết bị kết nối đến
bus, truyền xuống thông qua chuỗi các Hub. Tất cả các thiết bị đều nhận đƣợc tín
hiệu, nhƣng chỉ có một thiết bị , 1 địa chỉ chấp nhận dữ liệu. Ngƣợc lại, tại bất
cứ thời gian nào chỉ có một thiết bị có thể truyền đến máy chủ.
Thiết bị USB kết nối đến bus có thể là thiết bị đƣợc tùy chỉnh đầy đủ, yêu
cầu một trình điều khiển (driver) tùy chỉnh đầy đủ. Phân Lớp thiết bị cho phép
cùng một trình điều khiển thiết bị đƣợc sử dụng cho nhiều thiết bị có chức năng
tƣơng tự.. Ví dụ , thiết bị máy in có phân lớp thiết bị là 0x07, và hầu hết máy in
sử dụng kiểu driver này
Hầu hết phân lớp thiết bị thông dụng đƣợc trình bày ở bẳng 8.3. Lớp USB
human interface device (HID) tạm dịch là lớp thiết bị giao diện con ngƣời là lớp
đƣợc quan tâm đặc biệt, nó đƣợc sử dụng trong ví dụ ở bài này.
7.4.1.3. Một vài thuật ngữ USB thông dụng:
Endpoint (Điểm cuối): một điểm cuối là một bộ nhận hoặc truyền dữ liệu.
Endpoint của thiết bị là một bộ nhớ đệm (buffer) để lƣu trữ dữ liệu nhận hoặc là
dữ liệu để truyền. Thiết bị phải hỗ trợ một endpoint 0, endpoint này có thể nhận
và truyền dữ liệu.Một thiết bị USB giới hạn mƣời sáu enpoint IN (bộ đệm nhận)
và mƣời sáu enpoint out (bộ đệm truyền).
Transaction: một transaction là truyền dữ liệu trên bus.
Pipe (Đƣờng Ống): Một đƣờng ống là kết nối dữ liệu logic giữa máy chủ
và một điểm cuối (Enpoint).
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 81
Logical pipes: đường ống lôgic
Endpoints in the device: các endpoint trong thiết bị
Phân lớp
thiết bị
Miêu tả Thiết bị ví dụ
0x00 Để dành
0x01 USB audio device (USB thiết bị âm thanh )
Sound card (card âm
thanh)
0x02
USB communications device ( USB Thiết
bị truyền thông )
Modem, fax
0x03
USB human interface device ( USB Thiết
bị giao diện con ngƣời)
Keyboard, mouse (Bàn
phím, chuột)
0x07 USB printer device (USB Thiết bị in) Printer (Máy in)
0x08
USB mass storage device (USB Thiết bị
lƣu trữ )
Memory card, flash
drive
0x09 USB hub device ( USB Thiết bị hub) Hubs
0x0B
USB smart card reader device ( USB Thiết
bị đọc thẻ thông minh)
Card reader (bộ đọc thẻ
nhớ)
0x0E USB video device ( USB Thiết bị Video) Webcam, scanner
0xE0
USB wireless device ( USB Thiết bị
wireless)
Bluetooth
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 82
7.4.1.4. Định danh tốc độ trên bus:
Tại thiết bị , chân dữ liệu D+ hoặc D- đƣợc kéo lên nguồn 3.3 V thông
qua điện trở 1.5K. Khi thiết bị chạy ở tốc độ full-speed, chân D+ đƣợc kéo lên
nguồn 3.3V, Khi thiết bị chạy ở tốc độ low speed chân D- đƣợc kéo lên nguồn
3.3V. Khi cả hai đƣờng dữ liệu ở mức thấp, báo cho host rằng không có thiết bị
nào đƣợc kết nối. Khi có thiết bị kết nối, khi đó đƣờng dữ liệu D+ hoặc D- sẽ
đƣợc kéo lên mức cao, nhờ đó mà host biết đƣợc có thiết bị đang đƣợc kết nối.
Phụ thuộc đƣờng dữ liệu nào đƣợc kéo lên mức cao host xác định đƣợc tốc độ
truyền của thiết bị.
Thiết bị chạy ở tốc độ Full speed
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 83
Thiết bị chạy ở tốc độ Low speed
Code mẫu chƣơng trình giao tiếp USB với PIC
#include
#include
#include // Chứa các tác vụ quản lý các ngắt USB, các yêu cầu thiết lập USB của
enpoint 0
Đoạn chƣơng trình bên dƣới thực hiện khởi tạo cổng USB và kiểm tra quá
trình enumerated bởi máy tính và vi điều khiển PIC đã thành công hay chƣa
#include
#device ADC=8
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL2,CPUDI
V1,VREGEN
#use delay(clock=48000000)
#include
#include
#include
/***************************************/
void main(void)
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 84
{
output_d(0x00); //tắt tất cả các led kết nối đến port B
usb_init_cs();
Delay_ms(1000);
while(1)
{
usb_task();
if(usb_enumerated())
{
//nếu quá trình enumerated thành công , tại đây bạn có thể truyền và nhận dữ
liệu
if(usb_kbhit(1))
{
output_d(0xff); // nếu có dữ liệu trong bộ đệm nhận thì bật tất cả các đèn
led
}
}
}
}
Sau khi biên dịch và kết nối đến cổng USB , một thông điệp xuất hiện
báo máy tính đã nhận thiết bi
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 85
Giao tiếp USB và máy tính
BÀI TẬP CHƢƠNG 7
Bài 1: Trình bày về cấu trúc phần cứng trong các giao tiếp RS232, giao
tiếp I2C, SPI.
Bài 2: Thực hiện chƣơng trình demo về giao tiếp USB và kiểm tra kết
quả.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 86
CHƢƠNG 8 LẬP TRÌNH ỨNG DỤNG
Mục tiêu:
Sinh viên biết và thực hiện được cách thức lập trình hiển thị Led 7 đoạn,
LCD bằng CCS.
Sinh viên hiểu được chương trình điều khiển PID cho động cơ DC
8.1. LẬP TRÌNH HIỂN THỊ VỚI LED 7 ĐOẠN
8.1.1 Cấu tạo của led 7 đoạn
Led 7 đoạn
Một led 7 đoạn thực ra là gồm 7 led đơn nối với nhau (8 led đơn nêu có
thêm dấu chấm-dp). Có 2 loại:
Chung catod: các đầu catod (cực âm) đƣợc nối chung với nhau và nối với
đất, các đầu anod a,b,c,d,e,f,g,h đƣợc đƣa ra ngoài (các chân) nhận tín hiệu điều
khiển. Khi cấp điện áp 5v cho mỗi đầu anod, led tƣơng ứng với đầu đó sẽ sáng
Chung anod: các đầu anod (cực âm) đƣợc nối chung với nhau và nối với
nguồn, các đầu catod a,b,c,d,e,f,g,h đƣợc đƣa ra ngoài (các chân) nhận tín hiệu
điều khiển. Muốn led đơn nào sáng chỉ việc đƣa chân catod của led tƣơng ứng
xuống mức 0V.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 87
Cấu tạo của 2 loại led 7 đoạn
8.1.2 Hiển thị 1 led 7 đoạn dùng vi điều khiển:
Hiển thị led 7 đoạn
Nhƣ đã giới thiệu ở phần trên, thực chất led 7 đoạn gồm 8 hoặc 7 led đơn
nối với nhau. Vì vậy để điều khiển thanh led đơn sáng, cách thực hiện phần cứng
nhƣ hình 2.1.
Cụ thể hơn, nhƣ dùng led chung anod nhƣ hình vẽ trên. Mỗi đầu vào
a,b,c,d,e,f,g,h đƣợc nối với một chân của vi điều khiển, tƣơng ứng là RB0, RB1,
..RB7, thông qua các điện trở phân áp 200 ohm, đầu anod chung đƣợc nối với
nguồn. Để led đơn sáng đơn giản ta đƣa chân vi điều khiển nối với led đó xuống
mức thấp.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 88
Nhƣ trên hình 2.4 trên, để led 7 đoạn hiển thị số 2 thì các led a,b,d,e,g
sáng; các led c, f tắt. Giá trị sáng tƣơng ứng chân vi điều khiển nối vào ở mức 0,
giá trị tắt tƣơng ứng với chân vi điều khiển nối với ở mức 1.
Do đó nội dung của thanh ghi PORTB là:
0 0 1 0 0 1 0 0
Đây là mã led 7 đoạn của số 2
Nhƣ vậy, chúng ta lƣu ý một điều rằng, dữ liệu xuất ra led 7 đoạn là mã
led tƣơng ứng với số cần xuất
Mã led tƣơng ứng với các số từ 0 đến 9 là:
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90
Cách điều khiển led 7 đoạn chung catod thì ngƣợc lại.
Ví dụ : Hiển thị 1 led 7 đoạn từ 0-9, delay 1s
#include
void main()
{
int8 i;
int8 so[10]={192,249,164,176,153,146,130,248,128,144};
while(1)
{
for(i=0;i<10;i++)
{
output_C(so[i]);
delay_ms(1000);
}
}
}
8.1.3 Hiển thị nhiều led 7 đoạn dùng vi điều khiển:
Trong thực tế, ta phải dùng nhiều led 7 đoạn để hiển thị.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 89
Vậy giải quyết việc hiển thị nhiều led nhƣ thế nào?
Ví dụ: để hiển thị số 35 bằng 2 led 7 đoạn.
Đối chiếu với cách hiển thị 1 led 7 đoạn, ta nghĩ đơn giản chỉ là dùng 1
cổng hiển thị số 3, 1 cổng khác hiển thị số 5.
Như vậy ta mất 2 cổng. Hiển thị 4 led thì mất 4 cổng => toàn bộ chân
trên vi điều khiển dùng cho việc hiển thị ledKhông còn chân để giao tiếp với
các thiết bị khác như bàn phím, đầu vào số khác v.v Không khả thi!
Ta có phương pháp tiết kiệm chân hơn để giải quyết:
Hiển thị 2 led 7 đoạn
Các chân dữ liệu (chân sẽ nhận mã led từ vi điều khiển) được nối tương
ứng với nhau và nối vào 1 cổng của vi điều khiển, chẳng hạn như cổng B
Chân nguồn của 2 led được điều khiển bởi 2 chân trên vi điều khiển,
chằng hạn chân RA4 và RA5 như trên hình, thông qua cực B của 2 transistor
pnp.
Quá trình hiển thị con số 35 trên 2 led sẽ như sau:
Cho chân RA4 (chân nối với led hàng chục) xuống mức thấp, transistor
thứ nhất mở do tiếp giáp BE thuận, chân RA5 lên mức cao (chân nối với led
hàng đơn vị), transistor thứ hai không mở. Vậy chỉ có led hàng chục được cấp
nguồn.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 90
Cho cổng B xuất dữ liệu mã led của số 3. Chỉ có led hàng chục được cấp
nguồn nên chỉ có led này sáng
Tạo thời gian trễ 10-20ms
Điều khiển tương tự cho led hàng đơn vị được cấp nguồn, led hàng chục
không cấp nguồn, xuất dữ liệu mã led số 5 ra cổng B. Led đơn vị hiển thị số 5.
Tạo thời gian trễ 10-20ms
Quay lại bước thứ nhất
Nhƣ vậy, số 3 hiển thị 10ms, số 5 hiển thị 10ms và quay vòng nhƣ vậy.
Thời gian này rất nhanh, do hiệu ứng của mắt, ta cảm giác nhƣ số 35 hiển thị
cùng lúc. Bài toán đƣợc giải quyết, ta chỉ mất có 10 chân để điều khiển 2 led.
Cách hiển thị nhiều led cũng tƣơng tự nhƣ vậy.
Cũng giải thích thêm lí do dùng transistor nối vào RA4, RA5. Do chân vi
điều khiển có dòng khoảng vài chục mA, đây là chân cấp nguồn cho led 7 đoạn,
mỗi led đơn trong Led 7 đoạn mất 20mA vây cả led 7 đoạn mất trên 100mA. Vì
vậy ta phải dùng transistor để khuếch đại dòng.
8.2. GIAO TIẾP VỚI MÀN HÌNH LCD
8.2.1. Hiển thị dùng LCD
Các chân LCD
8.2.2. Các chân cơ bản của LCD 2 dòng 16 kí tự
VSS: Chân đất
VCC: Chân nguồn
D
7
1
4
D
6
1
3
D
5
1
2
D
4
1
1
D
3
1
0
D
2
9
D
1
8
D
0
7
E
6
R
W
5
R
S
4
V
S
S
1
V
D
D
2
V
E
E
3
LCD1
LM016L
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 91
VEE: Chân hiệu chỉnh độ sáng của LCD
RS:
=0: LCD sẽ nhận lệnh từ vi điều khiển
=1: LCD sẽ nhận kí tự từ vi điều khiển để hiển thị
R/W:
=1: Vi điều khiển đọc dữ liệu từ LCD
=0: Vi điều khiển ghi dữ liệu lên LCD
Thông thƣờng Vi điều khiển chủ yếu ghi dữ liệu lên LCD nên chân này
thƣờng nối đất
E: Chân cho phép (Enable). Sau khi lệnh hoặc dữ liệu đã đƣợc chuẩn bị
trên đƣờng dữ liệu, tạo xung mức cao-mức thấp sẽ bắt đầu quá trình LCD nhận
dữ liệu hoặc lệnh từ vi điều khiển.
D0-D7: các chân dữ liệu, nơi vi điều khiển truyền lệnh hoặc dữ liệu lên
LCD.
8.2.3. Khởi tạo LCD
LCD có nhiều độ làm việc, có thể kể ra nhƣ sau:
Chế độ 1 dòng hay 2 dòng
Chế độ giao tiếp 4 bit hay 8 bit
Chế độ font 5*8 hoặc 5*10
Ngoài ra còn có thể thay đổi vị trí hiển thị kí tự v.v
Vì vậy, trƣớc khi bắt đầu quá trình hiển thị một chuỗi kí tự nào đó, ta cần
quá trình khởi tạo để
cài đặt các chế độ này. Vi điều khiển thực hiện quá trình khởi tạo này bắt
cách ghi đến LCD một chuỗi các lệnh.
Căn cứ vào chức năng của các chân vi điều khiển đƣợc giới thiệu ở trên,
ta đƣa ra qui trình của việc gửi một lệnh từ Vi điều khiển đến LCD:
Cho chân R/W=0 để xác định đây là ghi xuống LCD (thông thƣờng chân
này đƣợc nối đất, nên mặc định chân này ở mức 0, ta không cần quan tâm đến
nữa)
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 92
Cho chân RS=0 để xác định đây là lệnh mà vi điều khiển gửi xuống LCD
(phân biệt với RS=1, gửi kí tự hiển thị)
Gửi mã lệnh xuống LCD theo các đƣờng dữ liệu (RD0-RD7 nếu dùng
chế độ 8 bit, R4-R7 nếu dùng chế độ 4 bit)
Đƣa chân E (chân cho phép- Enable) lên mức cao, mức 1
Tạo trễ vài chu kì lệnh
Đƣa chân E xuống mức thấp, mức 0
Mã lệnh nhƣ đã giới thiệu trong phần trên tùy thuộc vào từng lệnh, ở đấy
giới thiệu một số lệnh cơ bản nhƣ sau:
. Lệnh cài đặt chế độ làm việc:
0 0 1 DL N F - -
DL:
= 1: 8 bit
= 0: 4 bit
N:
= 1: 2 dòng
= 0 1 dòng
F:
= 1: font 5x10 dot
= 0: font 5x8 dot
. Lệnh đặt chế độ tăng giảm địa chỉ:
0 0 0 0 0 1 I/D S
I/D:
= 1 tăng địa chỉ
= 0 giảm địa chỉ
S:
=1: Cài đặt di chuyển cùng địa chỉ
. Lệnh đặt chế độ hiển thị:
0 0 0 0 1 D C B
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 93
D: Cho phép hiển thị
C: cài đặt hiển thị con trỏ
B: nhấp nháy vị trí kí tự
. Lệnh đặt vị trí hiển thị của kí tự:
1 ĐC ĐC ĐC ĐC ĐC ĐC ĐC
Địa chỉ dòng 1: 00- 0F
Địa chỉ dòng 2: 40-4F
Vì vậy, muốn hiển thị đầu dòng thứ nhất, mã lệnh sẽ là 0x80
muốn hiển thị đầu dòng thứ hai, mã lệnh sẽ là 0xC0
. Lệnh xóa màn hình: mã lệnh 0x01
. Lệnh trở về đầu dòng thứ nhất: mã lệnh 0x02
Chi tiết có thề xem datasheet đi kèm
8.2.4. Ghi kí tự lên LCD để hiển thị
Sau khi thực hiện quá trình khởi tạo để gửi các lệnh cài đặt chế độ làm
việc cùa LCD, kí tự sẽ đƣợc hiển thị lên LCD bất kì khi nào vi điều khiển muốn
gửi.
Quá trình gửi kí tự gồm các bƣớc sau:
Cho chân R/W=0 để xác định đây là ghi xuống LCD (thông thƣờng chân
này đƣợc nối đất, nên mặc định chân này ở mức 0, ta không cần quan tâm đến
nữa)
Cho chân RS=1 để xác định đây là kí tự mà vi điều khiển gửi xuống LCD
(phân biệt với RS=0, gửi lệnh)
Gửi mã ascii của kí tự cần hiển thị xuống LCD theo các đƣờng dữ liệu
(RD0-RD7 nếu dùng chế độ 8 bit, R4-R7 nếu dùng chế độ 4 bit)
Đƣa chân E (chân cho phép- Enable) lên mức cao, mức 1
Tạo trễ vài chu kì lệnh
Đƣa chân E xuống mức thấp, mức 0
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 94
8.2.5. Giới thiệu một thƣ viện cho LCD 4 bit và bài tập ứng dụng
File: LCD_lib_4bit:
#include
#define LCD_RS PIN_B2
#define LCD_EN PIN_B3
#define LCD_D4 PIN_B4
#define LCD_D5 PIN_B5
#define LCD_D6 PIN_B6
#define LCD_D7 PIN_B7
#define Line_1 0x80
#define Line_2 0xC0
#define Clear_Scr 0x01
#separate void LCD_Init ();// ham khoi tao LCD
#separate void LCD_SetPosition ( unsigned int cX );//Thiet lap vi tri con
tro
#separate void LCD_PutChar ( unsigned int cX );// Ham viet1kitu/1chuoi
len LCD
#separate void LCD_PutCmd ( unsigned int cX) ;// Ham gui lenh len
LCD
#separate void LCD_PulseEnable ( void );// Xung kich hoat
#separate void LCD_SetData ( unsigned int cX );// Dat du lieu len chan
Data
//khoi tao LCD**********************************************
#separate void LCD_Init ()
{
LCD_SetData ( 0x00 );
delay_ms(20); /*Cho cho lcd khoi tao */
output_low ( LCD_RS );// che do gui lenh
LCD_SetData ( 0x03 ); /* khoi tao che do 4 bit */
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 95
LCD_PulseEnable();
LCD_PulseEnable();
LCD_PulseEnable();
LCD_SetData ( 0x02 ); /* tao giao dien 4 bit */
LCD_PulseEnable(); /* send dual nibbles hereafter, MSN first */
LCD_PutCmd ( 0x2C ); /* function set (all lines, 5x7 characters) */
LCD_PutCmd ( 0x0C ); /* display ON, cursor off, no blink */
LCD_PutCmd ( 0x06 ); /* entry mode set, increment & scroll left */
LCD_PutCmd ( 0x01 ); /* clear display */
// Init for BarGraph
}
#separate void LCD_SetPosition ( unsigned int cX )
{
/* this subroutine works specifically for 4-bit Port A */
LCD_SetData ( swap ( cX ) | 0x08 );
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) );
LCD_PulseEnable();
}
#separate void LCD_PutChar ( unsigned int cX )
{
/* this subroutine works specifically for 4-bit Port A */
output_high ( LCD_RS );
LCD_PutCmd( cX );
output_low ( LCD_RS );
}
#separate void LCD_PutCmd ( unsigned int cX )
{
LCD_SetData ( swap ( cX ) ); /* send high nibble */
LCD_PulseEnable();
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 96
LCD_SetData ( swap ( cX ) ); /* send low nibble */
LCD_PulseEnable();
}
#separate void LCD_PulseEnable ( void )
{
output_high ( LCD_EN );
delay_us ( 3 ); // was 10
output_low ( LCD_EN );
delay_ms ( 3 ); // was 5
}
#separate void LCD_SetData ( unsigned int CX )
{
output_bit ( LCD_D4, CX & 0x01 );
output_bit ( LCD_D5, CX & 0x02 );
output_bit ( LCD_D6, CX & 0x04 );
output_bit ( LCD_D7, CX & 0x08 );
}
Chƣơng trình ứng dụng:
Ví dụ về LCD
#include
RA0/AN0
2
RA1/AN1
3
RA2/AN2/VREF-/CVREF
4
RA4/T0CKI/C1OUT
6
RA5/AN4/SS/C2OUT
7
RE0/AN5/RD
8
RE1/AN6/WR
9
RE2/AN7/CS
10
OSC1/CLKIN
13
OSC2/CLKOUT
14
RC1/T1OSI/CCP2
16
RC2/CCP1
17
RC3/SCK/SCL
18
RD0/PSP0
19
RD1/PSP1
20
RB7/PGD
40
RB6/PGC
39
RB5
38
RB4
37
RB3/PGM
36
RB2
35
RB1
34
RB0/INT
33
RD7/PSP7
30
RD6/PSP6
29
RD5/PSP5
28
RD4/PSP4
27
RD3/PSP3
22
RD2/PSP2
21
RC7/RX/DT
26
RC6/TX/CK
25
RC5/SDO
24
RC4/SDI/SDA
23
RA3/AN3/VREF+
5
RC0/T1OSO/T1CKI
15
MCLR/Vpp/THV
1
UDK
PIC16F877A
C1
30pF
C2
30pF
X1
CRYSTAL
R9
4K
D
7
1
4
D
6
1
3
D
5
1
2
D
4
1
1
D
3
1
0
D
2
9
D
1
8
D
0
7
E
6
R
W
5
R
S
4
V
S
S
1
V
D
D
2
V
E
E
3
LCD1
LM016L
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 97
#fuses HS, NOLVP, NOWDT, NOPROTECT
#use delay (clock=4000000) //Use built-in function: delay_ms() &
delay_us()
#include "LCD_LIB_4BIT.c"
VOID MAIN()
{
LCD_INIT();
LCD_PUTCHAR('X');
DELAY_MS(1000);
LCD_PUTCHAR('I');
DELAY_MS(1000);
LCD_PUTCHAR('N');
DELAY_MS(1000);
LCD_PUTCHAR(' ');
DELAY_MS(1000);
LCD_PUTCHAR('C');
DELAY_MS(1000);
LCD_PUTCHAR('H');
DELAY_MS(1000);
LCD_PUTCHAR('A');
DELAY_MS(1000);
LCD_PUTCHAR('O');
8.3. ĐIỀU KHIỂN PID CHO ĐỘNG CƠ DC
#include "PID1.h"
//Dinh nghia cac duong dieu khien motor
#define Sampling_time 50 //thoi gian lay mau (ms)
#define inv_Sampling_time 20 // 1/Sampling_time
#define PWM_Period 1023
unsigned int16 Pulse=0,pre_Pulse=0;
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 98
signed long rSpeed=0,Err=0 , pre_Err=0; //thanh phan PID
float Kp=5, Kd=0.6, Ki=2.4; //thanh phan PID
float pPart=0, iPart=0, dPart=0; //thanh phan PID
unsigned long Ctrl_Speed=10; //van toc can dieu khien (desired speed)
unsigned int16 Output;// absrSpeed;
unsigned char sample_count=0;
void Motor_Speed_PID(long int des_Speed);
#int_EXT
void EXT_isr(void)
{
if(!input(PIN_B0))Pulse++;
else Pulse--;
}
#int_TIMER1
void TIMER1_isr(void)
{
Set_timer1(3035);//25ms
sample_count++;
Motor_Speed_PID(Ctrl_Speed);
}
void Motor_Speed_PID(unsigned long des_Speed)
{
rSpeed=Pulse-pre_Pulse; //tinh van toc (trong sampling time)
pre_Pulse=Pulse;
Err=des_Speed-abs(rSpeed); //tinh error (loi)
pPart=Kp*Err;
dPart=Kd*(Err-pre_Err)*inv_Sampling_time;
iPart+=Ki*Sampling_time*(Err+pre_Err)/2000;
Output +=pPart+dPart+iPart; //cong thuc duoc bien doi vi la dieu
khien van toc
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 99
if (Output >PWM_Period) Output=PWM_Period-1;
if (Output <=0) Output=1;
set_pwm1_duty((int16)Output); //gan duty cycle cho CCP1 update
PWM
pre_Err=Err; //luu lai gia tri error
}
void main()
{
set_tris_a(0xff);
//set_tris_b(0x01);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
setup_timer_2(T2_DIV_BY_16,255,1);
setup_ccp1(CCP_PWM);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_EXT);
ext_int_edge( H_TO_L ); // Sets up EXT
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
while(true)
{
}
}
BÀI TẬP CHƢƠNG 8
Bài 1: Hiển thị 1 led 7 đoạn từ 0 đến 9
Bài 2: Sử dụng 2 Led 7 đoạn (phần cứng tự thiết kế)
- Lập trình cho 2 led hiển thị số 35
- Lập trình hiển thị số đếm từ 0-99
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 100
Bài 3: Lập trình thực hiển hiển thị họ tên, thay đổi các chế độ hiển thị
bằng cách gửi lệnh lên LCD
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 101
TÀI LIỆU THAM KHẢO
1. CCS C Complier Manual - Custom Computer Services - PO BOX
2452 BROOKFIELD, WI 53008 U.S.A – 2016.
2. Lập Trình Cho PIC Dùng PIC C Compiler – HanoiAptech Computer
Education Center.
3. Lập Trình Cho PIC Dùng PIC C Compiler - www.mientayvn.com.
4. PIC18F2331/2431/4331/4431 data Sheet - Microchip Technology Inc
2003.
5. Programmation en C d‘un microcontrôleur - Lycée LACHENAL - M.
BERNARD - édité le 13/11/2008.
6. Vi điều khiển PIC – học nhanh đi vào ứng dụng – Falleaf - Diễn đàn
PICVietnam.com.
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 102
PHỤC LỤC: CƠ BẢN VỀ CCS
1. Cơ bản về ngôn ngữ lập trình CCS
1.1. Ví dụ về một chƣơng trình viết trên ngôn ngữ CCS
// Đây là chú thích chương trình
//Bắt đầu các chỉ thị tiền xử lý của chương trình
#include // cho file định nghĩa thiết bị 16f877a.h vào chương
trình
#fuses HS,NOLVP,NOWDT// Cấu hình cho vi điều khiển PIC
#use delay (clock=4000000) // dùng thạch anh tần số 4MHz
// Khai báo biến hằng
byte const MAP[10] =
{0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
//===========================================
//===========================================
// Bắt đầu chương trình con hiển thị
void display(int n)
{
char b; // khai báo biến b
b=((MAP[n/10]) ^ 0x00);
if ((n/10)==(0)) b=0xff;
output_b(b); // sử dụng hàm xuất giá trị ra cổng B
output_low(PIN_A4);// sử dụng hàm đưa giá trị chân RA4 xuống mức
thấp
delay_ms(2);// Sử dụng hàm tạo trễ 2 ms
output_high(PIN_A4); // sử dụng hàm đưa giá trị chân RA4 lên mức cao
output_b((MAP[n%10]) ^ 0x00);
output_low(PIN_A5);
delay_ms(2);
output_high(PIN_A5);
}
// Kết thúc chương trình con hiển thị
//============================================
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 103
// Bắt đầu chương trình chính
// Đây là nơi vi điều khiển bắt đầu chạy lệnh
//============================================
void main()
{
int i,count;
count=0;
while(TRUE)
{
for (i=0;i<=50;i++)
display(count); // dispay 50 times
count=(count==99) ? 1: count+1;
}
}
1.2 Cấu trúc của một chương trình viết bằng CCS:
1.2.1 Khai báo tiền xử lý
Bắt đầu một chƣơng trình viết bằng ngôn ngữ CCS là phần khai báo tiền xử
lý:
1. Đầu tiên là phần khai báo file header:
#include
Ví dụ: # include
Việc khai báo này thực chất là chép cả file 18f4431.h vào chƣơng trình
này.
Vậy nội dung của file .h này là gì? Nội dung của file này sẽ định nghĩa tấc
cả các tên cũng nhƣ định nghĩa các hằng sẽ đƣợc dùng trong các hàm chức năng
của CCS.
Có thể mở file: C:\Program Files\PICC\Devices\16f877a.h để hiểu thêm
2. Thứ hai là phần khai báo cấu hình:
#fuses HS,NOLVP,NOWDT
Vi điều khiển PIC có thể hoạt động ở nhiều chế độ khác nhau, cũng nhƣ
cách cấu hình phần cứng của nó cũng có nhiều chế độ. Mỗi chế độ nhƣ vậy đƣợc
khai báo và dùng sẽ ảnh hƣởng đến hoạt động của các khối chức năng, cũng nhƣ
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 104
các chân của vi điều khiển. Vì vậy, đối với mỗi ứng dụng, ta phải khai báo cấu
hình cho phù hợp.
Trong ví dụ trên, khai báo cấu hình cho bộ dao động kiểu HS, không sử
dụng chức năng Watchdog Timer, và lập trình điện áp thấp.
3. Thứ ba là phần khai báo tần số của thạch anh dùng cho ứng dụng, tốc
độ này phải phù hợp với thạch anh ta dùng trong mạch.
# USE Delay(clock=tần số thạch anh)
Ví dụ: # USE Delay(clock=4000000)// Khai báo dùng thạch anh 4 MHz
Điều lƣu ý là chúng ta chỉ dùng đƣợc hàm tạo thời gian trễ delay_ms(),
delay_us() sau khi có khai báo này trong chƣơng trình.
4. Ngoài ra, khi sử dụng bất cứ khối chức năng đặc biệt nào trong vi điều
khiển PIC ta phải dùng chỉ thị tiền xử lý #USE để khai báo. Các khối chức năng
đặc biệt là RS232, PWM, SPI, I2C ..v.v
Ví dụ: #use rs232(baud=9600, xmit=PIN_C6,rcv=PIN_C7)
1.2.2 Phần khai báo biến toàn cục
Sau phần khai báo tiền xử lý là phần khai báo biến toàn cục nếu có.
Cũng nhắc lại biến toàn cục là biến đƣợc sử dụng trong toàn bộ chƣơng
trình, cả chƣơng trình chính và chƣơng trình con. Điều này khác với biến cục bộ
là biến đƣợc khai báo trong các chƣơng trình con, hàm con, chƣơng trình chính,
các biến này chỉ đƣợc tạo ra và sử dụng trong chính mỗi chƣơng trình khai báo
nó.
Nhân đây cũng giới thiệu qua dạng dữ liệu dùng trong CCS. Có một số
các dạng cơ bản nhƣ sau:
Khai báo biến:
Int1,short: dạng logic 1,0
Int,Int8,byte: dạng số nguyên 8 bit, nếu khai báo dạng số nguyên 8 bit có
dấu thêm signed
Int16,long: dạng số nguyên 16 bit
Int32: dạng số nguyên 32 bit
Char: dạng kí tự 8 bit
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 105
Float: dạng số thực 32 bit
Ví dụ: int8 a; // Khai báo a là biến số nguyên 8 bit
Khai báo hằng số:
Ví dụ: int8 const a=231;
Khai báo mảng hằng số:
Ví dụ: int const a[5]= {1, 23, 3, 4, 5}
2.4.2.3 Phần khai báo, định nghĩa các chương trình con
Chƣơng trình con là chƣơng trình sẽ đƣợc gọi từ chƣơng trình chính hoặc
chƣơng trình con khác.
Chƣơng trình con phải đƣợc khai báo và định nghĩa trong một file chƣơng
trình ứng dụng.
Phần khai báo phải đặt trƣớc chƣơng trình chính (trong file)
Phần định nghĩa có thể định nghĩa ngay trong khai báo hoặc đƣợc đặt bất
kì nơi nào sau phần khai báo biến toàn cục nếu có.
Ngoài các chƣơng trình con bình thƣờng ra, còn có chƣơng trình con phục
vụ ngắt đƣợc đặt sau khai báo tiền xử lý: # int_tên ngắt. Phần này sẽ đƣợc bàn kĩ
hơn trong các bài học sau.
1.2.3 Phần chương trình chính
Bắt đầu bằng:
void main()
{
}
Cũng nhắc lại là trong một chƣơng trình CCS , vi điều khiển sẽ chạy từ
chƣơng trình chính, hay nói cách khác là từ dòng lệnh đầu tiên sau void main().
Các chƣơng trình con chỉ đƣợc gọi tại các lời gọi chƣơng trình con trong
chƣơng trình chính hoặc từ các chƣơng trình con khác. Chƣơng trình con phục
vụ ngắt chỉ đƣợc chạy khi có ngắt xảy ra, và ngắt đó đƣợc cho phép (sẽ bàn kĩ
hơn trong các bài học sau).
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 106
2. Các cấu trúc thuật toán của ngôn ngữ CCS
Cấu trúc thuật toán của ngôn ngữ CCS kế thừa 100% từ ngôn ngữ C. Ở
đây xin nhắc lại một số các cấu trúc hay dùng:
- Cấu trúc IF:
If (biểu thức)
Lệnh1;
Else lệnh2;
Ví dụ: if (x==25)
x=1;
else
x=x+1;
- Cấu trúc lặp While:
While (biểu thức)
{
Các lệnh;
}
Ví dụ: While (count<20)
{
Output_B(count);
Count=count+1;
}
Chú ý: while(1) sẽ thực hiện các lệnh trong khối while này mãi mãi
- Cấu trúc lặp FOR:
For (biểu thức 1, biểu thức 2, biểu thức 3)
{
Các lệnh;
}
Ví dụ: for (i=1;i<=10;++i)
A=a+i;
- Cấu trúc lựa chọn SWITCH:
SWITCH (biến)
{
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 107
Case giá trị 1: lệnh 1;
Break;
Case giá trị 2: lệnh 2;
Break;
Case giá trị n: lệnh n
Break;
[default: lệnh n+1; break;]
}
Ví dụ: switch (cmd)
{ case 0:printf("cmd 0");
break;
case 1:printf("cmd 1");
break;
default:printf("bad cmd");
break;
}
Chú ý: lệnh break đƣợc dùng để thoát lập tức khỏi một vòng lặp For,
While, Switch
3. Các toán tử cơ bản trong CCS:
Hoàn toàn tƣơng tự trong C.
Nhắc lại một số toán tử hay dùng:
- += ý nghĩa là cộng thêm một giá trị và lấy kết quả
Ví dụ: a+=2 nghĩa là a= a+2
Tƣơng tự đối với các phép toán trừ, chia, nhân
-++ ý nghĩa là cộng thêm 1 đơn vị vào biến
Ví dụ: a++; tức là a=a+1
- &&: phép AND
- ||: phép OR
- !: phép NOT
- !=: không bằng
- >>n: dịch trái n bit
- <<n: dịch phải n bit
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 108
4. Các hàm số học cơ bản trong CCS
Hoàn toàn giống trong C.
Nhắc lại một số hàm cơ bản:
Abs (): lấy trị tuyệt đối
Ceil(): làm tròn theo hƣớng tăng
Floor(): làm tròn theo hƣớng giảm
Pow(): lũy thừa
Sqrt(): lấy căn
Chi tiết tra help CCS : trong tab contents, chọn Built-In-Function
Chú ý là khi sử dụng các hàm này cần khai báo file header tƣơng ứng
5. Các hàm vào ra cơ bản trong CCS
Output_low (chân): cho chân xuống mức logic thấp (mức điện áp 0V),
chân có thể là:
PIN_A0, PIN_A1, ..PIN_B0, PIN_B1,.. PIN_C0,..v.v Nói chung là các
chân có tên trong file C:\Program Files\PICC\Devices\16f877a.h
Ví dụ: Output_low(PIN_D0) đƣa chân RD0 của PIC xuống mức thấp
Output_high(chân): cho chân lên mức logic thấp (mức điện áp 0V), chân
có thể là:
PIN_A0, PIN_A1, ..PIN_B0, PIN_B1,.. PIN_C0,..v.v Nói chung là các
chân có tên trong file C:\Program Files\PICC\Devices\16f877a.h
Ví dụ: Output_high(PIN_a5) đƣa chân Ra5 của PIC lên mức cao
Output_bit(chân,giá trị): là lệnh tổng hợp 2 lệnh trên, xuất giá trị ra
chân. Giá trị có thể là 0 (mức thâp) hoặc là 1 (mức cao). Tên chân tƣơng tự nhƣ
2 lệnh trên
Ví dụ: output_bit(PIN_E0,1); đƣa chân E0 lên mức 1
Output_X(giá trị): lệnh này đƣa giá trị ra cổng X. X có thể là A, B, C, D,
E.
Ví dụ: Output_A(0x21); đƣa giá trị 0x21 ra cổng A
Biến=Input_X(): đƣa giá trị của cổng X vào Biến. X là A, hoặc B, C, D,
E
Bài giảng kỹ thuật lập trình vi điều khiển
Trang 109
Ví dụ: bien1= Input_A()
Biến=Input(chân): lệnh này đƣa giá trị của chân vào biến. Chân tƣơng tự
nhƣ trong các lệnh.
Ví dụ: bien2= Input(PIN_A2);
6. Các hàm tạo trễ
Các hàm tạo trễ gồm delay_cycles(), delay_us(), delay_ms. Tạo một
khoảng thời gian trễ từ lúc lệnh đƣợc thực hiện. Chú ý là phải sử dụng khai báo
tiền xử lý # use delay(clock=tần sô) thì mới dùng đƣợc các lệnh này.
delay_cycles(số chu kỳ): tạo trễ một khoảng thời gian bằng số chu kỳ. Số
chu kỳ=0-255
delay_us(số micro giây): tạo trễ số micro giây. Số micro giây =0-65535
delay_ms(số mili giây): tạo trễ số mili giây. Số mili giây= 0-65535
Các file đính kèm theo tài liệu này:
- bai_giang_ky_thuat_lap_trinh_vi_dieu_khien_pham_truong_tung.pdf