STM32 F103C8T6学习笔记11:RTC实时时钟—OLED手表日历

news2024/9/24 23:33:32

之前在 学习笔记10文章 做了一个简易的,使用定时器计时的简单时钟,现在使用RTC实时时钟同步代替定时器来实现一下OLED手表日历,接着上个实验文章进行完善~~

文章提供源码、测试工程下载、测试效果图。

目录

 RTC实时时钟:

简介:

主要特性:

 RTC框图:

UNIX时间戳:

程序设计:

配置RTC初始化过程分为以下几步:

 RTC日历初始化相关代码:

主函数代码:

测试效果:

测试工程下载:


 RTC实时时钟:

简介:

 STM32F10x-中文参考手册 有关于RTC实时时钟的介绍是从 P308页开始的:

 RTC时钟与DS1302时钟芯片不同,DS1302时钟芯片是通过读取寄存器实现读取年月日等信息的

而RTC时钟是作为STM32F103单片机中的一个时钟定时器模块(其余系列不一定),主电源掉电后会继续使用   后备电池(由 Vbat 引脚接 电源 继续供电 )继续运行的模块,它本质是一个32位的向上计数器。

因此我们在STM32F103单片机中 读取RTC时 本质是得到一个计数值,对其进行处理。

主要特性:

 我们一般在LSE接一个 32.768k ( 2^15=32768 )的晶振作为RTC的时钟源,便于分频产生1HZ的时钟基准,

 RTC框图:

 

 我们从RTC的框图可以了解到,它的秒、闹钟都是有中断的,但溢出事件(计数到达最大值)时没有中断。

UNIX时间戳:

在设计到日历时,我们就需要注意这个时间戳:

 

程序设计:

首先注意一下这些头文件,都是需要用到的,别忘记了添加

#include "stm32f10x_rtc.h" //RTC相关库
#include "stm32f10x_pwr.h"  
#include "stm32f10x_bkp.h"

配置RTC初始化过程分为以下几步:

1.配置中断,配置中断优先级

2.检查寄存器BKP_DR1,根据其值确定是否为第一次上电,V BAT是否有后备电池,第一次上电就要初始化时间。(V BAT没电池 以及 V BAT有电池 但寄存器没被写入值都算第一次上电)(后备寄存器区由V BAT引脚供电,因此当V BAT引脚有电时主电源断不会使得后备寄存器区的寄存器BKP_DR1的值丢失 )

3.定义时间结构体,用来存放改变时间等.

4.复制编写RTC_Configuration()函数,配置相关时钟源,外部时钟还是内部,分频等。

5.编写Time_Adjust()函数,给RTC时钟附上初始值(通过将 小时、分钟和秒都转换成秒 加起来 来实现设置当前计数值)(小时是 24小时制)

此处需要注意一个小细节:

就是我的程序设计使用上没用到串口,因此没有初始化串口,但在移植官方代码时,他们使用串口打印测试,各阶段初始化情况,起初我保留了这些printf()语句,认为会跳过,但实际上程序会因为没有初始化串口而在printf那卡住~·

 RTC日历初始化相关代码:

#include "RTC.h"


void RTC_init(void)
{
   NVIC_InitTypeDef NVIC_Initstructure;
	
	/*1. NVIC 中断配置 */
  /*Configure one bit for preemption priority 中断分组*/
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
   /*Enable the RTC Interrupt */
		NVIC_Initstructure.NVIC_IRQChannel = RTC_IRQn;
		NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 1;
		NVIC_Initstructure.NVIC_IRQChannelSubPriority = 0;
		NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init (&NVIC_Initstructure);	
	
		/*检查V BAT引脚是否为第一次上电(是否有后备电源)没有就要初始化时间*/
	   /*在启动时检查备份寄存器BKP_DR1,如果内容不是0xA5A5,
	  则需重新配置时间并询问用户调整时间*/
	if (BKP_ReadBackupRegister( BKP_DR1) != 0xA5A5)
	{
		//配置RTC与设置初值:
		RTC_Configuration();
		Time_Adjust(&time1);
		/*向BKP_DR1寄存器写入标志,说明RTC已在运行,只要后备有电,这个值就不会掉*/
		BKP_WriteBackupRegister( BKP_DR1, 0xA5A5);
	}
	
	else
	{
		/* 使能 PWR 和 Backup 时钟 */
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
		/* 允许访问 Backup 区域 */
	  PWR_BackupAccessCmd(ENABLE);		
	  /*LSE启动无需设置新时钟*/		
#ifdef RTC_CLOCK_SOURCE_LSI		
			/* 使能 LSI */
			RCC_LSICmd(ENABLE);
			/* 等待 LSI 准备好 */
			while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
			{}
#endif
		/*检查是否是系统掉电重启*/
		if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
		{ ;}
		/*检查是否Reset复位引脚引起的 复位*/
		else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
		{;}	
		/*等待寄存器同步*/
		RTC_WaitForSynchro();	
		/*允许RTC秒中断*/
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	
		/*等待上次RTC寄存器写操作完成*/
		RTC_WaitForLastTask();
	}
	   /*定义了时钟输出宏,则配置校正时钟输出到PC13*/
	#ifdef RTCClockOutput_Enable
	/* 使能 PWR 和 Backup 时钟 */
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
	
	/* 允许访问 Backup 区域 */
	  PWR_BackupAccessCmd(ENABLE);
	
	  /* 禁止 Tamper 引脚 */
	  /* 要输出 RTCCLK/64 到 Tamper 引脚,  tamper 功能必须禁止 */	
	  BKP_TamperPinCmd(DISABLE); 
	
	  /* 使能 RTC 时钟输出到 Tamper 引脚 */
	  BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);
	#endif
	  /* 清除复位标志 flags */
	  RCC_ClearFlag();
}


/*
 * 函数名:RTC_Configuration
 * 描述  :配置RTC
 * 输入  :无
 * 输出  :无
 * 调用  :外部调用
 */
void RTC_Configuration(void)
{
	/* 使能 PWR 和 Backup 时钟 */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
	/* 允许访问 Backup 区域 */
	PWR_BackupAccessCmd(ENABLE);	
	/* 复位 Backup 区域 */
	BKP_DeInit();	
//使用外部时钟还是内部时钟(在bsp_rtc.h文件定义)	
//使用外部时钟时,在有些情况下晶振不起振
//批量产品的时候,很容易出现外部晶振不起振的情况,不太可靠	
#ifdef 	RTC_CLOCK_SOURCE_LSE
	/* 使能 LSE */
	RCC_LSEConfig(RCC_LSE_ON);	
	/* 等待 LSE 准备好 */
	while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
	{}
	/* 选择 LSE 作为 RTC 时钟源 */
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);	
	/* 使能 RTC 时钟 */
	RCC_RTCCLKCmd(ENABLE);
	/* 等待 RTC 寄存器 同步
	 * 因为RTC时钟是低速的,内环时钟是高速的,所以要同步
	 */
	RTC_WaitForSynchro();	
	/* 确保上一次 RTC 的操作完成 */
	RTC_WaitForLastTask();	
	/* 使能 RTC 秒中断 */
	RTC_ITConfig(RTC_IT_SEC, ENABLE);
	/* 确保上一次 RTC 的操作完成 */
	RTC_WaitForLastTask();	
	/* 设置 RTC 分频: 使 RTC 周期为1s  */
	/* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) = 1HZ */
	RTC_SetPrescaler(32767); 	
	/* 确保上一次 RTC 的操作完成 */
	RTC_WaitForLastTask();	
#else
	/* 使能 LSI */
	RCC_LSICmd(ENABLE);
	/* 等待 LSI 准备好 */
	while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET){}	
	/* 选择 LSI 作为 RTC 时钟源 */
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);	
	/* 使能 RTC 时钟 */
	RCC_RTCCLKCmd(ENABLE);	
	/* 等待 RTC 寄存器 同步
	 * 因为RTC时钟是低速的,内环时钟是高速的,所以要同步
	 */
	RTC_WaitForSynchro();	
	/* 确保上一次 RTC 的操作完成 */
	RTC_WaitForLastTask();	
	/* 使能 RTC 秒中断 */
	RTC_ITConfig(RTC_IT_SEC, ENABLE);	
	/* 确保上一次 RTC 的操作完成 */
	RTC_WaitForLastTask();
	/* 设置 RTC 分频: 使 RTC 周期为1s ,LSI约为40KHz */
	/* RTC period = RTCCLK/RTC_PR = (40 KHz)/(40000-1+1) = 1HZ */	
	RTC_SetPrescaler(40000-1); 
	/* 确保上一次 RTC 的操作完成 */
	RTC_WaitForLastTask();
#endif
	
}
#ifndef _RTC_h_ 
#define _RTC_h_  

#include "headfire.h"

//使用LSE外部时钟 或 LSI内部时钟
//#define RTC_CLOCK_SOURCE_LSE      
#define RTC_CLOCK_SOURCE_LSI
//北京时间的时区秒数差
#define TIME_ZOOM						(8*60*60)

//初始化时间结构体
extern struct rtc_time time1;


void RTC_init(void);           //初始化 与 配置RTC
void RTC_Configuration(void);  //配置RTC


#endif

#include "RTC_day.h"

/*时间结构体,初始化默认时间 2023-08-21 17:55:55*/
struct rtc_time time1= {55,55,17,21,8,2023,1} ;//初始化时间结构体

uint16_t BMP_cnt,BMP_FLAG;

#define FEBRUARY		2
#define	STARTOFTIME		1970
#define SECDAY			86400L           /*  一天有多少s */
#define SECYR			(SECDAY * 365)
#define	leapyear(year)		((year) % 4 == 0)
#define	days_in_year(a) 	(leapyear(a) ? 366 : 365)
#define	days_in_month(a) 	(month_days[(a) - 1])

static int month_days[12] = {	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

/*
 * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
 */
 /*计算公历*/
void GregorianDay(struct rtc_time * tm)
{
	int leapsToDate;
	int lastYear;
	int day;
	int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };

	lastYear=tm->tm_year-1;

	/*计算从公元元年到计数的前一年之中一共经历了多少个闰年*/
	leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;      

     /*如若计数的这一年为闰年,且计数的月份在2月之后,则日数加1,否则不加1*/
	if((tm->tm_year%4==0) &&
	   ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
	   (tm->tm_mon>2)) {
		/*
		 * We are past Feb. 29 in a leap year
		 */
		day=1;
	} else {
		day=0;
	}

	day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday; /*计算从公元元年元旦到计数日期一共有多少天*/

	tm->tm_wday=day%7;
}

/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
 *
 * [For the Julian calendar (which was used in Russia before 1917,
 * Britain & colonies before 1752, anywhere else before 1582,
 * and is still in use by some communities) leave out the
 * -year/100+year/400 terms, and add 10.]
 *
 * This algorithm was first published by Gauss (I think).
 *
 * WARNING: this function will overflow on 2106-02-07 06:28:16 on
 * machines were long is 32-bit! (However, as time_t is signed, we
 * will already get problems at other places on 2038-01-19 03:14:08)
 *
 */
