温湿度采集与OLED显示

一、I2C总线协议

I2C(Inter-Integrated Circuit)是一种用于连接低速设备到处理器或微控制器的串行通信协议。I2C协议允许多个设备共享同一总线,通过地址来区分不同的设备。根据实现方式的不同,I2C可以分为软件I2C和硬件I2C。

1. 硬件I2C:

  • 硬件I2C是由微控制器或处理器的专用硬件模块实现的。这个模块负责生成I2C时序和处理数据传输。
  • 硬件I2C的优点包括:
    • 高可靠性:由于时序由硬件控制,因此更加精确和可靠。
    • 低CPU负载:硬件模块可以独立处理I2C通信,减轻CPU的负担。
    • 易于使用:通常有现成的库和API供开发者使用,简化了编程工作。
  • 硬件I2C的缺点是灵活性较低,因为它依赖于特定的硬件模块。

2. 软件I2C:

  • 软件I2C是通过软件代码来模拟I2C总线的时序和通信协议。它不依赖于专用的硬件模块,而是使用通用的I/O引脚来模拟I2C信号。
  • 软件I2C的优点包括:
    • 灵活性高:可以在任何具有可用I/O引脚的设备上实现。
    • 可定制性:开发者可以根据需要调整时序和参数。
  • 软件I2C的缺点是:
    • CPU负载较高:需要CPU实时处理I2C通信,可能导致较高的CPU占用率。
    • 时序精度较低:由于时序由软件控制,可能不如硬件I2C精确。
    • 复杂性较高:实现软件I2C需要编写更多的代码,并且调试可能更加复杂。

总结来说,硬件I2C依赖于专用硬件模块,具有更高的可靠性和较低的CPU负载,而软件I2C通过软件模拟实现,具有更高的灵活性和可定制性,但可能导致较高的CPU负载和时序精度较低。

二、实现温湿度采集

1.配置芯片

在STM32CubeMX中新建工程并选择我们所需的芯片
在这里插入图片描述
配置RCC
在这里插入图片描述
配置SYS
在这里插入图片描述
配置USART1
在这里插入图片描述
配置I2C2
在这里插入图片描述
配置TIM1
在这里插入图片描述
配置时钟
在这里插入图片描述
设置项目
在这里插入图片描述
在这里插入图片描述
之后生成代码
添加AHT20文件
1.新建文件夹
在这里插入图片描述
在keil中新建组
在这里插入图片描述
将新建的组名字改为与之前的文件夹同样的名字
在这里插入图片描述
在组里添加新文件
在这里插入图片描述
分别添加一个.c文件和.h文件
在这里插入图片描述
在这里插入图片描述

2.实验代码

在文件中添加代码
aht20.c

#include "aht20.h"
 
#define AHT20_ADDRESS 0x70 // 从机地址
//AHT20 的驱动程序
 void AHT20_Init () //AHT20初始化函数  记住要在"aht20.h"中声明
{
  uint8_t readBuffer;//用于接收状态信息
  HAL_Delay(40);
  HAL_I2C_Master_Receive(&hi2c1, AHT20_ADDRESS, &readBuffer, 1, HAL_MAX_DELAY);//I2C读取函数,读数据函数 readBuffer此时获得了一个字节的状态字。
  if((readBuffer & 0x08) == 0x00) //判断第三位是否为0 发送0xBE命令初始化
  {
	  uint8_t sendBuffer [3] = {0xBE , 0x08 , 0x00};
	  HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);//I2C发送函数
  }
 
}
 
 void AHT20_Read(float *Temperature , float *Humidity) //AHT20读取温度湿度函数  记住要在"aht20.h"中声明
{
	uint8_t sendBuffer [3] = {0xAC , 0x33 , 0x00};
	uint8_t readBuffer [6];
	HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);
	HAL_Delay(75);
	HAL_I2C_Master_Receive(&hi2c1, AHT20_ADDRESS, readBuffer, 6, HAL_MAX_DELAY);
	if((readBuffer[0] & 0x80) == 0x00)
	{
		uint32_t date = 0;//接收温湿度需要2个半字节 所以要32
		date = ((uint32_t )readBuffer[3] >> 4) + ((uint32_t )readBuffer[2] << 4) + ((uint32_t )readBuffer[1] << 12);//对数据进行移位拼接.
		*Humidity = date * 100.0f / (1 << 20);//(1 << 20) 意为2的20次方. 乘100.0可以表示为百分数
 
		date = (((uint32_t )readBuffer[3] & 0x0F)<< 16) + ((uint32_t )readBuffer[4] << 8) + (uint32_t )readBuffer[5];//& 0x0F: 将这个无符号整数与十六进制数0x0F进行按位与操作。0x0F的二进制表示为00001111,这个操作会保留readBuffer[3]的低四位,即将高四位清零。
		*Temperature = date * 200.0f / (1 << 20) - 50;
	}
}
 

