|
一、基本情况 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通讯协议
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
- #include "lc709203f.h" ) u3 ]9 {# w) q8 e8 n H. f; v
- #include "delay.h"
8 i5 ~/ h/ V8 A: W2 B$ e - % M8 m) W( N6 J. z) u* E, O
- //初始化IIC接口, v3 L) y: k5 n4 E
- void lc709203f_Init(void)0 S. T! B( K* y" L& R/ p
- {! [' u C/ v6 r; e
- u16 Buffer_data0=0x0001;//设置电源模式 i9 w" r; S; ~7 ^( M
- u16 Buffer_data1=0x0010;//设置适合您电池的APA参数% c" r1 B+ C, S. }9 h4 j0 u# W! B
- u16 Buffer_data2=0x0001;//设置适合您电池的配置文件$ c. R6 A) h, N4 I( v, X# ?' t7 ]
- u16 Buffer_data3=0xAA55;//初始化RSOC9 S3 c, V; E0 b5 h
- u16 Buffer_data4=0x0001;//设置热敏电阻模式
- [5 p, B# d/ R: f) q$ W. u -
& V2 V0 B& E: B9 D7 D - IIC2_Init();//IIC初始化
, n9 d4 S, q' |8 {& I - lc709203f_WriteOneWord(LC709203F_IC_Power_Mode,Buffer_data0);( C& S" E8 _, Y2 {+ D' \# \9 C
- lc709203f_WriteOneWord(LC709203F_Adjustment_Pack_Appli,Buffer_data1);
4 r* i' P# \$ F% y - lc709203f_WriteOneWord(LC709203F_Change_Parameter,Buffer_data2);
, K& B& I1 y8 q6 l- A& \6 s - lc709203f_WriteOneWord(LC709203F_Initial_RSOC,Buffer_data3);5 E* G5 l8 u8 q3 w* k3 N
- lc709203f_WriteOneWord(LC709203F_Status_Bit,Buffer_data4);! q+ i4 u# U. R5 K9 [! x0 \
-
1 A* t3 a( |/ v% E' t -
+ P# ]2 n8 C& B9 i6 Y - }
复制代码
- y0 K5 O0 d; t) M! G2)读一个字函数:u16 lc709203f_ReadOneWord(u8 ReadAddr),严格按照上述协议中的时许写代码
3 q# q: D! E+ ?% c$ }
: P* t2 n$ k5 K; G. y6 @/ K( J- u16 lc709203f_ReadOneWord(u8 ReadAddr)
; K" Y P3 Z5 i3 ~1 [( g# {: U9 ] - { & q1 o( g) P; l% g: V
- u16 data=0;
9 E) S, [; w6 i" x - u8 data_l=0;
. p: Y5 [& l( P# [# Z. O$ }! \ - u8 data_h=0;
, j* W* H6 I+ M* b$ p - u8 crc_8=0;
+ G+ T4 ^* l5 m/ X - u8 readcrc[5];& @0 S- D0 V9 I
- IIC2_Start(); //第一步:第一次启动2 S( L$ g$ [4 P% |& j
- delay_us(100);9 n) y8 M/ A; d: C2 c5 x1 ^
- IIC2_Send_Byte(LC709203F_ADDR_wr); //第二步:写入从机地址和写入指令
0 y0 O2 ?. e3 k8 `+ H" ~ - delay_us(100);
! R! k1 Y* g; L! Z# L- I; `" c8 H - IIC2_Wait_Ack(); //第三步:等待从机确认
( j8 J4 b7 _: Q" t3 F1 y - delay_us(100);
5 v7 v0 n- D! `- K7 s% p" v - IIC2_Send_Byte(ReadAddr); //第四步:发送寄存器地址(字节最高位为虚拟位)7 j/ E6 V& [' d- t$ {& E( J
- delay_us(100); k5 \6 U% D/ H
- IIC2_Wait_Ack(); //第五步:等待从机确认
0 m& ]. }9 B, \* q* w - delay_us(100);
2 ?4 B0 ~6 | w& K# o - IIC2_Start(); //第六步:第二次启动 ; ^7 v. D6 l: {* _+ l* p' k3 F
- delay_us(100);+ \! K6 V- R& }% [8 N; a
- IIC2_Send_Byte(LC709203F_ADDR_rd); //第七步:写入从机地址和读取指令
% F( n9 V; \+ s5 O) H. } K - delay_us(100); / f# v7 s6 S6 B) S4 I" Q
- IIC2_Wait_Ack(); //第八步:等待从机确认. w5 N; ^$ ]- Q$ B1 L F
- delay_us(100);
5 x, ?0 G# e* \/ P - data_l=IIC2_Read_Byte(1); //第九步:接收低字节数据+ c& n1 \" G+ ]3 [, ~
- delay_us(100);# e$ G* Z( y. i. O0 s) G; R* p) C
- //IIC2_Ack(); //产生应答1( D; D0 r# z' R5 B; i2 ~
- data_h=IIC2_Read_Byte(1); //第十步:接收高字节数据7 ]9 C' H8 s8 r( [
- delay_us(100);/ `$ h M$ Y! S3 F3 Z! ]; X
- //IIC2_Ack(); //产生应答2- e7 Y* Q, g9 W; ~
- crc_8=IIC2_Read_Byte(0); //第十一步:接收CRC-8数据
. u, I2 V/ c* x, ~ - delay_us(100);: U7 x( k$ Z, T5 k( \ C
- //IIC2_NAck(); //不产生应答- g% C% i+ r, f3 s9 y4 D
- IIC2_Stop(); //第十二步:停止
8 t1 a( l3 l2 ]: ^8 I! H - readcrc[0]=LC709203F_ADDR_wr;# M, A# u4 Q1 q, o+ U
- readcrc[1]=ReadAddr;6 H9 G- V N( t! p J% R2 M
- readcrc[2]=LC709203F_ADDR_rd;
' F* u& |+ o8 j S, s - readcrc[3]=data_l;
`% y+ n8 c$ D) q" A% V" X - readcrc[4]=data_h;
/ y+ L- |4 z$ r5 _3 {2 G - if(gh_crc8(readcrc,5)==crc_8)* `8 y7 f2 p' \1 j5 Q
- data=data_h*256+data_l;1 Y. d$ b+ t6 y1 E& \& m' I
- $ O& P; o& f2 P4 y& w0 r/ U* P
- return data;3 s2 D, e& ^/ Q* X/ t
- }
复制代码
~" t8 ?% t4 c/ U3)写一个字函数:void lc709203f_WriteOneWord(u8 WriteAddr,u16 DataToWrite) , W! y/ Z2 Z7 z4 z0 ?6 D
- void lc709203f_WriteOneWord(u8 WriteAddr,u16 DataToWrite)1 S& w6 X2 R# F5 m2 S
- { 0 n3 `+ H2 P1 ^3 v
- u8 data[4];: v5 |8 u6 d# ~4 @( Q
- IIC2_Start(); //第一步:启动# M6 K, l1 s2 M( @4 ^0 U$ J
- IIC2_Send_Byte(LC709203F_ADDR_wr); //第二步:写入从机地址和写入指令
9 P9 n, {6 h( L! p1 C$ Z/ K - IIC2_Wait_Ack(); //第三步:等待从机确认
6 j: V% O0 l2 `& r6 o( o: }# y - IIC2_Send_Byte(WriteAddr); //第四步:发送寄存器地址(字节最高位为虚拟位)6 i" L& s) B! B; `8 ^! S. e
- IIC2_Wait_Ack(); //第五步:等待从机确认
$ @% N9 U5 b- u - IIC2_Send_Byte((u8)(DataToWrite&0x00FF)); //第六步:发送低字节数据 + U. `7 m7 w" v1 K) O! M
- IIC2_Wait_Ack(); //第七步:等待从机确认 i# K; `8 e7 i3 m' ^; W( }
- IIC2_Send_Byte((u8)(DataToWrite>>8)); //第八步:发送高字节数据
) y+ d& g6 t% S k. O - IIC2_Wait_Ack(); //第九步:等待从机确认. F3 I( R& [ S* r& W" E
- data[0]=LC709203F_ADDR_wr;
, ^! x( A" \& ]# P! w! v! w - data[1]=WriteAddr;
! r: @( M; i& t( S% Z9 B. g - data[2]=(u8)(DataToWrite&0x00FF);
1 ]# p( \2 [4 w: b' i - data[3]=(u8)(DataToWrite>>8);3 K3 }8 K% L4 z. p1 s4 C
- IIC2_Send_Byte(gh_crc8(data,4)); //第十步:发送CRC-8数据 7 U( Z4 B" B3 R- D2 r
- IIC2_Wait_Ack(); //第十一步:等待从机确认, l* H$ S3 O; [6 ~6 `) q% J$ p
- IIC2_Stop(); //第十二步:停止8 ?3 y, R; ^6 E M, N- O$ [
- delay_ms(10);
8 T, h: @/ J ^5 G9 W3 U& z1 n - }
复制代码
/ [* s7 @) [; k7 g4)获取数据函数:void getLC709203FOutput(s16* LC709203FData)
* \- _2 ] c5 U- B: g$ H9 {4 U
- void getLC709203FOutput(s16* LC709203FData)6 V4 [' w( `. \4 Q) N. q
- {, Q7 J Q8 Z2 J" p! t& ^
-
4 \( C3 ~* o( e) d- D: {) H) C' Y - u16 data0,data1,data2;
7 Q" d& s. a K6 |6 ^3 o1 M; K- b -
6 n; ]. v& V4 S* h2 H - data0=lc709203f_ReadOneWord(LC709203F_Cell_Temperature);//电池温度9 q$ `( T- B3 P% T! e: M
- data1=lc709203f_ReadOneWord(LC709203F_RSOC);//电池剩余电量
* G3 @+ z% w- C: O' w* a8 ?. H - data2=lc709203f_ReadOneWord(LC709203F_Cell_Voltage); //电池电压; |$ C3 m& e1 j: P) e) {
-
0 [" r5 K) j5 W* n, j - if((data0>=0x0AAC)&&(data0<=0x7FFF)) //读取的数据处理1 @4 O1 K4 ^) s0 v
- LC709203FData[0]=data0-0x0AAC;6 s" \* {8 Q! j2 R/ V. j0 V) e
- if(data1<=0x0064)" Q* ]- |) Z! ?5 @
- LC709203FData[1]=data1;4 K& o4 R$ @( f$ X
- if((data2<=0x0FA0)&&(data2>=0x07D0))$ V! ]) h. s* n* z
- LC709203FData[2]=data2;& f6 _1 N7 M7 S! ^ }% v. i
- }
复制代码 - 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
- w: a" d# X' |: K ?* Q/ d- //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
9 c% W @/ h% m8 v( C# F - u8 IIC2_Read_Byte(unsigned char ack)8 S' ?( c, v& s$ f. a
- {5 O' S* z6 t0 o- R2 R, Y
- unsigned char i,receive=0;
1 [4 d) W: O" ?/ B8 r! a7 @ - SDA2_IN();//SDA设置为输入1 Q9 E$ m0 R+ ]& m* _% g4 V
- for(i=0;i<8;i++ )
! A) C; l# g' k! {0 y" w: K - {$ x4 H7 L( y" _! f
- IIC2_SCL=0; 4 j$ O2 n, Y& z" p: ~/ {
- delay_us(4); //LC709203F时钟频率400Khz=2.5us ?0 l# Z# k0 ?$ V- I+ T |
- IIC2_SCL=1;
' F: Y9 U1 W2 C3 ?. g7 z - receive<<=1; //receive=receive<<1;
& R( H" D/ g; E/ F - if(READ2_SDA)receive++; // 根据READ_SDA的值(SDA),从高到低顺序依次写入一个字节,8 n: d+ K2 x, _% q, s/ K
- delay_us(4); //i=0时,SDA=1则receive=0B00000001,i=1,SDA=1则receive=0B00000011: [3 M6 f2 V+ x% R
- }
- D/ _: l% F( ~$ K% Z - if (!ack)
! m0 x f) n2 _ o& f9 i - IIC2_NAck();//发送nACK
- u1 f( h. L+ m3 U - else3 J! M9 k3 L1 W/ k' `9 _5 b
- IIC2_Ack(); //发送ACK
( j- M; g/ S- G: \3 N" X& ` - return receive;
( r3 S4 w" P7 H5 `, w# M - }
复制代码
: 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 |