STM32_11(SPI)

news2024/11/16 7:30:14

一、SPI通信

  • SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线
  • 四根通信线:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)
  • MOSI:是主设备输出、从设备输入的数据信号线;、MISO:主设备输入、从设备输出的数据信号线; 
  • 同步,全双工
  • 支持总线挂载多设备(一主多从)

1. SPI硬件电路

  • 所有SPI设备的SCK、MOSI、MISO分别连在一起
  • 主机另外引出多条SS控制线,分别接到各从机的SS引脚
  • 输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入
  • 主机只能选择一个从机,选择多个从机就会导致数据冲突。当从机的SS引脚为高电平,就是从机未被选中,它的MISO引脚必须切换为高阻态,也就是把引脚断开。这样就可以防止一条线有多个输出,而导致的电平冲突问题。

2. 移位示意图

        移位寄存器有一个时钟输入端,因为SPI都是高位先行,所以每来一个时钟,移位寄存器就会向左移位,从机的移位寄存器同理。移位寄存器的时钟源是由主机提供的,这里叫做波特率发生器,它产生的时钟驱动主机的移位寄存器进行移位。同时,这个时钟也通过SCK引脚进行输出,接到从机的移位寄存器里。主机移位寄存器左边移出去的数据通过MOSI引脚,输入到从机的移位寄存器的右边,从机移位寄存器的数据根据MISO输入到主机移位寄存器的右边。

        首先规定,波特率发生器时钟上升沿,所有移位寄存器向左移动一位,移出去的位放在引脚上,波特率发生器时钟的下降沿,引脚上的位,采样输入到移位寄存器的最低位。

3. SPI时序基本单元

① 起始条件和终止条件

  • 起始条件:SS从高电平切换到低电平
  • 终止条件:SS从低电平切换到高电平

② 模式0

  • 交换一个字节(模式0)
  • CPOL=0:空闲状态时,SCK为低电平
  • CPHA=0:SCK第一个边沿移入数据,第二个边沿移出数据

总体来说,MOSI和MISO都提前SCK半个周期。

② 模式1

  • 交换一个字节(模式1)
  • CPOL=0:空闲状态时,SCK为低电平
  • CPHA=1(时钟相位:决定第一个时钟采样移入还是第二个时钟采样移入):SCK第一个边沿移出数据,第二个边沿移入数据

        SS高电平时,MISO用一条中间的线表示高阻态,SS下降沿之后,从机的MISO被允许开启输出。SS上升沿之后,从机的MISO必须置回高阻态。当SCK为上升沿时,主机和从机同时移除数据,主机通过MOSI移除最高位,此时的MOSI的电平就表示主机要发送数据B7,从机通过MISO移除最高位,此时MISO就表示从机要发送数据B7。之后时钟运行,产生下降沿,此时的主机和从机需同时移入数据,也就是数据采样,这里主机移除B7,进入从机移位寄存器的最低位,从机移除B7,进去主机移位寄存器的最低位。一个时钟脉冲产生完毕,一位数据传输完毕。

③ SPI时序(发送指令)

        在这里我们使用的是模式0,首先SS是高电平,SCK是低电平。SS产生下降沿,时序开始,在下降沿时刻,MOSI和MISO就开始比变换数据,MOSI的指令码仍为0,所以保持低电平不变,MISO从机没有数据发给主机,引脚电平没有变换。从机采样输入,得到0,主机采样输入,得到1。之后主机要发送数据1,SCK下降沿,数据移出,主机将1移出到MOSI,MOSI变高电平。当主机发送0时候,SCK下降沿,MOSI变为0。SCK上升沿,数据采样,从机接收数据为0。总体来说,SCK低电平时变化时期,高电平时读取时期(下降沿变换数据,上升沿采样数据)。

        这个SPI时序代表,主机用0x06换来了从机的0xFF。

④ SPI时序(指定地址写)

        向SS指定的设备,发送写指令(0x02),随后在指定地址(Address[23:0])下,写入指定数据(Data)。

