51单片机通过WIFI模块ESP8266控制LED灯(大致内容,经过测试成功实现)

51单片机通过WIFI模块ESP8266控制LED灯

准备材料:stm89c516、esp8266-01、至少5根杜邦线。。、电路板。
大概思路:在这里插入图片描述
1、控制esp和服务器连接。
2、pc向向服务器发送指令。
3、服务器接收到指令后,再向esp发送。
4、esp接收到指令后,再向单片机发送。
5、单片机接收到指令后,执行 指令。

先讲第一步:控制esp和服务器连接
首先用到是esp8266-01,如图:
首先:用esp
然后是下面TTL-USB串口线,如图:
在这里插入图片描述
还需要一个串口调试助手,为了接发数据。我使用的调试助手如,下图:
在这里插入图片描述
下面是硬件连接,硬件连接并不复杂,如图:
在这里插入图片描述
之后打开串口进行连接,如图:
在这里插入图片描述
备注:由于我之前把模块的波特率修改成9600了,其实esp8266波特率默认是115200。因此如果你没有修改波特率,则需要选择115200,不然没有结果。

准备工作做好之后,开始进行指令发送:

  1. 发送:AT+URAT=9600,8,1,0,0//设置串口
  2. 发送:AT+CWMODE=1//设置STA模式
  3. 发送:AT+RST//重启
  4. 发送:AT+CWJAP=“WIFI名”,“WIFI密码”//连接WIFI
  5. 发送:AT+CIPMUX=1//启动多链接
  6. 发送:AT+CIPSERVER=1//建立服务器
  7. 发送:AT+CIPSTART=2,“TCP”,“115.29.109.104”,6520//通过协议,IP,端口连接服务器。

指令全部成功发送后,esp的基本工作就完成了

接下俩讲第二步,运行以下代码:
`#include
#include<winsock.h>
#pragma comment(lib,“ws2_32.lib”)
using namespace std;
void initialization();
int main() {
//定义长度变量
int send_len = 0;
int recv_len = 0;
//定义发送缓冲区和接受缓冲区
char send_buf[100];
char recv_buf[100];
//定义服务端套接字,接受请求套接字
SOCKET s_server;
//服务端地址客户端地址
SOCKADDR_IN server_addr;
initialization();
//填充服务端信息
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr(“115.29.109.104”);
server_addr.sin_port = htons(6520);
//创建套接字
s_server = socket(AF_INET, SOCK_STREAM, 0);
if (connect(s_server, (SOCKADDR *)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
cout << “服务器连接失败!” << endl;
WSACleanup();
}
else {
cout << “服务器连接成功!” << endl;
}

//发送,接收数据
while (1) {
	cout << "you:";
	cin >> send_buf;
	send_buf[strlen(send_buf) - 1] = '\n';
	send_buf[strlen(send_buf) - 2] = '\r';
	send_len = send(s_server, send_buf, strlen(send_buf), 0);
	if (send_len < 0) {
		cout << "发送失败!" << endl;
		break;
	}
	/*recv_len = recv(s_server, recv_buf, 100, 0);
	if (recv_len < 0) {
		cout << "接受失败!" << endl;
		break;
	}
	else {
		cout << "other:" << recv_buf << endl;
	}*/

}
//关闭套接字
closesocket(s_server);
//释放DLL资源
WSACleanup();
return 0;

}
void initialization() {
//初始化套接字库
WORD w_req = MAKEWORD(2, 2);//版本号
WSADATA wsadata;
int err;
err = WSAStartup(w_req, &wsadata);
if (err != 0) {
cout << “初始化套接字库失败!” << endl;
}
else {
cout << “初始化套接字库成功!” << endl;
}
//检测版本号
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wHighVersion) != 2) {
cout << “套接字库版本号不符!” << endl;
WSACleanup();
}
else {
cout << “套接字库版本正确!” << endl;
}
//填充服务端地址信息

}
`
成功运行,如图:
在这里插入图片描述
第三步已经在第一步里面完成了。

接下来讲第四步,如何让esp向单片机发送指令:

