|
LTC6804是一款专门用来做多节电池电池组的监测芯片,最高可监测12节电池,官方误差是低于1.2mv,12 个通道的最快采样速度可以达到290us。 芯片分为两种型号,6804-1和6804-2,区别在于,6804-1采用级联的形式(级联控制),6804-2采用并联形式(分开控制)。 除开硬件连接之外,这两种型号的操作都是大同小异,基本可以视为一样,本文以6804-1为例进行讲解。 原理图和手册中的推荐一样,就不贴出来了,MCU与芯片的通信方式采用四线SPI,这种通信方式很常见,各种MCU的驱动也好找。(看了数据手册,芯片似乎还支持IIC和2线通信,不过我没有用) : v8 s% I2 E7 ^) v0 f9 I
" L2 H0 O& d9 \
下载下来的代码是C++文件,不能直接在STM32上使用,需要进行一些修改。 首先修改后缀名,改成C文件,然后打开LTC6804.c文件。
( ~6 N( E& E! J5 B, @8 I z8 ~( j& _# t第一步进行驱动的移植: - void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port9 s8 ~/ E, r# {$ B8 h7 L/ Y& T
- uint8_t data[] //Array of bytes to be written on the SPI port
, M" k% r6 ?) M, |7 F/ F) n8 \ - )
9 R- w0 q# k6 S2 @9 d - {
5 p$ ^' X# e2 @; ^8 d - uint8_t i;
4 s/ C( A1 ~/ {+ ] - " e0 \' l% t1 z' C9 V5 b; i! C* w) Q
- for(i = 0; i < len; i++)
+ N& C; `! h- b - {
, C( y8 N4 o* W' e - SPI2_Send_byte((int8_t)data[i]);& }3 I2 Z+ W, a$ X4 `6 V
- }
- a! u0 \% m" r; b4 i5 ~ - }
复制代码- void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port
: l( w6 S7 W/ I1 W! B2 g - uint8_t tx_len, //length of the tx data arry$ H% s3 K2 \' j6 J" d- M+ ?
- uint8_t *rx_data,//Input: array that will store the data read by the SPI port
) i: \9 \- D/ R$ a( v( Q- n$ a - uint8_t rx_len //Option: number of bytes to be read from the SPI port; H* z2 X% n/ X8 [% X& W
- )$ Y% S7 s6 q7 D
- {6 q f5 w8 ]% P$ I6 _
- uint8_t i;1 \ ~& y6 W8 _) k
- - v! B9 ]! e& ~2 |- F. {4 n
- for(i = 0; i < tx_len; i++)/ `' |, Z% K$ e7 J* }
- {
1 @6 e$ M0 I D$ [0 h1 J - SPI2_Send_byte(tx_Data[i]);/ R, ^9 N4 p0 v2 e7 y
- }$ D0 Q8 e' J" A7 s* f$ g7 X
2 S9 V" g+ z& i- for(i = 0; i < rx_len; i++)7 ?7 l7 G! `, p$ A- w4 I# C* I- m
- {9 [2 n2 p+ Q9 W( u, b7 {) D- Q& u
- rx_data[i] = (uint8_t)SPI2_Receive_byte();6 E' r3 ^. f7 M7 t0 M1 t" B6 z: ^. e
- }2 H( B# ?+ n) X# r, C" r$ J
- 1 ~+ c9 r: |( R F o; X' N( Y
- }
复制代码 4 I$ I9 [! O0 d/ ~, ~: e4 j' G
只需要把自己的SPI驱动替换上去就可以了。
7 U3 s+ @( H5 g5 ~8 U. c$ m- void wakeup_idle(); l' L; ]& t8 ?5 m5 C7 k$ k0 G: q
- {' u8 G0 x r( s. ~8 R# `
- output_low(LTC6804_CS);3 I* N% k% _& v6 u
- delayMicroseconds(2); //Guarantees the isoSPI will be in ready mode
- G3 Q- P5 G! ^9 h - output_high(LTC6804_CS);
2 n$ M$ m$ K7 v9 X - }
复制代码
" s9 r3 [3 I5 b, b4 x自己把这个函数中间的部分实现,或者替换成自己的函数: - void wakeup_idle(void)
! ]- h1 b7 j/ _: w* [# Q2 q - {
/ k! _+ C; g; }& {+ b - output_low(LTC6804_CS);: m2 A3 B _3 f* V, j$ D
- delay_ms(4); //Guarantees the isoSPI will be in ready mode7 |8 G/ X! V0 l- e' ~
- output_high(LTC6804_CS);
8 f" F1 }* V8 ^ @ ~ t9 j - }
复制代码
S" f/ V& y3 A2 q$ A( }2 A下面是原版的初始化函数: - void LTC6804_initialize()
; f3 L1 N% t7 `( B - {
9 L; _. T. U9 e" [3 V1 [8 I - quikeval_SPI_connect();
: S* @, d% D' E ~+ i - spi_enable(SPI_CLOCK_DIV16); // This will set the Linduino to have a 1MHz Clock
1 k) i# j# }5 @6 k5 i - set_adc(MD_NORMAL,DCP_DISABLED,CELL_CH_ALL,AUX_CH_ALL);4 c. H$ ]7 Q8 o- m8 ?# ?- R+ O
- }
复制代码
& a- H: B O1 v9 r我把它根据自己的实际情况修改一下 : - void LTC6804_initialize(void)
Y9 c2 @( H, j Y3 P - {8 K' c6 r& _: j) \' @8 h4 B
- Drive_LTC6804_Spi_Init();//SPI外设初始化
6 W! c1 V& Q( R; L0 I - init_cfg(); //配置LTC6804的寄存器# _! U$ @. L* D8 P0 u4 N. C
- set_adc(MD_FILTERED,DCP_DISABLED,CELL_CH_ALL,AUX_CH_GPIO1);//设置转换方式等
7 e/ G7 L* `5 [; \% O/ H - wakeup_sleep();//唤醒芯片2 h: {. v; x2 r2 C' i
- LTC6804_wrcfg(TOTAL_IC,tx_cfg);//把上面的设置写入芯片2 a _( X! Z! N
- if (LTC6804_rdcfg(TOTAL_IC,rx_cfg) == -1) //检查一下到底有没有配置成功
# T" C8 L1 y4 @: E* I% C - {) W9 n- T( q- b! L! |& z( e6 g
- printf("LTC6804_MODULAR INIT NG!\n\r");
. X# I7 O7 m m, [ - }& W* i- \4 S- J9 U ]8 Y
- else* l) r$ N: k8 N
- {
: N; a. c8 _* p# p2 c* i0 o( k' m - printf("LTC6804_MODULAR INIT OK!\n\r");
5 x- O$ v8 _1 D5 m$ F' T1 H/ f - }% g; ]) \* [. I+ O' f4 O
- 4 o( E4 A! { b
- }
复制代码- //手册第49页4 z$ z- \+ r. G; @$ Q8 V& _8 ^
- /* 寄存器 8 7 6 5 4 3 2 1 */6 g7 x1 r0 F; ]8 a: |# x
- //CFGR0 RD/WR GPIO5 GPIO4 GPIO3 GPIO2 GPIO1 REFON SWTRD ADCOPT5 F9 k U# g, c! U- q# U. _, R2 X
- //CFGR1 RD/WR VUV[7] VUV[6] VUV[5] VUV[4] VUV[3] VUV[2] VUV[1] VUV[0]! e! D# r$ y A! I
- //CFGR2 RD/WR VOV[3] VOV[2] VOV[1] VOV[0] VUV[11] VUV[10] VUV[9] VUV[8]
8 r, y8 ?; |) K% o6 p9 I - //CFGR3 RD/WR VOV[11] VOV[10] VOV[9] VOV[8] VOV[7] VOV[6] VOV[5] VOV[4]
8 D- m0 K$ q2 r9 v" B% q - //CFGR4 RD/WR DCC8 DCC7 DCC6 DCC5 DCC4 DCC3 DCC2 DCC1
# K* ~+ r: i, { - //CFGR5 RD/WR DCTO[3] DCTO[2] DCTO[1] DCTO[0] DCC12 DCC11 DCC10 DCC94 i$ W5 v- w% R% j
- void init_cfg(void)
- S4 C3 U( W) d! A2 r - {
. T$ A ~- |& w9 Y$ z! A - int i; f6 C% B% b; L" e
6 y% H/ N% n. Q( Z3 m- J5 d- for(i = 0; i<TOTAL_IC;i++)
, s! q0 s. c9 ]# a - {
& T9 Z ]; d+ E( ^0 m, f1 \ - tx_cfg[i][0] = 0xFE ; //GPIO引脚下拉电路关断(bit8~bit4) | 基准保持上电状态(bit3) | SWTEN处于逻辑1(软件定时器) | ADC模式选择为0
! }/ `/ W7 h( |" T. Y - tx_cfg[i][1] = 0x00 ; //不使用欠压比较功能. m7 @) m% U' ]
- tx_cfg[i][2] = 0x00 ; //不使用过压比较功能
0 H6 N: {- R9 ?- W - tx_cfg[i][3] = 0x00 ;" |' A& x. }; \ x j
- tx_cfg[i][4] = 0x00 ; //不使用电池放电功能
4 w2 j! [9 I- x' w/ b# P- L - tx_cfg[i][5] = 0x00 ; //放电超时时间4 ]: f" ^2 H6 C, v
- }
S2 A1 y/ \4 ?5 t5 U& h: J - }
复制代码
' O1 l& F- ]+ p1 E+ _. n( t5 ^2 O8 j- ]
这里只使用了最基本的电压采集,其他的功能都没有用。 上面的代码里面有一个宏 :TOTAL_IC。 这个宏是用来定义一共有几片LTC6804-1的,比如我这次使用了2片,那么它的值就是2. 上面的寄存器设置,可以参考手册: 比如需要追加一些别的功能,便可以根据手册的寄存器进行设置,比如设置报警,设置均衡,设置其他的功能。 以上初始化部分就完成了,或者说移植就完成了,然后便不必对代码文件进行任何修改就可以直接使用,接下来是采集部分: 我是把采集放在main中进行。 - /* 唤醒6804 */
6 _' l) W( K; I5 G2 r0 c+ |9 I - wakeup_sleep();5 p- m3 m, P4 M; z/ ~7 k3 u
- /* 启动电压采集 */5 w: m9 r: i$ B- W. i0 W
- LTC6804_adcv();- m& R! ~# l/ V k, z) y
- delay_ms(50);2 t! I8 Z3 Q: o' ~) K1 n* j4 g9 [
- /* 读取电压 */
# W+ w, D5 b: F3 _ - res = LTC6804_rdcv(0, TOTAL_IC, vol_buff);
复制代码 ) U1 d$ N% R4 _
以上便可以采集出电压了。 ) w' j! S0 O6 T2 P$ v+ n6 @% M
※如果发现几个级联起来的6804,有些片子可以运行正常通信,有些又不可以运行甚至无法通信,在排除硬件的原因以后,可以查看一下这个地方:wakeup_sleep(),试着把唤醒时间设置的长一些。
+ G: }' z( y( `% a, q, m2 I! [5 K6 x最后:可以看出来,精度还是不错的~
3 Z) M2 |1 u3 y2 u6 S |