【STM32】RTT-Studio中HAL库开发教程七:IIC通信--EEPROM存储器FM24C04

news2024/9/27 5:43:52

文章目录

    • 一、简介
    • 二、模拟IIC时序
    • 三、读写流程
    • 四、完整代码
    • 五、测试验证

一、简介

  FM24C04D,4K串行EEPROM:内部32页,每个16字节,4K需要一个11位的数据字地址进行随机字寻址。FM24C04D提供4096位串行电可擦除和可编程只读存储器(EEPROM),大小为512字,每个8位,具有128位UID和16字节安全扇区。该设备被优化用于许多工业和商业应用中,其中低功率和低压操作是必不可少的。

芯片优点:FM24C04芯片手册

  • 低工作电压: VCC = 1.7V到5.5V
  • 2-线串行接口,施密特触发器,滤波输入噪声抑制,双向数据传输协议
  • 1 MHz(2.5V~5.5V)和400 kHz (1.7V)兼容性
  • 写保护针硬件数据保护

  安全扇区:FM24C04D提供了16字节的安全扇区,可以写入和(以后)永久锁定在只读模式。这些寄存器可以被系统制造商用来从存储主内存阵列分开存储安全性和其他重要信息
  唯一ID:FM24C04D使用了一个单独的内存块,其中包含一个工厂编程的128位唯一ID。通过以“1011”(Bh)序列开始设备地址字来访问此内存位置
在这里插入图片描述
数据存储器:
(1)第七位是内存页面地址位(P0),第八位是读/写操作选择位。
(2)地址位P0和<7:4>定义页面地址,A<3:0>定义字节地址。总共32页,每页16个字节。设备地址P0为0(0xA0)时,地址从第0页开始;设备地址为1(0xA2)时,地址从第16页开始写数据。
安全扇区:
(3)第七位并不在乎,第八位是读/写操作选择位。
(4)地址位<7:6>必须是00”,A<3:0>定义字节地址,其他位不在乎。
唯一性标识:
(5)第七位并不在乎,第八位是读/写操作选择位,它必须是“1”。
(6)地址位<7:6>必须是10”,A<3:0>定义字节地址,其他位不在乎。


二、模拟IIC时序

1.起始信号: 在SCL为高电平期间,SDA由高变低;
在这里插入图片描述

/**
 * @brief 产生I2C起始信号
 * @note
  *       请参考I2C通信协议,I2C起始信号:当SCL为高电平时,SDA由高变低
  *       如下图所示:方框部分表示I2C起始信号
 *           _____     |
 *        __|__   |    |  ___  ___  ___  ___  ___  ___  ___  ___
 *   SDA:   |  \__|____|_/   \/   \/   \/   \/   \/   \/   \/   \     /
 *          |     |    | \___/\___/\___/\___/\___/\___/\___/\___/\___/
 *        __|_____|_   |   _    _    _    _    _    _    _    _    _
 *   SCL:   |     | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_
 *          |_____|    |
 *           start         D7   D6   D5   D4   D3   D2   D1   D0   ACK
 */
void I2C_Start(void)
{
    uint32_t i2c_delay = i2c_speed;

    SDA_OUT();      // SDA设置为输出
    I2C_SDA_HIGH;   // SDA: 高
    I2C_SCL_HIGH;   // SCL: 高

    BSP_I2C_Delay(i2c_delay);   // 延时>4.7us

    I2C_SDA_LOW;                // 当SCL为高电平时,SDA由高变低
    BSP_I2C_Delay(i2c_delay);   // 延时>4us

    I2C_SCL_LOW;    // SCL变低,钳住I2C总线,准备发送或接收数据
}

2.停止信号: 在SCL为高电平期间,SDA由低变高。
在这里插入图片描述

/**
 * @brief 产生I2C停止信号
 * @note
  *       请参考I2C通信协议,I2C停止信号:当SCL为高电平时,SDA由低变高
  *       发送完STOP信号后,SCL和SDA都为高电平,即释放了I2C总线
  *       如下图所示:方框部分表示I2C起始信号
 *                                    _____
 *         ___  ___  ___  ___        |   __|_
 *   SDA: /   \/   \/   \/   \       |  /  |
 *        \___/\___/\___/\___/\______|_/   |
 *         _    _    _    _    _    _|_____|_
 *   SCL: / \__/ \__/ \__/ \__/ \__/ |     |
 *                                   |_____|
 *        D3   D2   D1   D0   ACK     stop
 */
void I2C_Stop(void)
{
    uint32_t i2c_delay = i2c_speed;

    SDA_OUT();                  // SDA设置为输出
    I2C_SDA_LOW;                // SDA低电平
    I2C_SCL_HIGH;               // SCL高电平
    BSP_I2C_Delay(i2c_delay);   // 延时>4us

    I2C_SDA_HIGH;               // STOP:当SCL为高电平时,SDA由低变高
    BSP_I2C_Delay(i2c_delay);   // 延时>4.7us
}

3.等待ACK应答信号: 在8位数据信号传输完成之后,第9位就是应答信号。应答信号分为应答和非应答,应答为低电平,非应答为高电平。
在这里插入图片描述

/**
 * @brief  等待ACK应答信号
 * @retval 1 - 未接收到应答信号ACK;0 - 接收到应答信号ACK
 * @note
  *       请参考I2C通信协议,检测ACK应答信号:当SCL为高电平时,读取SDA为低电平
  *       如下图所示:方框部分表示I2C起始信号
 *                             ________     _____
 *         ___  ___  ___  ___ | _      |   |   __|_
 *   SDA: /   \/   \/   \/   \|/ \     |   |  /  |
 *        \___/\___/\___/\___/|   \____|___|_/   |
 *         _    _    _    _   | _____  |  _|_____|
 *   SCL: / \__/ \__/ \__/ \__|/     \_|_/ |     |
 *                            |________|   |_____|
 *        D3   D2   D1   D0      ACK        stop
 */
