单片机智能台灯

2020-02-15 21:34:12 weixin_44212493 阅读数 1015

功能及概述
本系统组成如图一所示,主要由三部分组成:

  1. 传感器及信号处理部分:检测人体辐射红外信号及光强信号经过处理后变成可处理的数字信号
  2. 以80C51组成的中央处理单元:处理信号并发出控制命令
  3. 提醒电路及灯光控制电路 :给出提醒信号并根据80C51给出的命令控制灯光
    整个系统是以80C51控制下工作的。其工作过程为:当环境光比较强时,光敏电阻阻值比较小,信号处理电路检测到低电平信号,禁止热释电红外传感器工作,省去了80C51处理过程。当环境光比较弱时,光敏电阻阻值变大,信号处理电路接收到高电平,从而启动热释电红外传感器工作。热释电红外传感器1探测比较远的距离,当人体进入到传感器1的控测范围内且光强较弱时,信号检测电路处理信号,并向单片机发送一个中断,80C51启动灯光控制电路,使灯慢慢变亮。当环境光比校弱时,且人体过于靠近桌面,热释电红外传感器2检测到信号,同时了在热释电红外传感器1的控测范围内,信号处理电路同时向80C51发送信号,80C51处理信号根据优先级顺序,屏蔽掉热释电红外传感器1的信号,启动延时电路,发出警报使人离开,若在设定的时间内未离开桌面,则启动灯光控制电路,使灯慢慢熄灭。当人体离开热释电红外传感器2的控测范围且在热释电红外传感器1的控测范围内时,灯光又慢慢变亮。

设计资料
在这里插入图片描述
在这里插入图片描述
电路原理图
在这里插入图片描述
三、测试结果:
本系统的主要设计思想来源于生活。台灯是一般家庭的生活必需品,但由于经常忘记关灯而造成巨大的能源浪费。全球这么多台灯,估算一下,消耗能源可观。另一个是作为一个必需品,当然要使生活变得更方便,省去了黑暗中开灯的麻烦,并且可以纠正坐姿。本系统在实验室进行了实物实验。热释电红外探测器1的距离是4m左右(距离可调),主要是因为般来说是门离书桌的距离;以便黑暗中时人一到门口则启动,省去了开灯的麻烦,用户可以根据自己的实际情况进行距离调节。热释电红外探测器1的距离是10cm左右(距离可调),主要考虑是当学习时,有时坐姿不正,引起身体离桌面太近,容易引起近视,此时台灯发出警告,提醒注意,若在设定的时间内未离开,则强制熄灭。有时人学习累了,趴在桌子上睡觉,而忘了关灯,这时系统就会检测到,从而启动延时程序,一段时间过后,台灯就会自动熄灭。
本系统的主要技术难点在于对人体红外信号的采集及处理。由于采用的是热释电红外传感器,当人体进入其感应范围时,传感器就会产生几mV信号,然后通过以BISS0001为中心的信号处理电路,对信号进行二次放大,并滤波,以防止外界的信号产生干扰。信号经过BISS0001后从而转化为数字信号输出,便于用单片机进处理。
本系统制作的主要设计源泉来源于生活,因此创新之处也在于处理生活中一些比较常见的问题。以专门感应人体红外信号的热释电红外传感器为基础,以BISS0001信号处理电路,利用单片机进行处理,以达到便于控制的目的。当房间亮度不够时,且有人在附近时,台灯便会自动点亮,省去了黑暗中摸开关的麻烦;当学习时由于靠桌面太近,造成坐姿不正,系统就会提示,以纠正坐姿,防止近视;当学习太累了时,趴在桌子上睡会儿时,台灯就会自动熄灭;当无人在时,系统也会使台灯自动熄灭,以达到节省能源的目的。除了硬件部分采用防干扰技术外,在软件中也采用了防干扰技术,当中断0产生时,并不立即执行,而是对其进行延时,防止由于不小心而进入到探测器2的范围内,以免产生误判。
虽然本系统以达到了使生活方便的目的,但是电路还是不够简单。因为当有多个热释电红外传感器时,就需要相应的信号检测电路。改进之处在于用一个信号处理电路同时控制多个传感器。还有一个不足之处在台灯开启时,产生的光强容易干扰光敏电阻对环境光强的判别,引起误判,现在的处理方法是传感器部分与控制部分单独分开放置。

设计感想:
本系统的设计思想来源于生活,所以所具有的功能也是为生活的方便而设置的。因此就产生了制作智能台灯的想法。首先在与老师的商讨下,对项目进行了认证,确定了项目的可行性,列出了项目的主要难点及可能出现的问题,确定了以后的制作重点。接下来进行构思,列出大体的框架图。然后根据框架图用PROTEL画出电路原理图。
在对电路原理图进行了严谨的认证后,便开始了焊接电路。由于主要对象是人,因此采用热释电红外传感器,此传感器是专门用于接收人体产生的10um左右的信号,相应的利用BISS0001处理其所产生的信号并转化为可处理的数字信号。在焊接的过程中发现若用到两个光敏电阻,则可能使单片机产生误判。因此将两个光敏电阻合到一块,不仅简化了电路,还提高了系统的稳定性。当信号检测及处理部分完成后,便开始试检,以确定电路焊接正确与否。在对电路进行调试的过程中,必须排除外界的干扰,尤其是附近热源的红外线干扰。首先将BISS0001设置成不可重复触发方式,比较长延迟时间,以便得到稳定的输出信号,并把接收光电池的引脚接成高电平,使BISS0001认为一直处于黑暗之中,便于观测。在运行时,当人远离时,BISS0001输出低电平,符合要求;但是在人靠近后信号出现不规则的变化。利用示波器对BISS0001的各个管脚进行测量,发现信来源的主要不稳定因于传感器,因此,在目前没有更好的更换下,只好采用目前的热释电传感器。
接下来做的是数字电路部分,主要80C51、74LS138、LM324、DAC0832组成。数字电路部分比较简单,焊接完成后,编写一个新程序,对各个端口进行扫描,从而显示数字电路是可行的。
在对电路部分进行了初步的检测后,解决了比较主要的问题;因此依据硬件编写相应的程序,经过KEIL软件仿真后,语法上无错误,各个端口的数据正是所需要的,最后是将软件烧到单片机中,然后运行整个系统。
通过本次实验,熟悉了电路的开发和制作及论文的编著写。在实验中也遇不少难题,但通过各种方法进行了解决。

