⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gas_mon.c

📁 DS2438 one wire (ow) battery monitor code for renesas M16c... (-:cool:-)
💻 C
📖 第 1 页 / 共 3 页
字号:
//_____________________________________________________________________________
//_____________________________________________________________________________
//  gas_mon
//_____________________________________________________________________________
//_____________________________________________________________________________

//_____________________________________________________________________________
//  DS2438 battery monitor IC one-wire bus communications
// 
//  If there is no gascell present, or there is any other type of open circuit 
//  in the gascell circuit, this will make the battery monitor produce random results 
//  including nonsense temperature measurements.
//
//  DS2438 SRAM/EEPROM Memory function commands
//  You can't read and write directly to the SRAM/EEPROM memory map.  
//  You can only directly read and alter the "shadow" or "scratch" page
//  registers.
//  However, the two high level commands gas_mon_readRegister(page, byte) and 
//  gas_mon_writeRegister(page, byte, data) overcome this limitation by carrying
//  out all the low level scratch pad copying automatically.
//
//  Exception: The data in the scratchpad of the status and threshold 
//             register will determine the operation of the device.
//
//
//  Writing to the SRAM/EEPROM memory map:-
//  To modify a memory location you have to "write" to the approproate scratch 
//  page and then "copy" that into SRAM/EEPROM.
//  
//  Reading from the SRAM/EEPROM memory map:-  
//  To read a memory location you have to "recall" that page to the appropriate 
//  scratch page and then "read" that scratch page.
//
//  Do not add reset() at the end of any functions, it seems to mess things up.
//
//  to do:  update to read full serial number and checksum from monitor which 
//          is longer than a word and would provide a guaranteed unique ID.
//  to do:  include checksum as part of serial number.  Then ID_NOT_FOUND can be any
//          any number with a false checksum.
//  to do:  add functions for enabling/disabling various features
//  to do:  CRC checks
//  to do:  think about removing the disabling on interrupts
//  to do:  Add hardware timer check into       while (!readBit()); 
//          statements do if communication gets stuck, it does not stop the
//          whole application from responding.
// 
//_____________________________________________________________________________


// Includes
//_________

#include ".\gas_mon.h"  // Prototypes and defines for this file

// Private Variables
//___________________
static float full_gas_mon_ICA; // the value of the ICA in mA when full

// Private Prototypes
//___________________
 static int resetDQ(void);
 static void write1(void);
 static void write0(void);
 static BOOL readBit(void);
 static void writebyte(byte Data);
 static byte readbyte(void);
 static void gas_mon_set_threshold(byte th2, byte th1);
 static float gas_mon_readVoltage(void);
 static void gas_mon_changeToVad(void);
 static void gas_mon_changeToVdd(void);

// Functions
//__________

//=============================================================================
//  public
//=============================================================================

//_____________________________________________________________________________
//  gas_mon_power_down
//_____________________________________________________________________________
// place gascell monitor in power down mode
//_____________________________________________________________________________
void gas_mon_power_down(void)
{
    DQ_PULL_UP = NO_PULL_UP; // pullup for DQ line

    DQ = LOW;
    DQ_DIRECTION = OUTPUT;

    DQ_EXTRA_PULL_UP = LOW;
    DQ_EXTRA_PULL_UP_DIRECTION = OUTPUT;
}
    

//_____________________________________________________________________________
//  gas_mon_power_up
//_____________________________________________________________________________
// Enable gascell monitor DQ line which powers it up and starts it operating
//_____________________________________________________________________________
void gas_mon_power_up(void)
{
    DQ_PULL_UP = PULL_UP; // pullup for DQ line
    DQ_DIRECTION = INPUT;
    DQ_EXTRA_PULL_UP_DIRECTION = INPUT;  // used for the pull up only
                                         // remains input only. does not get switched 
                                         //   high or low 
}