uint8_t I2C_Wait_ACK(void)
{
    uint32_t i2c_delay = i2c_speed;
    uint8_t timeout = 0;

    SDA_IN();           // SDA设置为输入
    I2C_SDA_HIGH;       // SDA上拉输入
    I2C_SCL_HIGH;       // SCL设置为高电平
    BSP_I2C_Delay(i2c_delay);

    while (I2C_SDA_READ() == 1)  // 等待ACK
    {
        if (timeout++ > 250)
        {
            I2C_Stop();
            return 1;
        }
    }

    I2C_SCL_LOW;        // 钳住I2C总线:时钟信号设为低电平
    return 0;
}

/**
 * @brief  产生ACK应答信号
 * @note
  *       请参考I2C通信协议,产生ACK应答信号: 在SDA为低电平时,SCL产生一个正脉冲
  *       如下图所示:方框部分表示I2C起始信号
 *                             _____     _____
 *         ___  ___  ___  ___ |     |   |   __|_
 *   SDA: /   \/   \/   \/   \|     |   |  /  |
 *        \___/\___/\___/\___/|\____|___|_/   |
 *         _    _    _    _   |  _  |  _|_____|_
 *   SCL: / \__/ \__/ \__/ \__|_/ \_|_/ |     |
 *                            |_____|   |_____|
 *        D3   D2   D1   D0     ACK      stop
 */
void I2C_ACK(void)
{
    uint32_t i2c_delay = i2c_speed;

    I2C_SCL_LOW;                // 低电平
    SDA_OUT();                  // 设置SDA为输出
    I2C_SDA_LOW;                // ACK信号
    BSP_I2C_Delay(i2c_delay);   // 延时>4us

    I2C_SCL_HIGH;               // 高电平
    BSP_I2C_Delay(i2c_delay);   // 延时>4us
    I2C_SCL_LOW;                // 钳住I2C总线:时钟信号设为低电平
}

/**
 * @brief  产生非应答信号NACK
 * @note
  *       请参考I2C通信协议,产生ACK应答信号: 在SDA为高电平时,SCL产生一个正脉冲
  *       如下图所示:方框部分表示I2C起始信号
 *                             _____      ______
 *         ___  ___  ___  ___ | ____|_   |    __|_
 *   SDA: /   \/   \/   \/   \|/    | \  |   /  |
 *        \___/\___/\___/\___/|     |  \_|__/   |
 *         _    _    _    _   |  _  |  __|______|_
 *   SCL: / \__/ \__/ \__/ \__|_/ \_|_/  |      |
 *                            |_____|    |______|
 *        D3   D2   D1   D0    NACK        stop
 */
void I2C_NACK(void)
{
    uint32_t i2c_delay = i2c_speed;

    I2C_SCL_LOW;                // 低电平
    SDA_OUT();                  // SDA设置为输出
    I2C_SDA_HIGH;               // NACK信号
    BSP_I2C_Delay(i2c_delay);   // 延时>4us

    I2C_SCL_HIGH;               // 高电平
    BSP_I2C_Delay(i2c_delay);   // 延时>4us
    I2C_SCL_LOW;                // 钳住I2C总线:时钟信号设为低电平
}

4.读写一个字节数据

/**
 * @brief  I2C发送一个字节
 * @note
  *       请参考I2C通信协议,产生ACK应答信号: 在SDA为高电平时,SCL产生一个正脉冲
  *       如下图所示:方框部分表示I2C起始信号
 *
 *           _____     |<------------I2C数据发送周期------------>|
 *        __|__   |    |  ___  ___  ___  ___  ___  ___  ___  ___ | _
 *   SDA:   |  \__|____|_/   \/   \/   \/   \/   \/   \/   \/   \|/
 *          |     |    | \___/\___/\___/\___/\___/\___/\___/\___/|\_
 *        __|_____|_   |   _    _    _    _    _    _    _    _  |
 *   SCL:   |     | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_|_
 *          |_____|    |                                         |
 *           start     |   D7   D6   D5   D4   D3   D2   D1   D0 |
 */
void I2C_Send_Byte(uint8_t data)
{
    uint8_t i = 0;
    uint32_t i2c_delay = i2c_speed;

    SDA_OUT();                          // SDA设为输出
    I2C_SCL_LOW;                        // 钳住I2C总线:SCL设为低电平
    for (i = 0; i < 8; i++)
    {
        if (data & 0x80)
            I2C_SDA_HIGH;               // 高位先传
        else
            I2C_SDA_LOW;

        BSP_I2C_Delay(i2c_delay);       // 延时>4us

        I2C_SCL_HIGH;                   // 在SCL上产生一个正脉冲
        BSP_I2C_Delay(i2c_delay);       // 延时>4us

        I2C_SCL_LOW;
        BSP_I2C_Delay(i2c_delay / 3);   // 延时>1us
        data <<= 1;                     // 右移一位
    }
}

/**
 * @brief  从I2C读取一个字节
 * @param  ack : 0 - NACK; 1 - ACK
 * @retval 接收到的数据
 * @note
  *       请参考I2C通信协议,产生ACK应答信号: 在SDA为高电平时,SCL产生一个正脉冲
  *       如下图所示:方框部分表示I2C起始信号
 *
 *           _____     |<------------I2C数据读取周期(ACK)------------>|
 *        __|__   |    |  ___  ___  ___  ___  ___  ___  ___  ___      |
 *   SDA:   |  \__|____|_/   \/   \/   \/   \/   \/   \/   \/   \     |
 *          |     |    | \___/\___/\___/\___/\___/\___/\___/\___/\____|_
 *        __|_____|_   |   _    _    _    _    _    _    _    _    _  |
 *   SCL:   |     | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_|_
 *          |_____|    |                                              |
 *           start     |   D7   D6   D5   D4   D3   D2   D1   D0   ACK
 *
 *           _____     |<------------I2C数据读取周期(NACK)----------->|
 *        __|__   |    |  ___  ___  ___  ___  ___  ___  ___  ___  ____|_
 *   SDA:   |  \__|____|_/   \/   \/   \/   \/   \/   \/   \/   \/    |
 *          |     |    | \___/\___/\___/\___/\___/\___/\___/\___/     |
 *        __|_____|_   |   _    _    _    _    _    _    _    _    _  |
 *   SCL:   |     | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_|_
 *          |_____|    |                                              |
 *           start     |   D7   D6   D5   D4   D3   D2   D1   D0  NACK
 */
