ESP8266-WIFI之例程篇

一、ESP8266_drive驱动类文件

1)esp8266_drive.hweb

#ifndef _esp8266_drive_H
#define _esp8266_drive_H

#include "system.h"
#include <stdio.h>
#include <stdbool.h>



#if defined ( __CC_ARM )
#pragma anon_unions
#endif

//ESP8266模式选择
typedef enum
{
    STA,
    AP,
    STA_AP  
}ENUM_Net_ModeTypeDef;

//网络传输层协议,枚举类型
typedef enum{
     enumTCP,
     enumUDP,
} ENUM_NetPro_TypeDef;
//链接号,指定为该链接号能够防止其余计算机访问同一端口而发生错误
typedef enum{
    Multiple_ID_0 = 0,
    Multiple_ID_1 = 1,
    Multiple_ID_2 = 2,
    Multiple_ID_3 = 3,
    Multiple_ID_4 = 4,
    Single_ID_0 = 5,
} ENUM_ID_NO_TypeDef;

#define ESP8266_RST_Pin GPIO_Pin_6 //复位管脚
#define ESP8266_RST_Pin_Port GPIOE //复位 
#define ESP8266_RST_Pin_Periph_Clock RCC_APB2Periph_GPIOE //复位时钟

#define ESP8266_CH_PD_Pin GPIO_Pin_7 //使能管脚
#define ESP8266_CH_PD_Pin_Port GPIOG //使能端口
#define ESP8266_CH_PD_Pin_Periph_Clock RCC_APB2Periph_GPIOG //使能时钟


#define ESP8266_RST_Pin_SetH GPIO_SetBits(ESP8266_RST_Pin_Port,ESP8266_RST_Pin)
#define ESP8266_RST_Pin_SetL GPIO_ResetBits(ESP8266_RST_Pin_Port,ESP8266_RST_Pin)


#define ESP8266_CH_PD_Pin_SetH GPIO_SetBits(ESP8266_CH_PD_Pin_Port,ESP8266_CH_PD_Pin)
#define ESP8266_CH_PD_Pin_SetL GPIO_ResetBits(ESP8266_CH_PD_Pin_Port,ESP8266_CH_PD_Pin)


#define ESP8266_USART(fmt, ...) USART_printf (USART2, fmt, ##__VA_ARGS__) //USART_printf是串口发送函数,在esp8266_public.c里面
#define PC_USART(fmt, ...) printf (fmt, ##__VA_ARGS__) //这是串口打印函数,串口1,执行printf后会自动执行fput函数,重定向了printf。



#define RX_BUF_MAX_LEN 1024 //最大字节数
extern struct STRUCT_USART_Fram   //数据帧结构体
{
    char Data_RX_BUF[RX_BUF_MAX_LEN];
    union 
    {
        __IO u16 InfAll;
        struct 
        {
            __IO u16 FramLength       :15;                               // 14:0 
            __IO u16 FramFinishFlag   :1;                                // 15 
        }InfBit;
    }; 
}ESP8266_Fram_Record_Struct;





//功能函数
void ESP8266_Init(u32 bound);
void ESP8266_AT_Test(void);
bool ESP8266_Send_AT_Cmd(char *cmd,char *ack1,char *ack2,u32 time);
void ESP8266_Rst(void);
bool ESP8266_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode);
bool ESP8266_JoinAP( char * pSSID, char * pPassWord );
bool ESP8266_Enable_MultipleId ( FunctionalState enumEnUnvarnishTx );
bool ESP8266_Link_Server(ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id);
bool ESP8266_SendString(FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId );
bool ESP8266_UnvarnishSend ( void );
void ESP8266_ExitUnvarnishSend ( void );
u8 ESP8266_Get_LinkStatus ( void );

#endif

2)esp8266_drive.c服务器

#include "esp8266_drive.h"
#include "SysTick.h"
#include <stdio.h> 
#include <string.h> 
#include <stdbool.h>
#include "sta_tcpclent_test.h"
#include "esp8266_public.h"



struct STRUCT_USART_Fram ESP8266_Fram_Record_Struct = { 0 };  //定义了一个数据帧结构体