//_____________________________________________________________________________
//  gas_mon_initialise
//_____________________________________________________________________________
// Sets up the gascell monitor so that all it resources are available for use 
// Loads ICA with max value.
//_____________________________________________________________________________
void gas_mon_initialise(void)
{
    asm("fclr I");  // disable interrupts 

    gas_mon_power_up();

    // configure status/config register
    //---------------------------------
    resetDQ(); // modify to check for presence pulse was received OK
    writebyte(SKIP_ROM); // Skip ROM
    writebyte(WRITE_SP); // write to a scratch pad
    writebyte(0x00); // scratch pad 0
    writebyte(0x0F); // change byte 0 (status/config register) so that
                    // all resources are turned on
    resetDQ(); // only wanted to write that first byte, so reset now instead
                // of writing next 7 bytes
    writebyte(SKIP_ROM); // Skip ROM
    writebyte(COPY_SP); // copy scratch pad to NV memory
    writebyte(0x00); // scratch pad 0
    while (!readBit()); // the monitor outputs all zeros on the DQ line
                            // until the NV writing is complete, at which
                            // time it outputs all ones.

    gas_mon_set_threshold((byte)1, (byte)0);  // ignore current accumulation up to +/- 4 LSB
    gas_mon_load_ICA(); // Loads ICA with max value
     

    asm("fset I");  // enable interrupts    

}


//_____________________________________________________________________________
//  gas_mon_setFullICA
//_____________________________________________________________________________
// Determine the value of a full ICA in mA.  This is partially determined by the
// exact value of the gascell sense resistor.
// DOES NOT actually change the value of the ICA, only tells you what the value of
// it is when full.
//
// set_cal must be called after gascell monitor comms to establish ID and calibration
// values.  However, part of the natural Initialisation would be gas_mon_setFullICA() which uses
// calibration information from set_cal.  This is a catch 22, so to get around this
// the monitor is initialised without gas_mon_setFullICA(), then set_cal happens
// and then gas_mon_setFullICA() can be called. 
//_____________________________________________________________________________
void gas_mon_setFullICA(void)
{
    full_gas_mon_ICA = ((float)0xFF/(2048.0f*getGascellSenseResistor())*1000.0f); // convert to mAhr
}



//_____________________________________________________________________________
//  gas_mon_getFullICA
//_____________________________________________________________________________
// Get the value of a full ICA in mA.
//_____________________________________________________________________________
float gas_mon_getFullICA(void)
{
    return full_gas_mon_ICA;
}