这里只要依照这电路图找出 RXD/TXD I/O 口就行,我这款单片机的 RXD、TXD 为 P30 和 P31 口,只要将 ESP8266 接通 3.3 V 电源,将 wifi 模块的 RX 和 TX 与单片机对应的口交叉相连就可以了,实际连线如下

-ESP8266-01--单片机-
-VCC--VCC(3.3)-
-GND--GND-
-RXD--TXD-
-TXD--RXD-

第四步完成!

开始,第五步!!(最后一步了!!!)

将以下代码烧入单片机中
#include <stdio.h>
#include <reg51.h>
#include <ctype.h>
#include <string.h>
#include <math.h>

#define uchar unsigned char
#define uint unsigned int

sbit LED1 = P2^0;
sbit LED2 = P2^1;
sbit LED3 = P2^2;
sbit LED4 = P2^3;
sbit LED5 = P2^4;
sbit LED6 = P2^5;
sbit LED7 = P2^6;
sbit LED8 = P2^7;

// 串口中断接收相关
uint scount = 0, maxLen = 25, tscount = 0;
uchar srdatas[25];
// 计时器 0, 多大代表有多少个 50ms(0 ~ 65535)
uint time0Count = 0;
// 串口接收数据已处理标志
bit sflag = 0;
// 校验连接发送标志(1-表示需要发送)
bit tsflag = 0;

void Delay2(unsigned long cnt);

void Tranfer(uchar s);
void SysInit();
void SetWifi();
void dealReceiveData();
void dealReceiveLine(uchar
line, uint length);
void dealWifiConnectInfo();
// 10 进制 => 2 进制
//uchar* decimal2binary(uint val);
// 字符串转数字
// uint parseInt(uchar* str, uint len);

void Delay2(unsigned long cnt) {
long i;
for(i=0;i<cnt*10;i++);
}

/*
uchar* decimal2binary(uint val) {
uchar chs[8];
uint i = 0, tmp = val;
for(i = 0; i < 8; i++) {
if(tmp == 0) {
chs[i] = 0;
continue;
}
chs[i] = (tmp % 2) + 48;
tmp = tmp / 2;
}

for(i = 0; i < 4; i++) {
	tmp = chs[i];
	chs[i] = chs[8-i-1];
	chs[8-i-1] = tmp;	
}
return chs;

}
*/

/*
uint parseInt(uchar* str, uint len) {
uint i = 0, resVal = 0;
for(i = 0; i < len; i++) {
resVal = resVal + ((str[i] - 0x30) * pow(10, len - i - 1));
}
return resVal;
}
*/

// 接收到字符串出现 /r/n, 视为新行标志
void dealReceiveData() {
uint t = 0;

if(sflag == 1 || scount <= 0) {
	return;
}

// 延时之后依然没有数据, 既断定为串口有数据接收到
tscount = scount;
// 使用 Delay2 有问题
// Delay2(100);
t = time0Count;

// 演示 50 ms
while(abs(time0Count - t) <= 0);

if(scount != tscount) {
   return;
}

// 数据处理期间暂停串口中断使能
ES = 0;
// 数组未溢出
if(scount < maxLen) {
  // 接收到第二个数据之后, 判断是否出现了结束符
  if(scount > 2) {
  	// 出现了换行符, 处理接收到的行的数据
  	if(srdatas[scount - 2] == '\r' && srdatas[scount - 1] == '\n') {
	   dealReceiveLine(srdatas, scount - 2);
	   scount = 0;	
	}	
  }
}

// 执行之后即为串口接收到的数据已经处理
sflag = 1;
ES = 1;

}

void dealWifiConnectInfo() {
// 开始发送尝试重连
if(tsflag == 1) {
ET0 = 0;
printf(“AT+CIPCLOSE=2\r\n”);
Delay2(5);
printf(“AT+CIPSTART=2,“TCP”,“115.29.109.104”,6520\r\n”);
Delay2(10);
tsflag = 0;
ET0 = 1;
}
}

