LED ĐƠN
1.1 Yêu cầu Điều kiển các chân I/0 của pic 16F887 với chức năng output thông qua chớt tắt các LED được nối với PORT E của vi điều khiển.
LED là một loại diode có khả năng phát sáng, bao gồm ánh sáng nhìn thấy, tia hồng ngoại và tia tử ngoại Điện thế phân cực thuận của LED dao động từ 1.5 đến 3V, trong khi điện thế phân cực nghịch thường thấp Do đó, LED rất dễ bị hư hỏng khi tiếp xúc với điện thế ngược.
Sơ đồ: Mạch điều kiển nối với PORT E 1.4 Cách điều kiển các chân xuất nhập số
PORT E có chức năng nhập số I/0 và chắc năng chuyển đổng ADC.
Để xác định các chân của PORT E là chân INPUT hay OUTPUT, chúng ta có thể sử dụng lệnh TRISB, TRISC, TRISD hoặc TRISE Tuy nhiên, vì đang điều khiển PORT E, nên lệnh phù hợp để sử dụng là TRISE.
- Mỗi chân sẽ có một trạng thái là 0 (chân OUTPUT) hoặc 1 (chân INPUT).
- Cả ba chân RE2, RE1, RE0 là chân OUTPUT thì: TRISE = 0b00 = 0x00 thứ tự bit là RE2-RE1-RE0.
- Chúng ta có thể khai báo mã ở dạng nhị phân 0b… hoặc khai báo mã ở dạng thập lục phân 0x…(mã hex).
Nếu là chân OUTPUT thì dùng 0 (mức thấp) hoặc 1 (mức cao) để hiển thị trạng thái của một chân.
Nếu là chân INPUT thì phải đọc tín hiệu của chân đó.
Một số hàm hổ trợ: delay_ms(số mili giây) hoặc delay_us(số micro dây) và các cấu trúc lập trình for, while, if, if…else,…
Yêu cầu viết chương trình chớp tắt LED ở PORT E với thời gian delay 250ms: Chương trình 1.1:
#include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#FUSES NOWDT, HS, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock = 20000000) //Tan so thach anh 20MHz void main(){
TRISE = 0x00; //Tat ca cac chan o PORT E la chan xuat (output) while (true){
PORTE = 0x00; //Tat ca cac chan o muc thap > LED tat delay_ms(250); //Duy tri trang thai cu trong 250ms
PORTE = 0x07; //Chan RE2, RE1, REO o muc cao >LED D3, D4, D5 sang delay_ms(250);
Yêu cầu viết chương trình chớp tắt LED ở PORT E với thời gian delay
#include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#FUSES NOWDT, HS, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock = 20000000) //Tan so thach anh 20MHz void main(){
TRISE = 0x00; //Tat ca cac chan o PORT E la chan xuat (output) while (true){
PORTE = 0x00; //Tat ca cac chan o muc thap > LED tat delay_ms(1000); //Duy tri trang thai cu trong 250ms
PORTE = 0x07; //Chan RE2, RE1, REO o muc cao >LED D3, D4, D5 sang delay_ms(1000);
Yêu cầu viết chương trình chớp tắt LED ở chân RE1 với thời gian delay 1s và ở chân RE2 với thời gian delay là 0.5s:
#include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#FUSES NOWDT, HS, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock = 20000000) //Tan so thach anh 20MHz void main(){
TRISE = 0x00; //Tat ca cac chan o PORT E la chan xuat (output) while (True){
HIỂN THỊ KÝ TỰ TRÊN LCD
Viết chương trình hiển thị ký tự trên LCD.
Chức năng của các chân của LCD:
STT Ký hiệu Mô tả Giá Trị
3 VEE Tùy chỉnh độ tương phản
4 RS Lựa chọn thanh ghi RS=0: ghi lệnh
5 R/W Chọn thanh ghi đọc/viết dữ liệu
R/W=0: viết dữ liệu R/W=1: đọc dữ liệu
Chân chuyền dữ liêu 8 bit từ BD0 đến BD7
15 A Cực dương của LED nền 0 đến 5V
16 K Cực âm của LED nền 0V
*Ngoài sử dụng LCD ta còn có thể sử dụng LED 7 đoạn, LED ma trận để hiển thị dữ liệu
Sơ đồ: Mạch điều kiển LCD 1.4 Cách lệch cơ bản để sử dụng LCD
Sử dụng thư viện LCD_LIB_4BIT.C để điều kiển LCD.
Các bước cơ bản để bắt đầu làm việc với LCD:
Thêm thư viện LCD vào chương trình: #include
Dùng LCD ở chế độ ghi ta dùng lệnh: OUTPUT_LOW(LCD_RW);
Khởi tạo LCD, dùng hàm: LCD_Init();
Chức năng một số hàm trong thư viện được sử dụng:
- void LCD_Init ( void );// ham khoi tao LCD
- void LCD_SetPosition ( unsigned int cX );//Thiet lap vi tri con tro
- void LCD_PutChar ( unsigned int cX );// Ham viet1kitu/1chuoi len LCD
- void LCD_PutCmd ( unsigned int cX) ;// Ham gui lenh len LCD
- void LCD_PulseEnable ( void );// Xung kich hoat
- void LCD_SetData ( unsigned int cX );// Dat du lieu len chan Data. Cách sử dụng hàm printf:
-xuất chuỗi, ký tự:printf (“chuỗi, ký tự cần xuất”);
* %.f: quy định số chữ số sau dấu phẩy.
Các cấu trúc: while, for, if, if…else,…
Yêu Cầu viết chương trình hiển thị các ký tự sau lên LCD:
DAI HOC KTCN CAN THO Chương trình 2.1:
#fuses HS,NOWDT, NOPROTECT, NOLVP
#use delay(clock 000000) //Tan so thach anh 20MHz
#include //Them thu vien LCD vao void main(){
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
LCD_PutCmd(0x01); //Xoa man hinh
LCD_PutChar("KTCN CAN THO");
Kết quả hiển thị ký tự lên LCD bài tập 2.1
Yêu cầu lập trình để hiển thị thông tin trên màn hình LCD, trong đó hàng đầu tiên sẽ trình bày họ và tên của sinh viên, còn hàng thứ hai sẽ hiển thị mã số sinh viên.
#fuses HS,NOWDT, NOPROTECT, NOLVP
#use delay(clock 000000) //Tan so thach anh 20MHz
#include //Them thu vien LCD vao void main(){
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
LCD_PutCmd(0x01); //Xoa man hinh
LCD_PutChar("Son Ngoc Phat");
Kết quả hiển thị ký tự họ tên và mã số sinh viên lên LCD Bài tập2.3
Yêu cầu viết chương trình đếm số từ 0 đếm 999 hiển thị trên LCD: Chương trình 2.3
#include // Khai bao ten PIC
#fuses HS,NOWDT, NOPROTECT, NOLVP
#use delay(clock 000000) //Tan so thach anh 20MHz
#include //Them thu vien LCD vao void main(){ unsigned long count,i, N_max = 999; //Gia tri dem gioi han int16 sleep = 200; //Thoi gian delay (ms)
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
LCD_PutCmd(0x01); //Xoa man hinh
LCD_PutChar("Dem so:"); while (True){ count = 0; for (i = 0; i N_max){ //Reset lai bien count count = 0;
LCD_PutChar("Reset!"); //Xoa man hinh delay_ms(2000);
LCD_PutCmd(0x01); //Xoa man hinh
LCD_PutChar("Dem so:");//xuat ra man hinh
XỬ LÝ NGẮT
Viết chương trình xử lý ngắt và nút nhấn
Ngắt là tín hiệu điều khiển giúp vi điều khiển tạm dừng công việc hiện tại để thực hiện các thao tác khác theo quy định của chương trình ngắt Khi phát hiện ngắt, vi điều khiển sẽ khởi động một chương trình độc lập, được gọi là chương trình ngắt.
Để viết hàm phục vụ ngắt, bạn chỉ cần thêm khai báo #INT_tên_ngắt trước hàm đó Trình dịch sẽ nhận diện đây là địa chỉ hàm cho ngắt, và khi ngắt tương ứng xảy ra, hệ thống sẽ tự động chuyển đến vị trí của hàm này.
1.3 Thiếp lập hoạt động ngắt
Sử dụng các lệch sau:
ENABLE_INTERRUPTS (level); với level là INT_tên_ngắt hoặc GLOBAL ( ngắt toàn cục): cho phép ngắt.
DISABLE_INTERRUPTS (level); với level giống như trên: vô hiệu quá ngắt.
CLEAR_INTERRUPTS (level); với level không có GLOBAL: xóa cờ ngắt.
EXT_INT_EDGE (soure, edge); với:
Soure = 0,1,2: nguồn ngắt ( ứng với EXT0, EXT1, EXT2).
Edge= L_TO_H, H_TO_L:cạnh kính ngắt
Thiết kế chương trình có dùng ngắt
Trong hàm main(): cho phép ngắt cụ thể (tên_ngắt), ngắt toàn cục (GLOBAL) và đợi ngắt (EXT_INT_EDGE).
Chương trình xử lý ngắt (đặt trước hàm main ()): xóa cờ ngắt
(CLEAR_INTERRUPTS), cấm ngắt toàn cục (DISABLE_INTERRUPTS (GLOBAL);), xứ lý ngắt xong rồi cho phép ngắt toàn cục (ENABLE_INTERRUPTS(GLOBAL);).
Yêu cầu viết chương trình nhận nút nhấn ở chân B0 của PICf887, cứ mỗi lần nhấn phím sẽ đảo trạng thái các LED ở PORT E:
Mạch đảo trạng thái LED ở PORT E với ngắt ngoài
#include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock = 20000000) //Tan so thach anh 20MHz
#INT_EXT //Ngat ngoai - chan B0 void NgatNgoai(){
CLEAR_INTERRUPT(INT_EXT); //Xoa co ngat
DISABLE_INTERRUPTS(GLOBAL); //vo hieu hoa ngat toan cuc
//Xu ly chuong trinh ngat
PORTE = ~PORTE; //Dao trang thai PORT ENABLE_INTERRUPTS(GLOBAL); //Cho phep ngat toan cuc
PORT_B_PULLUPS(0x01); //Noi dien tro len nguon cho B0
PORTE = 0x00; //Set gia tri ban dau la muc 0
ENABLE_INTERRUPTS(INT_EXT); //Kich hoat ngat ngoai
EXT_INT_EDGE(H_TO_L); //Chon canh ngat, cao xuong thap
ENABLE_INTERRUPTS(GLOBAL); //Cho phep ngat toan cuc while (True){ //Duy tri hoat dong cua vi dieu khien
Yêu cầu viết chương trình hiển thị số lần nhấn phím ở chân B0 của PIC16F887 lên màn hình LCD
Mạch đọc số lần nhất nút ở chân B0 hiển thị lên LCD
#include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock = 20000000) //Tan so thach anh 20MHz
#include //Them thu vien LCD vao unsigned long count = 0;
#INT_EXT //Ngat ngoai - chan B0 void NgatNgoai(){
CLEAR_INTERRUPT(INT_EXT); //Xoa co ngat
DISABLE_INTERRUPTS(GLOBAL); //vo hieu hoa ngat toan cuc
//Xu ly chuong trinh ngat delay_ms(20); //Chong nhieu if (INPUT(PIN_B0) == 0){ count++; //Tang gia tri bien dem
ENABLE_INTERRUPTS(GLOBAL); //Cho phep ngat toan cuc
PORT_B_PULLUPS(0x01); //Noi dien tro len nguon
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
LCD_PutCmd(0x01); //Xoa man hinh
ENABLE_INTERRUPTS(INT_EXT); //Kich hoat ngat ngoai
EXT_INT_EDGE(H_TO_L); //Chon canh ngat, cao xuong thap
ENABLE_INTERRUPTS(GLOBAL); //Cho phep ngat toan cuc while (True){ //Duy tri hoat dong cua vi dieu khien
LCD_SetPosition(0x06); printf(LCD_PutChar,"%lu",count);
Yêu cầu viết chương trình nhấn nút của chân B3-B5 của PIC16F887, hiển thị lên màn hình LCD.
Mạch đọc số lần nhất nút ở chân B3-B5 hiển thị lên LCD Bài tập 3.4
Yêu cầu Yêu cầu viết chương trình hiển thị số lần nhấn phím ở chân B0 của PIC16F887 có xử lý chống nhiễu.
#include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock = 20000000) //Tan so thach anh 20MHz
#INT_EXT //Ngat ngoai - chan B0 void NgatNgoai(){
CLEAR_INTERRUPT(INT_EXT); //Xoa co ngat
DISABLE_INTERRUPTS(GLOBAL); //vo hieu hoa ngat toan cuc
//Xu ly chuong trinh ngat delay_ms(20); if (INPUT(PIN_B0) == 0){
PORTE = ~PORTE; //Dao trang thai PORT E
ENABLE_INTERRUPTS(GLOBAL); //Cho phep ngat toan cuc
PORT_B_PULLUPS(0x01); //Noi dien tro len nguồn
PORTE = 0x00; //Set gia tri ban dau la muc 0
ENABLE_INTERRUPTS(INT_EXT); //Kich hoat ngat ngoai
EXT_INT_EDGE(H_TO_L); //Chon canh ngat, cao xuong thap
ENABLE_INTERRUPTS(GLOBAL); //Cho phep ngat toan cuc while (True){ //Duy tri hoat dong cua vi dieu khien
XỬ LÝ ADC
1.1 Yêu cầu Đọc giá trị ADC từ biến trở.
PIC 16F887 hỗ trợ tính năng ADC qua 2 PORT: PORT A và PORT E Bộ chuyển đổi ADC có thể hoạt động ở chế độ 10bit (0-1023) hoặc 8bit (0-255) tùy theo nhu cầu sử dụng Điện áp tham chiếu cho bộ ADC thường là 5V.
Khai báo chế độ đọc ADC 10bit hay 8bit:
#DEVICE*= 16 ADC 10 hoặc #DEVICE*= 16 ADC 8
Để xác định cách thức hoạt động của bộ biến đổi ADC, sử dụng lệnh SETUP_ADC(mode) Tiếp theo, thiết lập trưng lấy tín hiệu ADC và điện thế sử dụng bằng lệnh SETUP_ADC_PORTS(value) Cuối cùng, để chọn chân đọc tín hiệu Analog, sử dụng lệnh READ_ADC.
Để thiết lập kênh ADC, sử dụng lệnh SET_ADC_CHANNEL(channel) với channel có giá trị từ 0 đến 7, tương ứng với các chân A0 - A5 và E0 - E2 Sau khi thiết lập, cần sử dụng hàm delay_us(10) để đảm bảo kết quả chính xác Để đọc giá trị ADC từ chân đã được khai báo, sử dụng lệnh READ_ADC(mode), trong đó mode là tham số không bắt buộc.
Yêu cầu viết chương trình đọc giá trị từ biến trở R7 và hiển thị lên LCD.
#fuses HS,NOWDT, NOPROTECT, NOLVP
#use delay(clock 000000) //Tan so thach anh 20MHz
#include //Them thu vien LCD vao void main(){ int16 adc;
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
LCD_PutCmd(0x01); //Xoa man hinh
//Xac dinh cach thuc hoat dong cua bo ADC
//Thoi gian lay mau bang xung clock
SETUP_ADC(ADC_CLOCK_INTERNAL);
SET_ADC_CHANNEL(3); //Su dung chan A3 doc ADC delay_us(10); //Dam bao doc gia gia ADC chinh xac while (True){
LCD_PutCmd(0x01); adc = READ_ADC(); //Doc ADC tu chan A3
LCD_PutChar("Read ADC:"); printf(LCD_PutChar,"%lu",adc); //Hien thi len LCD delay_ms(1000);
Yêu cầu viết chương trình đọc giá trị từ biến trở R7 và xuất ra các giá trị ở các LED ởPORT E
Mạch đọc ADC từ biến trở xuất giá trị ra LED
#fuses HS,NOWDT, NOPROTECT, NOLVP
#use delay(clock 000000) //Tan so thach anh 20MHz
#include //Them thu vien LCD vao void main(){ int16 adc, a[10]; int count, i, pos;
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
LCD_PutCmd(0x01); //Xoa man hinh
//Xac dinh cach thuc hoat dong cua bo ADC
//Thoi gian lay mau bang xung clock
SETUP_ADC(ADC_CLOCK_INTERNAL);
SET_ADC_CHANNEL(3); //Su dung chan A3 doc ADC delay_us(10); //Dam bao doc gia gia ADC chinh xac while (True){ adc = READ_ADC(); //Doc ADC tu chan A3
OUTPUT_E(adc); //Dua gia tri ADC vao cong E LCD_SetPosition(0x00); //Cot 1 dong 1
LCD_SetPosition(0x09); //Cot 10 dong 1 printf(LCD_PutChar,"%lu",adc); //Hien thi len LCD //Chuyen sang nhi phan hien thi LCD count = 0;
//Chuyen sang ma nhi phan while (adc > 0){ //Con chia duoc a[count] = adc%2; adc = adc/2; count++;
LCD_PutChar("Bin:"); //Gia tri nhi phan
LCD_SetPosition(0x44); pos = 68; //0x44 = 64 for (i = count - 1; i>=0; i ){ printf(LCD_PutChar,"%lu",a[i]); pos++;
LCD_SetPosition(pos); if (i == 0){ break;
Yeu cầu viết chương trình đọc ADC từ biến trở và gửi lên máy tinh.
Mạch đọc ADC từ biến trở gửi lên PC Chương trình 4.3
#fuses HS,NOWDT, NOPROTECT, NOLVP
#use delay(clock 000000) //Tan so thach anh 20MHz
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
#include //Them thu vien LCD vao void main(){ int16 adc;
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
LCD_PutCmd(0x01); //Xoa man hinh
//Xac dinh cach thuc hoat dong cua bo ADC
//Thoi gian lay mau bang xung clock
SETUP_ADC(ADC_CLOCK_INTERNAL);
SET_ADC_CHANNEL(3); //Su dung chan A3 doc ADC delay_us(10); //Dam bao doc gia gia ADC chinh xac while (True){
LCD_PutCmd(0x01); adc = READ_ADC(); //Doc ADC tu chan A3 printf("%lu\n",adc); //Gui gia tri do duoc len PC
LCD_PutChar("Read ADC:"); printf(LCD_PutChar,"%lu",adc); //Hien thi len LCD delay_ms(1000);
TIMER
Sử dụng timer/counter trên vi điều khiển PIC 16F887 tạo thời gian trễ và tạo bộ đếm.
Timer được sử dụng để tạo ra khoảng thời gian trễ và đồng thời hoạt động như một bộ đếm, giúp đếm số xung vào một chân cụ thể trên vi điều khiển.
Vi điều khiẻn PIC 16F887 có 3 bộ timer:
Timer 0: 8bit , đếm được 255, chế độ định thời gian và bộ đếm.
Timer 1: 16bit, đếm được 65535, chế độ định thời gian và bộ đếm.
Timer 3: 8bit, có chức năng điều PWM – điều chế độ rộng xung.
1.3 các lệnh của timer/counter
SETUP_TIMER_X(mode); với X = 1 hoặc x = 2 (được định nghĩa trong device.h (device là tên chip)): khởi tạo TIMER
SET_TIMERX(value); với x = 0 hoặc x = 1 hoặc x = 2: thiết lặp giá trị bắt đầu cho TIMER.
GET_TIMERXx(); với x = 0 hoặc x = 1 hoặc x = 2: đọc giá trị của TIMER/COUNTER. Xét cho từng bộ timer:
TIMERO: ta có các lệnh SETUP_TIMER_0(mode); SETUP_COUNTERS(rtcc_state, ps_state); SET_TIMERO (value); GET_TIMERO();
TIMER1: ta có các lệnh SETUP_TIMER_1(mode); SET_TIMER1(value);
TIMER2: ta có các lệnh SETUP_TIMER_2(mode, period, postscale);
SET_TIMER2(value); GET_TIMER2();
Yêu cầu viết chương trình chớp tắt LED ở PORT E vời thời gian delay là 1s sử dụng time của PIC 16F887.
#include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#use delay(clock = 20000000) //Tan so thach anh 20MHz int32 count = 0;
#INT_TIMERO //Ngat TIMERO void Ngat_Timer0(){
//Xu ly chuong trinh ngat
++count; //Tang gia tri bien dem if (count == 1000) {
CLEAR_INTERRUPT(INT_TIMER0); //Xoa co ngat
DISABLE_INTERRUPTS(GLOBAL); //vo hieu hoa ngat toan cuc count = 0;
ENABLE_INTERRUPTS (GLOBAL); //Cho phep ngat toan cuc
ENABLE_INTERRUPTS(INT_TIMER0); //Kich hoat ngat tran Timer0
SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_32); //Xung kich noi va chia truoc 32
ENABLE_INTERRUPTS(GLOBAL); //Cho phep ngat toan cuc
SET_TIMER0 (100); //Bat dau dem tu 100, khi tran Timer0 duoc 1ms while (True) { //Duy tri hoat dong cua vi dieu khien
Yêu cầu viết chương trình từ 0 đến 9999 sử dụng timer của PIC 16F887 hiển thị trên LCD16x02
#include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#use delay(clock = 20000000) //Tan so thach anh 20MHz
#include int32 count = 0, sleep = 500, dem = 0, N_max = 9999;
#INT_TIMERO //Ngat TIMERO void Ngat_Timer0(){
//Xu ly chuong trinh ngat count++; //Tang gia tri bien dem if (count == sleep) {
CLEAR_INTERRUPT(INT_TIMER0); //Xoa co ngat
DISABLE_INTERRUPTS(GLOBAL); //vo hieu hoa ngat toan cuc count = 0; dem++;
ENABLE_INTERRUPTS (GLOBAL); //Cho phep ngat toan cuc
ENABLE_INTERRUPTS(INT_TIMER0); //Kich hoat ngat tran Timer0
SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_32); //Xung kich noi va chia truoc 32 ENABLE_INTERRUPTS(GLOBAL); //Cho phep ngat toan cuc
SET_TIMER0 (100); //Bat dau dem tu 100, khi tran Timer0 duoc 1ms while (True) { //Duy tri hoat dong cua vi dieu khien if (dem > N_max)} dem = 0;
LCD_SetPosition(0x07); //Cot 8 dong 1 printf(LCD_PutChar, "%lu", dem);
Yêu cầu viết chương trình đếm số lần nhấn phím sử dụng timer của PIC 16F887, hiển thị trên LCD 16x02.
Mạch đếm số lần nhấn nút sử dụng Chương trình 5.3 include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#FUSES NOWDT, HS, PUT, NOPROTECT
#use delay(clock = 20000000) //Tan so thach anh 20MHz
10 #include //Them thu vien LCD vao int32 count, value, over = 0; void main() {
TRISA OxFF; //PORT A la INPUT
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
LCD_PutCmd(0x01); //Xoa man hinh
//Cai dat Timer O voi che do la canh xuong (H to L) tu chan A4 //Su dung bo chia 1 (khong thay doi)
SETUP_TIMER_0(RTCC_EXT_H_TO_L|RTCC_DIV_1);
SET_TIMERO(0); //Bat dau dem tu 0.
LCD_SetPosition(0x00); //Cot 1 dong 1 LCD_PutChar("Count:"); while (True) { //Duy tri hoat dong cua vi dieu khien if (value == 255) { //Bat dau tran over++; //Tang so lan tran len
Đặt lại giá trị bộ đếm thời gian bằng cách sử dụng SET_TIMERO(0); và cập nhật giá trị bằng GET_TIMERO(); nếu không có tràn, đọc giá trị từ bộ đếm thời gian bằng GET_TIMERO(); để lấy giá trị hiện tại.
//Gia tri cua bien dem gia_tri_doc_duoc + so_lan_tran*255 count value + over*255;
LCD_SetPosition(0x06); //Cot 7 dong 1 printf(LCD_PutChar, "%lu", count); //Hien thi len LCD
GIAO TIẾP I2C
Viết chương trình giao tiếp 12C giữa vi điều khiển PIC 16F887 với các module có chuẩn giao tiếp I2C
Chuẩn I2C là chuẩn giao tiếp 2 dây là Serial Data (SDA) (truyền dữ liệu 2 hướng) và Serial Clock (SCL) (truyền xung đồng hồ theo một hướng).
Để kết nối các thiết bị I2C, chân SDA và SCL của module cần được nối đến chân SDA và SCL của vi điều khiển PIC 16F887 Việc này cho phép điều khiển nhiều thiết bị I2C thông qua hai chân này Mỗi thiết bị I2C sẽ được xác định bằng một địa chỉ duy nhất hoặc theo mối quan hệ chủ tớ (master-slave).
1.3 Giao tiếp chuẩn I2C với CCS Để giao tiếp ta dùng khai báo và các lệnh sau:
Khai báo: #use I2C(mode, speed, SDA PIN_C4, SLC= PIN_C3), với: mode: master hoặc slave speed: slow (100kHz) hoặc fast (400kHz).
Trên PIC 16F887, chân C4 và chân C3 lần lượt là chân SDA và SCL.
Các hàm giao tiếp được CCS định nghĩa:
I2C_ISR_STATE(): Thông báo trạng thái giao tiếp I2C
I2C_START(): Tạo điều kiện START.
I2C_STOP(): Tạo điều kiện STOP.
I2C_READ(mode): Đọc giá trị 8 bit thiết bị I2C Với mode = 0 (không chỉ ra ACK) và mode = 1 (chỉ ra ACK)
I2C_WRITE(Device_address): Ghi giá trị 8 bit đến thiết bị I2C
Yêu cầu viết chương trình đọc giá trị nhiệt độ từ cảm biến TC 47 và hiển thị lên LCD 16x02
Mạch đọc giá trị nhiệt độ từ IC TC74
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use i2c(Master, sda = PIN_C4, scl=PIN_C3)
#include int temp; void main()
{ lcd_putcmd(0x80); lcd_putcmd(0x01);//xoa man hinh delay_ms(100); i2c_start(); i2c_write(0x90); i2c_write(0x00); i2c_start(); i2c_write(0x91); temp=i2c_read(0); i2c_stop();
Printf(lcd_putchar,"nhiet do :%i oC",temp); delay_ms(1000);
Yêu cầu viết chương trình đọc giá trị thời gian từ IC DS1307 và hiển thị lên LCD 16x02
#fuses HS,NOWDT, NOPROTECT, NOLVP
#use delay(clock 000000) //Tan so thach anh 20MHz
#use I2C(Master, SDA = pin_C4, SCL = pin_C3) //Giao tiep I2C
#include //Them thu vien LCD vao
#include unsigned char s, min, hr, dy, dt, mt, yr; short am_pm; char day[3],ampm[2]; void main(){
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
DS3231_init(); setTime(2,30,0,0, _12_hour_format); setDate(4,25,11,20); getTime(hr, min, s, am_pm, _12_hour_format); getDate(dy, dt, mt, yr);
The code snippet initializes an LCD display by clearing the screen and enters an infinite loop to continuously retrieve the current time and date Inside the loop, it uses a switch-case structure to determine the day of the week based on a numerical input, with case 1 corresponding to Sunday, where it assigns the string "Sun" to the variable day.
} case 2:{ strcpy(day,"Mon"); break;
} case 3:{ strcpy(day,"Tus"); break;
} case 4:{ strcpy(day,"Wed"); break;
} case 5:{ strcpy(day,"Thu"); break;
} case 6:{ strcpy(day,"Fri"); break;
} case 7:{ strcpy(day,"Sat"); break;
} switch (am_pm){ //Tinh ra gio AM hay gio PM case 0:{ strcpy(ampm,"AM"); //Copy chuoi "AM" vao chuoi ampm break;
} case 1:{ strcpy(ampm,"PM"); break;
//Hien thi ket qua len LCD
LCD_SetPosition(0x03); printf(LCD_PutChar,"%02d:%02d:%02d %c%c",hr,min,s,ampm[0],ampm[1]);
LCD_SetPosition(0x41); printf(LCD_PutChar,"%c%c%c-%02d-%02d-20%02d",day[0],day[1],day[2],dt,mt,yr);
Yêu cầu viết chương trình đồ số hiển thị trên LCD 16x02 bao gồm giờ, phút, giây và nhiệt độ môi trường.
GIAO TIẾP RS232
Giao tiếp giữa máy tính và di điểu khiển PIC 16F887 thông qua module RS232
Cổng kết nối RS232 là một giao diện quan trọng dùng để kết nối với các thiết bị ngoại vi máy vi tính Với ưu điểm nổi bật như khả năng chống nhiễu cao và dễ dàng tháo gỡ khỏi máy tính, cổng này còn cung cấp nguồn cho vi điều khiển, làm cho nó trở thành lựa chọn lý tưởng cho nhiều ứng dụng.
Để kết nối module, chúng ta cần sử dụng hai chân RX và TX Cụ thể, chân RX của module sẽ được kết nối với chân RX của vi điều khiển, và chân TX của module sẽ được kết nối với chân TX của vi điều khiển.
Ta sử dụng khai báo và các lệnh sau để giao tiếp với RS232 qua cổng nối tiếp
Khai báo tần số thách anh : #use delay( clock 000000)
#use RS232 (BAUD 9600, PARITY N, XMIT PIN_C6, RCV PIN_C7) với BAUD = 9600: tốc độ truyền; PARITY = N: không kiểm tra chẳn lẻ; XMIT PIN_C6: chân truyền là C6; RCV PIN_C7: chân nhận là C7.
Các lệnh giao tiếp: printf, getc, getch, getchar, fgetc, gets, fgets, puc, putchar, fputc, puts, fputs, kbhit, assert, perror, set_uart_speed, setup_uart.
Yêu cầu viết chương trình truyền dữ liệu giữa PC và PIC 16F887, trong đó PC sử dụng MATLAB để gửi ký tự 'b' và 't' Khi PIC nhận được ký tự 'b', các LED ở PORT E sẽ được bật, còn khi nhận được ký tự 't', các LED ở PORT E sẽ được tắt.
#include // thu vien do nguoi dinh nghia
#fuses HS, NOWDT, NOPROTECT, NOLVP // cau chi
#use delay(clock = 20000000) // tan so thach anh
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7) char value;
#INT_RDA void RDA_interrupts(){ value =getc(); if (value == 'b')
ENABLE_INTERRUPTS(GLOBAL); // Cho phep ngat toan cuc while (True){
Yêu cầu Viết chương trình truyền chuỗi "TT VI DIEU KHIEN" từ PC xuống máy tính và hiển thị chuỗi nhận được lên LCD 16x02.
#fuses HS,NOWDT, NOPROTECT, NOLVP
#use delay(clock 000000) //Tan so thach anh 20MHz
#use I2C(Master, SDA = pin_C4, SCL = pin_C3) //Giao tiep I2C
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
#include //Them thu vien LCD vao
OUTPUT_LOW(LCD_RW); //Che do ghi
LCD_Init(); //Khoi tao LCD
LCD_PutCmd(0x01); //Xoa man hinh while (True){
LCD_SetPosition(0x00); printf(LCD_PutChar,"%.1f",getTemp()); //Hien thi nhiet do len LCD printf("%.1fC\n",getTemp()); //Gui nhiet do len may tinh
LCD_PutChar(223); printf(LCD_PutChar,"C");
ĐIỀU KHIỂN ĐỘNG CƠ DT
Động cơ một chiều DC (viết tắt của "Direct Current Motors") là loại động cơ sử dụng nguồn điện áp một chiều (DC), khác với điện áp xoay chiều (AC) Động cơ này được điều khiển bằng dòng điện có hướng xác định và thường có hai đầu dây ra, bao gồm dây nguồn (VCC) và dây tiếp đất (GND) DC motor cho phép cơ năng quay liên tục, mang lại hiệu suất cao trong nhiều ứng dụng.
2 Phân loại động cơ điện một chiều (đây là cách phân loại theo cách kích từ) Động cơ điện 1 chiều phân loại theo kích từ thành những loại sau:
Mỗi loại động cơ điện một chiều (DC) có những ứng dụng khác nhau, nhưng chủ yếu chúng ta tiếp xúc với động cơ DC công suất thấp sử dụng nam châm vĩnh cửu, do đó không cần phần kích từ Việc phân loại này chỉ mang tính chất tham khảo để tìm hiểu sâu hơn Khi nhắc đến kích từ, chúng ta thường quan tâm đến động cơ DC công suất lớn, nơi Stator không phải là nam châm vĩnh cửu mà là nam châm điện, bao gồm lõi thép kỹ thuật và bó dây Để Stator hoạt động như nam châm điện, cần cấp điện cho nó, và quá trình này được gọi là kích từ Vì vậy, với các loại động cơ DC thông dụng, chúng ta không cần phải lo lắng về phần kích từ.
3 Cấu tạo và nguyên tắc hoạt động
Gồm có 3 phần chính stator( phần cảm), rotor ( phần ứng), và phần cổ góp- chỉnh lưu.
• Stator của động cơ điện 1 chiều thường là 1 hay nhiều cặp nam châm vĩnh cửu, hay nam châm điện.
• Rotor có các cuộn dây quấn và được nối với nguồn điện một chiều.
Bộ phận chỉnh lưu có vai trò quan trọng trong việc đổi chiều dòng điện khi rotor quay liên tục Thông thường, bộ phận này bao gồm cổ góp và chổi than tiếp xúc với cổ góp để đảm bảo quá trình hoạt động hiệu quả.
Pha 1: Từ trường của rotor cùng cực với stator, sẽ đẩy nhau tạo ra chuyển động quay của rotor.
Pha 2: Rotor tiếp tục quay
Pha 3: Bộ phận chỉnh điện sẽ đổi cực sao cho từ trường giữa stator và rotor cùng dấu, trở lại pha 1
#fuses HS,NOWDT,NOPROTECT,NOLVP
{ set_tris_c(0xf9); output_c(0); setup_timer_2(t2_div_by_4,124,1); setup_ccp1(ccp_pwm); set_pwm1_duty(125);
Port_B_pullups (1 ); enable_interrupts(int_ext); ext_int_edge(H_TO_L); enable_interrupts(GLOBAL); while (true) {
ĐO KHOẢNG CÁCH BẰNG CẢM BIẾN SIÊU ÂM SRF0K
Sử dụng vi điều khiển PIC 16F887 lập trình đo khoảng cách với cảm biến siêu âm SRF05.
1.2 Cảm biến siêu âm SRF05
Nguyên lý đo khoảng cách của cảm biến siêm âm SRF05:
• Dùng nguyên lý phản xạ sóng để đo vật cản.
Cảm biến phát đi một lúc 8 xung với tần số 40kHz, gặp vật cản xung phát đi sẽ dội về.
Từ đây, có thể tính được khoảng cách.
• Khi phát xung đi, chân Echo ở mức cao, nhận xung dội về, chân Echo xuống mức thấp (hoặc sau 30ms không nhận được cũng xuống mức thấp)
Cảm biến có 2 chế độ hoạt động: chân Trigger và chân Echo dùng riêng hoặc dùng chung.
• Chân Trigger và chân Echo dùng riêng:
1.3 Đo khoảng cách với cảm biến siêu âm
Do khoảng cách với cảm biến siêu âm chính là đo thời gian chân Echo ở mức cao.
Ta thực hiện theo các bước sau:
• Kớch chõn Trigger: Xuất ra mức cao ở chõn Trigger và delay tối thiểu 10às.
• Đợi chân Echo lên mức cao.
• Khi chân Echo lên mức cao, kích hoạt Timer: có 2 cách thực hiện: Đợi chân Echo xuống mức thấp Cho phép ngắt cạnh xuống (sử dụng với ngắt).
• Khi chân Echo xuống mức thấp, dừng Timer, tính thời gian từ Timer rồi suy ra khoảng cách.
Cú v = 344m/s = 344 ì 102 ì 10-6 = 0.0344cm/às Thời gian t đơn vị là às. Công thức tính khoảng cách:
* Nếu sau 30ms mà không gặp vật cản thì chân Echo cũng sẽ xuống mức thấp.
• Reset lại giá trị của Timer để chuẩn bị cho các lần đo tiếp
#include //Khai bao ten PIC
#include //Thu vien do nguoi dung dinh nghia
#FUSES HS, NOWDT, NOPROTECT, NOLVP
#use delay(clock = 20000000) //Tan so thach anh 20MHz
#define PIN_TRIGGER PIN_A3 int1 echo = 0; int16 value = 0; void Trigger(){
OUTPUT_HIGH(PIN_TRIGGER); delay_us(12);
#INT_CCP1 void CCP1_ISR(void){ if (echo == 1){
SETUP_CCP1(CCP_CAPTURE_FE);
SETUP_CCP1(CCP_CAPTURE_RE); value = CCP_1; echo = 1;
SETUP_TIMER_1(T1_INTERNAL|T1_DIV_BY_4); SETUP_CCP1(CCP_CAPTURE_RE);
ENABLE_INTERRUPTS(GLOBAL); while (True){