aht20.h

/*
 * aht20.h
 *
 *  Created on: Apr 25, 2024
 *      Author: lenovo
 */
 
#ifndef INC_AHT20_H_
#define INC_AHT20_H_
 
#include "i2c.h"
 void AHT20_Init (void);
 
 void AHT20_Read(float *Temperature , float *Humidity);
#endif /* INC_AHT20_H_ */
 

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 "i2c.h"
#include "usart.h"
#include "gpio.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "i2c.h"
#include <stdio.h>
#include "string.h"
#include "aht20.h"
/* 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);
/* 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_I2C1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  AHT20_Init ();//初始化AHT20
 
  float temperature , humidity ;    //定义温湿度变量
  char message [50];                //后续串口打印数据
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  AHT20_Read( &temperature , &humidity); //读取AHT20
	  sprintf(message ,"温度: %f℃ , 湿度: %f.\r\n",temperature , humidity);//拼接
	  HAL_UART_Transmit(&huart1, (uint8_t*)message,strlen(message) , HAL_MAX_DELAY);//串口发送函数
	  HAL_Delay(1000);
    /* 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_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  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_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != 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 */
 

之后连接实物,再将串口连接电脑,得到传感器结果

3.实验结果

在这里插入图片描述

三、OLED屏显

1.显示自己的学号和姓名

(1)u8g2库的移植
新建工程
配置RCC
在这里插入图片描述
配置SYS
在这里插入图片描述
配置I2C2
在这里插入图片描述
配置TIM1
在这里插入图片描述
配置时钟
在这里插入图片描述
配置项目
在这里插入图片描述
下载通过网盘分享的文件:u8g2-master.zip
链接: https://pan.baidu.com/s/13E0xfqspVAFwrcQMkbjnkw 提取码: jp3k

在刚刚建立的项目中新建两个文件夹
在这里插入图片描述

将链接里面的文件下载解压,把文件里面csrc文件夹的所有文件复制到u8g2文件夹里面

进入keil,新建分组,命名为u8g2

在这里插入图片描述
把下载的文件里面csrc文件夹的所有文件添加到u8g2组里面
在这里插入图片描述
随后将新建文件夹(U8g2和test)的路径加进去
点击魔法棒,选择c/c++
在这里插入图片描述
精简u8g2_d_setup.c:在keil的u8g2组里面打开u8g2_d_setup.c
在这里插入图片描述
(保留上面这部分,其他全部删除或者注释掉)

精简u8g2_d_memory.c:在keil的u8g2组里面打开u8g2_d_memory.c
在这里插入图片描述
(保留上面这部分,其他全部删除或者注释掉)

编写移植函数(.c和.h)
在这里插入图片描述
stm32_u8g2.h

#ifndef __STM32_U8G2_H
#define __STM32_U8G2_H
 
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "u8g2.h"
/* USER CODE BEGIN Includes */
 
/* USER CODE END Includes */
 
 
 
/* USER CODE BEGIN Private defines */
 
/* USER CODE END Private defines */
#define u8         unsigned char  // ?unsigned char ????
#define MAX_LEN    128  //
#define OLED_ADDRESS  0x78 // oled
#define OLED_CMD   0x00  // 
#define OLED_DATA  0x40  // 
 