⑤ SPI时序(指定地址读)

        向SS指定的设备,发送写指令(0x02),随后在指定地址(Address[23:0])下,写入指定数据(Data)。

二、SPI外设

  • STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担
  • 可配置8位/16位数据帧、高位先行/低位先行
  • 时钟频率: fPCLK / (2, 4, 8, 16, 32, 64, 128, 256)
  • 支持多主机模型、主或从操作
  • 可精简为半双工/单工通信
  • 支持DMA
  • 兼容I2S协议
  • STM32F103C8T6 硬件SPI资源:SPI1、SPI2

1. SPI框图

        首先,移位寄存器右边低位的数据一位一位地从MOSI移出,MISO的数据一位一位地以到做左边移位寄存器的数据高位。

        这个可以控制是低位先行还是高位先行。

        假如我们需要连续发送一串数据,第一个数据写入发送缓冲区(TDR),当移位寄存器没有数据移位时,TDR的数据就会立刻转入移位寄存器,开始移位,这个转入时刻,会置状态寄存器的TXE为1(表示发送寄存器空),紧接着,下一个数据就可以提前写入TDR等待,一旦上个数据发送完成,下一个数据就可以立刻跟进,实现不间断的连续传输。当数据到移位寄存器后,它就会自动产生时钟,将数据移出去,在移除的过程中,MISO数据也会移入。一旦数据移除完成,数据移入也完成。这时,移入的数据就整体从移位寄存器转入到接收缓冲区RDR,这时会将状态寄存器RXNE置1(表示接收寄存器非空)。当我们检测RXNE置1后,就需要尽快把数据从RDR读出来,在下个数据来之前就可以读出RDR ,实现连续接收。

2. SPI基本结构

3. 主模式全双工连续传输(效率更高)

4. 非连续传输(代码友好)

步骤:

1、等待TXE置1;

2、写入数据到TDR寄存器;

3、等待RXNE为1;

4、读取RDR接收的数据。

三、W25Q64模块

  • W25Qxx系列是一种低成本、小型化、使用简单的非易失性存储器,常应用于数据存储、字库存储、固件程序存储等场景
  • 存储介质:Nor Flash(闪存)
  • 时钟频率:80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI)
  • 存储容量(24位地址):

    W25Q40:  4Mbit / 512KByte

    W25Q80:  8Mbit / 1MByte

    W25Q16:  16Mbit / 2MByte

    W25Q32:  32Mbit / 4MByte

    W25Q64:  64Mbit / 8MByte

    W25Q128:  128Mbit / 16MByte

    W25Q256:  256Mbit / 32MByte

1. W25Q64硬件电路图

 

 

        /CS(/代表低电平有效或者CS上面有一横线也是低电平有效。

        这里的CS对应SS,DI对应MOSI,DO对应MISO。

2. Flash操作注意事项

  • 写入操作时:
  • 写入操作前,必须先进行写使能
  • 每个数据位只能由1改写为0,不能由0改写为1
  • 写入数据前必须先擦除,擦除后,所有数据位变为1
  • 擦除必须按最小擦除单元进行(最小的擦除单元是一个扇区4096字节,最大的能把全部擦除)
  • 连续写入多字节时,最多写入一页(256字节)的数据,超过页尾位置的数据,会回到页首覆盖写入
  • 写入操作结束后,芯片进入忙状态,不响应新的读写操作
  • 读取操作时:直接调用读取时序,无需使能,无需额外操作,没有页的限制,读取操作结束后不会进入忙状态,但不能在忙状态时读取

四、代码部分

1. SPI软件配置代码

#include "Bsp_SPI.h"

/* SS写数据 */
void Bsp_SPI_W_SS(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}

/* SCK写数据 */
void Bsp_SPI_W_SCK(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);
}

/* MOSI写数据 */
void Bsp_SPI_W_MOSI(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);
}

/* MISO读数据 */
uint8_t Bsp_SPI_R_MISO(void)
{
    return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}

