江协科技51单片机学习- p27 I2C AT24C02存储器

  🚀write in front🚀  
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​ 

💬本系列哔哩哔哩江科大51单片机的视频为主以及自己的总结梳理📚 

前言:

本文是根据哔哩哔哩网站上“江协科技51单片机”视频的学习笔记,在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了江协科技51单片机教学视频和链接中的内容。

引用:

51单片机入门教程-2020版 程序全程纯手打 从零开始入门_哔哩哔哩_bilibili

​​​​​c51语言变量语句意思,C51中循环语句-CSDN博客

51单片机和AT24C02链接:

51之AT24C02数据存储(I2C总线)_at24c02的地址线-CSDN博客

江协科技 51单片机 AT24C02(I2C总线) 学习笔记——略带拓展_iic总线江协科技-CSDN博客

51单片机系列--AT24C02(总线)_at24c02电路-CSDN博客

ROM简介:

ROM学习笔记1-ROM、PROM、EPROM、EEPROM_掩膜rom-CSDN博客

正文:

0. 🌿概述

在淘宝上购买了江协科技51单片机开发板套件(普中科技STC51单片机A2型号),就上在上一篇博文里说的自己计划学习下江协科技51单片机开发教程,通过STC51单片机这种MCU这种贴近于裸机的开发来增加对于系统硬件层面知识的了解和掌握。

术语和缩略语:

缩写全称说明
I2CInter-Integrated Circuit一种串行通信总线
SDA(Serial Data)串行数据线,用于数据传输
SCL(Serial Clock)串行时钟线

1. 🚀 存储器介绍

    正如图所示,存储器主要分为2大类,RAM(Random Access Memory,随机存取存储器)和ROM(Read-Only Memory,只读存储器)。RAM由于是随机存储,所以存储速度快,但是它存在掉电数据丢失的缺点;ROM就正好相反,它存储速度较慢,但是掉电不丢失。

1.1 RAM

  RAM主要分成两种:SRAM和DRAM。

        🌳SRAM(Static RAM,静态RAM),速度比DRAM还更快,内部结构主要是使用触发器来完成数据存储,现在广泛使用于我们的电脑CPU等需要快速缓存的地方,缺点就是相对较贵。

        🌳DRAM(Dynamic RAM,动态RAM),速度稍慢于SRAM,内部主要基于电容来存储数据,所以价格稍微更低。但是电容在存入电信号之后会放电导致电流失,所以DRAM就要每隔一段时间再把数据重新读入,从而完成数据的持续存储。

1.2 ROM

  ROM分为很多种,有:Mask ROM(掩膜ROM),PROM(可编程ROM),EPROM(可擦除编程ROM),E2PROM(电可擦除可编程ROM),Flash(闪存),以及硬盘,软盘,光盘等。

  • 🌳Mask ROM(掩膜ROM)
  • 🌳PROM(可编程ROM)
  • 🌳EPROM(可擦除编程ROM,有一个开窗可以用紫外线照射进行ROM数据擦除)
  • 🌳E2PROM(电可擦除可编程ROM)
  • 🌳Flash(闪存)
  • 🌳硬盘,软盘,光盘等

1.2.1Mask ROM(掩膜ROM)

作为最早出现的一种ROM,它的缺陷自然是很多的,首先它的主要结构是下面的这种二极管:

 并且,由于使用的是这种二极管为基础的电路,它存储的数据就无法被更改,所以得名只读存储器。Mask ROM的数据写入是不可逆的,即一旦数据被写入,就无法更改。这种类型的存储器通常用于存储固定内容,因为它的成本相对较低,且由于其不可擦写的特性,适合于大批量生产。Mask ROM的优点包括成本较低和稳定性较高,因为它们不像其他可擦写存储器那样需要额外的擦写机制。然而,它们的缺点是缺乏灵活性,一旦制造完成,就不能更改存储在其中的数据。