uint8_t I2C_Read_Byte(uint8_t ack)
{
    uint8_t i, receive = 0x00;
    uint32_t i2c_delay = i2c_speed;

    I2C_SCL_LOW;                    // SCL低电平
    SDA_IN();                       // SDA设置为输入
    for (i = 0; i < 8; i++)
    {
        BSP_I2C_Delay(i2c_delay);
        I2C_SCL_HIGH;               // 高电平
        BSP_I2C_Delay(i2c_delay);

        receive <<= 1;
        if (I2C_SDA_READ())
            receive |= 1;           // 高位在前

        I2C_SCL_LOW;
    }

    if (ack == 0)
        I2C_NACK();                 // 发送NACK
    else
        I2C_ACK();                  // 发送ACK

    return receive;                 // 返回接收到的数据
}

三、读写流程

1.写数据流程
  START–>DEVICE ADDRESS(写)–>ACK–>WORD ADDRESS–>ACK–>DATA–>ACK–>STOP

  • START:起始信号
  • DEVICE-ADDRESS:设备地址,以及页地址设置
  • ACK:从设备发送的应答信号(低电平),主机接收应答。
  • WORD-ADDRESS:写的数据存入的地址,即页地址
  • DATA:写入的数据
  • STOP:结束信号
    在这里插入图片描述

2.读数据流程
  START–>DEVICE ADDRESS(写)–>ACK–>WORD ADDRESS–>START–>DEVICE ADDRESS(读)–>ACK–>DATA–>NACK–>STOP。

  • START:起始信号
  • DEVICE-ADDRESS:设备地址,以及页地址设置
  • ACK:从设备发送的应答信号(低电平),主机接收应答。
  • WORD-ADDRESS:写的数据存入的地址,即页地址
  • DATA:写入的数据
  • NACK:主机发送的非应答信号,高电平有效。
  • STOP:结束信号
    在这里插入图片描述

四、完整代码

1.fm24c04.h
  主要是定义IIC通信的引脚,以及引脚高低电平变化,设置数据线的模式。

#ifndef APPLICATIONS_FM24C04_H_
#define APPLICATIONS_FM24C04_H_

#include <drv_common.h>
#include <string.h>

/**====================================================###### 宏定义 ######==================================================*/
/* 定义读写SCL和SDA的宏 */
#define I2C_SDA_PIN     GET_PIN(B, 11)
#define I2C_SCL_PIN     GET_PIN(B, 10)

#define I2C_SCL_HIGH    rt_pin_write(I2C_SCL_PIN, 1)
#define I2C_SCL_LOW     rt_pin_write(I2C_SCL_PIN, 0)

#define I2C_SDA_HIGH    rt_pin_write(I2C_SDA_PIN, 1)
#define I2C_SDA_LOW     rt_pin_write(I2C_SDA_PIN, 0)

#define I2C_SDA_READ()  rt_pin_read(I2C_SDA_PIN)

#define SDA_IN()        rt_pin_mode(I2C_SDA_PIN, PIN_MODE_INPUT);
#define SDA_OUT()       rt_pin_mode(I2C_SDA_PIN, PIN_MODE_OUTPUT);

/* 根据处理器速度设置,这里处理器速度是72MHz */
#define I2C_SPEED_1K        5000

/* 状态枚举 */
typedef enum
{
    I2C_SUCCESS = 0,
    I2C_TIMEOUT,
    I2C_ERROR,

} I2C_StatusTypeDef;

uint32_t i2c_speed;                             // I2C访问速度 = I2C_SPEED_1K / i2c_speed
/**====================================================#######  END  #######=================================================*/

/**=========================================##### 依照I2C协议编写的时序函数 #####=========================================*/
extern void BSP_I2C_Init(void);                 // 初始化I2C的IO口
extern void I2C_Start(void);                    // 发送I2C开始信号
extern void I2C_Stop(void);                     // 发送I2C停止信号
extern uint8_t I2C_Wait_ACK(void);              // I2C等待ACK信号
extern void I2C_ACK(void);                      // I2C发送ACK信号
extern void I2C_NACK(void);                     // I2C不发送ACK信号
extern void I2C_Send_Byte(uint8_t data);        // I2C发送一个字节
extern uint8_t I2C_Read_Byte(uint8_t ack);      // I2C读取一个字节
extern uint16_t I2C_SetSpeed(uint16_t speed);   // 设置I2C速度(1Kbps~400Kbps,speed单位,Kbps)
/**================================================#######  END  #######=====================================================*/

/**============================================##### 封装好的I2C读写函数 #####===========================================*/
//具体到某一个器件,请仔细阅读器件规格书关于I2C部分的说明,因为某些器件在I2C的读写操作会
//有一些差异,下面的代码我们在绝大多数的I2C器件中,都是验证OK的!
I2C_StatusTypeDef I2C_WriteOneByte(uint8_t DevAddr, uint8_t DataAddr, uint8_t Data);              // 向I2C从设备写入一个字节
I2C_StatusTypeDef I2C_WriteBurst(uint8_t DevAddr, uint8_t DataAddr, uint8_t* pData, uint32_t Num);// 向I2C从设备连续写入Num个字节
I2C_StatusTypeDef I2C_ReadOneByte(uint8_t DevAddr, uint8_t DataAddr, uint8_t* Data);              // 从I2C从设备读取一个字节
I2C_StatusTypeDef I2C_ReadBurst(uint8_t DevAddr, uint8_t DataAddr, uint8_t* pData, uint32_t Num); // 从I2C设备连续读取Num个字节
I2C_StatusTypeDef I2C_WriteBit(uint8_t DevAddr, uint8_t DataAddr, uint8_t Bitx, uint8_t BitSet);  // 设置数据的某一位
/**================================================#######  END  #######=====================================================*/

#endif /* _bsp_FRAM_H */

2.fm24c04.c
  主要实现IIC的模式时序,编写发送和接收字节的函数,同时根据读取和写入的流程,编写读取和写入的函数,便于在存储的时候直接使用。

#include "fm24c04.h"

/*==========================================##### 依照I2C协议编写的时序函数 #####=========================================*/
/**
 * @brief 延时函数
 */