/* SPI初始化 */
void Bsp_SPI_Init(void)
{
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    Bsp_SPI_W_SS(1);
    Bsp_SPI_W_SCK(0);

}

/* SPI起始 */
void Bsp_SPI_Start(void)
{
    Bsp_SPI_W_SS(0);
}

/* SPI终止 */
void Bsp_SPI_Stop(void)
{
    Bsp_SPI_W_SS(1);
}

/* MOSI和MISO交换字节 */
/* 模式0 */
uint8_t Bsp_SPI_SwapByte(uint8_t ByteSend)
{
    uint8_t ByteReceive = 0x00;

    for (uint8_t i = 0; i < 8; i++)
    {
        Bsp_SPI_W_MOSI(ByteSend & (0x80 >> i));
        Bsp_SPI_W_SCK(1);
        if (Bsp_SPI_R_MISO() == 1)
        {
            ByteReceive |= (0x80 >> i);
        }
        Bsp_SPI_W_SCK(0);
    }

    return ByteReceive;
}

/* 模式1 */
/*uint8_t Bsp_SPI_SwapByte(uint8_t ByteSend)
{
    uint8_t ByteReceive = 0x00;

    for (uint8_t i = 0; i < 8; i++)
    {
        Bsp_SPI_W_SCK(1);
        Bsp_SPI_W_MOSI(ByteSend &(0x80 >> i));
        Bsp_SPI_W_SCK(0);
        if (Bsp_SPI_R_MISO == 1)
        {
            ByteReceive |= (0x80 >> i);
        }
    }

    return ByteReceive;
}*/

/* 模式3 */
/*uint8_t Bsp_SPI_SwapByte(uint8_t ByteSend)
{
    uint8_t ByteReceive = 0x00;

    for (uint8_t i = 0; i < 8; i++)
    {
        Bsp_SPI_W_SCK(0);
        Bsp_SPI_W_MOSI(ByteSend &(0x80 >> i));
        Bsp_SPI_W_SCK(1);
        if (Bsp_SPI_R_MISO == 1)
        {
            ByteReceive |= (0x80 >> i);
        }
    }

    return ByteReceive;
}*/

/* 模式2 */
/*uint8_t Bsp_SPI_SwapByte(uint8_t ByteSend)
{
    uint8_t ByteReceive = 0x00;

    for (uint8_t i = 0; i < 8; i++)
    {
        Bsp_SPI_W_MOSI(ByteSend &(0x80 >> i));
        Bsp_SPI_W_SCK(0);
        if (Bsp_SPI_R_MISO == 1)
        {
            ByteReceive |= (0x80 >> i);
        }
        Bsp_SPI_W_SCK(1);
    }

    return ByteReceive;
}*/

2. W25Q64地址封装

#ifndef __W25Q64_INS_H
#define __W25Q64_INS_H

#define W25Q64_WRITE_ENABLE                         0x06
#define W25Q64_WRITE_DISABLE                        0x04
#define W25Q64_READ_STATUS_REGISTER_1               0x05
#define W25Q64_READ_STATUS_REGISTER_2               0x35
#define W25Q64_WRITE_STATUS_REGISTER                0x01
#define W25Q64_PAGE_PROGRAM                         0x02
#define W25Q64_QUAD_PAGE_PROGRAM                    0x32
#define W25Q64_BLOCK_ERASE_64KB                     0xD8
#define W25Q64_BLOCK_ERASE_32KB                     0x52
#define W25Q64_SECTOR_ERASE_4KB                     0x20
#define W25Q64_CHIP_ERASE                           0xC7
#define W25Q64_ERASE_SUSPEND                        0x75
#define W25Q64_ERASE_RESUME                         0x7A
#define W25Q64_POWER_DOWN                           0xB9
#define W25Q64_HIGH_PERFORMANCE_MODE                0xA3
#define W25Q64_CONTINUOUS_READ_MODE_RESET           0xFF
#define W25Q64_RELEASE_POWER_DOWN_HPM_DEVICE_ID     0xAB
#define W25Q64_MANUFACTURER_DEVICE_ID               0x90
#define W25Q64_READ_UNIQUE_ID                       0x4B
#define W25Q64_JEDEC_ID                             0x9F
#define W25Q64_READ_DATA                            0x03
#define W25Q64_FAST_READ                            0x0B
#define W25Q64_FAST_READ_DUAL_OUTPUT                0x3B
#define W25Q64_FAST_READ_DUAL_IO                    0xBB
#define W25Q64_FAST_READ_QUAD_OUTPUT                0x6B
#define W25Q64_FAST_READ_QUAD_IO                    0xEB
#define W25Q64_OCTAL_WORD_READ_QUAD_IO              0xE3

