IIC 实验

news2024/12/24 22:10:19

IIC 简介

IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微 控制器以及其外围设备。它是由数据线 SDA 和时钟线 SCL 构成的串行总线,可发送和接收数 据,在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送。

IIC 总线有如下特点:

①总线由数据线 SDA 和时钟线 SCL 构成的串行总线,数据线用来传输数据,时钟线用来 同步数据收发。

②总线上每一个器件都有一个唯一的地址识别,所以我们只需要知道器件的地址,根据时 序就可以实现微控制器与器件之间的通信。

③数据线 SDA 和时钟线 SCL 都是双向线路,都通过一个电流源或上拉电阻连接到正的电 压,所以当总线空闲的时候,这两条线路都是高电平。

④总线上数据的传输速率在标准模式下可达 100kbit/s 在快速模式下可达 400kbit/s 在高速 模式下可达 3.4Mbit/s。

⑤总线支持设备连接。在使用 IIC 通信总线时,可以有多个具备 IIC 通信能力的设备挂载 在上面,同时支持多个主机和多个从机,连接到总线的接口数量只由总线电容 400pF 的限制决 定。

IIC 总线挂载多个器件的示意图,如下图所示:下面来学习 IIC 总线协议,IIC 总线时序图如下所示:

 为了便于大家更好的了解 IIC 协议,我们从起始信号、停止信号、应答信号、数据有效性、 数据传输以及空闲状态等 6 个方面讲解。

① 起始信号

当 SCL 为高电平期间,SDA 由高到低的跳变,起始信号是一种电平跳变时序信号,而不是 一个电平信号。该信号由主机发出,在起始信号产生后,总线就处于被占用状态,准备数据传 输。

② 停止信号

当 SCL 为高电平期间,SDA 由低到高的跳变;停止信号也是一种电平跳变时序信号,而不 是一个电平信号。该信号由主机发出,在停止信号发出后,总线就处于空闲状态。

③ 应答信号

发送器每发送一个字节,就在时钟脉冲 9 期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK 简称应答位),表示接收器已经成功地接收了 该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成 功。

观察上图就可以发现,有效应答的要求是从机在第 9 个时钟脉冲之前的低电平期间 将 SDA 线拉低,并且确保在该时钟的高电平期间为稳定的低电平。如果接收器是主机,则在它 收到最后一个字节后,发送一个 NACK 信号,以通知被控发送器结束数据发送,并释放 SDA 线,以便主机接收器发送一个停止信号。

④ 数据有效性

IIC 总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在 时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。数据在 SCL 的上 升沿到来之前就需准备好。并在下降沿到来之前必须稳定。

⑤ 数据传输

在 IIC 总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在 SCL 串行 时钟的配合下,在 SDA 上逐位地串行传送每一位数据。数据位的传输是边沿触发。

⑥ 空闲状态

IIC 总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个 器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉 高。

 了解前面的知识后,下面介绍一下 IIC 的基本的读写通讯过程,包括主机写数据到从机即 写操作,主机到从机读取数据即读操作。下面先看一下写操作通讯过程图,见图 34.1.3.2 所示:

主机首先在 IIC 总线上发送起始信号,那么这时总线上的从机都会等待接收由主机发出的 数据。主机接着发送从机地址+0(写操作)组成的 8bit 数据,所有从机接收到该 8bit 数据后,自行检验是否是自己的设备的地址,假如是自己的设备地址,那么从机就会发出应答信号。主机 在总线上接收到有应答信号后,才能继续向从机发送数据。注意:IIC 总线上传送的数据信号 是广义的,既包括地址信号,又包括真正的数据信号。

接着讲解一下 IIC 总线的读操作过程,先看一下读操作通讯过程图,见图 34.1.3.3 所示。

主机向从机读取数据的操作,一开始的操作与写操作有点相似,观察两个图也可以发现, 都是由主机发出起始信号,接着发送从机地址+1(读操作)组成的 8bit 数据,从机接收到数据验 证是否是自身的地址。 那么在验证是自己的设备地址后,从机就会发出应答信号,并向主机返 回 8bit 数据,发送完之后从机就会等待主机的应答信号。假如主机一直返回应答信号,那么从 机可以一直发送数据,也就是图中的(n byte + 应答信号)情况,直到主机发出非应答信号,从 机才会停止发送数据。

