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 .*),可以用于操作集…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