/* USER CODE BEGIN Prototypes */
uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
void u8g2Init(u8g2_t *u8g2);
void draw(u8g2_t *u8g2);
void testDrawPixelToFillScreen(u8g2_t *u8g2);
 
#endif

stm32_u8g2.c

#include "stm32_u8g2.h"
#include "tim.h"
#include "i2c.h"
 
 
uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
    static uint8_t buffer[128];
    static uint8_t buf_idx;
    uint8_t *data;
 
    switch (msg)
    {
    case U8X8_MSG_BYTE_INIT:
    {
        /* add your custom code to init i2c subsystem */
        MX_I2C2_Init(); //I2C初始化
    }
    break;
 
    case U8X8_MSG_BYTE_START_TRANSFER:
    {
        buf_idx = 0;
    }
    break;
 
    case U8X8_MSG_BYTE_SEND:
    {
        data = (uint8_t *)arg_ptr;
 
        while (arg_int > 0)
        {
            buffer[buf_idx++] = *data;
            data++;
            arg_int--;
        }
    }
    break;
 
    case U8X8_MSG_BYTE_END_TRANSFER:
    {
        if (HAL_I2C_Master_Transmit(&hi2c2, OLED_ADDRESS, buffer, buf_idx, 1000) != HAL_OK)
            return 0;
    }
    break;
 
    case U8X8_MSG_BYTE_SET_DC:
        break;
 
    default:
        return 0;
    }
 
    return 1;
}
 
 
 
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    switch (msg)
    {
    case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
        __NOP();
        break;
    case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
        for (uint16_t n = 0; n < 320; n++)
        {
            __NOP();
        }
        break;
    case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
        HAL_Delay(1);
        break;
    case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
        //Tims_delay_us(5);
        break;                    // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
    case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
        break;                    // arg_int=1: Input dir with pullup high for I2C clock pin
    case U8X8_MSG_GPIO_I2C_DATA:  // arg_int=0: Output low at I2C data pin
        break;                    // arg_int=1: Input dir with pullup high for I2C data pin
    case U8X8_MSG_GPIO_MENU_SELECT:
        u8x8_SetGPIOResult(u8x8, /* get menu select pin state */ 0);
        break;
    case U8X8_MSG_GPIO_MENU_NEXT:
        u8x8_SetGPIOResult(u8x8, /* get menu next pin state */ 0);
        break;
    case U8X8_MSG_GPIO_MENU_PREV:
        u8x8_SetGPIOResult(u8x8, /* get menu prev pin state */ 0);
        break;
    case U8X8_MSG_GPIO_MENU_HOME:
        u8x8_SetGPIOResult(u8x8, /* get menu home pin state */ 0);
        break;
    default:
        u8x8_SetGPIOResult(u8x8, 1); // default return value
        break;
    }
    return 1;
}
 
//U8g2的初始化,需要调用下面这个u8g2_Setup_ssd1306_128x64_noname_f函数,该函数的4个参数含义:
//u8g2:传入的U8g2结构体
//U8G2_R0:默认使用U8G2_R0即可(用于配置屏幕是否要旋转)
//u8x8_byte_sw_i2c:使用软件IIC驱动,该函数由U8g2源码提供
//u8x8_gpio_and_delay:就是上面我们写的配置函数
 
