软件I2C读SHT20温湿度传感器

发布时间 2023-08-30 18:48:36作者: Yannnnnnn

使用GPIO模拟I2C、

开始信号S void S_Soft_I2C_Start(void);
结束信号P void S_Soft_I2C_Stop(void );
发送1字节 void S_Soft_I2C_Send_1Byte(uint8_t S_I2C_Byte);
接收1字节 uint8_t S_Soft_I2C_Receive_1Byte(void);
发送应答 void S_Soft_I2C_Send_ACK(uint8_t S_ACK);
接收应答 uint8_t S_Soft_I2C_Receive_ACK(void);

软件IIC基本单元

#include "main.h"


/*
*软件实现IIC
*SCL:PB6
*SDA:PB7
*/

/*
*IIC时序基本单元
起始条件:SCL高电平时,SDA由高转低
结束条件:SCL高电平时,SDA由低转高
发送:SCL低电平,SDA数据转换;SCL高电平,SDA数据读取
接收:SCL低电平,从机改变SDA,主机释放SCL,主机在SCL高电平读取数据
发送应答:SCL高电平主机发送应答位,0=ACK 1=NACK
接收应答:SCL高电平主机接收应答位


*IIC时序
1.指定地址写
(S)(SlaveAddress+W)(ACK)(SendByte1)(ACK)(SendByte2)(ACK)(P)
2.当前地址读
(S)(SlaveAddress+R)(ACK)(ReceiveByte)(NACK)(P)
3.指定地址读
(S)(SlaveAddress+W)(ACK)(SendByte1/RegAddress)(ACK)(S repeat)(SlaveAddress+R)(RecerveByte)(NAK)(P)
*/

/********************************
*SCL:PB6
*SDA:PB7
***********************************/

/*IIC信号延时*/
void S_Soft_I2C_Delay(void)
{
    HAL_Delay(1);
}

/*SCL信号引脚选择*/
#define S_SCL_PORT  GPIOB
#define S_SCL_PIN   GPIO_PIN_6
/*SDA信号引脚选择*/
#define S_SDA_PORT  GPIOB
#define S_SDA_PIN   GPIO_PIN_7
/*SCL信号置高低电平*/
#define S_SCL_1 HAL_GPIO_WritePin(S_SCL_PORT,S_SCL_PIN,GPIO_PIN_SET);S_Soft_I2C_Delay()
#define S_SCL_0 HAL_GPIO_WritePin(S_SCL_PORT,S_SCL_PIN,GPIO_PIN_RESET);S_Soft_I2C_Delay()
/*SDA信号置高低电平*/
#define S_SDA_1 HAL_GPIO_WritePin(S_SDA_PORT,S_SDA_PIN,GPIO_PIN_SET);S_Soft_I2C_Delay()
#define S_SDA_0 HAL_GPIO_WritePin(S_SDA_PORT,S_SDA_PIN,GPIO_PIN_RESET);S_Soft_I2C_Delay()
/*读SDA信号值*/
#define S_SDA_R HAL_GPIO_ReadPin(S_SDA_PORT, S_SDA_PIN)


/**IIC引脚配置*/
void S_Soft_I2C_Init(void)
{

        /*GPIO引脚使能*/
        __HAL_RCC_GPIOB_CLK_ENABLE();
        /*配置SCL引脚*/
        GPIO_InitTypeDef S_GPIO_Init;
        S_GPIO_Init.Pin = S_SCL_PIN; //i2c_SCL
        S_GPIO_Init.Mode = GPIO_MODE_OUTPUT_OD;
        S_GPIO_Init.Pull = GPIO_NOPULL;
        S_GPIO_Init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        HAL_GPIO_Init(S_SCL_PORT, &S_GPIO_Init);
        /*配置SDA引脚*/
        S_GPIO_Init.Pin = S_SDA_PIN; //i2c_SDA
        S_GPIO_Init.Mode = GPIO_MODE_OUTPUT_OD;
        S_GPIO_Init.Pull = GPIO_NOPULL;
        S_GPIO_Init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        HAL_GPIO_Init(S_SDA_PORT, &S_GPIO_Init);
        
        /*初始化SCL,SDA为高电平*/
        S_SCL_1;
        S_SDA_1;
}

/**IIC开始信号S*/
void S_Soft_I2C_Start(void)
{
    /*先拉高SDA再拉高SCL,避免可能为P信号*/
    S_SDA_1;
    S_SCL_1;
    /*SDA在SCL高位拉低,S信号产生,之后拉低SCL,准备发送数据*/
    S_SDA_0;
    S_SCL_0;
}
/*IIC停止信号P*/
void S_Soft_I2C_Stop(void )
{
    /*在SCL高电平时,SDA由低转高,产生停止信号P*/
    S_SDA_0;
    S_SCL_1;
    S_SDA_1;
}

/*IIC发送一个字节*/
void S_Soft_I2C_Send_1Byte(uint8_t S_I2C_Byte)
{
    uint8_t i;
    /*从高位到低位,按bit循环发送1字节*/
    for(i=0;i<8;i++)
    {
            if((S_I2C_Byte & (0x80>>i)) == 0)
        {
            S_SDA_0;//此位为0,SDA写低电平
        }else
        {
            S_SDA_1;//此位为1,SDA写高电平
        }
        /*SCL变为高电平,此时从机允许读SDA*/
        S_SCL_1;
        /*从机读完SDA,SCL拉低,主机可以开始写SDA下一位*/
        S_SCL_0;
        
    }
}

/*接收一个字节*/
uint8_t S_Soft_I2C_Receive_1Byte(void)
{
    S_SDA_1;//主机释放SDA,从机才能写SDA,此时SCL为低,从机写SDA
    uint8_t S_I2C_Byte = 0x00;
    uint8_t i;
    for(i=0;i<8;i++)
    {
         S_SCL_1;//SCL拉高,固定SDA
        /*主机读SDA*/
        if(S_SDA_R == 1)
        {
            
            S_I2C_Byte |= (0x80>>i);
        }
        S_SCL_0;//SCL低,从机写SDA
    
    }

    return S_I2C_Byte;

}

/*发送应答位,0=ACK 1=NACK*/
void S_Soft_I2C_Send_ACK(uint8_t S_ACK)
{

         if(S_ACK == 0)
        {
            S_SDA_0;
        }else
        {
            S_SDA_1;
        }
        S_SCL_1;
        S_SCL_0;
        
    
}
/*接收应答位 0=ACK */
uint8_t S_Soft_I2C_Receive_ACK(void)
{
    S_SDA_1;//主机释放SDA,从机写SDA
    uint8_t S_ACK;

        S_SCL_1;//SCL拉高,固定SDA
        /*读SDA*/
        S_ACK = S_SDA_R;

        S_SCL_0;//SCL低
    return S_ACK;
}

软件IIC读取SHT20温湿度

/*Soft I2C 温度测量函数,返回温度值*/
float SHT20_Get_Temperature_SoftI2C(void)
{
    uint8_t DataBuff[3] = {0};
    uint16_t DataBuff_Link = 0;
    uint8_t sACK;
    float  SHT20_Temperature = 0;
    
    S_Soft_I2C_Start();
    S_Soft_I2C_Send_1Byte(SHT20_address+0);
    sACK = S_Soft_I2C_Receive_ACK();
    if(sACK==1)printf("NACK\n");
    S_Soft_I2C_Send_1Byte(CMD_T_Measure_noHold);
    sACK = S_Soft_I2C_Receive_ACK();
    if(sACK==1)printf("NACK\n");
    HAL_Delay(1);
    S_Soft_I2C_Stop();

    
    HAL_Delay(100);
    
    S_Soft_I2C_Start();
    S_Soft_I2C_Send_1Byte(SHT20_address+1);
    sACK = S_Soft_I2C_Receive_ACK();
    if(sACK==1)printf("NACK\n");
    DataBuff[0] = S_Soft_I2C_Receive_1Byte();
    S_Soft_I2C_Send_ACK(0);
    DataBuff[1] = S_Soft_I2C_Receive_1Byte();
    S_Soft_I2C_Send_ACK(0);
    DataBuff[2] = S_Soft_I2C_Receive_1Byte();
    S_Soft_I2C_Send_ACK(1);
    S_Soft_I2C_Stop();
    
    DataBuff_Link =(uint16_t)DataBuff[0];
    DataBuff_Link=DataBuff_Link<<8;
    DataBuff_Link=DataBuff_Link + (DataBuff[1] & 0xfc);

    //printf("DataBuff_Link = %d\n",DataBuff_Link);
    
    
    SHT20_Temperature = -46.85+175.72*((float)DataBuff_Link/65536);
    return SHT20_Temperature;

}

/*Soft I2C 湿度测量函数,返回温度值*/
float SHT20_Get_Humidity_SoftI2C(void)
{
    
    uint8_t DataBuff[3] = {0};
    uint16_t DataBuff_Link = 0;
    uint8_t sACK;
    float  SHT20_Humidity = 0;
    
    S_Soft_I2C_Start();
    S_Soft_I2C_Send_1Byte(SHT20_address+0);
    sACK = S_Soft_I2C_Receive_ACK();
    if(sACK==1)printf("NACK\n");
    S_Soft_I2C_Send_1Byte(CMD_RH_Measure_noHold);
    sACK = S_Soft_I2C_Receive_ACK();
    if(sACK==1)printf("NACK\n");
    HAL_Delay(1);
    S_Soft_I2C_Stop();

    
    HAL_Delay(100);
    
    S_Soft_I2C_Start();
    S_Soft_I2C_Send_1Byte(SHT20_address+1);
    sACK = S_Soft_I2C_Receive_ACK();
    if(sACK==1)printf("NACK\n");
    DataBuff[0] = S_Soft_I2C_Receive_1Byte();
    S_Soft_I2C_Send_ACK(0);
    DataBuff[1] = S_Soft_I2C_Receive_1Byte();
    S_Soft_I2C_Send_ACK(0);
    DataBuff[2] = S_Soft_I2C_Receive_1Byte();
    S_Soft_I2C_Send_ACK(1);
    S_Soft_I2C_Stop();
    
    DataBuff_Link =(uint16_t)DataBuff[0];
    DataBuff_Link=DataBuff_Link<<8;
    DataBuff_Link=DataBuff_Link + (DataBuff[1] & 0xfc);

    //printf("DataBuff_Link = %d\n",DataBuff_Link);
    
    
    SHT20_Humidity = -6+125*((float)DataBuff_Link/65536);
    return SHT20_Humidity;

}

/*soft IIC 使用串口打印温度和湿度值*/
void SHT20_test_soft_I2C(void )
{

    printf("Temperature = %f\n",SHT20_Get_Temperature_SoftI2C());
    HAL_Delay(20);
    printf("Humidity    = %f\n",SHT20_Get_Humidity_SoftI2C());


}

 

结果发送到串口