LTC6804是一款专门用来做多节电池电池组的监测芯片,最高可监测12节电池,官方误差是低于1.2mv,12 个通道的最快采样速度可以达到290us。 芯片分为两种型号,6804-1和6804-2,区别在于,6804-1采用级联的形式(级联控制),6804-2采用并联形式(分开控制)。 除开硬件连接之外,这两种型号的操作都是大同小异,基本可以视为一样,本文以6804-1为例进行讲解。 原理图和手册中的推荐一样,就不贴出来了,MCU与芯片的通信方式采用四线SPI,这种通信方式很常见,各种MCU的驱动也好找。(看了数据手册,芯片似乎还支持IIC和2线通信,不过我没有用) 4 i, P! }( R; W9 j2 u/ K
; ?2 n# J; \; j6 w
下载下来的代码是C++文件,不能直接在STM32上使用,需要进行一些修改。 首先修改后缀名,改成C文件,然后打开LTC6804.c文件。 ( `+ ?/ w J% S
第一步进行驱动的移植: - void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port9 y0 ]/ a% p5 |+ ^
- uint8_t data[] //Array of bytes to be written on the SPI port+ s3 L7 ^/ A f% H
- )
( J. P" }8 c3 W% z9 t - {0 l( Z; G3 h7 _* O* {6 ^8 e
- uint8_t i;4 X' G8 P2 r( L2 U( E0 w* d
- 5 Z+ Z. H( a( i
- for(i = 0; i < len; i++)! A" S8 N, J8 T; D( y* Q2 b$ |: A
- {, }# t- e+ K. ~+ l2 ]% C# I
- SPI2_Send_byte((int8_t)data[i]);
\ Z+ j& ^6 g( u4 v - }
0 ?8 A. F) L7 y" p$ d - }
复制代码- void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port
4 g1 ~/ e3 u$ M3 V/ X - uint8_t tx_len, //length of the tx data arry
+ y5 d. F$ ~; `8 x - uint8_t *rx_data,//Input: array that will store the data read by the SPI port C( ^" O. h. f
- uint8_t rx_len //Option: number of bytes to be read from the SPI port" Y7 A4 [+ @. U9 N( }) H
- )- F9 @( D+ `" i+ T/ u* k; J, L
- {
: B0 b) y& D# r4 X - uint8_t i;
. K! m& e- Z7 e2 z V4 t - 1 l+ l- h9 f* X
- for(i = 0; i < tx_len; i++)
4 `5 f' D% K' r: o: B - {
5 a0 L" K" J h b3 q+ ^3 L9 B - SPI2_Send_byte(tx_Data[i]);/ G0 p$ d/ U6 ?# o/ H3 K: S
- }
4 ~0 h8 I( y8 F/ t/ H' L6 S0 P
1 _7 E( ]& ^" X/ [- for(i = 0; i < rx_len; i++)
* {6 H& x/ i/ }: Y$ o2 W - {4 l5 S# h3 y4 v) T% A
- rx_data[i] = (uint8_t)SPI2_Receive_byte();
|. c2 |$ |+ _ - }
$ O3 T- f6 a: X: O& N - . _ O# h3 Z# T) I
- }
复制代码
4 d( K# v& `. {- |2 ~只需要把自己的SPI驱动替换上去就可以了。
6 @% [, H g: N: q; C- t- void wakeup_idle(): J. p3 t/ T0 d [+ ^1 _! {% N
- {6 f. g6 F# Y: o3 p- |
- output_low(LTC6804_CS);
. V6 k8 ]: j t8 ? - delayMicroseconds(2); //Guarantees the isoSPI will be in ready mode
$ K v- r- A* s8 o& M3 z! p - output_high(LTC6804_CS);" I q5 e. q4 ~/ C" L6 r
- }
复制代码
3 F6 a! V, f, H6 ]% }2 P' B自己把这个函数中间的部分实现,或者替换成自己的函数: - void wakeup_idle(void)5 S: U& W2 o1 d+ B! X2 ?
- {
9 f" G8 }9 F; b6 I. @! }/ ~ - output_low(LTC6804_CS);1 b0 K* I4 x* F
- delay_ms(4); //Guarantees the isoSPI will be in ready mode. a+ k7 N/ E6 `) M
- output_high(LTC6804_CS);
2 C6 O$ D; q+ E) I9 s) Z6 r5 P# X0 Q - }
复制代码 3 M; F; L1 O _2 y3 h
下面是原版的初始化函数: - void LTC6804_initialize()
0 Z+ B+ `' o" V9 d9 E - {
, [& {' ~" i4 S- {( W3 e | - quikeval_SPI_connect();* t% ~3 u; m! v& b/ w+ H, U
- spi_enable(SPI_CLOCK_DIV16); // This will set the Linduino to have a 1MHz Clock
; H4 N; l7 u- |. |* c- [ - set_adc(MD_NORMAL,DCP_DISABLED,CELL_CH_ALL,AUX_CH_ALL);
1 s' j3 v# Z* ?$ s+ [ - }
复制代码
4 X9 c& K# Q' x4 ?4 a& ]# a我把它根据自己的实际情况修改一下 : - void LTC6804_initialize(void)+ |# p& n; v: r9 y8 _/ Z' w
- {
2 z& v* S, i/ z - Drive_LTC6804_Spi_Init();//SPI外设初始化1 E) i: Q9 H1 m8 N) q7 |# u
- init_cfg(); //配置LTC6804的寄存器+ p# O: I# N9 E5 `
- set_adc(MD_FILTERED,DCP_DISABLED,CELL_CH_ALL,AUX_CH_GPIO1);//设置转换方式等
2 j8 d$ H+ j! X - wakeup_sleep();//唤醒芯片3 l/ L* g% C: }
- LTC6804_wrcfg(TOTAL_IC,tx_cfg);//把上面的设置写入芯片
6 t" h7 o$ G7 r! f* R - if (LTC6804_rdcfg(TOTAL_IC,rx_cfg) == -1) //检查一下到底有没有配置成功
1 s: j4 H h) F: X/ w! W5 U' Z) |& {- D - {% f+ [3 v4 D7 m8 H6 ]8 ^# k. [: @
- printf("LTC6804_MODULAR INIT NG!\n\r");
. Q/ ]2 s0 |7 Q( O0 [/ @$ D - }& r1 S/ p2 n8 x* D/ m' B! M% F: r/ q
- else1 e' F2 [& ?5 {
- {
) F+ A4 u0 i4 b4 A* {8 b) ~* q& j - printf("LTC6804_MODULAR INIT OK!\n\r");
% z+ C/ N6 t7 R# b' @/ }7 t7 |9 B - }
' u/ ?3 n! M5 Y& S) G2 i* }6 J) j" N - " S, h0 w6 q% K9 i$ N
- }
复制代码- //手册第49页
- j" q, z6 h K) ^( Y - /* 寄存器 8 7 6 5 4 3 2 1 */& w- y$ ]: H9 j
- //CFGR0 RD/WR GPIO5 GPIO4 GPIO3 GPIO2 GPIO1 REFON SWTRD ADCOPT4 [# q$ z9 A" }5 v& F$ o& ~6 W" o
- //CFGR1 RD/WR VUV[7] VUV[6] VUV[5] VUV[4] VUV[3] VUV[2] VUV[1] VUV[0]! h4 z3 B- M; l4 L" L+ A
- //CFGR2 RD/WR VOV[3] VOV[2] VOV[1] VOV[0] VUV[11] VUV[10] VUV[9] VUV[8]; S4 c4 n i! p- _0 ^+ _$ p
- //CFGR3 RD/WR VOV[11] VOV[10] VOV[9] VOV[8] VOV[7] VOV[6] VOV[5] VOV[4]: i: n) |, D) K4 F
- //CFGR4 RD/WR DCC8 DCC7 DCC6 DCC5 DCC4 DCC3 DCC2 DCC19 J" L( p4 [5 }8 }6 Q" ]/ m
- //CFGR5 RD/WR DCTO[3] DCTO[2] DCTO[1] DCTO[0] DCC12 DCC11 DCC10 DCC9
6 [5 R( J; P$ p0 K - void init_cfg(void)
8 `$ Z, x0 t+ b- h2 W# ?! Z7 C - {' V6 T9 s3 u9 Y" r
- int i;
/ h s# O4 N* c - 8 f3 e3 P# A" x: e, x
- for(i = 0; i<TOTAL_IC;i++)
9 K1 O4 F2 r2 f1 W" X8 F1 f - {% {" d! z9 s' q$ C; z; A/ d
- tx_cfg[i][0] = 0xFE ; //GPIO引脚下拉电路关断(bit8~bit4) | 基准保持上电状态(bit3) | SWTEN处于逻辑1(软件定时器) | ADC模式选择为0# [9 ?. T h& ^( w5 {/ ?) X( Z
- tx_cfg[i][1] = 0x00 ; //不使用欠压比较功能
4 f7 ^/ v3 S+ q4 F - tx_cfg[i][2] = 0x00 ; //不使用过压比较功能- o+ k4 ^2 Y$ X' d% W
- tx_cfg[i][3] = 0x00 ;
* K9 z2 u8 U4 B6 ^7 J3 q - tx_cfg[i][4] = 0x00 ; //不使用电池放电功能7 S) P" c; v7 e# H/ Z P$ ~1 |
- tx_cfg[i][5] = 0x00 ; //放电超时时间
^: p! a/ B4 ?. d7 _( d - }3 Q2 U; K3 o$ H4 g
- }
复制代码 * z0 f. e/ j' t5 H# R8 U6 \
. i$ x% p+ ?1 b7 p# k% ? H; I. i
这里只使用了最基本的电压采集,其他的功能都没有用。 上面的代码里面有一个宏 :TOTAL_IC。 这个宏是用来定义一共有几片LTC6804-1的,比如我这次使用了2片,那么它的值就是2. 上面的寄存器设置,可以参考手册: 比如需要追加一些别的功能,便可以根据手册的寄存器进行设置,比如设置报警,设置均衡,设置其他的功能。 以上初始化部分就完成了,或者说移植就完成了,然后便不必对代码文件进行任何修改就可以直接使用,接下来是采集部分: 我是把采集放在main中进行。 - /* 唤醒6804 */) o" R& V* `: i8 o
- wakeup_sleep();
9 m6 v; J: i. }7 Q0 N - /* 启动电压采集 */- I* b# \9 K; F F }) E" h
- LTC6804_adcv();( U$ U) u9 H: h9 D, f2 ^) y
- delay_ms(50);
- x7 ^$ F+ f2 S8 _; Z - /* 读取电压 */" _. g2 f: ^% F# H) y6 h
- res = LTC6804_rdcv(0, TOTAL_IC, vol_buff);
复制代码 4 ?, w5 [6 e( t8 [# g: S- h
以上便可以采集出电压了。 L" n# ?1 \6 x5 s; h, A
※如果发现几个级联起来的6804,有些片子可以运行正常通信,有些又不可以运行甚至无法通信,在排除硬件的原因以后,可以查看一下这个地方:wakeup_sleep(),试着把唤醒时间设置的长一些。
! I, d" U, Q/ G2 g" J最后:可以看出来,精度还是不错的~
( F" [ {" l' g( g% m S" m |