#define W25Q64_DUMMY_BYTE                           0xFF                // 空地址,代表没用的地址,因为在传输过程中总会只有发送或只有接收的时候

#endif

3. 软件SPI读取W25Q64

#include "Bsp_W25Q64.h"

void W25Q64_Init(void)
{
    Bsp_SPI_Init();
}

/* 读取ID */
void W25Q64_ReadID(uint8_t *MID, uint16_t *DID)
{
    Bsp_SPI_Start();
    Bsp_SPI_SwapByte(W25Q64_JEDEC_ID);               // 发送0x9F指令码
    *MID = Bsp_SPI_SwapByte(W25Q64_DUMMY_BYTE);      // 返回制造厂商ID
    *DID = Bsp_SPI_SwapByte(W25Q64_DUMMY_BYTE);      // 返回设备ID的高8位
    *DID <<= 8;                         
    *DID |= Bsp_SPI_SwapByte(W25Q64_DUMMY_BYTE);     // 返回设备ID的低8位
    Bsp_SPI_Stop();
}

/* 使能 */
void W25Q64_WriteEnable(void)
{
    Bsp_SPI_Start();
    Bsp_SPI_SwapByte(W25Q64_WRITE_ENABLE);         
    Bsp_SPI_Stop();
}

/* 读状态寄存器1(主要读取BUSY位,判断是否在忙) */
void W25Q64_WaitBusy(void)
{
    uint32_t TimeOut = 100000;

    Bsp_SPI_Start();
    Bsp_SPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1);   
    while ((Bsp_SPI_SwapByte(W25Q64_DUMMY_BYTE) & 0x01) == 0x01)        // 判断状态寄存器1的最低位,也就是BUSY位是否在忙。0:忙     1:在忙
    {
        TimeOut--;
        if (TimeOut == 0)
        {
            break;
        }
    }
    Bsp_SPI_Stop();
}

/* 页编程 */
void W25Q64_PageProgram(uint32_t Address, uint8_t *DataAarry, uint16_t Length)
{
    W25Q64_WriteEnable();                       // 使能
    Bsp_SPI_Start();
    Bsp_SPI_SwapByte(W25Q64_PAGE_PROGRAM);
    Bsp_SPI_SwapByte(Address >> 16);
    Bsp_SPI_SwapByte(Address >> 8);
    Bsp_SPI_SwapByte(Address);

    for (uint16_t i = 0; i < Length; i++)
    {
        Bsp_SPI_SwapByte(DataAarry[i]);
    }
    Bsp_SPI_Stop();

    W25Q64_WaitBusy();
}

/* 扇区擦除 */
void W25Q64_SectorErase(uint32_t Address)
{
    W25Q64_WriteEnable();                       // 使能
    Bsp_SPI_Start();
    Bsp_SPI_SwapByte(W25Q64_SECTOR_ERASE_4KB);
    Bsp_SPI_SwapByte(Address >> 16);
    Bsp_SPI_SwapByte(Address >> 8);
    Bsp_SPI_SwapByte(Address);
    Bsp_SPI_Stop();

    W25Q64_WaitBusy();
}