AT24C02 简介

24C02 是一个 2K bit 的串行 EEPROM 存储器,内部含有 256 个字节。在 24C02 里面还有 一个 8 字节的页写缓冲器。该设备的通信方式 IIC,通过其 SCL 和 SDA 与其他设备通信。

上图的 WP 引脚是写保护引脚,接高电平只读,接地允许读和写,我们的板子设计是把该 引脚接地。每一个设备都有自己的设备地址,24C02 也不例外,但是 24C02 的设备地址是包括 不可编程部分和可编程部分,可编程部分是根据上图的硬件引脚 A0、A1 和 A2 所决定。设备 地址最后一位用于设置数据的传输方向,即读操作/写操作,0 是写操作,1 是读操作。根据我们的板子设计,A0、A1 和 A2 均接地处理,所以 24C02 设备的读操作地址为:0xA1; 写操作地址为:0xA0。

 

上图展示的主机向 24C02 写操作时序图,主机在 IIC 总线发送第 1 个字节的数据为 24C02 的设备地址 0xA0,用于寻找总线上找到 24C02,在获得 24C02 的应答信号之后,继续发送第 2 个字节数据,该字节数据是 24C02 的内存地址,再等到 24C02 的应答信号,主机继续发送 第 3 字节数据,这里的数据即是写入在第 2 字节内存地址的数据。主机完成写操作后,可以发 出停止信号,终止数据传输。 

 24C02 读取数据的过程是一个复合的时序,其中包含写时序和读时序。先看第一个通信过 程,这里是写时序,起始信号产生后,主机发送 24C02 设备地址 0xA0,获取从机应答信号后, 接着发送需要读取的内存地址;在读时序中,起始信号产生后,主机发送 24C02 设备地址 0xA1, 获取从机应答信号后,接着从机返回刚刚在写时序中内存地址的数据,以字节为单位传输在总 线上,假如主机获取数据后返回的是应答信号,那么从机会一直传输数据,当主机发出的是非 应答信号并以停止信号发出为结束,从机就会结束传输。

目前大部分 MCU 都带有 IIC 总线接口,STM32F1 也不例外。但是这里我们不使用 STM32F1 的硬件 IIC 来读写 24C02,而是通过软件模拟。ST 为了规避飞利浦 IIC 专利问题,将 STM32 的 硬件 IIC 设计的比较复杂,而且稳定性不怎么好,所以这里我们不推荐使用。有兴趣的读者可 以自行研究 STM32F1 的硬件 IIC 的使用。

用软件模拟 IIC,最大的好处就是方便移植,同一个代码兼容所有 MCU,任何一个单片机只要 有 IO 口,就可以很快的移植过去,而且不需要特定的 IO 口。而硬件 IIC,则换一款 MCU,基 本上就得重新移植,这也是我们推荐使用软件模拟 IIC 的另外一个原因。

代码

#include "./BSP/IIC/iic.h"
#include "./SYSTEM/delay/delay.h"

/* 初始化IIC */
void iic_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};
    
    __HAL_RCC_GPIOB_CLK_ENABLE();/* SCL,SDA引脚时钟使能 */
    
    gpio_init_struct.Pin = GPIO_PIN_6;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;/* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;/* 上拉 */
    gpio_init_struct.Speed =  GPIO_SPEED_FREQ_HIGH;/* 高速 */
    HAL_GPIO_Init(GPIOB, &gpio_init_struct);/* SCL */
    
    gpio_init_struct.Pin = GPIO_PIN_7;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;/* 开漏输出 */
    HAL_GPIO_Init(GPIOB, &gpio_init_struct);/* SDA */
    /* SDA引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */

    iic_stop();/* 停止总线上所有设备 */
}

/* IIC延时函数,用于控制IIC读写速度 */
static void iic_delay(void)
{
    delay_us(2);/* 2us的延时, 读写速度在250Khz以内 */
}

/* 产生IIC起始信号 */
void iic_start(void)
{
    IIC_SCL(1);
    IIC_SDA(1);
    iic_delay();
    IIC_SDA(0);/* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */
    iic_delay();
    IIC_SCL(0);/* 钳住I2C总线,准备发送或接收数据 */
    iic_delay();
}

