ESP8266 WIFI模块的各功能实现,基于MSP430f149

文章目录

  • 一.模块功能介绍
    • 1.基本概况
    • 2.实现的几个基本功能
  • 二.各功能实现代码(基于MSP430f149)
    • 1.main.c
    • 2. Config.h及Config.c
    • 3.ESP8266.h及ESP8266.c
    • 4.AP.c源码
    • 5.STA.c源码
    • 6.AP+STA.c源码
    • 7.SNTP.c源码
    • 8.SMTP.h及SMTP.c

一.模块功能介绍

1.基本概况

ESP8266 是一款高性能的 UART-WiFi(串口-无线)模块,ATK-ESP8266 模块采用串口(LVTTL)与 MCU(或其他串口设备)通信,内置TCP/IP 协议栈,能够实现串口与 WIFI 之间的转换。通过 ESP8266 模块,传统的串口设备只是需要简单的串口配置,即可通过网络(WIFI)传输自己的数据。便的与你的产品进行连接。模块支持串口转WIFI STA、串口转AP和WIFI STA+WIFI模式。通俗来说,该模块通过串口与单片机进行连接(采用AT指令开发方式),通过该模块使得单片机能够联网,从而实现多种网络通信功能,以下一一进行介绍。

2.实现的几个基本功能

  • STA 模式:ESP8266 模块通过路由器连接互联网(局域网),手机或电脑通过互联网(连接同一个局域网)实现对设备的远程控制。
  • AP 模式:默认模式 ATK_ESP8266 模块作为热点,实现手机或电脑直接与模块通信,实现局域网无线控制。
  • STA+AP 模式:两种模式的共存模式,(STA 模式)即可以通过路由器连接到互联网,并通过互联网控制设备;(AP 模式)也可作为 wifi 热点,其他 wifi设备连接到模块。这样实现局域网和广域网的无缝切换,方便操作。
  • SNTP模式:通过SNTP网络协议获取实时网络时间,可作为基准对单片机的RTC时钟进行校正。
  • SMTP模式:通过SMTP网络邮箱协议使用单片机完成发邮件操作

二.各功能实现代码(基于MSP430f149)

各源文件与头文件分类及实现功能如下:
1.main.c(主程序)
2.Config.h
Config.c(基础配置文件,包括IO口初始化,按键扫描,串口,时钟等基础配置)
3.ESP8266.h
ESP8266.c(ESP8266模块配置的基本文件,包括一些基本配置函数)
4.AP.c(AP模式测试源代码)
5.STA.c(STA模式测试源代码)
6.AP+STA.c(AP+STA模式配置源代码)
7.SNTP.c(SNTP实时网络时间获取源代码)
8.SMTP.c(SMTP邮件发送源代码)

1.main.c

#include"ESP8266.h"
/*******************************
解释说明:设备联网之后有两种方式进行通信:1.在局域网内通过各局域网设备的ip地址进行访问 2.通过NAT连接外网云端服务器,此时ESP8266做TCP客户端
1.任一个设备连上一个wifi都会被自动分配一个IP地址
2.使用配网功能可以获取实时网络时间,使用SNTP协议
3.在STA模式下,先让模块联网,做TCP客户端,通过网络连接远程云端服务器
安信可透传云:http://tt.ai-thinker.com:8000/ttcloud
合宙云端服务器:http://tcplab.openluat.com/
配置步骤:设置为STA模式-->通过WIFI联网-->作为客户端时通过IP访问服务器(可以在局域网内访问,也可以通过NAT连接外网访问云端服务器)
4.可用于连接SMTP服务器来进行邮件发送,发送步骤如下:ESP8266模块初始化-->模块连接IP热点-->连接SMTP服务器-->和服务器打招呼-->请求登录-->输入用户名
-->输入密码-->输入信封发件人-->输入信封收件人-->通知服务器开始输入邮件内容-->输入内容(发送成功)-->结束和远程服务器的TCP连接
**********************************/

/*定义邮件标题和正文(发送邮件测试时用到)*/
//#define  Header_Title  "Test Masseage"                  //当用于发送邮件时的主题
//#define  Body_Content  "this is a test massseage!"  //当用于发送邮件时的正文

void main(void)
{ 
       	u8 key;
	    u8 timex;
        WDT_Init_OFF();              //设置看门狗为关闭状态
        Clock_Init_XT2();            //系统时钟初始化函数,XT2
        Port_Init();                 //P6口初始化,包括LED和按键KEY
        UART0_Init();                 //MSP430串口0初始化(串口0主要用于打印显示一些数据信息)
        UART1_Init();                 //MSP430串口1初始化(串口1主要用于和ESP8266模块之间进行通信)
        
        printf("ATK-ESP8266 WIFI模块测试\n");
	while(atk_8266_send_cmd("AT","OK",20))//检查WIFI模块是否在线
	{
		atk_8266_quit_trans();//退出透传
		atk_8266_send_cmd("AT+CIPMODE=0","OK",200);  //关闭透传模式
                printf("未检测到模块!!!\n");
		delay_ms(800);
                printf("尝试连接模块...\n");
	} 
	/*单片机发送邮件测试*/
//        if(sendEmail("[email protected]",Header_Title,Body_Content)!=0) //用作发送邮件,其中输入的地址为接收方的地址
//        {
//          printf("send email1 ok!\n");
//        }else 
//        {
//          printf("send email1 no!\n");
//        }
	while(atk_8266_send_cmd("ATE0","OK",20));//关闭回显
        //AP,STA,AP+STA三种模式测试
        printf("请选择:\n");
        printf("S1:WIFI AP\n");
        printf("S2:WIFI STA\n");
        printf("S3:WIFI AP+STA\n");
	while(1)
        {
		atk_8266_at_response(1);    //检查ATK-ESP8266模块发送过来的数据,及时上传给电脑
		key=KEY_Scan(0);           //按键扫描以确定进入哪种测试模式
		if(key)
		{
                      switch(key)
                      {
                      case S1_PRE://S1_PRE:进入AP测试状态
                        printf("ATK-ESP WIFI-AP 测试\n");
                        printf("正在配置ATK-ESP8266模块,请稍等...\n");
                        atk_8266_wifiap_test();	//WIFI AP测试
                        break;
                      case S2_PRE://S2_PRE:进入STA测试状态
                        printf("ATK-ESP WIFI-STA 测试\n");
                        printf("正在配置ATK-ESP8266模块,请稍等...\n");
                        atk_8266_wifista_test();//WIFI STA测试
                        break;
                      case S3_PRE://S3_PRE:进入AP+STA测试状态
                        printf("ATK-ESP WIFI-AP+STA 测试\n");
                        printf("正在配置ATK-ESP8266模块,请稍等...\n");
                        atk_8266_apsta_test();	//WIFI AP+STA测试
                        break;
                      }
                        printf("ATK_ESP8266 WIFI模块测试\n");
                        printf("请选择:\n");
                        printf("S1:WIFI AP\n");
                        printf("S2:WIFI STA\n");
                        printf("S3:WIFI AP+STA\n");
			timex=0;
		} 	 
		if((timex%20)==0)
                  P6OUT^=BIT7;//200ms闪烁 
		timex++;
        //sntp_test(); //获取实时网络时间测试(测试时只需把前面注释掉,执行该函数即可)
        }
}

2. Config.h及Config.c

/*************************Config.h*********************************/
#define u8  unsigned char  //无符号8位宏定义
#define u16 unsigned long //无符号16位宏定义
#define u32 unsigned int  //无符号32位宏定义
#define CPU_F         ((double)8000000)                                   //内部延时函数所需的时钟大小,单位为Hz
#define delay_ms(x)   __delay_cycles((long)(CPU_F*(double)x/1000.0))      //调用系统自定义函数__delay_cycles计算时钟
#define delay_us(x)   __delay_cycles((long)(CPU_F*(double)x/1000000.0))   //调用系统自定义函数__delay_cycles计算时钟
#define S1_PRE 1       //按键S1
#define S2_PRE 2       //按键S2
#define S3_PRE 3       //按键S3
#define S4_PRE 4       //按键S4

void WDT_Init_OFF();//看门狗初始化函数,关闭看门狗

void Port_Init();//IO口配置,包括LED和按键

u8 KEY_Scan(u8 mode);//*按键扫描函数,返回按键值,mode:0:不支持连按;1:支持连按

/*****************************定时器配置**************************************************/
void TimerA_Init_MC0(void);//TIMERA初始化程序,增计数模式MC0

void TimerA_Init_MC1(void);//TIMERA初始化程序,连续计数模式MC1

/*****************************串口配置****************************************************/
//串口波特率计算,当BRCLK=CPU_F时用下面的公式可以计算,否则要根据设置加入分频系数
#define baud           115200                                //设置波特率的大小
#define baud_setting   (u32)((u16)CPU_F/((u16)baud))  //波特率计算公式
#define baud_h         (u8)(baud_setting>>8)            //提取高位
#define baud_l         (u8)(baud_setting)               //低位

