读写BQ40Z50模块,我使用的是32单片机
该模拟IIC仅适用于BQ40Z50模块,因为每个模块延时有差异
1.初始化GPIO,根据你所使用的单片机完成初始化
__HAL_RCC_GPIOH_CLK_ENABLE();//初始化时钟
/*IIC3 Configure GPIO pins : PIPin PIPin */
GPIO_InitStruct.Pin = IIC3SDA_Pin|IIC3SCL_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
// GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
初始化输入输出模式
#define SDA_IN() {GPIOH->MODER&=~(3<<(8*2));GPIOH->MODER|=0<<8*2;} //PH8
#define SDA_OUT() {GPIOH->MODER&=~(3<<(8*2));GPIOH->MODER|=1<<8*2;} //PH8
#define SDA_OD_OUT() {GPIOH->OTYPER&=~(1<<8);GPIOH->OTYPER|=1<<8;} //PH8
#define SDA_PP_OUT() {GPIOH->OTYPER&=~(1<<8);GPIOH->OTYPER|=0<<8;} //PH8
2.封装管脚拉高拉低函数
//读取数据管脚电平
uint8_t I2C_SDA_READ(GPIO_I2C_ST IICx )
{
return HAL_GPIO_ReadPin(IICx.Gpio_Sda_Port,IICx.Gpio_Sda_Pin);
}
//读取时钟管脚电平
uint8_t I2C_SCL_READ(GPIO_I2C_ST IICx)
{
return HAL_GPIO_ReadPin(IICx.Gpio_Scl_Port,IICx.Gpio_Scl_Pin);
}
//将时钟电平拉高
void I2C_SCL_1(GPIO_I2C_ST IICx )
{
HAL_GPIO_WritePin(IICx.Gpio_Scl_Port,IICx.Gpio_Scl_Pin,GPIO_PIN_SET);
}
//时钟电平拉低
void I2C_SCL_0(GPIO_I2C_ST IICx )
{
HAL_GPIO_WritePin(IICx.Gpio_Scl_Port,IICx.Gpio_Scl_Pin,GPIO_PIN_RESET);
}
//数据电平拉高
void I2C_SDA_1(GPIO_I2C_ST IICx )
{
HAL_GPIO_WritePin(IICx.Gpio_Sda_Port,IICx.Gpio_Sda_Pin,GPIO_PIN_SET);
}
//数据电平拉低
void I2C_SDA_0(GPIO_I2C_ST IICx)
{
HAL_GPIO_WritePin(IICx.Gpio_Sda_Port,IICx.Gpio_Sda_Pin,GPIO_PIN_RESET);
}
3.读写IIC模块
延时是根据硬件IIC计算出来的
/*
开始
*/
void SMbus_Start(GPIO_I2C_ST IICx)
{
SDA_PP_OUT(); //
SDA_OUT(); //
I2C_SDA_1(IICx);
I2C_SCL_1(IICx);
delay_us(50);
I2C_SDA_0(IICx);
delay_us(50);
I2C_SCL_0(IICx);//
}
//结束
void SMbus_Stop(GPIO_I2C_ST IICx)
{
SDA_PP_OUT(); //
SDA_OUT();//
I2C_SCL_0(IICx);
I2C_SDA_0(IICx);//
delay_us(50);
I2C_SCL_1(IICx);
delay_us(10);
I2C_SDA_1(IICx);//
delay_us(50);
}
//发送ACK
void SMbus_Ack(GPIO_I2C_ST IICx)
{
SDA_PP_OUT();
SDA_OUT();
I2C_SCL_0(IICx);
I2C_SDA_0(IICx);
delay_us(60);
I2C_SCL_0(IICx);
delay_us(5);
I2C_SCL_1(IICx);
delay_us(50);
I2C_SCL_0(IICx);
delay_us(4);
//在发送完ACK后严禁数据线电平变化
// I2C_SDA_1(IICx);
}
// 接收ACK
uint8_t SMbus_Wait_Ack(GPIO_I2C_ST IICx)
{
uint8_t ucErrTime=0;
SDA_OD_OUT(); //SDA???????
I2C_SCL_0(IICx);
SDA_IN();
delay_us(100);//等待100US是为了等待高电平,时间太短可能等不到
I2C_SCL_1(IICx);delay_us(10);
while(I2C_SDA_READ(IICx))
{
ucErrTime++;
if(ucErrTime>250)
{
SMbus_Stop(IICx);
return 1;
}
}
return 0;
}
//发送一个字节
void SMbus_Send_Byte(GPIO_I2C_ST IICx,uint8_t txd)
{
uint8_t t;
SDA_PP_OUT(); //
SDA_OUT();
I2C_SCL_0(IICx);//
delay_us(5);
for(t=0;t<8;t++){
if((txd&0x80)>>7 == 1)
{
I2C_SDA_1(IICx);
}
else
{
I2C_SDA_0(IICx);
}
txd<<=1;
delay_us(50);
I2C_SCL_1(IICx);
delay_us(50);
I2C_SCL_0(IICx);
delay_us(4);
}
I2C_SCL_0(IICx);
delay_us(10);
}
//读取一个字节
uint8_t SMbus_Read_Byte(GPIO_I2C_ST IICx)
{
unsigned char i,receive=0;
SDA_OD_OUT(); //
SDA_IN();//
I2C_SCL_0(IICx);
//在读取第一个字节第一位的时候,延时需要超过60US,因为从设备控制数据线有个跳变的过程,这点必须注意
delay_us(70);
for(i=0;i<8;i++ )
{
I2C_SCL_0(IICx);
delay_us(50);
I2C_SCL_1(IICx);
delay_us(50);
receive<<=1;
if(I2C_SDA_READ(IICx))receive++;
}
I2C_SCL_0(IICx);
delay_us(10);
SMbus_Ack(IICx);
return receive;
}
//读取寄存器当中的两个字节,单片机做主,BQ40Z50做从
uint8_t bq40z50_Get_Data(GPIO_I2C_ST IICx,uint8_t address,uint8_t* buff)
{
SMbus_Start(IICx); //开始
SMbus_Send_Byte(IICx,0x16);//发送模块地址
if(SMbus_Wait_Ack(IICx) == 1)//读取ACK
{
return 1;
}
SMbus_Send_Byte(IICx,address); //发送寄存器地址
if(SMbus_Wait_Ack(IICx) == 1)//
{
return 1;
}
SMbus_Start(IICx);
SMbus_Send_Byte(IICx,0x17);
if(SMbus_Wait_Ack(IICx) == 1)//
{
return 1;
}
*(buff+0) = SMbus_Read_Byte(IICx);//读取一个字节
*(buff+1) = SMbus_Read_Byte(IICx);
SMbus_Stop(IICx);
return 0;
}
如果延时不会初始化点击下面链接
https://blog.youkuaiyun.com/weixin_43879214/article/details/111587924