【开源日记】宿舍断电自动关灯设备(一)

前言

  一个多月前,再一次早上被灯的光线刺醒之后,我随口吐槽一下学校这断电的骚操作,但是转念一想,为什么我不能做一个断电就自动把开关打下去的装置呢?于是开始了长达一个多月的“低成本开发历程”。

思路分析

  首先分析一下思路:熄灯之后自动把开关打下去,那首先得能检测到光线的变化,也就是需要一个光线传感器。其次是开关拨动的操作,虽然说还可以考虑把开关撬开,然后强行给它接一个继电器然后再去控制啥的,但是一来是不敢动这个线路(难度不大,主要是怕整短路然后被宿管找上门),二来是这方面的继电器选型问题,成本和安全无法保证。所以就采用了机械动作来拨动开关,所以需要一个舵机。既然有舵机,就需要给舵机配置一个控制电路

确定选型

  综合以上想法,开始选型。
  打开淘宝,搜索光线传感器,发现大部分卖的都是利用光电二极管来实现光线检测,找到一张卖家附的电路图:
请添加图片描述
  第一眼的想法就是:就这?那还是自己整一个!于是花了几块钱买了几个核心器件——光电二极管(光敏二极管),平均下来价格是成品是十分之一不到,而且还可以自己画板,超值!
在这里插入图片描述
  然后是舵机。找到一个某比赛剩下来的SG90舵机,这样的:
在这里插入图片描述
  确定选型之后,接下来就是真正开始实施方案了,也是我踩坑的开始。

踩坑记录

1. 用555定时器来控制舵机?

  之前参加各种科创比赛,舵机都是使用单片机来控制,但这个小玩意用单片机来控制感觉有点浪费。于是试图寻找其他办法。
  众所周知,舵机的控制原理实际上就是给它输入T=20ms,T_on = 0.5~2.5ms的脉冲波,既然这样,那为什么不用最简单的555定时器来做?说干就干,先仿真得到阻容大致取值,然后在面包板对着参数表开始调,为了效果更加直观,还借了一个示波器来看波形。
  但是,搭好电路就非常尴尬地发现,用555定时器正常产生一个脉冲波是没问题的,但是一旦接上舵机,波形立马就乱了,似乎是电流不够引起电压不稳?那就加电容,但是一直加到670μF还是一样的结果,查了一些资料,发现B站上一位大佬一样的电路(舵机不一样)舵机转得非常稳定,私信他也没有得出什么帮助。于是陷入了死局。
  最后在一位同学的提醒下,采用了STC低端的单片机——STC8G1K08A,SOP-8的封装,8个引脚却拥有两个定时器、一个10位ADC等外设,而价格也就2块钱一片,堪称国货之光
  确定单片机型号之后,接下来就是看手册、编程的过程了,不再赘述。

附:基于STC8G1K08A的可调节占空比和频率的PWM应用案例

2. 用升压电路来减少电池的数量?

  在一开始拟定的方案中,实际上我是想只用2节干电池来实现这些功能,但舵机和STC的单片机都是5V,没办法,只能再增加一个升压电路
  查阅相关资料后,我首先想到的就是最常用的MC34063,然后首先整了一个仿真,Proteus 8.10
在这里插入图片描述
在找资料的过程中,发现一个利用7402六非门实现升压的电路,基础功底确实了得!
在这里插入图片描述

原文链接(暂时没找到)

  仿真似乎没什么问题,但打板之后再焊接就发现问题了,虽然它datasheet上写的是输入电压大于3V,但是两节干电池还是有点太极限了,因为试了5V是能升到12V以上的。无奈,这个方案也得放弃。

  第二次尝试是直接在淘宝上搜升压电路,买了一个基于SB6286的现成的升压模块,据说可以输出2A,上手试了一下,发现升压倒是没什么问题,输出5V非常稳定,但是不知道为啥带不动300mA的舵机,去找店家质问,客服请教完技术之后来来回回就是一个回复:2A是最大电流,不能带电机。属于是解决不了开始扯皮了。无奈,这个方案也得放弃。
  最后,没办法,翻出了某比赛剩下的干电池,凑了四个,也总算是不需要升压模块了,电源问题就此解决。

3. 光电二极管需要聚光吗?

  众所周知,光电二极管实际上就是一个光敏开关,光线越强,导通电阻越小,这样就可以根据光线的强弱来得到不同的电压输出。然后再输入到比较器中,得到亮暗的二值表示。
  一开始,担心光线可能会不够强,是不是还需要设置一个聚光的结构,甚至还专门买了一个透镜。但最后实验发现,其实光线问题完全可以通过调整阈值来实现。而且熄灯和开灯之间的亮度差别足够大,不会出现单阈值抖动的问题。因此完全不需要透镜,这样电路板也能更加简洁。

4. 为什么比较器不能输出高电平?

  根据淘宝上扒来的那张电路图,我设计了一个光敏部分的电路:
在这里插入图片描述
这里有两个注意点:

  • 光电二极管正负极问题
    淘宝上扒的图好像是反过来的,不知道可不可行,但上面这张电路图肯定是对的(光电二极管和普通二极管一样,长脚的为正)
  • 输出上拉问题
    这个问题就比较尴尬了,好久没画电路导致忽略了这个细节。记住:LM393等一些常见的比较器都是开漏输出!

5. 舵机咋拨动开关?

  为了能够拨动墙上的开关,那舵机就必须得固定到墙上,为了提高集成度,便在电路板上做了几个定位孔,然后为舵机量身定制了一个支架:
