江协科技STM32学习笔记(第11章 RTC实时时钟)

news2024/12/27 2:02:01

第11章 RTC实时时钟

实时时钟本质上是一个定时器,但是这个定时器是专门用来产生年月日时分秒,这种日期和时间信息的。学会了RTC实时时钟,就可以在STM32内部拥有一个独立运行的钟表。想要记录或读取日期和时间,就可以通过操作RTC来实现。RTC这个外设比较特殊,它和备份寄存器BKP、电源控制PWR、这两章关联性比较强,在RTC这一章,BKP和PWR会经常来串门。

11.1 Unix时间戳

11.1.1 Unix时间戳

Unix 时间戳(Unix Timestamp)定义为从UTC/GMT197011000秒开始所经过的秒数,不考虑闰秒;

时间戳存储在一个秒计数器中,秒计数器为32/64位的整型变量;

世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间。

11.1.2 UTC/GMT 

GMT(Greenwich Mean Time)格林尼治标准时间是一种以地球自转为基础的时间计量系统。它将地球自转一周的时间间隔等分为24小时,以此确定计时标准;

GMT是以前的时间标准,这是因为GMT有一个棘手的问题,就是地球自转一周的时间,其实不是固定的,由于潮汐力、地球活动等原因,地球目前是越来越慢的,这时再根据一天的时间来定义时间基准,这个时间基准就是在不断变化的。

UTC(Universal Time Coordinated)协调世界时是一种以原子钟为基础的时间计量系统。它规定铯133原子基态的两个超精细能级间在零磁场下跃迁辐射9,192,631,770周所持续的时间为1秒。当原子钟计时一天的时间与地球自转一周的时间相差超过0.9秒时,UTC会执行闰秒来保证其计时与地球自转的协调一致.

11.1.3 时间戳转换

C 标准库 – | 菜鸟教程 (runoob.com)icon-default.png?t=N7T8https://www.runoob.com/cprogramming/c-standard-library-time-h.html

C语言的time.h模块提供了时间获取和时间戳转换的相关函数,可以方便地进行秒计数器、日期时间和字符串之间的转换。

函数

作用

time_t time(time_t*);

获取系统时钟

struct tm* gmtime(const time_t*);

秒计数器转换为日期时间(格林尼治时间

struct tm* localtime(const time_t*);

秒计数器转换为日期时间(当地时间)

time_t mktime(struct tm*);

日期时间转换为秒计数器(当地时间

char* ctime(const time_t*);

秒计数器转换为字符串(默认格式)

char* asctime(const struct tm*);

日期时间转换为字符串(默认格式)

size_t strftime(char*, size_t, const char*, const struct tm*);

日期时间转换为字符串(自定义格式)

11.2 BKP备份寄存器和RTC实时时钟 

11.2.1 BKP备份寄存器

11.2.1.1 BKP简介

BKP(Backup Registers)备份寄存器;

BKP可用于存储用户应用程序数据。当VDD2.0~3.6V)电源被切断,他们仍然由VBAT1.8~3.6V)维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位;

VBAT(V Battery):备用电池电源;

上图中VSS_i和VDD_i(i=1~3)是数字部分电路的供电, VSSA和VDDA是内部模拟部分电路的供电。这四组以VDD开头的供电,都是系统的主电源。在正常使用STM32时,这四组供电,全部都需要接到3.3V的电源上。

VBAT:就是备用电池供电引脚,如果要使用STM32内部的BKP和RTC实时时钟,这个引脚就必须接备用电池,用来维持BKP和RTC,在VDD主电源掉电后的供电。这里备用电池只有一根正极的供电引脚,接电池时,电池正极接到VBAT,电池负极和主电源的负极接在一起,共地就行了。如果VDD断电,VBAT也没电,那BKP里的数据就会清零,因为BKP本质上就是RAM存储器,没有掉电不丢失的能力。

TAMPER引脚产生的侵入事件将所有备份寄存器内容清除;

