ESP8266 是一款高性能的 UART-WiFi(串口-无线)模块,ATK-ESP8266 模块采用串口(LVTTL)与 MCU(或其他串口设备)通信,内置TCP/IP 协议栈,能够实现串口与 WIFI 之间的转换。通过 ESP8266 模块,传统的串口设备只是需要简单的串口配置,即可通过网络(WIFI)传输自己的数据。便的与你的产品进行连接。模块支持串口转WIFI STA、串口转AP和WIFI STA+WIFI模式。通俗来说,该模块通过串口与单片机进行连接(采用AT指令开发方式),通过该模块使得单片机能够联网,从而实现多种网络通信功能,以下一一进行介绍。
各源文件与头文件分类及实现功能如下:
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邮件发送源代码)
#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(); //获取实时网络时间测试(测试时只需把前面注释掉,执行该函数即可)
}
}
/*************************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标志位
}
/*************************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);
}
#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); //显示一些提示信息
}
}
#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); //显示一些提示信息(也就是模块返回的信息)
}
}
#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); //显示一些提示信息
}
}
#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;
}
}
}
/**********************************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");
}