[应用相关] STM32模拟IIC 代码

[复制链接]
220|0
Zuocidian 发表于 2025-11-7 21:59 | 显示全部楼层 |阅读模式
STM32模拟IIC 代码
头文件代码:

simulate_i2c.h

#include "stm32f4xx.h"
#include "main.h"

//切换控制IIC时用
extern GPIO_TypeDef*                IIC_SCL_Port;
extern uint16_t                                IIC_SCL_Pin;
extern GPIO_TypeDef*                IIC_SDA_Port;
extern uint16_t                                IIC_SDA_Pin;

//IIC引脚切换
void                setISL21400andTMP75IICPin();
void                setAD5316IICPin();

#define useSimulateIIC

#ifdef useSimulateIIC
#define        SDA_IN()
#define        SDA_OUT()
#define SCL_1()                HAL_GPIO_WritePin(IIC_PA_SCL_GPIO_Port, IIC_PA_SCL_Pin, GPIO_PIN_SET)
#define SCL_0()                HAL_GPIO_WritePin(IIC_PA_SCL_GPIO_Port, IIC_PA_SCL_Pin, GPIO_PIN_RESET)

#define SDA_1()                HAL_GPIO_WritePin(IIC_PA_SDA_GPIO_Port, IIC_PA_SDA_Pin, GPIO_PIN_SET)
#define SDA_0()                HAL_GPIO_WritePin(IIC_PA_SDA_GPIO_Port, IIC_PA_SDA_Pin, GPIO_PIN_RESET)

#define SDA_read()  HAL_GPIO_ReadPin(IIC_PA_SDA_GPIO_Port, IIC_PA_SDA_Pin)

void I2cStart(void);                                                                                //起始信号
void I2cStop(void);                                                                                  //终止信号
void I2cAck(void);                                                                                //发送应答信号
void I2cNAck(void);                                                                        //发送非应答信号
uint8_t I2cWaitAck(void);                                                         //等待应答信号

uint8_t I2cSendByte(uint8_t Byte);                                                //IIC发送一个字节
uint8_t I2cReadByte(void);                                                                        //IIC读取一个字节
#endif

uint8_t CheckDeviceI2C(uint8_t DeviceAddress);        //检测应答

//往器件的一个地址写入一个数据(器件地址,寄存器地址,数据)
uint8_t WriteI2C(uint8_t SlaveAddress,uint8_t RegistAddress,uint8_t RegistData);
//读取器件的一个地址的一个数据(器件地址,寄存器地址)
uint8_t ReadI2C(uint8_t SlaveAddress,uint8_t RegistAddress);

//往器件的一个地址写入一个数据(器件地址,寄存器地址,数据长度,数据数组)
uint8_t setI2C(uint8_t DeviceAddress,uint8_t RegistAddress,uint8_t DateLength,uint8_t* RegistData);
//读取器件的一个地址的一个数据(器件地址,寄存器地址,数据长度,数据数组)
uint8_t getI2C(uint8_t DeviceAddress,uint8_t RegistAddress,uint8_t DateLength,uint8_t* RegistData);


simulate_i2c.c

#include <TimTask.h>
#include "simulate_i2c.h"
#include "main.h"
#include "cmsis_os.h"
#include "globalData.h"

GPIO_TypeDef*                IIC_SCL_Port;
uint16_t                                        IIC_SCL_Pin;
GPIO_TypeDef*                IIC_SDA_Port;
uint16_t                                        IIC_SDA_Pin;

#ifdef        useSimulateIIC

//延时STM32F407ZE -168M,(STM32CubeIDE 优化等级none O0,不然会优化掉无延时)
static void delay_us(uint8_t us){
        uint32_t n;
        switch(us){        //调用函数花的时间约1.21us
                case 1:
                        for(n=0x07; n>0;n--);        //这里调试得的加上调用函数延时1us-1.05us                0x07
                        break;
                case 2:
                        for(n=0x15; n>0;n--);        //这里调试得的加上调用函数延时2us-2.05us                0x15
                        break;
                case 3:
                        for(n=0x23; n>0;n--);        //这里调试得的加上调用函数延时3.0us                                0x23
                        break;
                case 4:
                        for(n=0x31; n>0;n--);        //这里调试得的加上调用函数延时4us-4.05us                0x31
                        break;
                case 5:
                        for(n=0x3F; n>0;n--);        //这里调试得的加上调用函数延时5us-5.05us                0x3F
                        break;
        }
}

//起始信号
void I2cStart(void){
        SDA_1();
        SCL_1();
        delay_us(4);
        SDA_0();                                //SCL高,SDA下降,起始信号
        delay_us(4);
        SCL_0();
}          

//终止信号
void I2cStop(void){       
        SDA_0();
        SCL_1();
        delay_us(4);
        SDA_1();                                //SCL高,SDA上升,终止信号
        delay_us(4);                                                          
}

