LTC6802是一款完整的电池监视 IC,它内置一个 12 位 ADC、一个精准电压基准、一个高电压输入多工器和一个串行接口。每个 LTC6802-2 能够在总输入电压高达 60V 的情况下测量 12 个串接电池的电压。所有 12 个输入通道上的电压测量都能在 13ms 的时间之内完成。可以把多个 LTC6802-2 器件串联起来,以监视长串串接电池中每节电池的电压。每个 LTC6802-2 具有一个可单独寻址的串行接口,因而允许把多达 16 个 LTC6802-2 器件连接至一个控制处理器并同时运作。LTC6802采用一个三线或者四线的SPI的接口与MCU进行通讯,程序代码如下
- //本程序主要完成单体电池电压采集,电池组均衡、保护,SOC计算以及与外部设备的通讯等功能
- //-----------------------------------------------------------------------------
- // Includes(包含头文件)
- //-----------------------------------------------------------------------------
- #include <compiler_defs.h>
- #include <C8051F500_defs.h> // SFR declarations
- #include <stdio.h>
- #include <math.h>
- //-----------------------------------------------------------------------------
- // Global Constants(全局常量定义)
- //-----------------------------------------------------------------------------
- #define SYSCLK 24000000 // 系统时钟
- #define INT_DEC 50 // 电流采样数据累加计数值
- #define ANALOG_INPUTS 15 // 采集数据的数组维数
- #define SPI_CLOCK 500000 // SPI最大时钟
- #define SPI_WRITE 0x01 // 写配置寄存器
- #define SPI_READ 0x02 // 读配置寄存器
- #define RDCV 0x04 // 读电压寄存器
- #define SPI_READ_BUFFER 0x20 // 从控制器向主控制器发送一些列字节
- #define ERROR_OCCURRED 0x40 // 从控制器告诉主控制器发生错误的指示符
- #define CFGR0 0x19 // 初始化LTC6802参数
- #define CFGR1 0x00 // 初始化LTC6802参数
- #define CFGR2 0x00 // 初始化LTC6802参数
- #define CFGR3 0xF0 // 初始化LTC6802参数
- #define CFGR4 0x00 // 初始化LTC6802参数
- #define CFGR5 0xFF // 初始化LTC6802参数
- #define STCVAD 0x10 // 初始化LTC6802参数,电压开始转换
- #define STTMPAD 0x30 // 初始化LTC6802参数,温度开始转换
- #define RDTMP 0x08 // 读取LTC6802存储的温度寄存器命令
- #define PLADC 0x40 // 向LTC6802写入查询ADC转换状态命令
- //-----------------------------------------------------------------------------
- // Pin Declarations(引脚申明)
- //-----------------------------------------------------------------------------
- sbit SW1 = P1^5; // SW1 ='0' means switch pressed
- sbit SW2 = P1^6; // SW2 ='0' means switch pressed
- sbit Poll_IF=P1^1;
- //-----------------------------------------------------------------------------
- // Global Variables(全局变量定义)
- //-----------------------------------------------------------------------------
- unsigned int idata RESULT[ANALOG_INPUTS-5]; // 采集所得的数据的数组
- unsigned long idata Data_Current; // 采集的电流值
- unsigned char idata IF = 0; // AD采样一个周期结束的标志
- float idata PWM_Dutyratio; // PWM输出占空比
- unsigned char SPI_Array[ANALOG_INPUTS-9]={0x19,0x00,0x00,0xF0,0x00,0xFF}; // 采集所得的数据的数组
- U8 Command = 0x00; // 命令传输字节
- U8 SPI_Data_Array[ANALOG_INPUTS+20] = {0}; // 从LTC6802读取的数据
- U8 SPI_Data_Temp[ANALOG_INPUTS] = {0}; // 从LTC6802读取的数据
- U32 SPI_Data_Current; // 电流采集值
- U16 SPI_Data[ANALOG_INPUTS-5] = {0}; // 单体电压采样数组
- U8 data_convert=0; // 数据处理的中间变量
- //-----------------------------------------------------------------------------
- // Global Function Prototypes (全局功能函数定义)
- //-----------------------------------------------------------------------------
- //...初始化功能函数...//
- void PORT_Init (void); // 端口初始化
- void OSCILLATOR_Init (void); // 时钟初始化
- void PCA0_Init (void); // PCA计数器初始化
- void SPI0_Init (void); // SPI0通讯初始化
- void ADC0_Init(void); // ADC0数据采集初始化
- void LTC6802_Init (void); // LTC6802初始化
- void Init_Device (void); // 设备初始化
- //...采集功能函数...//
- void AD_Data_acquisition (void); // 电池单体电压,温度采集程序
- void SPI_AD (void); // 从LTC6802-1读取采集数据
- void SPI_Byte_Write (char Command); // 向LTC6802-1写字节命令
- void SPI_Array_Read (void); // 从LTC6802-1读取数据
- void AD_Current (void); // 采集总电流
- void Poll_AD (void); // 查询AD转换是否完成
- void AD_Data_process (void); // 对采集的数据进行处理
- //...保护功能函数...//
- void Protection_function (void); // 保护功能函数
- void Charge_switch_OFF (void); // 过充时断开充电开关函数
- void Charge_switch_ON (void); // 未过充时闭合充电开关函数
- void Discharge_switch_OFF (void); // 过放时断开放电开关函数
- void Discharge_switch_ON (void); // 未过放时闭合放电开关函数
- //...均衡智能控制函数...//
- void Electricity_Balance (void); // 均衡控制算法
- void Blance_PWM(void); // PWM输出
- void PORT_Rest(void); // 端口复位函数
- //-----------------------------------------------------------------------------
- // main() Routine (主功能函数)
- //-----------------------------------------------------------------------------
- void main (void)
- {
- PCA0MD = 0x00; // Disable the Watchdog Timer
- Init_Device (); // 硬件设备初始化
- EA = 1; // 全局开中断
- while(1)
- {
- AD_Data_acquisition (); // 数据采集
- AD_Data_process(); // 数据处理
- }
- }
- //-----------------------------------------------------------------------------
- // Init_Device (设备初始化)
- //-----------------------------------------------------------------------------
- void Init_Device (void)
- {
- PCA0_Init ();
- PORT_Init ();
- OSCILLATOR_Init ();
- SPI0_Init ();
- ADC0_Init ();
- }
- //-----------------------------------------------------------------------------
- // PCA0_Init (PCA计数器初始化)
- //-----------------------------------------------------------------------------
- void PCA0_Init (void)
- {
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = ACTIVE_PAGE;
- PCA0MD = 0x00; // Disable the Watchdog Timer
- SFRPAGE = SFRPAGE_save;
- }
- //-----------------------------------------------------------------------------
- // PORT_Init (端口初始化)
- //-----------------------------------------------------------------------------
- void PORT_Init (void)
- {
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = CONFIG_PAGE;
- P0MDIN = 0xF0;
- P0MDOUT = 0x40; // P0.6 (CAN0 TX) is push-pull,P0.7 (CAN0 RX) is open-drain
- P0SKIP = 0x3F; // Skip P0.0 (VREF),P0.2,P0.3
- P1MDIN = 0xEF; // P1.4被配置为模拟输入
- P1MDOUT = 0xED; // P1.0,P1.2,P1.3 is push-pull,P1.1 is open-drain
- P1SKIP = 0x10; // Skip P1.4 (电流检测端口)
- P1 = 0x7F; // 设置高电平输出
-
- P2MDIN |= 0xFF;
- P2MDOUT |= 0xFF; // P2.0,P2.1,P2.2,P2.3,P2.4,P2.5,P2.6,P2.7 is push-pull
- P2SKIP = 0x00;
- P2 = 0x80; // 设置高电平输出
- P3MDIN |= 0xFF;
- P3MDOUT |= 0xFF; // P2.0,P2.1,P2.2,P2.3,P2.4,P2.5,P2.6,P2.7 is push-pull
- P3SKIP = 0x00;
- P3 &= 0x00; // 设置高电平输出
- XBR0 = 0x06; // Enable CAN0和SPI0
- XBR2 = 0x40; // Enable crossbar and weak pull-ups
- SFRPAGE = SFRPAGE_save;
- }
- //-----------------------------------------------------------------------------
- // OSCILLATOR_Init (时钟初始化)
- //-----------------------------------------------------------------------------
- void OSCILLATOR_Init (void)
- {
- int i = 0;
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = CONFIG_PAGE;
- P0 |= 0x0C;
- OSCXCN = 0x67;
- for (i = 0; i < 3000; i++); // Wait 1ms for external oscillator initialization
- while ((OSCXCN & 0x80) == 0);
- CLKMUL = 0x01;
- CLKSEL = 0x01;
- OSCICN = 0x07;
- SFRPAGE = ACTIVE_PAGE;
- }
- //-----------------------------------------------------------------------------
- // SPI0_Init (SPI初始化)
- //-----------------------------------------------------------------------------
- void SPI0_Init()
- {
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = ACTIVE_PAGE;
- SPI0CFG = 0x73; // Enable the SPI as a Master,CKPHA = '1', CKPOL = '1'
- SPI0CN = 0x0D; // 4-wire Single Master, SPI enabled
- SPI0CKR = (SYSCLK / (2 * SPI_CLOCK)) - 1;
- ESPI0 = 1; // Enable SPI interrupts
- SFRPAGE = SFRPAGE_save;
- }
- //-----------------------------------------------------------------------------
- // ADC0_Init (主CPU AD数据采集初始化)
- //-----------------------------------------------------------------------------
- void ADC0_Init (void)
- {
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = ACTIVE_PAGE;
- ADC0CF |= 0x01; // Set GAINEN = 1
- ADC0H = 0x04; // Load the ADC0GNH address
- ADC0L = 0x6C; // Load the upper byte of 0x6CA to
- // ADC0GNH
- ADC0H = 0x07; // Load the ADC0GNL address
- ADC0L = 0xA0; // Load the lower nibble of 0x6CA to
- // ADC0GNL
- ADC0H = 0x08; // Load the ADC0GNA address
- ADC0L = 0x01; // Set the GAINADD bit
- ADC0CF &= ~0x01; // Set GAINEN = 0
- ADC0CN = 0x00; // ADC0 disabled, normal tracking,
- // 向AD0BUSY写1启动ADC0
- REF0CN = 0x32; // Enable on-chip VREF and buffer
- // Set voltage reference to 2.048V
- ADC0MX = 0x0C; // Set ADC input to P1.4
- ADC0CF = ((SYSCLK / 3000000) - 1) << 3; // Set SAR clock to 3MHz
- EIE1 |= 0x04; // Enable ADC0 conversion complete int.
- AD0EN = 1; // Enable ADC0
- SFRPAGE = SFRPAGE_save;
- }
- //-----------------------------------------------------------------------------
- // LTC6802_Init (LTC6802初始化)
- //-----------------------------------------------------------------------------
- void LTC6802_Init (void)
- {
- int array_m;
- char array_i;
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = ACTIVE_PAGE;
- NSSMD0=0; // 片选置低
- SPIF = 0;
- Command = SPI_WRITE; // LTC6802写寄存器WRCFG配置
- SPI0DAT = Command;
- while (TXBMT != 1) // Wait until the command is moved into
- { // the XMIT buffer
- }
- for(array_i=0;array_i<6;array_i++)
- {
-
- SPI0DAT = SPI_Array[array_i];
- while (TXBMT != 1) // Wait until the data is moved into
- { // the XMIT buffer
- }
- SPIF=0;
- for(array_m=0;array_m<500;array_m++);
- }
- NSSMD0=1; // 片选置高
- SFRPAGE = SFRPAGE_save;
- }
- //-----------------------------------------------------------------------------
- // AD_Data_acquisition (单体电池电压、温度等数据采集程序)
- //-----------------------------------------------------------------------------
- void AD_Data_acquisition (void)
- {
- int AD_i;
- U8 array_index = 0;
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = ACTIVE_PAGE; // Set for SPI
- AD_Current (); // 采集总电流
- //电压转换//
- LTC6802_Init ();
- Command = STCVAD;
- SPI_Byte_Write (Command); // 向LTC6802写入控制命令
- for(AD_i=0;AD_i<3000;AD_i++);
- while(Poll_IF==0) // 查询ADC转换是否完成
- {
- Poll_AD ();
- }
- SPI_Array_Read (); // 读取LTC6802电压
- Poll_IF=0; // 复位标志位
- SFRPAGE = SFRPAGE_save;
- }
- //-----------------------------------------------------------------------------
- // SPI_Byte_Write (向LTC6802写命令)
- //-----------------------------------------------------------------------------
- void SPI_Byte_Write (char Command)
- {
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = ACTIVE_PAGE;
- NSSMD0=0; // 片选置低
- SPIF = 0;
- SPI0DAT = Command;
- while (SPIF!=1);
- SPIF=0;
- NSSMD0=1;
- SFRPAGE = SFRPAGE_save;
- }
- //-----------------------------------------------------------------------------
- // SPI_Array_Read (向LTC6802写命令)
- //-----------------------------------------------------------------------------
- void SPI_Array_Read (void)
- {
- int mm;
- U8 array_index = 0;
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = ACTIVE_PAGE;
- NSSMD0=0; // 片选置低
- SPIF = 0;
- Command = RDCV; // 向LTC6802写入读取电压寄存器配置
- SPI0DAT = Command;
- while (TXBMT != 1) // Wait until the command is moved into
- { // the XMIT buffer
- }
- while (SPIF!=1);
- SPIF=0;
- for(array_index = 0;array_index <(ANALOG_INPUTS-6);array_index++)
- {
- Command = 0x00; // 向LTC6802写入读取电压寄存器配置
- SPI0DAT = Command;
- while (TXBMT != 1) // Wait until the command is moved into
- { // the XMIT buffer
- }
- while (SPIF!=1);
- SPIF=0;
- for(mm=0;mm<3000;mm++);
- SPI_Data_Array[array_index] = SPI0DAT;
- SPIF=0;
- }
- SPIF=0;
- NSSMD0=1; // 片选置高
- SFRPAGE = SFRPAGE_save;
- }
- //-----------------------------------------------------------------------------
- // AD_Current (采集总的电流)
- //-----------------------------------------------------------------------------
- void AD_Current (void)
- {
- char s;
- static U32 accumulator = 0;
- for(s=0;s<100;s++) // 数据累加10次
- {
- AD0BUSY=1; // 启动ADC0
- while((ADC0CN&0x20)!=0x20); // 查询是否完成一次数据转换
- EA=0;
- accumulator += ADC0; // 累加计数
- EA=1;
- AD0INT = 0; // 复位中断
- AD0BUSY=0;
- }
- SPI_Data_Current=(accumulator/100);
- accumulator = 0;
- }
- //-----------------------------------------------------------------------------
- // Poll_AD (查询ADC是否完成)
- //-----------------------------------------------------------------------------
- void Poll_AD (void)
- {
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = ACTIVE_PAGE;
- NSSMD0=0; // 片选置低
- SPIF = 0;
- Command = PLADC; // 向LTC6802写寄存器查询命令
- SPI0DAT = Command;
- while (!SPIF); // Wait until the SPI is free, in case it's already busy
- SPIF = 0;
- NSSMD0=1;
- SFRPAGE = SFRPAGE_save;
- }
- //-----------------------------------------------------------------------------
- // AD_Data_process (对采集数据进行处理)
- //-----------------------------------------------------------------------------
- void AD_Data_process (void)
- {
- char data_i=1;
- char data_j=0;
- char data_k=0;
- U8 SFRPAGE_save = SFRPAGE;
- SFRPAGE = ACTIVE_PAGE;
- while(data_i<=13)
- {
- data_convert=SPI_Data_Array[data_i]; // 将存在双数据的字节SPI_Data_Array[data_i]放入中间变量
- data_convert=(data_convert<<4); // 左移4位
- SPI_Data[data_j]=(((U16)data_convert)<<4); // 将数据放入16位变量中,然后左移4位
- SPI_Data[data_j]=(SPI_Data[data_j]+((U16)SPI_Data_Array[data_i-1])); // 相加得到一节单体电池的电压值(16位)
- data_convert=0;
- data_convert=SPI_Data_Array[data_i]; // 将存在双数据的字节SPI_Data_Array[data_i]放入中间变量
- data_convert=(data_convert>>4); // 右移4位
- SPI_Data[data_j+1]=(((U16)(SPI_Data_Array[data_i+1]))<<4); // 将数据放入16位变量中,然后左移8位
- SPI_Data[data_j+1]=(SPI_Data[data_j+1]+((U16)data_convert)); // 相加得到一节单体电池的电压值(16位)
- data_convert=0;
- data_i=(data_i+3);
- data_j=(data_j+2);
- }
- data_i=1; // 复位
- data_j=0;
- for(data_k=0;data_k<6;data_k++) // 采样值转换计算
- {
- RESULT[data_k]=(SPI_Data[data_k]*3/2); // 转换LTC6802的电压采样数据
- SPI_Data[data_k]=0;
- }
- Data_Current=(SPI_Data_Current*2048/4095); // 电流采样值转换
- SFRPAGE = SFRPAGE_save;
- }
-
|