51单片机通过WIFI模块ESP8266控制LED灯
准备材料:stm89c516、esp8266-01、至少5根杜邦线。。、电路板。
大概思路:
1、控制esp和服务器连接。
2、pc向向服务器发送指令。
3、服务器接收到指令后,再向esp发送。
4、esp接收到指令后,再向单片机发送。
5、单片机接收到指令后,执行 指令。
先讲第一步:控制esp和服务器连接
首先用到是esp8266-01,如图:
然后是下面TTL-USB串口线,如图:
还需要一个串口调试助手,为了接发数据。我使用的调试助手如,下图:
下面是硬件连接,硬件连接并不复杂,如图:
之后打开串口进行连接,如图:
备注:由于我之前把模块的波特率修改成9600了,其实esp8266波特率默认是115200。因此如果你没有修改波特率,则需要选择115200,不然没有结果。
准备工作做好之后,开始进行指令发送:
发送:AT+URAT=9600,8,1,0,0//设置串口发送:AT+CWMODE=1//设置STA模式发送:AT+RST//重启发送:AT+CWJAP=“WIFI名”,“WIFI密码”//连接WIFI发送:AT+CIPMUX=1//启动多链接发送:AT+CIPSERVER=1//建立服务器发送: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 与单片机对应的口交叉相连就可以了,实际连线如下
第四步完成!
开始,第五步!!(最后一步了!!!)
将以下代码烧入单片机中
#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(uchars);
void SysInit();
void SetWifi();
void dealReceiveData();
void dealReceiveLine(ucharline, 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 mswhile(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; // 工作在方式2TR0 = 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之后的样子: