基于STM32F103与ESP8266的网络日历

基于STM32F103与ESP8266的网络日历

最近尝试用ESP8266模块实现网络日历功能,通过免费的API接口NOW-API 获取网络时间与天气,大致思路是通过ESP8266连接服务器并通过HTTP GET的方式获取所需信息,以下是串口驱动ESP8266的代码及获取Demo。


代码块

ESP8266驱动esp8266.c


#include "stm32f10x.h"

#include "esp8266.h"

#include "delay.h"
#include "usart.h"

#include <stdarg.h>
#include <string.h>
#include <stdio.h>
//这里修改WIFI名称和密码
#define ESP8266_WIFI_INFO       "AT+CWJAP=\"TP-LINK_302\",\"330022AABBCCDD\"\r\n"

#define ESP8266_TIME_INFO   "AT+CIPSTART=\"TCP\",\"api.k780.com\",80\r\n"

char get_time0[] = "GET http://api.k780.com/?app=life.time&appkey=35488&sign=5138e2ad3378313fb818787e185054ae&format=json\r\n";
//阅读API接口说明后修改下面数据中的城市代码
char get_weather0[] = "GET http://api.k780.com/?app=weather.today&weaid=151&appkey=35488&sign=5138e2ad3378313fb818787e185054ae&format=json\r\n";
int i;
unsigned char esp8266_buf[1024];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;
extern clock localTime;//时间结构体
extern weather WEA;//天气结构体

#define REV_OK      0   
#define REV_WAIT    1   

void Usart2_Init(unsigned int baud)
{

    GPIO_InitTypeDef gpioInitStruct;
    USART_InitTypeDef usartInitStruct;
    NVIC_InitTypeDef nvicInitStruct;

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

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

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

    usartInitStruct.USART_BaudRate = baud;
    usartInitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;     
    usartInitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                     
    usartInitStruct.USART_Parity = USART_Parity_No;                                 
    usartInitStruct.USART_StopBits = USART_StopBits_1;                              
    usartInitStruct.USART_WordLength = USART_WordLength_8b;                         
    USART_Init(USART2, &usartInitStruct);

    USART_Cmd(USART2, ENABLE);                                                      

    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);                                  

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

}

void ESP8266_Clear(void)
{

    memset(esp8266_buf, 0, sizeof(esp8266_buf));
    esp8266_cnt = 0;

}

_Bool ESP8266_WaitRecive(void)
{

    if(esp8266_cnt == 0)                            
        return REV_WAIT;

    if(esp8266_cnt == esp8266_cntPre)           
    {
        esp8266_cnt = 0;                            

        return REV_OK;                          
    }

    esp8266_cntPre = esp8266_cnt;                   

    return REV_WAIT;                                

}

_Bool ESP8266_SendCmd(char *cmd, char *res)
{

    unsigned char timeOut = 200;

    Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));

    while(timeOut--)
    {
        if(ESP8266_WaitRecive() == REV_OK)                      
        {
            if(strstr((const char *)esp8266_buf, res) != NULL)      
            {
                ESP8266_Clear();                                    

                return 0;
            }
        }

        DelayXms(10);
    }

    return 1;

}

void ESP8266_SendData(unsigned char *data, unsigned short len)
{

    char cmdBuf[32];

    ESP8266_Clear();                                
    sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len);      
    if(!ESP8266_SendCmd(cmdBuf, ">"))               
    {
        Usart_SendString(USART2, data, len);        
    }

}

{

    char *ptrIPD = NULL;

    do
    {
        if(ESP8266_WaitRecive() == REV_OK)                              
        {
            ptrIPD = strstr((char *)esp8266_buf, "IPD,");//IPD为ESP8266设备返回接收数据前的标志              
            if(ptrIPD == NULL)                                          
            {

            }
            else
            {
                ptrIPD = strchr(ptrIPD, ':');                           
                if(ptrIPD != NULL)
                {
                    ptrIPD++;
                    return (unsigned char *)(ptrIPD);
                }
                else
                    return NULL;

            }
        }

        DelayXms(5);                                                    
    } while(timeOut--);

    return NULL;                                                    

}

