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

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

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

一、基本情况

6 F/ p, L  Y  v

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

( h2 }+ y, y+ o$ W! n6 T


* H  ?( @* C; F; U" C

二、LC709203F的I2C通讯协议

20200925214134995_meitu_1.jpg

4 W5 y; r! T5 k" O

三、程序

* u( B% ^2 W3 B- N4 ~: i. @' f9 _


' Y: z  D( p8 p; F5 o

lc709203f.c中程序:


1 d/ M" ~" f9 A" u5 t% c

  1. #include "lc709203f.h"  ) u3 ]9 {# w) q8 e8 n  H. f; v
  2. #include "delay.h"                                  
    8 i5 ~/ h/ V8 A: W2 B$ e
  3. % M8 m) W( N6 J. z) u* E, O
  4. //初始化IIC接口, v3 L) y: k5 n4 E
  5. void lc709203f_Init(void)0 S. T! B( K* y" L& R/ p
  6. {! [' u  C/ v6 r; e
  7.         u16 Buffer_data0=0x0001;//设置电源模式  i9 w" r; S; ~7 ^( M
  8.         u16 Buffer_data1=0x0010;//设置适合您电池的APA参数% c" r1 B+ C, S. }9 h4 j0 u# W! B
  9.         u16 Buffer_data2=0x0001;//设置适合您电池的配置文件$ c. R6 A) h, N4 I( v, X# ?' t7 ]
  10.         u16 Buffer_data3=0xAA55;//初始化RSOC9 S3 c, V; E0 b5 h
  11.         u16 Buffer_data4=0x0001;//设置热敏电阻模式
    - [5 p, B# d/ R: f) q$ W. u
  12.        
    & V2 V0 B& E: B9 D7 D
  13.         IIC2_Init();//IIC初始化
    , n9 d4 S, q' |8 {& I
  14.         lc709203f_WriteOneWord(LC709203F_IC_Power_Mode,Buffer_data0);( C& S" E8 _, Y2 {+ D' \# \9 C
  15.         lc709203f_WriteOneWord(LC709203F_Adjustment_Pack_Appli,Buffer_data1);
    4 r* i' P# \$ F% y
  16.         lc709203f_WriteOneWord(LC709203F_Change_Parameter,Buffer_data2);
    , K& B& I1 y8 q6 l- A& \6 s
  17.         lc709203f_WriteOneWord(LC709203F_Initial_RSOC,Buffer_data3);5 E* G5 l8 u8 q3 w* k3 N
  18.         lc709203f_WriteOneWord(LC709203F_Status_Bit,Buffer_data4);! q+ i4 u# U. R5 K9 [! x0 \
  19.        
    1 A* t3 a( |/ v% E' t

  20. + P# ]2 n8 C& B9 i6 Y
  21. }
复制代码

- y0 K5 O0 d; t) M! G

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


3 q# q: D! E+ ?% c$ }


  1. : P* t2 n$ k5 K; G. y6 @/ K( J
  2. u16 lc709203f_ReadOneWord(u8 ReadAddr)
    ; K" Y  P3 Z5 i3 ~1 [( g# {: U9 ]
  3. {                                  & q1 o( g) P; l% g: V
  4.         u16 data=0;       
    9 E) S, [; w6 i" x
  5.     u8 data_l=0;       
    . p: Y5 [& l( P# [# Z. O$ }! \
  6.         u8 data_h=0;
    , j* W* H6 I+ M* b$ p
  7.         u8 crc_8=0;
    + G+ T4 ^* l5 m/ X
  8.         u8 readcrc[5];& @0 S- D0 V9 I
  9.     IIC2_Start();                              //第一步:第一次启动2 S( L$ g$ [4 P% |& j
  10.         delay_us(100);9 n) y8 M/ A; d: C2 c5 x1 ^
  11.         IIC2_Send_Byte(LC709203F_ADDR_wr); //第二步:写入从机地址和写入指令
    0 y0 O2 ?. e3 k8 `+ H" ~
  12.         delay_us(100);
    ! R! k1 Y* g; L! Z# L- I; `" c8 H
  13.         IIC2_Wait_Ack();                           //第三步:等待从机确认
    ( j8 J4 b7 _: Q" t3 F1 y
  14.         delay_us(100);
    5 v7 v0 n- D! `- K7 s% p" v
  15.     IIC2_Send_Byte(ReadAddr);                  //第四步:发送寄存器地址(字节最高位为虚拟位)7 j/ E6 V& [' d- t$ {& E( J
  16.         delay_us(100);  k5 \6 U% D/ H
  17.         IIC2_Wait_Ack();                                  //第五步:等待从机确认
    0 m& ]. }9 B, \* q* w
  18.         delay_us(100);
    2 ?4 B0 ~6 |  w& K# o
  19.         IIC2_Start();                                         //第六步:第二次启动 ; ^7 v. D6 l: {* _+ l* p' k3 F
  20.         delay_us(100);+ \! K6 V- R& }% [8 N; a
  21.     IIC2_Send_Byte(LC709203F_ADDR_rd); //第七步:写入从机地址和读取指令       
    % F( n9 V; \+ s5 O) H. }  K
  22.     delay_us(100);         / f# v7 s6 S6 B) S4 I" Q
  23.         IIC2_Wait_Ack();                                  //第八步:等待从机确认. w5 N; ^$ ]- Q$ B1 L  F
  24.         delay_us(100);
    5 x, ?0 G# e* \/ P
  25.     data_l=IIC2_Read_Byte(1);                              //第九步:接收低字节数据+ c& n1 \" G+ ]3 [, ~
  26.         delay_us(100);# e$ G* Z( y. i. O0 s) G; R* p) C
  27.         //IIC2_Ack();                                   //产生应答1( D; D0 r# z' R5 B; i2 ~
  28.         data_h=IIC2_Read_Byte(1);                              //第十步:接收高字节数据7 ]9 C' H8 s8 r( [
  29.         delay_us(100);/ `$ h  M$ Y! S3 F3 Z! ]; X
  30.         //IIC2_Ack();                                   //产生应答2- e7 Y* Q, g9 W; ~
  31.         crc_8=IIC2_Read_Byte(0);                              //第十一步:接收CRC-8数据
    . u, I2 V/ c* x, ~
  32.         delay_us(100);: U7 x( k$ Z, T5 k( \  C
  33.         //IIC2_NAck();                                  //不产生应答- g% C% i+ r, f3 s9 y4 D
  34.     IIC2_Stop();                                      //第十二步:停止
    8 t1 a( l3 l2 ]: ^8 I! H
  35.         readcrc[0]=LC709203F_ADDR_wr;# M, A# u4 Q1 q, o+ U
  36.         readcrc[1]=ReadAddr;6 H9 G- V  N( t! p  J% R2 M
  37.         readcrc[2]=LC709203F_ADDR_rd;
    ' F* u& |+ o8 j  S, s
  38.         readcrc[3]=data_l;
      `% y+ n8 c$ D) q" A% V" X
  39.         readcrc[4]=data_h;
    / y+ L- |4 z$ r5 _3 {2 G
  40.         if(gh_crc8(readcrc,5)==crc_8)* `8 y7 f2 p' \1 j5 Q
  41.                 data=data_h*256+data_l;1 Y. d$ b+ t6 y1 E& \& m' I
  42.         $ O& P; o& f2 P4 y& w0 r/ U* P
  43.         return data;3 s2 D, e& ^/ Q* X/ t
  44. }
复制代码

  ~" t8 ?% t4 c/ U

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

, W! y/ Z2 Z7 z4 z0 ?6 D

  1. void lc709203f_WriteOneWord(u8 WriteAddr,u16 DataToWrite)1 S& w6 X2 R# F5 m2 S
  2. {                                                                                                  0 n3 `+ H2 P1 ^3 v
  3.     u8 data[4];: v5 |8 u6 d# ~4 @( Q
  4.     IIC2_Start();                              //第一步:启动# M6 K, l1 s2 M( @4 ^0 U$ J
  5.     IIC2_Send_Byte(LC709203F_ADDR_wr); //第二步:写入从机地址和写入指令
    9 P9 n, {6 h( L! p1 C$ Z/ K
  6.     IIC2_Wait_Ack();                              //第三步:等待从机确认
    6 j: V% O0 l2 `& r6 o( o: }# y
  7.     IIC2_Send_Byte(WriteAddr);                 //第四步:发送寄存器地址(字节最高位为虚拟位)6 i" L& s) B! B; `8 ^! S. e
  8.     IIC2_Wait_Ack();                            //第五步:等待从机确认                                 
    $ @% N9 U5 b- u
  9.     IIC2_Send_Byte((u8)(DataToWrite&0x00FF));               //第六步:发送低字节数据                               + U. `7 m7 w" v1 K) O! M
  10.     IIC2_Wait_Ack();                            //第七步:等待从机确认  i# K; `8 e7 i3 m' ^; W( }
  11.     IIC2_Send_Byte((u8)(DataToWrite>>8));      //第八步:发送高字节数据   
    ) y+ d& g6 t% S  k. O
  12.     IIC2_Wait_Ack();                            //第九步:等待从机确认. F3 I( R& [  S* r& W" E
  13.     data[0]=LC709203F_ADDR_wr;
    , ^! x( A" \& ]# P! w! v! w
  14.     data[1]=WriteAddr;
    ! r: @( M; i& t( S% Z9 B. g
  15.     data[2]=(u8)(DataToWrite&0x00FF);
    1 ]# p( \2 [4 w: b' i
  16.     data[3]=(u8)(DataToWrite>>8);3 K3 }8 K% L4 z. p1 s4 C
  17.     IIC2_Send_Byte(gh_crc8(data,4));      //第十步:发送CRC-8数据    7 U( Z4 B" B3 R- D2 r
  18.     IIC2_Wait_Ack();                            //第十一步:等待从机确认, l* H$ S3 O; [6 ~6 `) q% J$ p
  19.     IIC2_Stop();                               //第十二步:停止8 ?3 y, R; ^6 E  M, N- O$ [
  20.     delay_ms(10);     
    8 T, h: @/ J  ^5 G9 W3 U& z1 n
  21. }
复制代码

/ [* s7 @) [; k7 g

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


* \- _2 ]  c5 U- B: g$ H9 {4 U

  1. void getLC709203FOutput(s16* LC709203FData)6 V4 [' w( `. \4 Q) N. q
  2. {, Q7 J  Q8 Z2 J" p! t& ^
  3.       
    4 \( C3 ~* o( e) d- D: {) H) C' Y
  4.     u16 data0,data1,data2;
    7 Q" d& s. a  K6 |6 ^3 o1 M; K- b
  5.        
    6 n; ]. v& V4 S* h2 H
  6.     data0=lc709203f_ReadOneWord(LC709203F_Cell_Temperature);//电池温度9 q$ `( T- B3 P% T! e: M
  7.         data1=lc709203f_ReadOneWord(LC709203F_RSOC);//电池剩余电量
    * G3 @+ z% w- C: O' w* a8 ?. H
  8.         data2=lc709203f_ReadOneWord(LC709203F_Cell_Voltage); //电池电压; |$ C3 m& e1 j: P) e) {
  9.    
    0 [" r5 K) j5 W* n, j
  10.     if((data0>=0x0AAC)&&(data0<=0x7FFF)) //读取的数据处理1 @4 O1 K4 ^) s0 v
  11.         LC709203FData[0]=data0-0x0AAC;6 s" \* {8 Q! j2 R/ V. j0 V) e
  12.         if(data1<=0x0064)" Q* ]- |) Z! ?5 @
  13.         LC709203FData[1]=data1;4 K& o4 R$ @( f$ X
  14.     if((data2<=0x0FA0)&&(data2>=0x07D0))$ V! ]) h. s* n* z
  15.         LC709203FData[2]=data2;& f6 _1 N7 M7 S! ^  }% v. i
  16. }
复制代码
- d, j# Z) h" ?& y8 a7 ~% D3 q# S, _

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


2 X0 ]' l% n* C5 I& t

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


/ \3 b! ^5 h* H5 Z- Z: z


( o9 g3 L3 ?! V+ l& o

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


5 I/ l4 w  P) I' l: y" B

: N1 L& B/ |, L7 j( o7 X* r. p

IIC2_Read_Byte()如下:

+ u+ L" m( @% e


  1. - w: a" d# X' |: K  ?* Q/ d
  2. //读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
    9 c% W  @/ h% m8 v( C# F
  3. u8 IIC2_Read_Byte(unsigned char ack)8 S' ?( c, v& s$ f. a
  4. {5 O' S* z6 t0 o- R2 R, Y
  5.         unsigned char i,receive=0;
    1 [4 d) W: O" ?/ B8 r! a7 @
  6.         SDA2_IN();//SDA设置为输入1 Q9 E$ m0 R+ ]& m* _% g4 V
  7.     for(i=0;i<8;i++ )
    ! A) C; l# g' k! {0 y" w: K
  8.         {$ x4 H7 L( y" _! f
  9.         IIC2_SCL=0; 4 j$ O2 n, Y& z" p: ~/ {
  10.         delay_us(4);                   //LC709203F时钟频率400Khz=2.5us  ?0 l# Z# k0 ?$ V- I+ T  |
  11.                 IIC2_SCL=1;
    ' F: Y9 U1 W2 C3 ?. g7 z
  12.         receive<<=1;  //receive=receive<<1;
    & R( H" D/ g; E/ F
  13.         if(READ2_SDA)receive++;   // 根据READ_SDA的值(SDA),从高到低顺序依次写入一个字节,8 n: d+ K2 x, _% q, s/ K
  14.                 delay_us(4);             //i=0时,SDA=1则receive=0B00000001,i=1,SDA=1则receive=0B00000011: [3 M6 f2 V+ x% R
  15.     }                                         
    - D/ _: l% F( ~$ K% Z
  16.     if (!ack)
    ! m0 x  f) n2 _  o& f9 i
  17.         IIC2_NAck();//发送nACK
    - u1 f( h. L+ m3 U
  18.     else3 J! M9 k3 L1 W/ k' `9 _5 b
  19.         IIC2_Ack(); //发送ACK   
    ( j- M; g/ S- G: \3 N" X& `
  20.     return receive;
    ( r3 S4 w" P7 H5 `, w# M
  21. }
复制代码

: H7 E- A7 n; {7 D$ |# [! G
  • 7 K( F  b" j. b& O+ m" s0 V

    * g6 z$ ]  r6 Y4 w( N# p
    4 C( f/ x2 z4 x; ~: `

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


8 T( K/ m! m" a
赞 收藏 评论0 发布时间:2020-9-29 12:45

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版