/***********************MSP430串口0初始化*************************/
extern u8 USART_RX_BUF[200];                                //串口0接收缓冲区,最大200个字节
extern u32 USART_RX_COUNT;                                //串口0接收字节计数

extern u8 USART1_RX_BUF[200];                                //串口1接收缓冲区,最大200个字节
extern u32 USART1_RX_COUNT;                                //串口1接收字节计数
extern u8 USART1_TX_BUF[200]; 	                              //串口1最大发送字节缓存区

void UART0_Init();//MSP430串口0初始化

void Send_Byte(u8 data);//串口0发送数据函数

u8 UART0_RX_SR(void);//判断串口0是否接收完成

/***********************MSP430串口1初始化*************************/
void UART1_Init();//MSP430串口1初始化

void UART1_Setbaud(u16 bps);    //串口1设置波特率函数

void UART1_Send_Byte(u8 data);//串口1发送数据函数

u8 UART1_RX_SR(void);//判断串口1是否接收完成

//串口1,printf函数
//确保一次性发送的数据不超过200个字节
void u3_printf(char* fmt,...);

int putchar(int c);//向终端输出一个字符,为了支持printf函数
/*****************************时钟配置***********************************************************/
void Clock_Init_DCO();//设置内部DCO振荡器初始化函数

void Clock_Init_XT2();//设置外部高频XT2振荡器时钟初始化函数

void Clock_Init_XT1();//设置外部低频XT1振荡器时钟初始化函数



/*************************Config.c*********************************/
#include"stdarg.h"	 	 
#include"stdio.h"
#include"string.h"
#include"Config.h"
#include

u8 INT_flag=0;                                        //定时器中断标志

u8 USART_RX_BUF[200];                                //串口0接收缓冲区,最大200个字节
u32 USART_RX_COUNT=0;                                //串口0接收字节计数

u8 USART1_RX_BUF[200];                                //串口1接收缓冲区,最大200个字节
u32 USART1_RX_COUNT=0;                                //串口1接收字节计数
u8 USART1_TX_BUF[200]; 	                              //串口1最大发送字节缓存区

/*****************************看门狗配置**************************************************/
//看门狗初始化函数,关闭看门狗
void WDT_Init_OFF()
{
  WDTCTL=WDTPW+WDTHOLD;        //将WDTCTL寄存器的WDTPW和WDTHOLD位置1
}
/*****************************IO口配置,包括LED和按键****************************************************/
void Port_Init()
{
  P1SEL = 0x00;                   //P1普通IO功能,KEY,KEY,KEY
  P1DIR = 0xF0;                   //P10~P13输入模式,外部电路已接上拉电阻
  
  P6SEL = 0x00;                   //P6口普通IO功能,LED,LED,LED
  P6DIR = 0xFF;                   //P6口输出模式
  P6OUT = 0XFF;                   //设置P6初始值输出为0xFF
}
/******************************按键扫描函数,返回按键值,mode:0:不支持连按;1:支持连按***********************/
u8 KEY_Scan(u8 mode)
{	 
    u8 key_check;
	static u8 key_up=1;//按键松开标志
	if(mode)key_up=1;  //支持连按		  
    key_check=P1IN;  //读取IO口状态
    key_check &= 0x0F; 
	if(key_up&&key_check!=0x0F) //判断是否有键按下
	{
	    delay_ms(10);//键盘消抖,延时10MS
        key_up=0;    
	    if(key_check==0x0E)return 1;
	    else if(key_check==0x0D)return 2;
	    else if(key_check==0x0B)return 3;
        else if(key_check==0x07)return 4;
	}
        else if(key_check!=0x0E&&key_check!=0x0D&&key_check!=0x0B&&key_check!=0x07)key_up=1;//必须确认按键全部松开,才能使按键松开标志置1,很重要!!!	    
 	    return 0;//无按键按下
}
/*****************************定时器配置**************************************************/
//TIMERA初始化程序,增计数模式MC0
void TimerA_Init_MC0(void)
{
      TACTL=TASSEL0+TACLR;       //设置时钟源来自ACLK=32.768KHz,并清零计数器,需要先初始化时钟XT1
      TACTL |= MC0;              //设置增计数模式MC0
      TACCR0=32768-1;           //设置计时时间为一秒:32768/32768s
      TACTL |= TAIE;            //允许计时器溢出中断
      _EINT();                  //开总中断
}
//TIMERA初始化程序,连续计数模式MC1
void TimerA_Init_MC1(void)
{
      TACTL=TASSEL0+TACLR;       //设置时钟源来自ACLK=32.768KHz,并清零计数器,需要先初始化时钟XT1
      TACTL |= MC1;              //设置增计数模式MC1,65535/32768s
      TACTL |= TAIE;            //允许计时器溢出中断
      _EINT();                  //开总中断
}
//中断服务子函数
#pragma vector=TIMERA1_VECTOR             
__interrupt void TIMERA_IRQ(void)
{
    switch(TAIV)                //需要判断中断的类型
  {
  case 2:break;
  case 4:break;
  case 10:INT_flag=1;break;     //设置标志位Flag
  }
}
/*****************************串口0配置****************************************************/
/MSP430串口0初始化
void UART0_Init()
{
  U0CTL|=SWRST;               //复位SWRST
  U0CTL|=CHAR;                //8位数据模式 
  U0TCTL|=SSEL1;              //SMCLK为串口时钟
  U0BR1=baud_h;               //BRCLK=8MHZ,Baud=BRCLK/N
  U0BR0=baud_l;               //N=UBR+(UxMCTL)/8
  U0MCTL=0x00;                //微调寄存器为0,波特率9600bps
  ME1|=UTXE0;                 //UART0发送使能
  ME1|=URXE0;                 //UART0接收使能
  U0CTL&=~SWRST;
  //IE1|=URXIE0;                //接收中断使能位
  
  P3SEL|= BIT4 + BIT5;        //设置3.4,3.5为功能端口,UART口功能
  P3DIR|= BIT4;               //设置3.4口方向为输出
}
//串口0发送数据函数
void Send_Byte(u8 data)
{
    U0TXBUF=data;
    while((IFG1&UTXIFG0)==0);          //等待中断标志位复位,应该会自动复位
}
//处理来自串口 0 的接收中断
#pragma vector=UART0RX_VECTOR
__interrupt void UART0_RX_ISR(void)
{
  USART_RX_BUF[USART_RX_COUNT]=U0RXBUF;  //将收到的数据放在缓存区
  USART_RX_COUNT++;                  //收到的字节数加一
}
//判断串口0是否接收完成
u8 UART0_RX_SR(void)             
{
   u32 temp=0;
   temp=USART_RX_COUNT;                //当前计数值赋给temp
   delay_ms(10);                       //延时用来判断接收是否完成
   if(temp==USART_RX_COUNT&&USART_RX_COUNT!=0)            //判断计数值是否等于当前值,即判断是否接收完成
     return 1;                         //接收完成,返回1
   else 
     return 0;                         //未接收完成,返回0
}
//处理来自串口 0 的发送中断,预留
#pragma vector=UART0TX_VECTOR
__interrupt void UART0_TX_ISR(void)
{
  
}
//向终端输出一个字符,为了支持printf函数
int putchar(int c)
{
     if(c=='\n')
     {
        U0TXBUF='\r';
        while((IFG1&UTXIFG0)==0);        //发送寄存器空的时候发送数据
     }
     U0TXBUF=c;
     while((IFG1&UTXIFG0)==0);          //发送寄存器空的时候发送数据
     
     return c;
}
/*****************************串口1配置****************************************************/
void UART1_Init()
{
  U1CTL|=SWRST;               //复位SWRST
  U1CTL|=CHAR;                //8位数据模式 
  U1TCTL|=SSEL1;              //SMCLK为串口时钟
  U1BR1=baud_h;               //BRCLK=8MHZ,Baud=BRCLK/N
  U1BR0=baud_l;               //N=UBR+(UxMCTL)/8
  U1MCTL=0x00;                //微调寄存器为0,波特率9600bps
  ME2|=UTXE1;                 //UART1发送使能
  ME2|=URXE1;                 //UART1接收使能
  U1CTL&=~SWRST;
  IE2|=URXIE1;                //接收中断使能位
  _EINT();                   //开中断 ,为串口接收中断服务
  
  P3SEL|= BIT6 + BIT7;        //设置3.4,3.5为功能端口,UART口功能
  P3DIR|= BIT6;               //设置3.4口方向为输出
}

void UART1_Setbaud(u16 bps)    //串口1设置波特率函数
{
  u32 baud_set=(u32)((u16)CPU_F/((u16)bps));  //波特率计算公式
  u8 bps_h=(u8)(baud_set>>8);                 //提取高位
  u8 bps_l=(u8)(baud_set);                    //低位
  U1BR1=bps_h;                                //BRCLK=8MHZ,Baud=BRCLK/N
  U1BR0=bps_l;                                //N=UBR+(UxMCTL)/8
  U1MCTL=0x00;                                //微调寄存器为0
}