void ESP8266_Init(void)
{

    GPIO_InitTypeDef GPIO_Initure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Initure.GPIO_Pin = GPIO_Pin_0;                 
    GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_Initure);

    GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
    DelayXms(250);
    GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
    DelayXms(500);

    ESP8266_Clear();
    while(ESP8266_SendCmd("AT\r\n", "OK"))
    DelayXms(500);

    while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
    DelayXms(500);

    ESP8266_Clear();
}

void ESP8266_Init_TIME(void)
{

    GPIO_InitTypeDef GPIO_Initure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    //ESP8266重启
    GPIO_Initure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Initure.GPIO_Pin = GPIO_Pin_0;                 
    GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_Initure);

    GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
    DelayXms(250);
    GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
    DelayXms(500);

    ESP8266_Clear();

    while(ESP8266_SendCmd("AT\r\n", "OK"))
    DelayXms(500);

    while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
    DelayXms(500);

    while(ESP8266_SendCmd(ESP8266_TIME_INFO, "CONNECT"))
    DelayXms(500);

    ESP8266_Clear();


}

void    ESP8266_GETTIME(char *buff,int timeOut)
{
    char *ptrIPD = NULL;
    ESP8266_Init_TIME();
    ESP8266_SendData((unsigned char *)buff, strlen(buff));  

        do
        {
             //检查HTTP GET 后返回的数据是否正常
            ptrIPD = strstr((const char*)esp8266_buf, "datetime_2");

            if(ptrIPD == NULL)
            {

            }
      else
            {   
                        localTime.month =10*(*(ptrIPD-95+109-31)-0x30)+*(ptrIPD-95+110-31)-0x30;
                     localTime.day =10*(*(ptrIPD-95+112-31)-0x30)+*(ptrIPD-95+113-31)-0x30;

                     for(j=0;j<15;j++)
                         {
                            localTime.date[j] =*(ptrIPD-95+236-31+j);
                         }

            if(strstr((char *)localTime.date, "Sun")!=NULL){localTime.dateTemp=0;}
            else if(strstr((char *)localTime.date, "Mon")!=NULL){localTime.dateTemp=1;}
                        else if(strstr((char *)localTime.date, "Tue")!=NULL){localTime.dateTemp=2;}
                        else if(strstr((char *)localTime.date, "Wed")!=NULL){localTime.dateTemp=3;}
                        else if(strstr((char *)localTime.date, "Thu")!=NULL){localTime.dateTemp=4;}
                        else if(strstr((char *)localTime.date, "Fri")!=NULL){localTime.dateTemp=5;}
                        else if(strstr((char *)localTime.date, "Sat")!=NULL){localTime.dateTemp=6;}

    localTime.hour =10*(*(ptrIPD-95+115-31)-0x30)+*(ptrIPD-95+116-31)-0x30;
    localTime.min =10*(*(ptrIPD-95+118-31)-0x30)+*(ptrIPD-95+119-31)-0x30;
    localTime.sec =10*(*(ptrIPD-95+121-31)-0x30)+*(ptrIPD-95+122-31)-0x30+1;//延时补偿,可自行调整

                 if(localTime.sec>=60)
                         {
                             localTime.sec=localTime.sec-60;
                             localTime.min=localTime.min+1;
                             if(localTime.min==60)
                             {
                                 localTime.min=0;
                                 localTime.hour++;
                             }

                         }
          }
        DelayXms(10);                                                   
    } while(timeOut--);
    //检查接收是否成功,不成功重新再来
      if(localTime.date[0]==0x00)
        {
            ESP8266_Clear();
            ESP8266_GETTIME(get_time0,500);
        }

    ESP8266_Clear();
}