//产生ACK应答
void I2cAck(void){       
        SDA_0();
        SCL_0();
        delay_us(1);
        SCL_1();
        delay_us(1);
        SCL_0();
        delay_us(1);
        SDA_1();        //CPU释放SDA总线
}

//产生非应答
void I2cNAck(void){       
        SDA_1();
        SCL_0();
        delay_us(1);
        SCL_1();       
        delay_us(1);
        SCL_0();
        delay_us(1);
        SDA_1();        //CPU释放SDA总线
}

//等待应答
uint8_t I2cWaitAck(void){
        uint16_t n=500;                                //错误等待延时
       
        SDA_IN();                                        //改引脚为输入模式

        while(SDA_read()){                        //等待一定时间的应答,应答超时终止i2c
                n--;
                if(n==0){
                        I2cStop();                        ///未应答。结束
                        return 1;
                }
        }
        SCL_0();
        SDA_OUT();                                        //改引脚为输出模式
        return 0;  
}
                                                                              
//通过I2C发送一个字节,返回0发送成功,1未应答
uint8_t I2cSendByte(uint8_t Byte){                        
  uint8_t i,ack;
       
        for(i=0;i<8;i++){       
                if(Byte>>7){
                        SDA_1();
                }else{
                        SDA_0();
                }
                Byte<<= 1;
                delay_us(2);
                SCL_1();                                        //发送有效电平
                delay_us(2);       
                SCL_0();       
                delay_us(2);
        }
       
        SDA_1();                                                //释放SDA总线
        delay_us(1);
        SCL_1();       
        delay_us(1);       
       
        ack=I2cWaitAck();
        return ack;
}

//使用I2c读取一个字节
uint8_t I2cReadByte(void){
        uint8_t i,value=0;
        SDA_IN();                                //改引脚为输入模式
                for(i=0;i<8;i++ ){
                        SCL_0();
                        delay_us(2);
                        SCL_1();
                        value<<=1;
                        if(SDA_read()){
                                value++;
                        }
                        delay_us(1);
    }                 
                SCL_0();
                SDA_OUT();                        //改引脚为输出模式
    return value;
}

//通过应答判断从机是否正常,为未应答返回1,应答返回0
uint8_t CheckDeviceI2C(uint8_t DeviceAddress){
        uint8_t ack;
        I2cStop();                                                                //给一个停止信号, 复位I2C总线上的所有设备到待机模式
        I2cStart();                                                                //起始信号
        ack=I2cSendByte((DeviceAddress<<1)|0);        //发送设备地址+读写控制bit(0=wite,1=read)
        I2cStop();
        return ack;
}

//往器件的一个地址写入一个数据(器件地址,寄存器地址,数据)
uint8_t WriteI2C(uint8_t SlaveAddress,uint8_t RegistAddress,uint8_t RegistData){
  I2cStart();                                                                 //起始信号
        if(I2cSendByte((SlaveAddress<<1)|0)){        //发送设备地址+写信号
                I2cStop();                 
                return 1;               
        }
  I2cSendByte(RegistAddress);                                //内部寄存器地址
        if(I2cSendByte(RegistData)){                        //内部寄存器数据
                I2cStop();         
                return 1;                 
        }                 
  I2cStop();                                                                 //发送停止信号
        return 0;
}

//读取器件的一个地址的一个数据(器件地址,寄存器地址)
uint8_t ReadI2C(uint8_t SlaveAddress,uint8_t RegistAddress){
        uint8_t REG_data;
  I2cStart();                                                                 //起始信号
        if(I2cSendByte((SlaveAddress<<1)|0)){        //发送设备地址+写信号
                I2cStop();                 
                return 1;               
        }
  I2cSendByte(RegistAddress);                                //内部寄存器地址

  I2cStart();
        if(I2cSendByte((SlaveAddress<<1)|1)){        //发送器件地址+读信号
                I2cStop();                 
                return 1;               
        }
       
        REG_data=I2cReadByte();                                        //读取数据
        I2cNAck();                                                                //不应答
  I2cStop();                                                                //发送停止信号
        return REG_data;               
}