static void BSP_I2C_Delay(uint32_t us)
{
    while (us--);
}

/**
 * @brief  设置I2C速度
 * @param  speed : I2C速度,单位Kbps
 * @retval 返回设置前的I2C速度
 * @note   I2C速度设置范围是: 1Kbps ~ 400Kbps
 */
uint16_t I2C_SetSpeed(uint16_t speed)
{
    uint16_t temp;

    // I2C速度必须小于400Kbps,大于 1Kbps
    if ((speed > 400) || (speed < 1))
        return 0;

    temp = I2C_SPEED_1K / i2c_speed;    //备份原来的i2c速度
    i2c_speed = I2C_SPEED_1K / speed;   //设置新的i2c速度

    return temp;    //返回设置前的i2c速度
}

/**
 * @brief 产生I2C起始信号
 * @note
  *       请参考I2C通信协议,I2C起始信号:当SCL为高电平时,SDA由高变低
  *       如下图所示:方框部分表示I2C起始信号
 *           _____     |
 *        __|__   |    |  ___  ___  ___  ___  ___  ___  ___  ___
 *   SDA:   |  \__|____|_/   \/   \/   \/   \/   \/   \/   \/   \     /
 *          |     |    | \___/\___/\___/\___/\___/\___/\___/\___/\___/
 *        __|_____|_   |   _    _    _    _    _    _    _    _    _
 *   SCL:   |     | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_
 *          |_____|    |
 *           start         D7   D6   D5   D4   D3   D2   D1   D0   ACK
 */
void I2C_Start(void)
{
    uint32_t i2c_delay = i2c_speed;

    SDA_OUT();      // SDA设置为输出
    I2C_SDA_HIGH;   // SDA: 高
    I2C_SCL_HIGH;   // SCL: 高

    BSP_I2C_Delay(i2c_delay);   // 延时>4.7us

    I2C_SDA_LOW;                // 当SCL为高电平时,SDA由高变低
    BSP_I2C_Delay(i2c_delay);   // 延时>4us

    I2C_SCL_LOW;    // SCL变低,钳住I2C总线,准备发送或接收数据
}

/**
 * @brief 产生I2C停止信号
 * @note
  *       请参考I2C通信协议,I2C停止信号:当SCL为高电平时,SDA由低变高
  *       发送完STOP信号后,SCL和SDA都为高电平,即释放了I2C总线
  *       如下图所示:方框部分表示I2C起始信号
 *                                    _____
 *         ___  ___  ___  ___        |   __|_
 *   SDA: /   \/   \/   \/   \       |  /  |
 *        \___/\___/\___/\___/\______|_/   |
 *         _    _    _    _    _    _|_____|_
 *   SCL: / \__/ \__/ \__/ \__/ \__/ |     |
 *                                   |_____|
 *        D3   D2   D1   D0   ACK     stop
 */
void I2C_Stop(void)
{
    uint32_t i2c_delay = i2c_speed;

    SDA_OUT();                  // SDA设置为输出
    I2C_SDA_LOW;                // SDA低电平
    I2C_SCL_HIGH;               // SCL高电平
    BSP_I2C_Delay(i2c_delay);   // 延时>4us

    I2C_SDA_HIGH;               // STOP:当SCL为高电平时,SDA由低变高
    BSP_I2C_Delay(i2c_delay);   // 延时>4.7us
}

/**
 * @brief  等待ACK应答信号
 * @retval 1 - 未接收到应答信号ACK;0 - 接收到应答信号ACK
 * @note
  *       请参考I2C通信协议,检测ACK应答信号:当SCL为高电平时,读取SDA为低电平
  *       如下图所示:方框部分表示I2C起始信号
 *                             ________     _____
 *         ___  ___  ___  ___ | _      |   |   __|_
 *   SDA: /   \/   \/   \/   \|/ \     |   |  /  |
 *        \___/\___/\___/\___/|   \____|___|_/   |
 *         _    _    _    _   | _____  |  _|_____|
 *   SCL: / \__/ \__/ \__/ \__|/     \_|_/ |     |
 *                            |________|   |_____|
 *        D3   D2   D1   D0      ACK        stop
 */
uint8_t I2C_Wait_ACK(void)
{
    uint32_t i2c_delay = i2c_speed;
    uint8_t timeout = 0;

    SDA_IN();           // SDA设置为输入
    I2C_SDA_HIGH;       // SDA上拉输入
    I2C_SCL_HIGH;       // SCL设置为高电平
    BSP_I2C_Delay(i2c_delay);

    while (I2C_SDA_READ() == 1)  // 等待ACK
    {
        if (timeout++ > 250)
        {
            I2C_Stop();
            return 1;
        }
    }

    I2C_SCL_LOW;        // 钳住I2C总线:时钟信号设为低电平
    return 0;
}

/**
 * @brief  产生ACK应答信号
 * @note
  *       请参考I2C通信协议,产生ACK应答信号: 在SDA为低电平时,SCL产生一个正脉冲
  *       如下图所示:方框部分表示I2C起始信号
 *                             _____     _____
 *         ___  ___  ___  ___ |     |   |   __|_
 *   SDA: /   \/   \/   \/   \|     |   |  /  |
 *        \___/\___/\___/\___/|\____|___|_/   |
 *         _    _    _    _   |  _  |  _|_____|_
 *   SCL: / \__/ \__/ \__/ \__|_/ \_|_/ |     |
 *                            |_____|   |_____|
 *        D3   D2   D1   D0     ACK      stop
 */
void I2C_ACK(void)
{
    uint32_t i2c_delay = i2c_speed;

    I2C_SCL_LOW;                // 低电平
    SDA_OUT();                  // 设置SDA为输出
    I2C_SDA_LOW;                // ACK信号
    BSP_I2C_Delay(i2c_delay);   // 延时>4us

    I2C_SCL_HIGH;               // 高电平
    BSP_I2C_Delay(i2c_delay);   // 延时>4us
    I2C_SCL_LOW;                // 钳住I2C总线:时钟信号设为低电平
}

