前言
采用stm32f103vet6作为主控芯片,使用stm32的RTC外设获取时间,控制esp8266获取天气数据,然后使用0.96寸oled进行显示。
一、原理图
1、esp8266通过串口发送和接收消息,这里我接的是stm32的USART3;其中esp8266的RST引脚和EN引脚可以直接接3.3V高电平,因为我使用的野火指南者板子的esp8266是板载的,所以需要单独配置引脚;
2、我使用的是0.96寸I2C接口的oled显示屏,连接stm32的I2C1引脚,使用硬件I2C控制oled。
二、代码编写步骤
1.配置串口:
使用CubeMX软件初始化stm32的USART1和USART3串口(使用默认配置就行),并使能串口中断;编写串口的中断回调函数,代码如下:
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
if(huart == &huart1)
{
g_uart1_rx.buf[g_uart1_rx.size++] = aRxBuffer_rx1; //接收数据转存
if((g_uart1_rx.buf[g_uart1_rx.size-1] == 0x0A)&&(g_uart1_rx.buf[g_uart1_rx.size-2] == 0x0D)) //判断结束位
{
HAL_UART_Transmit(&huart1, (uint8_t *)&g_uart1_rx.buf, g_uart1_rx.size,0xFFFF); //将收到的信息发送出去
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX); //检测UART发送结束
g_uart1_rx.size = 0;
memset(g_uart1_rx.buf,0x00,sizeof(g_uart1_rx.buf)); //清空数组
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer_rx1, 1); //再开启接收中断
}
if(huart == &huart3)
{
g_uart3_rx.buf[g_uart3_rx.size++] = aRxBuffer_rx3; //接收数据转存
if((g_uart3_rx.buf[g_uart3_rx.size-1] == 'K')&&(g_uart3_rx.buf[g_uart3_rx.size-2] == 'O'))
{
HAL_UART_Transmit(&huart1, (uint8_t *)&g_uart3_rx.buf, g_uart3_rx.size,0xFFFF); //将收到的信息发送出去
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX); //检测UART发送结束
g_uart3_rx.size = 0;
memset(g_uart3_rx.buf,0x00,sizeof(g_uart3_rx.buf)); //清空数组
}
else if((g_uart3_rx.buf[g_uart3_rx.size-2] == ']')&&(g_uart3_rx.buf[g_uart3_rx.size-1] == '}')
&&(g_uart3_rx.buf[g_uart3_rx.size-3] == '}'))
{
HAL_UART_Transmit(&huart1, (uint8_t *)&g_uart3_rx.buf, g_uart3_rx.size,0xFFFF); //将收到的信息发送出去
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX); //检测UART发送结束
strcpy(Data_buff,(char *)g_uart3_rx.buf);
temp = 1;
g_uart3_rx.size = 0;
memset(g_uart3_rx.buf,0x00,sizeof(g_uart3_rx.buf)); //清空数组
}
HAL_UART_Receive_IT(&huart3, (uint8_t *)&aRxBuffer_rx3, 1); //再开启接收中断
}
}
代码实现的主要功能:能将usart1接收到的信息重新发送出去,判断串口usart3接收到的消息(这里主要是esp8266回传的信息)通过串口1发送给电脑的串口助手,用来调试查看信息是否正确。
2.配置RTC外设
这里我就直接跳过了,网上很多教程;
3.EPS8266配置和数据处理
通过串口3发送AT指令控制eps8266连接心知天气;
首先需要注册心知天气账号(https://www.seniverse.com/),获取自己的密钥,替换心知天气api中的Key;具体的配置我就不详细说明了,网上有很多。
发送AT指令的代码如下:
void SendATCmd(char *cmd, int waitms)
{ // 发送AT指令给串口3
if (NULL != cmd)
{
HAL_UART_Transmit(&huart3, (uint8_t *)cmd, strlen(cmd), 0xFFFF);
if (waitms > 0)
HAL_Delay(waitms); // 延时等待ESP01模块应答时间
}
}
基本的AT指令配置如下:
void esp8266_config(void)
{
char str[200];
sprintf(str, "AT+CWJAP=\"%s\",\"%s\"\r\n", WIFI_NAME, WIFI_PSW);
// SendATCmd("+++", 500); // 退出透传模式
SendATCmd("AT\r\n", 2000); // 测试ESP01模块是否存在
// SendATCmd("AT+GMR\r\n",3000); // 查看模块版本信息
SendATCmd("AT+CWMODE=1\r\n", 2000); // 开启STA+AP模式 ==================
SendATCmd("AT+RST\r\n", 3000);
SendATCmd(str, 10000); // 连接无线路由器或者手机热点,等待10秒 ============
SendATCmd("AT+CIPMUX=0\r\n", 2000); // 关闭多连接
SendATCmd("AT+CIPSTART=\"TCP\",\"api.seniverse.com\",80\r\n", 2000); // 连接心知天气TCP服务器
SendATCmd("AT+CIPMODE=1\r\n", 500); // 开启透传模式
SendATCmd("AT+CIPSEND\r\n", 500); // 开始透传
}
开始透传之后就可以发送get请求,这时串口3就会接收到天气信息,我们就可以将天气信息进行保存和处理。
信息处理代码如下:
char *p;
p = strstr(Data_buff,"text_day"); //查找天气
sscanf(p+11,"%[^\"]",weather);
OLED_ShowString(40,0,(uint8_t*)weather,16);
p = strstr(Data_buff,"high"); //查找气温
temperature[0]=atoi(p+7);
p = strstr(Data_buff,"low");
temperature[1]=atoi(p+6);
将接收到的天气信息存储到Data_buff字符串,采用strstr(),sscanf(),atoi()等字符串处理函数,将天气情况和最高气温和最低气温从字符串中取出来;
1、首先使用strstr()函数,找到子字符串“text_day”的位置,使用指针变量p存储子字符串出现的首地址;
2、接着使用sscanf()函数取出“text_day”后面代表天气的字符串并保存;
3、继续使用strstr()函数找到“high”和“low”代表天气温度的字符串,再使用atoi()强制转换函数,将两个代表天气字符串后面跟着的数字转换成整型数,最后保存在数组中。
三、显示效果
能实时显示时间,约半分钟刷新天气和气温信息
总结
上面的就随便写写,具体的还是看我附的源码;我觉得最有收获的就是对数据的处理,c语言虽然学过字符串处理函数,但是很少用到实际的代码中,看来还是要好好学习c语言。