admin 管理员组

文章数量: 887006

写在前面:

因为最近帮一个朋友完成他的项目,就有了这样一个支线项目,主线项目基于stm32的HAL库开发学习以后有时间一定会继续更新,考虑到广大大学牲完成这样一个新版本无完整开发过程,资料的情况下,我就给大家仔细介绍一下我的开发历程,希望对大家的学习生涯有所帮助,也欢迎各位大佬批评指正!!!文末贴上本次项目的完整例程。

UP几乎踩完了所有的坑,最后终于可以连上onenet,先贴上效果图

分别是连接上服务器,以及stm32采集的数据传到了onenet云平台上 

一:硬件选择

本次使用单片机是stm32f103c8t6 选用是最小系统板,其中使用usart1与esp8266通信,而usart3将esp8266返回的数据打印出来,我们便可以通过pc的串口助手观潮我们发送的信息以及收到回复的信息是否正确。

而esp8266本次选择的是esp01-s,最好的优点就是便宜好用。

但是在使用前,需要注意的是,由于本次使用的mqtt协议连接上云,而esp01s刚出场时自带的固件是不支持mqtt协议,所以就需要重新烧录固件,这里根据这篇文章做就可以了。

这里的esp01s我选择的是某宝上的这一家的,这一家客服耐心回答问题售后良好,硬件质量优秀,完全不用担心被坑,闭眼入就完了!(关键是确实便宜啊)。

ESP8266-01 MQTT固件烧录并连接阿里云服务器_烧录mqtt固件接线-CSDN博客

这样硬件部分就准备好了,但我这里还是建议大家用串口助手先发送at指令和esp8266通信试试,为了避免时硬件本身的问题导致后面的过程都通过不了。

二:stm32与esp8266通信至连接wifi部分

如上文所说,我们使用串口1和esp8266进行通信,下面将展示cubemx的配置

首先时RCC和SYS这个自不必说,主要看usart1的配置,

同时,我也开了DMA,DMA这里就不具体展开了,后面有机会的话再来介绍。

波特率设置为115200,同时打开NVIC串口中断开关,以及添加DMA通道。

同理,usart3的配置也是如此,唯一的区别就是并未开启DMA通道,因为usart3的唯一作用就只是在串口DMA中断函数里将接收到的数据打印出来。

下面开始贴代码。

#include "UART_DMA.h"
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "NumAndStr.h"
#include "stm32f1xx_hal.h"
#include "usart.h"
#include "oled.h"
uint8_t RxBuffer[UART_RX_BUF_SIZE] = {0};
  uint8_t TxBuffer[UART_RX_BUF_SIZE] = {0};
  uint8_t sendCompleteSign = 1;
  uint8_t flag,flag_wifi,flag_mqtt,flag_reset;
 uint8_t TxLen = 0;
int32_t a,b,c;
double  d,e,f;
	extern uint8_t uart3_RX_Buffer[r3_length];
 extern uint8_t  UART3_temp[REC_LENGTH]; 
extern unsigned int  UART3_Rx_cnt ;

void DataProcess(void)
{
	//在这里加入数据处理的函数
	a = str2int(RxBuffer, ' ', 1);
	b = str2int(RxBuffer, ' ', 2);
	c = str2int(RxBuffer, ' ', 3);
	str2double(RxBuffer, ' ', 4, &d);
	str2double(RxBuffer, ' ', 5, &e);
	str2double(RxBuffer, ' ', 6, &f);

}

//到USARTx_IRQHandler中添加,如:
//void USART1_IRQHandler(void)
//{
//  /* USER CODE BEGIN USART1_IRQn 0 */
//  if(__HAL_UART_GET_FLAG(&USB_Huart,UART_FLAG_IDLE))
//  {
//	  HAL_UART_IdleCallback(&USB_Huart);
//  }
//
//  /* USER CODE END USART1_IRQn 0 */
//  HAL_UART_IRQHandler(&huartx);
//}
void HAL_UART_IdleCallback(UART_HandleTypeDef *huart)
{
	__HAL_UART_CLEAR_IDLEFLAG(huart);
	{
		HAL_UART_DMAStop(huart);

        ProcessData();

        StartUartRxDMA();
	}
}