程序参考源代码(部分)

ORG 0000H
AJMP MAIN
ORG 0003H
AJMP DET1 ;远探测器
ORG 0013H
AJMP DET0 ;近探测器

ORG 0050H
MAIN: MOV P0, #00000001B ;置初始值DET0,DET1可重复触发,灯灭
MOV TMOD, #00000010B ;方式2,8位自动重装计数器
MOV TCON, #00010000B ;开启计数器T0
MOV IE, #10000111B ;开启所有中断
SJMP $
;灯慢慢变亮
DET1: MOV P0, #00000001B
CALL TIME0 ;灯亮度延时10ms
MOV P0, #00000011B
CALL TIME0
MOV P0, #00000101B
CALL TIME0
MOV P0, #00000111B
CALL TIME0
MOV P0, #00001001B
CALL TIME0
MOV P0, #00001011B
CALL TIME0
MOV P0, #00001101B
CALL TIME0
MOV P0, #00001111B
CALL TIME1
RETI
;灯慢慢熄灭
DET0: CALL TIME1 ;延时1分钟
MOV TCON, A
ANL A, #1
JZ LOOP
MOV P0, #00001111B
CALL TIME0
MOV P0, #00001101B
CALL TIME0
MOV P0, #00001011B
CALL TIME0
MOV P0, #00001001B
CALL TIME0
MOV P0, #00000111B
CALL TIME0
MOV P0, #00000101B
CALL TIME0
MOV P0, #00000011B
CALL TIME0
MOV P0, #00000001B
RETI
LOOP: ret
;延时10ms
TIME0: SETB TR0
MOV R0, #250
MOV R1, #20
D_1: DJNZ R0, D_1
MOV R0, #250
DJNZ R1, D_1
CLR TR0
RET
;延时1分钟
TIME1: SETB TR0
MOV R0, #250
MOV R1, #200
MOV R2, #60

鉴于篇幅限制,只有部分代码,需要完整代码请自行下载

最后,如果有什么意见或者建议欢迎您留言给我,让我们共同学习一起进步,
如果需要 完整代码或设计文件,请在下方留言或者私信我,看到后会第一时间回复。

谢谢!

2019-08-03 10:32:00 dknt54626 阅读数 317

  在学完了STM32F4的芯片后,尝试着独立开发一个智能灯小项目,大概功能就是:KEY2按键长按实现开关机,短按切换模式,分别为自动模式和手动模式,自动模式下会根据光照强度改变灯的亮度,手动模式用KEY1来改变灯的亮度,分为6档,按下KEY1逐渐变亮,第六次关闭。开关机蜂鸣器会发出提示音。使用的是STM32F103C8这款芯片。

在开发之前要搭建环境,STM32F103的芯片因为FLASH的大小不同分为了不同型号,不同型号所需的启动文件也不同

startup_stm32f10x_cl.s                  ------------  互联型的STM32F105xx,STM32F107xx

startup_stm32f10x_hd.s                -------------大容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_hd_vl.s           -------------大容量的STM32F100xx
startup_stm32f10x_ld.s                --------------小容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_ld_vl.s           ---------------小容量的STM32F100xx
startup_stm32f10x_md.s              ---------------中容量的STM32F101xx,STM32F102xx,STM32F103xx
startup_stm32f10x_md_vl.s         ----------------中容量的STM32F100xx
startup_stm32f10x_xl.s                ----------------超大容量FLASH在512K到1024K字节的STM32F101xx,STM32F102xx,STM32F103xx

一、GPIO的配置

按照之前的配置步骤:

1.看原理图确定引脚    ----原理图

 

LED0,PB3

2.看通用功能是否是IO的功能  -----数据手册

 

 通用功能是作为JTDO(调试功能)使用的,如果我们要将PB3作为通用IO口的功能,需要重映射,把IO口的功能映射到PB3上。

 

根据图中的内容看出我们需要将AFIO_MAPR这个寄存器的SWJ_CFG这个位配置成相应的功能,而使能这个寄存器又要打开相应的时钟

1、使能AFIO这个功能的时钟

2、配置SWJ_CFG这个位为相应的模式

这个寄存器是在APB2这个时钟上,只需要将第0位置为1就可以使能这个寄存器了,

2、配置AFIOP_MAPR寄存器

 因为在作IO口的功能时还需要用到调试功能,所以在这里将010写入SWJ_CFG这个寄存器就将IO口的功能映射IO口上了

3.配置工作模式

寄存器和STM32F4的有所不同,低寄存器配置的时相应端口的0~7八个管脚,高寄存器控制8~15八个管脚。

每个管脚由四个位控制,PB3作为灯的IO口,应该配置成通用推挽输出模式,在MODE位中写入01,10,11三个值都行,CNF位中写入00,因为CRL和CRH这两个寄存器的复位值位0x44444444所以使用前要将对应位清零,具体操作为

RCC->APB2ENR |= (1<<2);

GPIOB->CRL &=~ (0xf<<12);
GPIOB->CRL |= (3<<12);
GPIOB->ODR |= (1<<3);

然后通过ODR寄存器改变输出的信号就可以控制led灯了。

按键,热释电传感器的配置都是用作输出,只需要改变相应的为就可以了。(关于GPIO详细配置看另一篇文章)

 

转载于:https://www.cnblogs.com/whpl22-Blog/p/11293979.html

2019-08-06 17:23:18 sun_fengjiao 阅读数 1401

项目三:智能台灯的设计

三人为一个小组参加比赛,我们的选题是智能台灯,实现的基本功能是:台灯有两种模式可以选择一种模式是节能模式,自己根据外界的光照亮度调节亮度使亮度保持在一个范围,第二种模式是手动模式,可以通过按键调节台灯的亮度且总共有5个档次可以调节,另外台灯还可以显示时间精确到秒及实时的温度并可以通过按键调节时间。作为主要负责人之一,我负责光照亮度及温度的检测及显示模块并且制作台灯的造型。台灯的加分项是可以语音控制,这一部分我们没有做出来,但是我们利用红外传感器实现了台灯的手势控制。我们组全部完成了台灯的基本要求,获得了二等奖。

温度检测模块:DS18B20温度传感器

光照亮度检测与现实模块:利用光敏电阻和普通的电阻组成一个电路:然后再接入PCF8591 AD/DA芯片进行AD的转换再给51单片机处理。PCF8591 芯片是利用I2C协议进行通信。I2C总线只需要一根数据线和一根时钟线两根线。对于时序的要求特别高。

