嵌入式开发学习(STC51-12-I2C/IIC)

news2024/9/23 19:25:50

内容

在数码管右3位显示数字,从0开始,按K1键将数据写入到EEPROM内保存,按K2键读取EEPROM内保存的数据,按K3键显示数据加1,按K4键显示数据清零,最大能写入的数据是255;

I2C介绍

I2C简介

I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备,是微电子通信控制领域广泛采用的一种总线标准;

它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点;

I2C总线只有两根双向信号线,一根是数据线SDA,另一根是时钟线SCL;

I2C物理层

它的物理层有如下特点:

  • 它是一个支持多设备的总线,“总线”指多个设备共用的信号线;在一个I2C通讯总线中,可连接多个I2C通讯设备,支持多个通讯主机及多个通讯从机;
  • 一个I2C总线只使用两条总线线路,一条双向串行数据线(SDA),一条串行时钟线(SCL);数据线即用来表示数据,时钟线用于数据收发同步;
  • 每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问;
  • 总线通过上拉电阻接到电源;当I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平;
  • 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线;
  • 具有三种传输模式:标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模式下可达3.4Mbit/s,但目前大多I2C设备尚不支持高速模式;
  • 连接到相同总线的IC数量受到总线的最大电容400pF限制;

I2C总线常用的术语:

  • 主机:启动数据传送并产生时钟信号的设备;
  • 从机:被主机寻址的器件;
  • 多主机:同时有多于一个主机尝试控制总线但不破坏传输;
  • 主模式:用I2CNDAT支持自动字节计数的模式;位I2CRM,I2CSTT,I2CSTP,控制数据的接收和发送;
  • 从模式:发送和接收操作都是由I2C模块自动控制的;
  • 仲裁:是一个在有多个主机同时尝试控制总线但只允许其中一个控制总线并使传输不被破坏的过程;
  • 同步:两个或多个器件同步时钟信号的过程;
  • 发送器:发送数据到总线的器件;
  • 接收器:从总线接收数据的器件;

I2C协议层

I2C的协议定义了通信的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节;

数据有效性规定

I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化;

如下图:
在这里插入图片描述
每次数据传输都以字节为单位,每次传输的字节数不受限制;

起始和终止信号

SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号;

如下图:
在这里插入图片描述
起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态;在终止信号产生后,总线就处于空闲状态;

应答响应

每当发送器件传输完一个字节的数据后,后面必须紧跟一个校验位,这个校验位是接收端通过控制SDA(数据线)来实现的,以提醒发送端数据我这边已经接收完成,数据传送可以继续进行;

这个校验位其实就是数据或地址传输过程中的响应,响应包括“应答(ACK)”和“非应答(NACK)”两种信号;

作为数据接收端时,当设备(无论主从机)接收到I2C传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号即特定的低电平脉冲,发送方会继续发送下一个数据;

若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号即特定的高电平脉冲,发送方接收到该信号后会产生一个停止信号,结束信号传输;

应答响应时序图如下:
在这里插入图片描述
每一个字节必须保证是8位长度;

数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有 9 位);

由于某种原因从机不对主机寻址信号应答时(如从机正在进行实时性的处理工作而无法接收总线上的数据),它必须将数据线置于高电平,而由主机产生一个终止信号以结束总线的数据传送;

如果从机对主机进行了应答,但在数据传送一段时间后无法继续接收更多的数据时,从机可以通过对无法接收的第一个数据字节的“非应答”通知主机,主机则应发出终止信号以结束数据的继续传送;

当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号,这个信号是由对从机的“非应答”来实现的,然后,从机释放SDA线,以允许主机产生终止信号;

这些信号中,起始信号是必需的,结束信号和应答信号都可以不要;

总线的寻址方式

I2C总线寻址按照从机地址位数可分为两种,一种是7位,另一种是10位;

采用7位的寻址字节(寻址字节是起始信号后的第一个字节)的位定义如下:
在这里插入图片描述
D7~D1位组成从机的地址;D0位是数据传送方向位,为“0”时表示主机向从机写数据,为“1”时表示主机由从机读数据;

