最近因为项目需要,需要在STM32平台上对一个设备的电量进行监测,使用到的电量检测芯片是TI的BQ3060。该芯片使用的是SMBus协议,基本上跟I2C协议差不多,实际上我也是直接把I2C的驱动搬来用的。因为之前也用过BQ2084,跟BQ3060基本一样,连寄存器地址都是一样。原本想着直接把BQ2084的代码拿来用就好了,没想到BQ2084的代码读BQ3060的寄存器时死活读不对,应答信号都是有的,就是数据读出来明显是错误的,后来改了一下时序,速度比BQ2084调慢了很多,竟然行了,哈哈!如果有条件的话,建议还是拿示波器测试一下,我手头没有示波器,都是慢慢调时序调出来的,坑啊。
好了,直接上代码吧:
C文件
#include ".././includes.h"
#define POLYNOMIAL (0x107)
#define SCL_Low GPIO_ResetBits(BQ2084_PORT,BQ2084_SCL_PIN)
#define SCL_High GPIO_SetBits(BQ2084_PORT,BQ2084_SCL_PIN)
#define SDA_INPUT {BQ2084_PORT->CRH&=0XFF0FFFFF;BQ2084_PORT->CRH|=8<<20;}//第13脚,(13-8)*4 = 20
#define SDA_OUTPUT {BQ2084_PORT->CRH&=0XFF0FFFFF;BQ2084_PORT->CRH|=3<<20;}//第13脚,(13-8)*4 = 20
#define SDA_Low GPIO_ResetBits(BQ2084_PORT,BQ2084_SDA_PIN)
#define SDA_High GPIO_SetBits(BQ2084_PORT,BQ2084_SDA_PIN)
#define GetSDABit GPIO_ReadInputDataBit(BQ2084_PORT,BQ2084_SDA_PIN)
/**************************/
#define BQ2084_ADD_WR 0x16 //定义iic器件写地址
#define BQ2084_ADD_RD 0x17 //定义iic器件读地址
#define cack_timeout (5000) //定义应答信号检查超时时间
#define BQ2084_CLK_DLY_US (6) //延时常数,SMBus operating frequency Slave mode, SMBC 50% duty cycle 10~100 kHz
/**************************/
/*
**函数名:BQ2084_GPIO_Config
**传入参数:无
**返回值:无
**功能:初始化BQ2084引脚
*/
void BQ2084_GPIO_Config(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启GPIO的外设时钟*/
RCC_APB2PeriphClockCmd(BQ2084_PORT_RCC, ENABLE);
/*选择要控制的引脚*/
GPIO_InitStructure.GPIO_Pin = BQ2084_SDA_PIN | BQ2084_SCL_PIN;
/*设置引脚模式为开漏输出*/
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为10MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
/*调用库函数,初始化GPIO*/
GPIO_Init(BQ2084_PORT,&GPIO_InitStructure);
}
/*简单的延时函数*/
static void Delay(uint32_t Tcount)
{
uint32_t Tus,Temp;
for(Tus=0;Tus<72;Tus++)
for(Temp=0;Temp<Tcount;Temp++);;
}
static void I2C_Start(void)
{
SDA_OUTPUT;
SCL_High;
SDA_High;
Delay(BQ2084_CLK_DLY_US);
SDA_Low;
Delay(BQ2084_CLK_DLY_US);
SCL_Low;
}
static void I2C_Stop(void)// iic停止函数
{
SDA_OUTPUT;
SDA_Low;
SCL_High;
Delay(BQ2084_CLK_DLY_US);
SDA_High;
Delay(BQ2084_CLK_DLY_US);
SDA_Low;
SCL_Low;
}
uint8_t Cal_PEC(uint8_t *ptr, uint8_t len)
{
uint8_t i;
uint8_t crc=0;
while(len--!=0)
{
for(i=128;i!=0;i/=2)
{
if((crc&128)!=0)
{
crc *= 2;
crc ^= POLYNOMIAL;
}
else
{
crc*=2;
}
if((*ptr&i)!=0)
{
crc ^= POLYNOMIAL;
}
}
ptr++;
}
return crc;
}
void I2C_Write_Byte(const uint8_t s)//iic写1byte函数,S为需要写的