2019-01-19 21:54:06 lin5103151 阅读数 15961

1.功能介绍
智能台灯可分成自动和手动两种模式。在自动模式下,台灯能根据环境光的亮暗与人是否被台灯所检测到(人是否在)来自动开启台灯。当人被微机检测到,环境光又达到某个程度的时候(可以设定与调节),台灯就会开启。如果环境光没有达到这个程度,台灯不会开启。当人没有被微机检测到,无论多暗,台灯也不会开。  手动模式是为了不习惯使用自动模式的人或是台灯中的微机出故障等紧急情况时用的。在手动模式下,智能台灯和普通台灯是一样使用的。
主要功能 :
(1)亮度不够且有人靠近时台灯自动亮;
(2)靠的太近会提醒坐姿不正(蜂鸣器)
(3)附近无人时台灯自动熄灭(30秒) 时间可调
(4)根据环境亮度调节等亮度
(5)可手动调节台灯亮度
(6)设定学习时间

2.硬件设计
(1)总体硬件设计
整体硬件电路是以AT89C52单片机为控制核心,主要由热释电红外传感器,光敏电阻信号处理电路,提醒电路,灯光控制电路,故障报警电路等组成。单片机可将热释电红外传感器检测到的人体辐射红外信号及光强信号的模拟量转换成数字量。
在这里插入图片描述

(1)LED驱动电路
在这里插入图片描述
LED驱动电路采用3路串联、每路4颗的LED灯,使用三极管S8050来控制LED灯的亮灭。在软件上采用PWM控制方式,以此达到控制LED灯的亮度。
(2)光敏感应电路
在这里插入图片描述
对于台灯亮度的感应采用了光敏电阻,利用光敏电阻的阻值随着亮度的改变而改变,电阻值的改变会改变光敏电阻上的电压值。这时,通过AD转换器采集电压,转换成相应的光强数据传输给单片机。
在这里插入图片描述
(3)人体感应电路
人体感应电路采用了HC-SR501基于红外线技术的数字传感器。当传感器感应到人体时,传感器IO引脚输出高电平;当无人体时,传感器输出低电平。
在这里插入图片描述
(4)红外接近传感器
红外接近传感器采用了E18- D80NK数字型传感器,检测到目标是低电平输出,正常状态是高电平输出;此传感器的功能为检测用户是否坐于台灯前。
在这里插入图片描述
3.软件设计
(1)数码管驱动程序

#define DUAN P0				  //数码管段位
sbit W0=P2^7;		//数码管位端
sbit W1=P2^6;
sbit W2=P2^5;
sbit W3=P2^4;

/**********************************************************************
* 名称 : display();
* 功能 : 数码管显示
* 输入 : 无
* 输出 : 无
***********************************************************************/	  
void display()
{
	if(flag_set==0)			   //正常模式下
	{
		DUAN=tab[min/10];	   //送入段码,秒数高位
		W0=0;				   //打开位地址
		delay(1);			   //小延时
		W0=1;				   //关闭位地址
		DUAN=tab_dian[min%10]; //送入段码,秒数低位
		W1=0;
		delay(1);
		W1=1;
		DUAN=tab[sec/10];	   //送入段码,分钟数高位
		W2=0;
		delay(1);
		W2=1;
		DUAN=tab[sec%10];	   //送入段码,分钟数高位
		W3=0;
		delay(1);
		W3=1;
	}
	else if(flag_set==1)	   //设置模式下闪烁相应位
	{
		if(ss==1)			   //闪烁标志  ss=1 正常显示
		{
			DUAN=~tab[min/10];
			W0=0;
			delay(1);
			W0=1;
			DUAN=~tab_dian[min%10];
			W1=0;
			delay(1);
			W1=1;
		}
		else				   //闪烁标志  ss=0 熄灭相应位 达到闪烁效果	 ss在定时器里500ms取反一次
		{
			DUAN=~tab[10];	   //
			W0=0;
			delay(1);
			W0=1;
			DUAN=~tab_dian[10];
			W1=0;
			delay(1);
			W1=1;
		}
		DUAN=~tab[sec/10];
		W2=0;
		delay(1);
		W2=1;
		DUAN=~tab[sec%10];
		W3=0;
		delay(1);
		W3=1;
	}
	else
	{
		
		DUAN=~tab[min/10];
		W0=0;
		delay(1);
		W0=1;
		DUAN=~tab_dian[min%10];
		W1=0;
		delay(1);
		W1=1;
		if(ss==1)
		{
			DUAN=~tab[sec/10];
			W2=0;
			delay(1);
			W2=1;
			DUAN=~tab[sec%10];
			W3=0;
			delay(1);
			W3=1;
		}
		else
		{
			DUAN=~tab[10];
			W2=0;
			delay(1);
			W2=1;
			DUAN=~tab[10];
			W3=0;
			delay(1);
			W3=1;
		}
	}
}

(2)按键驱动程序

sbit change= P2^3;	//自动模式切换按键
sbit set = P2^2;	//设置按键
sbit add = P2^1;	//加按键
sbit sub = P2^0;	//减按键

/**********************************************************************
* 名称 : KEY();
* 功能 : 按键控制
* 输入 : 无
* 输出 : 无
***********************************************************************/
void KEY()
{
	uint lum_mean,lum_all;
	uchar b,c;
	if(change==0)				  //自动切换按键按下
	{
		delay(10);				  //去抖
		if(change==0)			  //再次判断按键按下
		{
			buzz=0;				  //蜂鸣器鸣响
			flag_auto=!flag_auto; //自动模式标志位取反
			if(flag_auto==1)	  //当切换到手动模式时  首先将LED发光比例PWM设置在50%
			scale=20;
			
		}
		while(!change) display();buzz=1; //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
	}
	if(jiejin==0&&flag_jiejin==1) //接近传感器检测到障碍时  开启报警
	{
		buzz=0;
		flag_jiejin=0;
	}
	if(jiejin!=flag_jiejin)	      //接近传感器检测不到障碍时  关闭报警
	{
		buzz=1;
		flag_jiejin=1;
	}
	if(set==0)				      //设置键按下时
	{
		delay(10);
		if(set==0)
		{
			buzz=0;
			flag_set++;			  //设置变量++
			if(flag_set==3)		  //加到3时回复回正常模式
			flag_set=0;
			flag_bs=0;			  //按下设置 关闭报警
			
		}
		while(!set) display(); buzz=1;//等待按键释放  松开按键后关闭蜂鸣器、刷新显示
	}
	if(flag_set==1)					  //加键按键只有在设置状态(flag_set!=0)时按下才有效	  调分
	{								 
		if(add==0)					  //加按键按下时
		{
			delay(10);				  //消抖
			if(add==0)
			{
				buzz=0;				  //蜂鸣器响
				min++;				  //分++
				if(min>=60)
				min=0;
				
			}
			while(!add) display(); buzz=1;	 //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
		if(sub==0)					  //减按键按下时
		{
			delay(10);				  //消抖
			if(sub==0)
			{
				buzz=0;				  //蜂鸣器响
				min--;				  //分--
				if(min>0)
				min=59;
				
			}
			while(!sub) display(); buzz=1;	 //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
	}
	if(flag_set==2)					//调秒
	{								
		if(add==0)					//加键按下
		{						
			delay(10);				//消抖
			if(add==0)
			{
				buzz=0;				//蜂鸣器响
				sec++;				//秒++
				if(sec>=60)
				sec=0;
				
			}
			while(!add) display(); buzz=1;	  //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
		if(sub==0)					 //减键按下
		{
			delay(10);
			if(sub==0)				 //消抖
			{
				buzz=0;				 //蜂鸣器响
				sec--;				 //秒--
				if(sec<0)
				sec=59;
				
			}
			while(!sub) display();	buzz=1;	  //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
		while(!sub);
	}
		
	if(flag_auto==0)					//自动模式
	{
		if(flag_rsd==1)					//且有人在范围内时	环境发光强度控制灯光变化
		{
			for(b=0;b<49;b++) 			//将空数组tt[]内数值整体左移一位
			{
				tt[b]=tt[b+1];			//将后一数值放到前一位置
			}
			tt[49]=ADC0809();			//将读出的ad0809数值放入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%
	}
	else						  	 //手动模式下
	{
		if(flag_set==0)				 //正常模式下
		{
			if(add==0)				 //加键按下
			{
				delay(10);
				if(add==0)
				{
				//	buzz=0;           //蜂鸣器响
					scale++;		  //灯光比例++
					if(scale>=41)
					scale=41;
					display();
				}
			//	while(!add) display();	buzz=1;
			}
			if(sub==0)				  //减键按下时
			{
				delay(10);
				if(sub==0)
				{
				//	buzz=0;			   //蜂鸣器响
					scale--;		   //灯光比例--
					if(scale>1)
					scale=1;
					display();
				}
		//		while(!sub) display(); buzz=1;
			}
		}
	}
}

(3)ADC控制程序

#define Data_ADC0809 P1
//ADC0809 控制引脚定义
sbit ST=P3^1;
sbit EOC=P3^2;
sbit OE=P3^3;

extern uchar ADC0809();	   //函数声明
/**********************************************************************
* 名称 : ADC0809();
* 功能 : ADC0809把模拟量转化为八位数字量
* 输入 : 无
* 输出 : 无
***********************************************************************/
uchar ADC0809()
{
	uchar temp_=0x00;	
	OE=0;		 //初始化高阻态	   转化初始化   低电平,禁止输出允许
	ST=0;
	ST=1;		 //上升沿 清零    
	ST=0;		 //下降沿 开始转换
	while(EOC==0);	    //外部中断 等待AD转换结束	EOC为1时AD转换结束跳出
	OE=1;			  	//高电平,输出允许
	temp_=Data_ADC0809;	//读取转换的AD值
	OE=0;				//低电平,禁止输出允许
	return temp_;		//返回ADC读取值
}

(4)LED亮度控制程序

//管脚声明
sbit LED = P3^4;	//PWM输出
sbit change= P2^3;	//自动模式切换按键
sbit rsd = P3^6;    //热释电
sbit jiejin=P3^5;   //接近开关
sbit buzz=P3^7;     //蜂鸣器报警电路
/**********************************************************************
* 名称 : init();
* 功能 : 初始化定时器
* 输入 : 无
* 输出 : 无
***********************************************************************/
void init()
{
	TMOD=0x11;	   //工作方式1
	TH1=0x3c;
	TL1=0xb0;	   //T1赋初值50ms
	TH0=0xff;
	TL0=0xe7;	   //T0赋初值25us	  
	ET0=1;
	ET1=1;		   //打开中断允许开关
	EA=1;		   //中断总开关
	TR0=1;		   //开定时器0 开关
	TR1=0;		   //关定时器0 开关
}

/**********************************************************************
* 名称 : void time0() interrupt 1
* 功能 : 定时器T0 中断服务函数:PWM脉冲发生函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void time0() interrupt 1
{
	uchar n;
	TH0=0xff;
	TL0=0xe7;		 //重新赋初值
	n++;			 //每25us  n++
	if(n>scale)		 //n<设置比例时,打开灯
	{
		LED=1;
	}
	else if(n<=scale)//n大于等于设置比例时 关闭灯
	{
		LED=0;
	}
	if(n==40)		 //n==40  :25us*40=1ms   1kHZ
	{
		n=0;		 //n=0
	}
	else ;	
}

/**********************************************************************
* 名称 : void time1() interrupt 3
* 功能 : 定时器T1 中断服务函数:计时和闪烁控制	  红外热释
* 输入 : 无
* 输出 : 无
***********************************************************************/
void time1() interrupt 3
{
	uchar m;
	TH1=0x3c;
	TL1=0xb0;		 //重新赋初值
	m++;			 //50ms  m++
	if((m==10||m==20)&&flag_set!=0)	  //每过500ms  并且 在设置状态时 
	{
		ss=!ss;						  //闪烁变量取反
	}
	if(m==20)						  //到达1s时
	{
		m=0;						  //m=0
		if(rsd==0)					  //热释电无信号时
		rsd_sec++;					  //热释电计时秒++
		if(rsd_sec<=30&&rsd==1)		  //热释电计时秒小于等于30 并且 热释电有信号时
		{
			rsd_sec=0;				  //将热释电秒清零
			flag_rsd=1;				  //标志位置1 控制AD0809采集数值 调节灯光亮度
		}
		else if(rsd_sec>30&&rsd==0)	  //热释电计时秒大于30 并且 热释电无信号时
		{
			flag_rsd=0;				  //标志位置0 停止ad0809转换 关闭灯光
			rsd_sec=0;				  //热释电计时秒清零
		}
		if(flag_set==0&&flag_bs==0&&((min+sec)!=0))		 //正常模式下&&未报警&&定时时间不为零时
		{
			sec--;
			if(sec<0)									 //定时秒--  小于0时
			{
				sec=59;									 //复位到59秒
				min--;									 //分--
			}
			if(min<=0&&sec==0)							 //分和秒都减到零时
			{
				min=0;
				flag_bs=1;
				buzz=0;									 //蜂鸣器报警提示时间到
			}
		}
//		else buzz=1;	
	}	
}

(5)主函数


/**********************************************************************
* 名称 : main();
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void main()
{
	init();		  //调用初始化函数
	flag_auto=1;  //初始化手动模式
	rsd=0;		  //热释电引脚置低(有信号时时高电平)
	delay(500);	  //延时500ms后开机

	while(1)	  //大循环
	{
		KEY();		 //调用按键函数
		display();	 //调用显示函数
	}
}

源码+AD电路图 下载:关注公众号,首页回复“智能台灯”获取资料
在这里插入图片描述

2016-05-26 22:11:09 sunzhaojie613 阅读数 23265

    用自己的手机控制自己的台灯,是不是想想就挺有趣的! 以后就可以在床上,用手机来控制台灯的开关,是不是很酷!博主以前也有过这种想法,然后就尝试做了一下。为了让有和我一样想法的同学少走点弯路,就写了这篇博客,与诸君共勉。大笑


国际惯例先上效果图



    先讲一下整体思路哈!手机肯定不能直接控制台灯的,需要一个中间物来协调,在这里我用的是51单片机(如果大家不知道也没关系,下面我还会说的)。接下来就是具体怎么控制的,其实原理挺简单的。1.手机通过蓝牙来与单片机通信,因而单片机需要外接一个蓝牙模块(我用的是hc-05  主从一体 蓝牙模块)。大家千万不要被外接给吓到了,外接模块一点都不难的,就只要去淘宝卖相应的模块然后用杜邦线(不知道的可以把它当做导线来理解)和51单片机连起来就好了。到这里手机已经可以和51单片机通信了,也就是说手机可以给单片机发送“开灯”和“关灯”的消息了。2.接下来就要解决当51单片机接收到”开灯“和”关灯“的消息后,该怎么控制台灯实际的开关?这个时候我们就需要一个继电器(也是单片机的外接模块),关于继电器我们可以看下面的图片。继电器一共有三个输出端口(常开端 公共端 常闭端)。事先申明,我们可以通过单片机控制继电器的公共端是和常开端

                                          




连通,还是和常闭端连通。现在我们只需要剪断台灯的一根电线,将电线的两头分别和继电器的常开端和公共端连接起来即可。通过单片机控制继电器的公共端和常开端连接时台灯打开,反之台灯关闭。大致原理就是这样,我们来梳理一下整个流程。首先手机通过蓝牙和单片机的蓝牙模块建立通信,当手机发送一个打开台灯信号时,单片机收到相应的信号并控制继电器的公共端指向常开端,台灯亮起。  




  next~就是具体实现了。一共分为两大部分,分别是Android端和单片机端,先从Android端开始说起。


   一.Android端:

   Android端其实就是一个简单的蓝牙通信,Android端只需要通过蓝牙向单片机的蓝牙模块发送开关对应的消息即可(我是用0xff表示打开台灯,0x00关闭台灯)。先来看看工程的总体结构以及软件界面。


                              


  其中BluetoothTool类是一个蓝牙工具类,里面有关于蓝牙的连接以及发送接收数据功能。IUpdateUI是一个接口,用来在 BlurtoothTool中更新主界面的设备列表以及log。MainAty就是主界面的Activity。activity_main.xml和layout_lv_devices_item.xml不用多说了吧,就是一些界面有关的。关于Android端的解析以贴代码为主,因为代码中我都有详细的解释,比较重要的我会在博客中用文字再次解释的。

 

1.MainAty:


获取蓝牙适配器,可以通过蓝牙适配器获取蓝牙设备的信息。

/**
 * 获得默认的蓝牙适配器
 */
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();


如果手机没打开蓝牙,则界面跳转到打开蓝牙界面。

@Override
protected void onStart() {
    super.onStart();

    /** 判断蓝牙是否可用,不可用时请求打开*/
    if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
        Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivity(intent);
    }
}


  通过蓝牙适配器获取之前匹配过的蓝牙设备信息(如单片机的蓝牙设备),所以第一次使用的时候,先用手机自带的蓝牙匹配成功一次哈!蓝牙设备中一个比较重要的信息就是设备地址-如98:D3:33:80:83:05就是一个蓝牙设备地址,唯一标示。

/** 获取以前匹配过的蓝牙设备*/
        Set<BluetoothDevice> devices = null;
        if (mBluetoothAdapter != null)
            devices = mBluetoothAdapter.getBondedDevices();
        else
            Toast.makeText(MainAty.this, "该设备不支持蓝牙功能 ", Toast.LENGTH_SHORT).show();

        if (devices != null && devices.size() > 0) {
            data.clear();
            for (BluetoothDevice device : devices) {
                HashMap<String, Object> map = new HashMap<>();
                map.put("lv_left_icon", R.drawable.lv_left_icon);
                map.put("lv_address", device.getAddress());
                map.put("lv_right_icon", R.drawable.lv_right_white);
                data.add(map);
            }
        } else {
            HashMap<String, Object> map = new HashMap<>();
            map.put("lv_left_icon", R.drawable.lv_left_icon);
            map.put("lv_address", "没有已经匹配的设备");
            map.put("lv_right_icon", R.drawable.lv_right_white);
            data.add(map);
            mTextView.append("没有已经匹配的设备" + "\r\n");
        }

        simpleAdapter.notifyDataSetChanged();

 连接指定的蓝牙:通过调用BluetoothTool连接蓝牙,我们传入了设备的地址"(String) data.get(0).get("lv_address")"以及连接类型 BluetoothTool.ServiceOrClient.CLIENT(这里我们是以客户端的形式连接,也就是单片机的蓝牙当作客户端 )。之后设置了BluetoothTool的更新UI接口,并在MainAty中具体实现。
builder.setPositiveButton("连接", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
        mBluetoothTool = new BluetoothTool((String) data.get(0).get("lv_address"),
                BluetoothTool.ServiceOrClient.CLIENT);
        mBluetoothTool.SetOnIUpdateUI(new IUpdateUI() {
            @Override
            public void updateListViewDevices() {
                for (int i = 0; i < data.size(); i++) {
                    if (i == index) {
                        data.get(i).put("lv_right_icon", R.drawable.checked);
                        continue;
                    }
                    data.get(i).put("lv_right_icon", R.drawable.lv_right_white);
                }

                simpleAdapter.notifyDataSetChanged();
            }

            @Override
            public void updateLog(String msg) {
                mTextView.append("\r\n" + msg);
            }
        });

    }


});


  可以看到打开台灯按钮的点击事件,只是调用了BluetoothTool的发送功能向单片机蓝牙发送了一个ff消息(具体发送时将ff转化成16进制0xff,因而在单片机端我们会收到一个0xff的数据)。关闭事件同上。

@Override
public void onClick(View view) {
    int id = view.getId();

    switch (id) {
        case R.id.id_btn_open:
            if (mBluetoothTool != null) {
                mBluetoothTool.sendData("ff");
            } else
                Toast.makeText(MainAty.this, "蓝牙未连接...", Toast.LENGTH_SHORT).show();
            break;
        case R.id.id_btn_close:
            if (mBluetoothTool != null) {
                mBluetoothTool.sendData("00");
            } else
                Toast.makeText(MainAty.this, "蓝牙未连接...", Toast.LENGTH_SHORT).show();
            break;
        default:
            break;
    }
}



2.BluetoothTool


传入的蓝牙设备地址(一般是单片机端蓝牙的地址)
/**
 * 蓝牙设备地址
 */
private String mBluetoothAddress = null;


通过传入的蓝牙地址获取相应的蓝牙设备。

/**
 * 蓝牙设备
 */
private BluetoothDevice mDevice = null;

mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(mBluetoothAddress);


这里我们都是以客户端的形式连接的。(也就是单片机上的蓝牙是客户端)。

/**
 * 枚举 表示是客户端还是服务端
 */
public static enum ServiceOrClient {
    NONE, SERVICE, CLIENT
}
private ServiceOrClient mServiceOrClient = ServiceOrClient.NONE;


Handler 用来更新UI

private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_UPDATE_LISTVIEW:
                if (iUpdateUI != null)
                    iUpdateUI.updateListViewDevices();
                break;
            case MSG_UPDATE_LOG:
                if(iUpdateUI!=null)
                iUpdateUI.updateLog(msg.obj + "");
                break;
        }
    }
};


单片机的蓝牙与手机端的蓝牙通信的socket,说明一下蓝牙通信其实也是基于socket通信的。

/**
 * 蓝牙客户端socket
 */
private BluetoothSocket mClientSocket = null;


以客户端身份连接的线程,我们来看看具体实现。

/**
 * 客户端线程
 */
private ClientThread mClientThread = null;


  通过蓝牙设备获取相应的socket,之后单片机的蓝牙和手机的蓝牙通信都是通过这个socket。其中在蓝牙中,每个服务和服务属性都唯一地由"全球唯一标识符" (UUID)来校验。而且这个UUID的值必须是00001101-0000-1000-8000-00805F9B34FB,这个是android的API上面说明的,用于普通蓝牙适配器和android手机蓝牙模块连接的。获取之后通过socket的connect进行连接,连接成功之后开启读取数据的线程。

/**
 * 客户端线程
 */
private class ClientThread extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            /** 客户端通过服务端的UUID与之连接*/
            mClientSocket = mDevice.createRfcommSocketToServiceRecord(
                    UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));

            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
            msg.obj = "正在连接。。。";
            mHandler.sendMessage(msg);

            /** 连接*/
            mClientSocket.connect();


            msg = Message.obtain(null, MSG_UPDATE_LOG);
            msg.obj = "连接成功";
            mHandler.sendMessage(msg);


            msg = Message.obtain(null, MSG_UPDATE_LISTVIEW);
            mHandler.sendMessage(msg);

            /** 接收数据*/
            mReadThread = new ReadThread();
            mReadThread.start();

        } catch (IOException e) {
            e.printStackTrace();

            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
            msg.obj = "连接失败";
            mHandler.sendMessage(msg);
        }
    }
}


  可以看到线程一直在查看有没有数据,如果有的话就接受,并根据接收到的数据进行相应的显示。有一点要先说一下,就是如果手机成功发送了一个开灯命令给单片机,单片机收到之后成功控制继电器将台灯打开之后,单片机会回发一个消息0xff给手机。因此手机端只要收到0xff这个消息,就知道台灯打开成功了手机就可以显示台灯成功开启。

/**
 * 读取数据线程
 */
private class ReadThread extends Thread {
    @Override
    public void run() {
        super.run();

        byte[] buffer = new byte[1024];
        int bytes;
        InputStream in = null;

        try {
            in = mClientSocket.getInputStream();

            while (true) {
                if ((bytes = in.read(buffer)) > 0) {
                    byte[] buf_data = new byte[bytes];
                    for (int i = 0; i < bytes; i++) {
                        buf_data[i] = buffer[i];


                        int j = buffer[i];
                        j = buffer[i] & 0xff;
                        String str = Integer.toHexString(j);
                        if ("ff".equals(str)) {
                            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
                            msg.obj = "台灯打开";
                            mHandler.sendMessage(msg);
                        } else if ("0".equals(str)) {//注意不能用00,因为0x00实际的值是0

                            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
                            msg.obj = "台灯关闭";
                            mHandler.sendMessage(msg);
                        } else {
                           Message msg = Message.obtain(null, MSG_UPDATE_LOG);
                            msg.obj = "err...";
                            mHandler.sendMessage(msg);
                        }

                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();

            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
            msg.obj = "连接数据失败";
            mHandler.sendMessage(msg);
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }
}


向单片机发送数据,通过socket获取相应的输出流,然后将要发送的字符串转化成16进制发送。

/**
 * 发送数据
 *
 * @param str
 */
public void sendData(String str) {
    if (mClientSocket == null) {
        Log.d(TAG, "sendData: 没有连接。。。");

        Message msg = Message.obtain(null, MSG_UPDATE_LOG);
        msg.obj = "没有连接";
        mHandler.sendMessage(msg);
        return;
    }

    OutputStream out = null;
    try {
        out = mClientSocket.getOutputStream();
        out.write(getHexBytes(str));
    } catch (IOException e) {
        e.printStackTrace();
        Message msg = Message.obtain(null, MSG_UPDATE_LOG);
        msg.obj = "发送失败";
        mHandler.sendMessage(msg);

    }
}


连接蓝牙,就是启动客户端连接线程。

/**
 * 连接蓝牙
 */
private void connect() {
    if (mIsConnected == true) {
        Log.d(TAG, "connect: 已经连接");
        Message msg = Message.obtain(null, MSG_UPDATE_LOG);
        msg.obj = "已经连接";
        mHandler.sendMessage(msg);
        return;
    }

    /** 客户端*/
    if (mServiceOrClient == ServiceOrClient.CLIENT) {
        if (!mBluetoothAddress.equals("null")) {

            mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(mBluetoothAddress);

            mClientThread = new ClientThread();
            mClientThread.start();
            mIsConnected = true;
        } else Log.d(TAG, "connect: address is null");
    }

}



Android端项目github地址:https://github.com/973927190/TableLamp



二.单片机端:


说具体实现之前,先要说一下用到的设备。


1.51单片机开发板 附上博主买的地址

 https://item.taobao.com/item.htm?spm=a1z09.2.0.0.TjO3yS&id=10613893319&_u=t1kstub999f8 

2.杜邦线(公对母,母对母,公对公) 附上博主买的地址

https://detail.tmall.com/item.htm?id=41254478179&spm=a1z09.2.0.0.TjO3yS&_u=t1kstub97e0c&sku_properties=122216547:20213

3.继电器(1路继电器模块带光耦隔离 支持高低电平触发 5V 一路) 我的台灯是usb接口的电压挺小的,大家也用这种台灯做这个吧。附上博主买的地址

https://detail.tmall.com/item.htm?id=41231430731&spm=a1z09.2.0.0.TjO3yS&_u=t1kstub9bd31

4.蓝牙模块(HC-05 主从机一体蓝牙模块 无线蓝牙串口透传模块 无线模块)  附上博主买的地址

https://detail.tmall.com/item.htm?spm=a220m.1000858.1000725.1.couEso&id=41281471872&areaId=330100&cat_id=2&rn=c5c64203413d531f3954899ca97dfd00&user_id=2207691322&is_b=1


哈哈 先给大家看一看单片机方面的代码 大家看了之后肯定就会有动力写了!

#include <reg52.h>
unsigned char flage,temp;
sbit p33=P3^3;//单片机P3.3口

void main()
{
	TMOD=0x20;//设置定时器1为工作方式2
    // 波特率=9600时定时初值为FDH
	TH1=0xfd;//装载TH1
	TL1=0xfd;//装载TL1
	TR1=1;//启动T1(定时器1),开始计数
	REN=1;//允许串行接收
	//SM0=0 SM1=1 为工作方式2
	SM0=0;
	SM1=1;
	EA=1;//开启总中断
	ES=1;//允许串口产生中断
	
	while(1)
	{
		if(flage==1)
		{
			ES=0;//不允许串口产生中断 保证此次操作安全
		    flage=0;
			SBUF=temp;//发送数据
			while(!TI);
			TI=0;//取消此次中断申请
			ES=1;//允许串口产生中断
		}
	}
}

void interrupt4() interrupt 4//4号中断 处理函数
{
	RI=0;//取消此次中断申请
	if(SBUF==0xff)//开灯
		p33=1;//单片机P33口置为高电平
	else if(SBUF==0x00)//关闭
		p33=0;//单片机P33口置为低电平	
	temp=SBUF;
	flage=1;
}

是不是看起来感觉挺少挺简单的,没错这就是单片机方面的所有代码。个人感觉单片机方面代码其实问题不是很大的,主要是硬件方面的问题,所以代码先放一放,我们先来说说具体器件的问题。



1.51单片机

   图一是单片机开发板,其中开发板中间那个长方形就是51单片机,图二就是单个的51单片机,图三是51单片机的引脚图。引脚就是单片机裸露在外面的银色导体,引脚可以输出高电压(等价于逻辑“1”)也可以输出低电压(等价于逻辑“0”)。补充一下电平信号的概念,TTL电平信号被利用的最多是因为通常数据表示采用二进制规定,+5V等价于逻辑“1”,0V等价于逻辑“0”,这被称做TTL(晶体管-晶体管逻辑电平)信号系统,这是计算机处理器控制的设备内部各部分之间通信的标准技术。个人认为单片机最重要的一个特性就是我们可以往单片机中写入自己的程序(C++/C/汇编  这个过程也叫做烧写程序),通过自己的程序控制单片机各个引脚的输出电压,然后在通过引脚的输出电压来控制相应的外接模块。外接模块就是将单片机的引脚和模块的引脚连接起来,单片机引脚的输出电压当做模块引脚的输入电压。如果之前没有接触过单片机开发的,博主强烈建议去看看“郭天祥十天学会单片机的视频教程”。如果你去淘宝买了单片机开发板到时会有一张光盘里面有很多的资料 教学视频 开发工具 以及配套开发板的结构图,郭天祥十天学会单片机的视频教程光盘里也有的。博主我将单片机有关的资料全部打包上传了 http://pan.baidu.com/s/1hrYwv1U


           

                              图一                                                                                         图二                                                                             图三

 2.HC-05主从一体蓝牙模块 

    HC-05主从一体蓝牙模块一共有6个引脚,我们只需要关注VCC,GND,TXD,RXD 这四个引脚。VCC:电源端,接单片机的VCC(高电平)。GND:接地端,接接单片机的GND端(低电平)。TXD:发送端,一般表示为自己的发送端,正常通信必须接另一个设备的RXD(我的单片机P30口是RX端)。RXD:接收端,一般表示为自己的接收端,正常通信必须接另一个设备的TXD(我的单片机P31口是TX端)led指示蓝牙连接状态,快闪表示没有蓝牙连接,慢闪表示进入AT模式,双闪表示蓝牙已连接并打开了端口。注意! 不要将电源接到信号脚上,会直接烧坏。有可能你们的单片机RXD端,TXD端和我的不一样,这个就要去看光盘里的开发板结构图了,里面有画出来的。这里我想提醒一下大家,单片机烧写程序也是通过RXD端和TXD端。所以在烧写的时候要确保RXD端和TXD端没有外接其他模块,如果你接了蓝牙就会烧写失败。

  蓝牙模块的编程本质上就是串口编程,串口编程大家可以去看看郭天祥十天学会单片机的视频教程”里面有相应的教学。在这里我稍微解释一下波特率,波特率,可以通俗的理解为一个设备在一秒钟内发送(或接收)了多少码元的数据。为了在彼此之间通讯,蓝牙收发端必须使用相同的波特率进行操作。如果将接收波特率设置为高于发送方的波特率,则接收数据时会出现错误。   hc-05可以用指令调节波特率,我们就用默认的9600bps。。在单片机代码中,我们要通过设置单片机的计数器将将单片机的波特率也调成9600,同时打开中断开关,这部分的代码如下。


	TMOD=0x20;//设置定时器1为工作方式2
    // 波特率=9600时定时初值为FDH
	TH1=0xfd;//装载TH1
	TL1=0xfd;//装载TL1
	TR1=1;//启动T1(定时器1),开始计数
	REN=1;//允许串行接收
	//SM0=0 SM1=1 为工作方式2
	SM0=0;
	SM1=1;
	EA=1;//开启总中断
	ES=1;//允许串口产生中断


    蓝牙模块收到数据会触发4号中断,程序进入4号中断处理函数。我们只要重写中断函数如下。51单片机有两个物理上独立的接收 发送缓冲器SBUF,它们占用同一地址99H。 在中断处理函数中通SBUF存储着蓝牙模块接收到的数据。将其和我们自己定义的‘开’和‘关’进行比较,如果接收到的数据是0xff就将pP33口置为高电平(打开台灯),反之接收到的数据是0x00就将pP33口置为低电平(关闭台灯)。单片机的P33口又和继电器的控制端口连接(这个我们之后会具体分析的)。

void interrupt4() interrupt 4//4号中断 处理函数
{
	RI=0;//取消此次中断申请
	if(SBUF==0xff)//开灯
		p33=1;//单片机P33口置为高电平
	else if(SBUF==0x00)//关闭
		p33=0;//单片机P33口置为低电平	
	temp=SBUF;
	flage=1;
}


  在中断函数中,处理完所有操作之后都会将flage置为1。在main函数中有一个无限循环,其中如果flage=1的话 就通过SBUF发送数据给手机端的蓝牙。发送的temp就是收到之前接收到的数据,还记得在之前分析Android端BluetoothTool的接收函数的时候,有说到如果手机成功发送了一个开灯命令给单片机,单片机收到之后成功控制继电器将台灯打开之后,单片机会回发一个消息0xff给手机。因此手机端只要收到0xff这个消息,就知道台灯打开成功了。具体发送过程就是在下面的代码中完成的,至于代码中ES TI这些都是和串口编程有关的,个人建议去看看视频教学比较好。

while(1)
	{
		if(flage==1)
		{
			ES=0;//不允许串口产生中断 保证此次操作安全
		    flage=0;
			SBUF=temp;//发送数据
			while(!TI);
			TI=0;//取消此次中断申请
			ES=1;//允许串口产生中断
		}
	}


3.继电器(1路继电器模块带光耦隔离 支持高低电平触发 5V 一路) 


    继电器模块接口有1、DC+:接电源正极(电压按继电器要求,有5V.9V.12V和24V选择)2、DC-:接电源负极3、IN:可以高或低电平控制继电器吸合。 IN端是用来控制继电器公共端是和常闭端连接还是和常开端连接用的,如果IN端是高电平那么继电器的公共端就和常闭端连接,反之公共端和常开端连接。我是将IN端和单片机的P33口连接,通过改变单片机P33端上的电平,从而改变继电器IN端的电平,达到控制继电器开合的效果。这里非常有必要说明一点,就是继电器的IN端和单片机的哪个口连的问题。不是所有的端口都可以连得,要接有上拉电阻的端口才可以,因为如果没有接上拉电阻的端口就算在代码中将该端口置为1,实际中该端口电压达不到高电压,只有接有外接电阻端口的电压才能达到高电压。至于怎么判断单片机端口是不是有接外接电阻有两种方法,一看单片机(开发板)的结构图找到接有外接电阻的端口,二是自己一个一个试过去。如代码所示,打开台灯的时候将P33口置为1(1是高电平 0是低电平)。

   继电器输出端:1、NO:  继电器常开接口,继电器吸合前悬空,吸合后与COM短接 2、COM:继电器公用接口 3、NC:  继电器常闭接口,继电器吸合前与COM短接,吸合后悬空

	if(SBUF==0xff)//开灯
		p33=1;//单片机P33口置为高电平
	else if(SBUF==0x00)//关闭
		p33=0;//单片机P33口置为低电平


4.台灯

   台灯方面主要就是将台灯的一根导线(零线或者火线)弄断,然后两端分别继电器的NO(继电器常开接口) COM(继电器公用接口)连接就好。这里要注意,台灯要是那种USB接口的,USB接口的有降压器会将220V降下来的。千万不要用那种不是USB的,那种电压太高太危险了,而且继电器也承受不了这么大的电压,要买相应的继电器。 切记!


5.单片机代码 

#include <reg52.h>
unsigned char flage,temp;
sbit p33=P3^3;//单片机P3.3口

void main()
{
	TMOD=0x20;//设置定时器1为工作方式2
    // 波特率=9600时定时初值为FDH
	TH1=0xfd;//装载TH1
	TL1=0xfd;//装载TL1
	TR1=1;//启动T1(定时器1),开始计数
	REN=1;//允许串行接收
	//SM0=0 SM1=1 为工作方式2
	SM0=0;
	SM1=1;
	EA=1;//开启总中断
	ES=1;//允许串口产生中断
	
	while(1)
	{
		if(flage==1)
		{
			ES=0;//不允许串口产生中断 保证此次操作安全
		    flage=0;
			SBUF=temp;//发送数据
			while(!TI);
			TI=0;//取消此次中断申请
			ES=1;//允许串口产生中断
		}
	}
}

void interrupt4() interrupt 4//4号中断 处理函数
{
	RI=0;//取消此次中断申请
	if(SBUF==0xff)//开灯
		p33=1;//单片机P33口置为高电平
	else if(SBUF==0x00)//关闭
		p33=0;//单片机P33口置为低电平	
	temp=SBUF;
	flage=1;
}






到这里手机控制台灯的开关有关内容都已经介绍完毕,大家不妨自己动手做一个,挺有趣的。

Android端项目github地址:https://github.com/973927190/TableLamp


单片机端项目:http://pan.baidu.com/s/1i4P87dj

单片机有关的资料: http://pan.baidu.com/s/1hrYwv1U

如果手机控制台灯开关的做出来了,大家也可以做做手机控制台灯暗亮的,可以用电阻来做的哈,





智能台灯

阅读数 2346