软件I2C读SHT20温湿度传感器
使用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());
}
结果发送到串口