就权当是给自己写的一个总结吧。

中间也走过不少的弯路,没人指导,只有自己慢慢摸索,网上看到的教程也是零零散散,或许是自己C代码功底不够硬,总之照搬别人的结果坑到最后还是自己,搞得一身疲惫,最后索性,按自己的想法来搞,废话不多说,先上几张图:

esp8266天气时钟教程 esp8266 oled天气_单片机


esp8266天气时钟教程 esp8266 oled天气_嵌入式_02


esp8266天气时钟教程 esp8266 oled天气_stm32_03


esp8266天气时钟教程 esp8266 oled天气_stm32_04


esp8266天气时钟教程 esp8266 oled天气_esp8266天气时钟教程_05


esp8266天气时钟教程 esp8266 oled天气_stm32_06


共有6页,MCU上两个按键控制,K1向前翻页,K2向后翻,第1页为默认页,是switch控制的默认页,然后第二页是RTC实时时钟,翻到这页数字时钟就会自动地跑起来--

其实它是在后台跑的,永不停歇,除非没电池了!第三页为今天的天气预报,其实是由ESP8266访问心知天气服务端口后返回来的数据解析得来,说起来这也是一个坑!因为心知天气返回来的是cJSON数据,要分析它的代码谈何容易,对于只会C代码的我来说除了用strstr来截取关键字外别无它法,后来不服呀,索性又学下怎么去解析cJSON数据,这一学又花了我一天时间,学着学着发现自己又掉入了另一个坑:因为要解析cJSON之前必须要先检查下返回来的数据包是否是cJSON数据包,明明是原封不动的返回来的数据包,得到的却是乱码,没错,中文全是乱码!--可想知,英文的方便,那些说用中文来替代代码的不知道他是怎么想,不是我看得起英文,而是我还得再花功夫去把这一包cJSON数据中的中文转换为GBK格式!--网上说cJSON的数据是UTF8格式的。

真是越搞事越多,一个头两个大!

要想转换为GBK,我发现并不是那么容易,纯C语言好难搞,即使弄好了,你会发现,为了那三五个中文正常显示,你的代码量或文字表格会多出几十K出来!这是我不能容忍的,索性用英文吧,把GET XXX,中的语言换为en,这下子整个代码过程顺利多了!有人说Linux上很简单呀,你是这么说,但我是用KEIL5.0开发的,那些个头文件看着都陌生!难道还要去找,去下载这些个鬼东西?英文他不香吗?

最后在取字模软件上取自己想要的文字然后再替换一些英文,一切得到完美解决!

我以为OLED上要显示的天气图标网络上会提供数据的,结果找了好久,没有,想想也对,人家怎么知道你要多大像素的?一想到这里发现自己好笨,笨哭了!一边用取模软件提取图片数据包一边在暗骂自己,活该你单身!--等等?关单身什么事?好像我总是把对方想得很完美?

就像这些代码,本身也不能算是很完美,ESP8266要玩得好,不是一朝一夕的事,可用命令指令集来开发也可以直接开发,将代码烤进ESP8266,用寄存器来开发,这是我下一个学习的目标。现在先看下用AT指令集的:

首先是我写了一个指针数组,将需要用到的指令全都集中在一起,不会指针数组的网上也有很多教程哈,这里就不再啰嗦了。

const u8 *WIFI_CMD_TAB[]={     //指针数组
	"AT",
	"AT+CWMODE=1",//设置为STA模式
	"AT+RST",//复位
	"AT+CIPMUX=0",//单连接模式
	"AT+CWJAP=\"iPhone\",\"123456788\"",//连入WIFI热点
	"AT+CIPSTART=\"TCP\",\"api.seniverse.com\",80",//建立TCP连接
	"AT+CIPMODE=1",//开启透传模式
	"AT+CIPSEND",//发送数据
	"GET https://api.seniverse.com/v3/weather/now.json?key=SPidi8cEM8Os4k3vn&location=shenzhen&language=en&unit=c",//这里语言改为英文,我的密钥也提供给大家用了。
//	"+++",//不能放这里,因为不需要换行回车
//	"AT+CIPCLOSE",
};
const u8 *WIFI_CMD_INFO[]={//一些信息提示
    "开始启动...",
	"启动成功!",
	"STA模式配置...",
	"STA模式配置成功!",
	"复位中...",
	"复位成功!",
	"配置为单连接模式...",
	"单连接模式配置成功!",
	"接入WIFI热点...",
	"连接热点成功!",
	"建立TCP连接...",
	"TCP链接成功!",
	"开启透传模式...",
	"透传模式开启成功!",
	"发送数据...",
	"信息返回成功!",

};

