打印
[创新制造展示]

【21ic DIY秀】+ 智能调光台灯

[复制链接]
4489|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 hbzjt2011 于 2019-2-27 12:56 编辑

智能调光台灯

1、作品介绍:
        闲来无事,重拾51,制作了一个基于51单片机的智能调光台灯,主要实现了以下功能:两种工作模式,一种自动调节的,还有一种手动按键调节。自动模式时,白天自动灭灯,晚上自动亮灯,灯光可以根据周围光强自动调节,晚上有人自动亮灯,没人延时一段时间自动熄灭。手动模式时,可以通过按键手动调节灯光亮度。作品简陋,纯当抛砖引玉了。

2、作品方案及主要元件介绍:
         作品方案:作品的系统框图如下所示,主要采用了STC89C52单片机最小系统用作系统的控制器,采用热释电红外人体感应传感器作为系统的人体检测,判断周围是否有人;采用光敏电阻用于光线和强度检测,ADC0832数模转换芯片采集光敏电阻的电压值进行转换以后传给单片机进行处理;单片机通过光强信号使用PWM进行LED灯的亮度调节,同时使用三个单独按键负责模式切换、手动模式亮度增加和手动模式亮度减小的功能。

         元件清单及主要元器件介绍:
STC89C52单片机:STC89C52RC单片机是宏晶科技推出的新一代高速/低功耗/超强抗干扰的单片机,指令代码完全兼容传统8051单片机,12时钟/机器周期和6时钟/机器周期可以任意选择。增强型8051单片机,6时钟/机器周期和12时钟/机器周期可以任意选择,指令代码完全兼容传统8051。工作电压:5.5V~3.3V(5V单片机)/3.8V~2.0V(3V单片机)。工作频率范围:0~40MHz,相当于普通8051的0~80MHz,实际工作频率可达48MH。 用户应用程序空间为8K字节,片上集成512字节RAM。
热释电红外感应模块:HC-SR501 是基于红外线技术的自动控制模块, 采用德国原装进口LHI778 探头设计,灵敏度高,可靠性强,超低电压工作模式,广泛应用于各类自动感应电器设备,尤其是干电池供电的自动控制产品。主要特性:1、全自动感应:人进入其感应范围则输出高电平,人离开感应范围则自动延时关闭高电平,输出低电平。2、光敏控制(可选择,出厂时未设)可设置光敏控制,白天或光线强时不感应。3、温度补偿(可选择,出厂时未设):在夏天当环境温度升高至30~32℃,探测距离稍变短,温度补偿可作一定的性能补偿。4、两种触发方式。5、具有感应封锁时间。
光敏电阻:型号:GL5528  
最大电压(V-dc):150  
最大功耗(mW):100  
环境温度(°C):-30--- +70  
光谱峰值(nm):540  
亮电阻(10Lux)(KΩ):10-20  
暗电阻(MΩ):1  
100λ10:0.6  
响应时间(ms):
                上升:20                    
                下降:30
ADC0832芯片介绍:ADC0832 为 8 位分辨率 A/D 转换芯片,其最高分辨可达 256 级,可以适应一般的模拟量转换要求。其内部电源输入与参考电压的复用,使得芯片的模拟电压输入在 0~5V 之间。芯片转换时间仅为 32μS,据有双数据输出可作为数据校验,以减少数据误差,转换速度快且稳定性能强。独立的芯片使能输入,使多器件挂接和处理器控制变的更加方便。通过 DI 数据输入端,可以轻易的实现通道功能的选择。
3、原理图设计:
         系统的硬件原理图如下:

4、程序设计:
        软件程序流程图如下:
程序源码:
//宏定义
#define uint unsigned int
#define uchar unsigned char
//头函数
#include <reg52.h>               
uchar pdata tt[51];                   //定义空数组用于AD0832取平均值

uchar scale,rsd_sec;                //定义占空比比例,热释电计时秒变量
uchar sec;
bit bdata flag_auto,flag_rsd;          //位定义自动切换,热释电动作标志

uint lum;                                        //ad0832读出值
uchar m;

//管脚声明
sbit LED = P2^5;        //灯光控制输出
sbit rsd = P1^5;   //热释电
sbit qiehuan=P3^7;
sbit add=P3^6;
sbit dec=P3^5;

