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