第二个指针数组是提示。这里多说一句,本人不才,在这里问一下大家,这个串口通信能不能同时复用两组引脚?比如USART1,它可以复用PA9,PA10还有PD5,PD6,如果我两组都想一起用行不行?我自己试了一下,结果搞得两组引脚都失灵了,屏闭掉其中一组,另外一组又好了,实在无语!如果不用两组引脚,那么我就无法在串口助手上打印我需要的信息,我记得在做GPS实验时是可行的,为什么这里就不行了呢?仔细缕一下思路发现了问题:就是说两组引脚共用一个USART,会出现两个输入和两个输出,USART在串口打印出来变成输出,而只要有输出了,它又会变成是给ESP8266输出命令的!这有点乱套了,反正我是试不出来,不知道哪位兄弟做出来过,告知我一下。
对了,这里我要说一下,我用的是STM32F407VET6。
后来,我又充分挖掘了我的这颗小脑袋的潜能,我找到了一种方法,用两个串口通信:USART1,和USART2。
USART1连接ESP8266,USART2配合USART1和串口助手,这样我就能在串口助手上看到了调试信息,还能用串口助手给ESP8266发送指令!具体做法请看本文后边的代码,总
之呢,没有人带,靠自己去摸索,坑真的是一个接着一个,比如,ESP8266,要用AT退出透传真的好难,发了三个“+++”--此处没有回车换行,它是一点反应都没有,看来是我对ESP8266学得不够精,我承认了!我只会按MCU上的复位键,然后再“+++”,这样好多了,每次都能退出了。
回到正题:我用一个for循环就把所有的AT指令发送出去,因为我发现ESP8266也不是吃素的,它反应很快,都是秒应答的,既然如此,我为什么不发快一点呢,所以我用for循环把指令发送出去,而且后期上边的设置可能也不会再走一遍吧?因为每次只有连上网了,前边的设置不已经是默认的吗?

void WIFI_Init(void)
{
	int i;
	u8 mark = 0;

	for(i=0;i<WIFI_CMD_TAB_LEN;i++)
	{
		
		u2_printf("%s\r\n",WIFI_CMD_INFO[i]);

		if(ESP8266_SendCmd((u8*)WIFI_CMD_TAB[i],"OK",20))
		{
			if((i == (WIFI_CMD_TAB_LEN-1))&& strstr((const char*)Rx_Buff,"res"))
			{
				u2_printf("数据接收成功!\r\n");
				Analyze_The_Current_Weather();
				break;
			}
			else if(ESP8266_SendCmd((u8*)WIFI_CMD_TAB[i],"OK",300))//再试一次
			{
				if(strstr((const char*)Rx_Buff,"res"))
				{
					u2_printf("数据接收成功!\r\n");
					Analyze_The_Current_Weather();
					Quit_tran();
					break;
				}
				u2_printf("%d)指令超时,连接失败!\r\n",i);
				OLED_ShowStr(3,3,"WIFI DISCONNECT",1);
				Quit_tran();
				break;
			}
		}

		GPIO_ToggleBits(GPIOA,GPIO_Pin_7);
	}
	if(mark)u2_printf("WIFI连接错误,请复位重新连接!\r\n");
}

