#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; } |