STM32F103单片机内部RTC实时时钟驱动程序

news2024/11/17 1:44:08

一、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, counter
		   value 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中的值,完全正确:
在这里插入图片描述
有兴趣的可以继续验证平年、闰年,以及年月日切换是否正确。

五、总结

  1. STM32F103系列的RTC模块,没有年月日及时间寄存器,只有一个32位计数器,每1秒加1,没有年月日及时间寄存器,需要软件配合,才能实现日历、时钟功能;
  2. 由于只有计数功能,可以任意时间作为基准时间(即开始时间),用UTC时间戳(以1970年1月1日00:00:00为开始时间),可以使程序通用性更强;
  3. 以上UTCToUnix和UnixToUTC两个函数是以标准UTC时间为基础的,实际北京时间为UTC+8,相差8个小时,如果需要计算北京时间,需要加8个小时;

水平有限,以上如有疏漏之处,欢迎指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1130198.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Power BI 傻瓜入门 8. 制作数据模型

本章内容包含&#xff1a; 描述不同的数据建模技术配置属性以满足数据模型要求设计模型以满足性能要求 您可能认为&#xff0c;通过Power BI对数据进行转换后&#xff0c;您将一帆风顺。在某些情况下&#xff0c;这是正确的。当然&#xff0c;当您创建了一个包含许多表的详细…

OpenCV 笔记(3):基本图形的绘制

Part11. 绘制简单的图形 绘图功能是 OpenCV 最基础的功能&#xff0c;OpenCV 提供了基础的绘制函数&#xff0c;用于帮助我们绘制一些基本的图形。通过这些函数的组合&#xff0c;我们也可以做一些高级的应用。 11.1 绘制点和圆 OpenCV 的绘制函数相对简单&#xff0c;而且很多…

[Unity]将所有 TGA、TIFF、PSD 和 BMP(可自定义)纹理转换为 PNG,以减小项目大小,而不会在 Unity 中造成任何质量损失

如何使用 只需在“项目”窗口中创建一个名为“编辑器”的文件夹&#xff0c;然后在其中添加此脚本即可。然后&#xff0c;打开窗口-Convert Textures to PNG&#xff0c;配置参数并点击“Convert to PNG&#xff01; ”。 就我而言&#xff0c;它已将某些 3D 资源的总文件大小…

C语言汇总

汇总一&#xff08;linux环境&#xff09; /bin &#xff1a;bin是二进制&#xff08;binary&#xff09;英文缩写。 /boot&#xff1a;存放的都是系统启动时要用到的程序。 /dev&#xff1a;包含了所有Linux系统中使用的外部设备。 /etc&#xff1a;存放了系统管理时要用到的…

uniapp中 background-image 设置背景图片不展示问题

有问题 <view class"file-picker__box jsz" tap"jszxszUpload(jsz)"></view>.jsz {background-image: url(../../static/example_drive.png); }解决1 <view class"file-picker__box jsz" :style"{ background-image: url(…

Android APP 隐藏系统软键盘的方法

1.场景描述&#xff1a; 1) APP项目中经常会开发自定义软键盘&#xff1b;同时在使用EditText时&#xff0c;也会常常遇到自动弹出系统自带的软键盘&#xff0c;与自定义的软键盘产生冲突的情况&#xff1b;此时需要禁止EditText自动弹出系统软键盘&#xff0c;从而使自定义的…

汽车电子专有名词与相应技术

1.EEA &#xff08;Electronic & Electrical Architecture 电子电气架构&#xff09; EEA在宏观上概括为物理架构与逻辑架构的结合&#xff0c;微观上通过众多电子元器件的协同配合&#xff0c;或集成式或分布式的系统级电子电气架构&#xff0c;具体详见专栏 新能源汽车电…

volatile 关键字有什么用?它的实现原理是什么?

volatile volatile是Java中的一个关键字&#xff0c;用于修饰变量&#xff0c;表示该变量是“易变的”&#xff08;Volatile&#xff09;。 volatile 关键字有两个作用&#xff1a; 可以保证在多线程环境下共享变量的可见性。 通过增加内存屏障防止多个指令之间的重排序。 可见…

【图结构从入门到应用】图的表示和遍历,图搜索算法详解与示例

1图的概念 图是一种非常常见的数据结构&#xff0c;用于表示对象之间的关系。在计算机科学中&#xff0c;有许多不同的图类型&#xff0c;包括有向图&#xff08;Directed Graph&#xff09;和无向图&#xff08;Undirected Graph&#xff09;。图通常由节点&#xff08;顶点&a…

