STM32学习笔记【32.BKP + RTC】

文章目录

  • 前言
  • 一、BKP【备份寄存器】
    • [1. 什么是BKP?](#1. 什么是BKP?)
    • [2. BKP框图](#2. BKP框图)
    • [3. 小实验:读写BKP](#3. 小实验:读写BKP)
      • [3.1 实验目的](#3.1 实验目的)
      • [3.2 硬件清单](#3.2 硬件清单)
      • [3.3 构思环节](#3.3 构思环节)
      • [3.4 出现的问题](#3.4 出现的问题)
      • [3.5 代码展示](#3.5 代码展示)
      • [3.6 实验结果](#3.6 实验结果)
  • 二、RTC【实时时钟】
    • [1. 什么是RTC?](#1. 什么是RTC?)
    • [2. RTC框图](#2. RTC框图)
    • [3. RTC寄存器](#3. RTC寄存器)
      • [3.1 备份域控制寄存器(RCC_BDCR)](#3.1 备份域控制寄存器(RCC_BDCR))
      • [3.2 RTC控制寄存器高位(RTC_CRH)](#3.2 RTC控制寄存器高位(RTC_CRH))
      • [3.3 RTC控制寄存器低位(RTC_CRL)](#3.3 RTC控制寄存器低位(RTC_CRL))
      • [3.4 RTC预分频装载寄存器(RTC_PRLH/RTC_PRLL)](#3.4 RTC预分频装载寄存器(RTC_PRLH/RTC_PRLL))
      • [3.5 RTC预分频器余数寄存器(RTC_DIVH / RTC_DIVL)](#3.5 RTC预分频器余数寄存器(RTC_DIVH / RTC_DIVL))
      • [3.6 RTC计数器寄存器 (RTC_CNTH / RTC_CNTL)](#3.6 RTC计数器寄存器 (RTC_CNTH / RTC_CNTL))
      • [3.7 RTC闹钟寄存器(RTC_ALRH/RTC_ALRL)](#3.7 RTC闹钟寄存器(RTC_ALRH/RTC_ALRL))
    • [4. RTC库函数](#4. RTC库函数)
    • [5. RTC驱动步骤](#5. RTC驱动步骤)
    • [6. 小实验](#6. 小实验)

前言

本文主要讲述BKP,42个16位的备份寄存器,用来存储84个字节的用户应用程序数据。其次,讲述RTC,一个独立的实时定时器,可提供时钟日历的功能,以及它相关的寄存器和库函数介绍。最后通过两个小实验帮助我们更实际的了解BKP和RTC。


一、BKP【备份寄存器】

1. 什么是BKP?

BKP,备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域Backup Domain里,当VDD电源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。

此外,BKP控制寄存器用来管理侵入检测RTC校准功能。

复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问:

  • 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟
  • 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。

用户数据存储容量:

20字节(中容量和小容量)/

84字节(大容量和互联型)

备份域:VDD【主电源】和VBAT两种供电方式。掉电依然是丢失的。

2. BKP框图

3. 小实验:读写BKP

3.1 实验目的

读写BKP

3.2 硬件清单

  • 上官二号
  • ST-Link
  • USB转TTL

3.3 构思环节

  1. 建立rtc文件夹:因为bkp内容一般是写在rtc中,所以直接建立rtc文件夹;建立.c和.h文件
  2. rtc.c
c 复制代码
void rtc_init(void)
{
   // 打开PWR和BKP时钟
   // 使能后备寄存器访问
   HAL_PWR_EnableBkUpAccess();

   // RTC初始化
   // 3个参数配置
   RTC
   32767
   NONE
   HAL_RTC_Init(&rtc_handle);
}

// 读取数据
uint16_t rtc_read_bkp(uint8_t bkrx)
{
uint16_t data = 0;
 data =  HAL_RTCEx_BKUPRead(&rtc_handle, bkrx);
 return (uint32_t)data;
}

// 写数据
void rtc_write_bkp(uint8_t bkrx, uint8_t data)
{
    HAL_RTCEx_BKUPWrite();
}
  1. main.c

rtc_init();

rtc_write_bkr(1, 0xA5A5);

printf("读出来的值:%X\r\n", rtc_read_bkr(1));

3.4 出现的问题

写入的数据未读出来

只打开了PWR时钟,未把BKP时钟打开

__HAL_RCC_BKP_CLK_ENABLE();

3.5 代码展示

rtc.c

c 复制代码
#include "rtc.h"

RTC_HandleTypeDef hrtc_handle = {0};

void rtc_init(void)
{
    // 打开PWR和BKP时钟
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_RCC_BKP_CLK_ENABLE();
    // 使能后备寄存器访问
    HAL_PWR_EnableBkUpAccess();
    
    hrtc_handle.Instance = RTC;
    hrtc_handle.Init.AsynchPrediv = 32767;
    hrtc_handle.Init.OutPut = RTC_OUTPUTSOURCE_NONE; 
    HAL_RTC_Init(&hrtc_handle);
}

// 读数据
uint16_t rtc_read_bkp(uint8_t bkr)
{
    uint32_t data = 0;
    data = HAL_RTCEx_BKUPRead(&hrtc_handle, bkr);
    
    return (uint16_t)data;
}

// 写数据
void rtc_write_bkp(uint8_t bkr, uint16_t data)
{
    HAL_RTCEx_BKUPWrite(&hrtc_handle, bkr, data);

}

rtc.h

c 复制代码
#ifndef __RTC_H__
#define __RTC_H__

#include "sys.h"

void rtc_init(void);
uint16_t rtc_read_bkp(uint8_t bkr);
void rtc_write_bkp(uint8_t bkr, uint16_t data);

#endif

main.c

c 复制代码
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "rtc.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();
    uart1_init(115200);
    rtc_init();
    printf("hello world! \r\n");
    
    rtc_write_bkp(1, 0xA7A7);
    printf("读出来的值:%X\r\n", rtc_read_bkp(1));
    
    while(1)
    {
        
    }
}

3.6 实验结果

读出来的值:A5A5

按复位键,读出来的值不受影响

二、RTC【实时时钟】

1. 什么是RTC?

实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。

RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。

复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问:

  • 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟
  • 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。

32位的可编程计数器,可对应Unix时间戳的秒计数器

Unix时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。

20位的可编程预分频器,可适配不同频率的输入时钟。

可选择三种RTC时钟源:

  • HSE时钟除以128(通常为8MHz/128)
  • LSE振荡器时钟(通常为32.768KHz)
  • LSI振荡器时钟(40KHz)

2. RTC框图

3. RTC寄存器

3.1 备份域控制寄存器(RCC_BDCR)

备份域控制寄存器中(RCC_BDCR)的LSEON、LSEBYP、RTCSEL和RTCEN位处于备份域。因

此,这些位在复位后处于写保护状态,只有在电源控制寄存器(PWR_CR)中的DBP位置'1'后才能对这些位进行改动。

关注:

RTCEN:RTC时钟使能

RTCSEL1:0:RTC时钟源选择

LSEON:外部低速振荡器使能 。1:外部32kHz振荡器开启。

3.2 RTC控制寄存器高位(RTC_CRH)

OWIE:允许溢出中断位。1------允许溢出中断

ALRIE:允许闹钟中断。1------允许闹钟中断

SECIE:允许秒中断。1------允许秒中断

这些位用来屏蔽中断请求。

注意:系统复位后,所有的中断被屏蔽,因此可通过写RTC寄存器来确保在初始化后没有挂起的中断请求。

当外设正在完成前一次写操作时(标志位RTOFF=0),不能对RTC_CRH寄存器进行写操作。

RTC功能由这个控制寄存器控制,一些位的写操作必须经过一个特殊的配置过程来完成。

3.3 RTC控制寄存器低位(RTC_CRL)

RTOFF :RTC操作关闭。

RTC模块利用这位来指示对其寄存器进行的最后一次操作的状态,指示操作是否完成。若此位为'0',则表示无法对任何的RTC寄存器进行写操作。此位为只读位。

1------上一次对RTC寄存器的写操作已经完成。

CNF :配置标志。

此位必须由软件置'1'以进入配置模式,从而允许向RTC_CNT、RTC_ALR或RTC_PRL寄存器写入数据。只有当此位在被置'1'并重新由软件清'0'后,才会执行写操作。

1------进入配置模式

3.4 RTC预分频装载寄存器(RTC_PRLH/RTC_PRLL)

预分频装载寄存器用来保存RTC预分频器的周期计数值。它们受RTC_CR寄存器的RTOFF位保护,仅当RTOFF值为'1'时允许进行写操作。

RTC预分频装载寄存器高位(RTC_PRLH)

0~3位

RTC预分频装载寄存器低位(RTC_PRLL)

0~15位

3.5 RTC预分频器余数寄存器(RTC_DIVH / RTC_DIVL)

RTC预分频器余数寄存器高位(RTC_DIVH)

0~3位

RTC预分频器余数寄存器低位(RTC_DIVL)

0~15位

3.6 RTC计数器寄存器 (RTC_CNTH / RTC_CNTL)

RTC核有一个32位可编程的计数器,可通过两个16位的寄存器访问。

RTC计数器寄存器高位(RTC_CNTH)

RTC计数器寄存器低位(RTC_CNTL)

3.7 RTC闹钟寄存器(RTC_ALRH/RTC_ALRL)

当可编程计数器的值与RTC_ALR中的32位值相等时,即触发一个闹钟事件,并且产生RTC闹钟中断。此寄存器受RTC_CR寄存器里的RTOFF位写保护,仅当RTOFF值为'1'时,允许写操作。

RTC闹钟寄存器高位(RTC_ALRH)

RTC闹钟寄存器低位(RTC_ALRL)

4. RTC库函数

c 复制代码
HAL_RTC_Init();

// 获取RTC当前时间
HAL_RTC_GetTime();
// 获取RTC当前日期
HAL_RTC_GetDate();

// 设置RTC当前时间
HAL_RTC_SetTime(); // 将CNT的值读出来(时间戳)
// 设置RTC当前日期
HAL_RTC_SetDate();

// 闹钟到点不会响
HAL_RTC_SetAlarm();
// 设置闹钟,到点后会响
HAL_RTC_SetAlarm_IT();

// 标志位是RTOFF位,置1才能写操作
__HAL_RTC_ALARM_GET_FLAG();

5. RTC驱动步骤

注意事项:

  • 必须设置RTC_CRL寄存器中的CNF位,是RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器
  • 对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1 时,才可以写入RTC寄存器。

6. 小实验

6.1 实验1:读写RTC时间实验

实验目的

读写RTC时间实验

构思环节
  1. 在rtc初始化函数中
c 复制代码
void rtc_init(void)
{
打开PWR和BKP时钟
使能后备寄存器访问
HAL_PWR_EnableBkUpAccess();

// 配置RTC参数
对象选择RTC
分频系数32767  进入之后会自动+1
侵入检测
HAL_RTC_Init();
}
  1. msp函数
c 复制代码
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
    // 使能RTC
    
    // 设置时钟源,两个函数,并对结构体参数进行配置
    振荡器
    LSE状态
    PLL
    HAL_RCC_OscConfig(&osc_initstruct);
 
外设RTC
时钟选择LSE :32767
HAL_RCCEx_PeriphCLKConfig(&periphclk_initstruct);
}
  1. 读取时间
c 复制代码
void rtc_get_time(void)
{
两个函数,获取时间和获取日期
HAL_RTC_GetTime();
HAL_RTC_GetDate();

// 打印输出rtc时间
printf();
}
  1. 设置时间
    struct tm time_data:该结构体是系统自带的,在#include "time.h"文件中
c 复制代码
void rtc_set_time(struct tm time_data)
{
   // 对时间的时分秒进行配置
   // 对日期的年月日进行配置
   需注意:年份系统给的是从1~99,所以年份表示为:`time_data.tm_year - 2000`

// 仅当RTOFF状态位是1时,才可以写入RTC寄存器,所以要做判断,一直获取RTOFF值
 while(!__HAL_RTC_ALARM_GET_FLAG(&hrtc_handle, RTC_FLAG_RTOFF));
}
代码展示

rtc.c

c 复制代码
#include "rtc.h"
#include "stdio.h"

RTC_HandleTypeDef hrtc_handle = {0};

void rtc_init(void)
{
    // 打开PWR和BKP时钟
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_RCC_BKP_CLK_ENABLE();
    // 使能后备寄存器访问
    HAL_PWR_EnableBkUpAccess();
    
    hrtc_handle.Instance = RTC;
    hrtc_handle.Init.AsynchPrediv = 32767;               // 分频系数
    hrtc_handle.Init.OutPut = RTC_OUTPUTSOURCE_NONE;     //侵入角   侵入检测
    HAL_RTC_Init(&hrtc_handle);
}

// 设置Msp函数
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
    // 使能RTC
    __HAL_RCC_RTC_ENABLE();
    
    RCC_OscInitTypeDef osc_initstruct = {0};
    RCC_PeriphCLKInitTypeDef  periphclk_initstruct = {0};
    
    // 设置时钟源
    osc_initstruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;        // 振荡器
    osc_initstruct.LSEState = RCC_LSE_ON;                          // LSE状态
    osc_initstruct.PLL.PLLState = RCC_PLL_NONE;
    HAL_RCC_OscConfig(&osc_initstruct);
    
    periphclk_initstruct.PeriphClockSelection = RCC_PERIPHCLK_RTC ;  // 外设RTC:32.768
    periphclk_initstruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;   //时钟选择  
    HAL_RCCEx_PeriphCLKConfig(&periphclk_initstruct);
    
}

// 读数据
uint16_t rtc_read_bkp(uint8_t bkr)
{
    uint32_t data = 0;
    data = HAL_RTCEx_BKUPRead(&hrtc_handle, bkr);
    
    return (uint16_t)data;
}

// 写数据
void rtc_write_bkp(uint8_t bkr, uint16_t data)
{
    HAL_RTCEx_BKUPWrite(&hrtc_handle, bkr, data);

}


// 读取时间
void rtc_get_time(void)
{
    RTC_TimeTypeDef rtc_time = {0};
    RTC_DateTypeDef rtc_date = {0};
    
    HAL_RTC_GetTime(&hrtc_handle, &rtc_time, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc_handle, &rtc_date, RTC_FORMAT_BIN);
    
    printf("rtc time: %d-%02d-%02d %02d:%02d:%02d\r\n", rtc_date.Year + 2000, rtc_date.Month, rtc_date.Date,
    rtc_time.Hours, rtc_time.Minutes, rtc_time.Seconds);
}

// 设置时间
void rtc_set_time(struct tm time_data)
{
    RTC_TimeTypeDef rtc_time = {0};
    RTC_DateTypeDef rtc_date = {0};
    
    rtc_time.Hours = time_data.tm_hour;
    rtc_time.Minutes = time_data.tm_min;
    rtc_time.Seconds = time_data.tm_sec;
    HAL_RTC_SetTime(&hrtc_handle, &rtc_time, RTC_FORMAT_BIN);
    
    rtc_date.Year = time_data.tm_year - 2000;
    rtc_date.Month = time_data.tm_mon;
    rtc_date.Date = time_data.tm_mday;
    HAL_RTC_SetDate(&hrtc_handle, &rtc_date, RTC_FORMAT_BIN);
    
    // 一直获取RTOFF值,0:一直在循环内
    while(!__HAL_RTC_ALARM_GET_FLAG(&hrtc_handle, RTC_FLAG_RTOFF));
}

rtc.h

c 复制代码
#ifndef __RTC_H__
#define __RTC_H__

#include "sys.h"
#include "time.h"

void rtc_init(void);
uint16_t rtc_read_bkp(uint8_t bkr);
void rtc_write_bkp(uint8_t bkr, uint16_t data);

void rtc_get_time(void);
void rtc_set_time(struct tm time_data);
    

#endif

main.c

c 复制代码
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "rtc.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();
    uart1_init(115200);
    rtc_init();
    printf("hello world! \r\n");
    
    if(rtc_read_bkp(1) != 0xA7A7)
    {
        rtc_write_bkp(1, 0xA7A7);
        printf("读出来的值:%X\r\n", rtc_read_bkp(1));

        struct tm time_data;
        time_data.tm_year = 2026;
        time_data.tm_mon = 7;
        time_data.tm_mday = 7;
        time_data.tm_hour = 9;
        time_data.tm_min = 42;
        time_data.tm_sec = 30;
        rtc_set_time(time_data);       
    }

    
    while(1)
    {
        rtc_get_time();
        delay_ms(1000);
    }
}
实验结果

但是按下复位键,还是从刚开始设置的值开始,思考如何按下复位键,时间不受影响?

解决:写之前判断一下,设置一次值,后面就不会改变。

c 复制代码
if(rtc_read_bkp(1) != 0xA7A7)
{
        rtc_write_bkp(1, 0xA7A7);
    printf("读出来的值:%X\r\n", rtc_read_bkp(1));

    struct tm time_data;
    time_data.tm_year = 2026;
    time_data.tm_mon = 7;
    time_data.tm_mday = 7;
    time_data.tm_hour = 9;
    time_data.tm_min = 42;
    time_data.tm_sec = 30;
    rtc_set_time(time_data);
}

为什么不是2024,而是2000,因为HAL库目前有bug,有需求再去解决。

6.2 实验2:RTC闹钟实验

在实验1基础上做RTC闹钟实验

实验目的

实现RTC闹钟功能

构思环节
c 复制代码
增加中断配置
HAL_NVIC_SetPriority(闹钟中断, 2, 2);
HAL_NVIC_EnableIRQ(闹钟中断);

闹钟中断服务函数
void RTC_Alarm_IRQHandler(void)
{
   HAL_RTC_AlarmIRQHandler
}

闹钟回调函数
printf("ring ring ring...");


// 设置闹钟
void rtc_set_alarm(struct tm alarm_data)
{
// 定义闹钟结构体
// 闹钟参数配置(闹钟选择、时、分、秒)
 // HAL库设置闹钟
}

main.c

c 复制代码
//设置闹钟
struct tm alarm_data;

// 设置闹钟的时分秒
alarm_data.tm_hour = 16; 
rtc_set_alarm(alarm_data);
c 复制代码
// 设置的闹钟会响
HAL_RTC_SetAlarm_IT(&hrtc_handle, &alarm, RTC_FORMAT_BIN);
部分代码展示

rtc.c

c 复制代码
// 设置Msp函数
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
    // 使能RTC
    __HAL_RCC_RTC_ENABLE();
    
    RCC_OscInitTypeDef osc_initstruct = {0};
    RCC_PeriphCLKInitTypeDef  periphclk_initstruct = {0};
    
    // 设置时钟源
    osc_initstruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;        // 振荡器
    osc_initstruct.LSEState = RCC_LSE_ON;                          // LSE状态
    osc_initstruct.PLL.PLLState = RCC_PLL_NONE;
    HAL_RCC_OscConfig(&osc_initstruct);
    
    periphclk_initstruct.PeriphClockSelection = RCC_PERIPHCLK_RTC ;  // 外设RTC:32.768
    periphclk_initstruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;   //时钟选择  
    HAL_RCCEx_PeriphCLKConfig(&periphclk_initstruct);
    
    // 中断配置
    HAL_NVIC_SetPriority(RTC_Alarm_IRQn, 2, 2);
    HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);

}
c 复制代码
// 闹钟中断函数
void RTC_Alarm_IRQHandler(void)
{
    HAL_RTC_AlarmIRQHandler(&hrtc_handle);
}

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    printf("ring ring ring...\r\n");
}
c 复制代码
//  设置闹钟
void rtc_alarm_time(struct tm alarm_data)
{
    RTC_AlarmTypeDef alarm = {0};

    alarm.Alarm = RTC_ALARM_A;
    alarm.AlarmTime.Hours = alarm_data.tm_hour;
    alarm.AlarmTime.Minutes = alarm_data.tm_min;
    alarm.AlarmTime.Seconds = alarm_data.tm_sec;
    HAL_RTC_SetAlarm_IT(&hrtc_handle, &alarm, RTC_FORMAT_BIN);
}

rtc.h

c 复制代码
#ifndef __RTC_H__
#define __RTC_H__

#include "sys.h"
#include "time.h"

void rtc_init(void);
uint16_t rtc_read_bkp(uint8_t bkr);
void rtc_write_bkp(uint8_t bkr, uint16_t data);

void rtc_get_time(void);
void rtc_set_time(struct tm time_data);

void rtc_alarm_time(struct tm alarm_data);

#endif

main.c

c 复制代码
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "rtc.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();
    uart1_init(115200);
    rtc_init();
    printf("hello world! \r\n");
    
    if(rtc_read_bkp(1) != 0xA7A7)
    {
        rtc_write_bkp(1, 0xA7A7);
        printf("读出来的值:%X\r\n", rtc_read_bkp(1));

        struct tm time_data, alarm_data;
        time_data.tm_year = 2024;
        time_data.tm_mon = 7;
        time_data.tm_mday = 1;
        time_data.tm_hour = 16;
        time_data.tm_min = 50;
        time_data.tm_sec = 30;
        rtc_set_time(time_data);


        // 设置闹钟的时分秒
        alarm_data.tm_hour = 16;
        alarm_data.tm_min = 50;
        alarm_data.tm_sec = 40;
        rtc_alarm_time(alarm_data);
    }

    while(1)
    {
        rtc_get_time();
        delay_ms(1000);
    }
}
实验结果
相关推荐
能摆一天是一天2 小时前
Spring ai vectorstore 使用本地模型导致只能匹配可行度为1.0的内容的解决方法笔记
java·笔记·spring
进阶的DW2 小时前
Wiki + Graph + RAG 知识库建设笔记2
笔记
AOwhisky2 小时前
Linux(CentOS)系统管理入门笔记(第四期)——文件系统(下篇):文件与目录操作实战——cpmvmkdirrmln
linux·运维·笔记·centos·云计算·文件系统
吠品2 小时前
Python字典键获取的四种实用方法
stm32·单片机·嵌入式硬件
bmy-happy2 小时前
网安专业课程笔记sale
笔记
网络与设备以及操作系统学习使用者3 小时前
通信的物理与逻辑双维度解析
学习·深度优先
浩瀚地学3 小时前
【Java基础复习】IO流(二)
java·开发语言·经验分享·笔记·学习
researcher-Jiang4 小时前
Manacher算法学习与应用
c++·学习·算法
追兮兮4 小时前
MCUQuickStart:一键生成 STM32 / GD32 的 Keil、CMake、RTOS 工程
stm32·单片机·freertos·gd32·gcc·工程模版