|
LTC6804是一款专门用来做多节电池电池组的监测芯片,最高可监测12节电池,官方误差是低于1.2mv,12 个通道的最快采样速度可以达到290us。 芯片分为两种型号,6804-1和6804-2,区别在于,6804-1采用级联的形式(级联控制),6804-2采用并联形式(分开控制)。 除开硬件连接之外,这两种型号的操作都是大同小异,基本可以视为一样,本文以6804-1为例进行讲解。 原理图和手册中的推荐一样,就不贴出来了,MCU与芯片的通信方式采用四线SPI,这种通信方式很常见,各种MCU的驱动也好找。(看了数据手册,芯片似乎还支持IIC和2线通信,不过我没有用) ! t; j3 w7 s- o8 m' N- l$ k( o) C
# m6 O9 \6 k. Y) W
下载下来的代码是C++文件,不能直接在STM32上使用,需要进行一些修改。 首先修改后缀名,改成C文件,然后打开LTC6804.c文件。 : i- T% q8 K! {/ m
第一步进行驱动的移植: - void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port' A4 g$ c6 D" x6 y
- uint8_t data[] //Array of bytes to be written on the SPI port! H' U/ L3 S3 K" ]1 u7 Z
- )
/ ^* B, {1 `4 x! I, t' R1 [ - {
4 T/ ]7 L9 p/ B/ C" v4 K - uint8_t i;
6 T) T! M/ M4 s: K! [: a q2 s% e
4 c; m" p2 A" J- for(i = 0; i < len; i++)
4 m% P( ]3 E: c+ G+ I) S7 g - {4 G; t! s' X2 F2 ]3 Y+ P) C: l3 j
- SPI2_Send_byte((int8_t)data[i]);6 g: {) T( A. `% q
- }
8 I t C4 H; ]4 r5 [ - }
复制代码- void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port& f) y3 L" F' r7 w/ Y
- uint8_t tx_len, //length of the tx data arry ~2 p# O4 R" x- P( k9 m( r3 b; l
- uint8_t *rx_data,//Input: array that will store the data read by the SPI port
' j4 a; d5 O* y. {; P2 k - uint8_t rx_len //Option: number of bytes to be read from the SPI port
+ x2 i$ F% u) J. ` v. X' b1 B - )
, L4 S, Q' I2 W0 y! ] - {- E- n u7 e9 ?% D. H3 |
- uint8_t i;
: L/ Q; R' H2 z% I4 i
9 `$ w( }2 @5 R- for(i = 0; i < tx_len; i++)
2 z; q) R2 i- s - {
3 ?9 f5 t0 X- _. E% g, c- d: K - SPI2_Send_byte(tx_Data[i]);
3 w7 @ N1 L( v7 ` F0 I - }
$ O' C4 Y& x1 k' { - 1 _; y+ O# I" o5 E7 m0 _
- for(i = 0; i < rx_len; i++)' O+ n" H: Y; J5 h/ S, y! m5 T. J# [
- {2 Q0 K( r5 X' D
- rx_data[i] = (uint8_t)SPI2_Receive_byte();
0 `( t! w/ U" l9 X- _5 B9 |: ]. T - }! \, Z' y6 C9 H" |8 k
- & c% Y7 ^! T2 k
- }
复制代码 - [$ _8 a$ J" q0 @3 h
只需要把自己的SPI驱动替换上去就可以了。
+ l9 j' z, O. ?1 l1 v; [- void wakeup_idle()4 N S8 ?# q6 q& D2 [
- {* `" N' K- G: V3 ?
- output_low(LTC6804_CS);. L$ h8 J# G$ X4 a* {) I& t+ k
- delayMicroseconds(2); //Guarantees the isoSPI will be in ready mode2 D) w' o# r) \+ W8 M1 i4 V7 e
- output_high(LTC6804_CS);
: z `5 K9 A( K& P& T& w - }
复制代码
4 q0 E# Q V7 c0 u自己把这个函数中间的部分实现,或者替换成自己的函数: - void wakeup_idle(void)6 N/ `& j% D7 y- W5 }7 T9 H5 v
- {
. a8 s/ H2 ^! \ - output_low(LTC6804_CS);* H# p: ]. D3 C# P- E/ Z
- delay_ms(4); //Guarantees the isoSPI will be in ready mode
+ t; N' i- A6 o% o9 R - output_high(LTC6804_CS);! J/ l+ T; q5 z2 ^( k6 F! Y
- }
复制代码 $ ^* B+ k2 A# e- }/ W4 `* v
下面是原版的初始化函数: - void LTC6804_initialize()
& G2 H) [$ w4 i/ R - {
$ z4 {3 @9 V4 I" T4 |1 |( E - quikeval_SPI_connect();
2 t6 }% D. t% G6 _ - spi_enable(SPI_CLOCK_DIV16); // This will set the Linduino to have a 1MHz Clock
Y1 m& ~$ u4 V# q" N, h: N - set_adc(MD_NORMAL,DCP_DISABLED,CELL_CH_ALL,AUX_CH_ALL);
( b! L' C4 n/ Z" E8 i, g( G - }
复制代码 ) [8 i9 x. A2 T$ w3 t G0 C3 |: T
我把它根据自己的实际情况修改一下 : - void LTC6804_initialize(void)5 |& h' N9 A7 Q {) S+ a0 h) X1 T W
- {
2 ^$ [# [4 _, {& z2 I9 w8 p" o; i - Drive_LTC6804_Spi_Init();//SPI外设初始化6 A A: k4 W7 P" B# F- _7 x
- init_cfg(); //配置LTC6804的寄存器1 b# R8 ^- U( n( J8 N* C+ o G
- set_adc(MD_FILTERED,DCP_DISABLED,CELL_CH_ALL,AUX_CH_GPIO1);//设置转换方式等8 h, z6 O( O: L* u- X
- wakeup_sleep();//唤醒芯片
" v, W3 y! D5 _. L* P+ O; h( ]: t - LTC6804_wrcfg(TOTAL_IC,tx_cfg);//把上面的设置写入芯片
4 C/ y i$ _; g, D2 ]3 C! r - if (LTC6804_rdcfg(TOTAL_IC,rx_cfg) == -1) //检查一下到底有没有配置成功: }% [5 U6 q/ T; S/ U2 W$ C ^
- {; f9 q$ X' I* Y* `( r
- printf("LTC6804_MODULAR INIT NG!\n\r");1 O$ |* [0 o% o. F" z
- }9 E- |/ X8 S( E4 X% w, c1 t; b) k
- else5 E; n; H* c" z
- {
9 ?$ F: h& n- [' @+ K - printf("LTC6804_MODULAR INIT OK!\n\r");
1 s; r2 Y$ s9 o$ R - }
; O7 I6 \% }) x% g$ A - ( j$ R/ C* t! k6 A
- }
复制代码- //手册第49页
! ~% g* y+ f) Z - /* 寄存器 8 7 6 5 4 3 2 1 */
3 M7 ]: d) r+ ^* p% [1 r4 a - //CFGR0 RD/WR GPIO5 GPIO4 GPIO3 GPIO2 GPIO1 REFON SWTRD ADCOPT& |: u0 x/ w+ T. h1 _# t) B' _$ D
- //CFGR1 RD/WR VUV[7] VUV[6] VUV[5] VUV[4] VUV[3] VUV[2] VUV[1] VUV[0]3 x4 D! x7 O/ x) `
- //CFGR2 RD/WR VOV[3] VOV[2] VOV[1] VOV[0] VUV[11] VUV[10] VUV[9] VUV[8]
, E1 q8 r, X* j/ g+ z4 s - //CFGR3 RD/WR VOV[11] VOV[10] VOV[9] VOV[8] VOV[7] VOV[6] VOV[5] VOV[4]1 p; `2 K% E6 d' _6 C$ n3 J
- //CFGR4 RD/WR DCC8 DCC7 DCC6 DCC5 DCC4 DCC3 DCC2 DCC1
5 I7 R& ^- ^2 F& x. O - //CFGR5 RD/WR DCTO[3] DCTO[2] DCTO[1] DCTO[0] DCC12 DCC11 DCC10 DCC9% c ?. L3 R4 E/ J6 D1 B+ C. [
- void init_cfg(void)
" p. [2 K5 r& F5 t' l$ l) g - {( s6 g: B, w3 F
- int i;& r! x+ c' R, Z3 W, w
1 u1 X9 f0 z1 n- for(i = 0; i<TOTAL_IC;i++)
5 A7 ]4 d$ T% Z: w) U3 ~2 m - {
7 w, P- S( l: a9 [" ]/ s8 l - tx_cfg[i][0] = 0xFE ; //GPIO引脚下拉电路关断(bit8~bit4) | 基准保持上电状态(bit3) | SWTEN处于逻辑1(软件定时器) | ADC模式选择为0) |- Z% d' V+ ^5 E, p1 g
- tx_cfg[i][1] = 0x00 ; //不使用欠压比较功能
. H1 b: v2 k/ w - tx_cfg[i][2] = 0x00 ; //不使用过压比较功能
+ T1 }6 t4 y: n& ^ - tx_cfg[i][3] = 0x00 ; N3 A! h- O5 ^$ {, c( k
- tx_cfg[i][4] = 0x00 ; //不使用电池放电功能8 h$ d3 [* ^' h* G# M
- tx_cfg[i][5] = 0x00 ; //放电超时时间1 I9 N7 d( O6 k* O' H8 ?7 L$ A
- }
, `# _, x A" r; {) F k - }
复制代码
! i& m" `/ \6 }' Z& B0 C
5 d; l* E k+ l' w$ h$ f; z3 @这里只使用了最基本的电压采集,其他的功能都没有用。 上面的代码里面有一个宏 :TOTAL_IC。 这个宏是用来定义一共有几片LTC6804-1的,比如我这次使用了2片,那么它的值就是2. 上面的寄存器设置,可以参考手册: 比如需要追加一些别的功能,便可以根据手册的寄存器进行设置,比如设置报警,设置均衡,设置其他的功能。 以上初始化部分就完成了,或者说移植就完成了,然后便不必对代码文件进行任何修改就可以直接使用,接下来是采集部分: 我是把采集放在main中进行。 - /* 唤醒6804 */) c/ Y1 |. ]2 Z) ^7 S8 ~
- wakeup_sleep();4 \0 R; e& r: b5 \% I% c
- /* 启动电压采集 */
8 X. A% C* q$ ?" [2 Q8 e - LTC6804_adcv(); S7 R4 U& }6 K1 b! p/ M0 W
- delay_ms(50);: s: A$ T/ l' _4 b# C
- /* 读取电压 */
# j7 e' U" @- } - res = LTC6804_rdcv(0, TOTAL_IC, vol_buff);
复制代码
# t- t A8 I: o6 x 以上便可以采集出电压了。
/ P4 r% f* h! i. j※如果发现几个级联起来的6804,有些片子可以运行正常通信,有些又不可以运行甚至无法通信,在排除硬件的原因以后,可以查看一下这个地方:wakeup_sleep(),试着把唤醒时间设置的长一些。 + a8 L: O2 l3 ~4 g$ R% X0 Z
最后:可以看出来,精度还是不错的~
7 ~3 H: ?+ U9 W7 P6 D- v |