/* 读数据 */
void W25Q64_ReadData(uint32_t Address, uint8_t *DataAarry, uint32_t Length)
{
    Bsp_SPI_Start();
    Bsp_SPI_SwapByte(W25Q64_READ_DATA);
    Bsp_SPI_SwapByte(Address >> 16);
    Bsp_SPI_SwapByte(Address >> 8);
    Bsp_SPI_SwapByte(Address);

    for (uint32_t i = 0; i < Length; i++)
    {
        DataAarry[i] = Bsp_SPI_SwapByte(W25Q64_DUMMY_BYTE);
    }
    Bsp_SPI_Stop();
}

4. 硬件SPI读取W25Q64

#include "Bsp_SPI.h"

/* SS写数据 */
void Bsp_SPI_W_SS(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}

/* SPI初始化 */
void Bsp_SPI_Init(void)
{
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    SPI_InitTypeDef SPI_InitStructure;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;                    // 分频系数,分频越高速度越快(注意:SPI1是72M,SPI2是36M。因为SPI1是在APB2,SPI2是在APB1)
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                                            // 选择第一个边沿采样还是第二个边沿采样
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                                              // 时钟极性:因为在这里选择模式0
    SPI_InitStructure.SPI_CRCPolynomial = 7;                                                // CRC校验多项式,默认值7
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                                       // 8位数据帧
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;                      // 双线全双工模式
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                                      // 高位先行
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                                           // 选择向前设备时SPI主机
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                               // NSS引脚,一般没用到选择软件NSS
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_Cmd(SPI1, ENABLE);

    Bsp_SPI_W_SS(1);

}

/* SPI起始 */
void Bsp_SPI_Start(void)
{
    Bsp_SPI_W_SS(0);
}

/* SPI终止 */
void Bsp_SPI_Stop(void)
{
    Bsp_SPI_W_SS(1);
}

/* MOSI和MISO交换字节 */
/* 模式0 */
uint8_t Bsp_SPI_SwapByte(uint8_t ByteSend)
{
    uint32_t TimeOut = 10000;
    uint8_t ByteReceive;
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != 1)
    {
        TimeOut--;
        if (TimeOut == 0)
        {
            break;
        } 
    }
    SPI_I2S_SendData(SPI1, ByteSend);
    TimeOut = 10000;
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != 1)
    {
        TimeOut--;
        if (TimeOut == 0)
        {
            break;
        } 
    }
    ByteReceive = SPI_I2S_ReceiveData(SPI1);
    return  ByteReceive;
}

5. 主程序

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Bsp_W25Q64.h"

uint8_t MID;
uint16_t DID;
uint8_t ArrayWrite[] = {0x11, 0x22, 0x33, 0x44};
uint8_t ArrayRead[4];

int main(void)
{

    OLED_Init();                        
    W25Q64_Init();

    /* 显示厂商和设备ID号 */
    OLED_ShowString(1, 1, "MID:    DID:");
    OLED_ShowString(2, 1, "W:");
    OLED_ShowString(3, 1, "R:");

    W25Q64_ReadID(&MID, &DID);
    OLED_ShowHexNum(1, 5, MID, 2);
    OLED_ShowHexNum(1, 13, DID, 4);

    W25Q64_SectorErase(0x000000);                    // 只要末尾3个十六进制数为0,那肯定是扇区的起始地址(不擦除,掉电不丢失)。如果不擦除则改写则会数据出错,因为只能1变0不能0变1的操作所以修改数据前得擦除。
    W25Q64_PageProgram(0x00000, ArrayWrite, 4);      // 写入数据ArrayWrite,并且写入的数据不能跨页

    W25Q64_ReadData(0x000000, ArrayRead, 4);         // 读数据

    /* 显示写入数据 */
    OLED_ShowHexNum(2, 3, ArrayWrite[0], 2);
    OLED_ShowHexNum(2, 6, ArrayWrite[1], 2);
    OLED_ShowHexNum(2, 9, ArrayWrite[2], 2);
    OLED_ShowHexNum(2, 12, ArrayWrite[3], 2);

    /* 显示读出数据 */
    OLED_ShowHexNum(3, 3, ArrayRead[0], 2);
    OLED_ShowHexNum(3, 6, ArrayRead[1], 2);
    OLED_ShowHexNum(3, 9, ArrayRead[2], 2);
    OLED_ShowHexNum(3, 12, ArrayRead[3], 2);

    while (1)
    {
        
    }
}

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

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