void u8g2Init(u8g2_t *u8g2)
{
	u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8x8_gpio_and_delay); // 初始化u8g2 结构体
	u8g2_InitDisplay(u8g2);                                                                       // 
	u8g2_SetPowerSave(u8g2, 0);                                                                   // 
	u8g2_ClearBuffer(u8g2);
}
 
 
//void draw(u8g2_t *u8g2)
//{
//	u8g2_ClearBuffer(u8g2); 
//	
//    u8g2_SetFontMode(u8g2, 1); /*字体模式选择*/
//    u8g2_SetFontDirection(u8g2, 0); /*字体方向选择*/
//    u8g2_SetFont(u8g2, u8g2_font_inb24_mf); /*字库选择*/
//    u8g2_DrawStr(u8g2, 0, 20, "U");
//    
//    u8g2_SetFontDirection(u8g2, 1);
//    u8g2_SetFont(u8g2, u8g2_font_inb30_mn);
//    u8g2_DrawStr(u8g2, 21,8,"8");
//        
//    u8g2_SetFontDirection(u8g2, 0);
//    u8g2_SetFont(u8g2, u8g2_font_inb24_mf);
//    u8g2_DrawStr(u8g2, 51,30,"g");
//    u8g2_DrawStr(u8g2, 67,30,"\xb2");
//    
//    u8g2_DrawHLine(u8g2, 2, 35, 47);
//    u8g2_DrawHLine(u8g2, 3, 36, 47);
//    u8g2_DrawVLine(u8g2, 45, 32, 12);
//    u8g2_DrawVLine(u8g2, 46, 33, 12);
//  
//    u8g2_SetFont(u8g2, u8g2_font_4x6_tr);
//    u8g2_DrawStr(u8g2, 1,54,"github.com/olikraus/u8g2");
//		
//	u8g2_SendBuffer(u8g2);
//	HAL_Delay(1000);
//}
// 
//画点填充
void testDrawPixelToFillScreen(u8g2_t *u8g2)
{
    int t = 1000;
    u8g2_ClearBuffer(u8g2);
 
  for (int j = 0; j < 64; j++)
  {
    for (int i = 0; i < 128; i++)
    {
      u8g2_DrawPixel(u8g2,i, j);
    }
  }
  HAL_Delay(t);
}



之后添加位置
在这里插入图片描述
(2)显示姓名学号
1.打开PCtoLCD2002(可自行在网络下载)
2.选择模式 - 字符模式
3.点击选项,进行设置
在这里插入图片描述
在输入栏输入需要取模的汉字(只能是汉字),然后点击生成字模
在这里插入图片描述
其中我们的完整主函数为

/* 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 "i2c.h"
#include "tim.h"
#include "gpio.h"
#include "u8g2.h"
#include "stm32_u8g2.h"
#include "OLED_1.h"
#include <stdio.h>
#include "string.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);
/* 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_I2C2_Init();
  MX_TIM1_Init();
  MX_I2C1_Init();
 
  u8g2_t u8g2;     
  u8g2_Init(&u8g2);      
	
   
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    
    u8g2_SetFont(&u8g2,u8g2_font_ncenB12_tf);

    u8g2_DrawXBMP(&u8g2,32,0,16,16,xiang);
    u8g2_DrawXBMP(&u8g2,48,0,16,16,yue);
    u8g2_DrawXBMP(&u8g2,64,0,16,16,liang);
    u8g2_SetFont(&u8g2,u8g2_font_ncenB10_tf);
    u8g2_DrawStr(&u8g2,16,50,"632207030523");
    u8g2_SendBuffer(&u8g2);
 
    /* 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 */

其中,我们的字模数据保存在我的字库OLED_1.h函数中,大家也可以自己定义一个字库,或者直接在主函数中声明就可以了。我这里展示我自己定义工程的字库。
OLED_1.h

static const unsigned char xiang[] =

{0x10,0x00,0x10,0x1F,0x10,0x11,0x7E,0x11,0x10,0x1F,0x18,0x11,0x38,0x1F,0x54,0x11,0x12,0x11,0x10,0x1F,0x80,0x00,0x10,0x21,0x12,0x49,0x12,0x48,0xE1,0x0F,0x00,0x00};
    
static const unsigned char yue[] =
{0x00,0x00,0xF8,0x1F,0x08,0x10,0x08,0x10,0x08,0x10,0xF8,0x1F,0x08,0x10,0x08,0x10,0x08,0x10,0xF8,0x1F,0x08,0x10,0x08,0x10,0x04,0x10,0x04,0x10,0x02,0x14,0x01,0x08};
	