vscode json文件添加注释报错

在vscode中创建json文件&#xff0c;想要注释一波时&#xff0c;发现报了个错&#xff1a;Comments are not permitted in JSON. (521)&#xff0c;意思是JSON中不允许注释 以下为解决方法&#xff1a; 在vscode的右下角中找到这个&#xff0c;点击 在出现的弹窗中输入json wit…

Python 自动化(十五)请求和响应

准备工作 将不同day下的代码分目录管理&#xff0c;方便后续复习查阅 (testenv) [rootlocalhost projects]# ls mysite1 (testenv) [rootlocalhost projects]# mkdir day01 day02 (testenv) [rootlocalhost projects]# cp -rf mysite1/ day01/ (testenv) [rootlocalhost proj…

vue路径中“@/“代表什么

举例&#xff1a; <img src"/../static/imgNew/adv/tupian.jpg"/>其中&#xff0c;/是webpack设置的路径别名&#xff0c;代表什么路径&#xff0c;要看webpack的build文件夹下webpack.base.conf.js里面对于是如何配置&#xff1a; 上图中代表src,上述代码就…

KDChart3.0编译过程-使用QT5.15及QT6.x编译

文章目录 参考原文一、下载KDChart源文件二、下载安装CMake三、编译Qt5.15.0 编译Qt6.x 编译使用Qt6.X编译的直接看这最快 四、使用测试方法一&#xff1a;测试方法二&#xff1a; 参考原文 记录我的KDChart3.0编译过程 系统&#xff1a;win11&#xff0c;Qt5.15 &#xff0c;编…

Android View拖拽/拖放DragAndDrop自定义View.DragShadowBuilder,Kotlin(2)

Android View拖拽/拖放DragAndDrop自定义View.DragShadowBuilder&#xff0c;Kotlin&#xff08;2&#xff09; import android.graphics.Canvas import android.graphics.Point import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.util…

关于前端如何下载后端接口返回content-type为application/octet-stream的文件

关于前端如何下载后端接口返回response-type为application/octet-stream的文件 问题描述 后端接口定义为直接返回一个文件&#xff0c;如果带认证信息可以直接通过浏览器url下载&#xff0c;但是接口需要传headers认证信息&#xff0c;url上又不支持传相关信息 解决 前端…

如何用 JMeter 编写性能测试脚本?

Apache JMeter 应该是应用最广泛的性能测试工具。怎么用 JMeter 编写性能测试脚本&#xff1f; 1. 编写 HTTP 性能测试脚本 STEP 1. 添加 HTTP 请求 img STEP 2. 了解配置信息 HTTP 请求各项信息说明&#xff08;以 JMeter 5.1 为例&#xff09;。 如下图所示&#xff1a;…

kibana监控

采取方式 Elastic Agent &#xff1a;更完善的功能 Metricbeat&#xff1a;轻量级指标收集&#xff08;采用&#xff09; 传统收集方法&#xff1a;使用内部导出器收集指标&#xff0c;已不建议 安装 metricbeat Download Metricbeat • Ship Metrics to Elasticsearch | E…

硬件安全与机器学习的结合

文章目录 1. A HT Detection and Diagnosis Method for Gate-level Netlists based on Machine Learning摘要Introduction 2. 基于多维结构特征的硬件木马检测技术摘要Instruction 3. A Hardware Trojan Detection and Diagnosis Method for Gate-Level Netlists Based on Diff…

第一章 系统工程概述|系统建模语言SysML实用指南学习

仅供个人学习记录 系统工程起因 期望当今系统能力较之前有显著提升。 竞争压力要求系统提升技术先进性&#xff1a;提高性能&#xff0c;同时降低成本及缩短交付周期 能力增长驱动需求增长&#xff0c;包括功能、互操作性、性能、可靠性提升与小型化等。 系统不再是孤立的&…

【软考系统架构设计师】2022年系统架构师综合知识真题及解析

本篇文章主要讲解2022年系统架构师综合知识真题及解析 【01】云计算服务体系结构如下图所示&#xff0c;图中①、②、③分别与SaaS、PaaS、Iaas相对应&#xff0c;图中①、②、③应为( )。 解析&#xff1a;答案选择B 从上到下&#xff0c;依次是应用层——平台层——基础设施…