sbit CS=P1^3;                //CS定义脚,连接ADC0832CS脚
sbit SCL=P1^0;                //SCL定义脚,连接ADC0832SCL脚
sbit DO=P1^1;                //DO定义脚,连接ADC0832DO脚

/*****************延时函数:大约1ms************************/
void delay(uchar i)
{
  uchar j,k;
  for(j=i;j>0;j--)
    for(k=125;k>0;k--);
}
/***********读数模转换数据********************************************************/        
//请先了解ADC0832模数转换的串行协议,再来读本函数,主要是对应时序图来理解,本函数是模拟0832的串行协议进行的

unsigned char ad0832read(bit SGL,bit ODD)
{
        unsigned char i=0,value=0,value1=0;               
                SCL=0;
                DO=1;
                CS=0;                //开始
                SCL=1;                //第一个上升沿        
                SCL=0;
                DO=SGL;
                SCL=1;          //第二个上升沿
                SCL=0;
                DO=ODD;
                SCL=1;            //第三个上升沿
                SCL=0;            //第三个下降沿
                DO=1;
                for(i=0;i<8;i++)
                {
                        SCL=1;
                        SCL=0; //开始从第四个下降沿接收数据
                        value<<=1;
                        if(DO)
                                value++;                                                
                }
                for(i=0;i<8;i++)
                {                        //接收校验数据
                        value1>>=1;
                        if(DO)
                                value1+=0x80;
                        SCL=1;
                        SCL=0;
                }
                CS=1;
                SCL=1;        
                if(value==value1)                                //与校验数据比较,正确就返回数据,否则返回0        
                        return value;
        return 0;
}

/*****************按键函数*****************/
void work()
{
        uint lum_mean,lum_all;
        uchar b,c;

        if(qiehuan==0)                                  //自动切换按键按下
        {
                delay(10);                                  //去抖
                if(qiehuan==0)                          //再次判断按键按下
                {
                        flag_auto=!flag_auto; //自动模式标志位取反
                        if(flag_auto==1)          //当切换到手动模式时  首先将LED发光比例设置在50%
                        scale=20;
                }
                while(!qiehuan); //按键释放  松开按键后关闭蜂鸣器
        }
        if(flag_auto==1)
        {
                if(add==0)                                 //加键按下
                {
                        delay(10);
                        if(add==0)
                        {
                                scale++;                  //灯光比例++
                                if(scale>=41)
                                scale=41;
                        }
                }
                if(dec==0)                                  //减键按下时
                {
                        delay(10);
                        if(dec==0)
                        {
                                scale--;                   //灯光比例--
                                if(scale<=1)
                                scale=1;
                        }
                }
        }
        else
        {
                if(flag_rsd==1)                                        //有人在范围内时
                {         
                        for(b=0;b<49;b++)                         //将空数组tt【】内数值整体左移一位
                        {
                                tt[b]=tt[b+1];                        //将后一数值放到前一位置
                        }        
                        tt[49] = ad0832read(1,0);  //将读出的ad数值放入tt【49】
                        for(c=0;c<50;c++)                        //将tt【】内数值相加
                        {
                                lum_all=lum_all+tt[c];
                        }
                        lum_mean=lum_all/50;                //将总数/50取出平均值
                        lum_all=0;                                        //将总数清零
                        if(lum_mean<=30) scale=1;                           //判断取出平均值大小  小于30  发光强度0%
                        else if(lum_mean>=150) scale=41;           //大于150  发光强度100%
                        else scale=((lum_mean-30)/3)+1;                   //其他值时将其计算得到发光强度 (计算目的是为了得到一个1-41之间的数值 控制灯光变化)        
                }
                else
                {
                        scale=1;                                         //没有人在范围内时 将灯光亮度调至0%
                }        
        }
}
/*********定时器初始化函数**********/
void init()
{
        TMOD=0x11;           //工作方式
        TH1=0x3c;
        TL1=0xb0;           //T1赋初值50ms
        TH0=0xff;
        TL0=0xe7;                //T0赋初值25us         
        ET0=1;
        ET1=1;                   //打开中断允许开关
        EA=1;                   //中断总开关
        TR0=1;
        TR1=1;                   //定时器定时开关
}

/****************主函数**********************/
void main()
{
        init();                  //调用初始化函数

        while(1)                   //循环
        {
                work();                 //调用函数
        }
}

