STM32初学-外部RTC时钟芯片DS3231

        RTC(Real_Time Clock)即实时时钟,它是电子产品中不可或缺的东西。其最直接的作用就是时钟功能。细心的朋友可以发现,当我们的电脑或者手机没联网时,仍然可以正常显示日期与时钟,这就是RTC的功劳。

        RTC的运行无需网络连接,只需一个频率固定的振荡源和一个计数器,就能实现精准的计时。假如有一个振荡源,其每秒固定振荡1000次,那我们就可以用计数器对振荡进行计数,每振荡1000次,代表时间过去了1s,然后复位计数器并开始新的计数,同时,秒寄存器加1。如此循环,就能实现时钟的走时。

21ad4e7542c24f098061485fea6c9146.png

        在单片机的某些使用场景下,RTC时钟是不可或缺的,例如使用了文件系统,就必须启用RTC时钟,用于更新文件的时间。

        STM32内置了RTC时钟模块,只要配置好参数,就能启用RTC。RTC的时钟振荡源可以来自内部也可以来自外部。内部时钟源由HCLK经过分频得到,外部时钟源则由石英晶振提供。

973457b0641540aaa604c7e12f8583a6.png

         内部时钟源是由高频晶振分频得到,所以其精度计时不高,为了准确计时,一般采用外部时钟源。外部时钟源一般选用32.768KHz的石英晶振。这种参数的石英晶振一秒钟能振荡32768次,正好对应2^16。

b98f599ebe9bc4ec1b60da566ec7fa39.jpeg

        然而,即使采用了外部晶振的RTC,其精度仍然是有限的。因为晶振外置,线路上的寄生电容电感、温度都会影响晶振频率,短时间可能看不出误差,但是时间一长,其误差就大了。

        如果想进一步减小RTC的误差,则需要使用RTC时钟芯片。时钟芯片的优势在于其内部带有温度补偿功能,能通过检测环境温度来对晶振进行误差补偿,减小计时误差。且时钟芯片的年、月、日等时间数据单独存储在内部的RAM中,对单片机来说,只要通过串口读取特定寄存器地址的数据就能得到时间参数,而无需再去计算。现在流行的时钟芯片很多,如DS1302、 DS1307。但是这些芯片仍需要外置晶振才能工作,所以仍存在误差。

        所以一种在内部集成晶振的时钟芯片应运而生。DS3231就是这样一种时钟芯片。其精度最高可以达到±2ppm。实测6个月在常温下连续运行,误差不超过1分钟。

61f5e66528d448859fee62d6a3aed26b.png

     DS3231采用快速IIC通信进行数据传输,最高时钟频率400KHz。还带有闹钟,复位等功能。224a5ac113814714a5bbfbb80213de94.png

 DS3231有两种封装,引脚功能一样,16pin的封装只是多了八个空引脚。

如下是其应用电路。9fb591b6e7464754a250edaffc08b806.png

        可以看到该芯片有两个电源输入,一个是VCC,另一个是Vbat。VCC我们可以与单片机共用3.3V电源,Vbat则接到一颗纽扣电池的正极。当单片机供电断开后,DS3231仍能靠纽扣电池供电维持计时功能,但是无法进行IIC通信,也就是不能读取时间数据,恢复VCC供电后,IIC通信随之被唤醒。

        INT是个漏极开路的输出,如果想输出高电平则需要外接上拉电阻,该引脚可连接到单片机IO口作为单片机的外部中断源。

        32kHz是一个固定输出32KHz频率方波的IO口,也可做为单片机的计时源。同为开漏输出。

        RST是芯片的复位脚,如果没有特别需要,可以直接悬空。该芯片无需复位也能直接初始化。

软件部分                                                          

        这里我使用的是STM32F4,F1的芯片也是兼容的,只是需要把头文件改成F1的。IIC通信采用软件模拟。iic的软件模拟可参考文章(STM32单片机-IIC通信(软件模拟)),这里我就不详细讲IIC软件模拟的原理了。接下来我们看程序。

1,我使用的是PB8和PB9分别做为IIC的SCL与SDA。如果想使用其他IO,稍微修改下就行。

#include<stm32f4xx.h>/********************软件模拟IIC*********************/
/*****************PB8=SCL,PB9=SDA*****************/#define	DS3231_ADDRESS_Write	0xD0
#define	DS3231_ADDRESS_Read		0xD1/**************DS3231内部寄存器地址***************/#define DS3231_SEC        0x00  // 秒
#define DS3231_MIN        0x01  //分
#define DS3231_HOUR       0x02	//时
#define DS3231_WEEK       0x03	//周
#define DS3231_DATE       0x04	//日
#define DS3231_MONTH      0x05	//月
#define DS3231_YEAR       0x06	//年#define DS3231_AL1SEC     0x07
#define DS3231_AL1MIN     0x08
#define DS3231_AL1HOUR    0x09
#define DS3231_AL1WDAY    0x0A#define DS3231_AL2MIN     0x0B
#define DS3231_AL2HOUR    0x0C
#define DS3231_AL2WDAY    0x0D#define DS3231_CONTROL          0x0E
#define DS3231_STATUS           0x0F
#define DS3231_AGING_OFFSET     0x0F
#define DS3231_TMP_High         0x11
#define DS3231_TMP_LOW          0x12/******DS3231内部寄存器地址******/
/**************END**************/#define Read_IIC_SDA GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9)		//定义Read_IIC_SDA为PB11的输入值#define IIC_SCL_H() GPIO_SetBits(GPIOB,GPIO_Pin_8)					//定义IIC_SCL_H()函数为将RES(PB10)置高电平	
#define IIC_SCL_L() GPIO_ResetBits(GPIOB,GPIO_Pin_8)				//定义IIC_SCL_L()函数为将RES(PB10)置低电平	#define IIC_SDA_H() GPIO_SetBits(GPIOB,GPIO_Pin_9)					//定义IIC_SDA_H()函数为将RES(PB11)置高电平	
#define IIC_SDA_L() GPIO_ResetBits(GPIOB,GPIO_Pin_9)				//定义IIC_SDA_L()函数为将RES(PB11)置低电平	//最后读取到的时间数据将赋值到下面这几个变量
u8 RTC_Sec,RTC_Min,RTC_Hour,RTC_Week,RTC_Date,RTC_Month;   
u16 RTC_Year;void IIC2_SoftInit(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8 | GPIO_Pin_9; 			//10--SCL   11--SDA;PB10 PB11GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;			//OD开漏GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;			//上拉GPIO_Init(GPIOB, &GPIO_InitStructure);
}/******* 设置SDA为输出*******/void SDA_OUT(void)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin= GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;	//推挽输出GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;			//OD开漏GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;			//上拉GPIO_Init(GPIOB, &GPIO_InitStructure);
}/******* 设置SDA为输入*******/void SDA_IN(void)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin= GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;		//上拉输入GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;			//OD开漏GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;			//上拉GPIO_Init(GPIOB, &GPIO_InitStructure);
}void IIC_Start(void)			//起始信号
{SDA_OUT();			//把SDA作为输出,初始化为推挽输出IIC_SDA_H();		//SDA输出高电平IIC_SCL_H();		//SCL输出高电平Delay_us(2);IIC_SDA_L();		//SDA输出低点评Delay_us(2);IIC_SCL_L();		//SCL输出低电平Delay_us(2);
}void IIC_Stop(void)		//停止信号
{IIC_SCL_H();		//SCL输出高电平IIC_SDA_L();		//SDA输出低点评Delay_us(2);IIC_SDA_H();		//SDA输出高电平Delay_us(2);
}u8 IIC_Wait_Ask(void)		//等待应答信号
{u8 count;IIC_SDA_H();Delay_us(2);SDA_IN();Delay_us(2);IIC_SCL_H();Delay_us(2);while(Read_IIC_SDA){count++;if(count>250){IIC_Stop();				//如果长时间无应答,则认为从站故障,终止数据传输,并返回1return 1;}   }IIC_SCL_L();Delay_us(1);return 0;
}void IIC_Ack(void)		//应答信号
{IIC_SCL_L();SDA_OUT();IIC_SDA_L();Delay_us(2);IIC_SCL_H();Delay_us(2);IIC_SCL_L();
}void IIC_NAck(void)		//主机不产生应答信号NACK
{IIC_SCL_L();SDA_OUT();IIC_SDA_H();Delay_us(2);IIC_SCL_H();Delay_us(2);IIC_SCL_L();
}void IIC_WriteByte(u8 data)			//写1Byte数据,每个数据都是以写1Byte作为基本单位
{u8 i;SDA_OUT();						//SDA切换到数据输出模式Delay_us(2);for(i=0;i<8;i++)				//循环传输1Byte数据,即8bit{IIC_SCL_L();				//SCL置低电平,为下个Bit数据做准备Delay_us(2);if(data & 0x80)     		//MSB,如果date的第八位为1IIC_SDA_H();			//则SDA置高elseIIC_SDA_L();			//否则置低Delay_us(1);IIC_SCL_H();				//SCL拉高,产生一个时钟信号,从机读取SDA状态Delay_us(2);				//延时,丛机在这段时间读取SDA状态IIC_SCL_L();				//延时后拉低SCL,为下个Bit数据做准备data<<=1;					//date左移1位,下一bit变成第八位}
}//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   u8 IIC_Read_Byte(const unsigned char ack)
{u8 i,receive=0;SDA_IN();			//SDA设置为输入Delay_us(2);for(i=0;i<8;i++ ){IIC_SCL_L(); Delay_us(2);IIC_SCL_H();receive<<=1;Delay_us(2);if(Read_IIC_SDA)receive++;   Delay_us(2); }					 if (!ack)IIC_NAck();		//发送nACKelseIIC_Ack();		 //发送ACK   return receive;
}void IIC_DS3231_ByteWrite(u8 WriteAddr,u8 date)
{IIC_Start();		//起始信号IIC_WriteByte(DS3231_ADDRESS_Write);		//DS3231设备地址,写IIC_Wait_Ask();				//等待应答IIC_WriteByte(WriteAddr);	//寄存器地址IIC_Wait_Ask();				//等待应答IIC_WriteByte(date);		//写入数据IIC_Wait_Ask();				//等待应答IIC_Stop();					//结束信号
}u8 IIC_DS3231_ByteRead(u8 ReadAddr)
{u8 data = 0;IIC_Start();										//产生起始位IIC_WriteByte(DS3231_ADDRESS_Write); 				//发送从机地址(写模式D0)IIC_Wait_Ask();				//等待应答IIC_WriteByte(ReadAddr);							//发送寄存器地址IIC_Wait_Ask();				//等待应答IIC_Start();										//重复起始信号IIC_WriteByte(DS3231_ADDRESS_Read);		//发送从机地址(读模式)IIC_Wait_Ask();							//等待应答data = IIC_Read_Byte(0);				//读取数据,参数设为0 --- NACKIIC_Stop();return data;
}void IIC_DS3231_ReadAll(void)		//读取所有时间数据并转换
{u8 Data_Sec,Data_Min,Data_Hour,Data_Week,Data_Date,Data_Month,Data_Year;u8 Low,High;Data_Sec= IIC_DS3231_ByteRead(DS3231_SEC);			//读取数据秒Data_Min = IIC_DS3231_ByteRead(DS3231_MIN);			//读取数据分Data_Hour = IIC_DS3231_ByteRead(DS3231_HOUR);		//读取数据时Data_Week = IIC_DS3231_ByteRead(DS3231_WEEK);		//读取数据周Data_Date = IIC_DS3231_ByteRead(DS3231_DATE);			//读取数据日Data_Month = IIC_DS3231_ByteRead(DS3231_MONTH);		//读取数据月Data_Year = IIC_DS3231_ByteRead(DS3231_YEAR);		//读取数据年Low=Data_Sec&0x0f;						//取低四位High=(( Data_Sec& 0xf0) >> 4);			//取高四位RTC_Sec=High*10+Low;					//转换秒(高四位*10+低四位)Low=Data_Min&0x0f;High=(( Data_Min& 0xf0) >> 4);RTC_Min=High*10+Low;					//转换分Low=Data_Hour&0x0f;High=(( Data_Hour& 0x30) >> 4);RTC_Hour=High*10+Low;					//转换时(高两位*10+低四位)RTC_Week=Data_Week;						//转换周(不需要转换)Low=Data_Date&0x0f;High=(( Data_Date& 0xf0) >> 4);RTC_Date=High*10+Low;					//转换日Low=Data_Month&0x0f;High=(( Data_Month& 0x10) >> 4);RTC_Month=High*10+Low;					//转换月Low=Data_Year&0x0f;High=(( Data_Year& 0xf0) >> 4);RTC_Year=((Data_Month>>7)+20)*100+High*10+Low;	//转换年(世纪*100+高四位*10+低四位)		
}void IIC_DS3231_WriteAll(u16 Year,u8 Month,u8 Date,u8 Week,u8 Hour,u8 Min,u8 Sec)
{	u8 Sec_Date,Min_Date,Hour_Date,Week_Date,Date_Date,Month_Date,Year_Date;u8 H_Bit,L_Bit;H_Bit=(Sec/10)<<4;			//取高四位L_Bit=Sec%10;				//取低四位Sec_Date=H_Bit|L_Bit;		//合并成八位H_Bit=(Min/10)<<4;L_Bit=Min%10;Min_Date=H_Bit|L_Bit;H_Bit=Hour/10;L_Bit=Hour%10;Hour_Date=(H_Bit<<4)|L_Bit;Week_Date=Week;H_Bit=Date/10;L_Bit=Date%10;Date_Date=(H_Bit<<4)|L_Bit;if(Year/100==20){	H_Bit=Month/10;L_Bit=Month%10;Month_Date=(H_Bit<<4)|L_Bit;H_Bit=(Year-2000)/10;L_Bit=(Year-2000)%10;Year_Date=(H_Bit<<4)|L_Bit;}else{H_Bit=Month/10+8;		//05h第8位如果是1,则为22世纪L_Bit=Month%10;Month_Date=(H_Bit<<4)|L_Bit;H_Bit=(Year-2100)/10;L_Bit=(Year-2100)%10;Year_Date=(H_Bit<<4)|L_Bit;}IIC_DS3231_ByteWrite(DS3231_YEAR,Year_Date);	IIC_DS3231_ByteWrite(DS3231_MONTH,Month_Date);IIC_DS3231_ByteWrite(DS3231_DATE,Date_Date);IIC_DS3231_ByteWrite(DS3231_WEEK,Week_Date);IIC_DS3231_ByteWrite(DS3231_HOUR,Hour_Date);IIC_DS3231_ByteWrite(DS3231_MIN,Min_Date);IIC_DS3231_ByteWrite(DS3231_SEC,Sec_Date);}void DS3231_Init(void)		//DS3231初始化
{IIC_DS3231_ByteWrite(0x0E,0x40);		//使能1Hz方波,使能振荡器	IIC_DS3231_ByteWrite(0x0F,0x00);		//启动振荡器Delay_ms(100);    //延时等待完全起振
}

 延时函数,IIC软件模拟需要用到延时函数,这里我采用的是滴答定时器进行延时,需要注意,F1 与F4的延时函数不能共用,因为主频不一样。

/***************************************************************** Function:    Delay_us* Description: Microsecond delay.* Input:       nus* Output:* Return:
*****************************************************************/
void Delay_us(u16 nus)
{ //Delay_Init();u32 temp;SysTick->LOAD = SystemCoreClock / 8000000 * nus;  /* Time load (SysTick-> LOAD is 24bit) */SysTick->VAL = 0x000000;                          /* Empty counter */SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;         /* Start the countdown */do{temp = SysTick->CTRL;}while(temp&0x01 && !(temp&(1<<16)));        /* Wait time is reached */SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;  /* Close Counter */SysTick->VAL = 0x000000;                    /* Empty counter */
}/***************************************************************** Function:    Delay_ms* Description: Millisecond delay.* Input:       nms* Output:* Return:
*****************************************************************/
void Delay_ms(u16 nms)
{u32 temp;while(nms > 500)	//24位定时器最大计数值2^24=16777216,计时器时钟频率初始化为21MHz,最大计时时间为16777216/21000000=0.798s=798ms,所以需要多次复位{SysTick->LOAD = SystemCoreClock / 8000 * 500; /* Time load (SysTick-> LOAD is 24bit) */SysTick->VAL = 0x000000;                      /* Empty counter */SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;     /* Start the countdown */do{temp = SysTick->CTRL;}while(temp&0x01 && !(temp&(1<<16)));        /* Wait time is reached */SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;  /* Close Counter */SysTick->VAL = 0x000000;                    /* Empty counter */nms -= 500;}SysTick->LOAD = SystemCoreClock / 8000 * nms; /* Time load (SysTick-> LOAD is 24bit) */SysTick->VAL = 0x000000;                      /* Empty counter */SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;     /* Start the countdown */do{temp = SysTick->CTRL;}while(temp&0x01 && !(temp&(1<<16)));        /* Wait time is reached */SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;  /* Close Counter */SysTick->VAL = 0x000000;                    /* Empty counter */
}

嘀嗒定时器初始化:在启用延时函数前必须对定时器进行初始化,配置对应的参数。这里我用主频HCLK的八分频做为其定时频率,即21MHz。也就是一秒钟对应定时器的21000000。

void Delay_Init(void)			//嘀嗒计时器初始化,用于Delay函数
{SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);		//计数器频率:168M/8=21MHZSysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;  				/* Disability SysTick counter */
}

main函数:初始化延时函数,初始化DS3231 ,讲时间写入DS3231,讲时间读取出来

#include<stm32f4xx.h>    //F4头文件void main(void)
{Delay_Init();                //嘀嗒定时器初始化,必须初始化,延时依靠嘀嗒计时器DS3231_Init();		//DS3231初始化,唤醒DS3231,并启动振荡器IIC_DS3231_WriteAll(2023,10,1,1,12,00,00);   //设置时间函数,实例为2023年10月1日12:00:00IIC_DS3231_ReadAll();        //读取DS3231所有时间数据
}

最终读取转换后的时钟数据分别为这些变量:u8 RTC_Sec,RTC_Min,RTC_Hour,RTC_Week,RTC_Date,RTC_Month;   
u16 RTC_Year;

可以通过串口打印,或者其他方式显示出当前时间。

这里我将时间显示到LCD屏幕上。

如果觉得本文有用,就点个赞吧~

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript设计模式(三)——单例模式、装饰器模式、适配器模式

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

MySQL——日志

日志的作用 1.用来排错 2.用来做数据分析 3.了解程序的运行情况&#xff0c;是否健康--》了解MySQL的性能&#xff0c;运行情况 分类 mysql很多有类型的日志&#xff0c;按照组件划分的话&#xff0c;可以分为 服务层日志 和 存储引擎层日志 &#xff1a; - 服务层…

java包装类简单认识泛型

1 包装类 在 Java 中&#xff0c;由于基本类型不是继承自 Object &#xff0c;为了在泛型代码中可以支持基本类型&#xff0c; Java 给每个基本类型都对应了一个包装 类型。类中比如由属性/方法 使用比较方便 1.1 基本数据类型和对应的包装类 1.2 装箱和拆箱 装包/装箱 : …

分布式版本控制工具——git

✅<1>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;Linux——git ☂️<3>开发环境&#xff1a;Centos7 &#x1f4ac;<4>前言&#xff1a;git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很…

学习笔记——树上哈希

普通子树哈希 树上的很多东西都是转化成链上问题的&#xff0c;比如树上哈希 树上哈希&#xff0c;主要是用于树的同构这个东西上的 什么是树的同构&#xff1f; 如图&#xff0c;不考虑节点编号&#xff0c;三棵树是同构的 将树转化成链&#xff0c;一般有两种方式&#xf…

JS防抖和节流在前端开发中的应用场景

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 防抖&#xff08;Debouncing&#xff09;⭐ 节流&#xff08;Throttling&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端…

KT142C-sop16语音芯片ic内置320Kbyte_USB更新内置空间详细说明

KT142C内置的是320K的空间&#xff0c;但是实际的大小&#xff0c;在电脑里面显示&#xff0c;应该是315Kbyte。 打开我的电脑&#xff0c;芯片连接PC之后&#xff0c;自动多出来了一个U盘&#xff0c;如下图所示&#xff1a; 这里的空间只有315KB &#xff0c;因为文件系统占…

猫头虎的技术笔记:Spring Boot启动报错解决方案

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Java项目基于SpringBoot藏区特产销售系统,可作为毕业设计

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 今天为大家带来的是基于 Java SpringBootVue 的藏区特产销售系统 文章目录 1. 简介2.主要技术3 功能分析4 系…

【2023高教社杯】B题 多波束测线问题 问题分析、数学模型及参考文献

【2023高教社杯】B题 多波束测线问题 问题分析、数学模型及参考文献 1 题目 1.1 问题背景 多波束测深系统是利用声波在水中的传播特性来测量水体深度的技术&#xff0c;是在单波束测深的基础上发展起来的&#xff0c;该系统在与航迹垂直的平面内一次能发射出数十个乃至上百个…

Redis集群3.2.11离线安装详细版本(使用Ruby)

1.安装软件准备 1.Redis版本下载 Index of /releases/http://download.redis.io/releases/ 1.2gcc环境准备 GCC(GNU Compiler Collection,GNU编译器套件)是一套用于编译程序代码的开源编译器工具集。它的主要用途是将高级编程语言(如C、C++、Fortran等)编写的源代码转换…

SEO百度优化基础知识全解析(了解百度SEO标签作用)

百度SEO优化的作用介绍&#xff1a; 百度SEO优化是指通过对网站的内部结构、外部链接、内容质量、用户体验等方面进行优化&#xff0c;提升网站在百度搜索结果中的排名&#xff0c;从而提高网站的曝光率和流量。通过百度SEO优化&#xff0c;可以让更多的潜在用户找到你的网站&…

软件设计模式(二):工厂、门面、调停者和装饰器模式

前言 在这篇文章中&#xff0c;荔枝将会梳理软件设计模式中的四种&#xff1a;工厂模式、Facade模式、Mediator模式和装饰器Decorator模式。其中比较重要的就是工厂模式和装饰器模式&#xff0c;工厂模式在开发中使用的频数比较高。希望荔枝的这篇文章能讲清楚哈哈哈哈&#xf…

【STM32】文件系统FATFS与Flash的初步使用

文件系统简介 简介可以不看&#xff0c;直接看移植步骤 文件系统是介于应用层和底层间的模糊层。底层提供API&#xff0c;比如说使用SDIO或者SPI等读写一个字节。文件系统把这些API组合包装起来&#xff0c;并且提供一些列函数&#xff0c;我们可以使用这些函数进行更进一步的…

分享一个python基于数据可视化的智慧社区服务平台源码

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1…

MySQL数据类型

目录 MySQL数据类型 数据类型分类 数值类型 tinyint类型 bit类型 float类型 decimal类型 字符串类型 char类型 varchar类型 char和varchar比较 时间日期类型 enum和set类型 MySQL数据类型 数据类型的作用&#xff1a; 决定了存储数据时应该开辟的空间大小。决定…

CocosCreator3.8研究笔记(十二)CocosCreator 字体资源理解

Cocos Creator 常用的字体资源有三种&#xff1a;系统字体、动态字体、位图字体。 一、系统字体 系统字体是调用运行平台自带的系统字体来渲染文字&#xff0c;不需要用户在项目中添加任何相关资源。 使用系统字体&#xff0c; Label 组件 Use System Font 属性需要勾选。 Fo…

手写签名到背景上合为1张图

手写签名到背景上合为1张图 package.json中 "signature_pad": "3.0.0-beta.3"<template><div class"home"><canvas id"canvas" width"500" height"300"></canvas><button click"…

【计算机基础知识4】网络通信协议:TCP、UDP、WebSockets

目录 一、TCP&#xff08;传输控制协议&#xff09; 1. TCP的特点 2. TCP的连接建立和终止 3. TCP的可靠性机制 4. TCP的流量控制 二、UDP&#xff08;用户数据报协议&#xff09; 1. UDP的特点 2. UDP的使用场景 三、WebSockets 1. WebSockets协议的特点 2. WebSock…

长安链BaaS服务平台调研

目录 一、菜单功能二、其他说明2.1、服务平台的部署方式2.2、链本身2.3、建链流程2.4、支持连接已部署的链2.5、链治理投票2.6、支持动态节点操作2.7、支持应用 长安链ChainMaker管理平台文档地址&#xff1a;https://docs.chainmaker.org.cn 一、菜单功能 菜单子菜单/功能点…