void USART3_Init(u32 bound)
{

    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //¸´ÓÃÍÆÍìÊä³ö
    GPIO_Init(GPIOB, &GPIO_InitStructure);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB11
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

    //Usart3 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      //响应优先级0
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //USART_IRQn通道使能
    NVIC_Init(&NVIC_InitStructure); //初始化NVIC

    //USART3 配置
    USART_InitStructure.USART_BaudRate = bound;//波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据长度
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//中止位1
    USART_InitStructure.USART_Parity = USART_Parity_No;//校验位无
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制无
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //使能串口的接收和发送功能
    USART_Init(USART3, &USART_InitStructure); //初始化串口

    USART_ITConfig(USART3, USART_IT_RXNE|USART_IT_IDLE, ENABLE);//配置了接收中断和总线空闲中断

    USART_Cmd(USART3, ENABLE);      //串口外设使能 
}

void USART3_IRQHandler( void )
{   
    u8 ucCh;

    if(USART_GetITStatus( USART3, USART_IT_RXNE ) != RESET )
    {
        ucCh  = USART_ReceiveData( USART3 );

        if(ESP8266_Fram_Record_Struct .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) ) 
        {
            //留最后一位作结束位
            ESP8266_Fram_Record_Struct .Data_RX_BUF[ ESP8266_Fram_Record_Struct .InfBit .FramLength ++ ]  = ucCh;   
        }                      
    }

    if( USART_GetITStatus( USART3, USART_IT_IDLE ) == SET )                              //若是总线空闲
    {
        ESP8266_Fram_Record_Struct .InfBit .FramFinishFlag = 1;

        ucCh = USART_ReceiveData( USART3 );                                                              //由软件序列清除中断标志位(先读USART_SR,而后读USART_DR)

        TcpClosedFlag = strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "CLOSED\r\n" ) ? 1 : 0;

    }   

}



void USART2_Init(u32 bound)
{

    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA2 TXD
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
    GPIO_Init(GPIOA, &GPIO_InitStructure);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3 RXD
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);


    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         
    NVIC_Init(&NVIC_InitStructure); 

    //USART2
    USART_InitStructure.USART_BaudRate = bound;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 
    USART_Init(USART2, &USART_InitStructure); 
    USART_ITConfig(USART2, USART_IT_RXNE|USART_IT_IDLE, ENABLE);

    USART_Cmd(USART2, ENABLE);                    
}

void USART2_IRQHandler( void )
{   
    u8 ucCh;

    if(USART_GetITStatus( USART2, USART_IT_RXNE ) != RESET )
    {
        ucCh  = USART_ReceiveData( USART2 );

        if(ESP8266_Fram_Record_Struct .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) ) 
        {

            ESP8266_Fram_Record_Struct .Data_RX_BUF[ ESP8266_Fram_Record_Struct .InfBit .FramLength ++ ]  = ucCh;   
        }                      
    }

    if( USART_GetITStatus( USART2, USART_IT_IDLE ) == SET )                                         //若是总线空闲
    {
        ESP8266_Fram_Record_Struct .InfBit .FramFinishFlag = 1;

        ucCh = USART_ReceiveData( USART2 );                                                              //由软件序列清除中断标志位(先读USART_SR,而后读USART_DR)

        TcpClosedFlag = strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "CLOSED\r\n" ) ? 1 : 0;

    }   

}

