LTC6804是一款专门用来做多节电池电池组的监测芯片,最高可监测12节电池,官方误差是低于1.2mv,12 个通道的最快采样速度可以达到290us。 芯片分为两种型号,6804-1和6804-2,区别在于,6804-1采用级联的形式(级联控制),6804-2采用并联形式(分开控制)。 除开硬件连接之外,这两种型号的操作都是大同小异,基本可以视为一样,本文以6804-1为例进行讲解。 原理图和手册中的推荐一样,就不贴出来了,MCU与芯片的通信方式采用四线SPI,这种通信方式很常见,各种MCU的驱动也好找。(看了数据手册,芯片似乎还支持IIC和2线通信,不过我没有用) ! ]. O1 C* E6 ~5 A, @4 s4 K* D
8 z* K! W& R8 `
下载下来的代码是C++文件,不能直接在STM32上使用,需要进行一些修改。 首先修改后缀名,改成C文件,然后打开LTC6804.c文件。
; j# a6 i: q# a8 V2 }) J, K- ^4 I第一步进行驱动的移植: - void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port
6 g# q3 [9 Q/ |$ c0 R1 D3 J - uint8_t data[] //Array of bytes to be written on the SPI port
7 J' i! F' A* L* ^' o - ). p3 z5 z. ~8 ~8 s
- {) f/ }3 w* x5 v' J7 N; ^
- uint8_t i;' L9 D+ b& D# {; ~9 C
- $ q& P# K) V5 f6 t1 _
- for(i = 0; i < len; i++)8 M6 A8 [ K, J9 m
- {" J; L. E5 h1 H% p2 R/ p
- SPI2_Send_byte((int8_t)data[i]);! \% W. Y% G4 S9 z, A, C' ]
- }; R* ]' z" }! A) Z( @9 g
- }
复制代码- void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port
* w0 r+ ?! E& V - uint8_t tx_len, //length of the tx data arry: y8 B8 s$ ?: D0 g, c( u. I
- uint8_t *rx_data,//Input: array that will store the data read by the SPI port& I8 X1 U8 [+ z% M4 c
- uint8_t rx_len //Option: number of bytes to be read from the SPI port/ W/ d4 Y3 Y- s$ ~. W+ x
- )* d1 p6 ~! E( a
- {
( Y6 Z9 o: t; o) h% L - uint8_t i;
: F$ _) X% b( U8 { - , J2 i( E* v: O' w; K
- for(i = 0; i < tx_len; i++)( v# G: E+ F r* j$ a
- {$ k, ?7 X4 `8 m* I+ S( Z5 I' P
- SPI2_Send_byte(tx_Data[i]);) E' [& y- I2 z/ d/ I0 r
- }3 m4 y) t. y1 U- X+ P+ v
- : w; h0 O9 ^, a6 ^2 m* E5 c
- for(i = 0; i < rx_len; i++)3 E5 N4 G4 v7 }5 \, f4 X
- {
( D3 r7 A4 Q5 P! `8 X& d - rx_data[i] = (uint8_t)SPI2_Receive_byte();+ q1 o: M2 [* G3 g9 `5 q$ t$ p0 r
- }9 t; p7 |3 q5 D F, I% I- E
- 7 m0 X4 v3 J0 D; Q' ~( W' \
- }
复制代码
- a @( _/ V& J4 I+ \只需要把自己的SPI驱动替换上去就可以了。 3 |, n6 Q1 Z- [
- void wakeup_idle()
5 t$ o: G0 @. ?; p4 ^ - {, z, b9 H* r2 m
- output_low(LTC6804_CS);7 F9 w0 P+ x* r: E' ?
- delayMicroseconds(2); //Guarantees the isoSPI will be in ready mode
0 X/ H1 D/ }( P/ O+ N - output_high(LTC6804_CS);
- d) ]0 s6 \! b - }
复制代码
3 G+ Z; Z7 J/ b$ [) x% f自己把这个函数中间的部分实现,或者替换成自己的函数: - void wakeup_idle(void)
& ]5 ?5 {2 A& V+ B! q8 i - {9 p5 N4 k! N1 E5 K( ^
- output_low(LTC6804_CS);+ J% o. ^ Y. p& z5 P
- delay_ms(4); //Guarantees the isoSPI will be in ready mode) G e6 P3 S) }# y* B: D) N6 S" T8 f
- output_high(LTC6804_CS);
( _7 L& g! n, A( O: H6 I/ M a. ^: r - }
复制代码
8 r: F' D6 h7 s J下面是原版的初始化函数: - void LTC6804_initialize()! e: c# \& Y/ s1 Q9 H
- {
; a$ P3 ^9 m Q, h, @% h5 c9 f$ j - quikeval_SPI_connect();
9 q$ H: p. c( w& z - spi_enable(SPI_CLOCK_DIV16); // This will set the Linduino to have a 1MHz Clock
% }; Y3 p4 c- \ - set_adc(MD_NORMAL,DCP_DISABLED,CELL_CH_ALL,AUX_CH_ALL);
, r9 d! h5 P4 c9 ?. t: J1 x - }
复制代码 ' m- Z) @5 v$ o5 Q) M: q
我把它根据自己的实际情况修改一下 : - void LTC6804_initialize(void)" ^9 q" t4 u0 _3 I! b! ^
- {
% E: Z/ G1 o v' z" w8 C7 O0 H8 W - Drive_LTC6804_Spi_Init();//SPI外设初始化$ _" O( s" O# y- F* E
- init_cfg(); //配置LTC6804的寄存器7 ]3 ] t- _1 T: X3 ~
- set_adc(MD_FILTERED,DCP_DISABLED,CELL_CH_ALL,AUX_CH_GPIO1);//设置转换方式等
8 u* z; I0 p4 T7 `4 u/ K - wakeup_sleep();//唤醒芯片; L( f+ }: R, @" j7 X& o* Y+ S9 q$ H+ L
- LTC6804_wrcfg(TOTAL_IC,tx_cfg);//把上面的设置写入芯片& R, L$ [; T) N+ H
- if (LTC6804_rdcfg(TOTAL_IC,rx_cfg) == -1) //检查一下到底有没有配置成功
9 V, j8 Z( p: ^; f* ], J - {
: }" r) d: A2 Y; I9 k s X; F( S! P - printf("LTC6804_MODULAR INIT NG!\n\r");
& |& Q C& j. k - }9 [0 h& V5 z! A, j/ t$ u
- else
2 C, _- U4 n. E! d$ _4 z7 W - {
; ?! o n9 A6 v( k. b7 M; r - printf("LTC6804_MODULAR INIT OK!\n\r");1 r" F/ ?# o# f J
- }$ V* N4 V, ~4 }0 k/ x( O
- 0 b9 T2 p5 v' p
- }
复制代码- //手册第49页1 l' t4 a# g8 A
- /* 寄存器 8 7 6 5 4 3 2 1 */
. }2 z' \8 k7 B' [* y' ? - //CFGR0 RD/WR GPIO5 GPIO4 GPIO3 GPIO2 GPIO1 REFON SWTRD ADCOPT. i7 k) w* M' G$ d" u2 K
- //CFGR1 RD/WR VUV[7] VUV[6] VUV[5] VUV[4] VUV[3] VUV[2] VUV[1] VUV[0]+ P I4 w5 P! f C/ X
- //CFGR2 RD/WR VOV[3] VOV[2] VOV[1] VOV[0] VUV[11] VUV[10] VUV[9] VUV[8], E X' {. c+ L' p& W8 A8 a
- //CFGR3 RD/WR VOV[11] VOV[10] VOV[9] VOV[8] VOV[7] VOV[6] VOV[5] VOV[4]
* X' F/ E Z6 C4 e* w0 v& q$ m' I( K - //CFGR4 RD/WR DCC8 DCC7 DCC6 DCC5 DCC4 DCC3 DCC2 DCC1( y2 ~- e) K: t" {, M0 n4 {
- //CFGR5 RD/WR DCTO[3] DCTO[2] DCTO[1] DCTO[0] DCC12 DCC11 DCC10 DCC9
+ ?$ S6 `3 ` ?- A c - void init_cfg(void)3 Q" D$ b6 i2 q- @% d. F; w
- {
7 j& X/ c0 g6 F - int i; q4 l. Q4 X. Z8 i0 I5 U" s
( U3 R# _) y3 Y3 i, X8 [( T- for(i = 0; i<TOTAL_IC;i++)
% y8 d/ o4 N# S+ O3 {( F - {$ X" s7 a$ \. c! T
- tx_cfg[i][0] = 0xFE ; //GPIO引脚下拉电路关断(bit8~bit4) | 基准保持上电状态(bit3) | SWTEN处于逻辑1(软件定时器) | ADC模式选择为0
$ N- r% n. d( B) [0 C- { - tx_cfg[i][1] = 0x00 ; //不使用欠压比较功能5 o6 V) Y& J* R- Z
- tx_cfg[i][2] = 0x00 ; //不使用过压比较功能
1 k/ I: B% _& G1 y1 M O8 N - tx_cfg[i][3] = 0x00 ;! t( X9 F% }! T, L
- tx_cfg[i][4] = 0x00 ; //不使用电池放电功能
) ]" |/ E1 R- K; o; K) O* F - tx_cfg[i][5] = 0x00 ; //放电超时时间6 z' j% S6 Y6 J! Q& H _
- }9 [, V. w9 i) G _: L7 }8 c
- }
复制代码
6 }! Z$ h" Z6 u/ m' J1 L8 ] U5 l7 b" w: O% W2 g; R* {. D
这里只使用了最基本的电压采集,其他的功能都没有用。 上面的代码里面有一个宏 :TOTAL_IC。 这个宏是用来定义一共有几片LTC6804-1的,比如我这次使用了2片,那么它的值就是2. 上面的寄存器设置,可以参考手册: 比如需要追加一些别的功能,便可以根据手册的寄存器进行设置,比如设置报警,设置均衡,设置其他的功能。 以上初始化部分就完成了,或者说移植就完成了,然后便不必对代码文件进行任何修改就可以直接使用,接下来是采集部分: 我是把采集放在main中进行。 - /* 唤醒6804 */
" r3 g( D+ h" }! f& J ~0 c2 R - wakeup_sleep();& ~. ], y! P8 P) x
- /* 启动电压采集 */9 ?) A& Z9 x: J4 N, [0 S; J+ E% l
- LTC6804_adcv();! l4 W1 ]: Y% |9 B
- delay_ms(50);
; `4 e6 c8 Y" q- C% X - /* 读取电压 */# S8 [+ { c8 {) l
- res = LTC6804_rdcv(0, TOTAL_IC, vol_buff);
复制代码 & B8 ^3 B2 q; _* b# e* }( e. T# I/ [
以上便可以采集出电压了。
" z6 c4 j4 H# E+ V4 O" S- N※如果发现几个级联起来的6804,有些片子可以运行正常通信,有些又不可以运行甚至无法通信,在排除硬件的原因以后,可以查看一下这个地方:wakeup_sleep(),试着把唤醒时间设置的长一些。 1 W+ ~: T4 D } I2 R
最后:可以看出来,精度还是不错的~ . @. m( ?* S# e* z
|