/******************定时器T0服务函数:脉冲发生函数*******************/
void time0() interrupt 1
{
        uchar n;
        TH0=0xff;
        TL0=0xe7;                 //重新赋初值
        n++;                         //每25us  n++
        if(n<scale)                 //n<设置比例时,打开灯
        {
                LED=0;
        }
        else if(n>=scale)//n大于等于设置比例时 关闭灯
        {
                LED=1;
        }
        if(n>=40)                 //n==40  :25us*40=1ms   1kHZ
        {
                n=0;                 //n=0
        }
}  
/********************定时器T0服务函数:计时和闪烁控制********************/
void time1() interrupt 3
{
        TH1=0x3c;
        TL1=0xb0;                 //重新赋初值
        m++;                         //50ms  m++
        
        if(m==20)                                                  //到达1s时
        {
                m=0;                                                  //m=0
                if(rsd==0)                                          //热释电无信号时
                rsd_sec++;                                          //热释电计时秒++
                if(rsd_sec<=20&&rsd==1)                  //热释电计时秒小于等于20 并且 热释电有信号时
                {
                        rsd_sec=0;                                  //将热释电秒清零
                        flag_rsd=1;                                  //标志位置1 控制AD0832采集数值 调节灯光亮度
                }
                else if(rsd_sec>20&&rsd==0)          //热释电计时秒大于20 并且 热释电无信号时
                {
                        flag_rsd=0;                                  //标志位置0 停止ad0832转换 关闭灯光
                        rsd_sec=0;                                  //热释电计时秒清零
                }
        }
}

5、制作过程:
焊接过程比较简单,元器件购买,万用板焊接:

6、作品展示:
焊接完成后的效果如下:
视频效果展示:


相关帖子

沙发
duhemayi| | 2019-2-27 17:14 | 只看该作者
很好

使用特权

评论回复
板凳
shunde117| | 2019-2-28 09:13 | 只看该作者
喜欢!!!!

使用特权

评论回复
地板
second_chan| | 2019-2-28 09:41 | 只看该作者
感谢楼主分享。。。

使用特权

评论回复
5
hbzjt2011|  楼主 | 2019-2-28 09:49 | 只看该作者

谢谢支持

使用特权

评论回复
6
hbzjt2011|  楼主 | 2019-2-28 09:49 | 只看该作者
second_chan 发表于 2019-2-28 09:41
感谢楼主分享。。。

谢谢支持

使用特权

评论回复
7
百川入海| | 2019-2-28 11:28 | 只看该作者
楼主做的很不错,谢谢分享。

使用特权

评论回复
8
jarye| | 2019-3-6 14:08 | 只看该作者
菜鸟才像你这样做,红外热释感应器只感应移动带热源的目标,你坐在灯下读书或写作业等不动的时候分分钟就熄灭,体验不好。单片机都有自带ADC的,还去加片IC,而且光敏二极管是不精确的,DIY一下没问题,做产品想要做的很精致光敏二极管搞不定,需要用光传感器。

使用特权

评论回复
9
hbzjt2011|  楼主 | 2019-3-7 14:19 | 只看该作者
jarye 发表于 2019-3-6 14:08
菜鸟才像你这样做,红外热释感应器只感应移动带热源的目标,你坐在灯下读书或写作业等不动的时候分分钟就熄 ...

呵呵,大神批评的是,既然都说了是DIY,何必在意那么多,再说单片机都带ADC,恐怕没这个说法吧

使用特权

评论回复
10
一路向北lm| | 2019-3-7 15:06 | 只看该作者
jarye 发表于 2019-3-6 14:08
菜鸟才像你这样做,红外热释感应器只感应移动带热源的目标,你坐在灯下读书或写作业等不动的时候分分钟就熄 ...

需要鼓励,别那么强势,明白就好

使用特权

评论回复
11
ningling_21| | 2019-3-9 14:05 | 只看该作者
hbzjt2011 发表于 2019-3-7 14:19
呵呵,大神批评的是,既然都说了是DIY,何必在意那么多,再说单片机都带ADC,恐怕没这个说法吧 ...

楼主做的不错,有遥控就更好了

使用特权

评论回复
12
liushiming82| | 2019-3-13 16:46 | 只看该作者
动手能力强,顶起

使用特权

评论回复
13
character| | 2020-9-22 08:20 | 只看该作者
很好啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:欢迎参与LabVIEW版块的讨论学习! 点我一键即达

157

主题

2338

帖子

41

粉丝