void ESP8266_Init(u32 bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(ESP8266_RST_Pin_Periph_Clock|ESP8266_CH_PD_Pin_Periph_Clock, ENABLE);

    GPIO_InitStructure.GPIO_Pin = ESP8266_RST_Pin;             
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //晶振频率
    GPIO_Init(ESP8266_RST_Pin_Port, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = ESP8266_CH_PD_Pin;               
    GPIO_Init(ESP8266_CH_PD_Pin_Port, &GPIO_InitStructure);

    USART2_Init(bound);

    ESP8266_RST_Pin_SetH;
    ESP8266_CH_PD_Pin_SetL; 
}



//对ESP8266模块发送AT指令
// cmd 待发送的指令
// ack1,ack2;期待的响应,为NULL表不需响应,二者为或逻辑关系
// time 等待响应时间
//返回1发送成功, 0失败
bool ESP8266_Send_AT_Cmd(char *cmd,char *ack1,char *ack2,u32 time)
{
    ESP8266_Fram_Record_Struct .InfBit .FramLength = 0; //从新接收新的数据包
    ESP8266_USART("%s\r\n", cmd);
    if(ack1==0&&ack2==0)     //不须要接收数据
    {
                      return true;

    }
    delay_ms(time);   //延时

    ESP8266_Fram_Record_Struct.Data_RX_BUF[ESP8266_Fram_Record_Struct.InfBit.FramLength ] = '\0';

    //PC_USART("%s", ESP8266_Fram_Record_Struct .Data_RX_BUF);
  printf("%s",ESP8266_Fram_Record_Struct .Data_RX_BUF);
    if(ack1!=0&&ack2!=0)
    {
        return ( ( bool ) strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, ack1 ) || 
                         ( bool ) strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, ack2 ) );
    }
    else if( ack1 != 0 )  //strstr(s1,s2);检测s2是否为s1的一部分,是返回该位置,不然返回false,它强制转换为bool类型了
        return ( ( bool ) strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, ack1 ) );

    else
        return ( ( bool ) strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, ack2 ) );

}


//复位重启
void ESP8266_Rst(void)
{
    ESP8266_RST_Pin_SetL;
    delay_ms(500); 
    ESP8266_RST_Pin_SetH;
}


//发送AT启动测试
void ESP8266_AT_Test(void)
{
    char count=0;

    ESP8266_RST_Pin_SetH;
    delay_ms(1000); 
    while(count < 10)
    {
        if(ESP8266_Send_AT_Cmd("AT","OK",NULL,500)) 
        {
            printf("OK\r\n");
            return;
        }

        ESP8266_Rst();
        ++ count;
    }
}


//选择ESP8266的工做模式
// enumMode 模式类型
//成功返回true,失败返回false
bool ESP8266_Net_Mode_Choose(ENUM_Net_ModeTypeDef enumMode)
{
    switch ( enumMode )
    {
        case STA:
            return ESP8266_Send_AT_Cmd ( "AT+CWMODE=1", "OK", "no change", 2500 ); 

        case AP:
            return ESP8266_Send_AT_Cmd ( "AT+CWMODE=2", "OK", "no change", 2500 ); 

        case STA_AP:
            return ESP8266_Send_AT_Cmd ( "AT+CWMODE=3", "OK", "no change", 2500 ); 

        default:
          return false;
    }       
}


//ESP8266链接外部的WIFI
//pSSID WiFi账号
//pPassWord WiFi密码
//设置成功返回true 反之false
bool ESP8266_JoinAP( char * pSSID, char * pPassWord )
{
    char cCmd [120];

    sprintf ( cCmd, "AT+CWJAP=\"%s\",\"%s\"", pSSID, pPassWord );

    return ESP8266_Send_AT_Cmd( cCmd, "OK", NULL, 5000 );

}


//ESP8266 透传使能
//enumEnUnvarnishTx 是否多链接,bool类型
//设置成功返回true,反之false
bool ESP8266_Enable_MultipleId (FunctionalState enumEnUnvarnishTx )
{
    char cStr [20];

    sprintf ( cStr, "AT+CIPMUX=%d", ( enumEnUnvarnishTx ? 1 : 0 ) );

    return ESP8266_Send_AT_Cmd ( cStr, "OK", 0, 500 );

}