10位寻址和7位寻址兼容,而且可以结合使用;10位寻址不会影响已有的7位寻址,有7位和10位地址的器件可以连接到相同的I2C总线;

以7位寻址为例,当主机发送了一个地址后,总线上的每个器件都将头7位与它自己的地址比较,如果一样,器件会判定它被主机寻址,其他地址不同的器件将被忽略后面
的数据信号,至于是从机接收器还是从机发送器,都由R/W位决定的;

从机的地址由固定部分和可编程部分组成;在一个系统中可能希望接入多个相同的从机,从机地址中可编程部分决定了可接入总线该类器件的最大数目;如一个从机
的7位寻址位有4位是固定位,3位是可编程位,这时仅能寻址8个同样的器件,即可以有8个同样的器件接入到该I2C总线系统中;

数据传输

I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号;

在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/W),用“0”表示主机发送(写)数据(W),“1”表示主机接收数据(R);

每次数据传送总是由主机产生的终止信号结束;但是,若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址;

在总线的一次数据传送过程中,可以有以下几种组合方式:

  • 1 主机向从机发送数据,数据传送方向在整个传送过程中不变
    在这里插入图片描述
    (注意:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送;A表示应答,A非表示非应答(高电平),S表示起始信号,P表示终止信号)

  • 2 主机在第一个字节后,立即从从机读数据
    在这里插入图片描述

  • 3 在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好相反
    在这里插入图片描述

AT24C02芯片介绍

由于51单片机没有硬件I2C接口,即使有硬件接口我们通常还是采用软件模拟I2C;

主要原因是硬件IIC设计的比较复杂,而且稳定性不怎么好,程序移植比较麻烦,而用软件模拟IIC,最大的好处就是移植方便,同一个代码兼容所有单片机,任何一个单片机只要有IO口(不需要特定IO),都可以很快的移植过去;

芯片简介

AT24C02芯片是一种EEPROM,即掉电后数据不丢失的存储芯片;

AT24C01/02/04/08/16……是一个1K/2K/4K/8K/16K位串行CMOS,内部含有128/256/512/1024/2048个8位字节,AT24C01有一个8字节页写缓冲器,AT24C02/04/08/16有一个16字节页写缓冲器;

该器件通过I2C总线接口进行操作,它有一个专门的写保护功能;

此芯片具有I2C通信接口,芯片内保存的数据在掉电情况下都不丢失,所以通常用于存放一些比较重要的数据等;

芯片管脚说明

如图所示
在这里插入图片描述
在这里插入图片描述

数据格式说明

AT24C02器件地址为7位,高4位固定为1010,低3位由A0/A1/A2信号线的电平决定;

因为传输地址或数据是以字节为单位传送的,当传送地址时,器件地址占7位,还有最后一位(最低位 R/W)用来选择读写方向,它与地址无关;

其格式如下:
在这里插入图片描述
开发板该芯片的A0/A1/A2连接到GND,所以器件地址为1010000,即0x50(未计算最低位);

如果要对芯片进行写操作时,R/W即为0,写器件地址(命令)即为0XA0;如果要对芯片进行读操作时,R/W即为1,此时读器件地址(命令)为0XA1;

开发板上也将WP引脚直接接在GND上,此时芯片允许数据正常读写;

I2C总线时序

在这里插入图片描述
在这里插入图片描述

原理图

在这里插入图片描述
由图可知,I2C总线的时钟线SCL连接P21口,数据线SDA连接P20口;

由于开发板单片机IO口默认有上拉电阻,因此该总线已经默认是高电平,无需改动;

思路

编写检测4个独立按键按下的函数,并返回对应的键值,再做出相应的应答;

编写数码管显示函数,可以选择从第几位开始显示,并根据段码数据显示对应数据;

根据I2C时序图,编写I2C的产生起始、终止、应答、非应答等信号和等待应答信号的函数,发送和接收字节数据的函数;

根据I2C的操作,编写向指定存储器地址发送和接收数据的函数;
(注意写命令为0XA0,读/接收命令为0XA1)