static const unsigned char liang[] =
{0x40,0x00,0x80,0x00,0xFE,0x3F,0x00,0x00,0xF8,0x0F,0x08,0x08,0xF8,0x0F,0x00,0x00,0xFE,0x7F,0x02,0x40,0xF1,0x27,0x10,0x04,0x10,0x04,0x08,0x44,0x04,0x44,0x03,0x78};

 

实验结果
在这里插入图片描述

2.滑动显示

用字库工具生成字模
在这里插入图片描述
在先前的OLED_1.h将之前要显示的文字的字模修改为现在所要展示的

static const unsigned char chong[] =

{0x00,0x08,0x00,0x1F,0xFC,0x00,0x80,0x00,0xFF,0x7F,0x80,0x00,0xF8,0x0F,0x88,0x08,0xF8,0x0F,0x88,0x08,0xF8,0x0F,0x80,0x00,0xFC,0x1F,0x80,0x00,0xFF,0x7F,0x00,0x00};
    
static const unsigned char qing[] =
{0x80,0x00,0x00,0x01,0xFC,0x7F,0x04,0x00,0x04,0x01,0x04,0x01,0x04,0x01,0xF4,0x3F,0x04,0x01,0x84,0x02,0x84,0x02,0x44,0x04,0x42,0x04,0x22,0x08,0x11,0x10,0x08,0x60};
	
static const unsigned char jiao[] =
{0x40,0x00,0x80,0x00,0x80,0x00,0xFF,0x7F,0x00,0x00,0x08,0x08,0x08,0x10,0x04,0x24,0x12,0x24,0x20,0x02,0x40,0x01,0x80,0x00,0x40,0x01,0x30,0x02,0x0C,0x0C,0x03,0x70};

static const unsigned char tong[] =

{0x00,0x00,0xE2,0x1F,0x04,0x08,0x84,0x05,0x00,0x02,0xE0,0x3F,0x27,0x22,0x24,0x22,0xE4,0x3F,0x24,0x22,0x24,0x22,0xE4,0x3F,0x24,0x22,0x24,0x2A,0x2A,0x10,0xF1,0x7F};
 
static const unsigned char da[] =

{0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xFF,0x7F,0x80,0x00,0x80,0x00,0x40,0x01,0x40,0x01,0x20,0x02,0x20,0x02,0x10,0x04,0x08,0x08,0x04,0x10,0x03,0x60};
 
static const unsigned char xue[] =