TAMPER是一个接到STM32外部的引脚,是一个安全保障设计,比如做一个安全系数非常高的设备,设备需要有防拆功能,然后BKP里也存储了一些敏感数据,这些数据不能被别人窃取或篡改,那就可以使用这个TAMPER引脚的侵入检测功能。设计电路时,TAMPER引脚可以先加一个默认的上拉或下拉电阻,然后引一根线,到设备外壳的防拆开关或触点,别人一拆开设备,触发开关,就会在TAMPER引脚产生上升沿或者下降沿,这样STM32就检测到侵入事件了,这时BKP的数据就会自动清零,并且申请中断,在中断里,还可以继续保护设备,比如清除其它存储器数据,然后设备锁死,这样来保证设备的安全。另外,主电源断电后,侵入检测任然有效,这样即使设备关机,也能防拆,这就是TAMPER侵入检测的功能。

RTC引脚输出RTC校准时钟、RTC闹钟脉冲或者秒脉冲;

存储RTC时钟校准寄存器;

用户数据存储容量:

20字节(中容量和小容量)/ 84字节(大容量和互联型)。

我们使用的芯片BKP是20字节,BKP一般只能用来存储少量的参数。

11.2.1.2 BKP基本结构

图中橙色部分我们可以叫做后备区域, BKP处于后备区域,但后备区域不止有BKP、还有RTC的相关电路,也位于后备区域,STM32后备区域的特性就是,当VDD主电源掉电时,后备区域仍然可以由VBAT的备用电池供电,当VDD主电源上电时,后备区域供电会由VBAT切换到VDD,也即是主电源有电时,VBAT不会用到,这样可以节省电池电量。BKP是位于后备区域的,BKP主要有数据寄存器、控制寄存器、状态寄存器和RTC实时时钟校准寄存器这些东西。其中数据寄存器是主要部分,用来存储数据的,每个数据寄存器都是16位的,也就是,一个数据寄存器可以存2个字节,那对于中容量和小容量的设备,里面有DR1、DR2,一直到DR10,总共10个数据寄存器。那一个寄存器存2个字节,所以容量是20个字节。对于大容量和互联型设备,里面除了DR1到DR10,还有DR11到DR12,一直到DR42,总共42个数据寄存器,容量是84个字节。

侵入检测,可以从PC13位置的TAMPER引脚引入一个检测信号,当TAMPER产生上升沿或下降沿时,清除BKP所有的内容,以保证安全。

时钟输出可以把RTC的相关时钟,从PC13位置的RTC引脚输出出去,供外部使用,其中输出校准时钟时,再配合校准寄存器,可以对RTC的误差进行校准。

11.2.2 RTC实时时钟

11.2.2.1 RTC简介

RTC(Real Time Clock)实时时钟;

RTC是一个独立的定时器,可为系统提供时钟和日历的功能;

RTC实时时钟,一般就指提供年月日时分秒这种日期时间信息的计时装置。在51单片机时有DS1302这个芯片,DS1302是外置的RTC芯片,这个芯片可以独立计时,我们需要设置时间或读取时间,就通过通信协议向它发送或接收数据来完成。在我们STM32内部,有这个RTC的外设,所以STM32可以在内部直接实现RTC的功能,这样就不用外挂RTC芯片了,当然RTC芯片所必要的元件,比如备用电池、RTC晶振这些东西就要接到STM32上了。

RTC和时钟配置系统处于后备区域,系统复位时数据不清零,VDD2.0~3.6V)断电后可借助VBAT1.8~3.6V)供电继续走时;

为了保持时钟能一直连续运行不出错,在主电源断电后,RTC走时肯定不能停下来,在系统复位时,RTC时间值肯定也不能复位。为了实现这些功能,VBAT接上备用电池就是必须的了。主电源断电后,VBAT的电池可以继续维持BKP和RTC的运行。

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

这个32位可编程计数器就是对应的是时间戳里的秒计数器,在读取时间时,我们先得到这个秒数,然后使用time.h模块里的localtime函数,就能立刻知道年月日时分秒的信息了。在写入时间时,我们先填充年月日时分秒信息到struct tm结构体,然后用mktime函数,得到秒数,再先写入到32位计数器即可。这样,操作这个秒计数器的思路就不是很清晰了。得益于时间戳的设计,这个硬件电路就得到了极大的简化,要想实现年月日时分秒的计时,只需要一个32位的秒计数器即可。

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

32位的秒计数器,1秒需要自增一次,所以这个地方驱动计数器的时钟,需要是一个1Hz的信号,但是实际提供给RTC模块的时钟,也就是RTCCLK,一般频率都比较高,所以,显然,我们需要在这之间,加一个分频器,给RTCCLK降一下频率,保证分频器输出给计数器的频率位1Hz。为了适配各种频率的RTCCLK,这里就加了一个20位的分频器,可以选择对输入时钟进行1~2^20这么大范围的分频,这样就可以适配不同频率的输入时钟。

