小白能懂:嵌入式进阶:RTOS嵌入式系统框架
第一章 嵌入式常用裸机编程框架
第二章 面向对象编程基础
第三章 ESP8622物联网基础
第四章 STM32与ESP8266物联网编程
前言
学习韦东山老师的七天物联网实战及直播课相关内容,以其课程笔记为骨,记录一下学习的过程,可能会加入一些自己的感想。
最后欢迎点赞、收藏与评论交流!
提示:本章主要是对上一章的框架进行编程
一、复位、模式设置、WIFI连接,UDP连接
在上一节的内容中我们得知物联网的复位
,模式设置
、WIFI连接
,创建UDP连接
这四个功能的模式类似,都是STM32要向ESP发送数据然后接收返回数据,比较返回数据或者报文是不是正确,为此我们设计的功能函数如下所示:
//向ESP8266发送数据
uint8_t ESP8266_SendCommand(char *cmd, char *reply, uint16_t timeout)
{
//1.保存传入的指令
char buf[256] = {0};
strcat(buf, cmd); //strcpy
//2.处理AT指令(添加换行),因为ESP8622的AT指令要以换行为结束标志
if (strstr(buf, "\r\n") == 0)
{
strcat(buf, "\r\n");
}
//3.清理前面接收的buf
USART2_ClearBuf();
//4.发送数据
USART2_Transmit((uint8_t *)buf, strlen(buf), 500);
//5.接收数据
memset(buf, 0, 256); //buf清空
while(timeout != 0) //超时控制
{
if (USART2_Receive((uint8_t *)buf)) //接收数据
{
//检查结果
if (strstr(buf, reply))
{
printf("%s Send ok!\r\n", cmd);//发送成功
return 0;
}
else
{
timeout--;
HAL_Delay(1);
}
}
}
printf("%s Send error!\r\n", cmd);//发送失败
return 1;
}
程序中的1、2、3和4部分主要是数据发送的内容,步骤5是设置了接收超时之后比较接收的数据或报文是否和预设的数据和报文是否相同,如果相同,则证明数据发送正确,若不同,则证明发送错误。
因此复位
,模式设置
、WIFI连接
,创建UDP连接
的功能可以通过以下函数完成。
ESP8266_SendCommand(“AT+RST”, “OK”, 500);
ESP8266_SendCommand(“AT+CWMODE=1”, “OK”, 500);
ESP8266_SendCommand(“AT+CWJAP=“NETGEAR”,“100ask.cq””, “OK”, 5000);
ESP8266_SendCommand(“AT+CIPSTART=“UDP”,“192.168.50.230”,9999,9999,2”, “OK”, 500);
二、获取IP
获取IP的功能和以上功能不一样,因为获取IP的函数返回的值我们不知道具体返回的值,不像上面那些功能知道返回的值为“OK”,因此我们需要设计一个新的函数将接收到的IP进行打印,如果接收错误,返回接收失败。
//获取ESP8266的IP
uint8_t ESP8266_GetIP(void)
{
uint16_t timeout = 500;
//1.准备发送的指令 AT+CIFSR,注意ESP8622的AT指令要以换行为结束标志
char buf[256] = {0};
strcat(buf, "AT+CIFSR\r\n");
//2.清理前面接收的buf
USART2_ClearBuf();
//4.发送数据
USART2_Transmit((uint8_t *)buf, strlen(buf), 500);
//5.接收数据
memset(buf, 0, 256); //buf清空
while(timeout != 0) //超时控制
{
if (USART2_Receive((uint8_t *)buf)) //接收数据
{
//检查结果
if (strstr(buf, "OK"))
{
printf("%s", buf); //打印IP
return 0;
}
else
{
timeout--;
HAL_Delay(1);
}
}
}
printf("Get IP Failed! \r\n"); //获取失败
return 1;
}
其函数架构与前面第一节架构类似,只不过在接收里面添加了一句输出buf的内容。
三、发送数据
本节主要介绍stm32端给PC或者手机端发送数据的案例。
1 按键设置
发送数据通过按键来实现,当按键按下,就会发送一组指令。
首先设置案件标志位,为了减少全局变量的使用,在此我们定义了Key_GetFlag函数进行标志位的传输,具体流程如下所述:
//首先定义一个静态变量在key.c中
static uint8_t key_flag = 0;
//标志位获取函数
uint8_t Key_GetFlag(void)
{
if(key_flag)
{
key_flag = 0;
return 1;
}
else
return 0;
}
//按键按下的外部中断的callback函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY_Pin)
{
key_flag = 1;
}
}
2 按键主函数发送
在main函数中进行轮询查询,当按键按下(1 按键设置节中的标志位置位),就发送相应的数据。
<main.c>
if (Key_GetFlag())
{
ESP8266_Send_UDP("{\"data\":\"doorbell\",\"status\":\"1\"}");
}
发送的函数ESP8266_Send_UDP
编写如下所示:
<gpio.c>
uint8_t ESP8266_Send_UDP(char *data)
{
//1.准备发送的指令 AT+CIPSEND=len
char buf[256] = {0};
uint8_t len = strlen(data);
sprintf(buf, "AT+CIPSEND=%d\r\n", len); //把格式化(%d)的数据写入字符串
if (ESP8266_SendCommand(buf, "OK", 500) == 0) //发送指令,如果可以放松的话,执行下面语句
{
ESP8266_SendCommand(data, "SEND OK", 1000); //发送数据
return 0;
}
return 1;
}
四、接收数据
本节主要介绍stm32端(ESP8622)接收PC或者手机端数据的实例。
ESP8622接收的数据格式如下所示:
本节主要介绍stm32端给PC或者手机端发送数据的案例。
在main函数中查询接收的数据,然后进行解析工作。
<main.c>
//收到UDP数据
if (USART2_Receive(rx_data)) //如果接收到数据
{
//printf("%s\r\n", rx_data);
if (strstr((char *)rx_data, "\"dev\":\"led\",\"status\":\"0\""))
{
printf("led off\r\n");
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
USART2_ClearBuf();
memset(rx_data, 0, 200);
}
else if (strstr((char *)rx_data, "\"dev\":\"led\",\"status\":\"1\""))
{
printf("led on\r\n");
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
USART2_ClearBuf();
memset(rx_data, 0, 200);
}
}
上面的流程是接收到数据进行分析;然后根据数据进行如果是该开灯的话执行else if,反之执行上面的if;然后清理一下usart2的buf;最后清理缓存区rx_data。
缓存区rx_data数据的来源是通过中断来的,一次次进入中断进行一次次的接收。
<usart.c>
static uint8_t rx_data = 0; //接收的字符
static uint8_t rx_len = 0; //接收的长度
static uint8_t usart_rx_buf[200] = {0};//保存接收的数据
//调用HAL库接收函数,等待接收数据
void USART_StartRx(void)
{
HAL_UART_Receive_IT(&huart2, (uint8_t*)&rx_data, 1);
}
//USART中断回调函数,保存接收的数据并启动下一次接收
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
usart_rx_buf[rx_len%200]= rx_data;
rx_len++;
HAL_UART_Receive_IT(&huart2, (uint8_t*)&rx_data, 1);
}
//获取接收的数据
uint8_t USART2_Receive(uint8_t *rx_data)
{
memcpy(rx_data, (uint8_t*)usart_rx_buf, rx_len);
return rx_len;
}
总结
本文主要介绍了stm32与ESP8622进行连接的相关编程,属于第三章的延续。