void    ESP8266_GETWEATHER(char *buff,int timeOut)
{
  char *IPD,*aqi,*daywea,*id,*gif= NULL;
    ESP8266_Init_TIME();
    ESP8266_SendData((unsigned char *)buff, strlen(buff));  

    do
    {
          IPD = strstr((char *)esp8266_buf, "IPD,");                
            if(IPD == NULL)                                         
            {

            }
            else
            {

          }

        DelayXms(1);                                                    
    } while(timeOut--);

      aqi = strstr((char *)esp8266_buf, "aqi");

           if(*(aqi+8)==0x22)
                    {
                        WEA.aqi=10*(*(aqi+6)-0x30)+*(aqi+7)-0x30;
                    }
                    else if(*(aqi+8)==0x22)
                    {
                      WEA.aqi=100*(*(aqi+6)-0x30)+10*(*(aqi+7)-0x30)+*(aqi+8)-0x30;
                    }   

        daywea = strstr((char *)esp8266_buf, "weather");

                for(i=0;i<32;i++)
                  {
                        WEA.dayweather[i]=*(daywea+10+i);
                    }

        id = strstr((char *)esp8266_buf, "weatid");

                    if(*(id+10)==0x22)
                    {
                        WEA.weatid=(*(id+9)-0x30);
                    }
                    else if(*(id+10)!=0x22)
                    {
                      WEA.weatid=10*(*(id+9)-0x30)+*(id+10)-0x30;
                    }   
        gif = strstr((char *)esp8266_buf, "weather_iconid");        

                    if(*(gif+18)==0x22)
                    {
                        WEA.weagif=(*(gif+17)-0x30);
                    }
                    else if(*(gif+18)!=0x22)
                    {
                      WEA.weagif=10*(*(gif+17)-0x30)+*(gif+18)-0x30;
                    }   

          if(WEA.dayweather[0]==0x00)
        {
            ESP8266_Clear();
      ESP8266_GETWEATHER(get_weather0,500);
        }
      ESP8266_Clear();
}

void USART2_IRQHandler(void)
{

    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) 
    {
        if(esp8266_cnt >= sizeof(esp8266_buf))  esp8266_cnt = 0; 
        esp8266_buf[esp8266_cnt++] = USART2->DR;

        USART_ClearFlag(USART2, USART_FLAG_RXNE);
    }

}

头文件esp8266.h

#ifndef ESP8266_h
#define ESP8266_h

typedef struct
{
  unsigned char sec;
  unsigned char min;
  unsigned char hour;
  unsigned char day;
  unsigned char date[4];
  unsigned char month;
  unsigned char year;
  unsigned char dateTemp;
}clock;

typedef struct
{
  u16 aqi;
  unsigned char dayweather[32];
  unsigned char weatid;
  u16 weagif;
}weather;

void Usart2_Init(unsigned int baud)£»

void esp8266_init(void);
void esp8266_get_tianqi(void);
void esp8266_get_shijian(void);
void esp8266_get_time(void);
void dispose_time_data(void);

void ESP8266_Init(void);
void ESP8266_Init_TIME(void);
void ESP8266_GETTIME(char *buff,int timeOut);
void ESP8266_GETWEATHER(char *buff,int timeOut);

void ESP8266_Clear(void);

void ESP8266_SendData(unsigned char *data, unsigned short len);

unsigned char *ESP8266_GetIPD(unsigned short timeOut);

#endif

其余的延时函数delay.c,delay.h参考我的博客基于STM32F103与MY2480-16P语音模块的时钟兼闹钟设计(第一部分)
下面是测试程序main.c

//单片机头文件
#include "stm32f10x.h"

//网络设备
#include "esp8266.h"

//硬件驱动
#include "delay.h"
#include "usart.h"

//C库
#include <string.h>
#include <stdio.h>

clock localTime;
weather WEA;

char get_time[] = "GET http://api.k780.com/?app=life.time&appkey=35488&sign=5138e2ad3378313fb818787e185054ae&format=json\r\n";
//阅读API接口说明后修改下面数据中的城市代码
char get_weather[] = "GET http://api.k780.com/?app=weather.today&weaid=151&appkey=35488&sign=5138e2ad3378313fb818787e185054ae&format=json\r\n";
u8 time[6];

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断控制器分组设置

    Delay_Init();                                   //systick初始化

    Usart2_Init(115200);                            //串口2,驱动ESP8266用

    ESP8266_GETTIME(get_time,500);                  //获取时间

    ESP8266_GETWEATHER(get_weather,500);            //获取天气  

    DelayXms(250);
}

注意事项

  1. 对HTTP GET方式不熟悉的请先仔细阅读NOW-API的说明文档
  2. 该代码配合我的第一篇博客基于STM32F103与MY2480-16P语音模块的时钟兼闹钟设计(第一部分),可以实现完整的网络时钟功能,日后会将完整工程上传

猜你喜欢

转载自blog.csdn.net/qq_37168444/article/details/82528132