可选择三种RTC时钟源:

HSE时钟除以128(通常为8MHz/128

LSE振荡器时钟(通常为32.768KHz

LSI振荡器时钟(40KHz

这三个时钟可以选择其中一个接入到RTCCLK。

高速时钟,一般供内部程序运行和主要外设使用, 低速时钟,一般供RTC、看门狗这些东西使用。我们最常用的是LSE OSC这一路外部32.768KHz的晶振,提供RTCCLK的时钟。第一个原因就是,中间这一路32.768KHz的晶振,本身就是专供RTC使用的,上面这两路其实是有各自的任务,上面这一路,主要作为系统主时钟,下面这一路主要作为看门狗时钟。它们只是顺带备选当作RTC的时钟。另外是只有这一路的时钟,可以通过VBAT备用电池供电,上下两路时钟,在主电源断电后,是停止运行的。所以要想实现RTC主电源掉电继续走时的功能,必须得选择中间这一路的RTC专用时钟。如果选择上下两路时钟,主电源断电后,时=时钟就暂停了,这样显然会出错。

11.2.2.2 RTC框图

11.2.2.3 RTC基本结构

最左边是RTCCLK时钟来源,这一块需要在RCC里配置, 3个时钟,选择一个当作RTCCLK,之后RTCCLK通过预分频器,对时钟进行分频。余数寄存器是一个自减计数器,存储当前的计数值,重装寄存器是计数目标,决定分频值,分频之后得到1Hz的秒计数信号,通向32位计数器,1秒自增1次,下面还有一个32位的闹钟值,可以设定闹钟,如果不需要的话,下面可以不用管。右边有三个信号可以触发中断,分别是秒信号,计数器溢出信号和闹钟信号,三个信号先通过中断输出控制,进行中断使能,使能的中断才能通向NVIC,然后向CPU申请中断。在程序中,我们可以配置数据选择器选择时钟来源,配置重装寄存器,可以选择分频系数,配置32位计数器,可以进行日期时间的读写。需要闹钟的话,配置32位闹钟值即可,需要中断的话,先允许中断,再配置NVIC。最后写对应的中断函数即可。

11.2.2.4 硬件电路

在最小电路上,外部电路还要再额外加两部分,第一部分就是备用电池供电, 第二部分就是外部低速晶振。

11.2.2.5 RTC操作注意事项 

执行以下操作将使能对BKPRTC的访问:

        设置RCC_APB1ENRPWRENBKPEN,使能PWRBKP时钟

        设置PWR_CRDBP,使能对BKPRTC的访问

若在读取RTC寄存器时,RTCAPB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1;

必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRLRTC_CNTRTC_ALR寄存器;

对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器。

11.3 读写备份寄存器

11.3.1 硬件电路

11.3.2 软件部分

(1)复制《OLED显示屏》并改为《读写备份寄存器》

(2)BKP库函数

void BKP_DeInit(void);             //恢复缺省配置,手动清空BKP所有的数据寄存器
void BKP_TamperPinLevelConfig(uint16_t BKP_TamperPinLevel);    //用于配置TAMPER侵入检测功能,高电平还是低电平触发
void BKP_TamperPinCmd(FunctionalState NewState);               //是否开启侵入检测功能
void BKP_ITConfig(FunctionalState NewState);                   //中断配置,是否开启中断
void BKP_RTCOutputConfig(uint16_t BKP_RTCOutputSource);        //时钟输出功能配置,可以选择在RTC引脚上输出时钟信号,输出RTC校准时钟、RTC闹钟脉冲或者秒脉冲
void BKP_SetRTCCalibrationValue(uint8_t CalibrationValue);     //设置RTC校准值,其实就是写入RTC校准寄存器
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);  //写备份寄存器,第一参数指定卸载哪个DR里,第二个参数指定要写入的数据
uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);              //读备份寄存器
FlagStatus BKP_GetFlagStatus(void);
void BKP_ClearFlag(void);
ITStatus BKP_GetITStatus(void);
void BKP_ClearITPendingBit(void);

(3) PWR库函数

void PWR_DeInit(void);
void PWR_BackupAccessCmd(FunctionalState NewState);         // 备份寄存器访问使能
void PWR_PVDCmd(FunctionalState NewState);
void PWR_PVDLevelConfig(uint32_t PWR_PVDLevel);
void PWR_WakeUpPinCmd(FunctionalState NewState);
void PWR_EnterSTOPMode(uint32_t PWR_Regulator, uint8_t PWR_STOPEntry);
void PWR_EnterSTANDBYMode(void);
FlagStatus PWR_GetFlagStatus(uint32_t PWR_FLAG);
void PWR_ClearFlag(uint32_t PWR_FLAG);

(4)main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"                      // 调用延时头文件
#include "OLED.h"
#include "Key.h"

uint8_t KeyNum;
uint16_t ArrayWrite[] = {0x1234,0x5678};
uint16_t ArrayRead[2];

int main(void)
{
	OLED_Init();                                 // 初始化OLED屏幕
	Key_Init();
	OLED_ShowString(1,1,"W:");
	OLED_ShowString(2,1,"R:");
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);   //使能PWR时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);   //使能BKP时钟
	PWR_BackupAccessCmd(ENABLE);                         //使能对BKP和RTC的访问
//	BKP_WriteBackupRegister(BKP_DR1,0x1234);
//	OLED_ShowHexNum(1,1,BKP_ReadBackupRegister(BKP_DR1),4);
	while(1)
	{	
		KeyNum = Key_GetNum();
		if(KeyNum == 1)
		{
			ArrayWrite[0]++;
			ArrayWrite[1]++;
			BKP_WriteBackupRegister(BKP_DR1,ArrayWrite[0]);
			BKP_WriteBackupRegister(BKP_DR2,ArrayWrite[1]);
			OLED_ShowHexNum(1,3,ArrayWrite[0],4);
			OLED_ShowHexNum(1,8,ArrayWrite[1],4);
		}
        ArrayRead[0] = BKP_ReadBackupRegister(BKP_DR1);   
		ArrayRead[1] = BKP_ReadBackupRegister(BKP_DR2); 
		OLED_ShowHexNum(2,3,ArrayRead[0],4);
		OLED_ShowHexNum(2,8,ArrayRead[1],4);
	}
}