/* 产生IIC停止信号 */
void iic_stop(void)
{
    IIC_SDA(0);/* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(1);/* 发送I2C总线结束信号 */
    iic_delay();
}

/**
 * @brief       等待应答信号到来
 * @param       无
 * @retval      1,接收应答失败
 *              0,接收应答成功
 */
uint8_t iic_wait_ack(void)
{
    uint8_t waittime = 0;
    uint8_t rack = 0;
    
    IIC_SDA(1);/* 主机释放SDA线(此时外部器件可以拉低SDA线) */
    iic_delay();
    IIC_SCL(1);/* SCL=1, 此时从机可以返回ACK */
    iic_delay();
    
    while(IIC_READ_SDA)/* 等待应答 */
    {
        waittime++;
        
        if(waittime > 250)
        {
            iic_stop();
            rack = 1;
            break;
        }
    }
    
    IIC_SCL(0);/* SCL=0, 结束ACK检查 */
    iic_delay();
    
    return rack;
}

/* 产生ACK应答 */
void iic_ack(void)
{
    IIC_SDA(0);/* SCL 0 -> 1  时 SDA = 0,表示应答 */
    iic_delay();
    IIC_SCL(1);/* 产生一个时钟 */
    iic_delay();
    IIC_SCL(0);
    iic_delay();
    IIC_SDA(1);/* 主机释放SDA线 */
    iic_delay();
}

/* 不产生ACK应答 */
void iic_nack(void)
{
    IIC_SDA(1);/* SCL 0 -> 1  时 SDA = 1,表示不应答 */
    iic_delay();
    IIC_SCL(1);/* 产生一个时钟 */
    iic_delay();
    IIC_SCL(0);
    iic_delay();
}

/*IIC发送一个字节*/
void iic_send_byte(uint8_t data)
{
    uint8_t t;
    
    for(t = 0; t < 8; t++)
    {
        IIC_SDA((data & 0x80) >> 7);/* 高位先发送 */
        iic_delay();
        IIC_SCL(1);
        iic_delay();
        IIC_SCL(0);
        data <<= 1;/* 左移1位,用于下一次发送 */
    }
    
    IIC_SDA(1);/* 发送完成, 主机释放SDA线 */
}

/**
 * @brief       IIC读取一个字节
 * @param       ack:  ack=1时,发送ack; ack=0时,发送nack
 * @retval      接收到的数据
 */
uint8_t iic_read_byte(uint8_t ack)
{
    uint8_t i, receive = 0;
    
    for(i = 0; i < 8; i++)/* 接收1个字节数据 */
    {
        receive <<= 1;/* 高位先输出,所以先收到的数据位要左移 */
        
        IIC_SCL(1);
        iic_delay();
        
        if(IIC_READ_SDA)
        {
            receive ++;
        }
        
        IIC_SCL(0);
        iic_delay();
    }
    
    if(!ack)
    {
        iic_nack();/* 发送nACK */
    }
    else
    {
        iic_ack();/* 发送ACK */
    }
    
    return receive;
}

在 iic_init 函数中主要工作就是对于 GPIO 的初始化,用于 iic 通信,不过这里需要注意的 一点是 SDA 线的 GPIO 模式使用开漏模式,同时需要注意:STM32F103 必须要外接上拉电阻!

在这里首先定义一个 iic_delay 函数,目的就是控制 IIC 的读写速度,通过示波器检测读写 速度在 250KHz 内,所以一秒钟传送 500Kb 数据,换算一下即一个 bit 位需要 2us,在这个延时 时间内可以让器件获得一个稳定性的数据采集。

 iic_start 函数中,通过调用 myiic.h 中通过宏定义好的可以输出高低电平的 SCL 和 SDA 来 模拟 iic 总线中起始信号的发送,在 SCL 时钟线为高电平的时候,SDA 数据线从高电平状态转 化到低电平状态,最后拉低时钟线,准备发送或者接收数据。

 iic_stop 函数中,也是按着模拟 iic 总线中停止信号的逻辑,在 SCL 时钟线为高电平的时候, SDA 数据线从低电平状态转化到高电平状态。

在 iic 的发送函数 iic_send_byte 中,我们把需要发送的数据作为形参,形参大小为 1 个字 节。在 iic 总线传输中,一个时钟信号就发送一个 bit,所以该函数需要循环八次,模拟八个时 钟信号,才能把形参的 8 个位数据都发送出去。这里使用的是形参 data 和 0x80 与运算的方式, 判断其最高位的逻辑值,假如为 1 即需要控制 SDA 输出高电平,否则为 0 控制 SDA 输出低电 平。

通过上图就可以很清楚了解数据传输时的细节,经过第一步的 SDA 高低电平的确定后,接 着需要延时,确保 SDA 输出的电平稳定,在 SCL 保持高电平期间,SDA 线上的数据是有效的, 此过程也是需要延时,使得从设备能够采集到有效的电平。然后准备下一位的数据,所以这里 需要的是把 data 左移一位,等待下一个时钟的到来,从设备进行读取。把上述的操作重复 8 次 就可以把 data 的 8 个位数据发送完毕,循环结束后,把 SDA 线拉高,等待接收从设备发送过 来的应答信号。

iic_read_byte 函数具体实现的方式跟 iic_send_byte 函数有所不同。首先可以明确的是时钟 信号是通过主机发出的,而且接收到的数据大小为 1 字节,但是 IIC 传输的单位是 bit,所以就 需要执行 8 次循环,才能把一字节数据接收完整。

具体实现过程:首先需要一个变量 receive 存放接收到的数据,在每一次循环开始前都需要 对 receive 进行左移 1 位操作,那么 receive 的 bit0 位每一次赋值前都是空的,用来存放最新接 收到的数据位,然后在 SCL 线进行高低电平切换时输出 IIC 时钟,在 SCL 高电平期间加入延 时,确保有足够的时间能让数据发送并进行处理,使用宏定义 IIC_READ_SDA 就可以判断读取 到的高低电平,假如 SDA 为高电平,那么 receive++即在 bit0 置 1,否则不做处理即保持原来的 0 状态。当 SCL 线拉低后,需要加入延时,便于从机切换 SDA 线输出数据。在 8 次循环结束 后,我们就获得了 8bit 数据,把它作为返回值返回,然而按照时序图,作为主机就需要发送应 答或者非应答信号,去回复从机。

首先先讲解一下 iic_wait_ack 函数,该函数主要用在写时序中,当启动起始信号,发送完 8bit 数据到从机时,我们就需要等待以及处理接收从机发送过来的响应信号或者非响应信号, 一般就是在 iic_send_byte 函数后面调用。

具体实现:首先先释放 SDA,把电平拉高,延时等待从机操作 SDA 线,然后主机拉高时 钟线并延时,确保有充足的时间让主机接收到从机发出的 SDA 信号,这里使用的是 IIC_READ_SDA 宏定义去读取,根据 IIC 协议,主机读取 SDA 的值为低电平,就表示“应答信 号”;读到 SDA 的值为高电平,就表示“非应答信号”。在这个等待读取的过程中加入了超时判 断,假如超过这个时间没有接收到数据,那么主机直接发出停止信号,跳出循环,返回等于 1的变量。在正常等待到应答信号后,主机会把 SCL 时钟线拉低并延时,返回是否接收到应答信 号。

当主机作为作为接收端时,调用 iic_read_byte 函数之后,按照 iic 通信协议,需要给从机返 回应答或者是非应答信号,这里就是用到了 iic_ack 和 iic_nack 函数。

具体实现:从上面的说明已经知道了 SDA 为低电平即应答信号,高电平即非应答信号,那 么还是老规矩,首先先根据返回“应答”或者“非应答”两种情况拉低或者拉高 SDA,并延时 等待 SDA 电平稳定,然后主机拉高 SCL 线并延时,确保从机能有足够时间去接收 SDA 线上的 电平信号。然后主机拉低时钟线并延时,完成这一位数据的传送。最后把 SDA 拉高,呈高阻态, 方便后续通信用到。 

#include "./BSP/24CXX/24cxx.h"
#include "./BSP/IIC/iic.h"
#include "./SYSTEM/delay/delay.h"

/* 初始化AT24C02 */
void at24c02_init(void)
{
    iic_init();
}

void at24c02_write_one_byte(uint8_t addr, uint8_t data)
{
    /* 1. 发送起始信号 */
    iic_start();
    
    /* 2. 发送通讯地址(写操作地址) */
    iic_send_byte(0xa0);
    
    /* 3. 等待应答信号 */
    iic_wait_ack();
    
    /* 4. 发送内存地址 */
    iic_send_byte(addr);
    
    /* 5. 等待应答信号 */
    iic_wait_ack();
    
    /* 6. 发送写入数据 */
    iic_send_byte(data);
    
    /* 7. 等待应答信号*/
    iic_wait_ack();
    
    /* 8. 发送停止信号 */
    iic_stop();
    
    /* 9. 等待EEPROM写入完成 */
    delay_ms(10);
}

uint8_t at24c02_read_one_byte(uint8_t addr)
{
    uint8_t rec = 0;
    
    /* 1. 发送起始信号 */
    iic_start();
    
    /* 2. 发送通讯地址(写操作地址) */
    iic_send_byte(0xa0);
    
    /* 3. 等待应答信号 */
    iic_wait_ack();
    
    /* 4. 发送内存地址 */
    iic_send_byte(addr);
    
    /* 5. 等待应答信号 */
    iic_wait_ack();
    
    /* 6. 发送起始信号 */
    iic_start();
    
    /* 7. 发送通讯地址(读操作地址) */
    iic_send_byte(0xa1);
    
    /* 8. 等待应答信号 */
    iic_wait_ack();
    
    /* 9. 等待接收数据 */
    rec = iic_read_byte(0);
    
    /* 10. 发送停止信号 */
    iic_stop();
    
    return rec;
}

下面先看一下 at24cxx_write_one_byte 函数,实现在 AT24Cxx 芯片指定地址写入一个 数据 。

该函数的操作流程跟前面已经分析过的 24C02 单字节写时序一样,首先调用 iic_start 函数 产生起始信号,然后调用 iic_send_byte 函数发送第 1 个字节数据设备地址,等待 24Cxx 设备返 回应答信号;收到应答信号后,继续发送第 2 个 1 字节数据内存地址 addr;等待接收应答后, 最后发送第 3 个字节数据写入内存地址的数据 data,24Cxx 设备接收完数据,返回应答信号, 主机调用 iic_stop 函数产生停止信号终止数据传输,最终需要延时 10ms,等待 eeprom 写入完 毕。 

接下来看一下 at24cxx_read_one_byte 函数。

这里的函数的实现跟前面第 34.1.4 小节 24C02 数据传输中的读时序一致,主机首先调用 iic_start 函数产生起始信号,然后调用 iic_send_byte 函数发送第 1 个字节数据设备写地址,使用 iic_wait_ack 函数等待 24Cxx 设备返回应答信号;收到应答信号后,继续发送第 2 个 1 字节数 据内存地址 addr;等待接收应答后,重新调用 iic_start 函数产生起始信号,这一次的设备方向 改变了,调用 iic_send_byte 函数发送设备读地址,然后使用 iic_wait_ack 函数去等待设备返回 应答信号,同时使用 iic_read_byte 去读取从从机发出来的数据。由于 iic_read_byte 函数的形参 是 0,所以在获取完 1 个字节的数据后,主机发送非应答信号,停止数据传输,最终调用 iic_stop 函数产生停止信号,返回从从机 addr 中读取到的数据。

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/24CXX/24cxx.h"

int main(void)
{
    uint8_t t = 0;
    uint8_t key = 0;
    uint8_t receive1 = 0, receive2 = 0;
    
    HAL_Init();                         /* 初始化 HAL 库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    usart_init(115200);                 /* 传口初始化 */
    
    led_init();                         /* LED初始化 */
    lcd_init();                         /* LCD初始化 */
    key_init();                         /* KEY初始化 */
    at24c02_init();                     /* AT24C02初始化 */
    
    lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
    lcd_show_string(30, 70, 200, 16, 16, "IIC TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "KEY0:Write  KEY1:Read", RED);    /* 显示提示信息 */
    lcd_show_string(30, 130, 200, 16, 16, "24C02 Ready!", RED);
    while(1)
    {
        key = key_scan(0);
        if(key == KEY0_PRES)
        {
            at24c02_write_one_byte(10, 66);
            lcd_show_string(30, 150, 200, 16, 16, "Data1 Write Finished!", BLUE);   /* 提示传送完成 */
            
            at24c02_write_one_byte(100, 124);
            lcd_show_string(30, 170, 200, 16, 16, "Data2 Write Finished!", BLUE);   /* 提示传送完成 */
        }
        if(key == KEY1_PRES)
        {
            receive1 = at24c02_read_one_byte(10);
            lcd_show_string(30, 150, 200, 16, 16, "The Data1 Readed Is:", BLUE);   /* 提示传送完成 */
            lcd_show_xnum(30 + 20 * 8, 150, receive1, 3, 16, 0, BLUE); /* 显示读取的值 */
            
            receive2 = at24c02_read_one_byte(100);
            lcd_show_string(30, 170, 200, 16, 16, "The Data2 Readed Is:", BLUE);   /* 提示传送完成 */
            lcd_show_xnum(30 + 20 * 8, 170, receive2, 3, 16, 0, BLUE); /* 显示读取的值 */
        }
        
        t++;
        if(t == 20)
        {
            t = 0;
            LED1_TOGGLE();
        }
        delay_ms(10);
    }
}

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

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

相关文章

VBA之Word应用:文档(Document)的书签

《VBA之Word应用》&#xff08;版权10178982&#xff09;&#xff0c;是我推出第八套教程&#xff0c;教程是专门讲解VBA在Word中的应用&#xff0c;围绕“面向对象编程”讲解&#xff0c;首先让大家认识Word中VBA的对象&#xff0c;以及对象的属性、方法&#xff0c;然后通过实…

虚拟机配置完NAT模式之后可以和主机ping通但是ping 百度显示:网络不可达

具体linux网络配置看这&#xff1a;http://t.csdnimg.cn/KRami 解决方案如下&#xff1a; 如果这里网关为空&#xff0c;那么和我遇到的问题一样网关没有设置上&#xff0c;在这直接配置网关之后重启即可

java--贪吃蛇

import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.Random;public class Snake extends JFrame implements KeyListener, ActionListener, MouseListener {int slong 2;//蛇当前长度//蛇坐标int[] Snakex new int[100];int[] Snakey new…

Google codelab WebGPU入门教程源码<2> - 绘制几何形状(源码)

对应的教程文章: https://codelabs.developers.google.com/your-first-webgpu-app?hlzh-cn#3 源码执行效果: 对应的教程源码: 此处源码和教程本身提供的部分代码可能存在一点差异。 class Color4 {r: number;g: number;b: number;a: number;constructor(pr 1.0, pg 1.0, …

Nginx(七) root和alias的区别及详细测试

本篇文章只讲root和alias的区别&#xff0c;配置文件详解请参考 Nginx(三) 配置文件详解&#xff0c;下面开始进行测试。 Nginx配置如下&#xff1a; server {listen 8688 default_server;server_name www.read******.cn;access_log logs/access.log format2;root pages;set …

【信息安全】浅谈SQL注入攻击的概念、原理和防范措施:简单分析六种常见攻击方式

银狼美图镇楼 用户登录 在开发Web应用程序时&#xff0c;用户登录是一个非常常见的功能。然而&#xff0c;不安全的用户登录功能可能会导致安全漏洞&#xff0c;例如SQL注入和跨站脚本攻击。 SQL注入 SQL注入是一种常见的攻击技术&#xff0c;攻击者通过在用户输入的数据中插…

BGP基本配置

配置逻辑 完成所有路由器的IGP配置使用直连接口建立EBGP对等体关系使用环回接口建立IBGP对等体关系使用connect-interface命令修改IBGP建邻源IP地址使用next-hop-local命令修改路由传递时的下一跳属性若存在使用环回接口建立EBGP对等体关系&#xff0c;则需要建立通讯条件&…

FastJson竟然会导致内存泄露?你遇到过吗?

FastJson是一款性能优异的java序列化和反序列框架&#xff0c;广泛应用于日常开发工作中&#xff0c;也许正是因为作者在设计这款框架时&#xff0c;比较注重性能方面的考量&#xff0c;在框架安全性&#xff0c;空间占用等方面做了一些牺牲。 很不幸小编前两天就遇到了一个使…

Ubuntu中apt-get update显示域名解析失败

第一步 检查主机->虚拟机能否ping成功 ping 红色框中的IPv4地址 能通&#xff0c;表示虚拟机ip配置成功;否则&#xff0c;需要先配置虚拟机ip 第二步 检查是否能ping成功百度网址 ping www.baidu.com 若不成功&#xff0c;可能原因 虚拟机没联网&#xff0c;打开火狐浏览器…

go学习之简单项目

项目 文章目录 项目1.项目开发流程图2.家庭收支记账软件项目2&#xff09;项目代码实现3&#xff09;具体功能实现 3.客户信息管理系统1&#xff09;项目需求说明2&#xff09;界面设计3&#xff09;项目框架图4&#xff09;流程5&#xff09;完成显示客户列表的功能6&#xff…

leetcode刷题日记:190. Reverse Bits(颠倒二进制位)和191. Number of 1 Bits( 位1的个数)

190. Reverse Bits&#xff08;颠倒二进制位&#xff09; 题目要求我们将一个数的二进制位进行颠倒&#xff0c;画出图示如下(以8位二进制为例)&#xff1a; 显然对于这种问题我们需要用到位操作&#xff0c;我们需要将原数的每一位取出来然后颠倒之后放进另一个数。 我们需要…

被锁总时间

题目描述&#xff1a; 对一个事务进行加锁与解锁&#xff0c;其中有加锁数组&#xff0c;解锁数组&#xff0c;这两个数组长度相等&#xff0c;且数组内数据代表加锁与解锁的具体时间点&#xff0c;求给出数组中事务的总被锁时间。&#xff08;其中加锁后默认在60秒后解锁&…

【信息安全】浅谈三种XSS(跨站脚本攻击)的攻击流程与防御措施

银狼美图镇楼 XSS 跨站脚本攻击&#xff08;Cross-Site Scripting&#xff0c;简称XSS&#xff09;是一种常见的Web安全漏洞&#xff0c;攻击者通过在Web应用中注入恶意脚本&#xff0c;使得浏览器在解析页面时执行该脚本&#xff0c;从而实现攻击目的。 类型 存储型XSS&…

SPASS-回归分析

回归分析概述 确定性关系与非确定性关系 变量与变量之间的关系分为确定性关系和非确定性关系,函数表达确定性关系。研究变量间的非确定性关系,构造变量间经验公式的数理统计方法称为回归分析。 回归分析基本概念 回归分析是指通过提供变量之间的数学表达式来定量描述变量间…

Oracle主备切换,ogg恢复方法(集成模式)

前言: 文章主要介绍Oracle数据库物理ADG主备在发生切换时(switchover,failover)&#xff0c;在主库运行的ogg进程(集成模式)如何进行恢复。 测试恢复场景&#xff0c;因为集成模式不能在备库配置&#xff0c;所以场景都是基于主库端: 1 主备发生switchover切换&#xff0c;主库…

LeetCode - 622. 设计循环队列(C语言,顺序存储结构,配图)

622. 设计循环队列 - 力扣&#xff08;LeetCode&#xff09; 设计循环队列&#xff0c;我们可以从顺序结构和链式结构来考虑&#xff0c;但因为链式结构实现起来较为复杂&#xff0c;不易理解&#xff0c;且主流使用顺序存储&#xff0c;所以本文就是用顺序存储结构实现。 因为…

【Spring】之注解存取Bean对象

在本系列的上一篇文章中&#xff0c;我们已经了解了Spring的一些核心概念&#xff0c;并且还学习了Spring存取。但是我们发现在存取的过程中还是比较复杂&#xff0c;接下来我们将学习更为简单的Spring存取&#xff0c;其中涉及到的主要内容就是注解。并且在Spring家族的学习过…

Virtual安装centos后,xshell连接centos

1. 网络使用Host-Only模式动态分配IP&#xff0c;运行 system restart network 后&#xff0c;使用ifconfig查看新的ip&#xff0c;XShell可以直接连上centos&#xff0c; 但是由于使用的是Host-Only模式&#xff0c;centos不能访问网络&#xff0c;只能与宿主机相互通信 2. 网…

【C语言基础】分享近期学习到的volatile关键字、__NOP__()函数以及# #if 1 #endif

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…