LTC6804是一款专门用来做多节电池电池组的监测芯片,最高可监测12节电池,官方误差是低于1.2mv,12 个通道的最快采样速度可以达到290us。 芯片分为两种型号,6804-1和6804-2,区别在于,6804-1采用级联的形式(级联控制),6804-2采用并联形式(分开控制)。 除开硬件连接之外,这两种型号的操作都是大同小异,基本可以视为一样,本文以6804-1为例进行讲解。 原理图和手册中的推荐一样,就不贴出来了,MCU与芯片的通信方式采用四线SPI,这种通信方式很常见,各种MCU的驱动也好找。(看了数据手册,芯片似乎还支持IIC和2线通信,不过我没有用)
5 `6 L' y5 |/ p
0 v; w1 [* i( j$ M, P" O, D 下载下来的代码是C++文件,不能直接在STM32上使用,需要进行一些修改。 首先修改后缀名,改成C文件,然后打开LTC6804.c文件。
# [! W! V/ U1 _: Z9 V* B第一步进行驱动的移植: - void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port7 J- ~$ v {; F3 w: u( V7 T
- uint8_t data[] //Array of bytes to be written on the SPI port4 I6 ?$ i/ q) b1 \( J
- )$ x; S, d; b" U. x
- {" m4 Z$ A M: f* x4 s+ ^! q+ H+ \3 {
- uint8_t i;- h0 p3 M" p3 S$ ~1 v6 \
9 i% F# ^7 |% }- for(i = 0; i < len; i++)" `7 n) n. X4 @; q9 j5 ~3 N3 A
- {1 a; \( p) [/ f6 [9 X
- SPI2_Send_byte((int8_t)data[i]);4 ^+ z" o8 F: H9 V+ S- ?
- }
* N7 v, I" q* k - }
复制代码- void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port+ Y9 K- ?1 U6 B; W9 ?
- uint8_t tx_len, //length of the tx data arry2 o) J; D( @4 [ w: \+ d( z
- uint8_t *rx_data,//Input: array that will store the data read by the SPI port
0 L( E0 P# @; u( u, d/ W4 C1 Z - uint8_t rx_len //Option: number of bytes to be read from the SPI port
p) s+ S( g3 f4 R; Q/ | - )
; k) v( ]# r; U2 Y/ v- b - {. q$ [5 J; A, Y& }4 L/ `: k. \
- uint8_t i;% X( ^' J9 U6 _3 O4 U# s6 \+ F
+ { d: ?5 q7 a- for(i = 0; i < tx_len; i++): o2 u9 E' G3 { b
- {: Z9 A' l3 t ^+ \
- SPI2_Send_byte(tx_Data[i]);
6 k. Y, v$ d. u, y) c - }
9 E1 D: V7 j$ ^0 l - - u: q) k8 l' }* O$ f" M' A
- for(i = 0; i < rx_len; i++)$ ~- ~7 H) W" y& U$ i$ J! W
- {2 e$ Q9 e4 P* s5 ^. M: C
- rx_data[i] = (uint8_t)SPI2_Receive_byte();( U5 H! Z6 w; o; f; o" |' C4 i; ^
- }
* v! j, `) O) q+ u& [ - 3 C* A' {% ^, X. ?/ T2 p" q
- }
复制代码 - q+ {$ h& }4 V' ^- W6 E# `
只需要把自己的SPI驱动替换上去就可以了。 " a3 G! L( M1 n6 Q% G
- void wakeup_idle()1 ?# T1 n: h5 y: x& w$ v
- {
& U; W! i2 v ], J5 y4 w& U - output_low(LTC6804_CS);
3 W) c/ n- G M4 ` - delayMicroseconds(2); //Guarantees the isoSPI will be in ready mode; Z' |0 o0 D! v. ~" c9 b$ u9 X
- output_high(LTC6804_CS);/ Z/ `6 }; q; Q5 W' d i, a
- }
复制代码 - k& V# j: g- R- X2 Q
自己把这个函数中间的部分实现,或者替换成自己的函数: - void wakeup_idle(void): a" K' X1 {; [7 J0 _) c
- {
& r- J: m" |- o& U4 l - output_low(LTC6804_CS);
( c6 W2 r7 m9 _- ]9 ~1 i* B - delay_ms(4); //Guarantees the isoSPI will be in ready mode
: ? K7 @" E" k1 e' X - output_high(LTC6804_CS);
% q6 x, i! D6 u- I0 p - }
复制代码 4 r( b' |8 ^" g o I* w
下面是原版的初始化函数: - void LTC6804_initialize()
# N6 `" h0 N1 o1 S3 X - {- D8 t' _5 E% A; P& G6 f' q. _' q
- quikeval_SPI_connect();8 u" t- t( V: V' ]6 m2 @/ u8 B8 T0 b
- spi_enable(SPI_CLOCK_DIV16); // This will set the Linduino to have a 1MHz Clock: }3 r7 h/ h' M4 S* t/ B4 V- L
- set_adc(MD_NORMAL,DCP_DISABLED,CELL_CH_ALL,AUX_CH_ALL);
2 G( \2 g$ W3 f f5 s! s1 F; t - }
复制代码 4 H! U# y+ M$ L' E; {
我把它根据自己的实际情况修改一下 : - void LTC6804_initialize(void)
6 J$ U% m/ s- D+ a ^ - {4 ^. R4 j: U8 A/ F; e
- Drive_LTC6804_Spi_Init();//SPI外设初始化- `. Q; Y8 ~/ [6 i; f1 B' d: C
- init_cfg(); //配置LTC6804的寄存器
1 t; c9 ?5 Z; m/ U' E' u* _ - set_adc(MD_FILTERED,DCP_DISABLED,CELL_CH_ALL,AUX_CH_GPIO1);//设置转换方式等
8 d1 W+ J$ ^6 f% a0 Q' N: U) X - wakeup_sleep();//唤醒芯片7 |$ [ y9 c' S; l) W: ~7 X
- LTC6804_wrcfg(TOTAL_IC,tx_cfg);//把上面的设置写入芯片1 Z% m8 Y2 p: j7 l: _- P
- if (LTC6804_rdcfg(TOTAL_IC,rx_cfg) == -1) //检查一下到底有没有配置成功8 d0 B* h4 J9 v$ W5 {
- {
, m3 F% y6 Z0 h - printf("LTC6804_MODULAR INIT NG!\n\r");
- U& L! r7 ]1 R, G6 V - }3 s) v! k( \ l
- else/ a1 H6 J; T* o8 ]+ k/ l! `6 d
- {$ z5 X& z: e8 ~# B
- printf("LTC6804_MODULAR INIT OK!\n\r");3 z, U R: o9 d& N, Y8 V, J
- }- E) `4 G" ]. d
T2 t/ E; d4 A) ^% o5 f- }
复制代码- //手册第49页
; A; A2 ^ m* x - /* 寄存器 8 7 6 5 4 3 2 1 */* N' U' q# M) X; _
- //CFGR0 RD/WR GPIO5 GPIO4 GPIO3 GPIO2 GPIO1 REFON SWTRD ADCOPT! U& h6 Y( r" F, W6 s
- //CFGR1 RD/WR VUV[7] VUV[6] VUV[5] VUV[4] VUV[3] VUV[2] VUV[1] VUV[0]2 ~' B3 Y6 |( w' K& O1 {! w& o3 f
- //CFGR2 RD/WR VOV[3] VOV[2] VOV[1] VOV[0] VUV[11] VUV[10] VUV[9] VUV[8]3 b3 A; H/ i. v& l$ V0 L
- //CFGR3 RD/WR VOV[11] VOV[10] VOV[9] VOV[8] VOV[7] VOV[6] VOV[5] VOV[4]6 B0 c( } x8 s9 J0 F( Q1 ~8 C
- //CFGR4 RD/WR DCC8 DCC7 DCC6 DCC5 DCC4 DCC3 DCC2 DCC1
4 G% o% I$ \2 T7 R* \0 E8 ]( @' n" u: V - //CFGR5 RD/WR DCTO[3] DCTO[2] DCTO[1] DCTO[0] DCC12 DCC11 DCC10 DCC9; H. I4 \4 `, Q1 q/ v3 P
- void init_cfg(void)3 j9 m9 S i/ i6 Q; e
- {" M1 G5 @/ q6 m( I1 g2 I: a
- int i;/ P6 L; g: l4 e! L+ q$ I
$ m/ C( K& }( C+ M$ A. l- for(i = 0; i<TOTAL_IC;i++)) L: X$ v- G' O4 }* X
- {/ Q: X2 u8 E& l* t- S% w- |" ^
- tx_cfg[i][0] = 0xFE ; //GPIO引脚下拉电路关断(bit8~bit4) | 基准保持上电状态(bit3) | SWTEN处于逻辑1(软件定时器) | ADC模式选择为0
7 d$ l: Q2 [& N7 g+ U; ?. o, v, B - tx_cfg[i][1] = 0x00 ; //不使用欠压比较功能' F v+ Q7 s4 Y3 p5 }' h" m# V: ]
- tx_cfg[i][2] = 0x00 ; //不使用过压比较功能
! R% t7 _# d) I2 J9 d+ {: ` - tx_cfg[i][3] = 0x00 ;
6 M, q5 }3 D3 c& A - tx_cfg[i][4] = 0x00 ; //不使用电池放电功能9 y" e9 r' Y* ]7 M( c3 x& s$ _
- tx_cfg[i][5] = 0x00 ; //放电超时时间 O3 e& @# G" A6 q$ K3 }
- } D. c1 q$ }, v0 s( }
- }
复制代码
5 t$ M5 D# x+ l& ?
+ I" \# A( w9 k" g P% w: w, D这里只使用了最基本的电压采集,其他的功能都没有用。 上面的代码里面有一个宏 :TOTAL_IC。 这个宏是用来定义一共有几片LTC6804-1的,比如我这次使用了2片,那么它的值就是2. 上面的寄存器设置,可以参考手册: 比如需要追加一些别的功能,便可以根据手册的寄存器进行设置,比如设置报警,设置均衡,设置其他的功能。 以上初始化部分就完成了,或者说移植就完成了,然后便不必对代码文件进行任何修改就可以直接使用,接下来是采集部分: 我是把采集放在main中进行。 - /* 唤醒6804 */& C* b$ E% T4 w) _& @) {/ S3 E
- wakeup_sleep();) v: f5 `1 D9 E$ R3 w7 Q) M. V' f2 X
- /* 启动电压采集 */9 e; j3 Y! S, @% W
- LTC6804_adcv();, R8 {2 o- t; v
- delay_ms(50);
2 ~: z+ a; t4 e6 l K - /* 读取电压 */
1 _( d$ X/ L' D - res = LTC6804_rdcv(0, TOTAL_IC, vol_buff);
复制代码
1 N$ `( }' b) a( r, l 以上便可以采集出电压了。 " d# T4 J; P5 Q
※如果发现几个级联起来的6804,有些片子可以运行正常通信,有些又不可以运行甚至无法通信,在排除硬件的原因以后,可以查看一下这个地方:wakeup_sleep(),试着把唤醒时间设置的长一些。 8 n) ~' P! G9 i/ P
最后:可以看出来,精度还是不错的~ : ^* w; w0 c! X+ |5 v' [, ]
|