高级会员
- 积分
- 598
- 金钱
- 598
- 注册时间
- 2014-4-14
- 在线时间
- 76 小时
|
发表于 2016-7-20 11:10:09
|
显示全部楼层
送你个我自己写的ESP8266的程序,三种工作模式,可以参考下各种模式的工作流程,个人感觉自己写的挺清楚的了~~~
ESP8266.c文件上半部分如下:
[mw_shl_code=c,true]/*
*******************************************************************************
*
* 模块名称 : ESP8266 WIFI模块
* 文件名称 : esp8266.c
* 说 明 : 实现WIFI模块的客户端与服务器模式的TCP通信
*
*******************************************************************************
*/
#include "usart3.h"
#include "stdio.h"
#include "stdlib.h"
#include "esp8266.h"
#include "string.h"
#include "delay.h"
#define MAXRECVBUFF USART3_BUFF
#define DEBUG_EN 1
//模块工作模式
#define MODULE_SERVER 1
#define MODULE_CLIENT 2
#define MODULE_SERCLI 3
//指令列表
#define AT "AT\r\n"
#define ATRES "AT+RST\r\n"
#define ATCIPSERVER "AT+CIPSERVER=1,%d\r\n" //服务器模式下,设置端口
#define ATCWMODE "AT+CWMODE=%d\r\n" //模块工作模式
#define ATCWMODE_CX "AT+CWMODE?\r\n" //查询wifi工作模式
#define ATCWLAPx "AT+CWLAP\r\n" //显示无线列表
#define ATCWJAPj "AT+CWJAP=\"%s\",\"%s\"\r\n" //加入无线网络
#define ATCIPMUX "AT+CIPMUX=1\r\n" //开启多联模式
#define ATCIPSTART(x) ((x)?"AT+CIPSTART=2,\"TCP\",\"%s\",%d\r\n"\
:"AT+CIPSTART=\"UDP\",\"%s\",%d\r\n") //连接服务器、透传模式
#define ATCIPSEND(x) ((x)?"AT+CIPSEND=%d,%d\r\n"\
:"AT+CIPSEND\r\n") //发送数据字节、进入透传模式
#define ATCWSAP "AT+CWSAP=\"%s\",\"%s\",1,%d\r\n" //创建WIFI热点
#define ATCWSAP_CX "AT+CWSAP?\r\n" //查询wifi热点设置信息
#define ATCIPSTO "AT+CIPSTO=%d\r\n" //服务器模式下,链接超时时间
#define ATCIPSTATUS "AT+CIPSTATUS\r\n" //获得链接状态
#define ATCIPMODE "AT+CIPMODE=1\r\n" //透传模式设置
#define CLOSEDTU "+++" //关闭透传
//指令ID
enum order{
_AT = 1,_ATRES,_ATCIPSERVER,_ATCWMODE,
_ATCWMODE_CX,_ATCWLAPx,_ATCWJAPj,_ATCIPMUX,
_ATCIPSTART,_ATCIPSEND,_ATDATA,_SENDDATAEND,
_ATCWSAP,_ATCIPSTO,_ATCWSAP_CX,_ATCIPSTATUS,
_ATCIPMODE,_CLOSEDTU
};
struct WifiData{
char *order; // 命令
int olen; // 命令长度
enum order type; // 命令类型
};
static char wifi_Data[MAXRECVBUFF]={0};
static int wifi_Dlen = 0;
/*
AT+CIPSTATUS
STATUS:3
+CIPSTATUS:0,"TCP","192.168.4.100",60154,1
+CIPSTATUS:2,"TCP","192.168.10.75",8080,0
*/
char Client_Link_id = ERROR_LINK_ID; //客户连接的ID号
char Server_Link_id = ERROR_LINK_ID; //服务器连接的ID号
static char Recv_Link_id = ERROR_LINK_ID; //当有数据来时,记录下ID
static char SearchWifiName[50]=""; //需要查询的wifi名
static char Dtu_flay = 0; //透传状态标志
/*********************************************************
* @function read_wifi_list
* @role 解析wifi列表
* @input 接收到的数据
* @output None
* @return wifi数目
********************************************************/
/*
static int read_wifi_list(char *pData)
{
char *p = pData;
char *pNext = p;
char node[5]="";
int i = wifinum, j = 0;
while(((p = strstr(pNext,"+CWLAP")) != 0) && (i < 25))
{
p += 8;
wifitype = 0;
wifitype = p[0] - 48;
p = strchr(p,'"'); p++;
for (j = 0; (*p != '"') && (*p != '\0') && (j < 99);++p, ++j){
wifiname[j] = *p;
}
wifiname[j] = '\0';
p += 2;
memset(node,0,sizeof(node));
for (j = 0; (*p != ',') && (*p != '\0') && (j < 4);++p, ++j){
node[j] = *p;
}
node[j] = '\0';
wifimax = atoi(node);
i++;
pNext = p;
}
return i;
}
*/
/*********************************************************
* @function mypow
* @role pow库函数的实现,计算num的n次幂,其中n为整数
* @input num
* @output n
* @return 计算结果
******************************************************
static int mypow(int Num, int N)
{
int powint=1;
int i;
for(i=1;i<=N;i++) powint*=Num;
return powint;
}
**/
/*********************************************************
* @function FreeStr
* @role 删除字符串中的字串,支持16进制数据,无视结束符
* @input 字符串、字符串总长度、开始删除的起始位置、要删除的长度
* @output None
* @return None
********************************************************/
static void FreeStr(char *pStr, int pStrsiz, int pHead, int pLen)
{
int i = 0;
while(pLen--)
{
for(i = pHead; i < pStrsiz;i++)
{
pStr = pStr[i+1];
pStr[i+1] = '\0';
}
}
}
/*********************************************************
* @function GetRecvData
* @role 提取字符串中跟命令无关的数据
* @input 数据和数据长度
* @output None
* @return None
********************************************************/
static void GetRecvData(char *pBuff, int *pLen)
{
int rlen = 0;
char buff[5]="";
s32 i = 0;
char *p1 = NULL;
char *p2 = NULL;
if((pBuff == NULL) || (*pLen == 0))
return;
if (((p1 = strstr(pBuff, "+IPD,")) != 0) && ((p2 = strchr(pBuff, ':')) != 0))
{
p1+=5;
Recv_Link_id = *p1 - '0';
p1+=2;
for (i = 0; ((p1-pBuff) < *pLen) && (i < 5) && (*p1 != ':'); ++i,++p1) {
buff = *p1;
}
buff = '\0';
rlen = atoi(buff);
p2++;
wifi_Dlen = ((rlen >= (*pLen - (p2 - pBuff)))?(*pLen - (p2 - pBuff)):rlen);
memcpy(wifi_Data, p2,wifi_Dlen);
rlen = wifi_Dlen;
p1 = strstr(pBuff, "+IPD,");
p2 = strchr(pBuff, ':');
rlen += ((p2+1)-p1);
printf("Rlen:[%d][%d][%d]\r\n", *pLen,p1-pBuff, rlen);
FreeStr(pBuff, *pLen,p1-pBuff, rlen);
if((*pLen -rlen) <=3)
*pLen = 0;
else
*pLen -=rlen;
return;
}
}
/*********************************************************
* @function GetFreeBuff
* @role 处理掉缓存中多余的数据,同时也起到延时200ms的作用,
读取数据函数自带延时10ms,所以这里num=20
* @input None
* @output None
* @return None
********************************************************/
static void GetFreeBuff(int num)
{
char buff[MAXRECVBUFF] = "";
int siz = 0;
while(num--)
{
siz = usart3_Receive((u8 *)buff,MAXRECVBUFF);
if(siz){
if(strstr(buff,"\r\nSEND OK\r\n")){
break;
}
GetRecvData((char *)buff, &siz);
}
}
}
/*********************************************************
* @function SendAT
* @role 发送AT指令并接收
* @input wifi:要发送的参数
* @output out:返回的参数
* @return 成功返回:_ATOK,失败返回:_ATERROR
********************************************************/
static s8 SendAT(struct WifiData *wifi, char *out, int Delay)
{
int siz = 0;
int i = 0, j =0;
char buff[MAXRECVBUFF] = "";
char node[100] = "";
char *p = NULL;
char *p2 = NULL;
s8 ret = _ATERROR;
#if DEBUG_EN
printf("\r\n------------------------------\r\n");
printf("len[%d]\r\n", wifi->olen);
printf(">>\r\n");
if(wifi->type != _ATDATA)
{
for(i = 0; i< wifi->olen; i++){
printf("%c", wifi->order);
}
printf("<<\r\n");
}
i = 0;
#endif
GetFreeBuff(2);//20ms,坑爹的不能太快,太快的话模块会返回"busy p...",坑爹的没法关回显。
usart3_Send((u8 *)wifi->order,wifi->olen);
if(wifi->type == _CLOSEDTU)
{
ret = _ATOK;
goto ESP8266_SENDATRET;
}
while(1)
{
buff[0]='\0';
siz = 0; i = 0;
while(siz == 0)
{
siz = usart3_Receive((u8 *)buff,MAXRECVBUFF);
if(i++ > Delay){
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
if(siz){
#if DEBUG_EN
printf("\r\n--------------RECV1:[%d]----------------\r\n",siz);
for(j = 0;j<siz;j++)
printf("%c",buff[j]);
printf("\r\n----------------------------------------\r\n");
#endif
GetRecvData(buff, &siz);
if(siz)
{
printf("\r\n-------RECV2:[%d]-------\r\n",siz);
for(j = 0;j<siz;j++)
printf("%c",buff[j]);
printf("\r\n------------------------\r\n");
}
}
}
switch(wifi->type)
{
case _AT:
case _ATCIPMUX:
case _ATCWSAP:
case _ATCIPSTO:
case _ATCIPSTART:
case _ATCIPSERVER:
case _ATCIPMODE:
if(strstr(buff, "OK")){
ret = _ATOK;
goto ESP8266_SENDATRET;
}else if(strstr(buff, "ERROR")) {
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
break;
case _ATRES:
if(strstr(buff, "OK"))
{
i = Delay;
while(i--)
{
siz = usart3_Receive((u8 *)buff,MAXRECVBUFF);
if(siz)
{
for(j = 0; j < siz;j++){
if(buff[j] == 0x00)
buff[j] = '0';
}
#if (DEBUG_EN == 1)
printf("\r\nrecv[%d]:\r\n%s\r\n",siz,buff);
#endif
if(strstr(buff, "Ready") || strstr(buff,"ready"))
{
ret = _ATOK;
goto ESP8266_SENDATRET;
}
}
}
ret = _ATERROR;
goto ESP8266_SENDATRET;
}else if(strstr(buff, "ERROR")) {
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
break;
case _ATCWMODE:
if(strstr(buff, "OK") || strstr(buff, "no change")){
ret = _ATOK;
goto ESP8266_SENDATRET;
}else if(strstr(buff, "ERROR")) {
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
break;
case _ATCWMODE_CX:
if(strstr(buff,"OK") && ((p = (char *)strstr(buff,"+CWMODE:")) != 0))
{
p += 8;
*out = *p;
ret = _ATOK;
goto ESP8266_SENDATRET;
}else if(strstr(buff, "ERROR")) {
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
ret = _ATERROR;
goto ESP8266_SENDATRET;
case _ATCWJAPj:
if(strstr(buff, "OK") || strstr(buff, "FAIL")){
ret = _ATOK;
goto ESP8266_SENDATRET;
}else if(strstr(buff, "ERROR")) {
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
break;
case _ATCWLAPx:
if(out != NULL)
{
if(SearchWifiName[0] != 0x00)
{
if(strstr(buff,(char *)SearchWifiName))
*out = '1';
else
*out = '0';
}
if(strstr(buff, "OK"))
{
ret = _ATOK;
goto ESP8266_SENDATRET;
}
}
else
{
/*
if(strstr(buff,"+CWLAP:") && strstr(buff,"OK")) {
wifinum = read_wifi_list((char *)buff);
ret = _ATOK;
goto ESP8266_SENDATRET;
}else if(strstr(buff,"+CWLAP:")) {
wifinum = read_wifi_list((char *)buff);
memset(buff, 0, sizeof((char *)buff));
}else if(strstr(buff,"OK"))
ret = _ATOK;
goto ESP8266_SENDATRET;
break;
*/
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
case _ATCIPSEND:
if(strstr(buff, "link is not")){
ret = _LINKNOT;
goto ESP8266_SENDATRET;
}
else if (strstr(buff, ">")) {
ret = _ATOK;
goto ESP8266_SENDATRET;
} else if (strstr(buff, "ERROR") || strstr(buff, "busy")) {
GetFreeBuff(2);
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
break;
case _ATDATA:
if (strstr(buff, "SEND OK")) {
if(wifi->olen > 1460)
GetFreeBuff(300);
ret = _ATOK;
goto ESP8266_SENDATRET;
}else if(strstr(buff, "ERROR")) {
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
/*
if(strstr(buff, "Recv") && strstr(buff, "bytes")) {
usart3_FreeBuff();
return _ATOK;
}
*/
break;
case _ATCIPSTATUS:
if(strstr(buff, "OK"))
{
/*
AT+CIPSTATUS
STATUS:3
+CIPSTATUS:0,"TCP","192.168.4.100",60154,1
+CIPSTATUS:2,"TCP","192.168.10.75",8080,0
OK
*/
Server_Link_id = ERROR_LINK_ID;
Client_Link_id = ERROR_LINK_ID;
p2 = strstr(buff,"+CIPSTATUS:");
while(p2)
{
//读取一行数据
for(i = 0; (*p2 != '\n') && (i<99); i++, p2++) {
node = *p2;
}
node='\0';
p2++;
//printf("Read Link ID:[%s]\r\n",node);
if(strstr(node,"OK")) break;
else if((p = (char *)strstr(node,"+CIPSTATUS:")) != 0)//提取出连接ID
{
p+=11;
//if(strstr(node,(char *)UserConfig[SER_IP])) {
if(strstr(node,"192.168.10.71")) {
Server_Link_id = *p - '0';
printf("Server_Link_id:[%d]\r\n",Server_Link_id);
} else {
Client_Link_id = *p - '0';
printf("Client_Link_id:[%d]\r\n",Client_Link_id);
}
}break;
}
ret = _ATOK;
goto ESP8266_SENDATRET;
}else if(strstr(buff, "ERROR")) {
ret = _ATERROR;
goto ESP8266_SENDATRET;
}
break;
default: ret = _ATERROR; goto ESP8266_SENDATRET;
}
}
ESP8266_SENDATRET:
return ret;
}
/*********************************************************
* @function ESP8266_ExecuteOrder
* @role 执行命令
* @input None
* @output None
* @return 成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
********************************************************/
static s8 ESP8266_ExecuteOrder(char *Order, int len, enum order type, int num, char *pOut)
{
int i = 0;
int delay_time = 1000;
s8 ret = _ATOTIME;
struct WifiData wifi;
if((type == _ATCWLAPx) || (type == _ATCWJAPj) || (type == _ATDATA))
delay_time = 10000;
wifi.order = Order;
wifi.olen = len;
wifi.type = type;
while((ret = SendAT(&wifi, pOut, delay_time)) != _ATOK)
{
if(ret == _ATERROR) {
if(++i >= num) return _ATERROR;
delay_s(1);
}else return _ATOTIME;
}
return _ATOK;
}
/*********************************************************
* @function ESP8266_init
* @role WIFI初始化
* @input None
* @output None
* @return 成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
********************************************************/
s8 ESP8266_init(char type)
{
char at_wifi[100]="";
s8 ret = _ATOTIME;
// 复位
if(_ATOK != (ret = ESP8266_ExecuteOrder(ATRES, strlen(ATRES), _ATRES, 2, NULL)))
goto ESP8266_INITRET;
// 设置工作模式
sprintf(at_wifi, ATCWMODE, (type == MODE_DTU)? MODE_ST: type);
if(_ATOK != (ret = ESP8266_ExecuteOrder(at_wifi, strlen(at_wifi), _ATCWMODE, 2, NULL)))
goto ESP8266_INITRET;
ret = _ATOK;
ESP8266_INITRET:
return ret;
}
/*********************************************************
* @function ESP8266_list_wifi
* @role 获取无线列表
* @input None
* @output 列表数目
* @return 成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
********************************************************/
/*
s8 ESP8266_list_wifi(int *pWifiNum)
{
int i=0;
char num[20]="";
struct WifiData wifi;
// 显示无线列表
wifi.order = ATCWLAPx;
wifi.olen = strlen(ATCWLAPx);
wifi.type = _ATCWLAPx;
while(_ATERROR == SendAT(&wifi, &num, 1000)) {
if(3 < i++) return -1;
}
*pWifiNum = atoi(num);
return 0;
}
*/
/*********************************************************
* @function ESP8266_SearchWifiName
* @role 查找某个wifi信号
* @input 要查找的名字
* @output None
* @return 成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
********************************************************/
s8 ESP8266_SearchWifiName(char *pWifi)
{
char cwm = 0;
char at_wifi[100] = "";
s8 ret = _ATOTIME;
if(pWifi == NULL) return -1;
strcpy((char *)SearchWifiName,(char *)pWifi);
// 查询工作模式,如果不是AP兼station模式,就进行修改
if(_ATOK != (ret = ESP8266_ExecuteOrder(ATCWMODE_CX, strlen(ATCWMODE_CX), _ATCWMODE_CX, 2, &cwm)))
goto ESP8266_SEARCHWIFINAME_END;
if(cwm != '3')
{
// 设置工作模式
sprintf((char *)at_wifi, (char *)ATCWMODE, MODE_SA);
if(_ATOK != (ret = ESP8266_ExecuteOrder(at_wifi, strlen(at_wifi), _ATCWMODE, 2, NULL)))
goto ESP8266_SEARCHWIFINAME_END;
}
// 查询WIFI
cwm = 0;
if(_ATOK != (ret = ESP8266_ExecuteOrder(ATCWLAPx, strlen(ATCWLAPx), _ATCWLAPx, 2, &cwm)))
goto ESP8266_SEARCHWIFINAME_END;
if(cwm == '1') ret = _ATOK;
else ret = _ATERROR;
ESP8266_SEARCHWIFINAME_END:
return ret;
}
/*********************************************************
* @function ESP8266_TCP_Client
* @role 连接到wifi和服务器,当服务器端口为0时,只连接到wifi
* @input wifi名字、密码、服务器IP、服务器端口
* @output None
* @return 成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
********************************************************/
s8 ESP8266_TCP_Client(struct ESP8266_Config *WifiConfig, char muxlock)
{
char at_wifi[100] = "";
s8 ret = _ATOTIME;
if( WifiConfig->wifi_ssid == NULL ||
WifiConfig->wifi_pass == NULL ||
WifiConfig->server_ip == NULL)
return ret;
if( !strlen(WifiConfig->wifi_ssid) ||
!strlen(WifiConfig->wifi_pass) ||
!strlen(WifiConfig->server_ip))
return ret;
// 连接到wifi
sprintf((char *)at_wifi,(char *)ATCWJAPj,WifiConfig->wifi_ssid, WifiConfig->wifi_pass);
if(_ATOK != (ret = ESP8266_ExecuteOrder(at_wifi, strlen(at_wifi), _ATCWJAPj, 2, NULL)))
goto ESP8266_TCP_CLIENTRET;
// 开启多连模式
if(muxlock)
{
if(_ATOK != (ret = ESP8266_ExecuteOrder(ATCIPMUX, strlen(ATCIPMUX), _ATCIPMUX, 2, NULL)))
goto ESP8266_TCP_CLIENTRET;
}
if(WifiConfig->server_port != 0)
{
// 连接服务器
sprintf(at_wifi,ATCIPSTART(1),WifiConfig->server_ip, WifiConfig->server_port);
if(_ATOK != (ret = ESP8266_ExecuteOrder(at_wifi, strlen(at_wifi), _ATCIPSTART, 2, NULL)))
goto ESP8266_TCP_CLIENTRET;
/* 查询出服务器连接ID号 */
if(_ATOK != (ret = ESP8266_ExecuteOrder(ATCIPSTATUS, strlen(ATCIPSTATUS), _ATCIPSTATUS, 2, NULL)))
goto ESP8266_TCP_CLIENTRET;
}
ESP8266_TCP_CLIENTRET:
return ret;
}
[/mw_shl_code]
后面还有下半部分,回复有字数限制,我分开发 |
|