在主函数里,根据对应的键值,响应对应的函数,并实现对应要求;

编码

User

存放主函数程序

main.c

/*
 * @Description: 在数码管右3位显示数字,从0开始;
 按K1键将数据写入到EEPROM内保存,按K2键读取EEPROM内保存的数据,按K3键显示数据加1,按K4键显示数据清零,最大能写入的数据是255
 */
#include "public.h"
#include "24c02.h"
#include "key.h"
#include "smg.h"

#define EEPROM_ADDRESS 0 // 定义数据存入EEPROM的起始地址

void main()
{
	u8 key_temp = 0;   // 存储返回的键值
	u8 save_value = 0; // 存储从EEPROM返回的数据
	u8 save_buf[3];	   // 存储数码管要显示的数据

	while (1)
	{
		key_temp = key_scan(0);
		if (key_temp == KEY1_PRESS)
		{
			at24c02_write_one_byte(EEPROM_ADDRESS, save_value);
		}
		else if (key_temp == KEY2_PRESS)
		{
			save_value = at24c02_read_one_byte(EEPROM_ADDRESS);
		}
		else if (key_temp == KEY3_PRESS)
		{
			save_value++;
			if (save_value == 255)
				save_value = 255;
		}
		else if (key_temp == KEY4_PRESS)
		{
			save_value = 0;
		}
		save_buf[0] = save_value / 100;
		save_buf[1] = save_value % 100 / 10;
		save_buf[2] = save_value % 100 % 10;
		smg_display(save_buf, 6);
	}
}

Public

存放一些通用的程序

public.h

#ifndef _public_H
#define _public_H

#include "reg52.h"

typedef unsigned int u16; // 对系统默认数据类型进行重定义
typedef unsigned char u8;

void delay_10us(u16 ten_us);
void delay_ms(u16 ms);

#endif

public.c

#include "public.h"

/**
 * @description: 延时函数,ten_us=1时,大约延时10us
 * @param {u16} ten_us 延时倍数
 * @return {*}
 */
void delay_10us(u16 ten_us)
{
	while (ten_us--)
		;
}

/**ms延时函数,ms=1时,大约延时1ms***
 * @param {u16} ms 延时倍数
 * @return {*}
 */
void delay_ms(u16 ms)
{
	u16 i, j;
	for (i = ms; i > 0; i--)
		for (j = 110; j > 0; j--)
			;
}

App/24c02

存放写入和输出EEPROM(即at24c02芯片)的函数程序

24c02.h

#ifndef _24c02_H
#define _24c02_H

#include "public.h"

void at24c02_write_one_byte(u8 addr, u8 dat); // AT24C02指定地址写数据
u8 at24c02_read_one_byte(u8 addr);			  // AT24C02指定地址读数据
#endif

24c02.c

#include "24c02.h"
#include "iic.h"

/**
 * @description: 在AT24CXX指定地址写入一个数据
 * @param {u8} addr 写入数据的目的地址
 * @param {u8} dat 要写入的数据
 * @return {*}
 */
void at24c02_write_one_byte(u8 addr, u8 dat)
{
	iic_start();
	iic_write_byte(0XA0); // 发送写命令
	iic_wait_ack();
	iic_write_byte(addr); // 发送写地址
	iic_wait_ack();
	iic_write_byte(dat); // 发送字节
	iic_wait_ack();
	iic_stop(); // 产生一个停止条件
	delay_ms(10);
}

/**
 * @description: 在AT24CXX指定地址读出一个数据
 * @param {u8} addr 目标数据的地址
 * @return {u8} 读到的数据
 */
u8 at24c02_read_one_byte(u8 addr)
{
	u8 temp = 0;
	iic_start();
	iic_write_byte(0XA0); // 发送写命令
	iic_wait_ack();
	iic_write_byte(addr); // 发送写地址
	iic_wait_ack();
	iic_start();
	iic_write_byte(0XA1); // 进入接收模式
	iic_wait_ack();
	temp = iic_read_byte(0); // 读取字节
	iic_stop();				 // 产生一个停止条件
	return temp;			 // 返回读取的数据
}

