既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
4.FreeRTOS配置
5.FreeRTOS的定时器配置
FreeRTOS是要使用定时器来管理任务的并行关系,所以要对定时器进行更改:
6.工程配置
配置完引脚之后,还要对工程输出进行配置:
这样,我们的工程就配置好了,下面就能编写功能代码了。
四、串口中断驱动编写
STM32CubeMx生成的代码使用HAL库写的,而且对串口中断做了一下改变,现在并不是说直接就可以在串口中断函数中处理数据。目前,串口中断函数中只有一个函数:
void USART1\_IRQHandler(void)
{
/\* USER CODE BEGIN USART1\_IRQn 0 \*/
/\* USER CODE END USART1\_IRQn 0 \*/
HAL\_UART\_IRQHandler(&huart1);
/\* USER CODE BEGIN USART1\_IRQn 1 \*/
/\* USER CODE END USART1\_IRQn 1 \*/
}
这个 HAL_UART_IRQHandler(&huart1) 函数只是判断中断类型而已,并没有处理数据的相关代码在里面。有兴趣的同学可以到函数里面看看。
那既然这个函数并没有做数据处理,那肯定是有个函数专门负责接收串口数据的:
串口中断接收函数: HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
这个函数的功能:这个函数是把husart 串口接收到的 Size数据量的字节存到pData中, 并且关掉中断。
也就说,当我们接受完数据之后,要重新使用这个函数来开启中断。另外还要介绍另一个和这个函数息息相关的函数:
串口接收回调函数: void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
这个函数默认不会自动生成,需要我们自己写。
函数功能:当HAL_UART_Receive_IT函数结束后,会进来这个函数当中,用户可以在这个函数中对数据进行处理。
方便大家,给各位同学贴出我自己写的函数HAL_UART_RxCpltCallback
if(huart->Instance==USART2)
{
UART2_DATA.UART_Data[UART2_DATA.UART_Cnt] = \*UART2_DATA.UART_DataBuf;
UART2_DATA.UART_Cnt++;
if(\*UART2_DATA.UART_DataBuf==0X0A)
{
UART2_DATA.UART_Flag = 1;
}
}
HAL\_UART\_Receive\_IT(huart,(uint8\_t \*)UART2_DATA.UART_DataBuf,sizeof(UART2_DATA.UART_DataBuf));
相关宏结构体:
typedef struct usart
{
unsigned char UART_Data[512];
unsigned char UART_Flag;
unsigned int UART_Cnt;
unsigned char UART_DataBuf[1];
}USART_DataBuf;
我把接收到的数据存在结构体当中进行同意处理,而且这个结构体是全局的,方便使用。
五、ESP8266的数据显示
这个函数可以把ESP8266接收到的数据通过USART1打印出来,方便我们查看调试和了解AT指令的进度。这个函数我把它放在了一个独立线程当中,这样就可以不断地读取并显示出来。
ESP8266DATATypedef esp8266data;
//获取串口数据
uint8\_t \*Esp8266GetData(void)
{
if (UART2_DATA.UART_Flag == 1)
{
strcpy((char \*)esp8266data.data, (const char \*)UART2_DATA.UART_Data);
esp8266data.data_size = UART2_DATA.UART_Cnt;
printf("%s", UART2_DATA.UART_Data);
for (; UART2_DATA.UART_Cnt > 0; UART2_DATA.UART_Cnt--)
UART2_DATA.UART_Data[UART2_DATA.UART_Cnt] = 0;
esp8266data.flag += 1;
if(esp8266data.flag>16) esp8266data.flag=16;
UART2_DATA.UART_Flag = 0;
return esp8266data.data;
}
return esp8266data.data;
}
void StartTask02(void \*argument)
{
/\* USER CODE BEGIN StartTask02 \*/
/\* Infinite loop \*/
uint8\_t \*sub_buf;
HAL\_UART\_RxCpltCallback(&huart2);
for (;;)
{
sub_buf = Esp8266GetData();
六、AT指令配置ESP8266连接WiFi和腾讯云
有了串口中断及之前地AT指令流程,就可以连接腾讯云了:
1.连接WiFi
//连接WiFi
void Esp8266LinkAp(uint8\_t \*ssid, uint8\_t \*passwd)
{
uint8\_t \*linkap;
linkap = (uint8\_t \*)malloc(128);
HAL\_UART\_Transmit(&huart2, " \r\n", 3, 1000);
do
{
switch (esp8266data.flag)
{
case 0: //复位ESP8266
HAL\_UART\_Transmit(&huart2, "AT+RST\r\n", strlen("AT+RST\r\n"), 5000);
osDelay(2000);
break;
case 2: //设置连接模式
case 3:
HAL\_UART\_Transmit(&huart2, "AT+CWMODE=1\r\n", strlen("AT+CWMODE=1\r\n"), 5000);
osDelay(1000);
break;
//开始连接WiFi
case 4:
case 5:
sprintf((char \*)linkap, "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, passwd);
HAL\_UART\_Transmit(&huart2, (uint8\_t \*)linkap, strlen((const char \*)linkap), 5000);
osDelay(5000);
break;
default:
break;
}
} while (esp8266data.flag < 7);
free(linkap);
}
2.连接腾讯云并订阅主题
void Esp8266LinkloTExplorer(void)
{
uint8\_t \*device_massage;
device_massage = (uint8\_t \*)malloc(128);
do
{
switch (esp8266data.flag)
{
// case 7: //设置连接信息
case 7:
case 8:
sprintf((char \*)device_massage, "AT+TCDEVINFOSET=1,\"%s\",\"%s\",\"%s\"\r\n", PRODUCT_ID, DEVUICE_NAME, DEVICE_SECRET);
HAL\_UART\_Transmit(&huart2, device_massage, strlen((const char \*)device_massage), 5000);
osDelay(1000);
break;
case 9:
case 10:
HAL\_UART\_Transmit(&huart2, "AT+TCMQTTDISCONN\r\n", strlen("AT+TCMQTTDISCONN\r\n"), 5000); //先断开现有链接
osDelay(500);
break;
case 11:
HAL\_UART\_Transmit(&huart2, "AT+TCMQTTCONN=1,5000,240,0,1\r\n", strlen("AT+TCMQTTCONN=1,5000,240,0,1\r\n"), 5000);
osDelay(500);
break;
case 12: //检查是否已经连接
HAL\_UART\_Transmit(&huart2, "AT+TCMQTTSTATE?\r\n", strlen("AT+TCMQTTSTATE?\r\n"), 5000);
osDelay(100);
break;
case 13: //订阅主题
sprintf((char \*)device_massage, "AT+TCMQTTSUB=\"$thing/down/property/%s/%s\",0\r\n", PRODUCT_ID, DEVUICE_NAME);
HAL\_UART\_Transmit(&huart2, device_massage, strlen((const char \*)device_massage), 5000);
osDelay(500);
break;
default:
esp8266data.flag = 16;
break;
}
} while (esp8266data.flag < 15);
free(device_massage);
}
七、处理JSON数据并控制LED
博主的腾讯云下发的数据在ESP8266中的打印是这样的:
+TCMQTTRCVPUB:"$thing/down/property/C9N29PAEXK/LED",105,
"{"method":"control","clientToken":"clientToken-d4c2c848-b930-44e7-bc4f-55c0226b0907","params":{"led1":1}}"
1.分割出Topic 和JSON数据
根据打印出来的信息可以看出,只要使用字符串操作就能轻松分割出Topic和JSON:
void loTMessageHandler(void)
{
char \*pub_buf;
unsigned int i = 0;
if (TCMQTTRCVPUB != 0)
{
//分离出Topic
pub_buf = strstr((const char \*)TCMQTTRCVPUB, "$thing/down/property");
if (pub_buf != NULL)
{
while (\*pub_buf != '\"')
{
Sub_Topic[i] = \*pub_buf++;
i++;
}
i = 0;
#if LOT\_Debug
printf("Topic=%s\r\n", Sub_Topic);
#endif
}
//分离出数据
pub_buf = strstr((const char \*)TCMQTTRCVPUB, "{\"method\":\"control\"");
if (pub_buf != NULL)
![img](https://img-blog.csdnimg.cn/img_convert/baf368d3667990f86a5025651403c608.png)
![img](https://img-blog.csdnimg.cn/img_convert/61ec8b823cb3968b91845508a9940303.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
[外链图片转存中...(img-HzKc0lrm-1715708511229)]
[外链图片转存中...(img-jAqOikqh-1715708511229)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**