vultr怎么建设影视网站,建立个人网站需要什么,云南省网站备案,网络运维app系统经过以下学习#xff0c;我们掌握#xff1a;
AT指令与wifi模块的测试方法#xff1a;通过CH340直接测试#xff0c;研究各种AT指令下wifi模块的响应信息形式。编程#xff0c;使用串口中断接收wifi模块对AT指令的响应信息以及透传数据#xff0c;通过判断提高指令执行的…经过以下学习我们掌握
AT指令与wifi模块的测试方法通过CH340直接测试研究各种AT指令下wifi模块的响应信息形式。编程使用串口中断接收wifi模块对AT指令的响应信息以及透传数据通过判断提高指令执行的准确度。wifi模块的调试方法白盒测试。串口接收缓冲区字符串的获取方法有两种①直接存在字符数组中用strstr()函数查找子串有效指令②定义临时字符保证子串有效指令从字符数组第0位开始存储。第二种更好因为你要考虑有效指令的存放可能因为字符数组的长度限制而只被部分捕获。了解wifi模块分别以客户端client以及服务器server模式进行工作的特点 服务器和客户端联入同一个局域网因此都知道互相的IP地址也是数据交互的前提以客户端模式工作就是多对1的关系8266和PC都是多路由器是1以服务器模式工作就是1对多的关系8266是1其余是多。总之服务器就是1客户端就是多。服务器有端口号服务器与每个客户端进行数据交互有通道号。服务器与客户端建立连接时的连接请求一般都是由客户端发起的通过服务器端口向服务器IP地址发送请求然后服务器这边就有个响应。服务器与客户端在连接期间都是保持一个握手状态。服务器与客户端断开连接的请求可以由服务器发起也可以由客户端发起。
1.ESP8266wifi模块
1、ESP8266介绍可以在乐鑫科技官网查询。 ESP8266模块是面向物联网应用的高性价比、高度集成的 Wi-Fi MCU也就是说它就是一个单片机。集成了 32 位 Tensilica 处理器、标准数字外设接口、天线开关、射频 balun、功率放大器、低噪放大器、过滤器和电源管理模块等仅需很少的外围电路可将所占 PCB 空间降低。ESP8266EX 内置超低功耗 Tensilica L106 32 位 RISC 处理器CPU 时钟速度最高可达 160 MHz支持实时操作系统 (RTOS) 和 Wi-Fi 协议栈可将高达 80% 的处理能力留给应用编程和开发。可以将wifi模块设计到51或32的PCB板上这样就制作成了一个可以上网的开发板。
2、AT指令蓝牙ESP-01sZigbee, NB-Iot等通信模块都是基于AT指令的设计。所有的指令没必要去记。
终端设备比如PC、MCU通过串口向终端适配器比如说蓝牙、wifi模块发送AT指令AT指令集是从终端设备Terminal EquipmentTE)或数据终端设备Data Terminal EquipmentDTE)向终端适配器(Terminal AdapterTA)或数据电路终端设备(Data Circuit Terminal EquipmentDCE)发送的。 AT指令的功能就是驱动终端适配器干活比如联网、数据交互等。
3、AT指令和普通数据的区别
AT指令对所传输的数据包大小有定义即对于AT指令的发送除AT两个字符外最多可以接收1056个字符的长度包括最后的空字符。每个AT命令行中只能包含一条AT指令对于由终端设备主动向PC端报告的URC指示或者response响应也要求一行最多有一个不允许上报的一行中有多条指示或者响应。AT指令是控制类数据都要以回车作为结尾响应或上报以回车换行为结尾。AT指令发送时一定需要在串口助手中勾选“发送新行”没有此选项的话需要手动在指令末位键盘敲一个回车键和指令一起发送给wifi模块。辨析比如说在AT指令模式下我第一次发送指令时忘记发送新行了下一次发送带新行的指令后wifi模块会响应“ERROR”因为wifi模块在读取AT指令时是以\r\n作为结尾的第一次没有新行的指令相当于还在缓冲区当中也就是没有结束符第二次带新行的指令发送过来才读到最后的\r\n相当于发送了两遍指令所以wifi模块不认识这个指令会响应“EEROR”。
4、ESP-01S初始配置和验证ESP-01s出厂波特率正常是115200也有可能是9600需要连在CH340驱动上再与电脑进行连接进行验证。此时PC就是终端设备ESP-01S就是终端适配器。
接线交叉接线经过测试ESP-01S的VCC接在CH340驱动的5V针脚上串口才能正常工作。另外模块会存在发热现象。打开ESP8266调试助手使用安信可串口助手实际上ESP8266的技术支持很多都是安信可做的。确定波特率经过验证是115200的波特率因为以9600的波特率发送AT指令后模块没有响应。发送ATRST重启wifi模块。购买来的模块的响应信息有两种情况如下但是以看见ready为准多次发送可能就看不到ready了。发送AT测试模块功能是否正常正常的话会响应OK。发送ATUART9600,8,1,0,0配置成9600的波特率同时说明数据位是8位、停止位是1位、校验位是0位。成功wifi模块会响应“OK”。点击关闭串口切换成9600波特率目的是以后用单片机来玩ESP-01S时波特率是对的上的实际上51单片机也能配置成115200但前面我们一直在讲9600。
2.AT指令入网设置
0、互联网的4个协议层从上到下依次是应用层、传输层、网络层、链路层。
网络层应用层1发送和接受数据包时要注明发送者和接收者的IP地址2IP协议版本IPV4四个8位二进制数(十进制下就是0~255)例如 192.168.0.1233连上路由器的无线终端设备会被分配独立但每次连接不固定的IP地址4查找我的电脑在WLAN中的IP地址方法ipconfig5默认网关gateway 连上“中国移动…服务器”的路由器可以使它的局域网连接互联网路由器Router的IP地址是网关它由上述服务器分配一个局域网下只有一个网关6子网掩码subnet255.255.255.0 子网是巨型网络的分支用于区分IPV4中的子网地址和设备序号二者组成了设备的IP7实例用连上WiFi的电脑在互联网上打开某网站的过程已知网站IP地址 数据包传输路线电脑浏览器→路由器→中国移动服务器→互联网→某网站1HTTPHyper Text Transfer Protocol超文本传输协议2HTTP请求和响应演示用连上WiFi的电脑在互联网上打开某网站的过程 电脑浏览器←→互联网←→网站服务器HTTP请求数据包→、HTTP响应数据包←3HTTP请求数据包 ①组成请求行 请求头 ②请求行请求方法 网站首页 协议版本例如GET/HTTP/1.1 ③请求头 HOST网址 ………………4网站IP地址的确定 请求数据包中的网址先被送至DNS服务器进行域名解析之后会返回网站服务器的IP地址5HTTP响应数据包 ①组成响应状态行 响应头 ②响应状态行协议版本 状态码 状态码含义例如HTTP/1.1 200 OK ③响应头 时间信息 Content-Type响应体内容类型字符集 类型 例如Content-Type: text/html; charset UTF-86注请求行、请求头以及响应行、响应头之间用 \r\n 区分开(表示隔一行) \r\n\r\n 则表示空行头与体之间用空行分隔。传输层1TCPTransmission Control Protocol传输控制协议 应用电子邮件、文件2UDPUser Datagram Protocol用户数据报协议 应用语音、视频、网游
1、设置wifi模块的工作模式这属于网络的链路层共有三种模式可选。指令是ATCWMODE1/2/3 1是设备模式或称无线设备模式Wirless Station这种模式下就像手机联wifi进行上网一样让ESP8266联入家里的路由器可与连入同一个局域网的其他设备通讯。2是路由模式或称接入点模式Acess Point这种模式下就像手机开热点一样将ESP8266当做一个小路由器。3是双模式设置成功wifi模块会响应“OK”设置失败wifi模块会响应“ERROR”失败的原因可能是拼写出错。没有响应的话说明你没有发送新行。设置双模式成功后能在电脑上看到这个wifi模块的wifi名字是ESP_28DCAB
2、以设备模式联入路由器告知wifi名字和密码。
在家里开路由器我的指令是ATCWJAPCMCC-XyVF,XyVFVsrz在学校开手机热点我的指令是ATCWJAPHUAWEI P20,abcdefgh
连接成功wifi模块会响应“WIFI CONNECTED” 、 “WIFI GOT IP” 、“OK”有时候可能不会显示“OK”不用担心实际上是有的连接失败有两种情况①wifi模块会响应“ERROR”。失败的原因可能是双引号和逗号没写成半角英文模式或者指令后面多了个空格②wifi模块会响应“CWJAP:3”、“FAIL”原因是wifi名字拼写错误导致这个wifi检索不到或者wifi密码拼写错误。没有响应的话说明你没有发送新行。wifi模块一上电就会去自动匹配上次连接的路由器一旦匹配上会自动连接wifi并返回“WIFI CONNECTED”、“WIFI GOT IP”没有“OK”没有匹配上的话会显示“WIFI DISCONNECT”并且wifi模块上的led指示灯会闪烁只有连上了才会熄灭。再次用上述AT指令连接wifi时wifi模块先会响应“WIFI DISCONNECTED”然后再进行连接响应“WIFI CONNECTED”、“GOT IP”、“OK”有时候可能不会显示“OK”不用担心实际上是有的我发现进入透传模式再返回AT指令模式后再次连网第一次wifi模块会响应“CLOSED”、“OK”之后再连网wifi模块会响应“OK”。 3、查询ESP-01S的IP地址指令是ATCIFSR
成功后wifi模块会响应多行信息包括路由模式的网关、路由模式的mac地址、设备模式的IP地址、设备模式的mac地址最后响应“OK”。设备模式的IP地址图中在连入家中wifi的前提下我的ESP-01S的IP地址是192.168.1.8路由模式的网关APIP后面的网关是当ESP-01S在路由模式下的网关当前的值是192.168.4.1网关的最后一位一般都是1路由模式的mac地址APMAC后面的12个6组一组2个16进制数是ESP-01S在路由模式下的mac地址物理地址相当于人的身份证每台可以联网的设备都有mac地址它是出厂就烧录好的IP地址不是永久的但mac地址是固定的。关于mac地址的具体解释参阅此链接。设备模式的mac地址STAMAC后面的也是mac地址我们可以发现只有连入wifi后我们才能看到这个设备的mac地址。并且一台设备可能有多个MAC地址比如说这个ESP8266它的MAC地址就有两个。注意家中路由器的网关不怎么变化如果你是用手机当做热点的话今天和明天的手机网关可能会变化所以用的时候需要实时去查。 3.作为客户端连接TCP服务器
1、数据传输路线我们接下来在PC上用网络调试助手构建一个基于TCP协议的服务器。接下来也是发送AT指令让ESP8266当做客户端工作。这个时候ESP8266和外部的通讯方式分为两类。 走串口wifi模块和PC走串口协议PC通过USB转TTL的CH340驱动将指令传送给wifi模块然后wifi模块响应一些配置信息给PC。走wifiwifi模块和PC也可以走网络传输层中的TCP协议这时候PC和wifi模块是连接在同一个局域网下的wifi模块作为客户端PC作为服务器。数据从wifi模块传递到路由器再由路由器中转将这个信息传递给PC上的TCP服务器数据也可以从TCP服务器经过路由器中转传递到wifi模块。
2、网络调试助手设置像这个服务器我们以后也能自己写基于Linux的或者基于Windows的通过Scoket编程用java或者C语言编程。或者说用手机上的网络助手app也是可以的。
协议类型选择TCP服务器本地主机IP用自己电脑的IP在家里连接路由器查到是192.168.1.7本机端口号使用8880尽量不要用8080。 3、wifi模块连接TCP服务器指令是ATCIPSTARTTCP,192.168.1.7,8880 这里的IPV4地址是PC的IP地址在PC的命令提示符中通过config指令查询
连接成功wifi模块会响应“CONNECT”、“OK”。另外还能在网络调试助手中的连接对象中看见wifi模块的IP地址。连接失败wifi模块会响应“ERROR”、“CLOSED”。失败的原因可能是没有让本机和ESP8266连在同一个局域网下或者8266没有提前连上局域网或者电脑需要关闭防火墙百度看看或者网络调试助手出问题了没有成功建立TCP服务器换一个。成功连接后如果再次发送上述AT指令wifi模块会响应“ALREADY CONNECTED”、“ERROR”。成功连接后如果在网络调试助手上手动将TCP服务器断开那么wifi模块会响应“CLOSED”这时候如果想再次连接需要手动重新建立TCP服务器并再往wifi模块发送连接该服务器的AT指令。 4、向服务器发送固定字节数据这种模式比较蠢每次发数据都要先设置数据的长度。
不要勾选网络调试助手中接收区设置中的16进制显示否则发送来的数据是16进制的。设置要发送数据的字节长度进入数据待发状态指令是ATCIPSENDn n表示数据的字节数设置成功wifi模块会响应“OK”同时在安可信串口调试助手中能看见这个符号代表等待数据发送。如果失败且wifi模块响应“IPMODE1”、“ERROR”那么其原因是你之前配置过透传模式见下面第3.5小节。发送的数据尽量不要有新行也就是我们不发送换行和回车符号\r\n因为它们占2个字节。发送成功后wifi模块会从透传模式自动回到AT指令模式。如果发送的字节数超出了n字节数wifi模块先会响应“busy s...”再响应“Recv n bytes”、“SEND OK”同时只会截取前面的字节发送给TCP服务器。如果你发送的数据长度不足n字节wifi模块不会有任何响应同时网络调试助手上看不到任何发送来的数据这个数据就好像一直存在“缓冲区”中只有你达到或者超过了设定的n个字节数才会显示。 5、透传模式下数据交互我们不希望每次发数据之前都设置数据长度同时我们也不希望受到是否发送新行的限制。在透传模式下随便你怎么发随便你怎么收。
设置透传模式指令是ATCIPMODE1 。 设置成功wifi模块会响应“OK”。设置失败wifi模块会响应“ERROR”。进入数据待发状态指令是ATCIPSEND 。 设置成功wifi模块会响应“OK”。设置失败wifi模块会响应“ERROR”。在透传模式下如果还继续让wifi模块给TCP服务器发送带有新行的AT指令wifi模块自身不会有任何响应这些数据会出现在网络调试助手上只不过成为带新行的普通数据。 退出透传模式回到AT指令模式wifi模块发送数据时发送不加新行发送一次没反应就发送两次。
4.单片机帮你做这一切实现wifi透传控制LED重在调试
1、单片机串口需要做哪些事情终端设备从PC变成单片机MCU让单片机通过串口给模块发送一系列AT指令指挥wifi模块以客户端模式工作。
重启wifi模块配置wifi模块的工作模式如果之前设置过的话这一步wifi模块会自动完成连接上局域网络之前设置过网络连接的话这一步wifi模块会自动完成连接上TCP服务器 设置透传模式进入数据待发状态正式进入透传模式发送数据本demo不演示发送透传指令也就是不向服务器发送任何请求只用来接收服务器数据关闭透传模式本demo不退出透传模式
注波特率是提前用电脑通过AT指令给wifi模块配置好的用9600。
2、白盒测试【项目工程文件夹】
白盒测试的原因在我们的串口中断程序中有一个从缓冲寄存器SBUF中读取字符到字符数组的这么一个过程所以wifi模块响应回来的字符串被单片机截胡了这导致我们没法在串口助手上看见它们这也称为黑盒测试。在AT指令模式下单片机通过串口给wifi模块发送指令后wifi模块会响应信息在透传模式下wifi模块会接收到由TCP服务器透传来的数据然后wifi模块会将数据响应给单片机。所以需要使用白盒测试来提前得知wifi模块的响应信息。白盒测试的接线方法不将wifi模块的TX接到单片机的RX而将其接到电脑的RX那么电脑就能通过安信可串口调试助手来观察“51给模块发送的指令之后模块到底有没有去执行这些指令”这有点像让ESP8266脚踏两只船。测试原理将由wifi模块发送的所有数据AT指令模式下的响应信息 透传模式下接收到的信息在串口助手上显示出来。在第2节习题4PC发送字符串指令给单片机的代码基础上我们让单片机每隔5s给wifi模块发送上述AT指令。当串口助手上对每条指令都响应“OK” 或者 PC上的网络调试助手上能收到数据 或者 串口能查看到网络调试助手发送来的数据 时都能说明单片机已经成功驱动wifi模块进入透传模式代码心得 用字符数粗保存AT指令这些字符串时需要注意字符串当中有双引号时则需要用转义字符保留原来的含义还需要注意AT指令需要新行也就是字符串末尾加上\r\n对于比较长AT指令的字符串它们太占空间程序会编译失败所以需要在定义的字符数组前面加上“code”这是个宏定义目的是将程序存放在比较占空间的字符串的存储位置关键字code放在以后介绍。白盒测试前需要验证只让51单片机与PC进行串口通讯先不着急把上图连线接好在串口助手中验证程序中写的AT指令是OK的也就是说检查我们写的字符串中逗号、双引号是否有错是否漏写\r\n。测试代码 #include reg52.h
#include intrins.h
#include string.h#define len 12
sfr AUXR 0x8E;
sbit ledD5 P3^7;
char cmd[len];
char esp01s_modeSetting[] ATCWMODE3\r\n; //配置wifi模块的工作模式
code char esp01s_connectLAN[] ATCWJAP\CMCC-XyVF\,\XyVFVsrz\\r\n; //连接上局域网络
code char esp01s_connectTCPServer[] ATCIPSTART\TCP\,\192.168.1.7\,8880\r\n; //连接上TCP服务器
// code char esp01s_connectLAN[] ATCWJAP\HUAWEI P20\,\abcdefgh\\r\n; //连接上局域网络
// code char esp01s_connectTCPServer[] ATCIPSTART\TCP\,\192.168.199.201\,8880\r\n;//连接上TCP服务器
char esp01s_serialNet_mode[] ATCIPMODE1\r\n; //设置透传模式
char esp01s_dataSend_waiting[] ATCIPSEND\r\n; //进入数据待发状态正式进入透传模式/* API1. 测试用于每隔5秒给串口缓冲寄存器发送代表AT指令的字符串 */
void Delay5000ms();
/* API2. 初始化串口 */
void UartInit(void);
/* API3. 通过串口给PC发送一个字符 */
void sendByte(char data_msg);
/* API4. 通过串口给PC发送一个字符串 */
void sendString(char *str);void main(void)
{UartInit();ledD5 1;while(1){Delay5000ms();sendString(esp01s_modeSetting);Delay5000ms();sendString(esp01s_connectLAN);Delay5000ms();sendString(esp01s_connectTCPServer);Delay5000ms();sendString(esp01s_serialNet_mode);Delay5000ms();sendString(esp01s_dataSend_waiting);}
}void Uart_Routine() interrupt 4
{static int i 0; //静态全局区的变量数组下标/* 中断处理程序中对于接收中断的响应 */if(RI 1){ RI 0;cmd[i] SBUF;i;if(i len){i 0;}if(strstr(cmd,en)!NULL){ledD5 0;i 0;memset(cmd,\0,len);}else if(strstr(cmd,se)!NULL){ledD5 1;i 0;memset(cmd,\0,len);}}/* 中断处理程序中对于发送中断的响应 */if(TI 1){// 暂时不做任何事情}
}void Delay5000ms() //11.0592MHz
{unsigned char i, j, k;_nop_();i 36;j 5;k 211;do{do{while (--k);} while (--j);} while (--i);
}void UartInit(void) //9600bps11.0592MHz
{AUXR 0x01;SCON 0x50; //8位UART允许串口接收TMOD 0xDF;TMOD | 0x20; //定时器8位重载工作模式TH1 0xFD;TL1 0xFD; //9600波特率初值TR1 1;EA 1;ES 1; //开启串口中断
}void sendByte(char data_msg)
{SBUF data_msg;// Delay10ms();while(TI 0);TI 0;
}void sendString(char *str)
{char *p str;while(*p ! \0){sendByte(*p);p;}
} 测试内容 观察串口调试助手上wifi模块对AT指令的反应结果以及从网络调试助手上透传来的数据拔掉wifi模块插在CH340模块RX上的TX引线将这个TX引脚插到51单片机上不重启51单片机试一下能否通过wifi透传点亮LED。 我测试了一下是可以的。这里留了个伏笔为什么说不要重启51单片机呢因为刚才的操作已经保证我们的wifi模块进入透传模式了你把引脚换一下就能成功。你重新上电之后网络调试助手有时候能看见透传数据但更多时候看不到任何透传数据也就是连接TCP服务器失败了你没法通过wifi透传对LED进行测试。 3、连接服务器失败的原因关于指令响应时间的讨论
问题剖析在上述白盒测试中我们重复给单片机上电wifi模块大概率会出现连接服务器失败的情况表现为wifi模块能够联网但是网络调试助手上没有数据从而后面的AT指令也自然变成了无效操作。猜测wifi模块以设备模式联入路由器的过程可能有点久因为会有一个自动匹配联网—断网—再联网的过程最终造成了还没有联上网之前单片机就又发送下一条AT指令导致联入TCP服务器的指令失效。测试我把wifi模块回到本节1.4的接线方法 经过串口调试助手测试在AT指令还在执行期间如果继续向wifi模块发送数据不论是普通数据还是AT指令wifi模块都会响应busy p...也就是说这些数据被吞掉了、无视掉了最后wifi模块没有连上TCP服务器。 总结只留5s时间给wifi模块联网有点稍短导致连接TCP服务器的AT指令发送后被丢失了同时每次重新给51单片机上电后连接wifi的时间是不一样不能简单用5s时间笼统概括。另外上述白盒测试代码有点残疾一上电之后只能停留在网络调试助手页面干巴巴地等没有指示灯告诉我成没成功到底连不连得上心里也没底很被动。
4、单片机处理wifi模块响应信息
目的针对上述连接TCP服务器失败的问题我们需要考虑给5s时间联网会不会太短考虑给5s时间联入服务器、设置工作模式、进入透传模式会不会太长。等于说我们需要优化AT指令执行的效率和准确度。总体方法 ①跟上节课串口中断点亮LED一样wifi模块对AT指令的响应信息也是在串口中断程序中完成读取的此外wifi模块对于从TCP服务器透传来的数据也是在串口中断程序中完成捕获的这两路数据共用一个接收数据缓冲寄存器SBUF。因此我们让单片机针对上述各类信息进行关键字眼的检索一旦检索到关键字眼说明单片机发送或者接收到了一条有效指令或是失败指令。②需要定义wifi模块响应AT指令成功的标志位这些标志位是全局变量在串口中断程序中读取到了关键字眼就对这些全局变量进行修改。标志位最终能帮助单片机判断是否发送下一条AT指令方法是在main函数中用while空循环体进行等待直到标志位改变为1才继续往下执行代码发送下一条AT指令。③肯定存在联网失败的情况在入网指令书写正确的情况下这是小概率事件。如果联网失败我们总不能让程序一直等待吧答在串口中断程序中一旦检测到联网失败的响应信息就发送一条联网的AT指令或者重启wifi模块的AT指令注可以发送重启wifi模块的AT指令的原因是wifi模块重新上电后会自动匹配上次的wifiwifi模块又会自动响应联网的信息。确定关键字眼与标志位在串口中断程序中不方便随手处理的有效指令需要标志位方便随手处理的有效指令就不需要标志位。当我们读到能标志响应成功的信息时“WIFI GOT IP”、“OK”我们就令对应的响应成功标志位为1当我们读到联网失败的响应信息时“FAIL”我们就随手重新发送一条联网的AT指令。 AT指令响应成功的关键字眼通过CH340直接测试观察各种AT指令下wifi模块的响应信息形式之前已经测试过了。针对《4.1小节单片机需要做哪些事情》中的那5个AT指令确定了以下关键字眼和标志位。 配置wifi模块的工作模式连接上局域网络连接上TCP服务器设置透传模式进入数据待发状态成功“OK”成功“WIFI GOT IP” “OK” 注一上电自动匹配上wifi时不会响应“OK” 失败“FAIL”成功“OK”成功“OK”成功“OK”成功标志位 AT_OK_Flag成功标志位AT_ConnectLAN_Flag成功标志位AT_OK_Flag成功标志位AT_OK_Flag成功标志位AT_OK_Flag透传有效指令的关键字眼我用首字母L代表LED我观察到在所有的AT指令的响应信息中字符L出现的次数比较少因此本demo中我们规定指令L-1亮灯指令L-0灭灯。即关键字眼是 灯控指令亮灯“L-1”灭灯“L-0” 临时字符变量的引入对关键字眼读取的前提是让数据缓冲寄存器SBUF读取到的字符串存放在我们定义的字符数组中我们不希望用上节课那样查找子串的方式来捕捉这些关键字眼因为有效指令的存放可能因为字符数组的长度限制而只被部分捕获。但是存储的顺序不一定从第0位开始存放以关键字眼“WIFI GOT IP”为例如下图怎么办呢 答方法是定义一个临时字符变量temp。用于检测是否读到字符W当检测到字符W后就让字符串从头开始存放这样就能保证有效指令字符串全部保存在字符数组中同时方便了我们编程。 通过硬件来窥探wifi模块配置情况 让wifi模块在成功联入局域网后D5亮main函数中对标志位 AT_ConnectLAN_Flag 判断让wifi模块成功联入服务器后D6亮main函数中对标志位 AT_OK_Flag 判断如果入网失败我们闪烁D5串口中断程序捕获到关键字眼“FAIL”后随手处理但实际上中断程序中最好不要有任何耗时操作。 习题1优化wifi透传控制LED【项目工程文件夹】
代码心得 本代码的串口中断程序中多出来了一个临时字符变量temp对temp的判断语句需要放在读取SBUF内容之前同时要注意串口缓冲寄存器SBUF中的内容被temp读取之后内容就不存在SBUF中了所以得用temp来给我们的字符数组赋值。字符数组下标i的偏移语句必须写在判断字符数组是否存满的判断语句前面不能写在后面因为我们要保证每次存满之后都从下标0位置开始存放如果写在后面那么每次都会从下标1位置开始存放。从而可以发现我们预设的字符数组长度为12实际上只能存放11个字符。
思路 宏定义
1. 定义符号常量len用它代表用于接收SBUF中缓冲字符串的全局数组的长度: #define len 12
全局变量
1. sfr指令直接找到AUXR寄存器: sfr AUXR 0X8E; //因为AUXR没有在reg52.h中声明
2. sbit指令找到P3这个I/O口组的第7位P3^7也就是D5这个LED: sbit ledD5 P3^7;
3. sbit指令找到P3这个I/O口组的第6位P3^6也就是D6这个LED: sbit ledD6 P3^6;
4. “设置wifi模块工作模式的AT指令”: char esp01s_modeSetting[] ATCWMODE3\r\n;
5. “设置wifi模块连接网络的AT指令”: code char esp01s_connectLAN[] ATCWJAP\HUAWEI P20\,\abcdefgh\\r\n;
6. “设置wifi模块连接TCP服务器的AT指令”: code char esp01s_connectTCPServer[] ATCIPSTART\TCP\,\192.168.45.201\,8880\r\n;
//5和6都要在前面加个关键词code因为太长了
7. “设置wifi模块透传模式的AT指令”: char esp01s_serialNet_mode[] ATCIPMODE1\r\n;
8. “设置wifi模块数据传输的AT指令”: char esp01s_dataSend_waiting[] ATCIPSEND\r\n;
9. 定义wifi模块响应AT指令OK的标志位: char AT_OK_Flag 0;
//AT_OK_Flag的传递路线为SBUF —— 串口中断中断4—— API2: wifiModule_Config();
10. 定义wifi模块响应AT指令WIFI GOT IP的标志位: char AT_ConnectLAN_Flag 0;
//AT_ConnectLAN_Flag的传递路线为SBUF —— 串口中断中断4—— API2: wifiModule_Config();
11. 定义一个用于接收串口中缓冲区字符串的全局数组serial_buffer: char serial_buffer[len];
//serial_buffer的传递路线为SBUF —— 串口中断中断4 1. 一上电先让指示灯D5和D6灭: ledD5 ledD6 1;
2. 调用API1. 初始化串口: UartInit();
3. 调用API5. 软件延时1s给wifi模块上电后ready的准备预留时间: Delay1000ms();
4. 调用API2. 配置wifi模块进入透传模式: wifiModule_Config();
5. while死循环每隔一秒通过串口给PC发送一个字符串当做心跳包5.1 调用API5软件延时1s: Delay1000ms();5.2 调用API4给输出数据缓冲寄存器SBUF发送一条字符串: sendString(hello shuaige\r\n); 中断:
中断4: 封装串口中断的中断服务程序 void Uart_Routine() interrupt 44.1 定义一个静态全局区的静态变量用来表示数组serial_buffer的下标: static int i 0;4.2 定义一个临时字符变量temp用于检测关键字眼保证我们的字符串是从字符数粗的第0位开始存放的。char temp;4.3 中断处理程序中对于接收中断的响应判据是RI 14.3.1 在接受到1字节数据后程序复位RI: RI 0;4.3.2 串口缓冲区接收到的字符先存放在临时变量temp中: temp SBUF;4.3.3 从数据缓冲寄存器SBUF中读到字符后根据我们提前设计好的关键字眼关心四件事WIFI GOT IP的W、 OK的O、 L-1的LFAIL的F判据是tempW || tempO || tempL || tempF4.3.3.1 如果是那么需要从头开始存放: i 0;4.3.3.2 否则那么什么也不做继续往下执行4.3.4 将temp的值保存在数组serial_buffer的第i个元素中:serial_buffer[i] temp;4.3.5 偏移数组下标: i;4.3.6 判断字符数组serial_buffer是否存满了判据是 i len //内在逻辑由于serial_buffer长度的限制当字符串超过len时我们需要覆盖掉原先的字符4.3.6.1 如果是那么需要从头开始存放: i 0;4.3.6.2 否则那么什么也不做继续往下执行4.3.7 通过字符数组的第0位和第5位捕捉关键字眼判断wifi模块是否响应WIFI GOT IP判据是serial_buffer[0]W serial_buffer[5]G4.3.7.1 如果是令标志位为1: AT_ConnectLAN_Flag 1;有效指令后清空字符数组: memset(serial_buffer,\0,len);4.3.7.2 否则那么什么也不做继续往下执行4.3.8 通过字符数组的第0位和第1位捕捉关键字眼判断wifi模块是否响应OK判据是serial_buffer[0]O serial_buffer[1]K4.3.8.1 如果是令标志位为1: AT_OK_Flag 1;有效指令后清空字符数组: memset(serial_buffer,\0,len);4.3.8.2 否则那么什么也不做继续往下执行4.3.9 通过字符数组的第0位和第1位捕捉关键字眼判断wifi模块是否响应FAIL判据是serial_buffer[0]F serial_buffer[1]L4.3.9.1 如果是用i当做循环变量使用for循环语句闪烁D5五次亮一秒灭一秒再次调用API4通过串口发送对应入网的AT指令: sendString(esp01s_connectLAN);有效指令后清空字符数组: memset(serial_buffer,\0,len);4.3.9.2 否则那么什么也不做继续往下执行4.3.10 通过字符数组的第0位和第2位捕捉关键字眼判断wifi模块是否收到透传数据L-1判据是serial_buffer[0]L serial_buffer[2]14.3.10.1 如果是点亮D5: ledD5 0;有效指令后清空字符数组: memset(serial_buffer,\0,len);4.3.10.2 否则如果wifi模块收到透传数据L-0熄灭D5: ledD5 1;有效指令后清空字符数组: memset(serial_buffer,\0,len);4.4 中断处理程序中对于发送中断的响应判据是TI 1暂时不做任何事情 /* 一级函数f1、f2、f4、f5 */
f1. 封装初始化串口的API: void UartInit(void);f1.1 禁用ALE信号: AUXR 0X01;f1.2 让串口以方式1工作8位UART可变波特率并允许串口接收: SCON 0x50;f1.3 让定时器1以8位重载工作模式工作:TMOD 0xDF;TMOD | 0x20;f1.4 根据波特率为9600波特率不翻倍设置定时器1的初值:TH1 0xFD;TL1 0xFD;f1.5 定时器开始数数: TR1 1;f1.6 开启串口中断:EA 1;ES 1;
f2. 封装配置wifi模块以客户端模式工作的API: void wifiModule_Config();f2.1 配置wifi模块工作模式为双模式设备模式路由模式:调用API4通过串口发送对应AT指令: sendString(esp01s_modeSetting);空循环体等待直到wifi模块响应OK: while(!AT_OK_Flag);为了不影响下一个条指令响应复位标志位: AT_OK_Flag 0;f2.2 配置wifi模块进行入网设置:调用API4通过串口发送对应AT指令: sendString(esp01s_connectLAN);空循环体等待直到wifi模块响应WIFI GOT IP: while(!AT_ConnectLAN_Flag);为了不影响下一个条指令响应复位标志位: AT_ConnectLAN_Flag 0;空循环体等待直到wifi模块响应OK: while(!AT_OK_Flag);为了不影响下一个条指令响应复位标志位: AT_OK_Flag 0;f2.3 配置wifi模块连接TCP服务器:调用API4通过串口发送对应AT指令: sendString(esp01s_connectTCPServer);空循环体等待直到wifi模块响应OK: while(!AT_OK_Flag);为了不影响下一个条指令响应复位标志位: AT_OK_Flag 0;f2.4 配置wifi模块设置成透传模式:调用API4通过串口发送对应AT指令: sendString(esp01s_serialNet_mode);空循环体等待直到wifi模块响应OK: while(!AT_OK_Flag);为了不影响下一个条指令响应复位标志位: AT_OK_Flag 0;f2.5 配置wifi模块进入数据待发状态正式进入透传模式:调用API4通过串口发送对应AT指令: sendString(esp01s_dataSend_waiting);空循环体等待直到wifi模块响应OK: while(!AT_OK_Flag); //不复位留给后面判断f2.6 测试代码经COM3这个端口发给PC上的串口助手看: sendString(wifi Module setting success!\r\n);f2.7 测试代码如果AT_OK_Flag1就点亮D6代表成功: ledD6 0;
f4. 封装给PC发送字符串的API: void sendString(char *str); //形参是字符串的地址f4.1 定义一个字符指针变量p用来保存字符串首地址: char *p str;f4.2 while循环控制循环的变量是*p当*p ! \0 时进入循环进行单个字符的发送f4.2.1 通过指针间接访问字符串字符再调用API3. 发送单个字符: sendByte(*p);f4.2.2 修改循环变量p的值让指针p偏移: p;
f5. 封装软件延时1s的API用于每隔1秒发送心跳包以及串口初始化后的短暂休眠: void Delay1000ms(); /* 二级函数f3 */
f3. 封装定时给PC发送一个字符的API: void sendByte(char data_msg); //形参是字符值f3.1 往SBUF寄存器中写入字符data_msg: SBUF data_msg;f3.2 根据串口发送中断触发位TI利用空循环体暂停程序: while(TI 0);f3.3 程序复位TI: TI 0; 代码 #include reg52.h
#include intrins.h
#include string.h#define len 12
sfr AUXR 0x8E;
sbit ledD5 P3^7;
sbit ledD6 P3^6;
char esp01s_modeSetting[] ATCWMODE3\r\n; //配置wifi模块的工作模式
// code char esp01s_connectLAN[] ATCWJAP\CMCC-XyVF\,\XyVFVsrz\\r\n; //连接上局域网络
// code char esp01s_connectTCPServer[] ATCIPSTART\TCP\,\192.168.1.7\,8880\r\n; //连接上TCP服务器
code char esp01s_connectLAN[] ATCWJAP\HUAWEI P20\,\abcdefgh\\r\n; //连接上局域网络
code char esp01s_connectTCPServer[] ATCIPSTART\TCP\,\192.168.45.201\,8880\r\n;//连接上TCP服务器
char esp01s_serialNet_mode[] ATCIPMODE1\r\n; //设置透传模式
char esp01s_dataSend_waiting[] ATCIPSEND\r\n; //进入数据待发状态正式进入透传模式
// char esp01s_reset[] ATRST\r\n; //wifi连接失败重启wifi模块
char AT_OK_Flag 0; //关键字眼OK的标志位用1代表AT指令响应成功0代表AT指令响应失败
char AT_ConnectLAN_Flag 0; //关键字眼WIFI GOT IP的标志位用1代表AT指令响应成功0代表AT指令响应失败
char serial_buffer[len];/* API1. 初始化串口 */
void UartInit(void);
/* API2. 配置wifi模块以客户端模式工作进入透传模式 */
void wifiModule_Client_Config();
/* API3. 通过串口给PC发送一个字符 */
void sendByte(char data_msg);
/* API4. 通过串口给PC发送一个字符串 */
void sendString(char *str);
/* API5. 用于每隔1秒给wifi模块发送心跳包以及串口初始化后的短暂休眠 */
void Delay1000ms();void main(void)
{ledD5 ledD6 1;UartInit();Delay1000ms(); //给wifi模块上电后ready的准备时间wifiModule_Client_Config();while(1){Delay1000ms();sendString(hello shuaige\r\n); //心跳包}
}void Uart_Routine() interrupt 4
{static int i 0; //静态全局区的变量数组下标char temp;/* 中断处理程序中对于接收中断的响应 */if(RI 1){ RI 0;//清除接收中断标志位temp SBUF;if(tempW || tempO || tempL || tempF){ //从数据缓冲寄存器SBUF中读到字符后关心四件事i 0;}serial_buffer[i] temp;i;if(i len){i 0;}//wifi模块响应值的判断if(serial_buffer[0]W serial_buffer[5]G){AT_ConnectLAN_Flag 1;memset(serial_buffer, \0, len);}if(serial_buffer[0]O serial_buffer[1]K){AT_OK_Flag 1;memset(serial_buffer, \0, len);}if(serial_buffer[0]F serial_buffer[1]A){for(i0; i5; i){ //测试入网失败后闪灯并发送联网指令ledD5 0;Delay1000ms();ledD5 1;Delay1000ms();}// sendString(esp01s_reset);sendString(esp01s_connectLAN);memset(serial_buffer, \0, len);}//灯控指令if(serial_buffer[0]L serial_buffer[2]1){ledD5 0;memset(serial_buffer, \0, len);}else if(serial_buffer[0]L serial_buffer[2]0){ledD5 1;memset(serial_buffer, \0, len);}}/* 中断处理程序中对于发送中断的响应 */if(TI 1){// 暂时不做任何事情}
}void UartInit(void) //9600bps11.0592MHz
{AUXR 0x01;SCON 0x50; //8位UART允许串口接收TMOD 0xDF;TMOD | 0x20; //定时器8位重载工作模式TH1 0xFD;TL1 0xFD; //9600波特率初值TR1 1;EA 1;ES 1; //开启串口中断
}void wifiModule_Client_Config()
{/* 经过白盒测试以及优化后以下AT指令只需要发送一遍所以不需要反复配置暂停程序直到AT指令响应成功 */sendString(esp01s_modeSetting);while(!AT_OK_Flag); //等待直到wifi模块响应OKAT_OK_Flag 0;sendString(esp01s_connectLAN);while(!AT_ConnectLAN_Flag); //等待直到wifi模块响应WIFI GOT IPledD5 0; //测试点亮D5代表入网成功while(!AT_OK_Flag); //等待直到wifi模块响应OKAT_OK_Flag 0;sendString(esp01s_connectTCPServer);while(!AT_OK_Flag); //等待直到wifi模块响应OKAT_OK_Flag 0;sendString(esp01s_serialNet_mode);while(!AT_OK_Flag); //等待直到wifi模块响应OKAT_OK_Flag 0;sendString(esp01s_dataSend_waiting);while(!AT_OK_Flag); //等待直到wifi模块响应OKsendString(wifi Module setting success!\r\n); //测试经COM3这个端口发给PC上的串口助手看if(AT_OK_Flag 1){ledD6 0; //测试点亮D6代表连接服务器并打开透传模式}
}void sendByte(char data_msg)
{SBUF data_msg;while(TI 0);TI 0;
}void sendString(char *str)
{char *p str;while(*p ! \0){sendByte(*p);p;}
}void Delay1000ms() //11.0592MHz
{unsigned char i, j, k;_nop_();i 8;j 1;k 243;do{do{while (--k);} while (--j);} while (--i);
}
5、白盒调试跟踪代码优化代码写完之后再按照白盒测试的套路进行调试跟踪代码执行过程。 我们这个代码烧进去之后由于51单片机的RX引脚没有接在wifi模块的TX引脚上所以51单片机从接收缓冲寄存器SBUF中接收不到任何数据。所以白盒测试中的串口助手COM6端口CH340和wifi模块的串口一定会卡着。所以需要我们在另一个串口助手COM3端口51单片机和PC的串口中手动模拟wifi模块本来应该响应给51单片机的数据。最后测试成功后就可以认为代码是可靠的了可以烧录进单片机中。
注白盒测试下不能够用透传来测试wifi控制LED也得用串口手动模拟。 5.ESP-01S当做服务器
1、数据传输路线前面4小节我们都是让wifi以客户端模式进行工作。我们接下来在PC上用网络调试助手构建一个基于TCP协议的客户端。也是给wifi模块发送AT指令让ESP8266在路由模式下以TCP服务器模式工作。然后让PC上的TCP客户端联入wifi模块构建的局域网。这个时候ESP8266和外部的通讯方式也分为两类。 走串口wifi模块和PC走串口协议PC通过USB转TTL的CH340驱动将AT指令传送给wifi模块然后wifi模块响应一些配置信息给PC。走wifiwifi模块和PC也可以走网络传输层中的TCP协议这时候PC和wifi模块是连接在同一个局域网下的wifi模块作为服务器PC作为客户端。数据可以从TCP客户端传递到wifi模块。数据也可以从wifi模块透传到TCP客户端。
2、串口测试时的AT指令及响应测试截图略总的响应信息见5.3中的图
wifi模块工作模式设置ATCWMODE3也可以写成ATCWMODE2wifi模块联网ATCWJAPHUAWEI P20,abcdefgh这种模式下是路由模式不需要联网查阅wifi模块以AP模式工作时的网关ATCIFSR 目的是用于确认服务器的IP地址就是wifi模块的网关有的网络调试助手上会写成远程主机地址一个意思将它写在网络调试助手的对应位置。也需要在命令提示符中明确当前PC的IPV4地址输入网络调试助手中。配置wifi模块成使能多链接ATCIPMUX1 配置成功wifi模块会响应“OK”配置失败wifi模块会响应“ERROR”如果再次发送该AT指令wifi模块会响应“OK”如果在wifi模块已经与TCP客户端建立连接的前提下再次发送该AT指令wifi模块会响应“link is builded”、“ERROR”让wifi模块建立TCP服务器端口号默认是333ATCIPSERVER1 建立成功wifi模块会响应“OK”建立失败wifi模块会响应“ERROR”建立成功后重复发送上述AT指令wifi模块会响应“no change”、“OK”在PC上的网络调试助手上配置好之后网络调试助手上点击连接后如果连接成功wifi模块会响应“0,CONNECT”逗号后无空格这里0代表连接的通道一个IP地址对应一个通道第1个联入的IP地址的通道是0网络调试助手上点击连接后如果连不上可能的原因是你的PC还没有联入wifi模块构建的局域网我的8266构建的局域网的名字是ESP_28DCAB或者网络调试助手出问题了没有成功建立TCP客户端换一个。TCP客户端和wifi模块成功建立连接后如果在网络调试助手上点击断开后也就是TCP客户端断开连接时wifi模块会响应“0,CLOSED”逗号后无空格。让wifi模块进入数据待发状态ATCIPSEND0,n 0是通道号、n是待发数据字节数逗号后无空格 当你数据手动发送成功后wifi模块会响应“Recv n bytes”、“SEND OK”如果在没有与TCP客户端建立连接时就立马发送上述AT指令wifi模块会响应“link is not valid”、“ERROR”让wifi模块主动断开TCP连接用的很少ATCIPCLOSE0 0是通道号 在TCP客户端和wifi模块成功建立连接的前提下发送上述指令并断开后wifi模块会响应“0,CLOSED”、“OK” 0是通道号逗号后无空格。同时网络调试助手上会显示未连接的状态。重复发送断开的AT指令也就是TCP服务器和客户端已经断开的状态下继续发送该AT指令wifi模块会响应“UNLINK”、“ERROR”。注意上述指令只是让wifi模块断开TCP连接并不是取消构建TCP服务器下次连接时仍然还是由TCP客户端发起的。
3、与客户端的数据交互
接收客户端发来的数据让wifi模块配置到上述第5步建立TCP服务器就能接收TCP客户端发送来的数据了。 但实际上这还不是透传模式。接收的数据具有固定的格式“IPD,0,n:xxx”逗号冒号后均无空格其中IPD是固定字符串0是连接的通道n是数据的字节数xxx才是从客户端透传来的数据往客户端透传数据需要让wifi模块配置到上述第6步进入数据待发状态才正式进入透传模式。 透传时尽量不要发送新行因为新行占两个字节。发送完毕后会自动退出透传模式。如果发送的字节数超出了n字节数wifi模块先会响应“busy s...”再响应“Recv n bytes”、“SEND OK”同时只会截取前面的字节发送。如果你发送的数据长度不足n字节wifi模块不会有任何响应同时网络调试助手上看不到任何发送来的数据这个数据就好像一直存在“缓冲区”中只有你达到或者超过了设定的n个字节数才会显示。 4、单片机配置服务器模式这里的步骤和4.1~4.5一致。
确认单片机要发送的AT指令终端设备是单片机MCU让单片机通过串口给模块发送一系列AT指令指挥wifi模块以服务器模式工作。 重启wifi模块配置wifi模块的工作模式如果之前设置过的话这一步wifi模块会自动完成设置成使能多链接模式建立TCP服务器 进入数据待发状态正式进入透传模式发送完毕后会自动退回到AT指令模式波特率是提前用电脑通过AT指令给wifi模块配置好的用9600。单片机处理wifi模块响应信息 AT指令响应成功的关键字眼及标志位配置wifi模块为路由模式使能多链接建立TCP服务器与TCP客户端建立连接进入数据待发状态5字节、通道0成功“OK”成功“OK”成功“OK”成功“0,CONNECT”成功“OK”成功标志位 AT_OK_Flag成功标志位 AT_OK_Flag成功标志位 AT_OK_Flag成功标志位 Client_Connect_Flag不检测透传有效指令的关键字眼灯控指令亮灯“:op” 灭灯“:cl” 对于进入数据待发状态的AT指令来说不要去检测“OK”因为我们要在main函数的while(1)循环中把这个指令用于给TCP客户端发送心跳包通过串口也能看见发送的心跳包如果说以后一旦检测不到OK了比如说TCP客户端主动与TCP服务器断开连接那么程序就会卡死在while(1)循环中那么就连串口上也无法监测到心跳包会让我们误以为单片机死掉了了。我在用白盒测试跟踪代码运行情况时灯控指令设置成了“:L-1”和“:L-0”出现了大问题①第一个OK需要发送两次才能被接收到②后面发送0,CONNECT也很难被接收到③即使与TCP客户端建立起了连接灯控指令也不能正常工作。经过我不断的调试心累其实从问题描述中也能看出终于发现了问题所在灯控指令不能设置成“:L-1”和“:L-0”。所以我选用了“:op”与“:cl”。通过硬件来窥探wifi模块配置情况 让wifi模块在成功建立TCP服务器后D5亮main函数中对标志位 AT_OK_Flag 判断让wifi模块与客户端建立连接后D6亮main函数中对标志位 Client_Connect_Flag 判断白盒测试跟踪代码代码见习题2。注意白盒测试下不能够测试wifi控制LED也得用串口手动模拟。 习题2wifi模块作为服务器在习题1的代码上做适当修改【项目工程文件夹】
思路 宏定义
1. 定义符号常量len用它代表用于接收SBUF中缓冲字符串的全局数组的长度: #define len 12
全局变量
1. sfr指令直接找到AUXR寄存器: sfr AUXR 0X8E; //因为AUXR没有在reg52.h中声明
2. sbit指令找到P3这个I/O口组的第7位P3^7也就是D5这个LED: sbit ledD5 P3^7;
3. sbit指令找到P3这个I/O口组的第6位P3^6也就是D6这个LED: sbit ledD6 P3^6;
4. “设置wifi模块工作模式的AT指令”: char esp01s_modeSetting[] ATCWMODE2\r\n;
5. “设置wifi模块使能多链接的AT指令”: char esp01s_multiLink[] ATCIPMUX1\r\n;
6. “设置wifi模块建立TCP服务器的AT指令”: char esp01s_setTCPServer[] ATCIPSERVER1\r\n;
7. “设置wifi模块数据传输的AT指令”: char esp01s_dataSend_waiting[] ATCIPSEND0,5\r\n;
8. 定义wifi模块响应AT指令OK的标志位: char AT_OK_Flag 0;
//AT_OK_Flag的传递路线为SBUF —— 串口中断中断4—— API2: wifiModule_Server_Config();
9. 定义wifi模块响应AT指令0,CONNECT的标志位: char Client_Connect_Flag 0;
//Client_Connect_Flag的传递路线为SBUF —— 串口中断中断4—— API2: wifiModule_Server_Config();
10. 定义一个用于接收串口中缓冲区字符串的全局数组serial_buffer: char serial_buffer[len];
//serial_buffer的传递路线为SBUF —— 串口中断中断4—— 临时字符变量temp 1. 一上电先让指示灯D5和D6灭: ledD5 ledD6 1;
2. 调用API1. 初始化串口: UartInit();
3. 调用API5. 软件延时1s给wifi模块上电后ready的准备预留时间: Delay1000ms();
4. 调用API2. 配置wifi模块以TCP服务器模式工作: wifiModule_Server_Config();
5. while死循环每隔4秒以两种方式串口和透传给PC发送一个字符串当做心跳包5.1 调用API4通过串口发送数据传输的AT指令: sendString(esp01s_0Channel_dataSend);5.2 调用API5软件延时2s: Delay1000ms();Delay1000ms();5.3 调用API4给输出数据缓冲寄存器SBUF发送一条字符串: sendString(hello);5.2 调用API5软件延时2s: Delay1000ms();Delay1000ms(); 中断:
中断4: 封装串口中断的中断服务程序 void Uart_Routine() interrupt 44.1 定义一个静态全局区的静态变量用来表示数组serial_buffer的下标: static int i 0;4.2 定义一个临时字符变量temp用于检测关键字眼保证我们的字符串是从字符数粗的第0位开始存放的。char temp;4.3 中断处理程序中对于接收中断的响应判据是RI 14.3.1 在接受到1字节数据后程序复位RI: RI 0;4.3.2 串口缓冲区接收到的字符先存放在临时变量temp中: temp SBUF;4.3.3 从数据缓冲寄存器SBUF中读到字符后根据我们提前设计好的关键字眼关心四件事OK的O、 0,CONNECT的0、 IPD,0,n:op的:判据是tempO || temp0 || temp:4.3.3.1 如果是那么需要从头开始存放: i 0;4.3.3.2 否则那么什么也不做继续往下执行4.3.4 将temp的值保存在数组serial_buffer的第i个元素中:serial_buffer[i] temp;4.3.5 偏移数组下标: i;4.3.6 判断字符数组serial_buffer是否存满了判据是 i len //内在逻辑由于serial_buffer长度的限制当字符串超过len时我们需要覆盖掉原先的字符4.3.6.1 如果是那么需要从头开始存放: i 0;4.3.6.2 否则那么什么也不做继续往下执行4.3.7 通过字符数组的第0位和第1位捕捉关键字眼判断wifi模块是否响应OK判据是serial_buffer[0]O serial_buffer[1]K4.3.7.1 如果是令标志位为1: AT_OK_Flag 1;有效指令后清空字符数组: memset(serial_buffer,\0,len);4.3.7.2 否则那么什么也不做继续往下执行4.3.8 通过字符数组的第0位和第2位捕捉关键字眼判断wifi模块是否响应0,CONNECT判据是serial_buffer[0]0 serial_buffer[2]C4.3.8.1 如果是令标志位为1: Client_Connect_Flag 1;有效指令后清空字符数组: memset(serial_buffer,\0,len);4.3.8.2 否则那么什么也不做继续往下执行4.3.9 通过字符数组的第0位和第2位捕捉关键字眼判断wifi模块是否收到透传数据IPD,0,n:open判据是serial_buffer[0]: serial_buffer[1]o serial_buffer[2]p4.3.9.1 如果是点亮D5: ledD5 0;有效指令后清空字符数组: memset(serial_buffer,\0,len);4.3.9.2 否则如果wifi模块收到透传数据IPD,0,n:close熄灭D5: ledD5 1;有效指令后清空字符数组: memset(serial_buffer,\0,len);4.4 中断处理程序中对于发送中断的响应判据是TI 1暂时不做任何事情 /* 一级函数f1、f2、f4、f5 */
f1. 封装初始化串口的API: void UartInit(void);f1.1 禁用ALE信号: AUXR 0X01;f1.2 让串口以方式1工作8位UART可变波特率并让REN使能允许串口接收: SCON 0x50;f1.3 让定时器1以8位重载工作模式工作:TMOD 0xDF;TMOD | 0x20;f1.4 根据波特率为9600波特率不翻倍设置定时器1的初值:TH1 0xFD;TL1 0xFD;f1.5 定时器开始数数: TR1 1;f1.6 开启串口中断:EA 1;ES 1;
f2. 封装配置wifi模块以客户端模式工作的API: void wifiModule_Server_Config();f2.1 配置wifi模块工作模式为路由模式:调用API4通过串口发送对应AT指令: sendString(esp01s_modeSetting);空循环体等待直到wifi模块响应OK: while(!AT_OK_Flag);为了不影响下一个条指令响应复位标志位: AT_OK_Flag 0;f2.2 配置wifi模块使能多链接模式:调用API4通过串口发送对应AT指令: sendString(esp01s_multiLink);空循环体等待直到wifi模块响应OK: while(!AT_OK_Flag);为了不影响下一个条指令响应复位标志位: AT_OK_Flag 0;f2.3 配置wifi模块建立TCP服务器:调用API4通过串口发送对应AT指令: sendString(esp01s_setTCPServer);空循环体等待直到wifi模块响应OK: while(!AT_OK_Flag);为了不影响下一个条指令响应复位标志位: AT_OK_Flag 0;测试代码点亮D5代表成功建立TCP服务器: ledD5 0;f2.4 空循环体等待直到wifi模块响应0,CONNECT: while(!Client_Connect_Flag); //不复位留给后面判断测试代码如果Client_Connect_Flag1就点亮D6代表成功与客户端建立链接: ledD6 0;
f4. 封装给PC发送字符串的API: void sendString(char *str); //形参是字符串的地址f4.1 定义一个字符指针变量p用来保存字符串首地址: char *p str;f4.2 while循环控制循环的变量是*p当*p ! \0 时进入循环进行单个字符的发送f4.2.1 通过指针间接访问字符串字符再调用API3. 发送单个字符: sendByte(*p);f4.2.2 修改循环变量p的值让指针p偏移: p;
f5. 封装软件延时1s的API用于每隔1秒发送心跳包以及串口初始化后的短暂休眠: void Delay1000ms(); /* 二级函数f3 */
f3. 封装定时给PC发送一个字符的API: void sendByte(char data_msg); //形参是字符值f3.1 往SBUF寄存器中写入字符data_msg: SBUF data_msg;f3.2 根据串口发送中断触发位TI利用空循环体暂停程序: while(!TI);f3.3 程序复位TI: TI 0; 代码 #include reg52.h
#include intrins.h
#include string.h#define len 12
sfr AUXR 0x8E;
sbit ledD5 P3^7;
sbit ledD6 P3^6;
char serial_buffer[len];
char esp01s_modeSetting[] ATCWMODE2\r\n; //配置wifi模块的工作模式
char esp01s_multiLink[] ATCIPMUX1\r\n; //使能多链接
char esp01s_setTCPServer[] ATCIPSERVER1\r\n; //建立TCP服务器
char esp01s_0Channel_dataSend[] ATCIPSEND0,5\r\n; //发送5个字节数据在连接0通道上
char AT_OK_Flag 0; //关键字眼OK的标志位用1代表AT指令响应成功0代表AT指令响应失败
char Client_Connect_Flag 0; //关键字眼0,CONNECT的标志位用1代表客户端接入成功0代表客户端接入失败/* API1. 初始化串口 */
void UartInit(void);
/* API2. 配置wifi模块以服务器模式工作 */
void wifiModule_Server_Config();
/* API3. 通过串口给PC发送一个字符 */
void sendByte(char data_msg);
/* API4. 通过串口给PC发送一个字符串 */
void sendString(char *str);
/* API5. 用于每隔1秒给wifi模块发送心跳包以及串口初始化后的短暂休眠 */
void Delay1000ms();void main()
{ledD5 ledD6 1;//灭状态灯UartInit();Delay1000ms();//给espwifi模块上电时间wifiModule_Server_Config();while(1){sendString(esp01s_0Channel_dataSend);Delay1000ms(); //虽然说发送也是需要时间但是不要用检测“OK”来暂停程序Delay1000ms();sendString(Hello); //服务器给客户端的心跳包串口助手上也能看见Delay1000ms();Delay1000ms();}
}void Uart_Routine() interrupt 4
{static int i 0;//静态变量被初始化一次char temp;/* 中断处理程序中对于接收中断的响应 */if(RI)//中断处理函数中对于接收中断的响应{RI 0;//清除接收中断标志位temp SBUF;if(temp O || temp 0 || temp :){i 0;}serial_buffer[i] temp;i;if(i len) i 0;//wifi模块响应值的判断if(serial_buffer[0] O serial_buffer[1] K){AT_OK_Flag 1;memset(serial_buffer, \0, len);}if(serial_buffer[0] 0 serial_buffer[2] C){Client_Connect_Flag 1;memset(serial_buffer, \0, len);}//灯控指令if(serial_buffer[0] : serial_buffer[1] o serial_buffer[2]p){ledD5 0;//点亮D5memset(serial_buffer, \0, len);}else if(serial_buffer[0] : serial_buffer[1] c serial_buffer[2]l){ledD5 1;//熄灭D5memset(serial_buffer, \0, len);}}/* 中断处理程序中对于发送中断的响应 */if(TI 1){// 暂时不做任何事情}
}void UartInit(void) //9600bps11.0592MHz
{AUXR 0x01;SCON 0x50; //8位UART允许串口接收TMOD 0xDF;TMOD | 0x20; //定时器8位重载工作模式TH1 0xFD;TL1 0xFD; //9600波特率初值TR1 1; //启动定时器EA 1;ES 1; //开启串口中断
}void wifiModule_Server_Config()
{sendString(esp01s_modeSetting);while(!AT_OK_Flag);AT_OK_Flag 0;sendString(esp01s_multiLink);while(!AT_OK_Flag);AT_OK_Flag 0;sendString(esp01s_setTCPServer);while(!AT_OK_Flag);AT_OK_Flag 0; ledD5 0; //点亮D5,代表成功建立TCP服务器while(!Client_Connect_Flag);if(Client_Connect_Flag){ledD6 0; //点亮D6,代表有客户端接入}
}void sendByte(char data_msg)
{SBUF data_msg;while(!TI);TI 0;
}void sendString(char *str)
{char *p str;while(*p ! \0){sendByte(*p);p;}
}void Delay1000ms() //11.0592MHz
{unsigned char i, j, k;_nop_();i 8;j 1;k 243;do{do{while (--k);} while (--j);} while (--i);
}