App/iic

存放I2C相关的操作程序

iic.h

#ifndef _iic_H
#define _iic_H

#include "public.h"

// 定义EEPROM控制脚
sbit IIC_SCL = P2 ^ 1; // SCL时钟线
sbit IIC_SDA = P2 ^ 0; // SDA数据线

// IIC所有操作函数
void iic_start(void);		 // 发送IIC开始信号
void iic_stop(void);		 // 发送IIC停止信号
void iic_write_byte(u8 txd); // IIC发送一个字节
u8 iic_read_byte(u8 ack);	 // IIC读取一个字节
u8 iic_wait_ack(void);		 // IIC等待ACK信号
void iic_ack(void);			 // IIC发送ACK信号
void iic_nack(void);		 // IIC发送NACK信号

#endif

iic.c

#include "iic.h"

/**
 * @description: 产生IIC起始信号
 * @return {*}
 */
void iic_start(void)
{
	IIC_SDA = 1; // 如果把该条语句放在SCL后面,第二次读写会出现问题
	delay_10us(1);
	IIC_SCL = 1;
	delay_10us(1);
	IIC_SDA = 0; // 当SCL为高电平时,SDA由高变为低
	delay_10us(1);
	IIC_SCL = 0; // 钳住I2C总线,准备发送或接收数据
	delay_10us(1);
}

/**
 * @description: 产生IIC停止信号
 * @return {*}
 */
void iic_stop(void)
{
	IIC_SDA = 0; // 如果把该条语句放在SCL后面,第二次读写会出现问题
	delay_10us(1);
	IIC_SCL = 1;
	delay_10us(1);
	IIC_SDA = 1; // 当SCL为高电平时,SDA由低变为高
	delay_10us(1);
}

/**
 * @description: 产生ACK应答
 * @return {*}
 */
void iic_ack(void)
{
	IIC_SCL = 0;
	IIC_SDA = 0; // SDA为低电平
	delay_10us(1);
	IIC_SCL = 1;
	delay_10us(1);
	IIC_SCL = 0;
}

/**
 * @description: 产生NACK非应答
 * @return {*}
 */
void iic_nack(void)
{
	IIC_SCL = 0;
	IIC_SDA = 1; // SDA为高电平
	delay_10us(1);
	IIC_SCL = 1;
	delay_10us(1);
	IIC_SCL = 0;
}

/**
 * @description: 等待应答信号到来
 * @return {u8} 1/0:接收应答失败/接收应答成功
 */
u8 iic_wait_ack(void)
{
	u8 time_temp = 0;

	IIC_SCL = 1;
	delay_10us(1);
	while (IIC_SDA) // 等待SDA为低电平
	{
		time_temp++;
		if (time_temp > 100) // 超时则强制结束IIC通信
		{
			iic_stop();
			return 1;
		}
	}
	IIC_SCL = 0;
	return 0;
}

/**
 * @description: IIC发送一个字节
 * @param {u8} dat 要发送的字节
 * @return {*}
 */
void iic_write_byte(u8 dat)
{
	u8 i = 0;

	IIC_SCL = 0;
	for (i = 0; i < 8; i++) // 循环8次将一个字节传出,先传高再传低位
	{
		if ((dat & 0x80) > 0)
			IIC_SDA = 1;
		else
			IIC_SDA = 0;
		dat <<= 1;
		delay_10us(1);
		IIC_SCL = 1;
		delay_10us(1);
		IIC_SCL = 0;
		delay_10us(1);
	}
}

/**
 * @description: IIC读一个字节
 * @param {u8} ack ack=1时,发送ACK,ack=0,发送nACK
 * @return {u8} 应答或非应答
 */
u8 iic_read_byte(u8 ack)
{
	u8 i = 0, receive = 0;

	for (i = 0; i < 8; i++) // 循环8次将一个字节读出,先读高再传低位
	{
		IIC_SCL = 0;
		delay_10us(1);
		IIC_SCL = 1;
		receive <<= 1;
		if (IIC_SDA)
			receive++;
		delay_10us(1);
	}
	if (!ack)
		iic_nack();
	else
		iic_ack();

	return receive;
}

