使用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;
}
五、成果展示
作者:小小萌星