STM32F103单片机内部RTC实时时钟驱动程序
一、STM32f103系列RTC功能
RTC实时时钟功能是嵌入式软件开发中比较常用的功能,一般MCU的RTC功能都带有年月日时间寄存器,比如STM32F4xx系列,RTC描述如下:
可见F4系列的RTC功能比较强大,设置好初始时间后,读取各个寄存器就可以获取日期及时间。
但有一些芯片的RTC功能比较简单,比如在STM32F103系列的手册中,是这样描述的:

由上可知,STM32F103系列的RTC功能只有一个计数器,每1秒加1,没有年月日及时间寄存器,读取计数器的值后,需要使用软件计算出时间,如果32位的寄存器存储无符号整型数,则2^32 -1秒≈136.19年,最长可计时100多年,对大部分场景来说足够用了。当然,如果再加上后备寄存器配合使用,可计时更长的时间。
计数器每秒加1,这样产生的时间是从开始时刻以来经过的秒数,不得不让我们想到另一个知识——Unix时间戳。
Unix时间戳(Unix timestamp),或称Unix时间(Unix time)、POSIX时间(POSIX time),是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数,不考虑闰秒。Unix时间戳不仅被使用在Unix系统、类Unix系统中,也在许多其他操作系统中被广泛采用。
所以,我们可以在读出32位寄存器中的计数值时,当做Unix时间戳,然后通过软件算法,转换为标准时间,这样程序的通用性就较强了。
下面使用STM32F103ZET6(正点原子战舰开发板),STM32Cube MX配置,IAR开发环境,进行程序编写、试验测试。
二、STM32Cube MX配置
使用的开发板上,有外接备用电池以及32.768kHz的晶振,断电后时钟可以继续计时,因此RTC的时钟源要现在32.768kHz的,其他时钟根据需要自行配置,如下图:
接下来使能RTC功能,如下图:
可根据需要,使能或禁用RTC中断以及闹钟中断功能,这里我们不使能:

三、 主要代码
首先,需要思考整个程序的流程,因为MCU有后备寄存器,其中的值会在电池供电的时候一直保持,我们可以在寄存器里写入一些标志,来在程序运行时判断RTC是首次运行,还是一直有电池供电运行,时间在继续计时。如果后备寄存器里没有我们想要的标志,说明RTC是首次运行,这个时候我们应该对时间计数器重新初始化,将日期和时间转为时间戳,写入计数器;如果后备寄存器里的值正是我们之前写入过的标志,则说明RTC一直在供电持续运行,此时读出计数器的值,转化成日期及时间。
而把Unix时间戳转换为时间,则不得不需要知道一些历法的知识,因为Unix时间不考虑闰秒,则只需要考虑闰年。把读出的秒数,按照每年(考虑闰年、平年)有多少秒,每月有多少秒,每天有多少秒,每小时有多少秒,每分钟多少秒,一一减掉,则可得出日期和时间。
1.判断闰年、平年
1582年以来公历的置闰规则:
普通闰年:公历年份是4的倍数,且不是100的倍数的,为闰年(如2004年、2020年等就是闰年)。
世纪闰年:公历年份是整百数的,必须是400的倍数才是闰年(如1900年不是闰年,2000年是闰年)。
1582年以前的惯例:四年一闰;如果公元A年的A(正数)能被4整除,那么它就是闰年;如果公元前B年的B(正数)除以4余1,那么它也是闰年。(1582年是神奇的一年,有兴趣的可以搜索一下1582年10月,看看发生了什么事。)
根据上述规则可以写一个判断是否是闰年的函数。实际上,STM32Cube MX自动生成的HAL库文件,在stm32f1xx_hal_rtc.c中有一个函数:
/*** @brief Check whether the passed year is Leap or not.* @param nYear year to check* @retval 1: leap year* 0: not leap year*/
static uint8_t RTC_IsLeapYear(uint16_t nYear)
{if ((nYear % 4U) != 0U){return 0U;}if ((nYear % 100U) != 0U){return 1U;}if ((nYear % 400U) == 0U){return 1U;}else{return 0U;}
}
但这个函数是静态函数,头文件里没有,为了不对自动生成的文件做修改,我们可以自己写一个相同功能的函数(实际上可以完全复制自动生成的函数static uint8_t RTC_IsLeapYear(uint16_t nYear)放到另一个文件里,去掉static即可):
/******************************************************************************** 函数名:IsLeapYear* 功 能:判断是否是闰年* 参 数:无* 返回值:1闰年,0平年* 说 明:整百年被400整除是闰年,其他被4整除是闰年
*******************************************************************************/
bool IsLeapYear(uint16_t Year)
{bool temp = 0;if ((Year % 4) == 0)//被4整除{if ((Year % 100) == 0)//整百年{if ((Year % 400) == 0){temp = 1;}}else//非整百年,能被4整除是闰年{temp = 1;}}return temp;
}
2.Unix时间戳转为UTC时间
该过程,以1970年1月1日00:00:00为开始时间,把32位寄存器的值,转化成日历时间,笔者根据程序总结的流程如下:
① 先计算较简单的weekday,起始时间是周四;因为不管平年还是闰年,不管哪个月份,每一周都是7天,算出寄存器值总共有多少天,天数模7的余数,经过简单计算,就是当前的weekday;
② 计算年份;如果天数大于1年,则根据该年平年或闰年,减去相应天数,年数递增,继续判断剩余天数包含的年数,直至剩余天数不足一年,退出循环;
③ 计算月份和日期;步骤②最后剩余的天数,已不满1年,逐月减去相应的天数,月份递增,注意如果遇到闰年二月,要减去29天,直至剩余天数不足一个月,退出循环;剩余的天数+1为日期;
④ 计算时、分、秒;时间戳模86400的余数,为不足整天的秒数s,s/3600,为小时,(s%3600)/60为分钟,s%60为秒,这部分的计算比较好理解;
该部分代码如下(RTC_MONTH_XX以及RTC_WEEKDAY_XX的宏定义在stm32f1xx_hal_rtc.h中):
typedef struct
{uint8_t Hours;uint8_t Minutes;uint8_t Seconds;uint8_t WeekDay;uint8_t Month;uint8_t Date;uint16_t Year;
}RTC_ts;//平年每月的天数
const uint8_t u8DayNumTab[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
/******************************************************************************** 函数名:UnixToUTC* 功 能:Unix时间戳转为UTC时间* 参 数:u32TimeStamp:Unix时间戳* 返回值:UTC时间,RTC_ts结构体格式* 说 明:无
*******************************************************************************/
RTC_ts UnixToUTC(uint32_t u32TimeStamp)
{RTC_ts sTemp;sTemp.Year = 1970;sTemp.Month = RTC_MONTH_JANUARY;sTemp.Date = 1;sTemp.Hours = 0;sTemp.Minutes = 0;sTemp.Seconds = 0;sTemp.WeekDay = RTC_WEEKDAY_THURSDAY;uint32_t temp1 = 0;//天数uint32_t temp2 = 1970;//年份temp1 = u32TimeStamp / 86400;//计算出天数sTemp.WeekDay = (uint8_t)((temp1 % 7) + RTC_WEEKDAY_THURSDAY);//计算weekday,1970年1月1日为周四if (sTemp.WeekDay > RTC_WEEKDAY_SATURDAY){sTemp.WeekDay -= 7;}if (temp1 > 0){ while (temp1 >= 365)//天数还大于1年,减去一年的天数,剩余的天数继续判断{if (IsLeapYear(temp2) == 1)//闰年{if (temp1 >= 366){temp1 -= 366;temp2++;}else{break;//不足一年,跳出循环} }else//平年{temp1 -= 365;temp2++;}}sTemp.Year = (uint16_t)temp2;//年份temp2 = RTC_MONTH_JANUARY;//月份,从1月份开始while (temp1 >= 28)//去掉整年/整月,剩余的天数{if ((IsLeapYear(sTemp.Year) == 1) && (temp2 == RTC_MONTH_FEBRUARY))//当年是闰年且是二月{if (temp1 >= 29){temp1 -= 29;}else{break;}}else//平年{if (temp1 >= u8DayNumTab[temp2 - 1])//剩余天数比1个月大{temp1 -= u8DayNumTab[temp2 - 1];}else{break;}}temp2++;}sTemp.Month = (uint8_t)temp2;//月份sTemp.Date = (uint8_t)(temp1 + 1);//日期 }temp1 = (u32TimeStamp % 86400);//去掉整天,剩余的秒数sTemp.Hours = (uint8_t)(temp1 / 3600);//计算出小时数sTemp.Minutes = (uint8_t)((temp1 % 3600) / 60);//计算出分钟数sTemp.Seconds = (uint8_t)(temp1 % 60);//计算出秒数return sTemp;
}
3.UTC时间转为Unix时间戳
这一部分,与“2.Unix时间戳转为UTC时间”是相反的过程,将日期和时间,转换为1970-1-1 00:00:00以来的秒数,但这个过程要简单一些,流程如下:
① 计算整年的秒数;以1970年为起始年,逐年增加一年的秒数,直至UTC时间年的前一年,需要注意是平年还是闰年;
② 计算整月的秒数;逐月增加一个月的秒数,直至UTC时间月的前一个月,如果有闰月,需要多加1天;
③ 计算整天、整小时、整分钟的秒数,加上剩余的UTC时间秒的秒数,以上所有数值的和,即为Unix时间戳;
/******************************************************************************** 函数名:UTCToUnix* 功 能:UTC时间转为Unix时间戳* 参 数:UTC时间,RTC_ts结构体格式* 返回值:Unix时间戳* 说 明:标准UTC时间转为Unix时间戳,时间范围1970~2100年
*******************************************************************************/
uint32_t UTCToUnix(RTC_ts sTime)
{uint32_t u32TimeStamp = 0;uint16_t i;if ((sTime.Year < 1970) || (sTime.Year > 2100)){return 0;}for (i = 1970; i < sTime.Year; i++)//计算整年的秒数{if (IsLeapYear(i) == 1){u32TimeStamp += (86400 * 366);}else{u32TimeStamp += (86400 * 365);}}for (i = 0; i < (sTime.Month - 1); i++)//增加整月的秒数{u32TimeStamp += ((uint32_t)u8DayNumTab[i] * 86400);}if ((IsLeapYear(sTime.Year) == 1) && ((sTime.Month - 1) >= RTC_MONTH_FEBRUARY))//当年是闰年且月份超过2月{u32TimeStamp += 86400;//多加1天}u32TimeStamp += (((uint32_t)sTime.Date - 1) * 86400);//增加整天的秒数 u32TimeStamp += ((uint32_t)sTime.Hours * 3600);//增加小时的秒数u32TimeStamp += ((uint32_t)sTime.Minutes * 60);//增加分钟的秒数u32TimeStamp += (uint32_t)sTime.Seconds;//增加剩余秒数return u32TimeStamp;
}
4.时间计数器读写函数
有了以上的函数后,还需要对计数器进行读、写操作,才能计算出时间,或者将时间更新。在stm32f1xx_hal_rtc.c中,也已经有该功能的函数,但不幸的是,这些函数仍然是静态函数,无法调用,只能自己在别处再写一个。不明白这么重要的函数,为什么不放到头文件里。我们把需要的函数复制过来,改个名字:
/******************************************************************************** 函数名:Drv_RTC_EnterInitMode* 功 能:进入初始化模式* 参 数:RTC_HandleTypeDef结构体指针* 返回值:HAL Status* 说 明:stm32f1xx_hal_rtc.c中有相似static函数
*******************************************************************************/
static HAL_StatusTypeDef Drv_RTC_EnterInitMode(RTC_HandleTypeDef *hrtc)
{uint32_t tickstart = 0U;tickstart = HAL_GetTick();/* Wait till RTC is in INIT state and if Time out is reached exit */while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET){if ((HAL_GetTick() - tickstart) > RTC_TIMEOUT_VALUE){return HAL_TIMEOUT;}}/* Disable the write protection for RTC registers */__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);return HAL_OK;
}
/******************************************************************************** 函数名:Drv_RTC_ExitInitMode* 功 能:退出初始化模式* 参 数:RTC_HandleTypeDef结构体指针* 返回值:HAL Status* 说 明:stm32f1xx_hal_rtc.c中有相似static函数
*******************************************************************************/
static HAL_StatusTypeDef Drv_RTC_ExitInitMode(RTC_HandleTypeDef *hrtc)
{uint32_t tickstart = 0U;/* Disable the write protection for RTC registers */__HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);tickstart = HAL_GetTick();/* Wait till RTC is in INIT state and if Time out is reached exit */while ((hrtc->Instance->CRL & RTC_CRL_RTOFF) == (uint32_t)RESET){if ((HAL_GetTick() - tickstart) > RTC_TIMEOUT_VALUE){return HAL_TIMEOUT;}}return HAL_OK;
}
/******************************************************************************** 函数名:Drv_RTC_ReadTimeCounter* 功 能:读取RTC计数器的值* 参 数:RTC_HandleTypeDef结构体指针* 返回值:计数器的值* 说 明:stm32f1xx_hal_rtc.c中有相似static函数
*******************************************************************************/
uint32_t Drv_RTC_ReadTimeCounter(RTC_HandleTypeDef *hrtc)
{uint16_t high1 = 0U, high2 = 0U, low = 0U;uint32_t timecounter = 0U;high1 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);low = READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT);high2 = READ_REG(hrtc->Instance->CNTH & RTC_CNTH_RTC_CNT);if (high1 != high2){/* In this case the counter roll over during reading of CNTL and CNTH registers,read again CNTL register then return the counter value */timecounter = (((uint32_t) high2 << 16U) | READ_REG(hrtc->Instance->CNTL & RTC_CNTL_RTC_CNT));}else{/* No counter roll over during reading of CNTL and CNTH registers, countervalue is equal to first value of CNTL and CNTH */timecounter = (((uint32_t) high1 << 16U) | low);}return timecounter;
}
/******************************************************************************** 函数名:Drv_RTC_WriteTimeCounter* 功 能:写入RTC计数器的值* 参 数:hrtc:RTC_HandleTypeDef结构体指针TimeCounter:要写入的值* 返回值:HAL Status* 说 明:stm32f1xx_hal_rtc.c中有相似static函数
*******************************************************************************/
HAL_StatusTypeDef Drv_RTC_WriteTimeCounter(RTC_HandleTypeDef *hrtc, uint32_t TimeCounter)
{HAL_StatusTypeDef status = HAL_OK;/* Set Initialization mode */if (Drv_RTC_EnterInitMode(hrtc) != HAL_OK){status = HAL_ERROR;}else{/* Set RTC COUNTER MSB word */WRITE_REG(hrtc->Instance->CNTH, (TimeCounter >> 16U));/* Set RTC COUNTER LSB word */WRITE_REG(hrtc->Instance->CNTL, (TimeCounter & RTC_CNTL_RTC_CNT));/* Wait for synchro */if (Drv_RTC_ExitInitMode(hrtc) != HAL_OK){status = HAL_ERROR;}}return status;
}
/******************************************************************************** 函数名:Drv_RTC_SetTime* 功 能:设置时间* 参 数:RTC_ts时间结构体* 返回值:无* 说 明:将时间转为时间戳,写入寄存器
*******************************************************************************/
void Drv_RTC_SetTime(RTC_ts sTime)
{//Drv_RTC_WriteTimeCounter(&hrtc, UTC8ToUnix(sTime));Drv_RTC_WriteTimeCounter(&hrtc, UTCToUnix(sTime));
}
/******************************************************************************** 函数名:Drv_RTC_GetTime* 功 能:获取时间* 参 数:无* 返回值:无* 说 明:每隔较短查询RTC模块获取一次
*******************************************************************************/
void Drv_RTC_GetTime(void)
{uint32_t u32Cnt = 0;u32Cnt = Drv_RTC_ReadTimeCounter(&hrtc);sTime = UnixToUTC(u32Cnt);
}
5.
首次上电时,初始化RTC模块(STM32CubeMx已自动生成该部分代码),读取后备寄存器的值,如果值不正确,则是首次配置,则初始化时间;如果值正确,则直接读取寄存器的值,将值转换为时间:
static RTC_ts sTime;//时间结构体变量
/******************************************************************************** 函数名:Drv_RTC_Init* 功 能:初始化* 参 数:无* 返回值:无* 说 明:无
*******************************************************************************/
void Drv_RTC_Init(void)
{uint16_t u16Backup = 0;RTC_ts sDefaultTime;//初始时间,可根据需要设定memset(&sTime, 0 , sizeof(sTime));u16Backup = HAL_RTCEx_BKUPRead(&hrtc, RTC_BACKUP_REG);//读后备寄存器if (u16Backup != RTC_BACKUP_DATA)//检查备份寄存器,不对则是首次配置,初始化时间{sDefaultTime.Hours = 12;//初始时间,可根据需要设定sDefaultTime.Minutes = 0;//初始时间,可根据需要设定sDefaultTime.Seconds = 0;//初始时间,可根据需要设定sDefaultTime.WeekDay = RTC_WEEKDAY_SATURDAY;//初始时间,可根据需要设定sDefaultTime.Month = RTC_MONTH_MAY;//初始时间,可根据需要设定sDefaultTime.Date = 20;//初始时间,可根据需要设定sDefaultTime.Year = 2023;//初始时间,可根据需要设定Drv_RTC_SetTime(sDefaultTime);//设置为默认起始时间HAL_PWR_EnableBkUpAccess();//启用对备份寄存器的写访问HAL_RTCEx_BKUPWrite(&hrtc, RTC_BACKUP_REG, RTC_BACKUP_DATA);HAL_PWR_DisableBkUpAccess();//关闭对备份寄存器的写访问}else//寄存器数值正确,读取寄存器,转换为时间{Drv_RTC_GetTime();}
}
在需要的时候,调用Drv_RTC_GetTime()函数,即可获得时间sTime。
四、试验测试效果
以1970年1月1日的某个时刻为例,如下图,算法输出了日期、时间、周几,最后一个数字为TimeCounter中的值,

找一个Uinx时间戳在线转换的网站,验证一下红框中的时间和TimeCounter中的值,完全正确:

有兴趣的可以继续验证平年、闰年,以及年月日切换是否正确。
五、总结
- STM32F103系列的RTC模块,没有年月日及时间寄存器,只有一个32位计数器,每1秒加1,没有年月日及时间寄存器,需要软件配合,才能实现日历、时钟功能;
- 由于只有计数功能,可以任意时间作为基准时间(即开始时间),用UTC时间戳(以1970年1月1日00:00:00为开始时间),可以使程序通用性更强;
- 以上UTCToUnix和UnixToUTC两个函数是以标准UTC时间为基础的,实际北京时间为UTC+8,相差8个小时,如果需要计算北京时间,需要加8个小时;
水平有限,以上如有疏漏之处,欢迎指正。
相关文章:
STM32F103单片机内部RTC实时时钟驱动程序
一、STM32f103系列RTC功能 RTC实时时钟功能是嵌入式软件开发中比较常用的功能,一般MCU的RTC功能都带有年月日时间寄存器,比如STM32F4xx系列,RTC描述如下: 可见F4系列的RTC功能比较强大,设置好初始时间后,读…...
ChinaSoft 论坛巡礼 | 开源软件生态健康度量论坛
2023年CCF中国软件大会(CCF ChinaSoft 2023)由CCF主办,CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办,将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…...
Leetcode.2698 求一个整数的惩罚数
题目链接 Leetcode.2698 求一个整数的惩罚数 rating : 1679 题目描述 给你一个正整数 n n n ,请你返回 n n n 的 惩罚数 。 n n n 的 惩罚数 定义为所有满足以下条件 i i i 的数的平方和: 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n i ∗ i i * i i∗i 的…...
大数据Flink(一百零二):SQL 聚合函数(Aggregate Function)
文章目录 SQL 聚合函数(Aggregate Function) SQL 聚合函数(Aggregate Function) Python UDAF,即 Python AggregateFunction。Python UDAF 用来针对一组数据进行聚合运算,比如同一个 window 下的多条数据、或者同一个 key 下的多条数据等。针对同一组输入数据,Python A…...
因mapjoin加载内存溢出而导致return code 3
因mapjoin加载内存溢出而导致return code 3 问题描述:日志定位: 问题描述: 例行Hive作业报错 日志定位: Starting to launch local task to process map join; maximum memory 5172101120 [2023-10-16 07:56:51,530] - INFO:…...
pip 指定源
pip定源 # 指定豆瓣 python -m pip install transformers -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com参考 出现错误:Looking in indexes:https://pypi.tuna.tsinghua.edu.cn/simple...
嵌入式中的MCU、ARM、DSP、FPGA
目录 “角色扮演” MCU ARM 特点 DSP 特点 FPGA 特点 应用 “角色扮演” MCU(Microcontroller Unit)、ARM(Advanced RISC Machine)、DSP(Digital Signal Processor)和FPGA(Field-Progr…...
二、PHP基础学习[变量]
部分内容引用自:https://blog.csdn.net/lady_killer9/article/details/108978062 一、PHP基础学习 1.语法与注释 示例: <?php // PHP 代码/* 这是 PHP 多行 注释 */ ?>2.输出 示例:echo 123; 3.变量 规矩: 变量以 …...
k8s kubeadm配置
master 192.168.41.30 docker、kubeadm、kubelet、kubectl、flannel node01 192.168.41.31 docker、kubeadm、kubelet、kubectl、flannel node02 192.168.41.32 do…...
B-3:Web安全之综合渗透测试
B-3:Web安全之综合渗透测试 任务环境说明: 服务器场景:Server2104(关闭链接) 服务器场景用户名、密码:未知 1.通过URL访问http://靶机IP/1,对该页面进行渗透测试,将完成后返回的结果内容作为FLAG值提交; 通过访问IP/1,查看源代码发现flagishere,访问后发现什么也没…...
设计模式—设计模式总览
设计模式—设计模式总览 在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 《Design Patterns - Elements of Reusable Object-Oriented Software》(中文译名:《设计模式 - 可复用的面向对…...
C++ 流程控制(分支、循环、跳转)
#include<iostream>using namespace std;int main() {// 单分支和双分支cout << "please enter your age:" << endl;int age;cin >> age;if(age > 18){cout << "welcome! adult." << endl;}else{cout << &qu…...
【网络协议】聊聊TCP的三挥四握
上一篇我们说了网络其实是不稳定的,TCP和UDP其实是两个不同的对立者,所以TCP为了保证数据在网络中传输的可靠性,从丢包、乱序、重传、拥塞等场景有自己的一套打法。 TCP格式 源端口和目标端口是不可缺少的,用以区分到达发送给拿…...
Docker镜像仓库
Docker镜像仓库 一、Docker镜像的创建1.1、基于已有镜像创建1.2、基于本地模板创建1.3、基于Dockerfile创建(使用最广泛)1.3.1、联合文件系统(UnionFS)1.3.2、镜像加载原理1.3.3、Dockerfile1.3.4、Docker 镜像结构的分层 二、如何…...
跨界技术:SOCKS5代理在电商、爬虫与游戏领域的应用
随着技术的日益发展,各种工具和技术手段被广泛应用于不同的领域。其中,SOCKS5代理、跨界电商、爬虫技术、出海策略以及游戏产业都成为了当下最热门的话题。本文将探讨这些关键技术如何相互融合,为企业和个人带来更多的机会和挑战。 1. SOCKS…...
LeetCode--快速排序
文章目录 1 排序原理2 代码实现 1 排序原理 quickSort(int[] arr, int left, int right) 参数描述 arr: 待排序的数组left: 排序的左边位置right: 排序的右边位置 排序步骤: 先选取左边节点的数据作为 pivot从右边开始, 向左遍历节点数据, 在满足right > left 条件前提下…...
2023年CSP-S赛后总结(2023CSP-S题解)
目录 T1 题目描述 输入格式 输出格式 代码 T2 题目描述 输入格式 输出格式 题目描述 输入格式 输出格式 题意翻译 代码 T3 题目背景 题目描述 输入格式 输出格式 代码 T4 题目描述 输入格式 输出格式 总结 T1 题目描述 小 Y 有一把五个拨圈的密码锁。…...
Django viewsets 视图集与 router 路由实现评论接口开发
正常来说遵循restful风格编写接口,定义一个类包含了 get post delete put 四种请求方式,这四种请求方式是不能重复的 例如:获取单条记录和多条记录使用的方式都是get,如果两个都要实现的话那么得定义两个类,因为在同一个类中不能有…...
RCE 远程代码执行漏洞分析
RCE 漏洞 1.漏洞描述 Remote Command/Code Execute 远程命令执行/远程代码执行漏洞 这种漏洞通常出现在应用程序或操作系统中,攻击者可以通过利用漏洞注入恶意代码,并在受攻击的系统上执行任意命令。 2.漏洞场景 PHP 代码执行PHP 代码注入OS 命令执…...
JDK8新特性:Stream流
目录 1.获取Stream流 2.Stream流常见的中间方法 3.Stream流常见的终结方法 1、 Stream 是什么?有什么作用?结合了什么技术? ●也叫 Stream 流,是Jdk8开始新增的一套 API ( java . util . stream .*),可以用于操作集…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