void ProcessData()
{
    uint32_t len = 0;

    //得到已经接收了多少个字节 = 总共要接收的字节数 - >NDTR F1为CNDTR F4为NDTR
    #ifdef __STM32F1xx_HAL_H
    	len = UART_RX_BUF_SIZE - USB_Huart.hdmarx->Instance->CNDTR;
    	#define ProcessDataOK
    #endif

    #ifdef  __STM32F4xx_HAL_H
        len = UART_RX_BUF_SIZE - USB_Huart.hdmarx->Instance->NDTR;
    	#define ProcessDataOK
    #endif

    #ifndef ProcessDataOK
    	增加所用芯片的版本
    #endif

    if(len > 0)
    {
        if(sendCompleteSign == 1)
        {
#if UART_RXTX_Switch
					memset((void *)TxBuffer, 0, sizeof(TxBuffer));//将TxBuffer数组全部赋值为0
					memcpy(TxBuffer, RxBuffer, len);//将RxBuffer的内容全部复制到TxBuffer
            TxLen = len;
            StartUartTxDMA();	//串口回显
#endif
            {
            	//在这里面加入数据处理的函数
            	DataProcess();
            }
        }
    }
}

void USB_DMA_printf(const char *format,...)
{
	uint32_t length;
	va_list args;

	va_start(args, format);
	length = vsnprintf((char*)TxBuffer, sizeof(TxBuffer)+1, (char*)format, args);
	va_end(args);

	HAL_UART_Transmit_DMA(&USB_Huart,TxBuffer,length);
}

void USB_printf(const char *format,...)
{
	uint32_t length;
	va_list args;

	va_start(args, format);
	length = vsnprintf((char*)TxBuffer, sizeof(TxBuffer)+1, (char*)format, args);
	va_end(args);

	HAL_UART_Transmit(&USB_Huart,TxBuffer,length,0xFFFF);
}

/**
  * @brief  Tx Transfer completed callbacks.
  * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
//  UNUSED(huart);
    if(huart == &USB_Huart)
    {
        sendCompleteSign = 1;
    }
  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_UART_TxCpltCallback could be implemented in the user file
   */
}

/**
  * @brief  Rx Transfer completed callbacks.
  * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
  *                the configuration information for the specified UART module.
  * @retval None
  */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
//  UNUSED(huart;);
    if(huart == &huart3)
		{
			uart3_RX_Buffer[UART3_Rx_cnt]=UART3_temp[0];
			UART3_Rx_cnt++;
//      USB_printf("%s",uart3_RX_Buffer);
			HAL_UART_Receive_IT(&huart3,(uint8_t *)UART3_temp,REC_LENGTH);

		}
    if(huart == &USB_Huart)
    {
        ProcessData();
      StartUartRxDMA();
			
			
       
    }
  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_UART_RxCpltCallback could be implemented in the user file
   */
}

uint8_t UartTxData(UART_HandleTypeDef *huart, uint8_t *buf, const uint32_t len)
{
	HAL_StatusTypeDef status;
	uint8_t ret = 1;

	if(sendCompleteSign == 0 || len == 0)
	{
		return 0;
	}

    sendCompleteSign = 0;

	status = HAL_UART_Transmit_DMA(huart, (uint8_t*)buf, len);

	if(HAL_OK != status)
	{
		ret = 0;
	}

	return ret;
}

//启动DMA发送
uint8_t StartUartTxDMA()
{
    return UartTxData(&USB_Huart, TxBuffer, TxLen);
}

uint8_t UartRxData(UART_HandleTypeDef *huart, uint8_t *buf, const uint32_t len)
{
	
	HAL_StatusTypeDef status;
	uint8_t ret = 1;

	status = HAL_UART_Receive_DMA(huart, (uint8_t*)buf, len);
	{	
if(strstr(buf,"OK")!=NULL)
{
	flag=1;
}
if(strstr(buf,"WIFI GOT IP")!=NULL)
   flag_wifi=2;
if(strstr(buf,"MQTTCONNECTED")!=NULL)
   flag_mqtt=1;
if(strstr(buf,"MQTTDISCONNECTED")!=NULL)
   flag_reset=1;

// if(strstr(buf,"CLOUD CONNECTED")!=NULL)
//	flag=3;
//if(strstr(buf,"led1off")!=NULL)
// LED1_OFF();
//if(strstr(buf,"led1on")!=NULL)
// LED1_ON();
//		OLED_ShowStr(0+8,5,buf,1);
		uart3_printf("%s",buf);
//		LCD_ShowString(10,10,500,12,12,buf);
		
//		
//	
//	if(buf[0]==0x31)
//	{
//		flag=1;
//	}
//else	if(buf[0]==0x32)
//	{
//		flag=2;
//	}
//else	if(buf[0]==0x33)
//	{
//		flag=3;
//	}
//else	if(buf[0]==0x34)
//	{
//		flag=4;
//	}
//	i++;
}
//pulseWide=buf[0]*10+buf[1];
	if(HAL_OK != status)
	{
		ret = 0;
	}
	else
	{
		/* 开启空闲接收中断 */
	    __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);
	}

	return ret;
}

