#include <reg52.h> //调用单片机头文件
#define uchar unsigned char //无符号字符型 宏定义 变量范围0~255
#define uint unsigned int //无符号整型 宏定义 变量范围0~65535
#include "intrins.h"
#include "lcd1602.h"
//bit flag_200ms ;
//bit flag_100ms ;
sbit Key1=P1^0; //自动手动切换
sbit Key2=P1^1; //减
sbit Key3=P1^2; //加
sbit ADC_CS = P3^5; //ADC0832引脚定义
sbit ADC_CLK = P3^6;
sbit ADC_DAT = P3^7;
sbit LED = P2^0; //自动模式指示灯
sbit sound = P1^4; //声音传感器
sbit dq = P2^1; //18b20 IO口的定义
sbit Module = P2^2; // 人体红外感应引脚定义
sbit Lamp = P1^3; // 照明灯定义
uchar gCount=0; // 全局计数变量
uchar gIndex; // 亮度变量,0是最暗,9是最亮,一共10档
uint gTime=0; // 计时变量,用于计时多久没检测到有人
uint temperature ; //温度变量
uchar ret; //AD采集结果
/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
uint i,j;
for(i=0;i<time;i++)
for(j=0;j<112;j++);
}
/*********************************************************/
// ADC0832的时钟脉冲
/*********************************************************/
void WavePlus()
{
_nop_();
ADC_CLK = 1;
_nop_();
ADC_CLK = 0;
}
/*********************************************************/
// 获取指定通道的A/D转换结果
/*********************************************************/
uchar Get_ADC0832()
{
uchar i;
uchar dat1=0;
uchar dat2=0;
ADC_CLK = 0; // 电平初始化
ADC_DAT = 1;
_nop_();
ADC_CS = 0;
WavePlus(); // 起始信号
ADC_DAT = 1;
WavePlus(); // 通道选择的第一位
ADC_DAT = 0;
WavePlus(); // 通道选择的第二位
ADC_DAT = 1;
for(i=0;i<8;i++) // 第一次读取
{
dat1<<=1;
WavePlus();
if(ADC_DAT)
dat1=dat1|0x01;
else
dat1=dat1|0x00;
}
for(i=0;i<8;i++) // 第二次读取
{
dat2>>= 1;
if(ADC_DAT)
dat2=dat2|0x80;
else
dat2=dat2|0x00;
WavePlus();
}
_nop_(); // 结束此次传输
ADC_DAT = 1;
ADC_CLK = 1;
ADC_CS = 1;
if(dat1==dat2) // 返回采集结果
return dat1;
else
return 0;
}
/*********************************************************/
// 手动控制
/*********************************************************/
void ManualControl()
{
// 亮度减少
if(Key2==0) // 如果按键2被按下去
{
if(gIndex>0) // 只要当前亮度不为最低才能减少亮度
{
gIndex--; // 亮度降低一档
DelayMs(300); // 延时0.3秒
}
}
// 亮度增加
if(Key3==0) // 如果按键3被按下去
{
if(gIndex<9) // 只要当前亮度不为最高才能增加亮度
{
gIndex++; // 亮度增加一档
DelayMs(300); // 延时0.3秒
}
}
}
/*********************************************************/
// 自动控制
/*********************************************************/
void AutoControl(uchar num)
{
if(num<30) // 最亮
gIndex=9;
else if((num>35)&&(num<45))
gIndex=8;
else if((num>50)&&(num<60))
gIndex=7;
else if((num>65)&&(num<75))
gIndex=6;
else if((num>80)&&(num<90))
gIndex=5;
else if((num>95)&&(num<105))
gIndex=4;
else if((num>110)&&(num<120))
gIndex=3;
else if((num>125)&&(num<135))
gIndex=2;
else if((num>140)&&(num<150))
gIndex=1;
else if(num>155) // 最暗
gIndex=0;
}
/***********************18b20初始化函数*****************************/
void init_18b20()
{
bit q;
dq = 1; //把总线拿高
delay_uint(1); //15us
dq = 0; //给复位脉冲
delay_uint(80); //750us
dq = 1; //把总线拿高 等待
delay_uint(10); //110us
q = dq; //读取18b20初始化信号
delay_uint(20); //200us
dq = 1; //把总线拿高 释放总线
}
/*************写18b20内的数据***************/
void write_18b20(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{ //写数据是低位开始
dq = 0; //把总线拿低写时间隙开始
dq = dat & 0x01; //向18b20总线写数据了
delay_uint(5); // 60us
dq = 1; //释放总线
dat >>= 1;
}
}
/*************读取18b20内的数据***************/
uchar read_18b20()
{
uchar i,value;
for(i=0;i<8;i++)
{
dq = 0; //把总线拿低读时间隙开始
value >>= 1; //读数据是低位开始
dq = 1; //释放总线
if(dq == 1) //开始读写数据
value |= 0x80;
delay_uint(5); //60us 读一个时间隙最少要保持60us的时间
}
return value; //返回数据
}
/*************读取温度的值 读出来的是小数***************/
uint read_temp()
{
uint value;
uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序
init_18b20(); //初始化18b20
write_18b20(0xcc); //跳过64位ROM
write_18b20(0x44); //启动一次温度转换命令
delay_uint(50); //500us
init_18b20(); //初始化18b20
write_18b20(0xcc); //跳过64位ROM
write_18b20(0xbe); //发出读取暂存器命令
EA = 0;
low = read_18b20(); //读温度低字节
value = read_18b20(); //读温度高字节
EA = 1;
value <<= 8; //把温度的高位左移8位
value |= low; //把读出的温度低位放到value的低八位中
value *= 0.625; //转换到温度值 小数
return value; //返回读出的温度 带小数
}
/******************写亮度函数*******************/
void write_light(uchar hang,uchar add,uchar light)//写星期函数
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
write_data(0x30+light);//显示亮度等级
}
/************定时器0初始化程序*********/
void init_time0()
{
EA = 1; //开总中断
TMOD = 0x01; //定时器0、工作方式1
TH0 = 252; //给定时器0的TH0装初值
TL0 = 24; //给定时器0的TL0装初值
ET0 = 1; //开定时器0中断
TR0 = 1; //允许定时器0定时
}
/*****************主函数********************/
void main()
{
LED=0; // 指示灯点亮(自动模式指示灯)
ret=Get_ADC0832(); // 获取AD采集结果(环境光照强度)
AutoControl(ret); // 上电先进行一次自动亮度控制
AutoControl(ret+7);
init_time0(); //初始化定时器
init_1602(); //lcd1602初始化
init_1602_dis_csf(); //lcd1602初始化显示
temperature = read_temp(); //先读出温度的值
DelayMs(650);
temperature = read_temp(); //先读出温度的值
while(1)
{
/* 模式切换控制 */
if(Key1==0) // 如果按键1被按下去
{
LED=~LED; // 切换LED灯状态
DelayMs(10); // 延时消除按键按下的抖动
while(!Key1); // 等待按键释放
DelayMs(10); // 延时消除按键松开的抖动
}
/* 亮度控制 */
if(LED==1) // 如果LED是灭的
{
ManualControl(); // 则进行手动控制
}
else // 如果LED是亮的
{
if(gTime<60000)
{
ret=Get_ADC0832(); // 获取AD采集结果(环境光照强度)
AutoControl(ret); // 进行自动控制
DelayMs(200);
}
}
/*检测是否有人*/
if(Module==1)
{
gTime=0; // 检测到有人,则把60秒计时清零
}
/*检测是否声音*/
if(sound==0)
{
gTime=0; // 检测到有人,则把60秒计时清零
}
if(gTime>60000) // 如果gTime的值超过了60000
{
gTime=60000; // 则把gTime的值重新赋值为60000,避免过大溢出
gIndex=0; // 如果1分钟检测不到有人,则把台灯熄灭
}
temperature = read_temp(); //先读出温度的值
write_sfm3_18B20(1,12,temperature);
write_light(2,13,gIndex);
DelayMs(1);
}
}
/**************定时器0中断程序*****************/
void time0() interrupt 1
{
TH0 = 252;
TL0 = 24; //1ms
/*检测是否声音*/
if(sound==0)
{
gTime=0; // 检测到有人,则把60秒计时清零
}
gTime++; // 每1毫秒,gTime变量加1
gCount++; // 每1毫秒,gCount变量加1
if(gCount==10) // 如果gCount加到10了
{
gCount=0; // 则将gCount清零,进入新一轮的计数
if(gIndex!=0) // 如果说台灯不是最暗的(熄灭)
{
Lamp=0; // 则把台灯点亮
}
}
if(gCount==gIndex) // 如果gCount计数到和gIndex一样了
{
if(gIndex!=9)
- 1
- 2
- 3
- 4
- 5
- 6
前往页