//串口1发送数据函数
void UART1_Send_Byte(u8 data)
{
    U1TXBUF=data;
    while((IFG2&UTXIFG1)==0);          //等待中断标志位复位,应该会自动复位
}
//处理来自串口 1 的接收中断
#pragma vector=UART1RX_VECTOR
__interrupt void UART1_RX_ISR(void)
{
  USART1_RX_BUF[USART1_RX_COUNT]=U1RXBUF;  //将收到的数据放在缓存区
  USART1_RX_COUNT++;                  //收到的字节数加一
}
//判断是否接收完成
u8 UART1_RX_SR(void)             
{
   u32 temp=0;
   temp=USART1_RX_COUNT;                //当前计数值赋给temp
   delay_ms(10);                       //延时用来判断接收是否完成
   if(temp==USART1_RX_COUNT&&USART1_RX_COUNT!=0)            //判断计数值是否等于当前值,即判断是否接收完成
     return 1;                         //接收完成,返回1
   else 
     return 0;                         //未接收完成,返回0
}
//处理来自串口 1 的发送中断,预留
#pragma vector=UART1TX_VECTOR
__interrupt void UART1_TX_ISR(void)
{
  
}
//串口1数据发送函数(主要用来和ESP8266之间的通信)
//确保一次性发送的数据不超过200个字节
void u3_printf(char* fmt,...)  
{  
	u16 i,j;
	va_list ap;
	va_start(ap,fmt);
	vsprintf((char*)USART1_TX_BUF,fmt,ap);
	va_end(ap);
	i=strlen((const char*)USART1_TX_BUF);//得到此次发送数据的长度
	for(j=0;j<i;j++)                      //循环发送数据
	{
	      U1TXBUF=USART1_TX_BUF[j];
              while((IFG2&UTXIFG1)==0);      //等待中断标志位复位,应该会自动复位
	}
}
/*****************************时钟配置***********************************************************/
//设置内部DCO振荡器初始化函数
void Clock_Init_DCO()              
{
  DCOCTL=DCO0+DCO1+DCO2;       //DCO选为最大的频率,0,1,2三位均输出为1
  BCSCTL1|=XT2OFF;             //关闭外部高频晶体
  BCSCTL1=RSEL0+RSEL1+RSEL2;   //最大标称频率,大概5MHz
}
//设置外部高频XT2振荡器时钟初始化函数
void Clock_Init_XT2()
{
   u8 i;
   BCSCTL1 &=~XT2OFF;           //打开XT2晶振,XT2OFF写0
   BCSCTL2 |=SELM1+SELS;        //MCLK=SMCLK=XT2,8MHz,0x80+0x08
   /*判断晶振是否稳定*/
   do
   {
   IFG1 &=~OFIFG;               //清除OFIFG标志位
   for(i=0;i<100;i++)           //等待晶振稳定
   _NOP();
   }
   while((IFG1 & OFIFG)!=0);
   IFG1 &=~OFIFG;               //清除OFIFG标志位
}
//设置外部低频XT1振荡器时钟初始化函数
void Clock_Init_XT1()
{
   u8 i;
   BCSCTL1 |= XT2OFF;           //关闭XT2晶振,XT1默认打开
   BCSCTL2 |=SELM1+SELM0;       //MCLK=XT1,32.768KHz,0x80+0x40,SMCLK默认来自DCO备注:SMCLK时钟不能由XT1提供!!!!!!!
     /*判断晶振是否稳定*/
   do
   {
   IFG1 &=~OFIFG;               //清除OFIFG标志位
   for(i=0;i<100;i++)           //等待晶振稳定
   _NOP();
   }
   while((IFG1 & OFIFG)!=0);
   IFG1 &=~OFIFG;               //清除OFIFG标志位
}



3.ESP8266.h及ESP8266.c

/*************************ESP8266.h*********************************/
#include
#include"stdio.h"         //为了支持printf函数
#include"Config.h"
#include"string.h"

//用户配置区
//4个网络模式
extern const u8 *ATK_ESP8266_CWMODE_TBL[3];	//ATK-ESP8266,3种网络模式,默认为路由器(ROUTER)模式 
//4种工作模式
extern const u8 *ATK_ESP8266_WORKMODE_TBL[3];	//ATK-ESP8266,4种工作模式
//5种加密方式
extern const u8 *ATK_ESP8266_ECN_TBL[5];
//连接端口号:8086,可自行修改为其他端口.
extern const u8* portnum;		 
//定义STA模式下的外部IP地址,若为动态IP地址,则需每次开机查看并修改该ip
extern const u8 *IP_address;
//WIFI STA模式,设置要去连接的路由器无线参数,请根据你自己的路由器设置,自行修改.
extern u8* wifista_ssid;			 //路由器SSID号
extern u8* wifista_encryption;	     //wpa/wpa2 aes加密方式
extern u8* wifista_password; 	    //连接密码

//WIFI AP模式,模块对外的无线参数,可自行修改.
extern const u8* wifiap_ssid;			//对外SSID号
extern const u8* wifiap_encryption;  	//wpa/wpa2 aes加密方式
extern const u8* wifiap_password; 		//连接密码 

u8 atk_8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime);//向ATK-ESP8266发送命令

u8* atk_8266_check_cmd(u8 *str);//ATK-ESP8266发送命令后,检测接收到的应答

u8 atk_8266_quit_trans(void);//ATK-ESP8266退出透传模式

void atk_8266_at_response(u8 mode);//将收到的AT指令应答数据返回给电脑串口

u8 atk_8266_netpro_sel(u8* name);//工作模式选择

void atk_8266_get_wanip(u8* ipbuf);//获取作为服务器端的地址(IP或STA模式下有效)

void atk_8266_get_ip(u8* AP_ipbuf,u8* STA_ipbuf);//获取作为服务器端的地址(IP+STA模式下有效)

void atk_8266_wificonf_show(u8* rmd,u8* ssid,u8* encryption,u8* password);//ATK-ESP8266模块WIFI配置参数显示(仅WIFI STA/WIFI AP模式测试时使用)

u8 atk_8266_send_data(u8 *data,u8 *ack,u16 waittime);//向ATK-ESP8266发送指定数据

u8 atk_8266_consta_check(void);//获取ATK-ESP8266模块的连接状态

void atk_8266_wifiap_test(void);//ATK-ESP8266 WIFI AP测试

void atk_8266_wifista_test(void);//ATK-ESP8266 WIFI STA测试

void atk_8266_apsta_test(void);//ATK-ESP8266 AP+STA模式测试

void direction_send_data(u8* p);//定向传输数据

void transparent_send_data(u8* p);//透明传输数据

void sntp_test(void);	//获取实时网络时间测试

u8 sendEmail(char* email_addr,char* subject,char* content);	//单片机发送邮件测试

static void codeBase64(char* basestr,char* str);//对字符串进行BASE64编码

u8 disconnectServer(void);            //断开连接

void initESP8266(void);//初始化ESP8266

void connectAP(u8* ssid,u8* pwd);//连接热点




/*************************ESP8266.c*********************************/
#include"ESP8266.h"

//用户配置区
//4个网络模式
const u8 *ATK_ESP8266_CWMODE_TBL[3]={"STA模式 ","AP模式 ","AP&STA模式 "};	//ATK-ESP8266,3种网络模式,默认为路由器(ROUTER)模式 
//4种工作模式
const u8 *ATK_ESP8266_WORKMODE_TBL[3]={"TCP服务器","TCP客户端"," UDP 模式"};	//ATK-ESP8266,4种工作模式
//5种加密方式
const u8 *ATK_ESP8266_ECN_TBL[5]={"OPEN","WEP","WPA_PSK","WPA2_PSK","WPA_WAP2_PSK"};

/*************该部分为联网配置,STA模式的第一步********************/
//WIFI STA模式,设置要去连接的路由器无线参数,请根据你自己的路由器设置,自行修改.
u8* wifista_ssid="VTU";			//路由器SSID号
u8* wifista_encryption="wpawpa2_aes";	//wpa/wpa2 aes加密方式
u8* wifista_password="vtu50563008"; 	//连接密码
/*********************************/

/*************该部分为连接服务器ip,STA模式的第二步********************/
//连接端口号:8086,可自行修改为其他端口.
const u8* portnum="50588";		 
//定义STA模式下的外部IP地址,若为动态IP地址,则需每次开机查看并修改该ip
const u8 *IP_address="180.97.81.180";
/*********************************/

//WIFI AP模式,模块对外的无线参数,可自行修改.
const u8* wifiap_ssid="ATK-ESP8266";			//对外SSID号
const u8* wifiap_encryption="wpawpa2_aes";	//wpa/wpa2 aes加密方式
const u8* wifiap_password="12345678"; 		//连接密码 