这里再多说一句关于按键的,按键还是少用中断为好,因为你一旦用了中断就会去设置中断服务函数,就会有可能与其它的中断优先级产生冲突,比如,刚开始做OLED显示的时候,我是用K1,和K2的外部中断来控制换页的,按一下K1进入K1的中断服务函数,然后清OLED屏,然后页编号—++,(page为全局变量),那中断优先级怎么设置?因为清屏里边涉及到IIC,如果是软件模拟IIC还好一点,偶尔不会出问题,如果是硬件IIC,问题就出来了,一旦按键的中断优先级比IIC中断优先级高,那么它就会卡死在K1清屏函数这里!另一方面:中断服务函数中执行另一个函数的中断服务函数总觉得哪里怪怪的,想了一下干脆不用了,按键这么简单的东西,总不能栽在这里对吧?用KeySCan()轮询方法多好,省事又方便!代码很简单:

void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);

	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4;
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOE,&GPIO_InitStructure);
	GPIO_SetBits(GPIOE,GPIO_Pin_3|GPIO_Pin_4);
}
u8 page=0;//page为全局变量
void KeyScan(void)
{
	if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==RESET)
	{
		delay_ms(10);
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==RESET)
		{
			OLED_Clear();
			page++;
		  if(page>6)page=1;
			
		}
	}
	else if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==RESET)
	{
		delay_ms(10);
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==RESET)
		{
			OLED_Clear();
			page--;
			if(page==0)page=6;
		}
	}		
}

最后主函数用switch()达到换页显示的效果:

while(1)
	{
		
		KeyScan();
		switch(page)
		{
			
			case 1:
			{
				RTC_ShowTime();
				break;
			}
			case 2:
			{
				Current_Weather_Show_0();
				break;
			}
			case 3:
			{
				Current_Weather_Show_1();
				break;
			}
				case 4:
			{
				Current_Weather_Show_2();
				break;
			}
			case 5:
			{
				Current_Weather_Show_3();
				break;
			}
			default:
			{
				OLED_ShowStr(30,3," WELCOME",2);
				break;
			}
}

case 1是显示RTC时钟的,网络上返回的时钟仅用来校正;

```c
void Current_Weather_Show_0(void)
{
	if(code>10)code=0;//本语句后期加入图标调整
	OLED_ShowBMP(15,1,code);//天气图标
	OLED_ShowCHinese(54,1,10);//深
	OLED_ShowCHinese(72,1,11);//圳
	OLED_ShowCHinese(90,1,12);//今
	OLED_ShowCHinese(108,1,13);//天
	OLED_ShowStr(10,6,buff[1],1);//天气状态
	OLED_ShowCHinese(54,4,17);//温
	OLED_ShowCHinese(72,4,19);//度
	OLED_ShowStr(92,5,buff[2],2);//温度值
	OLED_ShowCHinese(108,4,16);//温度单位
	OLED_ShowCHinese(54,6,18);//湿
	OLED_ShowCHinese(72,6,19);//度
	OLED_ShowStr(92,7,buff[3],2);//湿度值
}
csae 2显示深圳今天的天气,由心知天气返回来的数据包解析得到,显示天气图标,温度,湿度和天气状态;
case 3 是显示明天的天气状态,格式和case2一样,只是数据不一样而已;
case 4也是同理;
case 5显示数据更新时间。默认页显示“WELCOME”字样
```c
void Current_Weather_Show_3(void)
{

	OLED_ShowCHinese(24,1,23);//上
	OLED_ShowCHinese(44,1,24);//次
	OLED_ShowCHinese(60,1,25);//更
	OLED_ShowCHinese(78,1,26);//新
  OLED_ShowStr(44,5,buff[6],2);
}

需要说明的是天气图标我并没有全部做成16进制的数据格式,因为太多了,所以只做了一部分。同时我也会把天气图标全部放传上,供大家参考。
总之,ESP8266模块想玩好并不容易,说难不难,说不难又难,它涉及到IIC或SPI,USART,OLED,ESP8266,RTC,当然还有按键的写法,如果是参考正点原子的还会涉及到定时器TIM,解析数据包cJSON的两个文件,网上很难找,也附上供大家使用,千万不要傻傻的用strstr()函数,会被人笑的。