都说科技让人变懒,我也不例外。自从安装了松下的洗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编写。非科班出身,肯定有改进空间。不过确实达到了自己想要的目的 下面是制作过程中的一些图片: 第一个视频,正面对着人的超声波测距模块,用单片机程序控制实现智能判断和冲水。此次视频中程序判断为尿尿。。 第二个视频,主动红外模块,用来作为备用的软开关(平时一般用不到) 最后附上源代码: #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重新编辑 ]
(责任编辑:admin) |