//向ATK-ESP8266发送命令
//cmd:发送的命令字符串
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果)
//       1,发送失败
u8 atk_8266_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
	u8 res=0; 
	USART1_RX_COUNT=0;              //串口1接受数据清零
	u3_printf("%s\r\n",cmd);	//发送命令
	if(ack&&waittime)		//需要等待应答
	{
		while(--waittime)	//等待倒计时
		{
			delay_ms(10);
			if(UART1_RX_SR())//接收到期待的应答结果
			{
                            if(atk_8266_check_cmd(ack))
                            {
                              printf("%s_ack:%s\r\n",cmd,(u8*)ack);
                              break;//得到有效数据 
                            }
			    USART1_RX_COUNT=0;//串口1接受数据清零
			} 
		}
		if(waittime==0)res=1; 
	}
	return res;
} 
//ATK-ESP8266发送命令后,检测接收到的应答
//str:期待的应答结果
//返回值:0,没有得到期待的应答结果
//    其他,期待应答结果的位置(str的位置)
u8* atk_8266_check_cmd(u8 *str)
{
	char *strx=0;
	if(UART1_RX_SR())		//接收到一次数据了
	{ 
		USART1_RX_BUF[USART1_RX_COUNT]=0;//添加结束符
		strx=strstr((const char*)USART1_RX_BUF,(const char*)str);
	} 
	return (u8*)strx;
}
//ATK-ESP8266退出透传模式
//返回值:0,退出成功;
//       1,退出失败
u8 atk_8266_quit_trans(void)
{
	while((IFG2&UTXIFG1)==0);      //等待中断标志位复位,等待发送空
	U1TXBUF='+';     
	delay_ms(15);					//大于串口组帧时间(10ms)
	while((IFG2&UTXIFG1)==0);      //等待中断标志位复位,等待发送空
	U1TXBUF='+';     
	delay_ms(15);					//大于串口组帧时间(10ms)
	while((IFG2&UTXIFG1)==0);      //等待中断标志位复位,等待发送空
	U1TXBUF='+';    
	delay_ms(500);					//等待500ms
	return atk_8266_send_cmd("AT","OK",20);//退出透传判断.
}
//将收到的AT指令应答数据返回给电脑串口
//mode:0,不清零USART1_RX_STA;
//     1,清零USART1_RX_STA;
void atk_8266_at_response(u8 mode)
{
	if(UART1_RX_SR())		//接收到一次数据了
	{ 
		USART1_RX_BUF[USART1_RX_COUNT]=0;//添加结束符
		printf("收到的数据:%s",USART1_RX_BUF);	//发送到串口
		if(mode)USART1_RX_COUNT=0;
	} 
}

//工作模式选择
//返回值:
//0,TCP服务器
//1,TCP客户端
//2,UDP模式
u8 atk_8266_netpro_sel(u8* name) 
{
	u8 key=0,t=0;
        printf("工作模式选择:%s\n",name);
        printf("请按按键选择工作方式:\n");
        printf("S1:TCP服务器\n");
        printf("S2:TCP客户端\n");
        printf("S3:UDP模式\n");
	while(1)
	{
		key=KEY_Scan(0); 
		if(key)
		{
                      switch(key)
                      {
                      case S1_PRE://S1_PRE:TCP服务器
                        printf("选择了TCP服务器模式\n");
                        return 0;
                        break;
                      case S2_PRE://S2_PRE:TCP客户端
                        printf("选择了TCP客户端模式\n");
                        return 1;
                        break;
                      case S3_PRE://S3_PRE:UDP模式
                        printf("选择了UDP模式模式\n");
                        return 2;
                        break;
                      }
		} 
		delay_ms(10);
		if((t++)==20){t=0;P6OUT^=BIT0;}//LED闪烁
	} 
} 
//获取作为服务器端的地址(IP或STA模式下有效)
//ipbuf:ip地址输出缓存区
void atk_8266_get_wanip(u8* ipbuf)
{
	u8 *p,*p1;
        if(atk_8266_send_cmd("AT+CIFSR","OK",50))//获取WAN IP地址失败
        {
          ipbuf[0]=0;
          printf("获取WAN IP地址失败\n");
          return;
        }		
        p=atk_8266_check_cmd("\"");             //否则获取成功
        p1=(u8*)strstr((const char*)(p+1),"\"");
        *p1=0;
        sprintf((char*)ipbuf,"%s",p+1);	
        printf("获取WAN IP地址成功\n");
}
//获取作为服务器端的地址(IP+STA模式下有效)
//ipbuf:ip地址输出缓存区
void atk_8266_get_ip(u8* AP_ipbuf,u8* STA_ipbuf)
{
      u8 *p;
      u8 *p1;
      u8 *p2;
      u8 *ipbuf;
      if(atk_8266_send_cmd("AT+CIFSR","OK",50))//获取WAN IP地址失败
      { 
          printf("获取WAN IP地址失败\n");
          return;
      }
      else
      {		
        p=atk_8266_check_cmd("APIP,\"");
        p1=(u8*)strstr((const char*)(p+6),"\"");
        p2=p1;
        *p1=0;
        ipbuf=p+6;
        sprintf((char*)AP_ipbuf,"%s",ipbuf);//AP模式的IP地址存放在AP_ipbuf区
        p=(u8*)strstr((const char*)(p2+1),"STAIP,\"");
        p1=(u8*)strstr((const char*)(p+7),"\"");
        *p1=0;
        ipbuf=p+7;
        sprintf((char*)STA_ipbuf,"%s",ipbuf);//AP模式的IP地址存放在AP_ipbuf区
        printf("获取WAN IP地址成功:\n");
      } 
}
//ATK-ESP8266模块WIFI配置参数显示(仅WIFI STA/WIFI AP模式测试时使用)
//rmd:提示信息
//ssid,encryption,password:无线网络的SSID,加密方式,密码
void atk_8266_wificonf_show(u8* rmd,u8* ssid,u8* encryption,u8* password)
{ 
         printf("%s\n",rmd);
         printf("SSID:%s\n",ssid);
         printf("加密方式:%s\n",encryption);
         printf("密码:%s\n",password);	  
}
//向ATK-ESP8266发送指定数据
//data:发送的数据(不需要添加回车了)
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果)luojian
u8 atk_8266_send_data(u8 *data,u8 *ack,u16 waittime)
{
	u8 res=0; 
	USART1_RX_COUNT=0;       //串口1发送数据个数清零
	u3_printf("%s",data);	//发送命令
	if(ack&&waittime)		//需要等待应答
	{
		while(--waittime)	//等待倒计时
		{
			delay_ms(10);
			if(UART1_RX_SR())//接收到期待的应答结果
			{
				if(atk_8266_check_cmd(ack))break;//得到有效数据 
				USART1_RX_COUNT=0;
			} 
		}
		if(waittime==0)res=1; 
	}
	return res;
}
//获取ATK-ESP8266模块的连接状态
//返回值:0,未连接;1,连接成功.
u8 atk_8266_consta_check(void)
{
	u8 *p;
	u8 res;
	if(atk_8266_quit_trans())return 0;			//退出透传 
	atk_8266_send_cmd("AT+CIPSTATUS",":",50);	//发送AT+CIPSTATUS指令,查询连接状态
	p=atk_8266_check_cmd("+CIPSTATUS:"); 
	res=*p;						//得到连接状态	
	return res;
}
//定向传输数据
void direction_send_data(u8* p)
{
      printf("发送数据为:%s\n",p);
      atk_8266_send_cmd("AT+CIPSEND=0,10","OK",200);  //发送指定长度的数据
      delay_ms(200);
      atk_8266_send_data(p,"OK",100);  //发送指定长度的数据
}
//透明传输数据
void transparent_send_data(u8* p)
{
      printf("发送数据为:%s\n",p);
      atk_8266_quit_trans();
      atk_8266_send_cmd("AT+CIPSEND","OK",20);       //开始透传
      u3_printf("%s",p);
}

4.AP.c源码

