都说科技让人变懒,我也不例外。自从安装了松下的洗PP坐便器之后,上厕所之后的事情基本都由它解决了,很方便。
然而,唯一不满意的地方就是冲水,这个坐便器没法给你干,每次还得起身回头摁一下按钮,觉得很没技术含量。
于是就有了这次的DIY。
还只是半成品,后期估计还要美化一下。 方案构思:首先上淘宝搜索了一通,结果很少。要么就是连同整个马桶出售。要么就是需要进行对马桶排水器进行改造,预埋线等工作。对我来说都不方便。且价格偏高,不符合DIY精神。于是自己进行了设想,决定采用以下方案:
人体感应器 + 直流直线电机 + 换向电路 + 单片机系统智能控制 (实际效果见最后的视频实拍)
功耗:待机不到1W,动作时6W左右,如果24小时待机一年耗电24*1*365=8.76度电= 6块钱
造价:减速电机:128
单片机:2
超声测距模块:7
主动红外模块:5
12V剪线电源:7
继电器等其他忽略,加邮费在170左右。
程序逻辑:如果测距模块感应到障碍
小于一定距离并超过一定时间 -->判断为需要冲水(并
自动区分大号和小号) --> 人离开后一定时间 -->继电器动作 -->电机动作按压冲水按钮
下面上图:
1. 人体感应模块:原先打算使用主动红外模块,然而装上去后发现5V供电的模块,工作距离都太短,且容易受干扰。
后来更换了超声波测距模块,很精准。当然红外模块也没有浪费,用作了
备用冲水软开关使用(同时也是程序下载口)。
2. 直流电机:刚开始想用步进电机,后来觉得性价比不高,速度还挺慢。于是选了很久,选到一种直流电机的推杆。这样换向也变得非常容易,正负极交换就可以了。这个行程为20mm,带减速器,速度为10mm/s,力矩为800N,足够了。唯一的问题是噪音较大。
3. 马桶:下图是改造前的样子
4. 支架:最开始想用简单的支架搞定,被LP否决了,原因是太难看。被要求除电源外不能有任何线材裸露,于是就有了装电机的木箱子
5. 电机换向控制:这里我简单的用了两个继电器,加两个三极管进行驱动。
6. 单片机:使用普通的STC51单片机。程序为自己动手用Keil C编写。非科班出身,肯定有改进空间。不过确实达到了自己想要的目的
下面是制作过程中的一些图片:
第一个视频,正面对着人的超声波测距模块,用单片机程序控制实现智能判断和冲水。此次视频中程序判断为尿尿。。
flash: http://player.youku.com/player.php/sid/XNjc1MjMzMDU2/v.swf 第二个视频,主动红外模块,用来作为备用的软开关(平时一般用不到)
flash: http://player.youku.com/player.php/sid/XNjc1MjMxMDM2/v.swf 最后附上源代码:
#include "reg52.h"
#define uint unsigned int
#define uchar unsigned char
uchar time1;
uchar flush,average,distance;
uchar xdata value[4];
uint time;
sbit Motordown = P1^2; //高电平时推杆缩回
sbit Motorup = P1^0; //高电平时推杆伸出
sbit Senser_t = P1^4; //人体传感器Trigger
sbit Senser_e = P1^5; //人体传感器Echo
sbit Infrared_k = P3^0; //红外辅助开关
void InitMotor()
{
TMOD = 0X11; //工作方式
TH0 = 0x3C;
TL0 = 0xB0;
TH1 = 0x00;
TL1 = 0x00;
ET0 = 1; //打开定时器0中断
EA = 1; //打开总中断
TR0 = 1; //开始计时(数)
Motorup = 0;
Motordown = 1; //先回位
while (time1<60);
Motordown = 0; //同为高电平或同为低电平时,电机不转
}
void Delay(unsigned char j)
{
while(j) j--;
}
void Delayms(unsigned char x)
{
unsigned char y;
while (x--)
for (y=0;y<110;y++);
}
void MotorRun(unsigned char i)
{
switch (i)
{
case 1:
Motorup = 1; //伸出
while (time1<50);
Motordown = 1;
while (time1<70); //暂停1s
Motorup = 0; //缩回
while (time1<140);
Motordown =0; //停转
break;
case 2:
Motorup = 1; //伸出
while (time1<60);
Motordown = 1;
while (time1<100); //暂停2s
Motorup = 0; //缩回
while (time1<200);
Motordown =0; //停转
break;
}
}
void Cal()
{
TH1 = 0x00;
TL1 = 0x00;
ET1 = 1; //打开定时器1中断 注:无中断函数需求,可能不需要打开?
Senser_t = 1;
Delay(20); //至少10微秒高电平
Senser_t = 0;
while (!Senser_e); //等待低电平结束
TR1=1;
while (Senser_e); //等待高电平结束
distance = ((TH1*256+TL1)*0.017); //12M晶振时
TH1 = 0x00;
TL1 = 0x00;
TR1=0; //停止计数
ET1 = 0; //关闭定时器1中断
}
void Main()
{
unsigned char count;
InitMotor();
while (1)
{
Cal();
value[count] = distance;
count++;
if(count==5)
{
average = (value[0] + value[1] + value[2] + value[3] + value[4])/5;
count=0;
}
if (average<66)
{
time1 = 0;
if((time > 200) && (time<1800)) //持续感应10秒后
{
if (flush==0) flush=1; //冲水标记置1
}
if(time == 1800) //持续感应90秒后, 判断为大号
{
time1 = 0;
flush=2; //冲水标记置2
}
}
while ((Infrared_k == 0)&&(flush==0))
{
flush=2; //冲水标记置2
time1 = 90;
}
if (time1>100)
{
if (flush!=0) {time1=0; time=0; MotorRun(flush); flush=0;}
} //持续失去目标5秒后,执行冲水动作,time清零
Delayms(200);
}
}
/*************************************
[ t1 (50ms)中断]
*************************************/
void time0() interrupt 1
{
TL0+=0XB0;TH0=0X3C; //重装定时器初值,50ms一次
if ((time<1800)&&((average<66)||(Infrared_k==0))) time++; //90秒
if ((time>0)&&(average>66)) time--;
if ((time1<200)) time1++; //10秒
}
[ 此帖被ppxiaop在2014-02-24 19:31重新编辑 ]