你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F103CBT6单片机I2C接口读取锂电池电量计LC709203F数据

[复制链接]
STMCU-管管 发布时间:2020-9-29 12:45

一、基本情况


       LC709203F是一款适用于单节锂离子/聚合物电池应用的电量计,通过HG-CVR算法来测量电池的RSOC(相对电荷状态)。精确的RSOC数据有助于改善便携式设备的运行时间和合理使用。利用单片机的I2C口与LC709203F通讯,实现对其电池温度、电池电压、电池剩余电量(RSOC)等锂电池重要数据的采集。单片机管脚PB10(I2C2_SCL)连接LC709203F的第8脚SCL,单片机管脚PB11(I2C2_SDA))连接LC709203F的第7脚SDA。



二、LC709203F的I2C通讯协议

20200925214134995_meitu_1.jpg


三、程序



lc709203f.c中程序:


  1. #include "lc709203f.h"  
  2. #include "delay.h"                                  

  3. //初始化IIC接口
  4. void lc709203f_Init(void)
  5. {
  6.         u16 Buffer_data0=0x0001;//设置电源模式
  7.         u16 Buffer_data1=0x0010;//设置适合您电池的APA参数
  8.         u16 Buffer_data2=0x0001;//设置适合您电池的配置文件
  9.         u16 Buffer_data3=0xAA55;//初始化RSOC
  10.         u16 Buffer_data4=0x0001;//设置热敏电阻模式
  11.        
  12.         IIC2_Init();//IIC初始化
  13.         lc709203f_WriteOneWord(LC709203F_IC_Power_Mode,Buffer_data0);
  14.         lc709203f_WriteOneWord(LC709203F_Adjustment_Pack_Appli,Buffer_data1);
  15.         lc709203f_WriteOneWord(LC709203F_Change_Parameter,Buffer_data2);
  16.         lc709203f_WriteOneWord(LC709203F_Initial_RSOC,Buffer_data3);
  17.         lc709203f_WriteOneWord(LC709203F_Status_Bit,Buffer_data4);
  18.        

  19. }
复制代码

2)读一个字函数:u16 lc709203f_ReadOneWord(u8 ReadAddr),严格按照上述协议中的时许写代码



  1. u16 lc709203f_ReadOneWord(u8 ReadAddr)
  2. {                                  
  3.         u16 data=0;       
  4.     u8 data_l=0;       
  5.         u8 data_h=0;
  6.         u8 crc_8=0;
  7.         u8 readcrc[5];
  8.     IIC2_Start();                              //第一步:第一次启动
  9.         delay_us(100);
  10.         IIC2_Send_Byte(LC709203F_ADDR_wr); //第二步:写入从机地址和写入指令
  11.         delay_us(100);
  12.         IIC2_Wait_Ack();                           //第三步:等待从机确认
  13.         delay_us(100);
  14.     IIC2_Send_Byte(ReadAddr);                  //第四步:发送寄存器地址(字节最高位为虚拟位)
  15.         delay_us(100);
  16.         IIC2_Wait_Ack();                                  //第五步:等待从机确认
  17.         delay_us(100);
  18.         IIC2_Start();                                         //第六步:第二次启动
  19.         delay_us(100);
  20.     IIC2_Send_Byte(LC709203F_ADDR_rd); //第七步:写入从机地址和读取指令       
  21.     delay_us(100);        
  22.         IIC2_Wait_Ack();                                  //第八步:等待从机确认
  23.         delay_us(100);
  24.     data_l=IIC2_Read_Byte(1);                              //第九步:接收低字节数据
  25.         delay_us(100);
  26.         //IIC2_Ack();                                   //产生应答1
  27.         data_h=IIC2_Read_Byte(1);                              //第十步:接收高字节数据
  28.         delay_us(100);
  29.         //IIC2_Ack();                                   //产生应答2
  30.         crc_8=IIC2_Read_Byte(0);                              //第十一步:接收CRC-8数据
  31.         delay_us(100);
  32.         //IIC2_NAck();                                  //不产生应答
  33.     IIC2_Stop();                                      //第十二步:停止
  34.         readcrc[0]=LC709203F_ADDR_wr;
  35.         readcrc[1]=ReadAddr;
  36.         readcrc[2]=LC709203F_ADDR_rd;
  37.         readcrc[3]=data_l;
  38.         readcrc[4]=data_h;
  39.         if(gh_crc8(readcrc,5)==crc_8)
  40.                 data=data_h*256+data_l;
  41.        
  42.         return data;
  43. }
复制代码

