I2C的Hal库寄存器编程

想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

一.使用寄存器编程写入EEPROM
EEPROM 写入的完整过程本质上是一次标准的 I2C Memory Write 时序:首先配置并使能 STM32 的 I2C 外设,随后依次发送 START 信号、EEPROM 器件地址(写方向)、待写入的 EEPROM 内部存储地址,紧接着将 1 字节(或多字节)数据通过 I2C 数据寄存器(DR)发送出去(这一时刻数据才真正进入 EEPROM),最后发送 STOP 信号结束总线通信;但由于 EEPROM 接收到数据后还需进行内部 Flash 写操作(tWR),此时它会暂时停止响应 I2C 总线,因此必须通过一个“轮询 ACK”的过程(即不断发送 START 和器件地址直到收到 ACK)来等待 EEPROM 内部写完成,只有完成这一步,一次 EEPROM 写入才算彻底结束。

uint32_t I2C_EE_ByteWrite(uint8_t* pBuffer, uint8_t WriteAddr)
{
    uint32_t timeout;

    /*--------------------------------------------------
     * 1. 发送 START
     *--------------------------------------------------*/
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));

    /*--------------------------------------------------
     * 2. 发送 EEPROM 器件地址(写)
     *--------------------------------------------------*/
    I2C1->DR = EEPROM_ADDRESS;   // 0xA0
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;             // 清 ADDR

    /*--------------------------------------------------
     * 3. 发送 EEPROM 内部地址
     *--------------------------------------------------*/
    I2C1->DR = WriteAddr;
    while (!(I2C1->SR1 & I2C_SR1_TXE));

    /*--------------------------------------------------
     * 4. 发送数据
     *--------------------------------------------------*/
    I2C1->DR = *pBuffer;
    while (!(I2C1->SR1 & I2C_SR1_TXE));

    /*--------------------------------------------------
     * 5. 发送 STOP
     *--------------------------------------------------*/
    I2C1->CR1 |= I2C_CR1_STOP;

    /*--------------------------------------------------
     * 6. 等待 EEPROM 内部写完成  这里,EEPROM在写入时不会应答地址,写入完成后才会应答地址
     *    等价于 HAL_I2C_IsDeviceReady()
     *--------------------------------------------------*/
    timeout = EEPROM_MAX_TRIALS;
    do
    {
        /* 发送 START */
        I2C1->CR1 |= I2C_CR1_START;
        while (!(I2C1->SR1 & I2C_SR1_SB) && timeout);

        /* 发送 EEPROM 地址(写) */
        I2C1->DR = EEPROM_ADDRESS;
        timeout--;
        while (!(I2C1->SR1 & I2C_SR1_ADDR) && timeout);
        (void)I2C1->SR2;

        I2C1->CR1 |= I2C_CR1_STOP;
    }
    while (timeout == 0);

    return (timeout ? HAL_OK : HAL_TIMEOUT);
}

二.读EEPROM:
 

uint32_t I2C_EE_BufferRead(
    uint8_t* pBuffer,
    uint8_t  ReadAddr,
    uint16_t NumByteToRead
)
{
    uint16_t i;

    /*--------------------------------------------------
     * 1. 发送 START
     *--------------------------------------------------*/
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));

    /*--------------------------------------------------
     * 2. 发送 EEPROM 器件地址(写)
     *--------------------------------------------------*/
    I2C1->DR = EEPROM_ADDRESS;   // 0xA0
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;             // 清 ADDR

    /*--------------------------------------------------
     * 3. 发送 EEPROM 内部地址
     *--------------------------------------------------*/
    I2C1->DR = ReadAddr;
    while (!(I2C1->SR1 & I2C_SR1_TXE));

    /*--------------------------------------------------
     * 4. 发送 ReSTART
     *--------------------------------------------------*/
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));

    /*--------------------------------------------------
     * 5. 发送 EEPROM 器件地址(读)
     *--------------------------------------------------*/
    I2C1->DR = EEPROM_ADDRESS | 0x01;
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;

    /*--------------------------------------------------
     * 6. 连续读数据
     *--------------------------------------------------*/
    for (i = 0; i < NumByteToRead; i++)
    {
        /* 最后一个字节前给 ACK,最后一个给 NACK */
        if (i == NumByteToRead - 1)
            I2C1->CR1 &= ~I2C_CR1_ACK;  // NACK
        else
            I2C1->CR1 |= I2C_CR1_ACK;   // ACK

        while (!(I2C1->SR1 & I2C_SR1_RXNE));
        pBuffer[i] = I2C1->DR;
    }

    /*--------------------------------------------------
     * 7. 发送 STOP
     *--------------------------------------------------*/
    I2C1->CR1 |= I2C_CR1_STOP;

    return HAL_OK;
}


二.读EEPROM

uint32_t I2C_EE_BufferRead(
    uint8_t* pBuffer,
    uint8_t  ReadAddr,
    uint16_t NumByteToRead
)
{
    uint16_t i;

    /*--------------------------------------------------
     * 1. 发送 START
     *--------------------------------------------------*/
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));

    /*--------------------------------------------------
     * 2. 发送 EEPROM 器件地址(写)
     *--------------------------------------------------*/
    I2C1->DR = EEPROM_ADDRESS;   // 0xA0
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;             // 清 ADDR

    /*--------------------------------------------------
     * 3. 发送 EEPROM 内部地址
     *--------------------------------------------------*/
    I2C1->DR = ReadAddr;
    while (!(I2C1->SR1 & I2C_SR1_TXE));

    /*--------------------------------------------------
     * 4. 发送 ReSTART
     *--------------------------------------------------*/
    I2C1->CR1 |= I2C_CR1_START;
    while (!(I2C1->SR1 & I2C_SR1_SB));

    /*--------------------------------------------------
     * 5. 发送 EEPROM 器件地址(读)
     *--------------------------------------------------*/
    I2C1->DR = EEPROM_ADDRESS | 0x01;
    while (!(I2C1->SR1 & I2C_SR1_ADDR));
    (void)I2C1->SR2;

    /*--------------------------------------------------
     * 6. 连续读数据
     *--------------------------------------------------*/
    for (i = 0; i < NumByteToRead; i++)
    {
        /* 最后一个字节前给 ACK,最后一个给 NACK */
        if (i == NumByteToRead - 1)
            I2C1->CR1 &= ~I2C_CR1_ACK;  // NACK
        else
            I2C1->CR1 |= I2C_CR1_ACK;   // ACK

        while (!(I2C1->SR1 & I2C_SR1_RXNE));
        pBuffer[i] = I2C1->DR;
    }

    /*--------------------------------------------------
     * 7. 发送 STOP
     *--------------------------------------------------*/
    I2C1->CR1 |= I2C_CR1_STOP;

    return HAL_OK;
}

想深耕嵌入式?这个专辑值得收藏

MCU、FPGA、工控、传感器一站式学习,实战项目直接抄

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值