相关文章

一个菜单两个二级路由的搭建

效果如下&#xff0c;而且这是最上方的菜单&#xff0c;需要进入以后重定向。 {path: /,name: HOME,component: ConsoleLayout, //这里也有router-viewmeta: {menu: false},redirect: {name: ManagerList},children: [{path: /rightsManage,name: RightsManage,component: () &…

21.Oracle的程序包(Package)

Oracle的程序包Package 一、Package的概述1、什么是Oracle11g的Package2、Package的作用是什么3、常见的系统内置Package 二、创建Package的相关语法1、Package的创建语法2、Package的删除3、具体案例4、Package的使用5、与Package相关的其他语法 三、常见内置程序包的使用1、…

什么是电子负载

电子负载也被称为电子负载器或电源模拟器用于模拟实际负载的设备&#xff0c;它能够吸收和消耗电能&#xff0c;就像真实的电子设备一样&#xff0c;电子负载的主要功能是测试电源、电池、发电机等电源设备的性能和可靠性。 电子负载的工作原理是通过内部的电力转换电路&#x…

西工大网络空间安全学院计算机系统基础实验一(14,15)

给大家强调一点&#xff0c;如果这门课你只是通过了&#xff0c;但是其实你并不懂其中的原理&#xff0c;千万不要害怕&#xff0c;不要胆怯&#xff0c;因为后面你还有很多很多的时间来回头巩固它&#xff0c;正所谓“君子报仇&#xff0c;十年不晚”。同样的道理&#xff0c;…

OSI七层参考模型及其协议和各层设备

OSI网络模型是开放系统互联&#xff08;Open Systems Interconnection&#xff09;参考模型&#xff0c;它是由国际标准化组织&#xff08;ISO&#xff09;制定的。这个模型将网络系统划分为七个层次&#xff0c;OSI网络模型的七层是&#xff1a;物理层、数据链路层、网络层、传…

牛客算法题 HJ99 自守数 golang实现

题目 HJ99 自守数 描述 自守数是指一个数的平方的尾数等于该数自身的自然数。例如&#xff1a;25^2 625&#xff0c;76^2 5776&#xff0c;9376^2 87909376。请求出n(包括n)以内的自守数的个数数据范围&#xff1a; 1 ≤ &#xfffd; ≤ 100001≤n≤10000 输入描述&…

ACM32F070 RTC 引脚做普通 GPIO 用法配置

有场景需要把带RTC引脚功能的IO当做普通的GPIO使用&#xff0c;但是按照正常的GPIO初始化却无法使用&#xff0c;该芯片手册中有给出介绍 现给出配置方法&#xff0c;参考官方SDK里面PC13的配置&#xff1a; // PC13 GPIOC_Handle.Pin GPIO_PIN_13; GPIOC_Handle.Mod…

数据可视化:用图表和图形展示数据

写在开头 在当今信息爆炸的时代,海量的数据如同一座沉默的宝库,等待着我们挖掘和理解。然而,这些庞大的数据集本身可能令人望而生畏。在这个时候,数据可视化成为了解数据、发现模式和传达信息的强大工具。本篇博客将带领你探索数据可视化的奇妙世界,学习如何在python中使…

MacBook macOs安装RabbitMQ【超详细图解】

目录 一、使用brew安装RabbitMQ 二、安装RabbitMQWeb管理界面 三、启动RabbitMQ 一、使用brew安装RabbitMQ 刚好项目要用到RabbitMQ&#xff0c;安装顺便写下安装步骤记录一下以备用 使用brew命令安装&#xff0c;一般Mac会自带这个命令&#xff0c;如没有&#xff0c;…

如何看网络架构图-1基础篇

