Bài giảng Kỹ thuật lập trình vi điều khiển - Phạm Trường Tùng

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

pdf115 trang | Chia sẻ: linhmy2pp | Ngày: 21/03/2022 | Lượt xem: 240 | Lượt tải: 0download
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:

  • pdfbai_giang_ky_thuat_lap_trinh_vi_dieu_khien_pham_truong_tung.pdf