在这里插入图片描述
  此外,由于这种SG90的舵机配备的桨都是那种非常短小的,而且宿舍有两个开关,需要同时按下去,因此需要给舵机的桨“延申一下”。一开始做了一个这样的模型:
在这里插入图片描述
3D打印之后接上舵机的桨长这样:
在这里插入图片描述
但是这个支架延长之后,似乎力度就不够了,实测只能拨动一个开关,因此必须要更换结构。既然力度不够,那能不能整个杠杆来放大力?于是又翻出某比赛剩下的木条搭建了小型杠杆:
在这里插入图片描述
最后测试的时候还是用了原来的那种短小的桨来拨动开关,实现了预期目标。

电路及实际安装展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

得意之处——省电问题

  考虑到这个设备要长期使用,但实际使用也就是拨动开关的一下,如果让它一直上电,感觉有点浪费,所以就给它设计了一个互锁电路,即单片机可以在设备不需要工作时自己断自己的电,上电需要人为操作,当时的想法是:每次熄灯之后,设备拨动开关,然后自己断电,第二天晚上开灯的时候,人为按一下上电的开关,这样设备每天工作时长从24小时变成6小时(假设18:00开灯),实现大幅省电。
在这里插入图片描述

这个电路是从前辈那里学到的,确实巧妙!

总结

  回想整个“开发历程”,会发现其实有很多不符合项目开发流程,包括进度控制,未验证先实践等问题,但最主要反应的还是工程经验的不足,基础功底不扎实,再接再励吧!

后续版本期待

  • 增加ADC,实现光线模拟量测量
  • 长期运行,实现全自动化

后续

源码 //2023.4.18

本来以为这个代码本身应该是很简单的,会一点51即可,担心太占篇幅,所以当初没加,但好在现在csdn可以自动折叠代码,还是附一下吧,需要自取

#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char

sfr P5 = 0xC8;
sfr P5M0 = 0xCA;
sfr P5M1 = 0xC9;
sfr P3M0 = 0xB2;
sfr P3M1 = 0xB1;

sbit PWM = P5 ^ 5;   //舵机PWM输出引脚
sbit LED = P3 ^ 2;   //光敏二极管输出信号
sbit relay = P3 ^ 3; //继电器控制引脚
sbit mode = P5 ^ 4;  //用来切换模式

uchar time;        //定义频率(周期)的变量
static uchar th;   //阈值,用来改变占空比(范围在8-27左右,最使用static)
uint delay = 0;    //延时变量

uchar msec = 0;    //用来定时的变量
uchar sec =  0;
uchar min =  0;
uchar hour = 0;

/************************************************************************
--------------------------------------
PxM0 | PxM1 |           功能
--------------------------------------
  0  |   0  |         准双向口
  0  |   1  |         高阻输入(默认)
  1  |   0  |         推挽输出
  1  |   1  |         开漏输出
--------------------------------------
P5.4 : 高阻输入(mode)   //P5M0 : 0010 0000
P5.5 : 推挽输出(PWM)    //P5M1 : 1101 1111
P3.2 : 高阻输入(LED)    //P3M0 : 0000 1000
P3.3 : 推挽输出(relay)  //P3M1 : 1111 0100 (保持两个串口为双向口)
*************************************************************************/
void IO_Init()  //初始化端口
{
    P5M0 = 0x20;
    P5M1 = 0xDF;

    P3M0 = 0x00;
    P3M1 = 0xF4;
}

void Timer_Init() //初始化定时器
{
    TMOD = 0x00;//定时器0工作方式0【16位自动重装】
    TR0 = 0;    //关闭定时器0
    /*f_out = Sysclk/12/(65536-[TH0, TL0])*/
    /*频率手动设置为12MHz*/
    TH0 = 0xFF; //赋初值——目的是得到周期为0.1ms【10000Hz】
    TL0 = 0x9C; //舵机需要的周期为20ms,相当于要200分频,即舵机有200级可调
    ET0 = 1;    //开定时器0中断
    EA = 1;     //开总中断
    TR0 = 1;    //启动定时器0
}

int main()
{
    IO_Init();
    Timer_Init();
    LED = 1;    //设置为输出1,才能接收外界的输入
	mode = 1;
	th = 15;    //初始状态
    while(1)
    {
		if(mode == 1) //长效使用模式
		{
			if(msec == 50)
			{
				msec = 0;
				sec ++;
				if(sec == 60)
				{
					sec = 0;
					min ++;
					if(min == 60)
					{
						min = 0;
						hour ++;
						if(hour == 24)
							hour = 0;
					}
				}
			}
			if(hour == 0 && min == 0 && sec == 0)  //实现上电时关灯,且之后每间隔24小时进行一次
			{
				th = 5;
				delay = 0;
				while(delay < 50);
				th = 15;
			}
		}
		else
		{
			if(LED == 0)//注意要用双等号
			{
				th = 5;  //拨动开关
				delay = 0;
				while(delay < 50);  //延时
				th = 15; //复位
				delay = 0;
				while(delay < 50);
				relay = 0;
			}
			else th = 15;
        }
    }
}

void tim0() interrupt 1
{
    time++;
    if(time >= 200) //50hz
	{
		time = 0;
		delay ++;
		msec ++;
	}

    if(time <= th) //设置占空比
        PWM = 1;
    else PWM = 0;
}
  • 10
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

记录无知岁月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值