|
LTC6804是一款专门用来做多节电池电池组的监测芯片,最高可监测12节电池,官方误差是低于1.2mv,12 个通道的最快采样速度可以达到290us。 芯片分为两种型号,6804-1和6804-2,区别在于,6804-1采用级联的形式(级联控制),6804-2采用并联形式(分开控制)。 除开硬件连接之外,这两种型号的操作都是大同小异,基本可以视为一样,本文以6804-1为例进行讲解。 原理图和手册中的推荐一样,就不贴出来了,MCU与芯片的通信方式采用四线SPI,这种通信方式很常见,各种MCU的驱动也好找。(看了数据手册,芯片似乎还支持IIC和2线通信,不过我没有用) . ]" v( F3 J2 T+ H I, Z* V4 ]
+ a( x7 f; @3 _, Q 下载下来的代码是C++文件,不能直接在STM32上使用,需要进行一些修改。 首先修改后缀名,改成C文件,然后打开LTC6804.c文件。
& t3 {' U7 O0 m* W1 P' M第一步进行驱动的移植: - void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port
' i' ~8 F" l- P& h; s7 }6 O% \! k. m# W - uint8_t data[] //Array of bytes to be written on the SPI port
. v7 D) m, \; k5 K( v9 ^' q - )
: z# \% H; g& T2 C0 H2 p7 R& { - {2 v1 h9 Y3 U: ~+ d3 E
- uint8_t i;9 H8 `' k' ^( X' g! y6 I) c8 ?# j/ c8 _
1 r! H N$ ?5 A- for(i = 0; i < len; i++)
7 x$ \, g9 c. K8 u$ O6 }; g - {
# s5 _' d- Y! ~ - SPI2_Send_byte((int8_t)data[i]);
6 V. W6 D- A* i3 X- K% ^ - }
8 S" f& ]% {" M( \* W H - }
复制代码- void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port! x9 E/ n; o2 B9 B' e5 G
- uint8_t tx_len, //length of the tx data arry3 x7 q9 h2 }# q
- uint8_t *rx_data,//Input: array that will store the data read by the SPI port$ c5 E" \3 W& [; X, F9 x$ [
- uint8_t rx_len //Option: number of bytes to be read from the SPI port
4 w0 [( `- Z$ M _. t - )4 j0 G; |+ C6 f3 R1 ^
- {0 Z1 T, H: S. \; h* V0 j
- uint8_t i;7 g, a, D, ^; }& G; F+ p' o5 U
1 H* M# `& K/ S6 y: Z& O- for(i = 0; i < tx_len; i++)
( U8 w( e/ @# K" A - {( l, V: D( D" U8 f
- SPI2_Send_byte(tx_Data[i]);
; Z9 ~" ?3 ?1 e _5 y, u3 H - }
& r7 g7 ^0 k$ M* e3 t - ! {2 v" a" _9 v$ |
- for(i = 0; i < rx_len; i++)" P, k3 t& t& P
- {5 e8 |& O7 F8 c& ~
- rx_data[i] = (uint8_t)SPI2_Receive_byte();4 o$ u% L4 A% h' S4 p( e. G4 j+ p
- }
" j Q1 |5 ^% ^+ V, {3 ]# {& O- M7 `6 w - 7 ?. d7 o0 [1 u" d6 z! @8 \) R
- }
复制代码 . D( U T0 @! u# k8 W7 c$ f
只需要把自己的SPI驱动替换上去就可以了。 + x% ~1 G% P6 l6 h( @( h! o9 M% `1 L
- void wakeup_idle()9 V, u* c2 ^$ _+ ?3 V
- {
5 w4 o* a& J! h" u) ?0 f3 t- d - output_low(LTC6804_CS);% I) ?/ i9 d$ w5 ^! C( n: D% a5 w
- delayMicroseconds(2); //Guarantees the isoSPI will be in ready mode4 ]+ }9 I: R G6 V
- output_high(LTC6804_CS);
. j, r: { [. m' | - }
复制代码
9 e m1 Z: `' \3 P$ V6 @% ^自己把这个函数中间的部分实现,或者替换成自己的函数: - void wakeup_idle(void). ~5 y* a+ k. r9 M9 g
- {
% z2 m3 E; H: G { - output_low(LTC6804_CS);
) a2 n, C) ?3 M7 T$ V; G - delay_ms(4); //Guarantees the isoSPI will be in ready mode
- a5 ?6 I0 L: }1 Q6 ] - output_high(LTC6804_CS);- z8 p- F. D5 T8 U
- }
复制代码 ' ^$ k. H; O) ]' \2 K* W. v
下面是原版的初始化函数: - void LTC6804_initialize()) |9 w- u4 C) n; Q" R0 h* Z" |
- {! O }( S$ |* |5 Y% F7 i6 X
- quikeval_SPI_connect();% `! @, f, J4 N
- spi_enable(SPI_CLOCK_DIV16); // This will set the Linduino to have a 1MHz Clock r& O1 t5 ^7 {: ^' ~
- set_adc(MD_NORMAL,DCP_DISABLED,CELL_CH_ALL,AUX_CH_ALL);/ G! E& `3 A; \) Y7 H
- }
复制代码
" K6 L& h6 H7 A4 @6 D我把它根据自己的实际情况修改一下 : - void LTC6804_initialize(void) r$ t) d+ k0 r$ o/ u# w* N r9 }
- {- F! \' q3 j( g( y
- Drive_LTC6804_Spi_Init();//SPI外设初始化/ h7 r1 ]/ @! J' H1 K8 n" b
- init_cfg(); //配置LTC6804的寄存器
, O5 M/ u8 g5 g7 c( O5 U; D" j - set_adc(MD_FILTERED,DCP_DISABLED,CELL_CH_ALL,AUX_CH_GPIO1);//设置转换方式等) Z$ H K9 H0 |
- wakeup_sleep();//唤醒芯片. o% S( Y# V; |3 T
- LTC6804_wrcfg(TOTAL_IC,tx_cfg);//把上面的设置写入芯片. V' q! Z6 K% Y* F* W. R- X4 M
- if (LTC6804_rdcfg(TOTAL_IC,rx_cfg) == -1) //检查一下到底有没有配置成功3 p: p- D$ u" B$ b$ n
- {
0 R# E( ?% H& S6 Y- \/ j2 N6 D$ |+ B0 S# m! R - printf("LTC6804_MODULAR INIT NG!\n\r");2 u" \" ^$ t P+ Q, v
- }
: b0 f1 j( ], L4 B- K1 ]9 ` - else
( P/ h/ a. A3 b, B - {
0 c8 {' E8 [6 [" Y# u8 b; e7 ]5 g - printf("LTC6804_MODULAR INIT OK!\n\r");( x% Z1 @, Q; @9 _3 t3 k- A+ ^
- }
9 z" D) c J0 K1 L( ?8 @3 M2 D/ z- n - / y8 q- r) q1 R1 r- {
- }
复制代码- //手册第49页
: p% O: Q( D/ K9 q1 P+ O - /* 寄存器 8 7 6 5 4 3 2 1 */
! }9 O4 a! x6 A& N8 m9 A ]( A - //CFGR0 RD/WR GPIO5 GPIO4 GPIO3 GPIO2 GPIO1 REFON SWTRD ADCOPT
7 H7 T- S5 B6 s; R: V: R S - //CFGR1 RD/WR VUV[7] VUV[6] VUV[5] VUV[4] VUV[3] VUV[2] VUV[1] VUV[0]" f' w [1 d9 H
- //CFGR2 RD/WR VOV[3] VOV[2] VOV[1] VOV[0] VUV[11] VUV[10] VUV[9] VUV[8]
; `7 V2 M- U7 {! D, I - //CFGR3 RD/WR VOV[11] VOV[10] VOV[9] VOV[8] VOV[7] VOV[6] VOV[5] VOV[4]8 o6 D- Z* M& I$ x5 }8 r
- //CFGR4 RD/WR DCC8 DCC7 DCC6 DCC5 DCC4 DCC3 DCC2 DCC1" X/ N. |' f5 p+ G, R4 V
- //CFGR5 RD/WR DCTO[3] DCTO[2] DCTO[1] DCTO[0] DCC12 DCC11 DCC10 DCC9
+ z9 ^; ?- t t/ D; y! d) i% S - void init_cfg(void)
$ b- B* \9 c/ S2 l" ~3 f - {9 C/ |0 d( I0 X3 z
- int i;
2 K" d8 _% `1 z% Z2 {
7 H, U- {3 \) I& ]3 \& ~; B- for(i = 0; i<TOTAL_IC;i++)
$ S- J0 s- t$ O3 L* g - {
( e/ p n Z0 c' F+ J+ N% H - tx_cfg[i][0] = 0xFE ; //GPIO引脚下拉电路关断(bit8~bit4) | 基准保持上电状态(bit3) | SWTEN处于逻辑1(软件定时器) | ADC模式选择为0# M: |/ S( }: ^
- tx_cfg[i][1] = 0x00 ; //不使用欠压比较功能! ~; k2 X! I! X: P
- tx_cfg[i][2] = 0x00 ; //不使用过压比较功能
/ r4 e8 j3 R4 C4 ~) H - tx_cfg[i][3] = 0x00 ;
8 s: A1 p; x5 k5 p' r& M2 ?4 {: F - tx_cfg[i][4] = 0x00 ; //不使用电池放电功能8 [$ ^5 U: `# @( P1 _; a
- tx_cfg[i][5] = 0x00 ; //放电超时时间' J: Y+ b/ M, |% c" S: ?
- }" S: x+ s8 A/ z# }8 p
- }
复制代码 , E- M7 Y) w7 @" b' G
$ U3 B! J( r7 O$ e: `& ?
这里只使用了最基本的电压采集,其他的功能都没有用。 上面的代码里面有一个宏 :TOTAL_IC。 这个宏是用来定义一共有几片LTC6804-1的,比如我这次使用了2片,那么它的值就是2. 上面的寄存器设置,可以参考手册: 比如需要追加一些别的功能,便可以根据手册的寄存器进行设置,比如设置报警,设置均衡,设置其他的功能。 以上初始化部分就完成了,或者说移植就完成了,然后便不必对代码文件进行任何修改就可以直接使用,接下来是采集部分: 我是把采集放在main中进行。 - /* 唤醒6804 */" _, T" V$ [! s: {* i
- wakeup_sleep();
" x6 y9 A4 {9 G( Y; q4 g - /* 启动电压采集 */
- y) Q3 M% Z. o' d& y( H0 V - LTC6804_adcv();
2 t; u# b( e8 x$ t$ ] - delay_ms(50);
8 W7 M8 }. ~6 n$ X. o1 d/ _ - /* 读取电压 */
. N2 {, U& i7 G4 k2 k" M - res = LTC6804_rdcv(0, TOTAL_IC, vol_buff);
复制代码
# q6 G* S/ N# ^: n. R- G( @( z 以上便可以采集出电压了。 / F3 _0 E( M w5 r t5 Z
※如果发现几个级联起来的6804,有些片子可以运行正常通信,有些又不可以运行甚至无法通信,在排除硬件的原因以后,可以查看一下这个地方:wakeup_sleep(),试着把唤醒时间设置的长一些。 * Z0 M* P5 O$ h' f
最后:可以看出来,精度还是不错的~ 1 D9 B7 U+ Y& ~
|