u32 mktimev(struct rtc_time *tm)
{
	if (0 >= (int) (tm->tm_mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
		tm->tm_mon += 12;		/* Puts Feb last since it has leap day */
		tm->tm_year -= 1;
	}

	return (((
		(u32) (tm->tm_year/4 - tm->tm_year/100 + tm->tm_year/400 + 367*tm->tm_mon/12 + tm->tm_mday) +
			tm->tm_year*365 - 719499
	    )*24 + tm->tm_hour /* now have hours */
	  )*60 + tm->tm_min /* now have minutes */
	)*60 + tm->tm_sec; /* finally seconds */	 
}



void to_tm(u32 tim, struct rtc_time * tm)
{
	register u32    i;
	register long   hms, day;

	day = tim / SECDAY;			/* 有多少天 */
	hms = tim % SECDAY;			/* 今天的时间,单位s */

	/* Hours, minutes, seconds are easy */
	tm->tm_hour = hms / 3600;
	tm->tm_min = (hms % 3600) / 60;
	tm->tm_sec = (hms % 3600) % 60;

	/* Number of years in days */ /*算出当前年份,起始的计数年份为1970年*/
	for (i = STARTOFTIME; day >= days_in_year(i); i++) {
		day -= days_in_year(i);
	}
	tm->tm_year = i;

	/* Number of months in days left */ /*计算当前的月份*/
	if (leapyear(tm->tm_year)) {
		days_in_month(FEBRUARY) = 29;
	}
	for (i = 1; day >= days_in_month(i); i++) {
		day -= days_in_month(i);
	}
	days_in_month(FEBRUARY) = 28;
	tm->tm_mon = i;

	/* Days are what is left over (+1) from all that. *//*计算当前日期*/
	tm->tm_mday = day + 1;

	/*
	 * Determine the day of week
	 */
	GregorianDay(tm);
	
}

/*
 * 函数名:Time_Adjust
 * 描述  :时间调节
 * 输入  :用于读取RTC时间的结构体指针(北京时间)
 * 输出  :无
 * 调用  :外部调用
 */
void Time_Adjust(struct rtc_time* tm)
{
	  /* 等待确保上一次操作完成 */
	  RTC_WaitForLastTask();
		//更新日期
		 GregorianDay(tm);
	
//	  /* 设置当前时间  通过将 小时、分钟和秒都转换成秒 加起来 来实现设置当前计数值 (小时是 24小时制) */
//	  RTC_SetCounter(tm->tm_hour*3600+tm->tm_min*60+tm->tm_sec);  //Tmp HH*3600 Tmp MM*60 Tmp SS
	
	  /* 由日期计算时间戳并写入到RTC计数寄存器 */
	  RTC_SetCounter(mktimev(tm)-TIME_ZOOM);	
	
	  /* 等待确保上一次操作完成 */
	  RTC_WaitForLastTask();
}



void Time_Display(uint32_t TimeVar,struct rtc_time *tm)
{
	   char  buf[20];   //用于暂存oled数据
	   uint32_t BJ_TimeVar;

	   /*  把标准时间转换为北京时间*/
	   BJ_TimeVar =TimeVar + TIME_ZOOM;
	   to_tm(BJ_TimeVar,tm);/*把定时器的值转换为北京时间*/
	
		//打印年
		sprintf(buf,"%d",tm->tm_year);
		OLED_ShowString(75,0,(u8 *)buf,16);
	  OLED_ShowCHinese(75+16*2,0,0);  //打印中文“年”
		//打印时间:
	  sprintf(buf,"%02d:%02d:%02d",tm->tm_hour,tm->tm_min,tm->tm_sec);		
 		OLED_ShowString(64,2,(u8 *)buf,16);		          
		//打印日期:
		sprintf(buf,"%02d",tm->tm_mon);	   
		OLED_ShowString(75,4,(u8 *)buf,12);	//打印月	
		OLED_ShowCHinese_small(75+14,4,0);  //打印中文月	    
		sprintf(buf,"%02d",tm->tm_mday);		 
		OLED_ShowString(75+14+12,4,(u8 *)buf,12);	//打印日
		OLED_ShowCHinese_small(75+14+12+14,4,1);  //打印中文日
		//打印星期:
	  OLED_ShowCHinese(70,5,1);     //打印中文“星”		
	  OLED_ShowCHinese(70+16,5,2);  //打印中文“期”				
		sprintf(buf,"%d",tm->tm_wday);		   
		OLED_ShowString(70+16+16,5,(u8 *)buf,16);
}
#ifndef _RTC_day_h_
#define _RTC_day_h_

#include "headfire.h"

typedef unsigned int  u32;

//定义时间结构体
struct rtc_time {
	int tm_sec;
	int tm_min;
	int tm_hour;
	int tm_mday;
	int tm_mon;
	int tm_year;
	int tm_wday;
};

//初始化时间结构体
extern struct rtc_time time1;

extern uint16_t BMP_cnt,BMP_FLAG;

void GregorianDay(struct rtc_time * tm);
uint32_t mktimev(struct rtc_time *tm);
void to_tm(uint32_t tim, struct rtc_time * tm);
void Time_Display(uint32_t TimeVar,struct rtc_time *tm);
void Time_Adjust(struct rtc_time* tm);

#endif


 

主函数代码:

#include "main.h"

//时间结构体  在RTC_day.h中初始化了
//时间结构体定义在 RTC_day.h

//刷新时间标志
 uint16_t TimeDisplay_cnt,TimeDisplay;
	
int main(void)
{	
	init_ALL();     //初始化所有函数
  while(1)
	{	
		if(TimeDisplay==1)
		{
			Time_Display(RTC_GetCounter(),&time1);
			TimeDisplay=0;
		}
				switch(BMP_FLAG)
		{
			case 1:OLED_DrawBMP(0,0,64,8,BMP1);  break;
			case 2:OLED_DrawBMP(0,0,64,8,BMP2);  break;
			case 3:OLED_DrawBMP(0,0,64,8,BMP3);  break;
			case 4:OLED_DrawBMP(0,0,64,8,BMP4);  break;
			case 5:OLED_DrawBMP(0,0,64,8,BMP5);  break;
			case 6:OLED_DrawBMP(0,0,64,8,BMP6);  break;
			case 7:OLED_DrawBMP(0,0,64,8,BMP7);  break;
			case 8:OLED_DrawBMP(0,0,64,8,BMP8);  break;
			case 9:OLED_DrawBMP(0,0,64,8,BMP9);  break;
			case 10:OLED_DrawBMP(0,0,64,8,BMP10);  break;
			
			case 11:OLED_DrawBMP(0,0,64,8,BMP11);  break;
			case 12:OLED_DrawBMP(0,0,64,8,BMP12);  break;
			case 13:OLED_DrawBMP(0,0,64,8,BMP13);  break;
			case 14:OLED_DrawBMP(0,0,64,8,BMP14);  break;
			case 15:OLED_DrawBMP(0,0,64,8,BMP15);  break;
			case 16:OLED_DrawBMP(0,0,64,8,BMP16);  break;
			case 17:OLED_DrawBMP(0,0,64,8,BMP17);  break;
			case 18:OLED_DrawBMP(0,0,64,8,BMP18);  break;
			case 19:OLED_DrawBMP(0,0,64,8,BMP19);  break;
			case 20:OLED_DrawBMP(0,0,64,8,BMP20);  break;		

			case 21:OLED_DrawBMP(0,0,64,8,BMP21);  break;
			case 22:OLED_DrawBMP(0,0,64,8,BMP22);  break;
			case 23:OLED_DrawBMP(0,0,64,8,BMP23);  break;
			case 24:OLED_DrawBMP(0,0,64,8,BMP24);  break;
			case 25:OLED_DrawBMP(0,0,64,8,BMP25);  break;
			case 26:OLED_DrawBMP(0,0,64,8,BMP26);  break;
			case 27:OLED_DrawBMP(0,0,64,8,BMP27);  break;
			case 28:OLED_DrawBMP(0,0,64,8,BMP28);  break;

		}
	}
}


//初始化所有函数:
void init_ALL(void)
{
	SysTick_Init(72);         //初始化滴答计时器
	Timer2_Init();						//初始化定时器2
	i2c_GPIO_Config();	      //IIC初始化
	OLED_Init();              //初始化OLED屏幕
	OLED_Clear();             //清空屏幕数据
	RTC_init();
	
}


//定时器2中断服务函数
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{		
		if(++TimeDisplay_cnt==100)  //定时器刷新时间
		{
			TimeDisplay_cnt=0;TimeDisplay=1;
		}
		if(++BMP_cnt==10)		        //定时器   刷新太空人图片
		{
			BMP_cnt=0;BMP_FLAG++;
			if(BMP_FLAG==29){BMP_FLAG=1;}
		}
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清出中断寄存器标志位,用于退出中断
	}
}

//RTC每秒进的中断服务函数
void RTC_IRQHandler(void)
{
	  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
	  {
	    /* Clear the RTC Second interrupt */
	    RTC_ClearITPendingBit(RTC_IT_SEC);
	
//	    /* Enable time update */
//	    TimeDisplay = 1;
//	
	    /* Wait until last write operation on RTC registers has finished */
	    RTC_WaitForLastTask();
	  }
}

测试效果:

 

测试工程下载:

https://download.csdn.net/download/qq_64257614/88237879?spm=1001.2014.3001.5503

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

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

相关文章

MySQL——基础——内连接

一、内连接查询语法 隐式内连接 SELECT 字段列表 FROM 表1,表2 WHERE 条件...; 显示内连接 SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 连接条件...; 内连接查询的是两张表交集的部分 二、内连接演示 1.查询每一个员工的姓名,及关联的部门的名称…

多模双芯LC光纤跳线应用下的光模块方案之争

从40G QSFP SR4光模块产品开始,多模MPO光纤跳线 逐步进入光模块用户的视野。随着新建数据中心的增多,该类光纤跳线也开始普及并被广泛应用。然而,对于不少10G/25G时代就已经建设好的“老旧”机房来说,机房内基本全部部署的是多模L…

[MySQL]主从服务器布置

配置主服务器 配置文件 /etc/my.cnf 在[mysqld]下进行配置 log_binON //启动二进制日志 log-bin mysql-bin //启用二进制日志,用于记录主服务器的更新操作 server-id 1 // 用来表示mysql服务id,保证集成环境中的唯一性 , 范围 [1,2^32) read-only0 // 1表示只…

Java课题笔记~ VUE

1.1 概述 Vue 是一套前端框架,免除原生JavaScript中的DOM操作 我们之前也学习过后端的框架 Mybatis Mybatis 是用来简化 jdbc 代码编写的;而 VUE 是前端的框架,是用来简化 JavaScript 代码编写的。 学习了 VUE 后,这部分代码我…

6.链路追踪-Zipkin

链路追踪(Distributed Tracing)是一种用于监视分布式应用程序的技术,通过收集和展示分布式系统中不同组件之间的调用和交互情况,帮助开发人员和运维团队理解系统中的请求流程、性能瓶颈和异常情况。 1.Zipkin Zipkin 是一个开源的…

商户注册——异常处理

2.4.5 异常处理 2.4.5.1 异常信息格式 系统在交互中难免会有异常发生,前端为了解析异常信息向用户提示定义了异常信息的返回格式,如下: 1、返回response状态说明 状态码说明200成功401没有权限500程序错误(需要自定义错误体)2、自定义错误体 {"errCode": &qu…

matlab使用教程(20)—插值基础

1.网格和散点样本数据 插值是在位于一组样本数据点域中的查询位置进行函数值估算的方法。函数值是根据最接近查询点的样本数据点计算的。MATLAB 根据样本数据的结构,可以执行两种插值。样本数据可以形成网格,也可以是分散的。 网格化的样本数据使得插值…

1688批发工厂商品详情数据接口、商品采集接口(标题、详情、价格、主图)

接口背景 阿里巴巴(1688.com)是全球企业间(B2B)电子商务的著名品牌,为数千万网商提供海量商机信息和便捷安全的在线交易市场,也是商人们以商会友、真实互动的社区平台。供应商在该平台上展示和销售各类商品,而买家可以根据自己的需求选择合适的商品进行采购。为了提…

嵌入式糊涂蛋--基础恢复

2023年8月21日,距离找工作还有约365天。 现阶段状态:嵌入式各相关原理遗忘较大,嵌入式相关项目较少。机器学习、强化学习、数学规划等算法知识学得杂乱。 嵌入式学习路线 图片来源于公众号CodeSheep 图片来源于公众号CodeSheep 图片来源…

CSS 小技能(一):HTML 两个图片竖着平铺、设置图片点击、设置滚动条颜色

下面的代码没有考虑响应式的效果&#xff0c;如果考虑的话还需要一些代码进行处理。 【注】当时写的时候仅考虑了 webkit 内核的浏览器&#xff0c;如果是 IE 或者其他浏览器&#xff0c;请增加额外的 CSS 样式进行控制。 <!DOCTYPE html> <html> <head>&l…

YZ系列工具:YZ07:VBA对工作簿事件的监听

【分享成果&#xff0c;随喜正能量】善心善行的你&#xff0c;利己利他&#xff0c;积累无量福德&#xff0c;菩萨常伴左右&#xff0c;保佑一生平安&#xff0c; 财运亨通&#xff0c;福禄双收。身如逆流船&#xff0c;心比铁石坚。。 我给VBA下的定义&#xff1a;VBA是个人小…

微星笔记本暑促好货多多,开学季选购看这里!

随着即将到来的学期的临近&#xff0c;学生族如何选择一款称手的笔记本&#xff0c;就提上了日程。各种产品定位取向&#xff0c;各种价格范围&#xff0c;如果没有明确自己的需求和预算&#xff0c;就有点不知所措了~OK&#xff0c;今天就让我们从需求&预算出发&#xff0…

代码随想录(三) 哈希表

哈希表&#xff1a; 1.有效的字母异位词 用数组 class Solution { public:bool isAnagram(string s, string t) {int record[26] {0};for(int i 0; i < s.size(); i) {record[s[i] - a];} for(int i 0; i < t.size(); i) {record[t[i] - a]--;}for(int i 0; i <…

SDXL:Improving latent diffusion models for high-resolution image synthesis

文生图模型之SDXL - 知乎之前的文章 文生图模型之Stable Diffusion已经介绍了比较火的文生图模型Stable Diffusion&#xff0c;近期Stability AI又发布了新的升级版本SDXL。目前SDXL的代码、模型以及技术报告已经全部开源&#xff1a;官方代码&#xff1a;https://github.…htt…

灰鸽子远程控制病毒实验

一、实验目的&#xff1a; 1、掌握经典远控木马的原理 2、掌握“灰鸽子”木马的使用方法 二、预备知识&#xff1a; “灰鸽子”是现在网络上非常流行的一种木马&#xff0c;由两部分组成&#xff0c;一是控制端&#xff08;主程序&#xff09;&#xff0c;一是服务端&…

第19集丨Vue 江湖 —— ref属性

目录 一、多个单闭合组件标签二、ref属性三、小技巧 一、多个单闭合组件标签 下面案例中&#xff0c;多个单闭合标签<School/> &#xff0c;如果在非脚手架环境下只会显示第一个&#xff0c;但是在脚手架环境中&#xff0c;都会显示出来。 <template><div id&q…

手写 Mybatis-plus 基础架构(工厂模式+ Jdk 动态代理统一生成代理 Mapper)

这里写目录标题 前言温馨提示手把手带你解析 MapperScan 源码手把手带你解析 MapperScan 源码细节剖析工厂模式Jdk 代理手撕脚手架&#xff0c;复刻 BeanDefinitionRegistryPostProcessor手撕 FactoryBean代理 Mapper 在 Spring 源码中的生成流程手撕 MapperProxyFactory手撕增…

(排序) 剑指 Offer 51. 数组中的逆序对 ——【Leetcode每日一题】

❓剑指 Offer 51. 数组中的逆序对 难度&#xff1a;困难 在数组中的两个数字&#xff0c;如果前面一个数字大于后面的数字&#xff0c;则这两个数字组成一个逆序对。输入一个数组&#xff0c;求出这个数组中的逆序对的总数。 示例 1: 输入: [7,5,6,4] 输出: 5 限制&#xff…

测试框架pytest教程(9)自定义命令行-pytest_addoption

pytest_addoption pytest_addoption是pytest插件系统中的一个钩子函数&#xff0c;用于向pytest添加自定义命令行选项。 在pytest中&#xff0c;可以使用命令行选项来控制测试的行为和配置。pytest_addoption钩子函数允许您在运行pytest时添加自定义的命令行选项&#xff0c;…

十、接口(3)

本章概要 接口适配接口字段 初始化接口中的字段 接口嵌套接口和工厂方法模式 接口适配 接口最吸引人的原因之一是相同的接口可以有多个实现。在简单情况下体现在一个方法接受接口作为参数&#xff0c;该接口的实现和传递对象则取决于方法的使用者。 因此&#xff0c;接口的…