11.4  实时时钟

11.4.1 硬件电路

11.4.2 软件部分

(1)复制复制《OLED显示屏》并改为《实时时钟》

(2)添加驱动文件

(3)使用的RCC库函数

void RCC_LSEConfig(uint8_t RCC_LSE);                   //配置LSE外部低速时钟
void RCC_LSICmd(FunctionalState NewState);             //配置LSI内部低速时钟
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);      //选择RTCCLK的时钟源
void RCC_RTCCLKCmd(FunctionalState NewState);          //启动RTCCLK


FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);    //获取标志位,LSE时钟不是说让它启动就能立刻启动,还需要1等待标志位LSEREADY置1

(4)RTC库函数

void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);   //配置中断输出
void RTC_EnterConfigMode(void);                                 //进入配置模式,置CRL的CNF位为1,进入配置模式
void RTC_ExitConfigMode(void);                                  //退出配置模式,把CNF位清零
uint32_t  RTC_GetCounter(void);                                 //获取CNT计数器的值,读取时钟,就靠这个函数
void RTC_SetCounter(uint32_t CounterValue);                     //写入CNT计数器的值,设置时间,就靠这个函数    
void RTC_SetPrescaler(uint32_t PrescalerValue);                 //写入预分频器,这个值会写入的预分频器的PRL重装寄存器中,用来配置预分频器的分频系数
void RTC_SetAlarm(uint32_t AlarmValue);                         //写入闹钟值
uint32_t  RTC_GetDivider(void);                                 //读取预分频器中的DIV余数寄存器,余数寄存器是一个自减计数器,一般是为了得到更细致的时间
void RTC_WaitForLastTask(void);                                 //等待上次操作完成
void RTC_WaitForSynchro(void);                                  //等待同步,等待RSF位置1
FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);
void RTC_ClearFlag(uint16_t RTC_FLAG);
ITStatus RTC_GetITStatus(uint16_t RTC_IT);
void RTC_ClearITPendingBit(uint16_t RTC_IT);

(5)MyRTC.c