{0x44,0x10,0x88,0x10,0x88,0x08,0x00,0x04,0xFE,0x7F,0x02,0x40,0x01,0x20,0xF8,0x07,0x00,0x02,0x80,0x01,0xFF,0x7F,0x80,0x00,0x80,0x00,0x80,0x00,0xA0,0x00,0x40,0x00};
 

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 "i2c.h"
#include "tim.h"
#include "gpio.h"
#include "u8g2.h"
#include "stm32_u8g2.h"
#include "OLED_1.h"
#include <stdio.h>
#include "string.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);
/* 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_I2C2_Init();
  MX_TIM1_Init();

 
  u8g2_t u8g2;     
  u8g2Init(&u8g2);      
	
  float temperature=1, humindity;
	
	uint16_t x=0;
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    
  //  u8g2_SetFont(&u8g2,u8g2_font_ncenB12_tf);

    //u8g2_DrawXBMP(&u8g2,32,0,16,16,xiang);
   // u8g2_DrawXBMP(&u8g2,48,0,16,16,yue);
   // u8g2_DrawXBMP(&u8g2,64,0,16,16,liang);
    //u8g2_SetFont(&u8g2,u8g2_font_ncenB10_tf);
   // u8g2_DrawStr(&u8g2,16,50,"632207030523");
   // u8g2_SendBuffer(&u8g2);
 

        if(x<=128)
		{
			x++;//????,??????x???????????
		}
		else if(x>128)//??
		{
			x=0;
		}
    u8g2_SetFont(&u8g2,u8g2_font_ncenB12_tf);//??????
    //(???????,????x?y???????????????????)
    u8g2_DrawXBMP(&u8g2,x+16,0,16,16,chong);
    u8g2_DrawXBMP(&u8g2,x+32,0,16,16,qing);
    u8g2_DrawXBMP(&u8g2,x+48,0,16,16,jiao);
    u8g2_DrawXBMP(&u8g2,x+64,0,16,16,tong);
    u8g2_DrawXBMP(&u8g2,x+80,0,16,16,da);
    u8g2_DrawXBMP(&u8g2,x+96,0,16,16,xue);
    u8g2_SetFont(&u8g2,u8g2_font_ncenB10_tf);
    u8g2_SendBuffer(&u8g2);
 

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

之后运行并下载代码
实验结果如下

OLED移动显示

3.显示温湿度

首先我们需要将前文提到的AHT20的采集程序添加到我们的工程中,添加完之后,和之前的步骤相同,只是将串口打印改为了由OLED屏输出。需要值得注意的是,u8g2库并不能直接展示变量,所以我们还是需要使用sprintf将变量转义为字符。同时通过u8g2_DrawUTF8输出我们的UTF8编码格式的数据。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 "i2c.h"
#include "tim.h"
#include "gpio.h"
#include "u8g2.h"
#include "stm32_u8g2.h"
#include "OLED_1.h"
#include "aht20.h"
#include <stdio.h>
#include "string.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);
/* 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_I2C2_Init();
  MX_TIM1_Init();

  /* USER CODE BEGIN 2 */
 
  u8g2_t u8g2;     
  u8g2_Init(&u8g2);      //初始化
 
  /* USER CODE END 2 */
    float temperature=1 , humidity ;
    char t[5];
    char h[5];
 
//  uint16_t x=0;
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
//      //显示汉字和数字
//    u8g2_SetFont(&u8g2,u8g2_font_ncenB12_tf);//设置字体格式
//    //(参数顺序依次是,结构体、x、y、字宽、字高、储存要显示的字点阵的数组)
//    u8g2_DrawXBMP(&u8g2,32,0,16,16,xing);
//    u8g2_DrawXBMP(&u8g2,48,0,16,16,yue);
//    u8g2_DrawXBMP(&u8g2,64,0,16,16,liang);
//    u8g2_SetFont(&u8g2,u8g2_font_ncenB10_tf);
//    u8g2_DrawStr(&u8g2,16,50,"632207030523");
//    u8g2_SendBuffer(&u8g2);
      //滚动显示汉字
//        if(x<=128)
//		{
//			x++;//向右滑动,可以提高每次x的增加量来控制滑动速度
//		}
//		else if(x>128)//置零
//		{
//			x=0;
//		}
//    u8g2_SetFont(&u8g2,u8g2_font_ncenB12_tf);//设置字体格式
//    //(参数顺序依次是,结构体、x、y、字宽、字高、储存要显示的字点阵的数组)
//    u8g2_DrawXBMP(&u8g2,x+16,0,16,16,chong);
//    u8g2_DrawXBMP(&u8g2,x+32,0,16,16,qing);
//    u8g2_DrawXBMP(&u8g2,x+48,0,16,16,jiao);
//    u8g2_DrawXBMP(&u8g2,x+64,0,16,16,tong);
//    u8g2_DrawXBMP(&u8g2,x+80,0,16,16,da);
//    u8g2_DrawXBMP(&u8g2,x+96,0,16,16,xue);
//    u8g2_SetFont(&u8g2,u8g2_font_ncenB10_tf);
//    u8g2_SendBuffer(&u8g2);
        //显示采集到的温度和湿度
    AHT20_Read( &temperature , &humidity); //读取AHT20
	sprintf(t ," %f",temperature);//拼接
    sprintf(h ," %f",humidity);//拼接
    u8g2_SetFont(&u8g2,u8g2_font_ncenB12_tf);//设置字体格式
    //(参数顺序依次是,结构体、x、y、字宽、字高、储存要显示的字点阵的数组)
    u8g2_DrawXBMP(&u8g2,32,0,16,16,wen);
    u8g2_DrawXBMP(&u8g2,48,0,16,16,du);
	u8g2_DrawStr(&u8g2,64,16,":");
    u8g2_SetFont(&u8g2,u8g2_font_ncenB10_tf);
    u8g2_DrawXBMP(&u8g2,32,32,16,16,shi);
    u8g2_DrawXBMP(&u8g2,48,32,16,16,du);
	u8g2_DrawStr(&u8g2,64,48,":");
    u8g2_SetFont(&u8g2,u8g2_font_ncenB10_tf);
    u8g2_DrawUTF8(&u8g2,80,16,t);
	u8g2_DrawUTF8(&u8g2,80,48,h);
    u8g2_SendBuffer(&u8g2);
    /* 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 */