//ESP8266 链接服务器
//enumE 网络类型
//ip ,服务器IP
//ComNum 服务器端口
//id,链接号,确保通讯不受外界干扰
//设置成功返回true,反之fasle
bool ESP8266_Link_Server(ENUM_NetPro_TypeDef enumE, char * ip, char * ComNum, ENUM_ID_NO_TypeDef id)
{
    char cStr [100] = { 0 }, cCmd [120];

    switch (  enumE )
    {
        case enumTCP:
          sprintf ( cStr, "\"%s\",\"%s\",%s", "TCP", ip, ComNum );
          break;

        case enumUDP:
          sprintf ( cStr, "\"%s\",\"%s\",%s", "UDP", ip, ComNum );
          break;

        default:
            break;
    }

    if ( id < 5 )
        sprintf ( cCmd, "AT+CIPSTART=%d,%s", id, cStr);

    else
        sprintf ( cCmd, "AT+CIPSTART=%s", cStr );

    return ESP8266_Send_AT_Cmd ( cCmd, "OK", "ALREAY CONNECT", 4000 );

}


//透传使能
//设置成功返回true, 反之false
bool ESP8266_UnvarnishSend ( void )
{
    if (!ESP8266_Send_AT_Cmd ( "AT+CIPMODE=1", "OK", 0, 500 ))
        return false;

    return 
        ESP8266_Send_AT_Cmd( "AT+CIPSEND", "OK", ">", 500 );

}


//ESP8266发送字符串
//enumEnUnvarnishTx是否使能透传模式
//pStr字符串
//ulStrLength字符串长度
//ucId 链接号
//设置成功返回true, 反之false
bool ESP8266_SendString(FunctionalState enumEnUnvarnishTx, char * pStr, u32 ulStrLength, ENUM_ID_NO_TypeDef ucId )
{
    char cStr [20];
    bool bRet = false;


    if ( enumEnUnvarnishTx )
    {
        ESP8266_USART ( "%s", pStr );

        bRet = true;

    }

    else
    {
        if ( ucId < 5 )
            sprintf ( cStr, "AT+CIPSEND=%d,%d", ucId, ulStrLength + 2 );

        else
            sprintf ( cStr, "AT+CIPSEND=%d", ulStrLength + 2 );

        ESP8266_Send_AT_Cmd ( cStr, "> ", 0, 1000 );

        bRet = ESP8266_Send_AT_Cmd ( pStr, "SEND OK", 0, 1000 );
  }

    return bRet;

}


//ESP8266退出透传模式
void ESP8266_ExitUnvarnishSend ( void )
{
    delay_ms(1000);
    ESP8266_USART( "+++" );
    delay_ms( 500 );    
}


//ESP8266 检测链接状态
//返回0:获取状态失败
//返回2:得到ip
//返回3:创建链接 
//返回4:失去链接 
u8 ESP8266_Get_LinkStatus ( void )
{
    if (ESP8266_Send_AT_Cmd( "AT+CIPSTATUS", "OK", 0, 500 ) )
    {
        if ( strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "STATUS:2\r\n" ) )
            return 2;

        else if ( strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "STATUS:3\r\n" ) )
            return 3;

        else if ( strstr ( ESP8266_Fram_Record_Struct .Data_RX_BUF, "STATUS:4\r\n" ) )
            return 4;       

    }

    return 0;

}

二、ESP8266的public文件

1)esp8266_public.h网络

#ifndef _esp8266_public_H
#define _esp8266_public_H

#include "system.h"
void USART_printf( USART_TypeDef * USARTx, char * Data, ... );
#endif

2)esp8266_public.ctcp

#include "esp8266_public.h"
#include <stdarg.h>



static char *itoa( int value, char *string, int radix )
{
    int     i, d;
    int     flag = 0;
    char    *ptr = string;

    /* This implementation only works for decimal numbers. */
    if (radix != 10)
    {
        *ptr = 0;
        return string;
    }

    if (!value)
    {
        *ptr++ = 0x30;
        *ptr = 0;
        return string;
    }

    /* if this is a negative value insert the minus sign. */
    if (value < 0)
    {
        *ptr++ = '-';

        /* Make the value positive. */
        value *= -1;

    }

    for (i = 10000; i > 0; i /= 10)
    {
        d = value / i;

        if (d || flag)
        {
            *ptr++ = (char)(d + 0x30);
            value -= (d * i);
            flag = 1;
        }
    }

    /* Null terminate the string. */
    *ptr = 0;

    return string;

} /* NCL_Itoa */