🌳掩膜ROM的读取原理,是按照行列的方式扫描,横线为地址线,竖线为数据输出线,地址横线选中加上高电平,因为二极管的单向导电性,掩膜有二极管的交叉线(相当于一个bit位)就读取到高电平,没有掩膜二极管的就读取到低电平,通过这种方式就可以存储0或者1,这也就是掩膜ROM的工作模型。

1.2.2PROM(可编程ROM)

 PROM,即Program ROM,也称为可编程ROM,它的主要基本原理也是基于二极管:

🌲这里的蓝色二极管是根据我们写入的程序更改的,不同于Mask ROM,Mask ROM的数据是在厂家生产时就定下来了,PROM的数据则是在写入程序的时候生成,所有的电路都具备一对反向的二极管,这样的组成,当我们写入数据为高电平的时候,会触发击穿电压,从而达到写入数据的目的,因为是把这个蓝色的二极管击穿,所以我们写入程序也叫“烧入程序”,名字就是由此而来。但是PROM依旧是不能够擦除数据,只能写入程序,所以它的局限性依旧很大。

1.2.3EPROM(可擦除编程ROM)

由于时代的变迁和技术的革新,ROM的材料也开始变革,所以产生了EPROM,即可擦除编程ROM,它无非就是在PROM的二极管基础上更新材料,变成了可以恢复的一种材料,导致半导体击穿之后还可以通过一定的技术手段恢复,所以称为可擦除编程ROM。

通过紫外线照射擦写ROM的数据,ROM芯片封装上有一个开口,用紫外线灯照射就可以擦除数据。

擦除:EPROM的die会漏在外面,如下图所示。擦除时,只需要用如紫外灯照射20min即可。

1.2.4E2PROM(电可擦除可编程ROM)

由于技术的革新,产生了电可擦除编程ROM,E2PROM和前面的EPROM的区别就是:E2PROM可以通过电直接擦除数据,但是EPROM是不能用电直接擦除的,所以使用电擦除数据,也是一种使用电控制电的手段,也是现在大部分ROM存储的前身。

🌲EEPROM全称Electricially Erasable Programmable Read Only Memory, 通过分析EPROM的原理可知,SIMOS的二氧化硅层比较厚,势垒比较高,所以不管是往浮栅中充入电子还是擦除电子,都需要给电子充较大的能量,使用上的体现就是较高的电压和长时间的光照擦除。后来科学家门对其结构进行改进,在浮栅和漏区设置了一个极薄的氧化层区域,如下图所示。这样的mos管学名叫浮栅隧道氧化层MOS管(Floating-gate Tunnel Oxide MOS),又称Flotox管。

🌲Flotox管的工作原理与SIMOS类似,只是给浮栅充电方式是隧穿(Fowler-Nordheim隧穿),而不是热电子注入。当隧道区的电场足够大时,电子就能在电场的作用下通过隧道形成隧道电流,这种现象叫隧道效应。

  • 🌲编程前,浮栅上没有电荷,就是一个普通NMOS。
  • 🌲编程时,漏源均接地,控制栅上施加一个20V的脉冲。此时,隧道区产生强电场,吸引漏极的电子穿过隧道到达浮栅。撤除电压后,浮栅上的电子可以永久保留(通常可达十年以上)。
  • 🌲擦除时,源极与控制栅接地,在漏极上施加一个20V的脉冲。类似编程,隧道区产生一个反向的强电场,浮栅上的电子又被吸引回漏极,从而擦除信息。

EEPROM的存储单元由两个MOS管组成,T1为Flotox管,T2为普通mos管。
读过程:当要读这个存储单元时,首先给字线施加一个高电平,选通T2。如果T1管未经过编程,浮栅上不带电,在控制栅上施加正电压可以导通T1,位线上读到0;若浮栅中带电荷,控制栅上给高电平无法使T1管导通,位线上读到1(位线上有未画出的上拉到高电平的部分,常态读取时将电压拉高)。
擦除(相当于写1):擦除时,在字线和控制栅线上施加一个高电平脉冲,同时将位线拉低。在脉冲时间内,T2导通,T1的Ugd之间为20V高压,T1管被编程,浮栅上带了电荷。
写过程:对于要写0的存储单元,在字线和位线上施加一个高电平脉冲,同时将控制栅线拉低。在脉冲时间内,T2导通,T1的Ugd之间为-20V高压,T1管浮栅上的电荷被释放(如果有电荷的话)。

1.2.5Flash(闪存)

现在最为广泛使用的ROM存储手段,非常适合用作便携式设备的存储介质,如USB闪存驱动器、智能手机、平板电脑和其他嵌入式系统,广泛适用于各个地方,包括我们的51单片机,堪称ROM唯一真神。

 当然,除了上面这些,还有硬盘,软盘,光盘等ROM式的存储,我们这里就不多赘述了。

2.地址总线

 地址总线较为复杂,我们可以简化成上面的原理图进行说明:首先,地址总线上对应的是不同的设备,一般前面还会加一个译码器,通过对应的地址找到需要选中的设备,并且只能选中一行,这样就可以实现每次只有一个设备写入读取数据,就不会搞混了。选中设备后,设别就把数据写入到数据总线中去了。

3.AT24C02芯片简介

AT24C02芯片
存储介质: E2PROM
通讯接口: I2C 总线
容量: 256 字节

引脚

功能

VCC、GND

电源(1.8V~5.5V )

WP

写保护(高电平有效)

SCL、SDA

I2C接口

A0、A1、A2

I2C地址

AT24C02芯片是一个典型的掉电不丢失的ROM芯片,在单片机中,它的原理图是这样的:

  这里写的是EEPROM,其实就是我们前面所说的E2PROM,电可擦除编程ROM,这里的这个引脚好像和前面标注的不太一样,其实是一样的,只是不同的工程师对它有不同的命名罢了。

🌳还有这里有一个WE,上面有一个横线,在这里就表示Write Eable,即写入使能且低电平有效,意思就是接低电平这个芯片才可以写入数据,在原来的引脚定义图里面其实是WP即Write Protect,写保护,高电平有效,意思就是高电平开启写保护,此时无法写入数据,相反的,想要写入数据就要低电平,在普中单片机的原理图里面,这个引脚接GND,即默认这个引脚就是低电平,无论什么时候都是可以直接写入数据的。

所以,普中科技51单片机开发板在使用单片机的时候其实只要配置SCL,SDA还有三根数据线就行了。它们都是使用的I2C接口,所以我们这里就先了解一下I2C总线。

4.I2C总线

I2C总线(Inter IC BUS)是由Philips公司开发的一种通用数据总线,它使用两根通信线:SCL(Serial Clock)、SDA(Serial Data)。

  • 🌳工作特点是:同步、半双工,带数据应答
  • 🌳前面在讲串口通信的时候稍微提了一下I2C还有这个半双工和同步
  • 🌳同步且半双工就是下面这样:两个设备通过一根时钟线约定时钟周期(同步),在使用通信的两个设备可以通过同一个时钟线互相传递数据。

  • 1.🌿所有I2C设备的SCL连在一起,SDA连在一起。总线结构,在线上外接各种设备。如图中所示。
  • 2🌿.设备的SCL和SDA均要配置成开漏输出模式

这张图就是我们单片机IO口的输出线路,可以将控制器理解为一个电源连上一个无限大的电阻,Q1是一个控制开关的MOS口,当Q1打开时相当于此处不分压,所以输出低电平;当Q1关闭时,Q1处的电阻无限大,外部的VCC和控制器内部形成一个串联电路电阻相比于Q1很小,所以输出高电平。(我们可能在视频中常听到的强/弱上拉就是改变上拉电阻的阻值来达到控制输出电流电压大小的情况。)

  • 🌿开漏输出模式就是将此图中的VCC和上拉电阻去掉,那么在Q1关闭时电路相当于断开,输出的电平是不稳定,非常容易被影响的。

  • 3.🌿SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
  • 4.🌿开漏输出和上拉电阻的共同作用实现了“线与”的功能,此设计主要是为了解决多机通信互相干扰的问题 


