基于STM32F103与ESP8266的网络日历_esp8266+stm32获取网络时间-程序员宅基地

技术标签: STM32  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);		
	}

}

unsigned char *ESP8266_GetIPD(unsigned short timeOut)
{

	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语音模块的时钟兼闹钟设计(第一部分),可以实现完整的网络时钟功能,日后会将完整工程上传
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37168444/article/details/82528132

智能推荐

Java详解剑指offer面试题18--删除链表的结点_java创建一个单项循环链表,每经过三个结点,就删除第三个结点 → 找到最后遗留的一-程序员宅基地

文章浏览阅读213次。Java详解剑指offer面试题18——删除链表的结点题目一——O(1)删除链表结点给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间内删除该结点。假设要删除的结点确实在链表中。常规思路:删除某个结点需要找到该结点的前一个结点,由于单向链表没有指向前一个结点的指针,所以不得不从头指针开始遍历链表。显然时间复杂度为O(n)。实现如下:package Chap3;public class DeleteNode { private class Node { _java创建一个单项循环链表,每经过三个结点,就删除第三个结点 → 找到最后遗留的一

Unity - Ray射线检测_overlapspherenonalloc-程序员宅基地

文章浏览阅读3.2k次,点赞8次,收藏20次。一:Ray射线定义:射线是一条从原点出发,沿某一方向运动的无限直线。//创建一条初始位置为startPos,方向为dir的一条射线Ray ray = new Ray (startPos, dir);//创建一条从摄像机通过屏幕点的光线。//得到的光线在世界空间中,从相机的近平面开始,经过屏幕上的(x,y)像素坐标(位置)。z是忽略。Ray camerRay = Camera.main..._overlapspherenonalloc

使用硬件I2C读取甲醛传感器SGP30嵌入式_sgp30 不模拟i2c-程序员宅基地

文章浏览阅读203次。我们通过配置STM32CubeMX来初始化I2C外设,并编写代码来实现传感器的初始化和数据读取。在实际应用中,可以将读取到的甲醛浓度数据与预设的阈值进行比较,以便及时采取相应的措施来改善室内空气质量。因此,在许多应用中,监测室内空气中甲醛浓度的传感器变得越来越重要。通过以上步骤,我们可以使用硬件I2C在嵌入式系统中读取甲醛传感器SGP30的数据。打开Keil MDK,创建一个新的工程,并将生成的初始化代码添加到该工程中。最后,我们需要在main函数中调用这些函数,并添加必要的延时以进行周期性的数据读取。_sgp30 不模拟i2c

【iOS开发解决Tableview(CollectionView)上子视图和父试图手势冲突】_ios tableview 滑动手势冲突-程序员宅基地

文章浏览阅读605次。else { //如果不是,则恢复滑动。_ios tableview 滑动手势冲突

IDEA中用Service窗口展示所有服务及端口的办法_idea的service-程序员宅基地

文章浏览阅读1.2w次,点赞13次,收藏19次。IDEA中微服务在service窗口以配置方式启动网上千篇一律的在 workspace.xml中配置Run Dashboard,但是只有在旧版本中才有这个节点的配置。但是新版的该怎么办呢?压根就没有这个节点,硬着头皮添加进去你会发现,问题依然存在。纠结的我捣鼓一个夜晚终于搞明白了,赶紧激动的记录下来,和小伙伴们分享我的成果!1.idea版本我使用的版本是2020.1.1,service窗口中可以以配置方式启动微服务,一般是配置不同端口号启动。如下图。(但是在旧版本中,对应的窗口叫做Run Dash_idea的service

基础入门篇 | YOLOv8 项目【训练】【验证】【推理】最简单教程 | YOLOv8必看 | 最新更新,直接打印 FPS,mAP50,75,95_yolov8推理-程序员宅基地

文章浏览阅读1.1w次,点赞16次,收藏33次。三个文件搞定YOLOv8【训练】【验证】【推理】_yolov8推理

随便推点

下载的nginx证书转换成tomcat证书格式_nginx 证书 转换为pkcs12 证书-程序员宅基地

文章浏览阅读709次。XXX.crt private.key_nginx 证书 转换为pkcs12 证书

C#学习笔记11:winform上位机与西门子PLC网口通信_下篇-程序员宅基地

文章浏览阅读642次,点赞14次,收藏14次。主要知识点有:IP地址填写检查方法、读取写入方法、西门子PLC变量地址与类型的关系文章提供测试代码讲解、参数效果贴出、整体工程下载

一文讲清微服务架构、分布式架构、微服务、SOA_分布式架构与soa架构与微服务的区别-程序员宅基地

文章浏览阅读373次,点赞18次,收藏19次。中级架构,分布式应用,中间层分布式+数据库分布式,是单体架构的并发扩展,将一个大的系统划分为多个业务模块,业务模块分别部署在不同的服务器上,各个业务模块之间通过接口进行数据交互。**2.微服务架构:**其实和 SOA 架构类似,微服务是在 SOA 上做的升华,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”,原有的单个业务系统会拆分为多个可以独立开发、设计、运行的小应用。而且,它可以标准化,同样的容器不管在哪里运行,结果都是一样的,所以市场上有很多 SaaS 产品,提供标准化的微服务。

爆火的大规模深度学习模型是如何有效训练的?首篇综述一探究竟!-程序员宅基地

文章浏览阅读626次。点击下方卡片,关注“自动驾驶之心”公众号ADAS巨卷干货,即可获取点击进入→自动驾驶之心【AIGC】技术交流群摘要近年来,深度学习领域取得了重大进展,特别是在计算机视觉(CV)、自然语言处理(NLP)和语音等领域。根据大量数据训练的大规模模型的使用为实际应用、提高工业生产力和促进社会发展带来了巨大的希望。然而,它极易受到不稳定的训练过程和对计算资源的严格要求的影响。随着对计算能力自适应的要求越来越..._深度学习增量训练的训练过程

基于CTF探讨Web漏洞的利用与防范_漏洞利用场景ctf-程序员宅基地

文章浏览阅读1.3k次,点赞44次,收藏29次。随着Web2.0、社交网络、微博等等一系列新型的互联网产品的诞生,基于Web环境的互联网应用越来越广泛,企业信息化的过程中各种应用都架设在Web平台上,Web业务的迅速发展也引起黑客们的强烈关注,接踵而至的就是Web安全威胁的凸显,黑客利用网站操作系统的漏洞和Web服务程序的SQL注入漏洞等得到Web服务器的控制权限,轻则篡改网页内容,重则窃取重要内部数据,更为严重的则是在网页中植入恶意代码,使得网站访问者受到侵害。这也使得越来越多的用户关注应用层的安全问题,对Web应用安全的关注度也逐渐升温。_漏洞利用场景ctf

Mac 卸载 隐蔽软件 Core_Sync 的步骤_core sync-程序员宅基地

文章浏览阅读5.8k次。Mac 卸载 隐蔽软件 Core_Sync 的步骤_core sync