void dealReceiveLine(uchar* line, uint length) {
// bit hasCommand = 0;
uint i = 0, t = 0;
uchar command;
uchar newLine[25];

// 去除换行符
if(length > 3) {
	for(i = 0; i < length; i++) {
		if(line[i] != '\r' && line[i] != '\n') {
		   newLine[t] = line[i];
		   t++; 
		}
		if(t >= 25) {
			length = t;
			break;
		}
	}	
}

if(length > 3) {
	// 处理开关控制指令
 	if(
		newLine[0] == '+'
		&& newLine[1] == 'I'
		&& newLine[2] == 'P'
		&& newLine[3] == 'D'	
	) {
		i = 0;
		while(i < length && newLine[i] != ':') {
			i++;
		}
		// 存在有效位置
		if(i < length) {
		   t = 0;
		   for(i = i + 1; i < length; i++) {
		   		t++;
                if(newLine[i] == '/') {
					continue;
				}
		   		command = newLine[i] - 0x30;
		   		switch(t) {
					case 1:
						LED1 = !command;
						break;
					case 2:
						LED2 = !command;
						break;
				    case 3:
						LED3 = !command;
						break;
					case 4:
						LED4 = !command;
						break;
					case 5:
						LED5 = !command;
						break;
					case 6:
						LED6 = !command;
						break;
					case 7:
						LED7 = !command;
						break;
					case 8:
						LED8 = !command;
						break;
				}
				
				if(t >= 8) {
					break;
				}	
		   }
		}	
	}

	/*
	LED6 = ~LED6;
	 // 处理定时轮询的远程连接状态响应数据
	 if(tsflag == 1) {
	   LED7 = ~LED7;
	   if(
		 	newLine[0] == 'A'
			&& newLine[1] == 'L'
			&& newLine[2] == 'R'
			&& newLine[3] == 'E'
			&& newLine[4] == 'A'
			&& newLine[5] == 'D'
			&& newLine[6] == 'Y'
		) {
		 	LED8 = 0;
		} else {
			LED8 = 1;
		}
		tsflag = 0;
	 }
	 */
 }

}

void SysInit() {
// 初始化定时器1, 配置波特率发生器
TH1 = 0xFD; //晶振11.0592mhz 波特率设为9600
TL1 = TH1;
TMOD |= 0x20; //定时器1方式2
SCON = 0x50; //串口接收使能
ES = 1; //串口中断使能
TR1 = 1; //定时器1使能
TI = 1; //发送中断标记位,必须设置

// 初始化定时器0, 做系统定时任务(11.0592MHz, 定时 50ms)
/* */
TH0 = 0x4C;
TL0 = 0x00;
TMOD |= 0x01; // 工作在方式2
TR0 = 1; // 定时器0使能
ET0 = 1;


//REN = 0; // 禁止串口接收数据
printf("begin init wifi...\r\n");
SetWifi();
printf("wifi inited...\r\n");
//REN = 1;
EA=1;

}

void SetWifi() {
Delay2(1000);
printf(“AT+CIPMUX=1\r\n”);

Delay2(1000);
printf(“AT+CIPSERVER=1\r\n”);

Delay2(1000);
printf(“AT+CIPCLOSE=2\r\n”);

Delay2(2000);
printf(“AT+CIPSTART=2,“TCP”,“115.29.109.104”,6520\r\n”);

Delay2(2000);
}

/**/
void Timer0() interrupt 1 {
uint t = 0;
ET0 = 0;
// 继续下一轮定时
TH0 = 0x4C;
TL0 = 0x00;
time0Count = (time0Count + 1) % 1200;
// 大概 30s 判断一下连接是否断开, 断开之后需要重连
if(time0Count % 600 == 0) {
tsflag = 1;
}
ET0 = 1;
}

void Usart() interrupt 4 {
if(RI == 1)
{
RI = 0;
srdatas[scount] = SBUF;
scount += 1;
if(scount >= maxLen) {
scount = 0;
}
sflag = 0;
}
}

void main() {
SysInit();
while(1) {
dealReceiveData();
dealWifiConnectInfo();
}
}

备注:void dealReceiveLine(…) { … }
处理逻辑如下
去除接收到的行的前后换行符。
判断处理后的结果是否以 +IPD 开头。
找到 : 后的 8 个字符,依次控制 LED1 ~ LED8 的开关状态,1 为开启,0 为关闭。

  • 发送1100000000之后的样子:

在这里插入图片描述

  • 8
    点赞
  • 104
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值