这是一个设备的内部电路图:

  • 🌿I2C总线协议使用两条通信线,一条是SCL串行时钟线,一条是SDA串行数据线。
  • 🌿I2C总线上的所有设备的SCL总线连接在一起,SDA总线连接在一起。
  • 🌿I2C总线是同步,半双工,带应答的协议。
  • 🌿I2C总线的IO口需要配置为开漏输出模式,并且SCL,SDA总线上接上拉电阻,一般接上拉电阻为 4.7K~10K。
  • 🌿I2C总线当SCL为高电平,SDA为高电平时为空闲状态。
  • 🌿I2C总线的通信速率一般是 100Kb/s,高速I2C总线速率为 400Kb/s。

I2C总线是半双工通信协议,也就是同一时间数据只能由主机发送从机接受,或者从机发送主机接收,I2C总线的通信时钟总是由主机控制的,从机按照主机的时钟信号做出反应。

🔍️I2C总线是真正的多主机多从机通信协议,I2C主机和从机通信之间需要先进行从机地址呼叫,I2C从机的地址一般是7位,最多支持2 ^7=128个从机地址。

🔍️I2C从机地址的高4位是向飞利浦公司申请的,第3位地址是设备厂商自行设置的。

4.1 I2C通信协议

起始条件SCL为高电平,SDA从高电平变为低电平表示起始信号
结束条件SCL为高电平,SDA从低电平变为高电平表示接受信号
应答

I2C固定每发送或接受8个数据位,需要回复应答ACK或者非应答

应答ACK=0

非应答NACK=1

非应答

I2C固定每发送或接受8个数据位,需要回复应答ACK或者非应答

应答ACK=0

非应答NACK=1

发送bit在SCL为高电平时SDA必须保持不变,在SCL为低电平时SDA总线上数据才允许变化
接收bit

在SCL为高电平时SDA必须保持不变,在SCL为低电平时SDA总线上数据才允许变化。

主机释放SDA,在主机发送SCL低电平时,从机将0或者1发送到SDA总线,在SCL为高电平时,主机读取SDA总线获取从发送的数据。

4.2 数据帧(针对AT24C02芯片)

  1. Start起始信号
  2. 从机地址7位+1位写位
  3. 等待从机应答ACK
  4. 发送8位地址
  5. 等待从机应答ACK
  6. 发送8位数据
  7. 等待从机应答ACK
  8. 发送Stop信号

  1. Start起始信号
  2. 从机地址7位+1位写位
  3. 等待从机应答ACK
  4. 发送8位地址
  5. 等待从机应答ACK
  6. 重新Start起始信号 (Restart)
  7. 从机地址7位+1位读位
  8. 等待从机应答ACK
  9. 接收从机发送8位数据
  10. 回复NACK给从机,通知从机读取结束
  11. 发送Stop信号

4.3 I2C从机地址 

📒这里我们发现,在S(即开始)之后,有一个SLAVE ADRESS+R/W的一个字节,这个字节就是我们前面说过的匹配对象的过程同时也确定了主机为接收端还是发送端。

📒SLAVE ADRESS+R/W分为前面七个位表示地址和最后一位表示读/写模式

 在不同的设备中,这里都有不同的含义,这里就主要用我们这次使用的AT24C02芯片为例:

首先,对于AT24C02芯片而言,前面四位为它的固定位,这四个位是在I2C原厂商为AT24C02制定的固定地址位,为1 0 1 0,不能更改,后面的三位可以仔细看看:

4.4 I2C时序

根据上述原理图,写程序时我们要建立六个子函数模块,开始传输数据时SCL和SDA都应该处于高电平,先拉低SDA电平再拉低SCL电平,在传输或者接收数据时要拉高并保持SCL高电平然后读取放到SDA上的数据,结束传输数据就和开始时相反,还要设置应答模块在主机和从机间建立应答通讯。

📚️发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节 。注:真正传输时只有一条SDA

📚️接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA,SDA置1)  

4.5 AT24C02写周期

AT24C02写之后,内部需要5ms的写周期,数据才能写入到内部存储位置。