App/key

存放独立按键操作程序

key.h

#ifndef _key_H
#define _key_H

#include "public.h"

// 定义独立按键控制脚
sbit KEY1 = P3 ^ 1;
sbit KEY2 = P3 ^ 0;
sbit KEY3 = P3 ^ 2;
sbit KEY4 = P3 ^ 3;

// 使用宏定义独立按键按下的键值
#define KEY1_PRESS 1
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY_UNPRESS 0

u8 key_scan(u8 mode);

#endif

key.c

#include "key.h"

/**
 * @description: 检测独立按键是否按下,按下则返回对应键值
 * @param {u8} mode mode=0:单次扫描按键,mode=1:连续扫描按键
 * @return {u8} k1到k5的键值1-5,0表示没有按键按下
 */
u8 key_scan(u8 mode)
{
	static u8 key = 1;

	if (mode)
		key = 1;														// 连续扫描按键
	if (key == 1 && (KEY1 == 0 || KEY2 == 0 || KEY3 == 0 || KEY4 == 0)) // 任意按键按下
	{
		delay_10us(1000); // 消抖
		key = 0;
		if (KEY1 == 0)
			return KEY1_PRESS;
		else if (KEY2 == 0)
			return KEY2_PRESS;
		else if (KEY3 == 0)
			return KEY3_PRESS;
		else if (KEY4 == 0)
			return KEY4_PRESS;
	}
	else if (KEY1 == 1 && KEY2 == 1 && KEY3 == 1 && KEY4 == 1) // 无按键按下
	{
		key = 1;
	}
	return KEY_UNPRESS;
}

App/smg

存放数码管显示控制程序

smg.h

#ifndef _smg_H
#define _smg_H

#include "public.h"

#define SMG_A_DP_PORT P0 // 使用宏定义数码管段码口

// 定义数码管位选信号控制脚
sbit LSA = P2 ^ 2;
sbit LSB = P2 ^ 3;
sbit LSC = P2 ^ 4;

void smg_display(u8 dat[], u8 pos);

#endif

smg.c

#include "smg.h"

// 共阴极数码管显示0~F的段码数据
u8 gsmg_code[17] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};

/**
 * @description: 动态数码管显示函数
 * @param {u8} dat 要显示的数据
 * @param {u8} pos 从左开始第几个位置开始显示,范围1-8
 * @return {*}
 */
void smg_display(u8 dat[], u8 pos)
{
	u8 i = 0;
	u8 pos_temp = pos - 1;

	for (i = pos_temp; i < 8; i++)
	{
		switch (i) // 位选
		{
		case 0:
			LSC = 1;
			LSB = 1;
			LSA = 1;
			break;
		case 1:
			LSC = 1;
			LSB = 1;
			LSA = 0;
			break;
		case 2:
			LSC = 1;
			LSB = 0;
			LSA = 1;
			break;
		case 3:
			LSC = 1;
			LSB = 0;
			LSA = 0;
			break;
		case 4:
			LSC = 0;
			LSB = 1;
			LSA = 1;
			break;
		case 5:
			LSC = 0;
			LSB = 1;
			LSA = 0;
			break;
		case 6:
			LSC = 0;
			LSB = 0;
			LSA = 1;
			break;
		case 7:
			LSC = 0;
			LSB = 0;
			LSA = 0;
			break;
		}
		SMG_A_DP_PORT = gsmg_code[dat[i - pos_temp]]; // 传送段选数据
		delay_10us(100);							  // 延时一段时间,等待显示稳定
		SMG_A_DP_PORT = 0x00;						  // 消影
	}
}

编译和结果

按F7编译,无错误,生成.hex文件,使用pz-isp将hex文件下载到单片机

结果:在数码管右3位显示数字,从0开始,按K1键写入数据,按K2键读取数据,按K3键显示数据加1,按K4键显示数据清零,最大能写入的数据是255;
在这里插入图片描述

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

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

相关文章

CNN成长路:从AlexNet到EfficientNet(01)

