|
LTC6804是一款专门用来做多节电池电池组的监测芯片,最高可监测12节电池,官方误差是低于1.2mv,12 个通道的最快采样速度可以达到290us。 芯片分为两种型号,6804-1和6804-2,区别在于,6804-1采用级联的形式(级联控制),6804-2采用并联形式(分开控制)。 除开硬件连接之外,这两种型号的操作都是大同小异,基本可以视为一样,本文以6804-1为例进行讲解。 原理图和手册中的推荐一样,就不贴出来了,MCU与芯片的通信方式采用四线SPI,这种通信方式很常见,各种MCU的驱动也好找。(看了数据手册,芯片似乎还支持IIC和2线通信,不过我没有用) % f" ?+ e8 Z8 ~) G
. F9 _, V6 u4 Y( z( f% q% e
下载下来的代码是C++文件,不能直接在STM32上使用,需要进行一些修改。 首先修改后缀名,改成C文件,然后打开LTC6804.c文件。 . U7 M3 h4 Z' Z7 r$ C
第一步进行驱动的移植: - void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port( ^9 |1 E6 {! `" h& G% Q
- uint8_t data[] //Array of bytes to be written on the SPI port
1 x P2 _" h0 y( Y - )
8 ~$ O; a* k1 N& G/ [ - {
3 \) n- ~3 y& X1 C% k0 N& K" _. K5 B - uint8_t i;3 @: J1 Y x0 P7 k9 D Q
- ; |# C; G# W y# }+ n) k1 w
- for(i = 0; i < len; i++)8 h& f W) s! |! {4 Y' L* q& w
- {
6 Z- y* J6 K/ B; | - SPI2_Send_byte((int8_t)data[i]);
* N3 ?& e# X$ }$ i - }
% o1 B! i1 a5 W8 k - }
复制代码- void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port& M# r7 t$ ^$ C9 ~9 p B7 E. s
- uint8_t tx_len, //length of the tx data arry$ Z& Z( Z8 {" z, p3 i1 Y3 N- q
- uint8_t *rx_data,//Input: array that will store the data read by the SPI port) v8 J( N- Y6 _/ ]3 i8 x$ }- T
- uint8_t rx_len //Option: number of bytes to be read from the SPI port* z/ z& w. `+ d( r; `
- )
- j. \5 i) u0 C3 t& ~: {/ C - {
( D, K& ?5 m+ f: S& T/ D$ r: n" }) `! Z - uint8_t i;& r( L! `: ~* c# k0 Q# a
- 5 Z9 a7 @& q# o5 o2 h( y8 {
- for(i = 0; i < tx_len; i++)
5 ?$ u; K0 P' n - {
* y5 T9 U) X4 r% h/ b. K) N - SPI2_Send_byte(tx_Data[i]);' l4 F& ]8 f8 O1 ~( p
- }
% I! r `; @% { R
' t! X" L8 t8 P3 M* H3 T- for(i = 0; i < rx_len; i++)
" ^8 A: s/ O# Z) ?' E* Q - {' e8 g: v2 J4 K/ n# Q+ x" h+ g: H
- rx_data[i] = (uint8_t)SPI2_Receive_byte();
5 {+ ?1 s6 f% Z7 n - }" _% a$ S1 h) s- H
- " p! b* N, b7 G" D6 s# C! j
- }
复制代码 " Z! l; ~4 l4 D+ e( l. E
只需要把自己的SPI驱动替换上去就可以了。 : Y/ C% h6 F2 q4 F3 r, B
- void wakeup_idle()7 d9 e: l8 W8 w3 S8 j. u
- {$ }* d6 s g- A0 |# ?" H
- output_low(LTC6804_CS);+ [- A3 n: y* d' A5 C. ^5 z
- delayMicroseconds(2); //Guarantees the isoSPI will be in ready mode/ t. C& C7 j$ H7 e% B
- output_high(LTC6804_CS);
5 ?- z8 V$ K# }- s& c - }
复制代码 8 o. @: w' |2 F; w% ?
自己把这个函数中间的部分实现,或者替换成自己的函数: - void wakeup_idle(void)
' Y- E, y5 R% B R. y0 [2 d, x/ y - {. ]+ t( \2 x& f, k3 ^$ J3 e& g1 S
- output_low(LTC6804_CS);$ K8 A" ]3 m' \& C C2 M
- delay_ms(4); //Guarantees the isoSPI will be in ready mode
' }" @. f( z# J, w1 J! B - output_high(LTC6804_CS);2 f1 J2 A4 E- _9 M
- }
复制代码 * J! j2 N4 ]% F6 B' K
下面是原版的初始化函数: - void LTC6804_initialize()
6 k" g2 m+ K' @ - {) Q1 g8 E% J* S3 S& c* z( x+ \
- quikeval_SPI_connect();# x+ a. u8 h6 w, q1 R+ g
- spi_enable(SPI_CLOCK_DIV16); // This will set the Linduino to have a 1MHz Clock
5 O; {* B) v+ X3 L* K3 b. ` - set_adc(MD_NORMAL,DCP_DISABLED,CELL_CH_ALL,AUX_CH_ALL);
5 E$ \' L" ^4 G: A - }
复制代码 # j C) _& k& C9 O2 u6 x) T
我把它根据自己的实际情况修改一下 : - void LTC6804_initialize(void)
2 t+ o4 E1 ~0 k3 e- ?& w - {
+ G+ }: |1 B8 R+ Y2 t3 W - Drive_LTC6804_Spi_Init();//SPI外设初始化* n: P4 E, O7 z9 v1 A' c( @5 @( K8 w
- init_cfg(); //配置LTC6804的寄存器
5 P$ x# Y! B: F! F, {8 Z - set_adc(MD_FILTERED,DCP_DISABLED,CELL_CH_ALL,AUX_CH_GPIO1);//设置转换方式等* D0 ]1 b# f. S. ]* [ ~1 W
- wakeup_sleep();//唤醒芯片
6 E2 l" k$ v# p! U9 M5 Q- t - LTC6804_wrcfg(TOTAL_IC,tx_cfg);//把上面的设置写入芯片6 R2 R/ J! v8 M& |$ S! p. M& @0 b) [
- if (LTC6804_rdcfg(TOTAL_IC,rx_cfg) == -1) //检查一下到底有没有配置成功1 O, }9 I7 q1 L7 M( x
- {
* q t. t0 c0 Z3 F2 x& o( C - printf("LTC6804_MODULAR INIT NG!\n\r");
- {6 R6 a! Q7 Y+ i - }; ~" R0 c" y4 p' L, S
- else5 q; z+ N/ ~7 t2 ]1 w( V2 i
- {3 Z% W3 E! \. S" ^" h
- printf("LTC6804_MODULAR INIT OK!\n\r");
~3 s2 Q; t" R3 A - }2 f- K2 \- R9 B0 t2 O
- 4 E. l7 m0 P9 I2 I3 Y; q
- }
复制代码- //手册第49页6 q" N* t* Q, r; D# U, p" H
- /* 寄存器 8 7 6 5 4 3 2 1 */* C* z" a7 b* ]7 s2 ~# C' W" S
- //CFGR0 RD/WR GPIO5 GPIO4 GPIO3 GPIO2 GPIO1 REFON SWTRD ADCOPT
+ E/ \4 L' B! \7 e! ]" i - //CFGR1 RD/WR VUV[7] VUV[6] VUV[5] VUV[4] VUV[3] VUV[2] VUV[1] VUV[0]+ b! ~% W+ ?( P X8 J
- //CFGR2 RD/WR VOV[3] VOV[2] VOV[1] VOV[0] VUV[11] VUV[10] VUV[9] VUV[8]) ~/ ]2 l) E6 I% D3 D# u& `
- //CFGR3 RD/WR VOV[11] VOV[10] VOV[9] VOV[8] VOV[7] VOV[6] VOV[5] VOV[4]
+ |$ m1 F& `/ d - //CFGR4 RD/WR DCC8 DCC7 DCC6 DCC5 DCC4 DCC3 DCC2 DCC13 W: X a* q+ c8 ~
- //CFGR5 RD/WR DCTO[3] DCTO[2] DCTO[1] DCTO[0] DCC12 DCC11 DCC10 DCC9
7 P/ y3 ]2 D% }& D/ E9 _6 D1 z - void init_cfg(void)
! j, A' Z% Z9 O - {
" m6 b; P6 Y$ `% g+ ^ - int i;
5 T/ B b/ Y3 T1 S5 }( Y& P9 r
2 {* `6 S' J. ^4 I- for(i = 0; i<TOTAL_IC;i++)
& T! C1 e3 }% b' p - {
& R% U8 _* B. k0 g- ^6 ~3 v - tx_cfg[i][0] = 0xFE ; //GPIO引脚下拉电路关断(bit8~bit4) | 基准保持上电状态(bit3) | SWTEN处于逻辑1(软件定时器) | ADC模式选择为0% v0 B: S- s) h
- tx_cfg[i][1] = 0x00 ; //不使用欠压比较功能
! `( A6 K" _0 N+ E - tx_cfg[i][2] = 0x00 ; //不使用过压比较功能
! j& Y2 E/ u: v# Z3 W: ~$ O - tx_cfg[i][3] = 0x00 ;
4 a/ g9 V6 O; n. |2 y& `4 ]1 @ - tx_cfg[i][4] = 0x00 ; //不使用电池放电功能
9 K1 `1 F& P# N8 t5 W6 k- N& p - tx_cfg[i][5] = 0x00 ; //放电超时时间' a8 q q8 \% v1 D6 _
- }
" k9 f5 i+ v7 U* F) I - }
复制代码 $ e, C& t5 g# J0 N/ H# V3 W5 E7 d
% [! @5 V* K1 U- f3 `9 T7 V1 p这里只使用了最基本的电压采集,其他的功能都没有用。 上面的代码里面有一个宏 :TOTAL_IC。 这个宏是用来定义一共有几片LTC6804-1的,比如我这次使用了2片,那么它的值就是2. 上面的寄存器设置,可以参考手册: 比如需要追加一些别的功能,便可以根据手册的寄存器进行设置,比如设置报警,设置均衡,设置其他的功能。 以上初始化部分就完成了,或者说移植就完成了,然后便不必对代码文件进行任何修改就可以直接使用,接下来是采集部分: 我是把采集放在main中进行。 - /* 唤醒6804 */! {" p0 |( [" j# G9 g
- wakeup_sleep();
7 |6 z0 d5 L2 V* y7 J - /* 启动电压采集 */5 m- n; u( B0 O7 W, b
- LTC6804_adcv();
6 m- ~+ d0 f$ a7 W! C - delay_ms(50);
( W* U' P1 l: u6 E$ f - /* 读取电压 */* {6 q* B' \& e7 q4 E& ~
- res = LTC6804_rdcv(0, TOTAL_IC, vol_buff);
复制代码 ) A& t$ s6 N' u5 J0 T3 d4 ]3 _
以上便可以采集出电压了。 6 u x9 _; B7 U0 Q! D
※如果发现几个级联起来的6804,有些片子可以运行正常通信,有些又不可以运行甚至无法通信,在排除硬件的原因以后,可以查看一下这个地方:wakeup_sleep(),试着把唤醒时间设置的长一些。
- n& [- ]- a& v$ I7 _最后:可以看出来,精度还是不错的~ ; D% m, {: M3 ^# [/ W$ x* z7 n* ~
|