实验结果如下:
在这里插入图片描述

四、实验总结

1. I2C总线通信协议的理解与应用

理解I2C协议:
通过本次实验,我对I2C总线通信协议有了更深入的理解。I2C协议是一种同步串行通信协议,通常用于连接低速外围设备(如传感器、EEPROM等)到微控制器。
I2C总线的特点是只需要两条线:数据线(SDA)和时钟线(SCL)。这种简洁的连接方式使得多个设备可以共享同一总线,减少了引脚的使用。
硬件与软件I2C的选择:
在实验中,我使用了STM32F103的硬件I2C模块来实现与AHT20温湿度传感器的通信。硬件I2C模块提供了较高的传输速率和较低的CPU负载,这在处理多个传感器数据时尤为重要。
通过对比软件I2C和硬件I2C,我认识到硬件I2C在处理复杂通信时的优势,尤其是在需要高可靠性和高效率的应用中。

2. AHT20温湿度传感器数据采集

数据采集的实现:

实验中,我成功实现了每隔2秒采集一次AHT20传感器的温湿度数据,并通过串口发送到上位机。这一过程涉及到对AHT20数据手册的深入阅读和理解,以及对STM32串口通信的配置。
在数据采集过程中,我遇到了一些挑战,如确保数据的准确性和稳定性。通过调整采样频率和优化数据处理算法,我最终实现了稳定的数据采集。

3. OLED显示屏的应用

OLED显示原理:
通过实验,我理解了OLED显示屏的工作原理和汉字点阵编码方法。OLED显示屏通过控制每个像素点的亮度来显示图像,这使得它能够提供高对比度和低功耗的显示效果。
在实验中,我学会了如何使用STM32F103的SPI或I2C接口来控制OLED显示屏,实现了复杂的显示效果,如滑动显示长字符。
滑动显示的实现:
实现长字符的滑动显示是一个技术挑战,需要对OLED显示屏的刷新机制有深入的理解。通过使用硬件刷屏模式,我成功实现了平滑的滑动效果,这在显示长文本或动态信息时非常有用。

4.心得体会

本次实验让我深刻体会到硬件与软件结合的重要性。通过对STM32F103的编程和外围设备的连接,我掌握了如何将理论知识应用于实际问题的解决中。
实验中遇到的各种技术挑战,如I2C通信的调试和OLED显示的优化,通过查阅资料和反复测试,我最终实现了预期功能。这一过程不仅提升了我的技术能力,也增强了我的问题解决能力。
在实验过程中,我对I2C和SPI通信协议有了更深入的理解。这些协议的细节对于确保设备间的可靠通信至关重要。
通过对协议的深入研究,我学会了如何优化通信过程,减少错误和干扰,这对于提高系统的稳定性和性能非常重要。
实验不仅提升了我的技术能力,也加深了我对嵌入式系统的理解。通过对STM32F103的编程和外围设备的连接,我掌握了如何设计和实现一个完整的嵌入式系统。
这次实验经验为我今后的学习和工作打下了坚实的基础,让我对嵌入式系统的设计和开发有了更全面的认识。
通过这次实验,我不仅掌握了I2C和SPI通信协议的应用,还提升了我的编程能力和硬件调试技巧。这些经验将对我今后的学习和工作产生深远的影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值