一、说明 在 10年的深度学习中&#xff0c;进步是多么迅速&#xff01;早在 2012 年&#xff0c;Alexnet 在 ImageNet 上的准确率就达到了 63.3% 的 Top-1。现在&#xff0c;我们超过90%的EfficientNet架构和师生训练&#xff08;teacher-student&#xff09;。 如果我们在 Ima…

echarts 饼图的label放置于labelLine引导线上方

一般的饼图基础配置后长这样。 想要实现将文本放置在引导线上方&#xff0c;效果长这样 const options {// ...series: [{label: {padding: [0, -40],},labelLine: {length: 10,length2: 50,},labelLayout: {verticalAlign: "bottom",dy: -10,},},], };label.padd…

2配置篇:基础功能配置

前言 在上一章节中,我们学习了 NestJS CLI 的用法,得到了一套基础的项目工程。最开始做项目对比的时候也提到过,NestJS 作为一款自定义程度较高的框架,CLI 直接提供的基础功能虽然并不完善,但同时也为开发者提供了非常多的内置或配套的功能例如高速缓存、日志拦截、过滤器…

栈和队列(一) 栈操作详解

文章目录 一、物理结构和逻辑结构二、栈1、什么是栈2、栈中一些基本操作的实现Stack.hStack.c栈的初始化栈的销毁入栈出栈获得栈顶元素获得栈的元素数判断栈空 三、利用栈解决问题 一、物理结构和逻辑结构 栈和队列都属于逻辑结构&#xff0c;它们既可以用数组实现也可以用链表…

【小沐学前端】VuePress制作在线电子书、技术文档(VuePress + Markdown + node)

文章目录 1、简介1.1 VuePress简介1.2 它是如何工作的&#xff1f; 2、安装node3、安装VuePress4、配置VuePress4.1 修改标题4.2 修改导航条4.3 修改右侧栏4.4 修改正文 结语 1、简介 Vue驱动的静态网站生成器&#xff0c;生成的网页内容放到自己服务器上管理&#xff0c;可用于…

极光笔记 | 浅谈企业级SaaS产品的客户成长旅程管理(上)—— 分析篇

本文作者&#xff1a;陈伟&#xff08;极光用户体验部高级总监&#xff09; “企业级SaaS产品与C端互联网产品特征差异很大&#xff0c;有些甚至是截然相反&#xff0c;这些特征也会成为后续客户成长旅程的重要影响变量。本文就如何设计并服务好企业级SaaS产品客户成长旅程进行…

VUE之JWT前后端分离认证,学生管理系统

参考资料: SpringBoot搭建教程 SpringCloud搭建教程 JWT视频教程 JWT官网 Vue视频教程 JWT视频参考资料、VUE视频资料,及前后端demo 特别有参考价值的JWT博客1 特别有参考价值的JWT博客2 cookie、localstorage和sessionStorage的区别1 cookie、localstorage和sessi…

第1章 什么是JavaScript

引言 JavaScript最早诞生的原因是希望表单验证可以在客户端得到解决。频繁通过服务端的请求来验证表单缓慢的网速让页面每次刷新都考验着人们的耐心。 如今的js不再局限简单的表单验证&#xff0c;能够实现复杂的计算与交互&#xff0c;包括闭包、匿名&#xff08;lambda&…

Android Glide MemorySizeCalculator计算值,Kotlin

