打印
[STM32F1]

VSCODE STM32 裸机之I2C总线 AT24C02

[复制链接]
714|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 zero949079783 于 2021-11-21 16:32 编辑

开发环境:VSCODE(gcc编译链)+STM32CubeMX(也可以使用HUAWEI-LiteOS-Studio) 。
代码:链接:https://pan.baidu.com/s/1uXfIR0GFQOBZPl1NfQP08w  
提取码:6b0c



Master  features  主模式特性

I2C Speed Mode: IIC模式设置 快速模式和标准模式。实际上也就是速率的选择。

I2C Clock Speed:I2C传输速率,默认为100KHz

Slave  features  从模式特性

Clock No Stretch Mode: 时钟没有扩展模式

IIC时钟拉伸(Clock stretching)
clock stretching通过将SCL线拉低来暂停一个传输.直到释放SCL线为高电平,传输才继续进行.clock stretching是可选的,实际上大多数从设备不包括SCL驱动,所以它们不能stretch时钟.
Primary Address Length selection: 从设备地址长度 设置从设备的地址是7bit还是10bit 大部分为7bit
-Dual Address Acknowledged: 双地址确认

Primary slave address:  从设备初始地址

stm32f4xx_hal_i2c.c文件:
1、HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout)  //  Checks if target device is ready for communication.


eg:
    //检查设备是否准备好,地址检查,次数超时
    status=HAL_I2C_IsDeviceReady(&hi2c1, ADDRESS_W, 10, HAL_MAX_DELAY);

2、HAL_I2C_StateTypeDef HAL_I2C_GetState(I2C_HandleTypeDef *hi2c)  //Return the I2C handle state. 总线工作状态

eg:        
     //检查总线是否准备好
      flag=HAL_I2C_GetState(&hi2c1);

3、HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)   //Write an amount of data in blocking mode to a specific memory address

eg:
//发送写寄存器命令
HAL_I2C_Mem_Write(&hi2c1, ADDRESS_W, MPU_PWR_MGMT1_REG, 1, &pdata, 1, HAL_MAX_DELAY);

4、HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)  
// Read an amount of data in blocking mode from a specific memory address  MemAddSize 只能填1or2,代表8位或者16位,size代表uint16_t。

eg:
//读取寄存器命令
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_R, MPU_DEVICE_ID_REG, 1, &pdata, 1, HAL_MAX_DELAY);

#define I2C_MEMADD_SIZE_8BIT            0x00000001U  ,上边的1代表的是8bit。
#define I2C_MEMADD_SIZE_16BIT           0x00000010U

HAL库硬件I2C写数据:
/**
* [url=home.php?mod=space&uid=247401]@brief[/url]        AT24C02任意地址写入一个字节
* @param        addr —— 写数据的地址(0-255)
* @param        dat  —— 存放写入数据的地址
* @param             size :数据长度
* @retval        成功 —— HAL_OK
*/
uint32_t AT24C02_Write_Data(uint16_t addr,uint8_t dat)
{
    HAL_StatusTypeDef status = HAL_OK;
    status = HAL_I2C_Mem_Write(&hi2c1,AT24C02_READ_ADD,addr,I2C_MEMADD_SIZE_8BIT,&dat,1,100);
    // if(status != HAL_OK)
        // {
        // /* Execute user timeout callback */
        // }

    while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) //总线超时检测
        {
               
        }

    /*****************************************************************
     检查设备是否准备好,地址检查,次数超时 ,必须加入,否则总线会写进去数据  
    *****************************************************************/
    while (HAL_I2C_IsDeviceReady(&hi2c1, AT24C02_READ_ADD, 300, 300) == HAL_TIMEOUT)   
    {

    }

        // /* Wait for the end of the transfer */
        while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)//总线超时检测
        {
               
        }
        return status;
}

HAL库硬件I2C读数据:

/**
* [url=home.php?mod=space&uid=247401]@brief[/url]        AT24C02任意地址读多个字节数据
* @param        addr —— 读数据的地址(0-255)
* @param        read_buf —— 存放读取数据的地址
* @param        size :数据长度
* @retval        成功 —— HAL_OK
*/
uint32_t  AT24C02_Read_Byte(uint8_t addr, uint8_t *read_buf,uint16_t size)
{
    HAL_StatusTypeDef status = HAL_OK;
        
        status = HAL_I2C_Mem_Read(&hi2c1,AT24C02_READ_ADD,addr,I2C_MEMADD_SIZE_8BIT,read_buf,size,0xFFFF);

        return status;
}


HAL库模拟IIC写数据:
void AT24C02_Write_Data(uint8_t Addr,uint8_t Data){
        
        /* 第1步:发起I2C总线启动信号 */
        I2C_Start();
        /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
        I2C_Write_Byte(AT24C02_WRITE_ADD);
        /* 第3步:等待ACK */
        I2C_Wirte_Ack();
        /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
        I2C_Write_Byte(Addr);
         /* 第5步:等待ACK */
        I2C_Wirte_Ack();
        /* 第6步:开始写入数据 */
        I2C_Write_Byte(Data);
        /* 第7步:发送ACK */
        I2C_Wirte_Ack();
        /* 发送I2C总线停止信号 */
        I2C_Stop();
        delay_ms(5);
}

HAL库模拟IIC读数据:

uint8_t AT24C02_Read_Data(uint8_t Addr)
{
        uint8_t Data;
        /* 第1步:发起I2C总线启动信号 */
        I2C_Start();
         /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
        I2C_Write_Byte(AT24C02_WRITE_ADD);
        /* 第3步:等待ACK */
        I2C_Wirte_Ack();
        /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
        I2C_Write_Byte(Addr);
         /* 第5步:等待ACK */
        I2C_Wirte_Ack();
  /* 第6步:重新启动I2C总线。前面的代码的目的向EEPROM传送地址,下面开始读取数据 */
        I2C_Start();
         /* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
        I2C_Write_Byte(AT24C02_READ_ADD);
        /* 第8步:发送ACK */
        I2C_Wirte_Ack();
        
        /* 第9步:读取数据 */
        Data=I2C_Read_Data();
         /* 第10步:发送ACK */
        I2C_Wirte_Ack();
        /* 发送I2C总线停止信号 */
        I2C_Stop();

        return Data;
}


标准库模拟IIC写数据:

void AT24C02_Write_Data(uint8_t Addr,uint8_t Data){
        
        /* 第1步:发起I2C总线启动信号 */
        I2C_Start();
        /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
        I2C_Write_Byte(AT24C02_WRITE_ADD);/* 此处是写指令 */
        /* 第3步:发送一个时钟,判断器件是否正确应答 */
        I2C_Wirte_Ack();
        /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
        I2C_Write_Byte(Addr);
                /* 第5步:等待ACK */
        I2C_Wirte_Ack();
        /* 第6步:开始写入数据 */
        I2C_Write_Byte(Data);
        /* 第7步:发送ACK */
        I2C_Wirte_Ack();
        /* 命令执行成功,发送I2C总线停止信号 */
        I2C_Stop();
        //写完入后延时
        delay_ms(5);
}

标准库模拟IIC读数据:

uint8_t AT24C02_Read_Data(uint8_t Addr)
{
        uint8_t Data;
        
        /* 第1步:发起I2C总线启动信号 */
        I2C_Start();
        /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
        I2C_Write_Byte(AT24C02_WRITE_ADD);
        /* 第3步:等待ACK */
        I2C_Wirte_Ack();
        /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
        I2C_Write_Byte(Addr);
        /* 第5步:等待ACK */
        I2C_Wirte_Ack();

        /* 第6步:重新启动I2C总线。前面的代码的目的向EEPROM传送地址,下面开始读取数据 */
        I2C_Start();
        /* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
        I2C_Write_Byte(AT24C02_READ_ADD);/* 此处是读指令 */
        /* 第8步:发送ACK */
        I2C_Wirte_Ack();
        /* 第9步:读取数据 */
        Data=I2C_Read_Data();
        /* 第8步:发送ACK */
        I2C_Wirte_Ack();
        /* 命令执行成功,发送I2C总线停止信号 */
        I2C_Stop();
        
        
        return Data;
}



标准库硬件IIC写数据:

<blockquote>/**


标准库硬件IIC读数据:

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]   I2C读多个字节
        *        @param                device_addr        :设备地址
        * @param           addr :地址
        *        @param    data :数据                     
        *        @param          size :数据长度
  *                [url=home.php?mod=space&uid=2817080]@ARG[/url]
  * @retval
  */
uint32_t I2C_Read_Data(uint8_t device_addr,uint8_t addr,uint8_t *data,uint16_t size){
        
        //第一次起始信号
        I2C_GenerateSTART(I2C1,ENABLE );        //起始信号
        
        TimeOut = I2CTIME; //超时检测时间
        while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT ) == ERROR)         //EV5事件
        {
                if(TimeOut-- == 0)        // 防卡死 超时检测时间
                {
                        return 0;
                }
        }
        
        //EV5事件被检测到,发送设备地址
        I2C_Send7bitAddress(I2C1,device_addr,I2C_Direction_Transmitter);//设备地址,写入模式
        
        TimeOut = I2CTIME; //超时检测时间
        while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR)         //写数据EV6事件
        {
                if(TimeOut-- == 0)        // 防卡死 超时检测时间
                {
                        return 0;
                }
        }
        
        //EV6事件被检测到,发送要操作的存储单元地址
        I2C_SendData(I2C1,addr);         //地址
        
        TimeOut = I2CTIME; //超时检测时间
        while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR)         //写数据EV8事件        
        {
                if(TimeOut-- == 0)        // 防卡死 超时检测时间
                {
                        return 0;
                }
        }
        

        //第二次起始信号
        
        I2C_GenerateSTART(I2C1,ENABLE );        //起始信号
        
        TimeOut = I2CTIME; //超时检测时间
        while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT ) == ERROR)         //EV5事件
        {
                if(TimeOut-- == 0)        // 防卡死 超时检测时间
                {
                        return 0;
                }
        }
        
        //EV5事件被检测到,发送设备地址
        I2C_Send7bitAddress(I2C1,EEPROM_I2C_ADDR,I2C_Direction_Receiver);//读入模式
        
        while(size){
               
                if(size==1){
                                
                                //接收最后一个字节
                                I2C_AcknowledgeConfig(I2C1,DISABLE);               
                        }
                                TimeOut = I2CTIME; //超时检测时间
                                while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED  ) == ERROR)         //读数据EV7事件
                                {
                                        if(TimeOut-- == 0)        // 防卡死 超时检测时间
                                        {
                                                return 0;
                                        }
                                }        
                        
                        //EV7事件被检测到时,数据寄存器有新的有效数据
                        *data = I2C_ReceiveData(I2C1);
                        data++; //下一个数据
                        size--;
                }
               
               
                        
        //数据传输完成
        I2C_GenerateSTOP(I2C1,ENABLE);
        //I2C_AcknowledgeConfig(I2C1,ENABLE); //重新配置ACK使能,以便下次通讯
        return 1;        
}







  

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

81

帖子

1

粉丝