/**
 * @brief  产生非应答信号NACK
 * @note
  *       请参考I2C通信协议,产生ACK应答信号: 在SDA为高电平时,SCL产生一个正脉冲
  *       如下图所示:方框部分表示I2C起始信号
 *                             _____      ______
 *         ___  ___  ___  ___ | ____|_   |    __|_
 *   SDA: /   \/   \/   \/   \|/    | \  |   /  |
 *        \___/\___/\___/\___/|     |  \_|__/   |
 *         _    _    _    _   |  _  |  __|______|_
 *   SCL: / \__/ \__/ \__/ \__|_/ \_|_/  |      |
 *                            |_____|    |______|
 *        D3   D2   D1   D0    NACK        stop
 */
void I2C_NACK(void)
{
    uint32_t i2c_delay = i2c_speed;

    I2C_SCL_LOW;                // 低电平
    SDA_OUT();                  // SDA设置为输出
    I2C_SDA_HIGH;               // NACK信号
    BSP_I2C_Delay(i2c_delay);   // 延时>4us

    I2C_SCL_HIGH;               // 高电平
    BSP_I2C_Delay(i2c_delay);   // 延时>4us
    I2C_SCL_LOW;                // 钳住I2C总线:时钟信号设为低电平
}

/**
 * @brief  I2C发送一个字节
 * @note
  *       请参考I2C通信协议,产生ACK应答信号: 在SDA为高电平时,SCL产生一个正脉冲
  *       如下图所示:方框部分表示I2C起始信号
 *
 *           _____     |<------------I2C数据发送周期------------>|
 *        __|__   |    |  ___  ___  ___  ___  ___  ___  ___  ___ | _
 *   SDA:   |  \__|____|_/   \/   \/   \/   \/   \/   \/   \/   \|/
 *          |     |    | \___/\___/\___/\___/\___/\___/\___/\___/|\_
 *        __|_____|_   |   _    _    _    _    _    _    _    _  |
 *   SCL:   |     | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_|_
 *          |_____|    |                                         |
 *           start     |   D7   D6   D5   D4   D3   D2   D1   D0 |
 */
void I2C_Send_Byte(uint8_t data)
{
    uint8_t i = 0;
    uint32_t i2c_delay = i2c_speed;

    SDA_OUT();                          // SDA设为输出
    I2C_SCL_LOW;                        // 钳住I2C总线:SCL设为低电平
    for (i = 0; i < 8; i++)
    {
        if (data & 0x80)
            I2C_SDA_HIGH;               // 高位先传
        else
            I2C_SDA_LOW;

        BSP_I2C_Delay(i2c_delay);       // 延时>4us

        I2C_SCL_HIGH;                   // 在SCL上产生一个正脉冲
        BSP_I2C_Delay(i2c_delay);       // 延时>4us

        I2C_SCL_LOW;
        BSP_I2C_Delay(i2c_delay / 3);   // 延时>1us
        data <<= 1;                     // 右移一位
    }
}

/**
 * @brief  从I2C读取一个字节
 * @param  ack : 0 - NACK; 1 - ACK
 * @retval 接收到的数据
 * @note
  *       请参考I2C通信协议,产生ACK应答信号: 在SDA为高电平时,SCL产生一个正脉冲
  *       如下图所示:方框部分表示I2C起始信号
 *
 *           _____     |<------------I2C数据读取周期(ACK)------------>|
 *        __|__   |    |  ___  ___  ___  ___  ___  ___  ___  ___      |
 *   SDA:   |  \__|____|_/   \/   \/   \/   \/   \/   \/   \/   \     |
 *          |     |    | \___/\___/\___/\___/\___/\___/\___/\___/\____|_
 *        __|_____|_   |   _    _    _    _    _    _    _    _    _  |
 *   SCL:   |     | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_|_
 *          |_____|    |                                              |
 *           start     |   D7   D6   D5   D4   D3   D2   D1   D0   ACK
 *
 *           _____     |<------------I2C数据读取周期(NACK)----------->|
 *        __|__   |    |  ___  ___  ___  ___  ___  ___  ___  ___  ____|_
 *   SDA:   |  \__|____|_/   \/   \/   \/   \/   \/   \/   \/   \/    |
 *          |     |    | \___/\___/\___/\___/\___/\___/\___/\___/     |
 *        __|_____|_   |   _    _    _    _    _    _    _    _    _  |
 *   SCL:   |     | \__|__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_|_
 *          |_____|    |                                              |
 *           start     |   D7   D6   D5   D4   D3   D2   D1   D0  NACK
 */
uint8_t I2C_Read_Byte(uint8_t ack)
{
    uint8_t i, receive = 0x00;
    uint32_t i2c_delay = i2c_speed;

    I2C_SCL_LOW;                    // SCL低电平
    SDA_IN();                       // SDA设置为输入
    for (i = 0; i < 8; i++)
    {
        BSP_I2C_Delay(i2c_delay);
        I2C_SCL_HIGH;               // 高电平
        BSP_I2C_Delay(i2c_delay);

        receive <<= 1;
        if (I2C_SDA_READ())
            receive |= 1;           // 高位在前

        I2C_SCL_LOW;
    }

    if (ack == 0)
        I2C_NACK();                 // 发送NACK
    else
        I2C_ACK();                  // 发送ACK

    return receive;                 // 返回接收到的数据
}
/*=================================================#######  END  #######=====================================================*/

/*=============================================##### 封装好的I2C读写函数 #####===========================================*/
/**
 * @brief  模拟I2C接口初始化
 * @note
 *       SCL:    PB10
 *       SDA:    PB11
 */