我们可以发现,这里最短时间限制少于1us,然而我们的单片机最短反应时间足足有1us,所以我们根本不需要担心时间不够的问题,直接使用,不需要延时,单片机完全有时间反应过来。

✏️注意:

写进去立马读出来能读到吗?

✏️不能!

为什么不能?

我们看一下手册上的写周期是5ms

5. 程序源码

I2C.c中模拟I2C总线的时序,起始信号,结束信号,发送字节,接收字节,发送ACK,接收ACK。

I2C.c

#include <REGX52.H>
#include <INTRINS.H>
#include "Delay.h"
#include "I2C.h"sbit I2C_SCL = P2^1;
sbit I2C_SDA = P2^0;/*** @brief  I2C延时通过 * @param  * @retval */
void I2C_Nop(void)
{_nop_();_nop_();_nop_();_nop_();_nop_();
}/*** @brief  I2C发送起始信号Start* @param  无* @retval 无*/
void I2C_Start(void)
{I2C_SDA = 1;I2C_SCL = 1;	//SCL时钟拉高电平I2C_SDA = 0;	//当SCL为高电平时,SDA从高变低表示StartI2C_Nop();I2C_SCL = 0;
}/*** @brief  I2C发送停止信号Stop* @param  无* @retval 无*/
void I2C_Stop(void)
{I2C_SDA = 0;	//SDA拉低I2C_SCL = 1;	//SCL拉高I2C_SDA = 1;	//当SCL为高电平时SDA从低变为高电平表示Stop
}/*** @brief  I2C发送8位数据* @param  无* @retval 无*/void I2C_SendByte(unsigned char byte)
{unsigned char i = 0;for(i=0; i < 8; i++){I2C_SDA = byte & (0x80 >> i);I2C_Nop();I2C_SCL = 1;I2C_Nop();I2C_SCL = 0;}
}/*** @brief  I2C接收8位数据* @param  无* @retval 接收到的8位数据*/
unsigned char I2C_RecvByte(void)
{unsigned char i = 0;unsigned char byte = 0;byte = 0;for(i=0; i < 8; i++){I2C_SDA = 1;				//释放SDA总线I2C_SCL = 1;				//SCL拉高if(I2C_SDA){byte |= (0x80 >> i);	//读取SDA}I2C_Nop();I2C_SCL = 0;				//SCL拉低}return byte;
}/*** @brief  I2C发送ACK应答信号* @param  无* @retval 无*/
void I2C_SendAck(void)
{I2C_SDA = 0;I2C_SCL = 1;I2C_Nop();I2C_SCL = 0;
}/*** @brief  I2C发送NACK应答信号* @param  无* @retval 无*/
void I2C_SendNack(void)
{I2C_SDA = 1;I2C_SCL = 1;I2C_Nop();I2C_SCL = 0;
}/*** @brief  获取I2C ACK应答* @param  无* @retval 返回值为0或1,0表示ACK,1表示NACK*/
unsigned char I2C_RecvAck(void)
{unsigned char ack = 0;I2C_SDA = 1;		//释放SDA总线I2C_SCL = 1;		//拉高SCL总线if(I2C_SDA == 1)	//读取SDA总线ack = 1;elseack = 0;I2C_Nop();I2C_SCL = 0;return ack;
}

I2C.h

#ifndef __I2C_H__
#define __I2C_H__void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char byte);
unsigned char I2C_RecvByte(void);
void I2C_SendAck(void);
void I2C_SendNack(void);
unsigned char I2C_RecvAck(void);#endif

AT24C02.C

#include <REGX52.H>
#include <INTRINS.H>
#include "I2C.h"
#include "AT24c02.h"#define AT24C02_ADDR		0xA0/*** @brief  AT24C02 EPROM存储器指定地址写一个字节数据* @param  addr 写存储器地址* @param  data 写存储器数据* @retval 0 写成功,1 写失败*/
unsigned char AT24c02_WriteByte(unsigned char addr, unsigned char byte)
{I2C_Start();I2C_SendByte(AT24C02_ADDR);I2C_RecvAck();I2C_SendByte(addr);I2C_RecvAck();I2C_SendByte(byte);I2C_RecvAck();//结束条件I2C_Stop();
}/*** @brief  AT24C02 EPROM存储器指定地址读一个字节数据* @param  addr 读存储器地址 * @retval */
unsigned char AT24c02_ReadByte(unsigned char addr)
{unsigned char byte = 0;//起始条件I2C_Start();//从机地址 写I2C_SendByte(AT24C02_ADDR);I2C_RecvAck();//写存储器地址I2C_SendByte(addr);I2C_RecvAck();//Restart起始条件I2C_Start();//从机地址 读I2C_SendByte(AT24C02_ADDR | 0x01);I2C_RecvAck();byte = I2C_RecvByte();I2C_SendNack();//结束条件I2C_Stop();return byte;
}

AT24C02.H

#ifndef __AT24C02_H__
#define __AT24C02_H__unsigned char AT24c02_ReadByte(unsigned char addr);
unsigned char AT24c02_WriteByte(unsigned char addr, unsigned char byte);#endif

main.c

#include <REGX52.H>
#include <INTRINS.H>
#include "Delay.h"
#include "Key.h"
#include "timer0.h"
#include "LCD1602.h"
#include "Nixie.h"
#include "AT24c02.h"unsigned char Minute;
unsigned char Second;
unsigned char HunSecond;
unsigned char Second_Enable = 1;void main()
{unsigned char Key_Num = 0;unsigned char Byte = 0;unsigned int i = 0;Timer0_Init();P2 = 0xff;//LCD_Init();//LCD_ShowString(1,1,"Hello!");Nixie_Setbuffer(1, 0);Nixie_Setbuffer(2, 0);Nixie_Setbuffer(3, 10);Nixie_Setbuffer(4, 0);Nixie_Setbuffer(5, 0);Nixie_Setbuffer(6, 10);Nixie_Setbuffer(7, 0);Nixie_Setbuffer(8, 0);Minute = AT24c02_ReadByte(0x00);Second = AT24c02_ReadByte(0x01);HunSecond = AT24c02_ReadByte(0x02);while(1){Key_Num = Key();if(Key_Num == 1){Second_Enable = !Second_Enable;}if(Key_Num == 2){AT24c02_WriteByte(0x00, Minute);Delay(5);AT24c02_WriteByte(0x01, Second);AT24c02_WriteByte(0x02, HunSecond);//LCD_Init();//LCD_ShowString(1,1,"Saving Data");//Delay(1000);//LCD_Init();}if(Key_Num == 2){Minute = AT24c02_ReadByte(0x00);Second = AT24c02_ReadByte(0x01);HunSecond = AT24c02_ReadByte(0x02);//LCD_Init();//LCD_ShowString(1,1,"Read Data");//Delay(1000);//LCD_Init();}//Delay(1000);}
}/*** @brief  定时器0中断处理函数模版* @param  无* @retval 无*/
void Timer_Routine(void) interrupt 1
{static unsigned int key_count = 0;static unsigned int nixie_count = 0;static unsigned int sec_count = 0;TR0 = 0;key_count++;if(key_count >= 20){Key_Loop();key_count = 0;		}nixie_count++;if(nixie_count >= 2){Nixie_Loop();nixie_count = 0;		}sec_count++;if(sec_count >= 10)		//10ms{sec_count = 0; 		//10ms counterif(Second_Enable){HunSecond++;if(HunSecond >= 100){HunSecond = 0;Second++;}if(Second >= 60){Second = 0;Minute++;}if(Minute >= 60){Minute = 0;}Nixie_Setbuffer(1, HunSecond%10);Nixie_Setbuffer(2, HunSecond/10);Nixie_Setbuffer(3, 10);Nixie_Setbuffer(4, Second%10);Nixie_Setbuffer(5, Second/10);Nixie_Setbuffer(6, 10);Nixie_Setbuffer(7, Minute%10);Nixie_Setbuffer(8, Minute/10);}}//定时器溢出之后需要重新装载TH0 = (65535 - 1000) / 256;					//12MHz晶振,12分频TL0 = (65535 - 1000) % 256 + 1; 			//TR0 = 1;
}

6. 实验结果

使用Keil5编译代码,并使用STC-ISP烧录到普中科技51单片机开发板上上效果如下:

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

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

相关文章

Wikijs 部署教程

以下是一个 Wikijs 部署的简单教程&#xff0c;涵盖了使用 Docker 和直接安装两种方式&#xff1a; 方法一&#xff1a; 使用 Docker (推荐) Docker 是一个方便快捷的方式来部署 Wikijs&#xff0c;它可以避免许多手动配置步骤。 安装 Docker: 按照 https://docs.docker.com/…

JRE、JVM、JDK分别是什么。

JDK JDK的英文全称是Java Development Kit。JDK是用于制作程序和Java应用程序的软件开发环境。JDK 是 Java 开发工具包&#xff0c;它是 Java 开发者用来编写、编译、调试和运行 Java 程序的集合。JDK 包括了 Java 编译器&#xff08;javac&#xff09;、Java 运行时环境&…

【已解决】如何在一篇笔记中呈现另一篇笔记的内容,hover editor插件?obsidian

问题 问题&#xff1a;【已解决】如何让一篇笔记内容在另一篇的笔记里呈现&#xff1f; - 疑问解答 - Obsidian 中文论坛 如何在一篇笔记里&#xff0c;在插入内链接时&#xff0c;同时展示内链接的笔记中的内容&#xff1f; 比如&#xff1a; 哲学是一门[[学问]]这篇笔记…

2024年上半年信息系统项目管理师——综合知识真题题目及答案(第1批次)(3)

2024年上半年信息系统项目管理师 ——综合知识真题题目及答案&#xff08;第1批次&#xff09;&#xff08;3&#xff09; 第41题&#xff1a;在应用集成中&#xff0c;有多个组件帮助协调连接各种应用。其中&#xff08;&#xff09;利用特定的数据结构&#xff0c;帮助开发人…

电脑硬盘里的文件能保存多久?电脑硬盘文件突然没了怎么办

在数字化时代&#xff0c;电脑硬盘作为我们存储和访问数据的重要设备&#xff0c;承载着无数珍贵的回忆、工作成果和创意灵感。然而&#xff0c;硬盘里的文件能保存多久&#xff1f;当这些文件突然消失时&#xff0c;我们又该如何应对&#xff1f;本文将深入探讨这两个问题&…

13-《鸭跖草》

鸭跖草 鸭跖草&#xff0c;拉丁学名&#xff1a;&#xff08;Commelina communis&#xff09;&#xff0c;别名碧竹子、翠蝴蝶、淡竹叶等。属粉状胚乳目、鸭跖草科、鸭跖草属一年生披散草本。鸭跖草叶形为披针形至卵状披针形&#xff0c;叶序为互生&#xff0c;茎为匍匐茎&…

实验发现AI提高了个人创造力,但降低了整体创造力

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【ingress-nginx】安装配置及Helm工具安装

【ingress-nginx】安装配置及Helm工具安装 安装时候需要用到一个工具——Helm【相当于linux中的yum工具】。 一&#xff0c;Helm安装 官网&#xff1a;https://helm.sh/docs/intro/install # 下载 wget https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz# 解压 tar -zxv…

【数据结构】初探数据结构面纱:栈和队列全面剖析

【数据结构】初探数据结构面纱&#xff1a;栈和队列全面剖析 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;数据结构 文章目录 【数据结构】初探数据结构面纱&#xff1a;栈和队列全面剖析前言一.栈1.1栈的概念及结构1.2栈的结构选择1.3栈的…

Win10工具:批量word转png图片

首先声明这个小工具是小编本人开发的&#xff0c;无任何广告&#xff0c;会员收费机制等&#xff0c;永久使用。允许公司或个人使用&#xff0c;不允许倒卖&#xff0c;否则发现后会追究法律责任&#xff0c;毕竟开发不易。工具是用python开发的。 功能非常单一&#xff0c;就…

做过的试卷怎样才能去掉答案打印

对于做过的试卷&#xff0c;如想将其打印比较难以解决的困难就是“去除打印”。当然&#xff0c;目前应用上市场上也会有很多能够去除打印的应用软件&#xff0c;如“试卷擦除宝”这是一款专业的试卷擦除软件&#xff0c;能够擦除试卷上的手写笔迹&#xff0c;并将试卷转化为电…

python:绘制一元三次函数的曲线

编写 test_x3_3x.py 如下 # -*- coding: utf-8 -*- """ 绘制函数 y x^33x4 在 -3<x<3 的曲线 """ import numpy as np from matplotlib import pyplot as plt# 用于正常显示中文标题&#xff0c;负号 plt.rcParams[font.sans-serif] […

Games101——光珊化——深度缓存——shading着色 1

深度缓存 如何解决远近的问题&#xff0c;能正确的覆盖 按照画作来说&#xff0c;先画出远处的物体&#xff0c;再画出近处的物体&#xff0c;近处会将其覆盖&#xff0c;这种算法叫做画家算法 但事实上&#xff0c;排序不仅要花更多的时间&#xff0c;而且排序并不容易&…

RIP路由协议概述

RIP【Routing Information Protocol】 RIP是为TCP/IP 环境中开发的第一个路由选择协议标准 RIP是一个【距离——矢量】路由选择协议 当路由器的更新周期为30s到来时&#xff0c;向邻居发送路由表 RIP以跳数作为唯一度量值 RIP工作原理 RIP路由协议向邻居发送整个路由表信息RI…

农场资源的获取

一、网站 资源 二、搜索土壤资源 1、找到类别&#xff0c;点击Browse Texture 2、搜索、选择 3、搜索Brown Mud Dry 4、搜索Brown Mud 三、

[web]-图片上传、文件包含-图片上传

题目内容提示&#xff1a;上传图片试试吧&#xff0c;注意统一时区问题 打开页面如图&#xff0c;源码没有过滤&#xff0c;随便输入&#xff0c;进入上传目录 根据链接可以看到是文件包含&#xff0c;可以利用编码读取源码&#xff0c;这里只列出有用页面的编码&#xff08;?…

【Hive SQL 每日一题】在线峰值人数计算

文章目录 测试数据需求说明需求实现 测试数据 -- 创建 user_activity 表 DROP TABLE IF EXISTS user_activity ; CREATE TABLE user_activity (user_id STRING,activity_start TIMESTAMP,activity_end TIMESTAMP );-- 插入数据 INSERT INTO user_activity VALUES (user1, 2024…

银河麒麟高级服务器操作系统 V10 SP3 2403

系统简介 银河麒麟高级服务器操作系统V10是一款为企业级关键业务设计的新一代自主服务器操作系统&#xff0c;它满足虚拟化、云计算、大数据等时代需求&#xff0c;具备高可靠性、安全性、性能和扩展性。该系统基于CMMI5级标准开发&#xff0c;支持多种国产处理器平台&#xf…

UDP网络通信(发送端+接收端)实例 —— Python

简介 在网络通信编程中&#xff0c;用的最多的就是UDP和TCP通信了&#xff0c;原理这里就不分析了&#xff0c;网上介绍也很多&#xff0c;这里简单列举一下各自的优缺点和使用场景 通信方式优点缺点适用场景UDP及时性好&#xff0c;快速视网络情况&#xff0c;存在丢包 与嵌入…

【JavaEE】网络编程——TCP

&#x1f921;&#x1f921;&#x1f921;个人主页&#x1f921;&#x1f921;&#x1f921; &#x1f921;&#x1f921;&#x1f921;JavaEE专栏&#x1f921;&#x1f921;&#x1f921; 文章目录 前言1.网络编程套接字1.1流式套接字(TCP)1.1.1特点1.1.2编码1.1.2.1ServerSo…