#include"ESP8266.h"
//ATK-ESP8266 WIFI AP测试(AP模式自身作为热点源,因此不需要进行联网)
//用于测试TCP/UDP连接
//返回值:0,正常
//    其他,错误代码
void atk_8266_wifiap_test(void)
{
	u8 netpro=0;	//网络模式
	u8 key;
	u8 ipbuf[16]; 	//IP缓存
	u8 p[50];	    //定义一缓存区
    u32 t=199;		//加速第一次获取链接状态
	u16 rlen=0;     //接收字节长度
	u8 constate=0;	//连接状态
PRESTA:
    atk_8266_send_cmd("AT+CWMODE=2","OK",20);   //设置模块作为AP模式
	atk_8266_send_cmd("AT+RST","OK",20);        //重启生效
	delay_ms(1000);//延时2s等待模块重启
	delay_ms(1000);//
    delay_ms(1000);//
	sprintf((char*)p,"AT+CWSAP=\"%s\",\"%s\",1,4",wifiap_ssid,wifiap_password);    //配置模块AP模式无线参数
	atk_8266_send_cmd(p,"OK",1000); //通过串口1将指令发送给模块    
	netpro=atk_8266_netpro_sel((u8*)ATK_ESP8266_CWMODE_TBL[1]);//选择网络模式
        if(netpro==0)//0,TCP服务器
        {
            printf("ATK-ESP WIFI-AP-TCP服务器测试\n");
            printf("正在配置ATK-ESP模块,请稍等...\n");
            atk_8266_send_cmd("AT+CIPMUX=1","OK",20);             //0:单连接,1:多连接
            atk_8266_send_cmd("AT+CIPSERVER=1,8086","OK",20);     //开启Server模式,端口号为8086   
        }
        else if(netpro==1)//1,TCP客户端
        {
            printf("ATK-ESP WIFI-AP-TCP客户端测试\n");
            printf("正在配置ATK-ESP模块,请稍等...\n");
            atk_8266_send_cmd("AT+CIPMUX=0","OK",20);   //0:单连接,1:多连接
            sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s","192.168.4.2","8086");//配置目标TCP服务器,IP地址和端口号设置
            while(atk_8266_send_cmd(p,"OK",200))
            {
              printf("ATK-ESP 连接TCP失败\n"); 
              printf("按S4_PRE返回重新设置\n");
              key=KEY_Scan(0);
              if(key==S4_PRE)goto PRESTA;             //按下S4返回重新选择通信方式
            }
            //当设置成透传模式发生任意长度数据时需要加下面这一句,定长数据发送则删除
            atk_8266_send_cmd("AT+CIPMODE=1","OK",200);      //传输模式为:透传
        }
        else if(netpro&0X02)//2,UDP模式
        {
              printf("ATK-ESP WIFI-AP-UDP测试\n");
              printf("正在配置ATK-ESP模块,请稍等...\n");
              atk_8266_send_cmd("AT+CIPMUX=0","OK",100);  //单链接模式
              sprintf((char*)p,"AT+CIPSTART=\"UDP\",\"%s\",%s","192.168.4.2","8086");    //配置目标UDP服务器
              while(atk_8266_send_cmd(p,"OK",500));
              {
                printf("ATK-ESP 连接UDP失败\n"); 
                printf("按S4_PRE返回重新设置\n");
                key=KEY_Scan(0);
                if(key==S4_PRE)goto PRESTA;             //按下S4返回重新选择通信方式
              }
              //当设置成透传模式发生任意长度数据时需要加下面这一句,定长数据发送则删除
              atk_8266_send_cmd("AT+CIPMODE=1","OK",200);      //传输模式为:透传
              printf("配置ATK-ESP模块成功!\n");
        }
              printf("配置ATK-ESP模块成功!\n");
              printf("S1_PRE:退出重新选择  S2_PRE:发送数据  S4_PRE:退出AP运行\n");

              atk_8266_get_wanip(ipbuf);//服务器模式,获取WAN IP
              printf("AP模式的IP地址:%s\n",ipbuf);//显示IP地址和端口
	
              atk_8266_wificonf_show("请用设备连接WIFI热点:",(u8*)wifiap_ssid,(u8*)wifiap_encryption,(u8*)wifiap_password);
              printf("%s\n",(u8*)ATK_ESP8266_WORKMODE_TBL[netpro]);//连接状态
              USART1_RX_COUNT=0;                      //串口1接受数据清零
              
              while(1)
              {
                      key=KEY_Scan(0);
                      if(key==S1_PRE)		//S1_PRE:退出测试		 
                      {  
                          atk_8266_quit_trans();	//退出透传
                          printf("退出重新选择\n");
                          goto PRESTA;											 
                      }
                      else if(key==S2_PRE)	//S2_PRE:发送数据 
                      {
                        if(netpro==0)           //0,TCP服务器
                        {
                          sprintf((char*)p,"TCP服务器定向发送数据:ABCDEFGH");//要发送的数据
                          direction_send_data(p);         //调用透明传输函数进行发送数据
                          printf("TCP服务器定向传输发送完成!\n");
                        }
                        else if(netpro==1)           //1,TCP客户端
                        {
                          sprintf((char*)p,"TCP客户端透明随便传输");//要发送的数据
                          transparent_send_data(p);         //调用透明传输函数进行发送数据
                          printf("TCP客户端透明传输发送完成!\n");
                        }
                        else                         //UDP
                        {
                            /***************************发送指定长度的数据模式************************************/
//                          sprintf((char*)p,"UDP定向发送数据:ABCDEFGH");//要发送的数据
//                          direction_send_data(p);         //调用透明传输函数进行发送数据
//                          printf("UDP定向传输发送完成!\n");
                          /***************************透明传输:发送任意长度的数据模式************************************/
                          sprintf((char*)p,"UDP透明传输");//要发送的数据
                          transparent_send_data(p);         //调用透明传输函数进行发送数据
                          printf("UDP透明传输发送完成!\n");
                        }
                      }
                      else if(key==S4_PRE)	//S4_PRE:退出AP运行
                      {
                        atk_8266_quit_trans();	//退出透传
                        atk_8266_send_cmd("AT+CIPMODE=0","OK",20);   //关闭透传模式
                        printf("退出AP模式,重新选择!\n");
                        break;				
                      }
                      t++;
                      delay_ms(5);
   /*以下是串口1循环扫描判断是否接收到模块发回的数据,也即模块是否收到返回的数据*/
                      	if(UART1_RX_SR())		//接收到一次数据了
                      	{ 
                      		rlen=USART1_RX_COUNT;	//得到本次接收到的数据长度
                      		USART1_RX_BUF[rlen]=0;		//添加结束符 
                      		printf("%s",USART1_RX_BUF);	//发送到串口   
                      		USART1_RX_COUNT=0;
                      		if(constate!='+')t=199;		//状态为还未连接,立即更新连接状态
                      		else t=0;                   //状态为已经连接了,10秒后再检查
                      	}  
                      if(t==200)//连续10秒钟没有收到任何数据,检查连接是不是还存在.
                      {
                          constate=atk_8266_consta_check();//得到连接状态
                          if(constate=='+')
                            printf("连接成功\n");  //连接状态
                          else
                            printf("连接失败\n");  //连接状态 	  	 
                          t=0;
                      }
                      if(t%20==0)P6OUT^=BIT0;          //LED状态翻转,闪烁
                      atk_8266_at_response(1);        //显示一些提示信息
              }	
} 

5.STA.c源码