//启动DMA接收
uint8_t StartUartRxDMA()
{
    return UartRxData(&USB_Huart, RxBuffer, UART_RX_BUF_SIZE);
}


			


/*开始本次的代码解释 首先是USART1的全局中断进行改写,在ISR里添加了代码,对于串口中断的信号位进行判断
判断之后,就开始中断,,其实这个函数集其实也是层层利用的,在TX(由存储器到外设,发送)的中断回调函数里
设置串口中断标志位,然后是RX(外设到存储器,接收)函数的中断回调函数里接受DMA初始化
进而开启DMA接收,在DMA接收函数里返回接收到的数据,其中还有一个数据处理函数,里面将串口数据回显*/

如上代码是根据某一位佬的串口接收数据处理代码改了一下,使用的是DMA的空闲中断,所以需要在it.c里面将usart1_handler函数里面的内容改写一下。其中在UartRxdata里面出现的strtr函数就是比较esp8266返回的语句是否与我们预料的语句

例如

if(strstr(buf,"OK")!=NULL)
{
	flag=1;
}

就是判断给esp8266发送AT的时候,是否能正确返回OK。

#include "esp8266.h"

extern uint8_t flag,flag_mqtt,flag_reset;
extern uint8_t flag_wifi;
uint8_t ssid[]={"xxx"};
uint8_t psd[]={"xxxx"};
uint8_t devicename[]={"test"};
uint8_t productid[]={"xxxxxxxx"};
uint8_t deviceid[]={"xxxx"};
uint8_t subscribe[]={"$sys/xxxx/test/thing/property/post/reply"};
uint8_t pubscribe[]={"$sys/xxxx/test/thing/property/post"};

uint8_t fuc[]={"temperature"};
//uint8_t data[]={"$sys/422b4zbv12/test/thing/property/post","{\"id\":\"123\"\,\"params\":{\"temperature\":{\"value\":30\}}}"};
int flag_temp;
extern int temp;
void esp_reset()
{
	int i=0;
		while(i<=6)
	{
		USB_printf("AT+RST\r\n");
		HAL_Delay(500);
    if(flag==1)
		{
			break;
			flag=0;
		}
	}

	
}
uint16_t  esp_init(void)
{
int i=0;

	while(i<=6)
{	USB_printf("AT\r\n");
	HAL_Delay(500);
	i++;
}
if(flag==1)
{
//HAL_Delay(1000);
return ESP8266_Result_OK;
}
else 
{
	return ESP8266_Result_Err;
}
}

uint16_t esp_wifi_connect()
{
	int i=0;
	while(1)
	{
		USB_printf("AT\r\n");
		HAL_Delay(500);
    if(flag==1)
		{
			break;
			flag=0;
		}
	}
	HAL_Delay(500);
	while(1)
	{
		USB_printf("AT+CWMODE=1\r\n");
		HAL_Delay(200);
	if(flag==1)
		break;
	else 
		return ESP8266_Result_Err;
	}
		HAL_Delay(500);
	while(1)
	{
		USB_printf("AT+CWDHCP=1,1\r\n");
		HAL_Delay(200);
	if(flag==1)
		break;
	else 
		return ESP8266_Result_Err;
	}

	while(1)
	{
		flag=0;
		USB_printf("AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,psd);
		HAL_Delay(200);
    if(flag_wifi==2)
			break;
//		else
//			return ESP8266_Result_Err;
	}
	
	}

如上,不像一般esp8266通信代码一样,会等待多长时间然后返回通过或者没有通过,我的逻辑很简单,就是while循环里一直esp8266发送消息,直到esp返回OK或者是“WIFI GOT IP”才break掉while循环结束发送的流程,就是一直暴力发送(手动狗头),可能函数写的不像一般开源的代码优美,但本人试过确实好用。

其中ssid是wifi名称,psd是wifi密码,上述代码在main函数里的while循环之前被执行。后面会继续讲所有的程序逻辑。待上述程序跑完后,不出意外的话这边你的串口就会给你提示WIFI GOT IP以及WIFI CONNECTED。

tips:这里有坑!!!你的WIFI一定得是2.4G网络,5G网络无法使用,这是因为esp8266的芯片设定,而且如果的esp8266返回了AT+CWJAP=3,这就代表你的wifi是5G的,这是你就需要更换的wifi了。

三:onenet云平台如何创建一个可以连接mqtt的界面

第一步:首先是创建一个onenet平台的账号,然后登录,登录之后,如图

在产品开发这里创建一个产品,然后

创建产品之后产品品类这里选择其他行业

产品名称自填,节点类型选择直连设备,接入协议选择mqtt,数据协议选择onejeson

开发方案选择标准方案,其他的东西都无所谓了就。

紧接着创建设备,当你创建好产品之后,就可以添加设备了,如图

右上角有一个添加设备,添加完设备,设备名最好写test(因为和下文中的token生成有关),点进详情就有如下界面。

记住产品ID和设备密钥,这是我们与平台交互需要的钥匙,

根据平台提供的文档:OneNET - 中国移动物联网开放平台 (10086)

里面可以知道我们需要的指令形式

其中需要下一个token生成器

https://download5.mcloud.139/storageWeb/servlet/downloadServlet?code=TDAwMDExV2xBTXAxbTgyNzkxN3c4aTZTQXdJ&un=505808AAA2BC94B5F91FF8732C800E7A2EE72758AEF113513DCC9E0167B4B091&dom=D950&rate=0&txType=0

第一行最后一个/后是你的设备名,第一个/后是你的设备ID,ret是时间戳,key是设备密钥,点击generate,然后就会生成一串密钥。记住他,我们后面会用到

AT+MQTTUSERCFG=0,1,"test","422b4zbv12","version=2018-10-31&res=products%2F422b4zbv12%2Fdevices%2Ftest&et=2052911776&method=md5&sign=kSKpEHBa9KKDg%2FtfYQLKFQ%3D%3D",0,0,""

第二个引号里的内容是设备id,后面一长串则是刚刚生成的密钥。

AT+MQTTCONN=0,"mqtts.heclouds",1883,1

这一段代码直接无脑输入,是连接mqtt服务器的地址和端口。

AT+MQTTSUB=0,"$sys/422b4zbv12/test/thing/property/post/reply",1

这个是订阅mqtt服务器的消息,以上消息若成功发送,则会返回OK。这里建议大家用电脑串口助手测试一下。然后继续进行下一步的stm32代码编写。

四:通过串口给esp8266发送信息与onenet通信。

void esp_mqtt_connect()
	{
		int i=0;
		flag=0;
//		if(flag_wifi==2)
		{
			while(1)
			{
			USB_printf("AT+MQTTUSERCFG=0,1,\"%s\",\"%s\",\"%s\",0,0,\"\"\r\n",devicename,productid,deviceid);
			HAL_Delay(200);
				if(flag==1)
				break;
				i++;
			}
		
			flag=0;
			HAL_Delay(200);
			while(1)
			{

			USB_printf("AT+MQTTCONN=0,\"mqtts.heclouds\",1883,1\r\n");
			HAL_Delay(200);
			if(flag==1)
			break;
			}
			flag=0;
			HAL_Delay(200);
			while(1)
			{
				i++;
			USB_printf("AT+MQTTSUB=0,\"%s\",1\r\n",subscribe);
			HAL_Delay(200);
			if(flag==1)
			{
			break;
			}
			}
			flag_temp=1;

			HAL_Delay(500);
//			while(1)
//			{
//				i++;
//				USB_printf("AT+MQTTPUB=0,\"%s\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"%s\\\":{\\\"value\\\":%d}}}\",0,0\r\n",pubscribe,fuc,i);
//			HAL_Delay(1500);
//			}

			
		}
		
	}
	

以上代码逻辑和连接wifi代码逻辑相同,暴力发送直到他返回ok,大家自己测试的时候最好先把延时的时间改稍微长一点看回复,当最后一条语句订阅了服务器消息的语句发送完毕,并且返回OK的时候,这里你会惊喜的发现,onenet平台你的设备就会显示在线了。

在这里解释一下前面productid是设备ID,deviceid是用token生成的密钥,subscribe是订阅消息的指令。

这里面又有坑!因为esp8266有记住wifi的功能,就是当你上电后,可能wifi随之就连上了,但是你后面又重新发送连接wifi指令的时候,可能这个时候wifi会掉,这也是我目前 代码一个  bug,此时你并没有连上wifi或者因为其他的原因导致wifi没连上,但是走到了连接mqtt服务器这一步的时候,mqtt就会返回mqttdisconnected :0 error,在你发送连接服务器请求后是有一段这个响应时间,

一般情况下,AT MQTT命令会在10秒内响应,但AT+MQTTCONN命令除外。例如,如果路由器无法访问internet,则AT+MQTTPUB命令会在10秒内响应。但是AT+MQTTCONN命令可能需要更多的时间,因为在不良的网络环境中需要重传数据包。.如果AT+MQTTCONN基于TLS连接,每个包的超时为10秒,则根据握手包计数,总超时将长得多。

后面有时间会修复这个bug,也希望各位读者可以帮我修一修哈哈。一般来说打断点,一步步debug可以避免这个问题,脱机后就可能会出现连不上的情况。

五:当你前面所有的操作都完成之后,将stm32外设采集的消息传到onenet云平台。

如果你千帆过尽,走到这最后一步的时候,恭喜你,快要成功了。

我拿温度举例,如下图,点进产品开发,右边点击设置物模型,自定义功能点

如下图设置,读写类型设置读写。

设置完毕后就是指令,

AT+MQTTPUB=0,"$sys/422b4zbv12/test/thing/property/post","{\"id\":\"123\"\,\"params\":{\"temperature\":{\"value\":20\}}}",0,0

第二个引号之后是你的产品ID,需要改的就是你的这个变量的标识符,与onenet云平台对应就好。

这里用电脑串口助手测试,回复ok,这个时候你就可以看到设备详情里的属性里的温度就会有你value后面的值了。

放在32里 是这样写的

void send_temp()
{
		
	if(flag_temp==1)
		{
//					while(1)
			{
			USB_printf("AT+MQTTPUB=0,\"%s\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"%s\\\":{\\\"value\\\":%d}}}\",0,0\r\n",pubscribe,fuc,temp);
//			HAL_Delay(1500);
			}
		}
		
	}

如果代码跑下来一切顺利的话,电脑的串口助手应该会有如下图样

到这里就大功告成了!

最后:补充main.c以及串口3发送函数代码

main.c

​
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "UART_DMA.h"
#include "esp8266.h"
#include "bsp_ds18b20.h"
#include "oled.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
uint8_t uart3_RX_Buffer[r3_length]={0};
uint8_t  UART3_temp[REC_LENGTH] = {0}; 
unsigned int  UART3_Rx_cnt;
int temp,temp_set=15;
int flag_ds;
float m_water=0.15;

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_USART3_UART_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
	  HAL_TIM_Base_Start(&htim2);
	  HAL_TIM_Base_Start(&htim3);
		HAL_TIM_Base_Start(&htim1);  

		HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

//__HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE);

//HAL_UART_Receive_IT(&huart3,(uint8_t *)UART3_temp,REC_LENGTH);

Ds18b20_Init();

StartUartRxDMA();
  OLED_Init();

USB_DMA_printf("AT+RST\r\n");
HAL_Delay(100);
//uart3_printf("666");
//esp_init();
esp_wifi_connect();
HAL_Delay(100);
esp_mqtt_connect();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

​

如你所见,我的esp8266函数在main里的while循环前执行,在所有的模块初始化我完成之后,而且每一个与esp8266有关的函数都是一个while循环,这样写是因为之前frertos写多了,想每个功能都单独开一个任务完成,但f1的性能不足以支持这样玩,我这样的写法也是不合适的,像大多数开源等待响应返回函数值执行下一步,放在while循环里写才是正道,这时候你可能会问我的其他外设写在哪儿了,相信佬一定猜出来了,我开了四个定时器,其他的事件都放在定时器里刷新了。

串口3打印函数

void uart3_printf(char *fmt, ...)
{
	uint32_t length;
	va_list args;

	va_start(args, fmt);
	length = vsnprintf((char*)uart3_tx_buf,sizeof(uart3_tx_buf)+1, (char*)fmt, args);
	va_end(args);

	HAL_UART_Transmit(&huart3,uart3_tx_buf,length,0xFFFF);

}

到这里,全文就结束了,如果有什么问题,欢迎大家批评指正!

拜谢!

如果想要完整工程代码,请务必一键三连私信up,或者评论区,谢谢大家!!!最后祝大家都能成功实现,不踩坑!

链接:https://pan.baidu/s/12sCS9a8b8_6EFs6pVi8uPg?pwd=wifi 
提取码:wifi 
--来自百度网盘超级会员V2的分享

所有工程均在链接中~

本文标签: 最新版 旧版 协议 版本 代码