接线图

这是江科大的接线图,我的版本还是使用硬件I2C与OLED屏幕通信,由于用的是硬件I2C2,所以按键键码值只读取GPIO_Pin_1就行,PB11被占用用来发送I2C信号,把相关代码注释即可
代码实现
标准库实现
已开源到:https://gitee.com/qin-ruiqian/jiangkeda-stm32
Key.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
//#include "Serial.h"//初始化按键
void Key_Init(void)
{//打开APB2总线GPIOB外设端口,并开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //读取按键,选择上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //选的是PB1GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//Serial_Init();
}//读取按键值
uint8_t Key_GetNum(void)
{uint8_t KeyNum = 0;//Serial_Printf("KeyNumStart:%d\r\n", KeyNum);if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) //读取PB1口的电平{Delay_ms(20); //消抖while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0); //直到按键松手Delay_ms(20); //消抖KeyNum = 1;}//Serial_Printf("KeyNumEnd:%d\r\n", KeyNum);// if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0) //读取PB11口的电平// {// Delay_ms(20); //消抖// while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0); //直到按键松手// Delay_ms(20); //消抖// KeyNum = 2;// }return KeyNum;
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "MYOLED.h"
#include "Key.h"
//#include "Serial.h"uint8_t KeyNum;
uint16_t ArrayWrite[] = {0x1234, 0x5678};
uint16_t ArrayRead[2]; //用于存放写入和读取数组的数组int main(void)
{//Serial_Init();MYOLED_Init();//Serial_Printf("OLED屏幕初始化完成\r\n");Key_Init();//Serial_Printf("按键初始化完成\r\n");MYOLED_ShowString(0,0,"W:");//Serial_Printf("OLED屏幕'W:'显示完成\r\n");MYOLED_ShowString(0,1,"R:");//BKP代码非常少,不进行封装了,直接在主函数中演示//第一步,开启PWR和BKP的时钟//第二部,使用PWR的一个函数,使能对BKP和RTC的访问RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); //开启PWR时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE); //开启BKP时钟PWR_BackupAccessCmd(ENABLE); //使能对BKP和RTC的访问//BKP_WriteBackupRegister(BKP_DR1, 0x1234); //写备份寄存器DR1// MYOLED_ShowHexNum(0,0,BKP_ReadBackupRegister(BKP_DR1),4); //读备份寄存器DR1,并用OLED屏幕显示//每次都读取一下:ArrayRead[0] = BKP_ReadBackupRegister(BKP_DR1);ArrayRead[1] = BKP_ReadBackupRegister(BKP_DR2);MYOLED_ShowHexNum(2,1,ArrayRead[0],4);MYOLED_ShowHexNum(7,1,ArrayRead[1],4);while (1) {KeyNum = Key_GetNum();//Serial_Printf("KeyNum:%d\r\n", KeyNum);if(KeyNum == 1){ArrayWrite[0]++;ArrayWrite[1]++;BKP_WriteBackupRegister(BKP_DR1, ArrayWrite[0]);BKP_WriteBackupRegister(BKP_DR2, ArrayWrite[1]);MYOLED_ShowHexNum(2,0,ArrayWrite[0],4);MYOLED_ShowHexNum(7,0,ArrayWrite[1],4);}ArrayRead[0] = BKP_ReadBackupRegister(BKP_DR1);ArrayRead[1] = BKP_ReadBackupRegister(BKP_DR2);MYOLED_ShowHexNum(2,1,ArrayRead[0],4);MYOLED_ShowHexNum(7,1,ArrayRead[1],4);}
}
HAL库实现
已开源到:https://gitee.com/qin-ruiqian/jiangkeda-stm32-hal
IDE关于RTC的设置如下图:

Key.c
/** Key.c** Created on: Aug 9, 2025* Author: Administrator*/
#include "stm32f1xx_hal.h"//读取按键值
uint8_t Key_GetNum(void)
{uint8_t KeyNum = 0;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0){HAL_Delay(20); //消抖while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0); //直到按键松手HAL_Delay(20); //消抖KeyNum = 1;}
// if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11) == 0)
// {
// HAL_Delay(20); //消抖
// while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11) == 0); //直到按键松手
// HAL_Delay(20); //消抖
// KeyNum = 2;
// }return KeyNum;
}
main.c
/* USER CODE BEGIN Header */
/********************************************************************************* @file : main.c* @brief : Main program body******************************************************************************* @attention** Copyright (c) 2025 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 "rtc.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "MYOLED.h"
#include "Key.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 */
uint8_t KeyNum;
uint16_t ArrayWrite[] = {0x1234, 0x5678};
uint16_t ArrayRead[2]; //用于存放写入和读取数组的数组
/* 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_RTC_Init();/* USER CODE BEGIN 2 */MYOLED_SetI2CHandleBeforeInit(&hi2c2); //一定别忘了加,这里得把句柄传进去MYOLED_Init();MYOLED_ShowString(0,0,"W:");MYOLED_ShowString(0,1,"R:");//每次都读取一下:ArrayRead[0] = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);// HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, Data);ArrayRead[1] = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);MYOLED_ShowHexNum(2,1,ArrayRead[0],4);MYOLED_ShowHexNum(7,1,ArrayRead[1],4);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){KeyNum = Key_GetNum();if(KeyNum == 1){ArrayWrite[0]++;ArrayWrite[1]++;HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, ArrayWrite[0]);HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, ArrayWrite[1]);MYOLED_ShowHexNum(2,0,ArrayWrite[0],4);MYOLED_ShowHexNum(7,0,ArrayWrite[1],4);}ArrayRead[0] = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);;ArrayRead[1] = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);MYOLED_ShowHexNum(2,1,ArrayRead[0],4);MYOLED_ShowHexNum(7,1,ArrayRead[1],4);/* 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_LSI|RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.LSIState = RCC_LSI_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_LSI;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != 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 */
实现效果
读取上一次按的结果

这次按的结果

读取这次按的结果