void BSP_I2C_Init(void)
{
    I2C_SetSpeed(100); //设置I2C访问速度为100Kbps
    rt_pin_mode(I2C_SCL_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(I2C_SDA_PIN, PIN_MODE_OUTPUT);

    I2C_SCL_HIGH;
    I2C_SDA_HIGH;
}

/**
 * @brief  向设备指定地址写入单一Byte数据
 * @param  DevAddr : I2C从设备地址
 * @param  DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
 * @param  Data    : 写入的数据
 * @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
 * @note
 *   1 - 设备地址DevAddr高7bit是固定的,最低位是读/写(R/W)位,1为读,0为写
 *   2 - 时序:
 *           _______________________________________
 *          | |         |   |        |   |    |   | |
 *   Master:|S|DevAddr+W|   |DataAddr|   |Data|   |P|
 *          |_|_________|___|________|___|____|___|_|
 *           _______________________________________
 *          | |         |   |        |   |    |   | |
 *   Slave: | |         |ACK|        |ACK|    |ACK| |
 *          |_|_________|___|________|___|____|___|_|
 */
I2C_StatusTypeDef I2C_WriteOneByte(uint8_t DevAddr, uint8_t DataAddr, uint8_t Data)
{
    I2C_Start();                          // Master发送起始信号
    I2C_Send_Byte(DevAddr);               // Master发送从设备地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;               // 等待ACK超时错误

#ifdef FM24CL64
        I2C_Send_Byte(DataAddr >> 8);     // 发送高8位数据地址
        if(I2C_Wait_ACK())
        {
            return I2C_TIMEOUT;           // 等待ACK超时错误
        }
        I2C_Send_Byte(DataAddr);          // 发送低八位数据地址
        if(I2C_Wait_ACK())
        {
            return I2C_TIMEOUT;           // 等待ACK超时错误
        }
#else
    I2C_Send_Byte(DataAddr);              // 发送低八位数据地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;               // 等待ACK超时错误
#endif

    I2C_Send_Byte(Data);                  // 发送数据
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;               // 等待ACK超时错误
    I2C_Stop();                           // 发送停止信号
    return I2C_SUCCESS;
}

/**
 * @brief  向设备指定地址连续写入数据(Burst写模式)
 * @param  DevAddr : I2C从设备地址
 * @param  DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
 *                   对于Burst模式,DataAddr一般是设备的FIFO,缓存,或存储设备的数据地址
 * @param  *pData  : 写入的数据首地址
 * @param     Num  : 连续写入的数据个数
 * @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
 * @note
 *   1 - 设备地址DevAddr高7bit是固定的,最低为是读/写(R/W)位,1为读,0为写
 *       2 - 时序:
 *           ____________________________________________________
 *          | |         |   |        |   |    |   |   |    |   | |
 *   Master:|S|DevAddr+W|   |DataAddr|   |Data|   |...|Data|   |P|
 *          |_|_________|___|________|___|____|___|___|____|___|_|
 *           ____________________________________________________
 *          | |         |   |        |   |    |   |   |    |   | |
 *   Slave: | |         |ACK|        |ACK|    |ACK|...|    |ACK| |
 *          |_|_________|___|________|___|____|___|___|____|___|_|
 */
I2C_StatusTypeDef I2C_WriteBurst(uint8_t DevAddr, uint8_t DataAddr, uint8_t* pData, uint32_t Num)
{
    uint32_t i = 0;

    I2C_Start();                                // Master发送起始信号
    I2C_Send_Byte(DevAddr);                     // Master发送从设备地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;                     // 等待ACK超时错误

#ifdef FM24CL64
        I2C_Send_Byte(DataAddr >> 8);           // 发送高8位数据地址
        if(I2C_Wait_ACK()) return I2C_TIMEOUT;  // 等待ACK超时错误
        I2C_Send_Byte(DataAddr);                // 发送低八位数据地址
        if(I2C_Wait_ACK()) return I2C_TIMEOUT;  // 等待ACK超时错误
#else
    I2C_Send_Byte(DataAddr);                    // 发送低八位数据地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;                     // 等待ACK超时错误
#endif

    for (i = 0; i < Num; i++)
    {
        I2C_Send_Byte(*(pData + i));            // 发送数据
        if (I2C_Wait_ACK())
            return I2C_TIMEOUT;                 // 等待ACK超时错误
    }
    I2C_Stop();                                 // 发送停止信号
    return I2C_SUCCESS;
}

/**
 * @brief  从指定设备读取1Byte数据
 * @param  DevAddr : I2C从设备地址
 * @param  DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
 * @param  *Data   : 数据的存放地址
 * @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
 * @note
 *   1 - 设备地址DevAddr高7bit是固定的,最低为是读/写(R/W)位,1为读,0为写
 *       2 - 时序:
 *           _________________________________________________________
 *          | |         |   |        |    | |         |   |    |    | |
 *   Master:|S|DevAddr+W|   |DataAddr|    |S|DevAddr+R|   |    |NACK|P|
 *          |_|_________|___|________|____|_|_________|___|____|____|_|
 *           _________________________________________________________
 *          | |         |   |        |    | |         |   |    |    | |
 *   Slave: | |         |ACK|        |ACK | |         |ACK|Data|    | |
 *          |_|_________|___|________|____|_|_________|___|____|____|_|
 */
I2C_StatusTypeDef I2C_ReadOneByte(uint8_t DevAddr, uint8_t DataAddr, uint8_t* Data)
{
    I2C_Start();                                // Master发送起始信号
    I2C_Send_Byte(DevAddr);                     // Master发送从设备地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;                     // 等待ACK超时错误

#ifdef FM24CL64
        I2C_Send_Byte(DataAddr >> 8);           // 发送高8位数据地址
        if(I2C_Wait_ACK()) return I2C_TIMEOUT;  // 等待ACK超时错误
        I2C_Send_Byte(DataAddr);                // 发送低八位数据地址
        if(I2C_Wait_ACK()) return I2C_TIMEOUT;  // 等待ACK超时错误
#else
    I2C_Send_Byte(DataAddr);                    // 发送低八位数据地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;                     // 等待ACK超时错误
#endif

    I2C_Start();                                // Master发送起始信号
    I2C_Send_Byte(DevAddr + 1);                 // Master发送从设备读地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;                     // 等待ACK超时错误

    *Data = I2C_Read_Byte(0);                   // 读数据,NACK
    I2C_Stop();                                 // 发送停止信号
    return I2C_SUCCESS;
}

/**
 * @brief  向设备指定地址连续读取数据(Burst写模式)
 * @param  DevAddr : I2C从设备地址
 * @param  DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
 *                   对于Burst模式,DataAddr一般是设备的FIFO,缓存,或存储设备的数据地址
 * @param  *pData  : 写入的数据首地址
 * @param     Num  : 连续写入的数据个数
 * @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
 * @note
 *   1 - 设备地址DevAddr高7bit是固定的,最低为是读/写(R/W)位,1为读,0为写
 *       2 - 时序:
 *           _____________________________________________________________________
 *          | |         |   |        |   | |         |   |    |   |   |    |    | |
 *   Master:|S|DevAddr+W|   |DataAddr|   |S|DevAddr+R|   |    |ACK|...|    |NACK|P|
 *          |_|_________|___|________|___|_|_________|___|____|___|___|____|____|_|
 *           _____________________________________________________________________
 *          | |         |   |        |   | |         |   |    |   |   |    |    | |
 *   Slave: | |         |ACK|        |ACK| |         |ACK|Data|   |...|Data|    | |
 *          |_|_________|___|________|___|_|_________|___|____|___|___|____|____|_|
 */
I2C_StatusTypeDef I2C_ReadBurst(uint8_t DevAddr, uint8_t DataAddr, uint8_t* pData, uint32_t Num)
{
    uint32_t i = 0;

    I2C_Start();                                // Master发送起始信号
    I2C_Send_Byte(DevAddr);                     // Master发送从设备地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;                     // 等待ACK超时错误

#ifdef FM24CL64
        I2C_Send_Byte(DataAddr >> 8);           // 发送高8位数据地址
        if(I2C_Wait_ACK()) return I2C_TIMEOUT;  // 等待ACK超时错误
        I2C_Send_Byte(DataAddr);                // 发送低八位数据地址
        if(I2C_Wait_ACK()) return I2C_TIMEOUT;  // 等待ACK超时错误
#else
    I2C_Send_Byte(DataAddr);                    // 发送低八位数据地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;                     // 等待ACK超时错误
#endif

    I2C_Start();                                // Master发送起始信号
    I2C_Send_Byte(DevAddr + 1);                 // Master发送从设备读地址
    if (I2C_Wait_ACK())
        return I2C_TIMEOUT;                     // 等待ACK超时错误

    for (i = 0; i < (Num - 1); i++)
    {
        *(pData + i) = I2C_Read_Byte(1);        // 读数据,ACK
    }
    *(pData + i) = I2C_Read_Byte(0);            // 读数据,NACK

    I2C_Stop();                                 // 发送停止信号
    return I2C_SUCCESS;
}

/**
 * @brief  设置数据的某一位
 * @param  DevAddr : I2C从设备地址
 * @param  DataAddr: 需要访问的设备内地址(如寄存器地址,EEPROM地址等)
 * @param  Bitx  : 第几位
 * @param  BitSet: 需要设置的值
 * @retval I2C访问的结果: I2C_SUCCESS / I2C_TIMEOUT / I2C_ERROR
 * @note
 */
I2C_StatusTypeDef I2C_WriteBit(uint8_t DevAddr, uint8_t DataAddr, uint8_t Bitx, uint8_t BitSet)
{
    I2C_StatusTypeDef status = I2C_ERROR;
    uint8_t tempdata = 0;

    status = I2C_ReadOneByte(DevAddr, DataAddr, &tempdata); // 获取原有数据
    if (status != I2C_SUCCESS)
        return status;                                      // I2C错误,则返回

    tempdata &= ~(1 << Bitx);                               // 将要设定的位清零
    tempdata |= (BitSet << Bitx);                           // 设置指定的bit
    status = I2C_WriteOneByte(DevAddr, DataAddr, tempdata); // 写入数据

    return status;                                          // 返回状态
}
/*=================================================#######  END  #######=====================================================*/

3.main.c
  主要是使用函数来进行数据的读取和写入。

#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "fm24c04.h"

I2C_StatusTypeDef eeStatus = I2C_ERROR;
uint8_t wrEE[5] = {0x10, 0x11, 0x12, 0x13, 0x14};
uint8_t rdEE[5] = {0x00};

int main(void)
{
    rt_pin_mode(GET_PIN(D, 13), PIN_MODE_OUTPUT);
    rt_pin_write(GET_PIN(D, 13), 1);

    BSP_I2C_Init();

#if 1
    // 使用多字节写数据
    I2C_ReadBurst(0xA0, 0, rdEE, 5);

    I2C_WriteBurst(0xA0, 0, wrEE, 5);

    I2C_ReadBurst(0xA0, 0, rdEE, 5);

#else
    // 使用单个字节写数据
    for (int i = 0; i < 5; i++)
    {
        eeStatus = I2C_ReadOneByte(0xA0, i, &rdEE[i]);
    }

    for (int i = 0; i < 5; i++)
    {
        eeStatus = I2C_WriteOneByte(0xA0, i, wrEE[i]);
    }
    eeStatus = I2C_ERROR;
    HAL_Delay(10);

    for (int i = 0; i < 5; i++)
    {
        eeStatus = I2C_ReadOneByte(0xA0, i, &rdEE[i]);
    }

#endif

    while (1)
    {
        rt_thread_mdelay(1000);
    }
}

五、测试验证

  通过将测试代码下载到控制板中,先读取存储芯片中的数据,并打印出存储的数据,将接收到的数据用于实际参数中即可。在存储数据的时候,一般可以使用自动存储的方式,即定时进行存储或者当数据稳定后,将需要存储的数据进行存储,存储的时候,可以自己定义存储的位置,根据上述的内容,进行数据的分区。
  本次实验的IIC模拟时序函数,可以应用于大部分的模拟IIC时序,并且封装的读写函数也可以使用于大部分模拟IIC通信。


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

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

相关文章

Excel 设置自动换行

背景 版本&#xff1a;office 专业版 11.0 表格内输入长信息&#xff0c;发现默认状态时未自动换行的&#xff0c;找了很久设置按钮&#xff0c;遂总结成经验帖。 操作 1&#xff09;选中需设置的单元格/区域/行/列。 2&#xff09;点击【开始】下【对齐方式】中的【自动换…

HAproxy,nginx实现七层负载均衡

环境准备&#xff1a; 192.168.88.25 &#xff08;client&#xff09; 192.168.88.26 &#xff08;HAproxy&#xff09; 192.168.88.27 &#xff08;web1&#xff09; 192.168.88.28 (web2) 192.168.88.29 &#xff08;php1&#xff09; 192.168.88.30…

基于微信小程序的教学质量评价系统ssm(lw+演示+源码+运行)

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于微信小程序的教学质量评价系统的开发全过程。通过分析基于微信小程序的教学质量评价系统管理的不足&#xff0c;创建了一个计算机管理基于微信小程序的教学…

【Anti-UAV410】论文阅读

摘要 无人机在红外视频中的感知&#xff0c;对于有效反无人机是很重要的。现有的跟踪数据集存在目标大小和环境问题&#xff0c;不能完全表示复杂的逼真场景。因此作者就提出了Anti-UAV410数据集&#xff0c;该数据集总共410个视频和超过438K个标注框。为了应对复杂环境无人机跟…

丹摩智算(damodel)部署stable diffusion实验

名词解释&#xff1a; 丹摩智算&#xff08;damodel&#xff09;&#xff1a;是一款带有RTX4090&#xff0c;Tesla-P40等显卡的公有云服务器。 stable diffusion&#xff1a;是一个大模型&#xff0c;可支持文生图&#xff0c;图生图&#xff0c;文生视频等功能 一.实验目标 …

Linux-TCP重传

问题描述&#xff1a; 应用系统进行切换&#xff0c;包含业务流量切换&#xff08;即TongWeb主备切换&#xff09;和MYSQL数据库主备切换。首先进行流量切换&#xff0c;然后进行数据库主备切换。切换后发现备机TongWeb上有两批次慢请求&#xff0c;第一批慢请求响应时间在133…

【HarmonyOS】应用引用media中的字符串资源如何拼接字符串

【HarmonyOS】应用引用media中的字符串资源如何拼接字符串 一、问题背景&#xff1a; 鸿蒙应用中使用字符串资源加载&#xff0c;一般文本放置在resoutces-base-element-string.json字符串配置文件中。便于国际化的处理。当然小项目一般直接引用字符串&#xff0c;不需要加载s…

计算机毕业设计 基于Python国潮男装微博评论数据分析系统的设计与实现 Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

LeetCode 149. 直线上最多的点数

LeetCode 149. 直线上最多的点数 给你一个数组 points &#xff0c;其中 points[i] [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。 示例 1&#xff1a; 输入&#xff1a;points [[1,1],[2,2],[3,3]] 输出&#xff1a;3 示例 2&#xff1a; 输入&…

【数据结构之线性表】有序表的合并(链表篇)

链表有序表的合并 思路图 将链表L1和L2按照顺序合并到L3中&#xff08;注&#xff1a;三个链表都是带头结点的&#xff09; A、要实现有序合并&#xff0c;必须先比较L1,L2两表中结点的大小&#xff0c;这里我们暂时先不讨论&#xff0c;直接根据图中来进行思路整理&#xff…

pve主要架构和重要服务介绍

Proxmox VE (PVE) 是一款开源的虚拟化平台&#xff0c;它基于 KVM (Kernel-based Virtual Machine) 和 LXC (Linux Containers) 技术&#xff0c;支持虚拟机和容器的运行。PVE 还提供高可用集群管理、软件定义存储、备份和恢复以及网络管理等企业级功能。下面介绍 PVE 的主要架…

jenkins中多个vue项目共用一个node_modules减少服务器内存的占用,对空间造成资源浪费

多个vue项目使用的node_modules一致&#xff0c;每个项目都安装一遍依赖&#xff0c;对空间造成资源浪费。 通过服务器上的软连接mklink(windows服务器&#xff0c;如果是linux服务器用ln)来共用一套node_modules windows mklink /d [链接文件或目录] [原始文件或目录] 进入…

二叉树的基本概念(下)

文章目录 &#x1f34a;自我介绍&#x1f34a;二叉树的分类满二叉树完全二叉树 &#x1f34a;二叉树的存储顺序存储[完全二叉树]链式存储 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34…

无人机避障——4D 毫米波雷达 SLAM篇(一)

做无人机避障相关工作&#xff0c;3D毫米波避障测试顺利后&#xff0c;开始做4D毫米波雷达无人机避障遇到4D雷达点云需要进行处理的问题&#xff0c;查阅文献&#xff0c;发现以下这篇文章中的建图方法应该为后续思考的方向&#xff0c;特此将这个开源项目进行复现和学习&#…

react crash course 2024(2) 创建项目及vscode插件

使用vite创建react项目 npm create vitelatest react-crash-2024 跳到那个项目 cd .\react-crash-2024 打开那个项目 code . 在vite.config.js中设置端口 安装依赖 npm i 运行 npm run dev vs code插件 rafce //在底部导出的react箭头函数组件

计算机毕业设计 基于Python医院预约挂号系统 Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

【AI】深度学习的数学--核心公式

1 梯度下降 f ( x Δ x , y Δ y ) ≃ f ( x , y ) ∂ f ( x , y ) ∂ x Δ x ∂ f ( x , y ) ∂ y Δ y f(x\Delta x,y\Delta y) \simeq f(x,y)\frac{\partial f(x,y)}{\partial x}\Delta x\frac{\partial f(x,y)}{\partial y}\Delta y f(xΔx,yΔy)≃f(x,y)∂x∂f(x,y)​…

聚观早报 | 豆包视频生成大模型发布;华为纯血鸿蒙将开启公测

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 9月25日消息 豆包视频生成大模型发布 华为纯血鸿蒙将开启公测 高德地图将发放百亿补贴 12306上线“车内换座”新…

RK3568笔记六十三:基于LVGL的Linux相机

若该文为原创文章,转载请注明原文出处。 记录移植韦老师的基于LVGL的Linux相机项目,主要是想学习如何在LVGL下显示摄像头数据。 此项目是基于老师的源码框架移植的,地址是lv_100ask_linux_camera: 基于LVGL的Linux相机 (gitee.com) 个人使用的是RK3568,正点原子板子,所以…

CTF-PWN方向自学习笔记

基础知识 栈的结构 熟悉如下寄存器 db 定义的是1Byte的变量 也就是8位 define byte dd 定义的通常是4字节的变量 也就是32位 Define Double Word dw 定义一个16位 也就是2字节的变量 Define Word dq 定义一个8字节 也就是64位的变量 多少位的机器就表示一个字是多少位 x86…