//_____________________________________________________________________________
//  gas_mon_calibrate_current
//_____________________________________________________________________________
// Calibrates current ADC for zero offset by adjusting offset register.
// Comments are based on page 6 of the data sheet, but the data sheet does not
// tell the whole story.
// 
// The following process can be used to calibrate the current ADC:
//    1.   Ensure no current flows through the sense resistor by turning the load 
//         and charge current off.  
//    2.   Wait until the voltage on the sense resistor decays to zero if using 
//         a low pass filer.
//    3.   Disable the current ADC by setting the IAD bit in the 
//         Status/Configuration Register to 0
//    4.   Write all zeroes to the Offset Register.
//    5.   Enable the current ADC by setting the IAD bit in the 
//         Status/Configuration Register to 1
//    6.   Wait for the first current conversion to give a valid result in the 
//         current register.  60ms should be more than enough.
//    7.   Read the Current Register value.
//    8.   Disable the current ADC by setting the IAD bit in the 
//         Status/Configuration Register to 0
//    9.   Change the sign of the previously-read Current Register value by 
//         performing the two抯 complement
//         and write the result to the Offset Register.
//    10.  Enable the current ADC by setting the IAD bit in the 
//         Status/Configuration Register to 1
//    11.  Wait for the first current conversion to give a valid result 
//         in the current register before reading it.  60ms should be more than enough.
//_____________________________________________________________________________
void gas_mon_calibrate_current(void)
{
    word_union raw_current_register;
    bool previous_gascell_state;

    asm("fclr I");  // disable interrupts 
    
    // Ensure it is awake
    // ------------------
    gas_mon_power_up(); 

    previous_gascell_state = HR_Gascell_Switch_IN; // save gascell switch state so it can be restored

    // Turn load off
    //-------------
    gascell_off();                // turn off gascell and wait a few ms for V on Rsense to zero
                                  // shouldn't really be part of gas monitor code but better 
                                  // than forgetting to turn it off before calling this function.
    // wait for voltage across sense resistor to fall to zero
    delay_ms(80);  // wait for voltage on Rsense to decay to zero  - filter effect
    
    // Write all zeroes to the offset register to remove old offset
    //-------------------------------------------------------------
    // When writing to the Offset Register, current measurement MUST be disabled 
    // (IAD bit set to 0).
    gas_mon_clearIAD();   
    gas_mon_writeRegister(1, 5, 0); 
    gas_mon_writeRegister(1, 6, 0); 

    // Read the Current Register value
    //----------------------------------
    // IAD bit set to 1 so current can be measured
    gas_mon_setIAD(); // must be set here so current can be measured

    // wait for current A/D to do first automatic current measurement cycle
    delay_ms(80);  
    raw_current_register.asword = gas_mon_readCurrentRegisterword();

    // Negate offset error
    //----------------------
    // Change the sign of the previously-read Current Register value by performing the two抯 complement
    raw_current_register.asSignedInt = - raw_current_register.asSignedInt;


    // Update offset Register
    //-----------------------
    // offset register is in a different format to current register
    raw_current_register.asword = raw_current_register.asword << 3;  

    // When writing to the Offset Register, current measurement MUST be disabled 
    // (IAD bit set to 0).
    gas_mon_clearIAD();
    
    // write the result to the Offset Register.
    gas_mon_writeRegister(1, 5, raw_current_register.asbytes.lowbyte);  // write LSB
    gas_mon_writeRegister(1, 6, raw_current_register.asbytes.highbyte);  // write MSB


    // IAD bit set to 1 so current can be measured
    gas_mon_setIAD(); 
    delay_ms(80);  // wait for current A/D to do first automatic current measurement cycle
                   // after resetting the IAD bit to one.  Waiting here means 
                   // that the current register is valid for reading immediately at 
                   // the return of this function.

    // restore gascell switch state
    HR_Gascell_Switch_IN = (previous_gascell_state)? (bool)ON:OFF;

    asm("fset I");  // enable interrupts    

}


//_____________________________________________________________________________
//  gas_mon_load_ICA
//_____________________________________________________________________________
// Loads ICA with max value
// Note:  The ICA counts DOWN when the gascell is discharging
// Writes over elapsed time registers
// to do: avoid writing over elapsed time registers.
//_____________________________________________________________________________
void gas_mon_load_ICA(void)
{
    asm("fclr I");  // disable interrupts 


    resetDQ(); // modify to check for presence pulse was received OK
    writebyte(SKIP_ROM); // Skip ROM
    writebyte(WRITE_SP); // write to a scratch pad
    writebyte(0x01); // scratch pad 1

    writebyte(0x00); // write over elapsed time registers
    writebyte(0x00);
    writebyte(0x00);
    writebyte(0x00);
    writebyte(0xFF); // write max value into ICA for it to decrement when
                     // gascell is discharging

    resetDQ();  // only wanted to write those first bytes, so reset now instead
                // of writing next bytes
    writebyte(SKIP_ROM); // Skip ROM
    writebyte(COPY_SP); // copy scratch pad to NV memory
    writebyte(0x01); // scratch pad 1
    while (!readBit()); // the monitor outputs all zeros on the DQ line
                            // until the NV writing is complete, at which
                            // time it outputs all ones.
     

    asm("fset I");  // enable interrupts    

}


//_____________________________________________________________________________
// gas_mon_readROMserial
//_____________________________________________________________________________
// read serial number in ROM .
// The SN is in ROM, not in the SRAM/EEPROM memory map.
//_____________________________________________________________________________
word gas_mon_readROMserial(void)
{
    word_union monitor_id = 0;   
    // to do:  the id is 6 bytes, this only reads 2 of them at the moment
 
    asm("fclr I");  // disable interrupts 

    resetDQ(); // modify to check for presence pulse was received OK

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -