基于51单片机的wifi智能led灯的毕业设计
摘要
系统基于STC89C52RC单片机设计,拥有自动与手动两种模式,自动模式下可以过热释红外传感器检测是否有人,采用光敏电阻构成的电路检测环境光的强度,从而自动实现灯的自动开启和关闭;手动模式下可以使用wifi连接手机,通过手机app手动控制不同灯的开启和关闭并可控制各LED灯的光亮度,并采用可移动充电式电源供电,满足不同场景的需求。系统简单易行、控制方便,可用于传统照明的节能改造。
设计思路
本系统基于STC89C52单片机设计,可实现灯具的自动控制;同时,结合esp8266wifi模块通过安卓手机端app与wifi模块进行数据通信,实现对被控对象的无线连接手动控制。主要功能如下:
(1)自动模式: 通过光敏电阻和热释红外传感器分别自动检测光的强弱和是否有人,室内无人或者光照充足时自动灭灯,灭灯时间延时一分钟;有人到且光照不足时自动开灯;该模式即节约了人力资源又节约了大量电能。
(2)手动模式:开启手机wifi,通过手机APP手动控制灯的开启和关闭,使用手机轻松控制灯的开关,方便快捷。
图1 系统框图
硬件设计
wifi模块
wifi模块采用esp8266,对wifi模块进行配置就需要使用到AT指令集。其最基础的一些AT指令集在下面贴出,部分会在代码中使用到。
WIFIAT+CIPMUX=1AT+CIPSERVER=1,80 //修改端口号
AT+CWMODE=3 //设置模式
AT+RST //重启
AT+CWJAP="WiFixdd","xiaojieying" //搜索并连接路由器
AT+CIPMODE=1 //透传
AT+CIPMUX=0 //单路模式
AT+CIPSTART="TCP","172.29.242.2",8080 //连接手机端
AT+CIPSEND //进入透传
若想深入研究自行找资料学习AT指令集。
热释电传感器
HC-SR501 人体红外传感器模块是基于红外技术的自动控制模块,它可以检测人或某些动物发出的红外辐射并输出电信号我们使用的 。
电源模块
电源模块采用18650可充电电池,由于其供电电压为3.6V,不能很好的为电路工作,所以我们通过升压模块对其进行电压放大,以达到标准供电电压5V。并能通过变压充电模块为18650电池充电。
驱动电路
由于52单片机的IO口驱动能力较弱,无法满足大型LED灯的需要,所以我们在这里通过三极管进行电流放大,该驱动电路通过电阻对单片机IO口进行降压,使得三极管得以导通,并对单片机IO口电流进行放大,以达到驱动该大型灯泡的能力,并给每一个LED灯串联一个限流电阻,已达到保护LED灯延长使用寿命的作用。该电路共使用六个大型LED灯照明,三黄三白,不同颜色交替摆放,已保证单种颜色灯光的照明范围。
要注意的是实物硬件电路板对led灯的一个布局,以及合理跳线的一个问题。
代码实施
程序主要模块是通过单片机串口与蓝牙进行通信。由于STC89c52没有独立的波特率发生器,所以我们这里将定时计数器T1改装成波特率发生器,产生9600的标准波特率,并通过串口中断函数对读取数据进行接收,并将串口中断优先级调到最高。
下面是手机APP与单片机的简单通信协议,创建单独协议的目的是为了对以后项目扩展,技术升级留下足够的预留空间,并可以保证产品的加密安全性。
通过对程序的算法设计,该智能灯泡可达到黑夜可自动控制,有人经过则自动开起,并保持最大可调时间10分钟后自动熄灭。通过手机APP控制LED的开关以及亮度调节,若夜晚通过手机APP开起灯光,人经过后无需手机关闭即可自动关闭,以防止由于忘关造成的电力浪费。以下是主程序流程图。
main.c
#include "reg52.h"
#include"uart.h"
#include"led.h"
#include<stdio.h>
sbit MAN=P1^4;
int main()
{
unsigned char dat=0;
NewLineReceived = 0;
MAN=1;
ColorLED_Init(); //LED灯初始化
Serial_Init(); //串口初始化
ms_delay(1000);
WIFI_Init(); //WIFI模块初始化
timer0_init(); //定时计数器零初始化
color_led_pwm(0, 0);
while(1)
{
if(MAN==0)
{
color_led_pwm(255, 255);
while(MAN==0) ;
color_led_pwm(0, 0);
}
if(NewLineReceived == 1)
{
uart_send_string("Init OK!");
serial_led();//调用串口解析函数
NewLineReceived = 0;
}
}
}
led.c
#include "reg52.h"
sbit LED_W = P1^0;
sbit LED_W1=P1^1;
sbit LED_W2=P1^2;
sbit LED_Y = P1^5;
sbit LED_Y1 = P1^6;
sbit LED_Y2 = P1^7;
unsigned char whitenum=0;
unsigned char yellownum=0;
unsigned char ledWnum=0;
unsigned char ledYnum=0;
void ColorLED_Init()
{ LED_W = 1; LED_W1 = 1; LED_W2 = 1; LED_Y = 1; LED_Y1 = 1; LED_Y2 = 1;}
void color_led_pwm(unsigned char v_iwhite, unsigned char v_iyellow)//点亮相应颜色的灯
{ whitenum = v_iwhite; yellownum = v_iyellow; }
/*** Function ledRPwmWrite* @author Danny* @date 2017.08.16* @brief LED_R产生pwm* @param void* @retval void* @par History 无*/
void ledWPwmWrite()
{ if((whitenum != 0) && (whitenum!=255)) { if(ledWnum <= whitenum) { LED_W=1; LED_W1=1; LED_W2=1; } else { LED_W=0; LED_W1=0; LED_W2=0; } } else if(whitenum==0) { LED_W=0; LED_W1=0; LED_W2=0; } else if(whitenum==255) { LED_W=1; LED_W1=1; LED_W2=1; }}
/*** Function ledGPwmWrite* @author Danny* @date 2017.08.16* @brief LED_G产生pwm* @param void* @retval void* @par History 无*/
void ledYPwmWrite()
{ if((yellownum != 0)&&(yellownum!=255)) { if(ledYnum<=yellownum) { LED_Y=1; LED_Y1=1; LED_Y2=1; } else { LED_Y=0; LED_Y1=0; LED_Y2=0; } } else if(yellownum==0) { LED_Y=0; LED_Y1=0; LED_Y2=0; } else if(yellownum==255) { LED_Y=1; LED_Y1=1; LED_Y2=1; }}
void Update_ColorPWM()
{ ledWPwmWrite(); ledYPwmWrite();}
void timer0_init()
{ TMOD|=0X01; //定时器T0工作方式1,定时器T1工作方式2
TH0=0XFF; //100us定时,装入初值
TL0=0XA4; TR0=1; //启动T0工作
ET0=1; //允许T0中断
EA =1; //开总中断
PT0=0; }
void timer0() interrupt 1
{ TH0=0XFF; //50us定时,装入初值
TL0=0XD2; //控制pwmled
ledWnum++; ledYnum++; Update_ColorPWM();
}
uart.c
#include "reg52.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include"led.h"
bit NewLineReceived = 0; //串口接收完成标志位bit StartBit = 0; //协议开始标志int g_num=0; //定义变量int g_packnum=0;char InputString[50] = {0}; //用来储存接收到的内容 /*** Function StringFind* @author Danny* @date 2017.08.16 * @brief 字符串查找* @param[in] pSrc:源字符串; pDst:查找的字符串; v_iStartPos:源字符串起始位置* @param[out] void* @retval void* @par History 无*/int StringFind(const char *pSrc, const char *pDst, int v_iStartPos) { int i, j; for (i = v_iStartPos; pSrc[i]!='\0'; i++) //判断是否到了源字符串的结束符 { if(pSrc[i]!=pDst[0]) //与所要查找的字符串的第一个字节作比较 continue; j = 0; while(pDst[j] !='\0' && pSrc[i+j]!='\0') //判断是否到了所要查找字符串以及源字符串的结束符 { j++; if(pDst[j]!=pSrc[i+j]) break; } if(pDst[j]=='\0') //判断是否到了所要查找字符串的结束符 return i; } return -1; } /*** Function uart_send_byte* @author Danny* @date 2017.08.16* @brief 串口发送一个字符* @param[in] data:字符* @param[out] void* @retval void* @par History 无*/void uart_send_byte(unsigned char dat){ SBUF = dat; //把数据放到SBUF中 while(TI == 0); //未发送完毕就等待 TI=0; //发送完毕后,要把TI重置0} /*** Function uart_send_string* @author Danny* @date 2017.08.16* @brief 串口发送一个字符串* @param[in] void* @param[out] void* @retval void* @par History 无*/void uart_send_string(unsigned char *str){ while(*str != '\0') //判断指针str是否指向字符串的末尾 { uart_send_byte(*str); //往串口上发送字符串 str++; //指针自增,按照一个字节一个字节发送字符串 }} /*** Function Serial_Init* @author Danny* @date 2017.08.16* @brief 串口初始化函数* @param void* @retval void* @par History 无*/void Serial_Init(){ SCON=0x50; //[bit6:5]SM1 SM2 = 1 0;[bit4]REN=1 /* AUXR=0x11; //[bit4]BRTR=1,允许独立波特率发生器运行;[bit0]SIBRS=1, //独立波特率作为串口1的波特率发生器,此时定时器1释放 BRT=0XFD; //独特波特率发生器定时器(产生波特率9600) */ TMOD|=0X20; PCON=0; TH1=TL1=0XFD; TR1=1; ES=1; //开串口中断 EA=1; //开总中断 PS=1;} /*** Function serial_IRQHandler* @author Danny* @date 2017.08.16* @brief 串口中断处理接收串口数据函数* @param void* @retval void* @par History 无*/void serial_IRQHandler(void) interrupt 4 using 1 //串行口中断,第一组寄存器{ unsigned char date = 0; if(RI) { RI=0; //清除接收中断标志位 date=SBUF; //串行口接收到的数据 if(date == '$') { StartBit = 1; //协议开始 g_num = 0; } if(StartBit == 1) { InputString[g_num]=date; //将接收到的数据存储到定义的数组中 } if(StartBit == 1 && date == '#') { NewLineReceived = 1; //串口接收完成标志 StartBit = 0; //协议关闭 g_packnum = g_num; } g_num++; //g_num自增 if(g_num >= 80) { g_num=0; //将g_num清零 StartBit=0; NewLineReceived=0; //串口接收完成标志 } }}/******************************************************************函 数: void ms_delay(int t)功 能: 毫秒级延时参 数: 无返回值: 无*******************************************************************/void ms_delay(int t) { int i,j; for(i=t;i>0;i--) for(j=110;j>0;j--); }/******************************************************************函 数: void WIFI_Init(void)功 能: wifi初始化(名字:esp8266;密码:1234567890)参 数: 无返回值: 无*******************************************************************/ void WIFI_Init(void) { ES = 0; TI = 1; printf("AT+RST\r\n"); ms_delay(1000) ; printf("AT+CWMODE=3\r\n"); ms_delay(1000) ; printf("AT+CIPMUX=1\r\n"); ms_delay(1000) ; printf("AT+CIPSERVER=1,8080\r\n"); ms_delay(1000) ;printf("AT+CIOBAUD=9600\r\n"); // 设置与单片机一致的波特率 ms_delay(1000) ; while(!TI); TI = 0; ES = 1;} /*void WIFI_Init(void) { ES = 0; TI = 1; uart_send_string("AT+RST\r\n"); ms_delay(1000) ; uart_send_string("AT+CWMODE=3\r\n"); ms_delay(1000) ; uart_send_string("AT+CIPMUX=1\r\n"); ms_delay(1000) ; uart_send_string("AT+CIPSERVER=1,8080\r\n"); ms_delay(1000) ;uart_send_string("AT+CIOBAUD=9600\r\n"); // 设置与单片机一致的波特率 ms_delay(1000) ; while(!TI); TI = 0; ES = 1;} */void serial_led(){ //解析蓝牙APP发来的灯控信息 //如:$JC,CLW255,CLY000# 亮白灯 if (StringFind((const char *)InputString, (const char *)"CLW", 0) > 0) //判断是否查找到了字符串"CLW" { int m_kp, i, ii, white, yellow; //定义变量 char m_skp[5] = {0}; //寻找以CLW开头,,结束中间的字符 //定义数组存放数据 i = StringFind((const char *)InputString, (const char *)"CLW", 0); //查找到字符串"CLW"的位置赋值给i ii = StringFind((const char *)InputString, (const char *)",", i); //查找到字符串","的位置赋值给ii if (ii > i) //判断ii与i的关系大小 { memcpy(m_skp, InputString + i + 3, ii - i -3); //从InputString + i + 3所指的内存地址的起始位置开始拷贝(ii-i-3)个字节到m_skp所指的内存地址的起始位置中 m_kp = atoi(m_skp); //将找到的字符串m_skp转换成整形数赋值给m_kp white = m_kp; } //寻找以CLY开头,#结束中间的字符 i = StringFind((const char *)InputString, (const char *)"CLY", 0); //查找到字符串"CLY"的位置赋值给i ii = StringFind((const char *)InputString, (const char *)"#", i); //查找到字符串","的位置赋值给ii if (ii > i) //判断ii与i的关系大小 { memset(m_skp, 0x00, sizeof(m_skp)); //清空m_skp中的数据 memcpy(m_skp, InputString + i + 3, ii - i -3); //从InputString + i + 3所指的内存地址的起始位置开始拷贝(ii-i-3)个字节到m_skp所指的内存地址的起始位置中 m_kp = atoi(m_skp); //将找到的字符串m_skp转换成整形数赋值给m_kp yellow = m_kp; //sprintf(ReturnTemp, "%d", green); //uart_send_string(ReturnTemp); color_led_pwm(white, yellow); //点亮相应颜色的灯 NewLineReceived = 0; memset(InputString, 0x00, sizeof(InputString)); //清空串口数据 return; } } if (StringFind((const char *)InputString, (const char *)"JC", 0) == -1 ) //判断是否查找到了字符串"4WD" { //点灯判断 if (InputString[1] == 'W') //白灯 { if(InputString[2]=='1') color_led_pwm(255, 0); if(InputString[2]=='0') color_led_pwm(0, 0); } else if (InputString[1] == 'Y') //黄灯 { if(InputString[2]=='1') color_led_pwm(0, 255); if(InputString[2]=='0') color_led_pwm(0, 0); } else if (InputString[1] == 'O') //全部灯 { if(InputString[2]=='1') color_led_pwm(255,255); if(InputString[2]=='0') color_led_pwm(0, 0); } }
}
由于格式问题,代码格式是乱的,可自行整理,并添加.h文件,或通过下方链接下载。
手机APP程序
可自行制作或下载第三方软件WiFi调试助手。
凭借其开放性的巨大优势,安卓平台在设备开发应用中广受欢迎。安卓平台允许开发者根据自己的喜好和应用需求,设计出具有不同特色的实用软件。同时,安卓平台还能够适配多种硬件开发平台,对于硬件开发门槛要求低,极大地方便了用户对其进行相关的开发研究。此外,凭借其巨大的优势,安卓平台在当前开发平台领域中呈现逐年上升的趋势。因此在本设计中采用安卓平台进行本项目的设计开发。