#include<reg51.h> //加載頭文件 #include<intrins.h> #define uchar unsigned char //宏定義 #define uint unsigned int #define AddWr 0x90 //PCF8591地址 #define LCD_DATA P0 //液晶數據口定義 #define RS_CLR LCD_RS=0 //液晶控制口宏定義 #define RS_SET LCD_RS=1 #define RW_CLR LCD_RW=0 #define RW_SET LCD_RW=1 #define EN_CLR LCD_EN=0 #define EN_SET LCD_EN=1 sbit LCD_RS=P2^7; //液晶控制口定義 sbit LCD_RW=P2^6; sbit LCD_EN=P2^5; sbit SCL=P2^2; //I2C時鐘-PCF8591 sbit SDA=P2^1; //I2C數據-PCF8591 sbit lamp=P2^3;//燈 sbit k1=P1^2;//按鈕 sbit k2=P1^3; int light=0; //光照度變量 uchar dis; //ADC用變量 uint limit=100;//光強 uint time=0; uint pwm=0,sec=0; bit ack; //應答標志位 void Delay_US(uchar t) //US延時函數 { while(--t); } void Delay_MS(uchar t) //MS延時函數 { while(t--) { Delay_US(245); Delay_US(245); } } void Lcd_W_Com(uchar com) //液晶寫指令函數 { RS_CLR; RW_CLR; LCD_DATA=com; Delay_MS(1); EN_SET; Delay_MS(1); EN_CLR; } void Lcd_W_Dat(uchar dat) //液晶寫數據函數 { RS_SET; RW_CLR; LCD_DATA=dat; Delay_MS(1); EN_SET; Delay_MS(1); EN_CLR; } void Lcd_Clr_Scr() //液晶清屏函數 { Lcd_W_Com(0x01); Delay_MS(5); } void Lcd_Show_String(uchar x,uchar y,uchar *s) //液晶顯示字符串函數 { if(y==0) Lcd_W_Com(0x80+x); //表示第一行 else Lcd_W_Com(0xC0+x); //表示第二行 while(*s) { Lcd_W_Dat(*s); s++; } } void Lcd_Show_Char(uchar x,uchar y,uchar dat) //液晶寫字符函數 { if(y==0) Lcd_W_Com(0x80+x); else Lcd_W_Com(0xC0+x); Lcd_W_Dat(dat); } void Lcd_Init() //液晶初始化函數 { Lcd_W_Com(0x38); //顯示模式設置 Lcd_W_Com(0x08); //顯示關閉 Lcd_W_Com(0x01); //顯示清屏 Lcd_W_Com(0x06); //顯示光標移動設置 Lcd_W_Com(0x0C); //顯示開及光標設置 } void IIC_Start() //總線啟動函數 { SDA=1; //發送起始條件的數據信號 _nop_(); SCL=1; _nop_(); //起始條件建立時間大于4.7us,延時 _nop_(); _nop_(); _nop_(); _nop_(); SDA=0; //發送起始信號 _nop_(); //起始條件鎖定時間大于4μs _nop_(); _nop_(); _nop_(); _nop_(); SCL=0; //鉗住I2C總線,準備發送或接收數據 _nop_(); _nop_(); } void IIC_Stop() //總線結束函數 { SDA=0; //發送結束條件的數據信號 _nop_(); //發送結束條件的時鐘信號 SCL=1; //結束條件建立時間大于4μs _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); SDA=1; //發送I2C總線結束信號 _nop_(); _nop_(); _nop_(); _nop_(); } void IIC_Send_Byte(uchar c) //IIC發送字節函數 { uchar i; for(i=0;i<8;i++) //要傳送的數據長度為8位 { if((c<<i)&0x80) SDA=1; //判斷發送位 else SDA=0; _nop_(); SCL=1; //置時鐘線為高,通知被控器開始接收數據位 _nop_(); _nop_(); //保證時鐘高電平周期大于4μs _nop_(); _nop_(); _nop_(); SCL=0; } _nop_(); _nop_(); SDA=1; //8位發送完后釋放數據線,準備接收應答位 _nop_(); _nop_(); SCL=1; _nop_(); _nop_(); _nop_(); if(SDA==1) ack=0; else ack=1; //判斷是否接收到應答信號 SCL=0; _nop_(); _nop_(); } uchar IIC_Receive_Byte() //IIC接收字節函數 { uchar retc=0,i; SDA=1; //置數據線為輸入方式 for(i=0;i<8;i++) { _nop_(); SCL=0; //置時鐘線為低,準備接收數據位 _nop_(); _nop_(); //時鐘低電平周期大于4.7μs _nop_(); _nop_(); _nop_(); SCL=1; //置時鐘線為高使數據線上數據有效 _nop_(); _nop_(); retc=retc<<1; if(SDA==1) retc=retc+1; //讀數據位,接收的數據位放入retc中 _nop_(); _nop_(); } SCL=0; _nop_(); _nop_(); return(retc); } void IIC_Ack(bit a) //IIC應答函數 { if(a==0) SDA=0; //在此發出應答或非應答信號 else SDA=1; //0為發出應答,1為非應答信號 _nop_(); _nop_(); _nop_(); SCL=1; _nop_(); _nop_(); //時鐘低電平周期大于4μs _nop_(); _nop_(); _nop_(); SCL=0; //清時鐘線,住I2C總線以便繼續接收 _nop_(); _nop_(); } bit Pcf_Send_Byte(uchar addr,uchar channel) //PCF8591寫一個控制指令 { //addr(器件地址),channel(轉換通道) IIC_Start(); //啟動總線 IIC_Send_Byte(addr); //發送器件地址 if(ack==0) return(0); IIC_Send_Byte(0x40|channel); //發送控制字節 if(ack==0) return(0); IIC_Stop(); //結束總線 return(1); } uchar Pcf_Receive_Byte(uchar addr) //PCF8591讀取一個轉換值 { uchar dat; IIC_Start(); //啟動總線 IIC_Send_Byte(addr+1); //發送器件地址 if(ack==0) return(0); dat=IIC_Receive_Byte(); //讀取數據0 IIC_Ack(1); //發送非應答信號 IIC_Stop(); //結束總線 return(dat); } //主函數 void main() { Lcd_Init(); //液晶初始化 Lcd_Clr_Scr(); //液晶清屏 Lcd_Show_String(1,0,"Light"); //液晶顯示固定字符 Lcd_Show_String(13,0,"lx"); Lcd_Show_String(1,1,"lim"); Lcd_Show_String(13,1,"lx"); TMOD|=0X01; TH0=0X3C; TL0=0XB0; ET0=1;//打開定時器0中斷允許 EA=1;//打開總中斷 TR0=1;//打開定時器 while(1) { if(!k1)//加 { limit++; while(!k1); } if(!k2)//減 { limit--; while(!k2); } //PWM if(sec<99) sec++; else sec=1; if(pwm<sec) lamp=1; else lamp=0; } } //定時器0中斷 void Timer0() interrupt 1 { if(time<10)//定時0.5s time++; else { time=0; Pcf_Send_Byte(AddWr,0); dis=Pcf_Receive_Byte(AddWr); //ADC0 模數轉換0 光敏電阻 light=-39*dis+10000; Lcd_Show_Char(7,0,light/10000+'0'); //光照度顯示 萬 Lcd_Show_Char(8,0,light%10000/1000+'0'); //千 Lcd_Show_Char(9,0,light%1000/100+'0'); //百 Lcd_Show_Char(10,0,light%100/10+'0'); //十 Lcd_Show_Char(11,0,light%10+'0'); // 個 Lcd_Show_Char(7,1,light%10000/1000+'0'); //千 Lcd_Show_Char(8,1,limit/100+0x30); // 百 Lcd_Show_Char(9,1,limit%100/10+0x30); // 十 Lcd_Show_Char(10,1,limit%10+0x30); // 個 if(light>limit)//功能1 { pwm=0; } else { pwm=99-light*100/limit;//輸出PWM占空比,光照強度越低,pwm占空比越大 } } TH0=0X3C; TL0=0XB0; } |