打印
[经验知识]

【秀出我的 Linear模拟设计方案】+LTC6802

[复制链接]
1226|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
grace75|  楼主 | 2014-9-15 11:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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;
}



相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

68

帖子

0

粉丝