void USART_printf ( USART_TypeDef * USARTx, char * Data, ... )
{
    const char *s;
    int d;   
    char buf[16];


    va_list ap;
    va_start(ap, Data);

    while ( * Data != 0 )     // 判断数据是否到达结束符
    {                                         
        if ( * Data == 0x5c )  //'\'
        {                                     
            switch ( *++Data )
            {
                case 'r':                                     //回车符
                USART_SendData(USARTx, 0x0d);
                Data ++;
                break;

                case 'n':                                     //换行符
                USART_SendData(USARTx, 0x0a);   
                Data ++;
                break;

                default:
                Data ++;
                break;
            }            
        }

        else if ( * Data == '%')
        {                                     
            switch ( *++Data )
            {               
                case 's':                                         //字符串
                s = va_arg(ap, const char *);
                for ( ; *s; s++) 
                {
                    USART_SendData(USARTx,*s);
                    while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
                }
                Data++;
                break;

                case 'd':           
                    //十进制
                d = va_arg(ap, int);
                itoa(d, buf, 10);
                for (s = buf; *s; s++) 
                {
                    USART_SendData(USARTx,*s);
                    while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
                }
                     Data++;
                     break;
                default:
                     Data++;
                     break;
            }        
        }
        else USART_SendData(USARTx, *Data++);
        while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );

    }
}

三、客户端(STA数据透传测试)

1)sta_tcpclent_test.hsvg

#ifndef _sta_tcpclent_test_H
#define _sta_tcpclent_test_H
#include "system.h"

#define User_ESP8266_SSID     "S237"          //wifi名
#define User_ESP8266_PWD      "20152620"      //wifi密码

#define User_ESP8266_TCPServer_IP     "192.168.1.106"     //服务器IP
#define User_ESP8266_TCPServer_PORT   "8080"      //服务器端口号


extern volatile uint8_t TcpClosedFlag;  //链接状态标志

void ESP8266_STA_TCPClient_Test(void);



#endif

2)sta_tcpclent_test.c函数

#include "sta_tcpclent_test.h"
#include "SysTick.h"
#include "usart.h"
#include "esp8266_drive.h"


volatile u8 TcpClosedFlag = 0;


void ESP8266_STA_TCPClient_Test(void)
{
    u8 res;

    char str[100]={0};

    printf ( "\r\正在配置esp8266,请耐心等待...\r\n" );

    ESP8266_CH_PD_Pin_SetH;
    ESP8266_AT_Test();
    ESP8266_Net_Mode_Choose(STA);
    while(!ESP8266_JoinAP(User_ESP8266_SSID, User_ESP8266_PWD));
    ESP8266_Enable_MultipleId ( DISABLE );
    while(!ESP8266_Link_Server(enumTCP, User_ESP8266_TCPServer_IP, User_ESP8266_TCPServer_PORT, Single_ID_0));

    while(!ESP8266_UnvarnishSend());
    printf ( "\r\nESP8266配置 OK\r\n" );

    while ( 1 )
    {       
        sprintf (str,"I am very good!\r\n" );  //格式化 即str = "I am very good!\r\n"
        ESP8266_SendString ( ENABLE, str, 0, Single_ID_0 );
        delay_ms(1000);
        if(TcpClosedFlag) //判断是否失去链接
        {
            ESP8266_ExitUnvarnishSend(); //退出透传模式
            do
            {
                res = ESP8266_Get_LinkStatus();     //获取链接状态
            }   
            while(!res);

            if(res == 4)                     //确认失去链接,重连
            {
                printf ( "\r\从新链接...\r\n" );

                while (!ESP8266_JoinAP(User_ESP8266_SSID, User_ESP8266_PWD ) );

                while (!ESP8266_Link_Server(enumTCP, User_ESP8266_TCPServer_IP, User_ESP8266_TCPServer_PORT, Single_ID_0 ) );

                printf ( "\r\从新链接成功\r\n" );
            } 
            while(!ESP8266_UnvarnishSend());                    
        }
    }   
}

四、其余工程文件请下载:

ESP8266-WIFI数据透传 免费下载连接:
http://download.csdn.net/detail/it_boy__/9842033测试