#include"ESP8266.h"
//ATK-ESP8266 WIFI STA测试(STA模式下模块和其他网络设备需连接在同一个局域网下,因此需进行联网操作)
//用于测试TCP/UDP连接
//返回值:0,正常
//    其他,错误代码
void atk_8266_wifista_test(void)
{
	u8 netpro=0;	//网络模式
	u8 key;
	u8 ipbuf[16]; 	//IP缓存
	u8 p[50];	//注意:此处一定要定义成字符缓存区(u8 或char),不能定义成指针变量*p!!!!!!!
	u32 t=199;		//加速第一次获取链接状态
	u16 rlen=0;
	u8 constate=0;	//连接状态
PRESTA:
	atk_8266_send_cmd("AT+CWMODE=1","OK",50);		//设置WIFI STA模式
	atk_8266_send_cmd("AT+RST","OK",20);		    //DHCP服务器关闭(仅AP模式有效) 
	delay_ms(3000);         //延时3S等待重启成功
	//设置连接到的WIFI网络名称/加密方式/密码,这几个参数需要根据您自己的路由器设置进行修改!! 
	sprintf((char*)p,"AT+CWJAP=\"%s\",\"%s\"",wifista_ssid,wifista_password);//设置无线参数:ssid,密码
	atk_8266_send_cmd(p,"WIFI GOT IP",300);//连接目标路由器,并且获得IP
        delay_ms(3000);//等待连接WiFi成功
	netpro=atk_8266_netpro_sel((u8*)ATK_ESP8266_CWMODE_TBL[0]);//选择网络模式
	if(netpro&0X02)   //UDP
	{
              printf("ATK-ESP WIFI-STA-UDP测试\n");
              printf("正在配置ATK-ESP模块,请稍等...\n");    
              sprintf((char*)p,"AT+CIPSTART=\"UDP\",\"%s\",%s",IP_address,portnum);    //配置目标UDP服务器
              atk_8266_send_cmd("AT+CIPMUX=0","OK",20);  //单链接模式
              delay_ms(200);
              while(atk_8266_send_cmd(p,"OK",500));
              //当设置成透传模式发生任意长度数据时需要加下面这一句,定长数据发送则删除
              atk_8266_send_cmd("AT+CIPMODE=1","OK",200);      //传输模式为:透传
	}
	else     //TCP
	{
		if(netpro&0X01)     //TCP Client    透传模式测试
		{
                      printf("ATK-ESP WIFI-STA-TCP客户端测试\n");
                      printf("正在配置ATK-ESP模块,请稍等...\n");
                      atk_8266_send_cmd("AT+CIPMUX=0","OK",20);   //0:单连接,1:多连接
                      sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",IP_address,portnum);    //配置目标TCP服务器
                      while(atk_8266_send_cmd(p,"OK",200))
                      {
                          printf("ATK-ESP 连接TCP失败\n"); 
                          printf("按S4_PRE返回重新设置\n");
                          key=KEY_Scan(0);
                          if(key==S4_PRE)goto PRESTA;             //按下S4返回重新选择通信方式
                      }
                      //当设置成透传模式发生任意长度数据时需要加下面这一句,定长数据发送则删除
                      atk_8266_send_cmd("AT+CIPMODE=1","OK",200);  //传输模式为:透传			
		}
		else					//TCP Server
		{
                        printf("ATK-ESP WIFI-STA-TCP服务器测试\n");
                        printf("正在配置ATK-ESP模块,请稍等...\n");
                        atk_8266_send_cmd("AT+CIPMUX=1","OK",20);   //0:单连接,1:多连接
                        sprintf((char*)p,"AT+CIPSERVER=1,%s",portnum);    //开启Server模式(0,关闭;1,打开),端口号为portnum
                        atk_8266_send_cmd(p,"OK",50);    
		}
	}
                        printf("配置ATK-ESP模块成功!\n");
                        printf("S1_PRE:退出重新选择  S2_PRE:发送数据  S4_PRE:退出AP运行\n");

			            atk_8266_get_wanip(ipbuf);//服务器模式,获取WAN IP
                        printf("IP地址:%s 端口号:%s\n",ipbuf,portnum);//显示IP地址和端口
                        printf("请设置路由器无线参数为:%s %s %s\n",(u8*)wifista_ssid,(u8*)wifista_encryption,(u8*)wifista_password);
                        printf("连接状态:%s\n",(u8*)ATK_ESP8266_WORKMODE_TBL[netpro]);//连接状态
			    USART1_RX_COUNT=0;                      //串口1接受数据清零
			while(1)
			{
				key=KEY_Scan(0);
				if(key==S1_PRE)			//S1_PRE:退出重新选择	 
				{ 
                                      atk_8266_quit_trans();	//退出透传,退出透传的意义在于只有退出透传了才能发命令进行配置!!!!!!!!
                                      printf("退出重新选择\n");
                                      goto PRESTA;												 
                                }
				else if(key==S2_PRE)	//S2_PRE: 发送数据 
				{
					if((netpro==3)||(netpro==2))   //UDP
					{
                                              /***************************发送指定长度的数据模式************************************/
                    //                        sprintf((char*)p,"UDP定向发送数据:ABCDEFGH");//要发送的数据
                    //                        direction_send_data(p);         //调用透明传输函数进行发送数据
                    //                        printf("UDP定向传输发送完成!\n");
                                              /***************************透明传输:发送任意长度的数据模式************************************/
                                              sprintf((char*)p,"UDP透明传输");//要发送的数据
                                              transparent_send_data(p);         //调用透明传输函数进行发送数据
                                              printf("UDP透明传输发送完成!\n");
					}
					else if((netpro==1))   //TCP Client
					{
                                              sprintf((char*)p,"TCPHDJS");//要发送的数据
                                              transparent_send_data(p);         //调用透明传输函数进行发送数据
                                              printf("TCP客户端透明传输发送完成!\n");
					}
					else    //TCP Server
					{
                                              sprintf((char*)p,"TCPABCDEFG");//要发送的数据
                                              direction_send_data(p);         //调用透明传输函数进行发送数据
                                              printf("TCP服务器定向传输发送完成!\n");
					}
				}
                                else if(key==S4_PRE)	//S4_PRE:退出STA运行
                                {
                                      atk_8266_quit_trans();	//退出透传
                                      atk_8266_send_cmd("AT+CIPMODE=0","OK",20);   //关闭透传模式
                                      printf("退出STA模式,重新选择!\n");
                                      break;				
                                }
				t++;
				delay_ms(5);
				if(UART1_RX_SR())		//接收到一次数据了
				{
                                    rlen=USART1_RX_COUNT;	//得到本次接收到的数据长度
                                    USART1_RX_BUF[rlen]=0;		//添加结束符 
                                    printf("%s",USART1_RX_BUF);	//发送到串口   
                                    USART1_RX_COUNT=0;
                                    if(constate!='+')t=199;		//状态为还未连接,立即更新连接状态
                                    else t=0;                   //状态为已经连接了,10秒后再检查
				}  
				if(t==200)//连续10秒钟没有收到任何数据,检查连接是不是还存在.
				{
                                    constate=atk_8266_consta_check();//得到连接状态
                                    if(constate=='+')
                                      printf("连接成功\n");  //连接状态
                                    else
                                      printf("连接失败\n");  //连接状态 	  	 
                                    t=0;
				}
                                if(t%20==0)P6OUT^=BIT0;          //LED状态翻转,闪烁
                                atk_8266_at_response(1);        //显示一些提示信息(也就是模块返回的信息)
			}	
} 

6.AP+STA.c源码

#include"ESP8266.h"

//ATK-ESP8266 AP+STA模式测试(即把上面两种模式综合)
//用于测试TCP/UDP连接
//返回值:0,正常
//    其他,错误代码
void atk_8266_apsta_test(void)
{
	u8 netpro;
	u8 key=0;
	u8 AP_ipbuf[16]; 	         //AP_IP缓存
    u8 STA_ipbuf[16]; 	         //STA_IP缓存
	u8 p[50];	         //注意:此处一定要定义成字符缓存区(u8 或char),不能定义成指针变量*p!!!!!!!
	u32 t=199;		 //加速第一次获取链接状态
	u16 rlen=0;
	u8 constate=0;	//连接状态
PRESTA:
	atk_8266_send_cmd("AT+CWMODE=3","OK",50);	//设置WIFI AP+STA模式(1)
	atk_8266_send_cmd("AT+RST","OK",20);		//重启模块 (2)
	delay_ms(3000);         //延时2S等待重启成功
        //设置模块AP模式的WIFI网络名称/加密方式/密码,这几个参数看自己喜好设置
	sprintf((char*)p,"AT+CWSAP=\"%s\",\"%s\",1,4",wifiap_ssid,wifiap_password);//设置无线参数:ssid,密码
	atk_8266_send_cmd(p,"OK",1000);					//设置AP模式参数(3)
	//设置连接到的WIFI网络名称/加密方式/密码,这几个参数需要根据您自己的路由器设置进行修改!! 
	sprintf((char*)p,"AT+CWJAP=\"%s\",\"%s\"",wifista_ssid,wifista_password);//设置无线参数:ssid,密码
	atk_8266_send_cmd(p,"WIFI GOT IP",1000);			//连接目标路由器,并获得IP(4)
        delay_ms(3000);//等待连接WiFi成功
	while(atk_8266_send_cmd("AT+CIFSR","STAIP",20));   //检测是否获得STA IP
        printf("获取STA IP成功\n");
	while(atk_8266_send_cmd("AT+CIFSR","APIP",20));   //检测是否获得AP IP
        printf("获取AP IP成功\n");
        
	atk_8266_send_cmd("AT+CIPMUX=1","OK",50);   //0:单连接,1:多连接(5)
	delay_ms(500);
	sprintf((char*)p,"AT+CIPSERVER=1,%s",portnum);
	atk_8266_send_cmd(p,"OK",50);     //开启Server模式,端口号为8086(6)
	delay_ms(500);
	atk_8266_send_cmd("AT+CIPSTO=1200","OK",50);     //设置服务器超时时间(7)
	
	netpro=atk_8266_netpro_sel((u8*)ATK_ESP8266_CWMODE_TBL[2]);	//AP+STA模式网络模式选择
	if(netpro&0X02)   //STA UDP
	{
              printf("AP:TCP服务器  STA:UDP 测试\n");
              printf("正在配置ATK-ESP模块,请稍等...\n");   
              sprintf((char*)p,"AT+CIPSTART=0,\"UDP\",\"%s\",%s",IP_address,portnum);//STA 作为 ID0 连接到 172.16.10.106,8086
              while(atk_8266_send_cmd(p,"OK",500));
              //当设置成透传模式发生任意长度数据时需要加下面这一句,定长数据发送则删除
              //atk_8266_send_cmd("AT+CIPMODE=1","OK",200);      //传输模式为:透传
	}

        else if(netpro&0X01)//STA TCP 客户端  
        {
              printf("AP:TCP服务器  STA:TCP客户端 测试\n");
              printf("正在配置ATK-ESP模块,请稍等...\n");   
              sprintf((char*)p,"AT+CIPSTART=0,\"TCP\",\"%s\",%s",IP_address,portnum);//STA 作为 ID0 连接到 172.16.10.106,8086
              while(atk_8266_send_cmd(p,"OK",200))
              {
                  printf("ATK-ESP 连接TCP失败\n"); 
                  printf("按S4_PRE返回重新设置\n");
                  key=KEY_Scan(0);
                  if(key==S4_PRE)goto PRESTA;             //按下S4返回重新选择通信方式
              }
              //atk_8266_send_cmd("AT+CIPMODE=1","OK",200);  //传输模式为:透传
        }
        else if(netpro==0)//STA TCP 服务器  
        {
              printf("AP:TCP服务器  STA:TCP服务器 测试\n");
              printf("正在配置ATK-ESP模块,请稍等...\n");   
        }
	
        printf("配置ATK-ESP模块成功!\n");
        printf("S1_PRE:退出重新选择  S2_PRE:发送数据  S4_PRE:退出AP运行\n");
        atk_8266_get_ip(AP_ipbuf,STA_ipbuf);//服务器模式,获取WAN IP  STA+AP模式,获取 IP,并显示	
        printf("AP_IP地址:%s\n STA_IP地址:%s\n 端口号:%s\n",AP_ipbuf,STA_ipbuf,portnum);//显示IP地址和端口

        printf("请设置路由器无线参数为:%s %s %s\n",(u8*)wifista_ssid,(u8*)wifista_encryption,(u8*)wifista_password);
        printf("STA连接状态:%s\n",(u8*)ATK_ESP8266_WORKMODE_TBL[netpro&0X03]);//STA连接状态
	printf("AP连接状态:%s\n",(u8*)ATK_ESP8266_WORKMODE_TBL[netpro>>4]);//AP连接状态
	USART1_RX_COUNT=0;                      //串口1接受数据清零
        
	while(1)
	{
		key=KEY_Scan(0);
                if(key==S1_PRE)			//S1_PRE:退出重新选择	 
                { 
                    atk_8266_quit_trans();	//退出透传,退出透传的意义在于只有退出透传了才能发命令进行配置!!!!!!!!
                    printf("退出重新选择\n");
                    goto PRESTA;												 
                }
		else if(key==S2_PRE)	       //S2_PRE 向ID0发送数据,STA端
		{
                    sprintf((char*)p,"ATK-8266模块ID0发数据%02d\r\n",t/10);//测试数据
                    printf("发送数据为:%s\n",p);
                    atk_8266_send_cmd("AT+CIPSEND=0,25","OK",200);  //发送指定长度的数据
                    delay_ms(200);
                    atk_8266_send_data(p,"OK",100);  //发送指定长度的数据
		}
		else if(key==S3_PRE)	      //S3_PRE 向ID1发送数据 ,AP端
		{
                    sprintf((char*)p,"ATK-8266模块ID1发数据%02d\r\n",t/10);//测试数据
                    printf("发送数据为:%s\n",p);
                    atk_8266_send_cmd("AT+CIPSEND=1,25","OK",200);  //发送指定长度的数据
                    delay_ms(200);
                    atk_8266_send_data(p,"OK",100);  //发送指定长度的数据
		}
                else if(key==S4_PRE)	//S4_PRE:退出STA运行
                {
                    atk_8266_quit_trans();	//退出透传
                    atk_8266_send_cmd("AT+CIPMODE=0","OK",20);   //关闭透传模式
                    printf("退出STA模式,重新选择!\n");
                    break;				
                }
	 t++;
	 delay_ms(5);
	 if(UART1_RX_SR())		//接收到一次数据了
	{ 
              rlen=USART1_RX_COUNT;	//得到本次接收到的数据长度
              USART1_RX_BUF[rlen]=0;		//添加结束符 
              printf("%s",USART1_RX_BUF);	//发送到串口   
              USART1_RX_COUNT=0;
              if(constate!='+')t=199;		//状态为还未连接,立即更新连接状态
              else t=0;                   //状态为已经连接了,10秒后再检查
	}  
        if(t==200)//连续10秒钟没有收到任何数据,检查连接是不是还存在.
        {
            constate=atk_8266_consta_check();//得到连接状态
            if(constate=='+')
              printf("连接成功\n");  //连接状态
            else
              printf("连接失败\n");  //连接状态 	  	 
            t=0;
        }
        if(t%20==0)P6OUT^=BIT0;          //LED状态翻转,闪烁
        atk_8266_at_response(1);        //显示一些提示信息
      }
}