#include "stm32f10x.h"                  // Device header
#include <time.h>
void MyRTC_SetTime(void);

uint16_t MyRTC_Time[]= {2024,8,15,11,13,55};            //十进制前面千万不要补0,因为8进制以0开头

/*RTC初始化函数*/
void MyRTC_Init(void)
{
	/*第1步:开启PWR和BKP的时钟,使能BKP和RTC的访问*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
	PWR_BackupAccessCmd(ENABLE);
	if(BKP_ReadBackupRegister(BKP_DR1 != 0xA5A5))
	{
		/*第2步:开启LSE时钟,并等待LSE时钟启动完成*/
		RCC_LSEConfig(RCC_LSE_ON);                        //启动LSE晶振
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=SET);   //等待LSE状态标志位置1
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);           //选择RTCCLK时钟源
		RCC_RTCCLKCmd(ENABLE);                            //使能时钟                        
		
		RTC_WaitForSynchro();                             //等待同步 
		RTC_WaitForLastTask();                            //等待上一次操作完成	
		
		RTC_SetPrescaler(32768-1);                        //配置分频系数得到1Hz
		RTC_WaitForLastTask();                            //等待上一次操作完成
	//	RTC_SetCounter(1723690874);	
		MyRTC_SetTime();
		
		/*有的板子RTC晶振起振不了,RTC晶振不起振,就会卡死在RCC_GetFlagStatus(RCC_FLAG_LSERDY)这里
		,这时侯只能备选LSI,进行以下修改*/
	//	RCC_LSICmd(ENABLE);                        //启动LSI晶振
	//	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)!=SET);   //等待LSI状态标志位置1
	//	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);           //选择RTCCLK时钟源
	//	RCC_RTCCLKCmd(ENABLE);                            //使能时钟                        
	//	
	//	RTC_WaitForSynchro();                             //等待同步 
	//	RTC_WaitForLastTask();                            //等待上一次操作完成	
	//	
	//	RTC_SetPrescaler(40000-1);                        //配置分频系数得到1Hz
	//	RTC_WaitForLastTask();                            //等待上一次操作完成
	//	RTC_SetCounter(1723690874);
		BKP_WriteBackupRegister(BKP_DR1,0xA5A5);
	}
	else
		{
			RTC_WaitForSynchro();                             //等待同步 
			RTC_WaitForLastTask();                            //等待上一次操作完成	
		}
}

/*将时间转换位Unix时间戳形式函数*/
void MyRTC_SetTime(void)
{
	time_t time_cnt;
	struct tm time_date;
	time_date.tm_year = MyRTC_Time[0]-1900;
	time_date.tm_mon= MyRTC_Time[1]-1;
	time_date.tm_mday = MyRTC_Time[2];
	time_date.tm_hour = MyRTC_Time[3];
	time_date.tm_min = MyRTC_Time[4];
	time_date.tm_sec = MyRTC_Time[5];
	time_cnt = mktime(&time_date)-8*60*60;
	RTC_SetCounter(time_cnt);
	RTC_WaitForLastTask();
}

/*读取时间函数*/
void MyRTC_ReadTime(void)
{
	time_t time_cnt;
	struct tm time_date;
	time_cnt = RTC_GetCounter() + 8*60*60;
	time_date = *localtime(&time_cnt);
	MyRTC_Time[0]=time_date.tm_year + 1900;
	MyRTC_Time[1]=time_date.tm_mon + 1;
	MyRTC_Time[2]=time_date.tm_mday;
	MyRTC_Time[3]=time_date.tm_hour ;
	MyRTC_Time[4]=time_date.tm_min;
	MyRTC_Time[5]=time_date.tm_sec;
}

(6)MyRTC.h

#ifndef __MYRTC_
#define __MYRTC_
extern uint16_t MyRTC_Time[];  
void MyRTC_Init(void);
void MyRTC_SetTime(void);
void MyRTC_ReadTime(void);
#endif
 

(7)main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"                      // 调用延时头文件
#include "OLED.h"
#include "MyRTC.h"

uint8_t KeyNum;

