minhsondaklak
24-07-2008, 10:17 PM
Được học Pic thì thích rồi, nhưng mình nghĩ phải làm một cái ứng dụng thực tế với Pic thì mới khoái được (mini thôi, cho mau thấy !).
Ở nhà các bạn có chơi cá kiểng không? ở hồ cá kiểng thì thường phải có cái bơm lọc nước nho nhỏ, để lọc cho nước trong ấy mà. Nếu không có nó thì cá chẳng sống được mấy ngày, mà có nó thì sao ... tiếng ù ù nho nhỏ thôi nhưng liên tục ngày đêm không nghĩ, lắm khi mất điện một phát nghe nhẹ cả người ! Hẳn là tiếng ù ù kia cũng đã làm căng thẳng mấy sợi thần kinh chứ chẳng chơi đâu (ban đêm càng tệ).
Sẵn những kiến thức học được trên PicVietnam này, tôi làm luôn 1 cái mạch điều khiển cho cái bơm lọc nước hồ cá kiểng kia cho đỡ ù tai ! Ý tôi là cho nó chạy chừng chừng, 10 phút ON, lại OFF 10 phút, ban đêm cho nghĩ hẳn ...
Làm cái này tôi đã "nạp" cở 99% cái "Lịch vạn niên" của Bác Thép trên diễn đàn đây vào cho con Pic của mình (à mà tôi phải cám ơn và xin lỗi bác Thép cái đã !), và tôi cũng dùng MikroC. Xin mời các bác mới mày mò em PIC như tôi cùng tham khảo:
Linh kiện: Pic16F877A, thạch anh 4Mhz, IC ds1307.
unsigned short set, luu, giay, phut, gio, thu, ngay, thang, nam, flag1, flag2, delay1s = 0, delay1p = 0;
//Giai thich cac bien:
//set, luu: truy cap dia chi 0x07, 0x08 cua DS1307, xu ly khi mat nguon pin nuoi, phai set lai ds1307
//giay, phut ...nam : cac bien truy cap thoi gian tu ds1307
//flag1, flag2: cac co tin hieu; delay1s, delay1p: bien dem ngat tran, tinh chu ky giay, phut
void INIT_MAIN() // Khoi tao cac PORT, NGAT, I2C
{
/* Khoi tao cong B -----------------------------------------------------------*/
TRISB = 0xFF; // Dinh nghia cong B la Digital Input
PORTB = 0x00;
/* Khoi tao cong C Out put----------------------------------------------------*/
TRISC = 0x00;
PORTC = 0x00;
TRISD = 0x00;
PORTD = 0x00;
/* Khoi tao I2C voi toc do baud = 100khz --------------*/
I2C_Init(100000);
/* Khoi tao ngat ngoai va Timer0 ---------------------------------------------*/
INTCON= 0xB0; // Mo ngat xoa co ngat
OPTION_REG = 0x87; // Chon suon, bo ti le 1:256 Timer0
TMR0 = 0x00; //Xoa ve 0 (cho dem tu 0 den 256)
}
/*
Voi Fta=4Mhz -> Chukymay =4/4Mhz=1 us, hesochia = 256 -> T =1x256x256=65536 us =~ 65,5 ms
Vay ta can: 1000 / 65,5 =` 15 lan tran de co 1 s, 15 x 60 = 900 lan tran de co 1 phut
*/
void SET_12h() //Ghi vao ds1307, gia tri 12 gio 00 phut, khi co bam nut SET_12h (thay vi phai dung man hinh LCD)
/*Luu y: DS1307 co dia chi I2C la 0xD0, no co 7 thanh ghi thoi gian tu 0x00 -:- 0x06. cac thanh nay lam viec voi so o dang ma BCD,
Thanh ghi 0x07 la thanh ghi dieu khien DS1307. Tu thanh 0x08 tro di la RAM trong*/
{
I2C_Start(); // Phat bit STAR I2C
I2C_Wr(0xD0); // Truyen d/c cua DS1307 la 0xD0 len duong truyen I2C
I2C_Wr(0x00); // Truyen dia chi o nho dau tien cua ds1307, 0x00
I2C_Wr(0x00); // Ghi gia tri ban dau bang 0, cho thanh ghi giay tai 0x00
//I2C_Wr(0x00); //Ghi 00 cho phut
I2C_Wr(0x07); // Chay thu: Ghi Phut = 07,
I2C_Wr(0x12); // Ghi ... Gio = 12 tai 0x02
I2C_Wr(0x06); // Ghi ... Thu bay, tai 0x03
I2C_Wr(0x19); // Ghi ... Ngay 19, tai 0x04
I2C_Wr(0x07); // Ghi ... Thang 7, tai 0x05
I2C_Wr(0x08); // Ghi ... Nam 2008, tai 0x06
I2C_Wr(0x90); // Ghi cau hinh cho thanh dieu khien (tai 0x07)
I2C_Wr(0x55); // Lam dau tai d/c 0x08, theo doi nguon pin ds1307
I2C_Stop(); // Phat bit STOP I2C
}
void READ_DS() //Doc gio, phut, giay ... tu ds1307
{
I2C_Start(); // Phat bit Star I2C
I2C_Wr(0xD0); // Truyen dia chi Slave (0xD0)len duong truyen I2C
I2C_Wr(0x00); // Truyen d/c can truy cap (tai 0x00) den slave
I2C_Repeated_Start(); // Khoi dong lai I2C
I2C_Wr(0xD1); // Truyen d/c Slave+1 = 0xD0+1 = 0xD1
giay = I2C_Rd(1u); // Doc du lieu tai d/c 0x00, phat bit ACK (se doc tiep)
phut = I2C_Rd(1u); // Doc o tiep theo (0x01)
gio = I2C_Rd(1u); // tiep ....0x02
thu = I2C_Rd(1u); // Doc thu, tai d/c 0x03
ngay = I2C_Rd(1u); // Doc ngay, tai 0x04
thang = I2C_Rd(1u); // Doc thang, tai 0x05
nam = I2C_Rd(1u); // Doc nam, tai d/c 0x06
set = I2C_Rd(1u); // Doc d/c 0x07 (doc cho qua, khong dung)
luu = I2C_Rd(0u); // Doc d/c 0x08 (gia tri 0x55) phat bit NACK (thoi)
I2C_Stop(); // Phat bit STOP I2C
}
void HIEN_THI() //Dung hien thi gio phut, dang ma nhi phan BCD
{
PORTD = gio; Delay_ms(2000); PORTD = 0; Delay_ms(2000); //xem gio, dang BCD
PORTD = phut; Delay_ms(2000); PORTD = 0; //xem phut, dang BCD
}
void ON_OFF() //Kiem tra gio -> cho ON, OFF chan PORTC.F0:
/*Neu ban ngay (tu 6h den 20h) dong thoi so hang chuc cua phut la so chan thi ON, la
so le thi OFF (ON 10 phut, OFF 10 phut)
Neu ban dem (21h den 5h)thi OFF*/
{
gio = Bcd2Dec(gio); phut = Bcd2Dec(phut);
if (6 <= gio && gio <= 21) // set thoi gian ON vao ban ngay
{
if ((phut / 10) % 2 == 0) // neu chu so hang chuc cua phut là so chan
{if (PORTC.F0 == 0) PORTC.F0 = 1;} //thi ON
else
{if (PORTC.F0 == 1) PORTC.F0 = 0;} // la so le thi OFF
}
else
{if (PORTC.F0 == 1) PORTC.F0 = 0;} // ban dem cho OFF luon
}
void interrupt() //Chuong trinh NGAT
/*Luu y: MikroC chi co 1 ham ngat chung
MikroC cung khong cho goi ham trong ngat*/
{
//Xu ly cho ngat timer0:
if (INTCON.T0IF) //Neu ngat la dinh thoi timer0, co bao 1 (65,5ms)
{
delay1s++; //Tang bien dem len 1 don vi, moi khi tran timer0
if (delay1s == 15)
{
delay1p++; // 1 giay tang len 1
PORTC.F1 = ~PORTC.F1; //Lam den nhay theo nhip 1 giay
delay1s = 0;
}
if (delay1p == 60) //Neu du 900 lan tran = (60 x 15) x 65,5ms ~ 1 phut, se bat co flag1 len 1 lan, roi xoa delay1p ve 0, dem lai tu dau
{
flag1 = 1; // Tin hieu da troi qua 1 phut
PORTC.F2 = 1; Delay_ms(1000); PORTC.F2 = 0; //Den bao da qua 1 phut
delay1p = 0; // xoa ve 0, dem lai tu dau
}
INTCON.T0IF = 0; //Xoa co ngat time0
}
//Xu ly cho ngat ngoai : (khi co xung ngoai vao chan PORTB.F0)
if (INTCON.INTF) //Neu la ngat ngoai, co bao 1
{
flag2 = 1; //Tin hieu: Co bam nut SET
INTCON.INTF = 0; // Xoa co ngat ngoai
}
} //Het interrup
void MAIN() //CHUONG TRINH CHINH
{
INIT_MAIN(); //khoi tao cac PORT, NGAT, I2C
READ_DS(); //Doc ds1307
//Neu mat gia tri 0x55 tai d/c 0x08 thì set lai ds1307, truoc khi Bat dau
if (luu != 0x55) {SET_12h(); Delay_ms(100);}
HIEN_THI(); //Xemi gio, phut dang ma nhi phan BCD, xuat tren PORTD
while (1)
{
if (flag1 == 1) {READ_DS(); HIEN_THI(); ON_OFF(); flag1 = 0;} //Khi co tien hieu da qua chu ky 1 phut thi cho doc ds1307, kiem tra, xuat tin hieu ra PORTC.F0
if (flag2 == 1) {SET_12h(); flag2 = 0;} //Khi co tin hieu bam nut SET_12h, cho ds1307 ve 12 gio trua (lay gio theo dong ho, luc 12 gio trua)
}
}
Kèm theo file mô phỏng trên Proteus. Có 1 điều:
Không hiểu sao, khi chạy mô phỏng thì OK 100%
Còn chạy trên mạch thực tế thì có chuyện, mà tôi chưa lý giải được: Sau khi khởi động được 30 giây thì mạch đã nháy đèn phút rồi (đã qua 1 phút = 900 lần tràn timer0, không đúng!), từ phút thứ 2 trở đi thì vẫn đủ 60 giây. Chỗ này chắc phải nhờ đến các Sư Huynh chỉ giúp thôi !
À còn về mạch điện, vì không rành lắm nên tôi chơi thẳng chân con Pic vào cổng Triac, chắc không ổn. Có gì nhờ các Huynh luôn (về xử lý giao tiếp cách ly giữa Pic và Triac - mang điện 220v)
Lưu ý, mạch này không có LCD nên hơi kén người xem và chỉnh giờ cho nó 1 chút:
- Cứ 1 phút nó báo giờ 1 lần, nhưng ở dạng mã nhị phân BCD à nghen (xuất trên PORTD)
- Muốn chỉnh giờ theo đồng hồ thì phải đúng ngọ đó, (đúng 12 giờ trưa, nhấn vào cái nút duy nhất đó) hơi bị mê tín đó !
Ở nhà các bạn có chơi cá kiểng không? ở hồ cá kiểng thì thường phải có cái bơm lọc nước nho nhỏ, để lọc cho nước trong ấy mà. Nếu không có nó thì cá chẳng sống được mấy ngày, mà có nó thì sao ... tiếng ù ù nho nhỏ thôi nhưng liên tục ngày đêm không nghĩ, lắm khi mất điện một phát nghe nhẹ cả người ! Hẳn là tiếng ù ù kia cũng đã làm căng thẳng mấy sợi thần kinh chứ chẳng chơi đâu (ban đêm càng tệ).
Sẵn những kiến thức học được trên PicVietnam này, tôi làm luôn 1 cái mạch điều khiển cho cái bơm lọc nước hồ cá kiểng kia cho đỡ ù tai ! Ý tôi là cho nó chạy chừng chừng, 10 phút ON, lại OFF 10 phút, ban đêm cho nghĩ hẳn ...
Làm cái này tôi đã "nạp" cở 99% cái "Lịch vạn niên" của Bác Thép trên diễn đàn đây vào cho con Pic của mình (à mà tôi phải cám ơn và xin lỗi bác Thép cái đã !), và tôi cũng dùng MikroC. Xin mời các bác mới mày mò em PIC như tôi cùng tham khảo:
Linh kiện: Pic16F877A, thạch anh 4Mhz, IC ds1307.
unsigned short set, luu, giay, phut, gio, thu, ngay, thang, nam, flag1, flag2, delay1s = 0, delay1p = 0;
//Giai thich cac bien:
//set, luu: truy cap dia chi 0x07, 0x08 cua DS1307, xu ly khi mat nguon pin nuoi, phai set lai ds1307
//giay, phut ...nam : cac bien truy cap thoi gian tu ds1307
//flag1, flag2: cac co tin hieu; delay1s, delay1p: bien dem ngat tran, tinh chu ky giay, phut
void INIT_MAIN() // Khoi tao cac PORT, NGAT, I2C
{
/* Khoi tao cong B -----------------------------------------------------------*/
TRISB = 0xFF; // Dinh nghia cong B la Digital Input
PORTB = 0x00;
/* Khoi tao cong C Out put----------------------------------------------------*/
TRISC = 0x00;
PORTC = 0x00;
TRISD = 0x00;
PORTD = 0x00;
/* Khoi tao I2C voi toc do baud = 100khz --------------*/
I2C_Init(100000);
/* Khoi tao ngat ngoai va Timer0 ---------------------------------------------*/
INTCON= 0xB0; // Mo ngat xoa co ngat
OPTION_REG = 0x87; // Chon suon, bo ti le 1:256 Timer0
TMR0 = 0x00; //Xoa ve 0 (cho dem tu 0 den 256)
}
/*
Voi Fta=4Mhz -> Chukymay =4/4Mhz=1 us, hesochia = 256 -> T =1x256x256=65536 us =~ 65,5 ms
Vay ta can: 1000 / 65,5 =` 15 lan tran de co 1 s, 15 x 60 = 900 lan tran de co 1 phut
*/
void SET_12h() //Ghi vao ds1307, gia tri 12 gio 00 phut, khi co bam nut SET_12h (thay vi phai dung man hinh LCD)
/*Luu y: DS1307 co dia chi I2C la 0xD0, no co 7 thanh ghi thoi gian tu 0x00 -:- 0x06. cac thanh nay lam viec voi so o dang ma BCD,
Thanh ghi 0x07 la thanh ghi dieu khien DS1307. Tu thanh 0x08 tro di la RAM trong*/
{
I2C_Start(); // Phat bit STAR I2C
I2C_Wr(0xD0); // Truyen d/c cua DS1307 la 0xD0 len duong truyen I2C
I2C_Wr(0x00); // Truyen dia chi o nho dau tien cua ds1307, 0x00
I2C_Wr(0x00); // Ghi gia tri ban dau bang 0, cho thanh ghi giay tai 0x00
//I2C_Wr(0x00); //Ghi 00 cho phut
I2C_Wr(0x07); // Chay thu: Ghi Phut = 07,
I2C_Wr(0x12); // Ghi ... Gio = 12 tai 0x02
I2C_Wr(0x06); // Ghi ... Thu bay, tai 0x03
I2C_Wr(0x19); // Ghi ... Ngay 19, tai 0x04
I2C_Wr(0x07); // Ghi ... Thang 7, tai 0x05
I2C_Wr(0x08); // Ghi ... Nam 2008, tai 0x06
I2C_Wr(0x90); // Ghi cau hinh cho thanh dieu khien (tai 0x07)
I2C_Wr(0x55); // Lam dau tai d/c 0x08, theo doi nguon pin ds1307
I2C_Stop(); // Phat bit STOP I2C
}
void READ_DS() //Doc gio, phut, giay ... tu ds1307
{
I2C_Start(); // Phat bit Star I2C
I2C_Wr(0xD0); // Truyen dia chi Slave (0xD0)len duong truyen I2C
I2C_Wr(0x00); // Truyen d/c can truy cap (tai 0x00) den slave
I2C_Repeated_Start(); // Khoi dong lai I2C
I2C_Wr(0xD1); // Truyen d/c Slave+1 = 0xD0+1 = 0xD1
giay = I2C_Rd(1u); // Doc du lieu tai d/c 0x00, phat bit ACK (se doc tiep)
phut = I2C_Rd(1u); // Doc o tiep theo (0x01)
gio = I2C_Rd(1u); // tiep ....0x02
thu = I2C_Rd(1u); // Doc thu, tai d/c 0x03
ngay = I2C_Rd(1u); // Doc ngay, tai 0x04
thang = I2C_Rd(1u); // Doc thang, tai 0x05
nam = I2C_Rd(1u); // Doc nam, tai d/c 0x06
set = I2C_Rd(1u); // Doc d/c 0x07 (doc cho qua, khong dung)
luu = I2C_Rd(0u); // Doc d/c 0x08 (gia tri 0x55) phat bit NACK (thoi)
I2C_Stop(); // Phat bit STOP I2C
}
void HIEN_THI() //Dung hien thi gio phut, dang ma nhi phan BCD
{
PORTD = gio; Delay_ms(2000); PORTD = 0; Delay_ms(2000); //xem gio, dang BCD
PORTD = phut; Delay_ms(2000); PORTD = 0; //xem phut, dang BCD
}
void ON_OFF() //Kiem tra gio -> cho ON, OFF chan PORTC.F0:
/*Neu ban ngay (tu 6h den 20h) dong thoi so hang chuc cua phut la so chan thi ON, la
so le thi OFF (ON 10 phut, OFF 10 phut)
Neu ban dem (21h den 5h)thi OFF*/
{
gio = Bcd2Dec(gio); phut = Bcd2Dec(phut);
if (6 <= gio && gio <= 21) // set thoi gian ON vao ban ngay
{
if ((phut / 10) % 2 == 0) // neu chu so hang chuc cua phut là so chan
{if (PORTC.F0 == 0) PORTC.F0 = 1;} //thi ON
else
{if (PORTC.F0 == 1) PORTC.F0 = 0;} // la so le thi OFF
}
else
{if (PORTC.F0 == 1) PORTC.F0 = 0;} // ban dem cho OFF luon
}
void interrupt() //Chuong trinh NGAT
/*Luu y: MikroC chi co 1 ham ngat chung
MikroC cung khong cho goi ham trong ngat*/
{
//Xu ly cho ngat timer0:
if (INTCON.T0IF) //Neu ngat la dinh thoi timer0, co bao 1 (65,5ms)
{
delay1s++; //Tang bien dem len 1 don vi, moi khi tran timer0
if (delay1s == 15)
{
delay1p++; // 1 giay tang len 1
PORTC.F1 = ~PORTC.F1; //Lam den nhay theo nhip 1 giay
delay1s = 0;
}
if (delay1p == 60) //Neu du 900 lan tran = (60 x 15) x 65,5ms ~ 1 phut, se bat co flag1 len 1 lan, roi xoa delay1p ve 0, dem lai tu dau
{
flag1 = 1; // Tin hieu da troi qua 1 phut
PORTC.F2 = 1; Delay_ms(1000); PORTC.F2 = 0; //Den bao da qua 1 phut
delay1p = 0; // xoa ve 0, dem lai tu dau
}
INTCON.T0IF = 0; //Xoa co ngat time0
}
//Xu ly cho ngat ngoai : (khi co xung ngoai vao chan PORTB.F0)
if (INTCON.INTF) //Neu la ngat ngoai, co bao 1
{
flag2 = 1; //Tin hieu: Co bam nut SET
INTCON.INTF = 0; // Xoa co ngat ngoai
}
} //Het interrup
void MAIN() //CHUONG TRINH CHINH
{
INIT_MAIN(); //khoi tao cac PORT, NGAT, I2C
READ_DS(); //Doc ds1307
//Neu mat gia tri 0x55 tai d/c 0x08 thì set lai ds1307, truoc khi Bat dau
if (luu != 0x55) {SET_12h(); Delay_ms(100);}
HIEN_THI(); //Xemi gio, phut dang ma nhi phan BCD, xuat tren PORTD
while (1)
{
if (flag1 == 1) {READ_DS(); HIEN_THI(); ON_OFF(); flag1 = 0;} //Khi co tien hieu da qua chu ky 1 phut thi cho doc ds1307, kiem tra, xuat tin hieu ra PORTC.F0
if (flag2 == 1) {SET_12h(); flag2 = 0;} //Khi co tin hieu bam nut SET_12h, cho ds1307 ve 12 gio trua (lay gio theo dong ho, luc 12 gio trua)
}
}
Kèm theo file mô phỏng trên Proteus. Có 1 điều:
Không hiểu sao, khi chạy mô phỏng thì OK 100%
Còn chạy trên mạch thực tế thì có chuyện, mà tôi chưa lý giải được: Sau khi khởi động được 30 giây thì mạch đã nháy đèn phút rồi (đã qua 1 phút = 900 lần tràn timer0, không đúng!), từ phút thứ 2 trở đi thì vẫn đủ 60 giây. Chỗ này chắc phải nhờ đến các Sư Huynh chỉ giúp thôi !
À còn về mạch điện, vì không rành lắm nên tôi chơi thẳng chân con Pic vào cổng Triac, chắc không ổn. Có gì nhờ các Huynh luôn (về xử lý giao tiếp cách ly giữa Pic và Triac - mang điện 220v)
Lưu ý, mạch này không có LCD nên hơi kén người xem và chỉnh giờ cho nó 1 chút:
- Cứ 1 phút nó báo giờ 1 lần, nhưng ở dạng mã nhị phân BCD à nghen (xuất trên PORTD)
- Muốn chỉnh giờ theo đồng hồ thì phải đúng ngọ đó, (đúng 12 giờ trưa, nhấn vào cái nút duy nhất đó) hơi bị mê tín đó !