7.SNTP.c源码

#include"ESP8266.h"
//设置步骤:设置为STA模式--连接到WIFI--发送获取网络时间指令--获取网络时间
void sntp_test(void)	//获取实时网络时间测试
{
          u8 key;
          u16 rlen=0;
          u8 p[50];	//注意:此处一定要定义成字符缓存区(u8 或char),不能定义成指针变量*p!!!!!!!
          printf("ATK-ESP 获取实时网络时间测试\n");
          
          atk_8266_send_cmd("AT+CWMODE=1","OK",50);		//设置WIFI STA模式
          
          atk_8266_send_cmd("AT+RST","OK",20);		//复位模块
          delay_ms(3000);         //延时3S等待重启成功
          
          //设置连接到的WIFI网络名称/加密方式/密码,这几个参数需要根据您自己的路由器设置进行修改!! 
          sprintf((char*)p,"AT+CWJAP=\"%s\",\"%s\"",wifista_ssid,wifista_password);//设置无线参数:ssid,密码
          atk_8266_send_cmd(p,"WIFI GOT IP",1000);//连接目标路由器,并且获得IP
          delay_ms(3000);
          
          atk_8266_send_cmd("AT+CIPSNTPCFG=1,8","OK",20);	//设置获取实时网络时间测试指令
          printf("S1_PRE:查询日期和时间\n");

          while(1)
          {  
            key=KEY_Scan(0); 
              if(key==S1_PRE) //S1_PRE:发送数据
              {
                   atk_8266_send_cmd("AT+CIPSNTPTIME?","OK",20);	//获取实时网络时间测试
                   printf("获取实时网络时间完成\n");
              }
              if(UART1_RX_SR())		//接收到一次数据了
              {
                rlen=USART1_RX_COUNT;	//得到本次接收到的数据长度
                USART1_RX_BUF[rlen]=0;		//添加结束符 
                printf("%s",USART1_RX_BUF);	//发送到串口0打印出来   
                USART1_RX_COUNT=0;
              }  
          }
}

8.SMTP.h及SMTP.c

/**********************************SMTP.h**********************************************/
/*发信人邮箱登录名/密码*/
char*   EMAIL_USER="[email protected]";
char*   EMAIL_PWD="yggxtkypypvtgbbc";

/*SMTP服务器IP及端口号*/
const u8* SMTP_SERVER_PORT="25";		 
const u8* SMTP_SERVER_IP="smtp.qq.com";

typedef enum
{
    SERVER_NOLINK,      //未连接到服务器
    SERVER_LINKED,      //已连接服务器
    SERVER_HELO,        //发送HELO给服务器
    SERVER_LOGIN,       //请求登录
    SERVER_IN_NAME,     //输入邮箱用户名
    SERVER_IN_PWD,      //输入邮箱密码
    SERVER_MIAL_FROM,   //输入信封发件人
    SERVER_RCPT_TO,     //输入信封收件人
    SERVER_DATA,        //请求输入正文
    SERVER_CONTENT,     //输入正文
    SERVER_QUIT         //发送完成,断开和服务器的连接 
}LINK_STATUS;
/**********************************SMTP.c**********************************************/
#include"ESP8266.h"
#include"SMTP.h"

/**
 * 功能:给指定邮箱发送一封电子邮件
 * 参数:
 *      email_addr:收件人邮箱地址
 *      subject:邮件标题
 *      content:邮件正文
 * 返回值:非0表示发送成功,0表示发送失败
 */
u8 sendEmail(char* email_addr,char* subject,char* content)
{  
    u8 p[50];
    u8 smtp_sta = SERVER_NOLINK;                //邮件发送状态
    u8 send_result = 0;                         //发送结果
    char Base64[40] = {0};                      //存放编码后的结果,注意:不能定义成全局变量,要及时释放
    char Envelope_From[40]={0};
    char Envelope_To[40]={0};
    
    char Header_From[40]={0};
    char Header_To[40]={0};
    char Header_Subject[40]={0};
    
    initESP8266();                              //初始化ESP8266
    
    connectAP(wifista_ssid,wifista_password);  //连接热点
  
    /*格式化发送命令*/
    sprintf(Envelope_From,"mail from:<%s>",EMAIL_USER);
    sprintf(Envelope_To,"rcpt to:<%s>",email_addr);
    sprintf(Header_From,"from:%s\r\n",EMAIL_USER);
    sprintf(Header_To,"to:%s\r\n",email_addr);
    sprintf(Header_Subject,"subject:%s\r\n\r\n",subject);

    /*发送状态机*/
    switch(smtp_sta)
    {
        /*连接服务器*/
        case SERVER_NOLINK: 
             atk_8266_quit_trans();            //退出透传
             delay_ms(500);
             sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",SMTP_SERVER_IP,SMTP_SERVER_PORT);    //配置目标TCP服务器
             if(!atk_8266_send_cmd(p,"220",200))
             {
                printf("连接SMTP服务器成功\n");
                smtp_sta=SERVER_HELO;                   //如果连接服务器成功,则发送HELO给服务器
             }
             else 
             {
                printf("连接SMTP服务器失败\n");
                smtp_sta = SERVER_NOLINK;               //如果连接服务器不成功,则状态标记为SERVER_NOLINK,继续连接
             }
             atk_8266_send_cmd("AT+CIPMODE=1","OK",200);      //设置为透传模式
             atk_8266_send_cmd("AT+CIPSEND","OK",20);         //开始透传
        /*和服务器打招呼,标明自己身份*/                    
        case SERVER_HELO  :
             if(!atk_8266_send_cmd("helo qq.com","250",800))
             {
               printf("和服务器打招呼成功\n");
                smtp_sta=SERVER_LOGIN;                   //如果和服务器打招呼成功,则请求登录
             }
             else 
             {
               printf("和服务器打招呼失败\n");
                smtp_sta = SERVER_QUIT;               //如果和服务器打招呼不成功,则断开和服务器的连接 
             }
        /*请求登录*/
        case SERVER_LOGIN : 
             if(!atk_8266_send_cmd("auth login","334",200))
             {
               printf("请求登录成功\n");
                smtp_sta=SERVER_IN_NAME;                   //如果请求登录成功,则输入用户名
             }
             else 
             {
               printf("请求登录失败\n");
                smtp_sta = SERVER_QUIT;                    //如果请求登录不成功,则断开和服务器的连接  
             }
        /*输入用户名*/
        case SERVER_IN_NAME : 
              codeBase64(Base64,EMAIL_USER);                //codeBase64编码(这里之所以用到Base64编码是因为在网络传输协议中对于一些特殊字符没法传输,需要转码后传输,如@)
             if(!atk_8266_send_cmd((u8*)Base64,"334",200))
             {
               printf("输入用户名成功\n");
               smtp_sta=SERVER_IN_PWD;                   //如果输入用户名成功,则输入邮箱密码
             }
             else 
             {
               printf("输入用户名失败\n");
               smtp_sta = SERVER_QUIT;                    //如果输入用户名不成功,则断开和服务器的连接   
             }
        /*输入密码*/
        case SERVER_IN_PWD  : 
              codeBase64(Base64,EMAIL_PWD);
              if(!atk_8266_send_cmd((u8*)Base64,"235",200))//如果输入密码成功,则输入信封发件人
              {
                printf("密码输入成功,登陆成功!\n");                  //打印登录成功
                smtp_sta=SERVER_MIAL_FROM;                 //输入信封发件人
              }else 
              {
                printf("密码输入失败,登陆失败!\n");                     //打印登录失败
                smtp_sta = SERVER_QUIT;                   //断开和服务器的连接
              };
        /*输入信封发件人*/
        case SERVER_MIAL_FROM  :                      
              if(!atk_8266_send_cmd((u8*)Envelope_From,"250",200))
              {
                printf("输入信件发件人成功\n");                  //输入信件发件人成功
                smtp_sta=SERVER_RCPT_TO;                       //输入信件收件人
              }else 
              {
                printf("输入信件发件人失败\n");                  //输入信件发件人失败
                smtp_sta = SERVER_QUIT;                        //断开和服务器的连接
              };       
        /*输入信封收件人*/
        case SERVER_RCPT_TO   :                  
              if(!atk_8266_send_cmd((u8 *)Envelope_To,"250",200))
              {
                printf("输入信件收件人成功\n");                  //输入信件收件人成功
                smtp_sta=SERVER_DATA;                   //通知服务器开始输入邮件内容
              }else 
              {
                printf("输入信件收件人失败\n");                  //输入信件收件人失败
                smtp_sta = SERVER_QUIT;                 //断开和服务器的连接
              };
        /*通知服务器开始输入邮件内容*/
        case SERVER_DATA   : 
              if(!atk_8266_send_cmd("data","354",200))
              {
                printf("开始输入邮件内容成功\n");                  //开始输入邮件内容成功
                smtp_sta=SERVER_CONTENT;                          //输入内容
              }else 
              {
                printf("开始输入邮件内容失败\n");                  //开始输入信件收件人失败
                smtp_sta = SERVER_QUIT;                  //断开和服务器的连接
              };
        /*输入内容*/
        case SERVER_CONTENT   : 
              u3_printf("%s",Header_From);//发送发件人地址
              u3_printf("%s",Header_To);    //发送收件人地址
              u3_printf("%s",Header_Subject);	             //发送主题
              u3_printf("%s",content);	                     //发送内容
              if(!atk_8266_send_cmd("\r\n.","250",200))     //发送内容之后要以\r\n.\r\n结尾,会自动发送
              {
                send_result = 1;
               smtp_sta=SERVER_QUIT;                    //断开和服务器的连接
                printf("邮件发送成功\n");
              }else 
              {  
                printf("邮件发送失败\n");        
                smtp_sta = SERVER_QUIT;                   //断开和服务器的连接
              };
        /*结束和远程服务器的TCP连接*/
        case SERVER_QUIT   : 
              if(!atk_8266_send_cmd("QUIT","221",200))
              {
                smtp_sta = SERVER_NOLINK;
              }else 
              {
                disconnectServer();
                smtp_sta = SERVER_NOLINK;                   //状态标记为SERVER_NOLINK
              };
        default:    break;                           
    }
    return send_result;//返回结果
}

/**
*功能:对字符串进行BASE64编码
*参数:
*     basestr:编码后存储缓冲指针
*     str:待编码缓存指针
*     返回值:None
*说明:
*     对于传址处理的函数,一定要保证所传地址对应的空间足够大,才能避免内存溢出
*/
static void codeBase64(char* basestr,char* str)
{
    /*BASE64编码表*/
	const char Base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

	u8 len = strlen(str);
	u8 remain = len%3;
	u8 i,j=0;
	
    /*清空残留*/
    memset(basestr,0,strlen(basestr));
    /*每3个字节为一组进行切分*/
	for(i=0;i<len;i+=3)
	{	
        /*不够3字节时进行补充*/
		if(len-i == remain)
		{
            /*剩一个字节(8bits)时,可以拆分成两个6bits的字节,
             *第二个6bits字节低4bits不够用0填充
             *剩两个字节时,可以拆分成3个6bits的字节,第三个6bits字节
             *低4bits不够用0填充*/
			if(remain==1)
			{
				basestr[j++] = Base64_table[str[i]>>2];
				basestr[j++] = Base64_table[(str[i]&0x03)<<4 | 0x00];
				basestr[j++] = '=';
				basestr[j] = '=';
			}else if(remain==2)
			{
				basestr[j++] = Base64_table[str[i]>>2];
				basestr[j++] = Base64_table[(str[i]&0x03)<<4 | (str[i+1]&0xF0)>>4];
				basestr[j++] = Base64_table[(str[i+1]&0x0F)<<2 | 0x00];
				basestr[j] = '=';
			}else 
			{
				
			}	
			break;
		}	

        /*够3字节将3字节拆分成4个有效位数为6位的字节,并查表赋值*/
		basestr[j++] = Base64_table[str[i]>>2];
		basestr[j++] = Base64_table[(str[i]&0x03)<<4 | (str[i+1]&0xF0)>>4];
		basestr[j++] = Base64_table[(str[i+1]&0x0F)<<2 | (str[i+2]&0xC0)>>6];
		basestr[j++] = Base64_table[str[i+2]&0x3F];
	}	
}
u8 disconnectServer(void)            //断开连接
{
    atk_8266_quit_trans();            //退出透传
    delay_ms(500);
    if(!atk_8266_send_cmd("AT+CIPCLOSE","CLOSED",200))//关闭链接
    {
        return 1;
    }else 
    {
        return 0;
    }
}
/**
 * 功能:初始化ESP8266
 * 参数:None
 * 返回值:初始化结果,非0为初始化成功,0为失败
 */
void initESP8266(void)
{
    printf("初始化ESP8266\n");
    atk_8266_quit_trans();            //退出透传
    delay_ms(500); 
    atk_8266_send_cmd("AT+RST","OK",20);//复位模块
    delay_ms(2000);                   //延时3S等待重启成功 
    atk_8266_send_cmd("ATE0","OK",20);//关闭回显
    printf("ESP8266初始化完成\n");
}
/**
 * 功能:连接热点
 * 参数:
 *         ssid:热点名
 *         pwd:热点密码
 * 返回值:
 *         连接结果,非0连接成功,0连接失败
 * 说明: 
 *         失败的原因有以下几种(UART通信和ESP8266正常情况下)
 *         1. WIFI名和密码不正确
 *         2. 路由器连接设备太多,未能给ESP8266分配IP
 */
void connectAP(u8* ssid,u8* pwd)
{
    u8 p[50];
    printf("开始联网\n");
    atk_8266_send_cmd("AT+CWMODE=1","OK",200);		//设置WIFI STA模式
    /*设置连接到的WIFI网络名称/加密方式/密码,这几个参数需要根据您自己的路由器设置进行修改!! */
    sprintf((char*)p,"AT+CWJAP=\"%s\",\"%s\"",ssid,pwd);//设置无线参数:ssid,密码
    atk_8266_send_cmd(p,"WIFI GOT IP",1000);            //连接目标路由器,并且获得IP
    delay_ms(2000);
    printf("网络连接成功\n");
}

你可能感兴趣的:(无线通信)