这是一个比较常见的网络部署架构图&#xff0c;通过LVSKeepalive做网络层的高可用架构&#xff0c;在应用层通过nginx做应用层细粒度的请求管控&#xff0c;然后根据负载均衡策略将请求转发到后端的tomcat服务。 首先看到这样的图&#xff0c;相信大部分人都能看懂&#xff0c;…

【Hydro】SG滤波器纯numpy实现

目录 说明WIKI示例滑动平均卷积系数的推导第一点和最后点的处理scipy.signal中的savgol_filter纯numpy实现的savgol_filterCPP实现的savgol_filter参考文献说明 Savitzky-Golay滤波器(S-G滤波器)是一种在时域和频域上同时进行的滤波方法,它通过局部多项式拟合来平滑信号。这…

python中,or、not的用法

or的用法 在python中,or运算符是一个逻辑运算符&#xff0c;用于在多个条件中选择至少一个为真&#xff08;True&#xff09;的情况。 如果条件中的任意一个为真&#xff0c;整个表达式的结果就为真 如&#xff1a; 示例1: 检查两个数字中至少有一个正数 示例2: x True y …

分发测试应用平台怎么用之应用详情功能

我的应用 应用功能引导 ●您会看到以下页面&#xff0c;下图为功能的解释方便您的运行 我的应用-详情-应用详情 ●我们点击应用详情数字③&#xff0c;点击应用详情&#xff0c;下图是对详情页的功能介绍。 详情-应用设置 ●详情-应用设置-下图为应用设置的上半部分 ●下图为应…

从零构建属于自己的GPT系列1:文本数据预处理、文本数据tokenizer、逐行代码解读

&#x1f6a9;&#x1f6a9;&#x1f6a9;Hugging Face 实战系列 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在PyCharm中进行 本篇文章配套的代码资源已经上传 从零构建属于自己的GPT系列1&#xff1a;文本数据预处理 从零构建属于自己的GPT系列2&#xff1a;语…

聚焦清晰度评价指标所用到的各种算法

首先&#xff0c;我想吐槽一下&#xff0c;看了好几篇聚焦评价函数的文章&#xff0c;说到底都是一篇文章转载或者重复上传&#xff0c;介绍了将近 15 种清晰度的算法&#xff0c;原文找了半天都没找到在哪&#xff0c;最多也仅能找到一些比较早的转载。 无参考图像的清晰度评…

众新万能空调遥控器代码

众新万能空调遥控器代码 特此记录 anlog 2023年11月30日

JPA代码生成器

【Java代码生成神器】自动化生成Java实体类、代码、增删改查功能&#xff01;点击访问 推荐一个自己每天都在用的Java代码生成器&#xff01;这个网站支持在线生成Java代码&#xff0c;包含完整的Controller\Service\Entity\Dao代码&#xff0c;完整的增删改查功能&#xff01…

Linux | Ubuntu设置 netstat(网络状态)

netstat命令用于显示与IP、TCP、UDP和ICMP协议相关的统计数据&#xff0c;一般用于检验本机各端口的网络连接情况。netstat是在内核中访问网络及相关信息的程序&#xff0c;它能提供TCP连接&#xff0c;TCP和UDP监听&#xff0c;进程内存管理的相关报告。 1.netstat的安装 搜…

自己的邮箱名称出现在别人的此电脑的网络位置中

在公司别的同事告诉我&#xff0c;我的邮箱名字出现在他们的【此电脑】-【网络位置中】 如图&#xff1a; 当时吓我一跳&#xff0c;因为我总喜欢搞一些渗透的东西&#xff0c;我以为把自己暴漏了&#xff0c;然后疯狂的在网上找原因。 于是就搜到一位安暖的博主&#xff1a; …

VSCode搭建STM32开发环境

1、下载安装文件 链接&#xff1a;https://pan.baidu.com/s/1WnpDTgYBobiZaXh80pn5FQ 2、安装VSCodeUserSetup-x64-1.78.2.exe软件 3、 在VSCode中安装必要的插件 3、配置Keil Assistant插件 4、在环境变量中部署mingw64编译环境