int main(void)
{
	OLED_Init();                                 // 初始化OLED屏幕
	MyRTC_Init();
	OLED_ShowString(1,1,"Date:XXXX-XX-XX");
	OLED_ShowString(2,1,"Time:XX:XX:XX");
	OLED_ShowString(3,1,"CNT:");
	OLED_ShowString(4,1,"DIV:");
	
	while(1)
	{
		MyRTC_ReadTime();
		OLED_ShowNum(1,6,MyRTC_Time[0],4);
		OLED_ShowNum(1,11,MyRTC_Time[1],2);
		OLED_ShowNum(1,14,MyRTC_Time[2],2);
		OLED_ShowNum(2,6,MyRTC_Time[3],2);
		OLED_ShowNum(2,9,MyRTC_Time[4],2);
		OLED_ShowNum(2,12,MyRTC_Time[5],2);
		OLED_ShowNum(3,6,RTC_GetCounter(),10);
		OLED_ShowNum(2,12,MyRTC_Time[5],2);
		OLED_ShowNum(3,6,RTC_GetCounter(),10);
		OLED_ShowNum(4,6,(32767-RTC_GetDivider())/32767.0*999,10);
	}
}

 

 

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

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

相关文章

【机械原理学习】——《机械原理》(第二版)机构部分

机械原理 绪论&#xff1a; 机械机器机构 第一章&#xff1a;平面机构的结构分析 构件与零件 每个独立运动的单元体称为构件机构总是由一些零件组成的‌过盈配合是指两个配合零件之间存在一定的过盈量&#xff0c;即一个零件的孔径比另一个零件的轴径小&#xff0c;装配时…

算法:排序(下)

六、快速排序 快速排序用到了分治思想&#xff0c;同样的还有归并排序。乍看起来快速排序和归并排序非常相似&#xff0c;都是将问题变小&#xff0c;先排序子串&#xff0c;最后合并。不同的是快速排序在划分子问题的时候经过多一步处理&#xff0c;将划分的两组数据划分为一…

【IPD流程】产品开发V模型阶段介绍

目录 阶段简介 配图 阶段详解 作者简介 阶段简介 V模型大体可以划分为以下几个不同的阶段步骤: 需求分析、软件需求分析、概要设计、详细设计、软件编码、单元测试、集成测试、系统测试、验收测试。配图 refer:https://t.zsxq.com/NS41O 阶段详解 客户需求定义: 此阶段…

C/C++圣诞树代码

目录 系列文章 写在前面 圣诞节 C语言 圣诞树 写在后面 系列文章 序号目录直达链接1爱心代码https://want595.blog.csdn.net/article/details/1363606842李峋同款跳动的爱心https://want595.blog.csdn.net/article/details/1397222493满屏飘字代码https://want595.blog.…

247.2k star! 超强大的私有化ChatGPT,支持图像识别/文生图/语音输入/文本朗读,个人电脑即可运行!试试吧

今天作者带大家实现一个普通配置电脑即可运行的私有化ChatGPT&#xff0c;支持以下功能&#xff1a; 1.界面体验与ChatGPT官方几乎一样。 2.支持多种开源模型&#xff0c;可以聊天、写代码、识别图片内容等。 3.支持文生图。 4.支持麦克风语音输入聊天。 5.支持自动朗读回…

如何在wordpress当中使用插件WP Coder(将html、css、javascript应用到wordpress上)

了解认识阶段 安装并运行好WP Coder之后如下图&#xff1a; 设置全局PHP 禁用gutenberg 输入代码 add_filter(gutenberg_can_edit_post, __return_false, 10); add_filter(use_block_editor_for_post, __return_false, 10); 记得点击save并勾选enable PHP code 禁用之后打…

从0开始Vue3数据交互之promise详解

目录 前言 1. 预先须知-普通函数和回调函数 1.1 普通函数: 1.2 回调函数: 2. Promise 简介 2.1 简介 2.2 特点 3. Promise 基本用法 3.1 Promise then 1. 没有传参 3.1.1 没有调用resolve 函数和reject 函数时 3.1.2 调用resolve()函数 3.1.3 调用 reject()函数 2…

【Linux详解】进度条实现 Linux下git 的远程上传

&#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;Linux—登神长阶 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f49e; &#x1f49e; &#x1f49e; &#x1f680;前言 &#x…

张飞硬件1~9电阻篇笔记

电阻有标定值和实际值&#xff0c;关于误差的问题&#xff1a; 精密的电流、电压采样可能会用到1%的精度。如果只是做限流用途的话&#xff0c;用5%就足够。 电阻功率&#xff1a;标定值、额定值、瞬态值&#xff1a; 标定值由封装所决定&#xff0c;例如5W额定值由电路中平…