Android Glide MemorySizeCalculator计算值,Kotlin for (i in 100..1000 step 50) {val calculator MemorySizeCalculator.Builder(this).setMemoryCacheScreens(i.toFloat()).setBitmapPoolScreens(i.toFloat()).setMaxSizeMultiplier(0.8f).setLowMemoryMaxSizeMultiplier(0…

使用U盘重装Windows10系统详细步骤及配图【官方纯净版】

文章目录 1.制作启动盘1.1准备U盘及一台电脑1.2下载win10安装包 2.安装操作系统2.1插入系统安装盘2.2设置启动盘为第一启动项2.3开始安装操作系统 3.安装成功后进入图形界面3.1启动问题3.2驱动问题3.3调出"控制面板"3.4给磁盘分区 4.win10激活 前天下午不知道怎么想的…

springBean生命周期解析

本文基于Spring5.3.7 参考&#xff1a; kykangyuky Spring中bean的生命周期 阿斌Java之路 SpringBean的生命周期&#xff0c; 杨开振 JavaEE互联网轻量级框架整合开发 黑马程序员 JavaEE企业级应用开发教程 马士兵 Spring源码讲解 一. SpringBean生命周期流程图 二. 示例代码 …

升级到mybatis-plus,系统启动的一些问题

在分表后mybatis-plus删除操作失效等问题处理 mybatis-plus 旧系统重构遇到的种种问题 在这三篇文章中&#xff0c;我花了近1个月时间重构了28个微服务&#xff0c;当中遇到的一些问题&#xff0c;但是发布到pretest环境&#xff0c;却还有启动问题&#xff0c;看来系统重构不是…

变压器参数测定中空载实验和短路实验的理解

确定变压器的参数是在《电机学》和《电力系统分析》中非常重要的一个环节&#xff0c;这里用自己习惯的方式讲一下怎样理解 首先要讲下变压器的额定参数&#xff0c;这个也是个常考的知识点 额定功率&#xff0c;即视在功率&#xff0c;电压电流&#xff0c;单位是VA或者kVA额…

【docker】dockerfile发布springboot项目

目录 一、实现步骤二、示例 一、实现步骤 1.定义父镜像&#xff1a;FROM java:8 2.定义作者信息&#xff1a;MAINTAINER&#xff1a;learn_docker<https://www.docker.com> 3.将jar包添加到容器&#xff1a;ADD jar包名称.jar app.jar 4.定义容器启动执行命令&#xff1a…

在tensorflow分布式训练过程中突然终止(终止)

问题 这是为那些将从服务器接收渐变的员工提供的培训功能&#xff0c;在计算权重和偏差后&#xff0c;将更新的渐变发送到服务器。代码如下&#xff1a; def train():"""Train CIFAR-10 for a number of steps."""g1 tf.Graph()with g1.as_de…

不规则文件转JSON

需求分析&#xff1a; 有时候&#xff0c;我们取出来的数据并不是一个规则的JSON文件&#xff0c;这个时候面对存库还是ES检索都是一个问题&#xff0c;所以我们就需要进行解析&#xff0c;然而用字符串分割是不现实的&#xff0c;我们需要一种快速的方法。 问题解决&#x…

设计模式行为型——备忘录模式

目录 什么是备忘录模式 备忘录模式的实现 备忘录模式角色 备忘录模式类图 备忘录模式举例 备忘录模式代码实现 备忘录模式的特点 优点 缺点 使用场景 注意事项 实际应用 什么是备忘录模式 备忘录模式&#xff08;Memento Pattern&#xff09;又叫做快照模式&#x…

ant.design 组件库中的 Tree 组件实现可搜索的树: React+and+ts

ant.design 组件库中的 Tree 组件实现可搜索的树&#xff0c;在这里我会详细介绍每个方法&#xff0c;以及容易踩坑的点。 效果图&#xff1a; 首先是要导入的文件 // React 自带的属性 import React, { useMemo, useState } from react; // antd 组件库中的&#xff0c;输入…

VSCode插件Todo Tree的使用

在VSCode中安装插件Todo Tree。按下快捷键ctrlshiftP&#xff0c;输入setting.jspn&#xff0c;选择相应的配置范围&#xff0c;我们选择的是用户配置 Open User Settings(JSON)&#xff0c;将以下代码插入其中。 //todo-tree 标签配置从这里开始 标签兼容大小写字母(很好的功…

JAVA方向的大数据包含啥内容?

文章目录 大数据是啥大数据就业方向知识体系HadoophiveHBaseSparkScala 总结 大数据是啥 你了解到的大数据是啥样子&#xff1f; 还是… 大数据(big data)&#xff0c;或称巨量资料&#xff0c;指的是所涉及的资料量规模巨大到无法透过主流软件工具&#xff0c;在合理时间…