[经验知识] 【秀出我的 Linear模拟设计方案】+LTC6802

[复制链接]
 楼主| 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进行通讯,程序代码如下
  1. //本程序主要完成单体电池电压采集,电池组均衡、保护,SOC计算以及与外部设备的通讯等功能
  2. //-----------------------------------------------------------------------------
  3. // Includes(包含头文件)
  4. //-----------------------------------------------------------------------------
  5. #include <compiler_defs.h>
  6. #include <C8051F500_defs.h>                     // SFR declarations
  7. #include <stdio.h>
  8. #include <math.h>
  9. //-----------------------------------------------------------------------------
  10. // Global Constants(全局常量定义)
  11. //-----------------------------------------------------------------------------
  12. #define  SYSCLK             24000000            // 系统时钟

  13. #define  INT_DEC            50                  // 电流采样数据累加计数值
  14. #define  ANALOG_INPUTS      15                  // 采集数据的数组维数

  15. #define  SPI_CLOCK          500000              // SPI最大时钟
  16. #define  SPI_WRITE          0x01                // 写配置寄存器
  17. #define  SPI_READ           0x02                // 读配置寄存器
  18. #define  RDCV               0x04                // 读电压寄存器
  19. #define  SPI_READ_BUFFER    0x20                // 从控制器向主控制器发送一些列字节
  20. #define  ERROR_OCCURRED     0x40                // 从控制器告诉主控制器发生错误的指示符

  21. #define  CFGR0              0x19                // 初始化LTC6802参数
  22. #define  CFGR1              0x00                // 初始化LTC6802参数
  23. #define  CFGR2              0x00                // 初始化LTC6802参数
  24. #define  CFGR3              0xF0                // 初始化LTC6802参数
  25. #define  CFGR4              0x00                // 初始化LTC6802参数
  26. #define  CFGR5              0xFF                // 初始化LTC6802参数
  27. #define  STCVAD             0x10                // 初始化LTC6802参数,电压开始转换
  28. #define  STTMPAD            0x30                // 初始化LTC6802参数,温度开始转换
  29. #define  RDTMP              0x08                // 读取LTC6802存储的温度寄存器命令
  30. #define  PLADC              0x40                // 向LTC6802写入查询ADC转换状态命令

  31. //-----------------------------------------------------------------------------
  32. //  Pin Declarations(引脚申明)
  33. //-----------------------------------------------------------------------------
  34. sbit SW1  =  P1^5;                              // SW1 ='0' means switch pressed
  35. sbit SW2  =  P1^6;                              // SW2 ='0' means switch pressed
  36. sbit Poll_IF=P1^1;
  37. //-----------------------------------------------------------------------------
  38. // Global Variables(全局变量定义)
  39. //-----------------------------------------------------------------------------
  40. unsigned int idata    RESULT[ANALOG_INPUTS-5];  // 采集所得的数据的数组
  41. unsigned long idata   Data_Current;             // 采集的电流值
  42. unsigned char idata   IF   =   0;               // AD采样一个周期结束的标志
  43. float idata  PWM_Dutyratio;                     // PWM输出占空比
  44. unsigned char SPI_Array[ANALOG_INPUTS-9]={0x19,0x00,0x00,0xF0,0x00,0xFF};  // 采集所得的数据的数组

  45. U8 Command = 0x00;                              // 命令传输字节
  46. U8 SPI_Data_Array[ANALOG_INPUTS+20] = {0};         // 从LTC6802读取的数据
  47. U8 SPI_Data_Temp[ANALOG_INPUTS] = {0};         // 从LTC6802读取的数据
  48. U32 SPI_Data_Current;                           // 电流采集值
  49. U16 SPI_Data[ANALOG_INPUTS-5] = {0};            // 单体电压采样数组
  50. U8  data_convert=0;                             // 数据处理的中间变量

  51. //-----------------------------------------------------------------------------
  52. // Global Function Prototypes (全局功能函数定义)
  53. //-----------------------------------------------------------------------------
  54. //...初始化功能函数...//
  55. void PORT_Init (void);                          // 端口初始化
  56. void OSCILLATOR_Init (void);                    // 时钟初始化
  57. void PCA0_Init (void);                          // PCA计数器初始化
  58. void SPI0_Init (void);                          // SPI0通讯初始化
  59. void ADC0_Init(void);                           // ADC0数据采集初始化
  60. void LTC6802_Init (void);                       // LTC6802初始化
  61. void Init_Device (void);                        // 设备初始化
  62. //...采集功能函数...//
  63. void AD_Data_acquisition (void);                // 电池单体电压,温度采集程序
  64. void SPI_AD (void);                             // 从LTC6802-1读取采集数据
  65. void SPI_Byte_Write (char Command);             // 向LTC6802-1写字节命令
  66. void SPI_Array_Read (void);                     // 从LTC6802-1读取数据
  67. void AD_Current (void);                         // 采集总电流
  68. void Poll_AD (void);                            // 查询AD转换是否完成
  69. void AD_Data_process (void);                    // 对采集的数据进行处理
  70. //...保护功能函数...//
  71. void Protection_function (void);                // 保护功能函数
  72. void Charge_switch_OFF (void);                  // 过充时断开充电开关函数
  73. void Charge_switch_ON (void);                   // 未过充时闭合充电开关函数
  74. void Discharge_switch_OFF (void);               // 过放时断开放电开关函数
  75. void Discharge_switch_ON (void);                // 未过放时闭合放电开关函数
  76. //...均衡智能控制函数...//
  77. void Electricity_Balance (void);                // 均衡控制算法
  78. void Blance_PWM(void);                          // PWM输出
  79. void PORT_Rest(void);                           // 端口复位函数
  80. //-----------------------------------------------------------------------------
  81. // main() Routine  (主功能函数)
  82. //-----------------------------------------------------------------------------
  83. void main (void)
  84. {
  85.          PCA0MD  = 0x00;                            // Disable the Watchdog Timer
  86.          Init_Device ();                            // 硬件设备初始化
  87.      EA = 1;                                    // 全局开中断
  88.      while(1)
  89.          {
  90.                    AD_Data_acquisition ();              // 数据采集
  91.            AD_Data_process();                   // 数据处理
  92.          }

  93. }

  94. //-----------------------------------------------------------------------------
  95. // Init_Device     (设备初始化)
  96. //-----------------------------------------------------------------------------
  97. void Init_Device (void)
  98. {
  99.    PCA0_Init ();                     
  100.    PORT_Init ();
  101.    OSCILLATOR_Init ();
  102.    SPI0_Init ();
  103.    ADC0_Init ();
  104. }
  105. //-----------------------------------------------------------------------------
  106. // PCA0_Init       (PCA计数器初始化)
  107. //-----------------------------------------------------------------------------
  108. void PCA0_Init (void)
  109. {
  110.    U8 SFRPAGE_save = SFRPAGE;
  111.    SFRPAGE = ACTIVE_PAGE;
  112.    PCA0MD  = 0x00;                            // Disable the Watchdog Timer
  113.    SFRPAGE = SFRPAGE_save;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // PORT_Init       (端口初始化)
  117. //-----------------------------------------------------------------------------
  118. void PORT_Init (void)
  119. {
  120.    U8 SFRPAGE_save = SFRPAGE;
  121.    SFRPAGE  =   CONFIG_PAGE;

  122.    P0MDIN    =  0xF0;
  123.    P0MDOUT   =  0x40;                          // P0.6 (CAN0 TX) is push-pull,P0.7 (CAN0 RX) is open-drain
  124.    P0SKIP    =  0x3F;                          // Skip P0.0 (VREF),P0.2,P0.3

  125.    P1MDIN    =  0xEF;                          // P1.4被配置为模拟输入
  126.    P1MDOUT   =  0xED;                          // P1.0,P1.2,P1.3 is push-pull,P1.1 is open-drain
  127.    P1SKIP    =  0x10;                          // Skip P1.4 (电流检测端口)
  128.    P1        =  0x7F;                         // 设置高电平输出

  129.    P2MDIN   |=  0xFF;
  130.    P2MDOUT  |=  0xFF;                          // P2.0,P2.1,P2.2,P2.3,P2.4,P2.5,P2.6,P2.7 is push-pull
  131.    P2SKIP    =  0x00;                          
  132.    P2        =  0x80;                          // 设置高电平输出

  133.    P3MDIN   |=  0xFF;
  134.    P3MDOUT  |=  0xFF;                          // P2.0,P2.1,P2.2,P2.3,P2.4,P2.5,P2.6,P2.7 is push-pull
  135.    P3SKIP    =  0x00;                          
  136.    P3       &=  0x00;                          // 设置高电平输出

  137.    XBR0     =   0x06;                          // Enable CAN0和SPI0
  138.    XBR2     =   0x40;                          // Enable crossbar and weak pull-ups

  139.    SFRPAGE = SFRPAGE_save;
  140. }
  141. //-----------------------------------------------------------------------------
  142. // OSCILLATOR_Init  (时钟初始化)
  143. //-----------------------------------------------------------------------------
  144. void OSCILLATOR_Init (void)
  145. {
  146.     int i = 0;
  147.         U8 SFRPAGE_save = SFRPAGE;
  148.     SFRPAGE   = CONFIG_PAGE;
  149.     P0        |= 0x0C;
  150.     OSCXCN    = 0x67;
  151.     for (i = 0; i < 3000; i++);               // Wait 1ms for external oscillator initialization
  152.     while ((OSCXCN & 0x80) == 0);
  153.     CLKMUL    = 0x01;
  154.     CLKSEL    = 0x01;
  155.     OSCICN    = 0x07;
  156.     SFRPAGE   = ACTIVE_PAGE;
  157. }
  158. //-----------------------------------------------------------------------------
  159. // SPI0_Init        (SPI初始化)
  160. //-----------------------------------------------------------------------------  
  161. void SPI0_Init()
  162. {
  163.    U8 SFRPAGE_save = SFRPAGE;
  164.    SFRPAGE = ACTIVE_PAGE;
  165.    SPI0CFG   = 0x73;                         // Enable the SPI as a Master,CKPHA = '1', CKPOL = '1'
  166.    SPI0CN    = 0x0D;                         // 4-wire Single Master, SPI enabled
  167.    SPI0CKR   = (SYSCLK / (2 * SPI_CLOCK)) - 1;
  168.    ESPI0 = 1;                                // Enable SPI interrupts
  169.    SFRPAGE = SFRPAGE_save;
  170. }
  171. //-----------------------------------------------------------------------------
  172. // ADC0_Init        (主CPU AD数据采集初始化)
  173. //-----------------------------------------------------------------------------   
  174. void ADC0_Init (void)
  175. {
  176.    U8 SFRPAGE_save = SFRPAGE;
  177.    SFRPAGE = ACTIVE_PAGE;
  178.    ADC0CF |= 0x01;                          // Set GAINEN = 1
  179.    ADC0H   = 0x04;                          // Load the ADC0GNH address
  180.    ADC0L   = 0x6C;                          // Load the upper byte of 0x6CA to
  181.                                             // ADC0GNH
  182.    ADC0H   = 0x07;                          // Load the ADC0GNL address
  183.    ADC0L   = 0xA0;                          // Load the lower nibble of 0x6CA to
  184.                                             // ADC0GNL
  185.    ADC0H   = 0x08;                          // Load the ADC0GNA address
  186.    ADC0L   = 0x01;                          // Set the GAINADD bit
  187.    ADC0CF &= ~0x01;                         // Set GAINEN = 0

  188.    ADC0CN = 0x00;                           // ADC0 disabled, normal tracking,
  189.                                             // 向AD0BUSY写1启动ADC0
  190.    REF0CN = 0x32;                           // Enable on-chip VREF and buffer
  191.                                             // Set voltage reference to 2.048V

  192.    ADC0MX = 0x0C;                           // Set ADC input to P1.4

  193.    ADC0CF = ((SYSCLK / 3000000) - 1) << 3;  // Set SAR clock to 3MHz

  194.    EIE1 |= 0x04;                            // Enable ADC0 conversion complete int.

  195.    AD0EN = 1;                               // Enable ADC0

  196.    SFRPAGE = SFRPAGE_save;
  197. }
  198. //-----------------------------------------------------------------------------
  199. //  LTC6802_Init     (LTC6802初始化)
  200. //-----------------------------------------------------------------------------
  201. void LTC6802_Init (void)
  202. {
  203.           int array_m;
  204.           char array_i;
  205.           U8 SFRPAGE_save = SFRPAGE;
  206.       SFRPAGE = ACTIVE_PAGE;
  207.           NSSMD0=0;                         // 片选置低
  208.       SPIF = 0;         
  209.       Command = SPI_WRITE;              // LTC6802写寄存器WRCFG配置
  210.       SPI0DAT = Command;
  211.           while (TXBMT != 1)                  // Wait until the command is moved into
  212.       {                                   // the XMIT buffer
  213.       }
  214.       for(array_i=0;array_i<6;array_i++)
  215.           {
  216.                
  217.                SPI0DAT = SPI_Array[array_i];
  218.                    while (TXBMT != 1)               // Wait until the data is moved into
  219.            {                                // the XMIT buffer
  220.            }
  221.            SPIF=0;          
  222.                    for(array_m=0;array_m<500;array_m++);
  223.           }
  224.       NSSMD0=1;                         // 片选置高
  225.           SFRPAGE = SFRPAGE_save;
  226. }        
  227. //-----------------------------------------------------------------------------
  228. // AD_Data_acquisition       (单体电池电压、温度等数据采集程序)
  229. //-----------------------------------------------------------------------------   
  230. void AD_Data_acquisition (void)
  231. {
  232.        int AD_i;
  233.            U8 array_index = 0;
  234.            U8 SFRPAGE_save = SFRPAGE;
  235.            SFRPAGE = ACTIVE_PAGE;           // Set for SPI
  236.            AD_Current ();                   // 采集总电流
  237.            //电压转换//
  238.        LTC6802_Init ();
  239.            Command = STCVAD;
  240.        SPI_Byte_Write (Command);        // 向LTC6802写入控制命令
  241.            for(AD_i=0;AD_i<3000;AD_i++);                                       
  242.        while(Poll_IF==0)                // 查询ADC转换是否完成
  243.            {
  244.                     Poll_AD ();
  245.            }
  246.            SPI_Array_Read ();           // 读取LTC6802电压
  247.            Poll_IF=0;                   // 复位标志位
  248.            SFRPAGE = SFRPAGE_save;      
  249. }
  250. //-----------------------------------------------------------------------------
  251. //  SPI_Byte_Write           (向LTC6802写命令)
  252. //-----------------------------------------------------------------------------
  253. void SPI_Byte_Write (char Command)
  254. {
  255.           U8 SFRPAGE_save = SFRPAGE;
  256.       SFRPAGE = ACTIVE_PAGE;
  257.       NSSMD0=0;                         // 片选置低
  258.       SPIF = 0;
  259.       SPI0DAT = Command;
  260.           while (SPIF!=1);
  261.           SPIF=0;
  262.           NSSMD0=1;
  263.           SFRPAGE = SFRPAGE_save;
  264. }  
  265. //-----------------------------------------------------------------------------
  266. //  SPI_Array_Read            (向LTC6802写命令)
  267. //-----------------------------------------------------------------------------
  268. void SPI_Array_Read (void)
  269. {
  270.           int mm;
  271.           U8 array_index = 0;
  272.       U8 SFRPAGE_save = SFRPAGE;
  273.       SFRPAGE = ACTIVE_PAGE;
  274.           NSSMD0=0;                         // 片选置低
  275.       SPIF = 0;
  276.       Command = RDCV;                   // 向LTC6802写入读取电压寄存器配置
  277.       SPI0DAT = Command;
  278.           while (TXBMT != 1)                  // Wait until the command is moved into
  279.       {                                   // the XMIT buffer
  280.       }
  281.           while (SPIF!=1);
  282.           SPIF=0;
  283.           for(array_index = 0;array_index <(ANALOG_INPUTS-6);array_index++)
  284.           {          
  285.                    Command = 0x00;                     // 向LTC6802写入读取电压寄存器配置
  286.            SPI0DAT = Command;
  287.                while (TXBMT != 1)                  // Wait until the command is moved into
  288.            {                                   // the XMIT buffer
  289.            }
  290.                    while (SPIF!=1);
  291.                SPIF=0;
  292.                    for(mm=0;mm<3000;mm++);
  293.                    SPI_Data_Array[array_index] = SPI0DAT;
  294.                    SPIF=0;          
  295.           }
  296.           SPIF=0;   
  297.       NSSMD0=1;                         // 片选置高
  298.           SFRPAGE = SFRPAGE_save;
  299. }
  300. //-----------------------------------------------------------------------------
  301. //  AD_Current                (采集总的电流)
  302. //-----------------------------------------------------------------------------            
  303. void AD_Current (void)
  304. {
  305.      char s;
  306.          static U32 accumulator = 0;
  307.          for(s=0;s<100;s++)                 // 数据累加10次
  308.          {       
  309.              AD0BUSY=1;                    // 启动ADC0
  310.              while((ADC0CN&0x20)!=0x20);   // 查询是否完成一次数据转换           
  311.                  EA=0;
  312.          accumulator += ADC0;          // 累加计数
  313.                  EA=1;  
  314.                  AD0INT = 0;                   // 复位中断
  315.          AD0BUSY=0;
  316.          }
  317.      SPI_Data_Current=(accumulator/100);
  318.          accumulator = 0;   
  319. }
  320. //-----------------------------------------------------------------------------
  321. //  Poll_AD                 (查询ADC是否完成)
  322. //-----------------------------------------------------------------------------     
  323. void Poll_AD (void)
  324. {
  325.       U8 SFRPAGE_save = SFRPAGE;
  326.       SFRPAGE = ACTIVE_PAGE;
  327.       NSSMD0=0;                         // 片选置低
  328.       SPIF = 0;
  329.       Command = PLADC;                  // 向LTC6802写寄存器查询命令
  330.       SPI0DAT = Command;
  331.           while (!SPIF);                    // Wait until the SPI is free, in case it's already busy
  332.       SPIF = 0;
  333.           NSSMD0=1;
  334.           SFRPAGE = SFRPAGE_save;
  335. }
  336. //-----------------------------------------------------------------------------
  337. //  AD_Data_process           (对采集数据进行处理)
  338. //-----------------------------------------------------------------------------   
  339. void AD_Data_process (void)   
  340. {
  341.          char data_i=1;
  342.          char data_j=0;
  343.      char data_k=0;
  344.      U8 SFRPAGE_save = SFRPAGE;
  345.      SFRPAGE = ACTIVE_PAGE;
  346.          while(data_i<=13)
  347.          {
  348.              data_convert=SPI_Data_Array[data_i];                                       // 将存在双数据的字节SPI_Data_Array[data_i]放入中间变量
  349.          data_convert=(data_convert<<4);                                            // 左移4位
  350.          SPI_Data[data_j]=(((U16)data_convert)<<4);                                 // 将数据放入16位变量中,然后左移4位
  351.          SPI_Data[data_j]=(SPI_Data[data_j]+((U16)SPI_Data_Array[data_i-1]));         // 相加得到一节单体电池的电压值(16位)
  352.          data_convert=0;
  353.                  data_convert=SPI_Data_Array[data_i];                                       // 将存在双数据的字节SPI_Data_Array[data_i]放入中间变量
  354.          data_convert=(data_convert>>4);                                            // 右移4位
  355.          SPI_Data[data_j+1]=(((U16)(SPI_Data_Array[data_i+1]))<<4);                   // 将数据放入16位变量中,然后左移8位
  356.          SPI_Data[data_j+1]=(SPI_Data[data_j+1]+((U16)data_convert));               // 相加得到一节单体电池的电压值(16位)
  357.          data_convert=0;
  358.          data_i=(data_i+3);
  359.          data_j=(data_j+2);
  360.          }
  361.      data_i=1;                                                                      // 复位
  362.          data_j=0;   
  363.      for(data_k=0;data_k<6;data_k++)                                                // 采样值转换计算
  364.          {
  365.                 RESULT[data_k]=(SPI_Data[data_k]*3/2);                                            // 转换LTC6802的电压采样数据
  366.         SPI_Data[data_k]=0;
  367.          }
  368.      Data_Current=(SPI_Data_Current*2048/4095);                                  // 电流采样值转换
  369.          SFRPAGE = SFRPAGE_save;
  370. }



您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

68

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

5

主题

68

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部