结构开发笔记(三):solidworks软件(二):小试牛刀,绘制一个立方体

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/141122350 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

如果忘记了 Apple ID 密码,如何重设

“我忘记了我的 Apple ID 密码&#xff0c;如何恢复我的帐户&#xff1f;”为了方便用户&#xff0c;Apple 允许每个人使用唯一的 Apple ID 和密码激活设备并访问所有 Apple 服务。然而&#xff0c;实际上&#xff0c;手动选择某项并忘记它似乎很容易。例如&#xff0c;许多 Ap…

AI大模型零基础入门学习路线(非常详细)从入门到精通,看这篇就 够了

学习AI大模型从零基础入门到精通是一个循序渐进的过程&#xff0c;涉及到理论知识、编程技能和实践经验。下面是一份详细的指南&#xff0c;帮助你从头开始学习并逐步掌握AI大模型的构建与应用。 第一阶段&#xff08;10天&#xff09;&#xff1a;初阶应用 该阶段让大家对大…

北斗导航系统:助力保护生态环境的利器

近年来&#xff0c;随着科技的迅猛发展和生态危机的加剧&#xff0c;环保问题成了全球热点话题。而北斗导航系统&#xff0c;作为中国自主研发的全球卫星导航系统&#xff0c;不仅在军事和民用领域显示出了巨大潜力&#xff0c;也在应对生态保护挑战中发挥了重要作用。本篇文章…

ue5正确导入资源 content(内容),content只能有一个

把资源content下的东西&#xff0c;全部拷贝&#xff0c;放在项目的content下 content只能有一个

除毛除臭不够彻底?宠物空气净化器帮你解决

之前养猫的时候就想买一个空气净化器吸一吸空气的浮毛&#xff0c;尤其是夏天&#xff0c;因为夏天天气热流汗也会多&#xff0c;每次外出回家之后全身都是汗的时候想坐下来吹一下空调&#xff0c;但是一坐下去就会发现&#xff0c;沙发上全都是猫咪浮毛&#xff0c;而且还没开…

了解Android

Android 系统架构 从图中可以看出&#xff0c;整个Android操作系统分为五层。它们分别是&#xff1a; 内核层 Android系统是基于Linux内核的&#xff0c;这一层为Android设备的各种硬件提供了底层的驱动。硬件抽象层 该层为硬件厂商定义了一套标准的接口。这样可以在不影响上层…

Labelimg安装、使用及不显示标注、覆盖标签等问题

目录 1 安装 2 基本使用方法 3 显示已标记图片的标记 4 覆盖标签的问题 简单记录下Labelimg安装、使用以及在使用过程中遇到的几个问题的解决方法&#xff0c;以免忘记。 1 安装 这里是在Anaconda中搭建机器学习的环境&#xff0c;在Anaconda Prompt中激活虚拟环境后&…

C++ 之动手写 Reactor 服务器模型(二):服务器模型概述以及 Reactor 服务器 V1 版本实现

五种网络 IO 模型 就是下面五种&#xff1a; 要注意同步与异步、阻塞与非阻塞的辨析&#xff0c;常见误解就是认为&#xff1a;同步就是阻塞&#xff0c;异步就是非阻塞。 接下来分别给出例子来说明这五种 IO 模型。 基础知识 操作系统分为用户态和内核态。 一个网络数据输…

STM32低功耗与备用备份区域

STM的备份备用区域其实就是两个区块&#xff1a;BKP和RTC。低功耗则其实是STM32四种模式中的三种耗能很低的模式。 目录 一&#xff1a;备用区域 1.BKP 2.RTC 二&#xff1a;低功耗模式 1.睡眠模式&#xff1a; 2.停机模式&#xff1a; 3.待机模式&#xff1a; 一&…

AI绘画赏析:基于Stable Diffusion扩散模型

**Stable Diffusion**是2022年发布的深度学习文本到图像生成模型。它主要用于根据文本的描述产生详细图像&#xff0c;尽管它也可以应用于其他任务&#xff0c;如内补绘制、外补绘制&#xff0c;以及在提示词指导下产生图生图的翻译。它是一种潜在扩散模型&#xff0c;由慕尼黑…