//往器件的一个地址写数据(器件地址,寄存器地址,数据长度,数据数组指针)
uint8_t setI2C(uint8_t DeviceAddress,uint8_t RegistAddress,uint8_t DateLength,uint8_t* RegistData){
        uint8_t i;
  I2cStart();                                                                 //起始信号
        if(I2cSendByte((DeviceAddress<<1)|0)){        //发送设备地址+写信号
                I2cStop();                 
                return 1;               
        }
  I2cSendByte(RegistAddress);                                //内部寄存器地址
        for(i=0;i<DateLength;i++){
                if(I2cSendByte(RegistData[i])){                //连续数据数据
                        I2cStop();         
                        return 1;                 
                }               
        }   
  I2cStop();                                                                 //发送停止信号
        return 0;       
}
//读取器件的一个地址的数据(器件地址,寄存器地址,数据长度,数据数组指针)
uint8_t getI2C(uint8_t DeviceAddress,uint8_t RegistAddress,uint8_t DateLength,uint8_t* RegistData){
        I2cStart();                                                         //起始信号
        if(I2cSendByte((DeviceAddress<<1)|0)){        //发送设备地址+写信号
                I2cStop();                 
                return 1;               
        }
  I2cSendByte(RegistAddress);                                //内部寄存器地址
       
  I2cStart();                                                                //起始信号
        if(I2cSendByte((DeviceAddress<<1)|1)){        //发送设备地址+读信号
                I2cStop();                 
                return 1;               
        }
        while(1){                                                                //连续读数据
                if(DateLength==1){
                        *RegistData=I2cReadByte();
                        I2cNAck();                                                       
                        break;
                }else{                                
                        *RegistData=I2cReadByte();
                        I2cAck();
                        DateLength--;
                        RegistData++;
                }
        }   
  I2cStop();                                                                //发送停止信号
        return 0;       
}

#else
/******* Blocking mode: Polling
* i2c里面:  __HAL_RCC_I2C1_CLK_ENABLE();
*
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);
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);
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);
HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout);
*/

uint8_t CheckDeviceI2C(uint8_t DeviceAddress){
        //检查设备是否淮备好 地址 检查次数 超时时间
                return HAL_I2C_IsDeviceReady(&hi2c1, DeviceAddress, 1, 100);
}

//往器件的一个地址写入一个数据(器件地址,寄存器地址,数据)
uint8_t WriteI2C(uint8_t SlaveAddress,uint8_t RegistAddress,uint8_t RegistData){
                SlaveAddress=(SlaveAddress<<1);
                return HAL_I2C_Mem_Write(&hi2c1,SlaveAddress,RegistAddress,I2C_MEMADD_SIZE_8BIT,&RegistData,1,100);
}
//读取器件的一个地址的一个数据(器件地址,寄存器地址)
uint8_t ReadI2C(uint8_t SlaveAddress,uint8_t RegistAddress){
        uint8_t  readData;
                SlaveAddress=(SlaveAddress<<1)+1;
                HAL_I2C_Mem_Read(&hi2c1,SlaveAddress,RegistAddress,I2C_MEMADD_SIZE_8BIT,&readData,1,100);
        return readData;
}
//往器件的一个地址写数据(器件地址,寄存器地址,数据长度,数据数组指针)
uint8_t setI2C(uint8_t DeviceAddress,uint8_t RegistAddress,uint8_t DateLength,uint8_t* RegistData){
                DeviceAddress=(DeviceAddress<<1);
                return HAL_I2C_Mem_Write(&hi2c1,DeviceAddress,RegistAddress,I2C_MEMADD_SIZE_8BIT,RegistData,DateLength,100);

}
//读取器件的一个地址的数据(器件地址,寄存器地址,数据长度,数据数组指针)
uint8_t getI2C(uint8_t DeviceAddress,uint8_t RegistAddress,uint8_t DateLength,uint8_t* RegistData){
                DeviceAddress=(DeviceAddress<<1)+1;
                return HAL_I2C_Mem_Read(&hi2c1,DeviceAddress,RegistAddress,I2C_MEMADD_SIZE_8BIT,RegistData,DateLength,100);
}
#endif


需要示波器调试simulate_i2c.c的delay函数:

//延时STM32F407ZE -168M,(STM32CubeIDE 优化等级none O0,不然会优化掉无延时)
static void delay_us(uint8_t us){
            uint32_t n;
            switch(us){      //调用函数花的时间约1.21us
                        case 1:
                                    for(n=0x07; n>0;n--); //这里调试得的加上调用函数延时1us-1.05us                0x07
                                    break;
                        case 2:
                                    for(n=0x15; n>0;n--); //这里调试得的加上调用函数延时2us-2.05us                0x15
                                    break;
                        case 3:
                                    for(n=0x23; n>0;n--); //这里调试得的加上调用函数延时3.0us                     0x23
                                    break;
                        case 4:
                                    for(n=0x31; n>0;n--); //这里调试得的加上调用函数延时4us-4.05us                0x31
                                    break;
                        case 5:
                                    for(n=0x3F; n>0;n--);  //这里调试得的加上调用函数延时5us-5.05us                0x3F
                                    break;
            }
}



————————————————
版权声明:本文为CSDN博主「几个叶子」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44015616/article/details/153936969

您需要登录后才可以回帖 登录 | 注册

本版积分规则

98

主题

301

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部