3)写一个字函数:void lc709203f_WriteOneWord(u8 WriteAddr,u16 DataToWrite)


  1. void lc709203f_WriteOneWord(u8 WriteAddr,u16 DataToWrite)
  2. {                                                                                                  
  3.     u8 data[4];
  4.     IIC2_Start();                              //第一步:启动
  5.     IIC2_Send_Byte(LC709203F_ADDR_wr); //第二步:写入从机地址和写入指令
  6.     IIC2_Wait_Ack();                              //第三步:等待从机确认
  7.     IIC2_Send_Byte(WriteAddr);                 //第四步:发送寄存器地址(字节最高位为虚拟位)
  8.     IIC2_Wait_Ack();                            //第五步:等待从机确认                                 
  9.     IIC2_Send_Byte((u8)(DataToWrite&0x00FF));               //第六步:发送低字节数据                              
  10.     IIC2_Wait_Ack();                            //第七步:等待从机确认
  11.     IIC2_Send_Byte((u8)(DataToWrite>>8));      //第八步:发送高字节数据   
  12.     IIC2_Wait_Ack();                            //第九步:等待从机确认
  13.     data[0]=LC709203F_ADDR_wr;
  14.     data[1]=WriteAddr;
  15.     data[2]=(u8)(DataToWrite&0x00FF);
  16.     data[3]=(u8)(DataToWrite>>8);
  17.     IIC2_Send_Byte(gh_crc8(data,4));      //第十步:发送CRC-8数据   
  18.     IIC2_Wait_Ack();                            //第十一步:等待从机确认
  19.     IIC2_Stop();                               //第十二步:停止
  20.     delay_ms(10);     
  21. }
复制代码

4)获取数据函数:void getLC709203FOutput(s16* LC709203FData)


  1. void getLC709203FOutput(s16* LC709203FData)
  2. {
  3.       
  4.     u16 data0,data1,data2;
  5.        
  6.     data0=lc709203f_ReadOneWord(LC709203F_Cell_Temperature);//电池温度
  7.         data1=lc709203f_ReadOneWord(LC709203F_RSOC);//电池剩余电量
  8.         data2=lc709203f_ReadOneWord(LC709203F_Cell_Voltage); //电池电压
  9.    
  10.     if((data0>=0x0AAC)&&(data0<=0x7FFF)) //读取的数据处理
  11.         LC709203FData[0]=data0-0x0AAC;
  12.         if(data1<=0x0064)
  13.         LC709203FData[1]=data1;
  14.     if((data2<=0x0FA0)&&(data2>=0x07D0))
  15.         LC709203FData[2]=data2;
  16. }
复制代码

四、调试中遇到的问题处理总结


1、起初,未严格按照协议,读取到的数据均是0XABAB等,以为是I2C读写函数信号延时函数设置不合适的问题,后来多次测试还是不行,再后来仔细阅读协议,发现此协议还需要CRC8校验,比其他一些芯片的I2C通讯协议要复杂,于是按照通讯协议写lc709203f_ReadOneWord()和lc709203f_WriteOneWord()函数;



2、之后下载程序运行,仍然读不到正确数据,检查程序,发现lc709203f_ReadOneWord()中第九步、第十步、第十一步都是IIC2_Read_Byte(1),函数的形参都为1,而该函数1表示为产生应答ACK,0为不产生应答NACK,根据I2C通讯协议,应该为上面程序所写的,不产生应答的改为IIC2_Read_Byte(0),并且此函数里面已经有ACK和NACK函数,如上述程序所写的需要注释掉产生应答1、产生应答2和不产生应答。



IIC2_Read_Byte()如下:



  1. //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
  2. u8 IIC2_Read_Byte(unsigned char ack)
  3. {
  4.         unsigned char i,receive=0;
  5.         SDA2_IN();//SDA设置为输入
  6.     for(i=0;i<8;i++ )
  7.         {
  8.         IIC2_SCL=0;
  9.         delay_us(4);                   //LC709203F时钟频率400Khz=2.5us
  10.                 IIC2_SCL=1;
  11.         receive<<=1;  //receive=receive<<1;
  12.         if(READ2_SDA)receive++;   // 根据READ_SDA的值(SDA),从高到低顺序依次写入一个字节,
  13.                 delay_us(4);             //i=0时,SDA=1则receive=0B00000001,i=1,SDA=1则receive=0B00000011
  14.     }                                         
  15.     if (!ack)
  16.         IIC2_NAck();//发送nACK
  17.     else
  18.         IIC2_Ack(); //发送ACK   
  19.     return receive;
  20. }
复制代码




3、修改上述后,下载程序运行仍然读不到正确数据,但是通过单步调试都能正确读到数据,原因在哪里呢?单步调试发现写的数据均已写入进去了,于是在读字节函数lc709203f_ReadOneWord()中,在每一步之间增加delay_us(100);//延时100us,此时运行,都能正确读到数据。


收藏 评论0 发布时间:2020-9-29 12:45

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版