使用STM32和ESP8266连接7脚oled屏幕显示心知天气

一、硬件准备

我这里用到了stm32f103c8t6、esp8266、7脚0.96寸oled屏幕。

二、stm32连接oled屏幕

我这里借鉴了大神得stm32连接oled屏幕0.96寸 OLED 驱动,HAL库+SPI,集合了网上所有好用的函数,测试过。解决花屏问题。_c51 oled0.96 spi驱动-CSDN博客

我这里用得是7脚得oled、他们得引脚有(需要了解更多看数据手册):

GND 电源地
VCC 3.3v电源
D0 时钟总线
D1 数据总线
RES 复位
DC 数据/命令选项
CS 片选

我使用的是通过硬件spi来控制oled屏幕,使用时先配置HAL库,我使用的SPI1,板子上学显示3个绿色引脚,分别是SCK、MISO、MOSI,他们的作用是SCK控制时钟线、MISO是在主机这边是输入,在从机那边是输出、MOSI是在主机这边是输出,在从机那边是输入。使用D0连接SCK、D1连接MOSI。其他的RES、DC、CS都随便连接、配置成GPIO推挽输出。以下是HAL库配置。

后面就是配置时钟这些简单,随便就能找到。上面有大神的链接,可以用它的代码、将他的引脚号改成自己的引脚号就能正常的驱动oled屏幕了,其实很简单的,多少也会遇到坑。

三、esp8266连接wifi发送AT指令

这个我上个文章写了就不说了我吧连接发出来esp8266连接心知天气_esp8266天气-CSDN博客、写的不是很好,请谅解我还是一个萌新。

四、通过stm32通过串口给esp8266发送AT指令

最先需要打开2个串口、一个串口是负责给esp8266发送AT指令、另一个串口是来打印esp8266返回的数据。先配置hal库、需要打开2个串口,还有启动串口中断、这个都很简单我就懒得贴图了,接线也很简单也不想说了返回的数据是json格式需要解析一下,在网上找json的包,。现在到了最激动的时候了写代码了。

main.c

#include "main.h"
#include "dma.h"
#include "rtc.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"
#include "oled.h"
#include "string.h"
#include "stdlib.h"
#include "time_data.h"
#include "cJSON.h"
#include "bmp.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */

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


/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 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);
uint8_t Weather_analysis(uint8_t* buff,uint8_t *Weather_stat,uint8_t *datas);
/* USER CODE BEGIN PFP */
uint8_t WIFI_Connect[64];
uint8_t Know_Customer_Service[64];
uint8_t Transparent_Transmission[64];
uint8_t get[254];
uint8_t Number;

uint8_t rxBuffers[1];
uint8_t rxBuffer[MAX_RX_BUFFER_SIZE];
uint32_t rxBufferIndex = 0;
uint8_t rxflang=0;
char buffs[64];
uint8_t buff_data[1024];
uint8_t buff_data_cp[562];
/* USER CODE END PFP */
uint16_t My_Time[] = {0, 0, 0, 0, 0, 0};  //年月日时分秒
int week; //温度
char celsius_symbol[] = {0xE2, 0x84, 0x83, '\0'}; // 摄氏度符号的UTF-8编码
char* temperature;
/* 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_SPI1_Init();
  MX_USART1_UART_Init();
  MX_USART3_UART_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
	OLED_Init();
	OLED_ColorTurn(1);
	OLED_Refresh();
	OLED_ShowChinese(0,0,16,(uint8_t *)"楷体测试",1);
	//OLED_ShowString(0,24,16,"Load...");
	OLED_Refresh();
	HAL_Delay(200);
	OLED_Clear(1);
	HAL_UART_Receive_IT(&huart1, (uint8_t*)&rxBuffers, 1);  //打开串口3的串口中断
	
	Number=0;
	
	HAL_UART_Transmit(&huart1,(uint8_t*)AT,strlen(AT),HAL_MAX_DELAY);  //发送AT测试
	HAL_Delay(200);
	
	HAL_UART_Transmit(&huart1,(uint8_t*)WiFi_Mode,strlen(WiFi_Mode),HAL_MAX_DELAY);  //配置STA模式
	HAL_Delay(200);
	
	sprintf(WIFI_Connect,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,pass);  //连接wifi
	HAL_UART_Transmit(&huart1,(uint8_t*)WIFI_Connect,strlen(WIFI_Connect),HAL_MAX_DELAY);
	HAL_Delay(1500);
	
	
	HAL_UART_Transmit(&huart1,(uint8_t*)SET_TIME,strlen(SET_TIME),HAL_MAX_DELAY);  //设置时区
	HAL_Delay(200);
	
	HAL_UART_Transmit(&huart1,(uint8_t*)GET_TIME,strlen(GET_TIME),HAL_MAX_DELAY);  //获取时间
	HAL_Delay(200);
	
	sprintf(Know_Customer_Service,"AT+CIPSTART=\"%s\",\"%s\",\%d\r\n",tcp,site,port);  //连接心知天气服务端
	HAL_UART_Transmit(&huart1,(uint8_t*)Know_Customer_Service,strlen(Know_Customer_Service),HAL_MAX_DELAY);
	HAL_Delay(1000);
	
	sprintf(Transparent_Transmission,"AT+CIPMODE=\%d\r\n",1);  //开启透传模式
	HAL_UART_Transmit(&huart1,(uint8_t*)Transparent_Transmission,strlen(Transparent_Transmission),HAL_MAX_DELAY);
	HAL_Delay(200);
	
	HAL_UART_Transmit(&huart1,(uint8_t*)Start_Data,strlen(Start_Data),HAL_MAX_DELAY);  //开始发送数据
	HAL_Delay(200);
	
	//https://api.seniverse.com/v3/weather/daily.json?key=%s&&location=chengdu&language=en&unit=c&start=-1&days=2
	//https://api.seniverse.com/v3/weather/now.json?key=%s&location=chengdu&language=en&unit=c
	sprintf(get,"GET https://api.seniverse.com/v3/weather/now.json?key=%s&location=chengdu&language=en&unit=c\r\n",Keys);  //获取json数据
	HAL_UART_Transmit(&huart1,(uint8_t*)get,strlen(get),HAL_MAX_DELAY);
	HAL_Delay(1000);
	
	HAL_UART_Transmit(&huart1,(uint8_t*)quit,strlen(quit),HAL_MAX_DELAY);  //退出发送模式
	HAL_Delay(200);  
	
	//HAL_UART_Transmit(&huart3,(uint8_t*)&rxBuffer,strlen(rxBuffer)* sizeof(char),HAL_MAX_DELAY);
	int length = sizeof(rxBuffer) / sizeof(rxBuffer[0]);
	int nuber;
	//获取时间
	for(int i=0;i<length;i++){
		if(rxBuffer[i]=='?'){
			nuber=i+16;
			for(int j=0;j<24;j++){
				buffs[j]=rxBuffer[nuber++];
			}
		}
		
	}
	//HAL_UART_Transmit(&huart3,(uint8_t*)&buffs,strlen(buffs)* sizeof(char),HAL_MAX_DELAY);
  HAL_Delay(10);
	//***********************************************提取JSON数据
	int number_cp;
	int num;
	int f;
	for(int z=0;z<strlen(rxBuffer) * sizeof(char);z++){
		if(rxBuffer[z]=='{'){
			number_cp=strlen(rxBuffer) * sizeof(char)-z;
			num=z;
			for(int f=0;f<number_cp;f++){
					buff_data[f]=rxBuffer[num];
					num++;				
			}
			break;		
		}
		//buff_data[z]=rxBuffer[z];
	}
	
	
	//printf("复制:%s\r\n",rxBuffer);
	//printf("数据:%s\r\n",buff_data);
	//************************************************获取年月日时分秒
	My_Time[0]=Year_Init(buffs,20,24); //年
	My_Time[1]=Month_Init(buffs,4,6); //月
	My_Time[2]=Day_Time_Init(buffs,8,9); //日
	My_Time[3]=Day_Time_Init(buffs,11,12); //时
	My_Time[4]=Day_Time_Init(buffs,14,15); //分
	My_Time[5]=Day_Time_Init(buffs,17,18); //秒
	week=calculateWeekday(My_Time[0],My_Time[1],My_Time[2]); //星期
	
	//HAL_UART_Transmit(&huart3,(uint8_t*)&My_Time,strlen(My_Time)* sizeof(char),HAL_MAX_DELAY);
	/*printf("年:%d\r\n",My_Time[0]);
	printf("月:%d\r\n",My_Time[1]);
	printf("日:%d\r\n",My_Time[2]);
	printf("时:%d\r\n",My_Time[3]);
	printf("分:%d\r\n",My_Time[4]);
	printf("秒:%d\r\n",My_Time[5]);
	printf("星期%d\r\n",My_Time[6]);
	printf("第一次:%s\r\n",buffs);*/
	//HAL_UART_Transmit(&huart1,(uint8_t*)at_cmd,strlen(at_cmd),HAL_MAX_DELAY);
	//HAL_Delay(200);

	cJSON *json;

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		//***********************************JSON解析数  据
		cJSON *root =cJSON_Parse((char*)buff_data);//读取心知天气回调包
		
		
		printf("数据1:%s\r\n",buff_data);
		//printf("数据2:%s\r\n",text);
		if (root == NULL) {
			const char *error_ptr = cJSON_GetErrorPtr();
			if (error_ptr != NULL) {
        printf("错误: %s\n", error_ptr);
			} else {
        printf("解析JSON出现未知错误.\n");
			}
		} else {
			printf("JSON 解析成功.\n");
		}
		
		cJSON *array =cJSON_GetObjectItem(root,"results");//读取关键字
		cJSON *results0=cJSON_GetArrayItem(array,0);//判断位置		

		cJSON *location =cJSON_GetObjectItem(results0,"location");//读取关键字
		cJSON *now =cJSON_GetObjectItem(results0,"now");//读取关键字
		
		cJSON *name_item= cJSON_GetObjectItem(now, "text");//状态
		
		cJSON *tem_item=cJSON_GetObjectItem(now,"temperature");  //温度
		temperature=tem_item->valuestring;
		
		
		
		HAL_Delay(1000); 
		if(My_Time[5]==59){   //秒
				My_Time[5]=0;
				My_Time[4]+=1;
				if(My_Time[4]==60){  //分
					My_Time[4]=0;
					My_Time[3]+=1;
					if(My_Time[3]==24){ //时
						My_Time[3]=0;
						//启动看门狗让硬件复位
					}
					
				}
		}	else{
			My_Time[5]+=1;
		}
		
		printf("时间:%d\r\n",My_Time[3]);
		if(My_Time[3]>=0&&My_Time[3]<2){
			OLED_ShowChinese(94,28,16,"凌晨",0);
		}else if(My_Time[3]>=2&&My_Time[3]<6){
			OLED_ShowChinese(94,28,16,"深夜",0);
		}else if(My_Time[3]>=6&&My_Time[3]<10){
			OLED_ShowChinese(94,28,16,"早晨",0);
		}else if(My_Time[3]>=10&&My_Time[3]<13){
			OLED_ShowChinese(94,28,16,"中午",0);
		}else if(My_Time[3]>=13&&My_Time[3]<17){
			OLED_ShowChinese(94,28,16,"下午",0);
		}else if(My_Time[3]>=17&&My_Time[3]<19){
			OLED_ShowChinese(94,28,16,"傍晚",0);
		}else if(My_Time[3]>=19&&My_Time[3]<0){
			OLED_ShowChinese(94,28,16,"晚上",0);
		}
		
		
		//年月日
		OLED_ShowNum01(1,0,16,My_Time[0],4);
		OLED_ShowChar(35,0,16,'.',1);
		OLED_ShowNum01(41,0,16,My_Time[1],2);
		OLED_ShowChar(57,0,16,'.',1);
		OLED_ShowNum01(61,0,16,My_Time[2],2);
		OLED_ShowChinese(94,0,16,"成都",0);
		//时钟
		//printf("%d:%d:%d\r\n",My_Time[3],My_Time[4],My_Time[5]);
		
		OLED_ShowChar(23,24,16,':',1);
		OLED_ShowChar(50,24,16,':',1);
		OLED_ShowNum01(3,21,24,My_Time[3],2);
		OLED_ShowNum01(31,21,24,My_Time[4],2);
		OLED_ShowNum01(58,21,24,My_Time[5],2);
		//星期
		OLED_ShowChinese(80,48,16,"星期",0);
		if(week==1){
			OLED_ShowChinese(108,48,16,"一",0);
		}else if(week==2){
			OLED_ShowChinese(112,48,16,"二",0);
		}else if(week==3){
			OLED_ShowChinese(112,48,16,"三",0);
		}else if(week==4){      
			OLED_ShowChinese(112,48,16,"四",0);
		}else if(week==5){
			OLED_ShowChinese(112,48,16,"五",0);
		}else if(week==6){
			OLED_ShowChinese(112,48,16,"六",0);
		}else if(week==0){
			OLED_ShowChinese(112,48,16,"天",0);
		}
		
		if(name_item != NULL && strcmp(name_item->valuestring, "Cloudy") == 0){
			OLED_ShowChinese(42,48,16,"多云",0);
		}else if(name_item != NULL && strcmp(name_item->valuestring, "Foggy") == 0){
			OLED_ShowChinese(42,48,16,"多雾",0);
		}
		
		OLED_ShowNum01(3,48,16,atoi(temperature),2);
		OLED_ShowChinese(19,48,16,"°",0);
		OLED_ShowChar(26,48,16,'C',1);
		
		OLED_Refresh();
		
		cJSON_Delete(root);//释放json
		
		
		//获取心知天气
		//char *buff_datajson = "{\"results\":[{\"location\":{\"id\":\"WM6N2PM3WY2K\",\"name\":\"Chengdu\",\"country\":\"CN\",\"path\":\"Chengdu,Chengdu,Sichuan,China\",\"timezone\":\"Asia/Shanghai\",\"timezone_offset\":\"08:00\"},\"now\":{\"text\":\"Cloudy\",\"code\":\"4\",\"temperature\":\"18\"},\"last_update\":\"2024-03-25T22:32:49+08:00\"}]}";
		//char *json_data = "{\"results\":[{\"location\":{\"id\":\"WM7V66VSE5DV\",\"name\":\"Guangan\",\"country\":\"CN\",\"path\":\"Guangan,Guangan,Sichuan,China\",\"timezone\":\"Asia/Shanghai\",\"timezone_offset\":\"+08:00\"},\"daily\":[{\"date\":\"2022-07-28\",\"text_day\":\"Sunny\",\"code_day\":\"0\",\"text_night\":\"Clear\",\"code_night\":\"1\",\"high\":\"34\",\"low\":\"24\",\"rainfall\":\"0.00\",\"precip\":\"0.00\",\"wind_direction\":\"SW\",\"wind_direction_degree\":\"225\",\"wind_speed\":\"8.4\",\"wind_scale\":\"2\",\"humidity\":\"87\"},{\"date\":\"2022-07-29\",\"text_day\":\"Sunny\",\"code_day\":\"0\",\"text_night\":\"Cloudy\",\"code_night\":\"4\",\"high\":\"38\",\"low\":\"25\",\"rainfall\":\"0.00\",\"precip\":\"0.00\",\"wind_direction\":\"CLM\",\"wind_direction_degree\":\"\",\"wind_speed\":\"8.4\",\"wind_scale\":\"2\",\"humidity\":\"81\"},{\"date\":\"2022-07-30\",\"text_day\":\"Cloudy\",\"code_day\":\"4\",\"text_night\":\"Cloudy\",\"code_night\":\"4\",\"high\":\"37\",\"low\":\"25\",\"rainfall\":\"0.00\",\"precip\":\"0.00\",\"wind_direction\":\"CLM\",\"wind_direction_degree\":\"\",\"wind_speed\":\"3.0\",\"wind_scale\":\"1\",\"humidity\":\"78\"}],\"last_update\":\"2022-07-28T08:00:00+08:00\"}]}";

		//printf("%s\r\n",text);
		//printf("数据:%s\r\n",buff_data);
		
		
		
		
		
		
    /* 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};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {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();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV128;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
	//HAL_UART_Transmit(&huart2,&rdata,1,0xffff);
	
  if (huart->Instance == USART1) {
    
		// 接收到一个字节的数据
		rxBuffer[rxBufferIndex++] = rxBuffers[0];
		
		if(rxflang==0){
			if(rxBuffers[0]=='\n'){
				rxBufferIndex=0;
			  //HAL_UART_Transmit(&huart3,(uint8_t*)&rxBuffer,strlen(rxBuffer)* sizeof(char),HAL_MAX_DELAY);
				rxflang=1;
		 }		
		}
		
    // 处理接收到的数据,例如打印或解析数据
    // ...
		//printf("%s\r\n",rxBuffer);
		//printf("%d\r\n",rxBufferIndex);
    // 继续接收数据
    HAL_UART_Receive_IT(&huart1,(uint8_t*)&rxBuffers, 1);
  }
} 


/* 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 */

main.h

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.h
  * @brief          : Header for main.c file.
  *                   This file contains the common defines of the application.
  ******************************************************************************
  * @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 */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#define AT "AT\r\n"
#define WiFi_Mode "AT+CWMODE=1\r\n"
#define ssid "wifi账号"
#define pass "wifi密码"
#define SET_TIME "AT+CIPSNTPCFG=1,8\r\n"
#define GET_TIME "AT+CIPSNTPTIME?\r\n"
#define MAX_RX_BUFFER_SIZE 6553
#define tcp "TCP"
#define site "api.seniverse.com"
#define port 80
#define Start_Data "AT+CIPSEND\r\n"
#define Keys "私钥"
#define quit "+++"
#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */

/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */

/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);

/* USER CODE BEGIN EFP */

/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/
#define OLED_CS_Pin GPIO_PIN_4
#define OLED_CS_GPIO_Port GPIOA
#define OLED_RES_Pin GPIO_PIN_0
#define OLED_RES_GPIO_Port GPIOB
#define OLED_DC_Pin GPIO_PIN_1
#define OLED_DC_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

usart.c添加代码

int fputc(int ch,FILE *f)
{   
    HAL_UART_Transmit(&huart3 , (uint8_t *)&ch , 1 , 0xffff);
    return ch;
}

五、成果展示

作者:小小萌星

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32和ESP8266连接7脚oled屏幕显示心知天气

发表评论