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

📄 adc_elmb.c

📁 AVR平台下的CanOpen协议桟源码包括应用
💻 C
📖 第 1 页 / 共 5 页
字号:
     2. Read the ADC Gain Register
     3. Multiply the Gain Register value with the gain factor
     4. Write the resulting value to the Gain Register */

#ifdef __VARS_IN_EEPROM__
  AdcConfig    = eeprom_read( EE_ADCCONFIG );
  AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
  adc_range_id = ((AdcConfig & CS23_CSR_GAIN_MASK) >> CS23_CSR_GAIN_SHIFT);

  for( phys_chan_no=0; phys_chan_no<4; ++phys_chan_no )
    {
      /* Read the gain factor from EEPROM and apply (only if available) */
      if( adc_get_calib_const( RANGE_ID[adc_range_id],
			       phys_chan_no, calibcnst_b, send_emergency ) )
	{
	  UINT32 *ptr;
	  BYTE   *bptr;

	  /* Read Gain Register (that's just 3 bytes) */
	  ADC_SELECT();
	  cs5523_read_reg( CS23_CMD_GAIN_REG, phys_chan_no, gainreg_b );
	  ADC_DESELECT();
	  gainreg_b[3] = 0x00;

	  /* Convert Gain Register value to float */
	  ptr       = (UINT32 *) gainreg_b;
	  gainreg_l = *ptr;
	  gainreg_f = (float) gainreg_l;

	  /* or (less efficient, but portable):
	  gainreg_l = (((UINT32) gainreg_b[0]) |
		       (((UINT32) gainreg_b[1]) << 8) |
		       (((UINT32) gainreg_b[2]) << 16));
	  gainreg_f = (float) gainreg_l;
	  */

	  /* Convert the gain factor value to float */
	  ptr         = (UINT32 *) calibcnst_b;
	  calibcnst_l = *ptr;
	  calibcnst_f = ((float) calibcnst_l) / 1000000.0;

	  /* or (less efficient, but portable):
	  calibcnst_l = (((UINT32) gain_b[0]) |
	                 (((UINT32) gain_b[1]) << 8) |
			 (((UINT32) gain_b[2]) << 16));
	  calibcnst_f = ((float) gain_l) / 1000000.0;
	  */

	  /* Make sure it has a sensible value */
	  if( calibcnst_f >= 4.0 || calibcnst_f <= 0.1 ) calibcnst_f = 1.0; 

	  /* Multiply Gain Register value with the gain factor */
	  gainreg_f = (gainreg_f * calibcnst_f) + 0.5;

	  /* Convert Gain Register float value back to an array of bytes */
	  gainreg_l = (UINT32) gainreg_f;
	  bptr      = (BYTE *) &gainreg_l;

	  /* Write the corrected Gain Register value */
	  ADC_SELECT();
	  cs5523_write_reg( CS23_CMD_GAIN_REG, phys_chan_no, bptr );
	  ADC_DESELECT();
	}
    }
  return result;
}

/* ------------------------------------------------------------------------ */

static BOOL adc_self_calibrate( BOOL send_emergency )
{
  BOOL result;

  /* Not allowed when ADC conversion in progress... */
  if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;

  /* =================================== */
  /* OFFSET calibration */

  ADC_SELECT();

  /* Do a Self Offset calibration... */
#ifdef __VARS_IN_EEPROM__
  AdcConfig    = eeprom_read( EE_ADCCONFIG );
  AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
  result = cs5523_calibrate( CS23_CMD_OFFSET_SELF_CALIB, AdcConfig );

  ADC_DESELECT();

  if( result == FALSE )
    {
      /* Calibration error... */

      AdcError |= ADC_ERR_CALIBRATION;

      if( send_emergency )
	{
	  /* CANopen Error Code 0x5000: device hardware */
	  can_write_emergency( 0x00, 0x50, EMG_ADC_OFFSET_CALIB, 0, 0, 0,
			       ERRREG_MANUFACTURER );
	}

      adc_serial_init();

      return FALSE;
    }

  /* =================================== */
  /* GAIN calibration */

  ADC_SELECT();

  /* ...followed by a Self Gain calibration */
#ifdef __VARS_IN_EEPROM__
  AdcConfig    = eeprom_read( EE_ADCCONFIG );
  AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
  result = cs5523_calibrate( CS23_CMD_GAIN_SELF_CALIB, AdcConfig );

  ADC_DESELECT();

  if( result == FALSE )
    {
      /* Calibration error... */

      AdcError |= ADC_ERR_CALIBRATION;

      if( send_emergency )
	{
	  /* CANopen Error Code 0x5000: device hardware */
	  can_write_emergency( 0x00, 0x50, EMG_ADC_GAIN_CALIB, 0, 0, 0,
			       ERRREG_MANUFACTURER );
	}

      adc_serial_init();

      return FALSE;
    }

  /* =================================== */

  return TRUE;
}

/* ------------------------------------------------------------------------ */

static void adc_init_confreg( void )
{
  /* Remember to select the ADC (if necessary)
     before calling this routine (and to deselect afterwards) */
  BYTE adc_conf_reg[3];

  adc_conf_reg[0] = ADC_CNFREG_0;
  adc_conf_reg[1] = ADC_CNFREG_1;
  adc_conf_reg[2] = AdcConfReg_2;

  /* Write to the Config Register */
  cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, adc_conf_reg );
}

/* ------------------------------------------------------------------------ */

static void adc_init_csr( void )
{
  /* Remember to select the ADC (if necessary)
     before calling this routine (and to deselect afterwards) */

  /* Channel Setup Register data
     (4 registers, each for 2 Logical Channels,
      each consisting of 2 bytes) */
  BYTE csr_data[4*2*2];
  BYTE i;

  /* Settings for Logical Channels 1 to 4 in CSR #1 and #2
     (only LC #1 will be used) */
  for( i=0; i<4; ++i )
    {
      csr_data[2*i]   = 0; /* LC low byte */
      csr_data[2*i+1] = 0; /* LC high byte */
    }

  /* Settings for Logical Channels 5 to 8 in CSR #3 and #4: these Logical
     Channels are used only to set A1A0 pins to be latched !
     (to select one of the four 16-chan input banks;
     so do that at the maximum possible conversion rate) */
  for( i=0; i<4; ++i )
    {
      BYTE a1a0;

      a1a0 = i;

      /* LC low byte */
      //csr_data[2*(4+i)] = CS23_WORDRATE_101 << CS23_CSR_WORDRATE_SHIFT;
      /* ###Don't change the wordrate to do this, because the ADC displays
	 some erratic behaviour / noisy conversions when changing wordrates */
      csr_data[2*(4+i)]   = AdcConfig;

      /* LC high byte */
      csr_data[2*(4+i)+1] = a1a0 << CS23_CSR_A1A0_SHIFT;
    }

  /* Load initial settings in the CSRs: LC 5 to 8 are used
     to select the four 16-chan input banks (via A1A0 latch outputs) */
  cs5523_write_csr( 4, csr_data );
}

/* ------------------------------------------------------------------------ */

void adc_serial_init( void )
{
  ADC_SELECT();
  cs5523_serial_init();
  ADC_DESELECT();
}

/* ------------------------------------------------------------------------ */

void adc_pdo_scan_start( BOOL volts, BOOL force_readout )
{
  /* Start scanning only if scanning not already in progress, unless
     'force_readout' is true AND ADC-readout-on-change is enabled,
     then stop the current scan cycle and initiate a new scan cycle
     forcing read-out of the ADC channels */

#ifdef __VARS_IN_EEPROM__
  AdcChans = eeprom_read( EE_ADCCHANS );
#endif

  /* Refresh Data-Direction Register settings */
#ifdef __MOTHERBOARD1__
  /* Old Motherboard configuration */
  ADC_INIT_DDR_V1();
#endif
#ifndef __ALL_MOTHERBOARDS__
  /* Motherboard V3 configuration */
  ADC_INIT_DDR_V3();
#endif

#ifdef __VARS_IN_EEPROM__
  AdcReadoutOnChange = eeprom_read( EE_ADCREADOUTONCHANGE );
#endif /* __VARS_IN_EEPROM__ */

  if( AdcReadoutOnChange && force_readout )
    {
      /* Stop any ongoing scan cycle */
      adc_pdo_scan_stop();

      /* Force read-out of all channels at next scan cycle */
      AdcForcedReadout = TRUE;
    }

  if( (AdcScanInProgress & TRUE) == FALSE && AdcChans > 0 )
    {
#ifdef __VARS_IN_EEPROM__
      AdcCalibBeforeScan = eeprom_read( EE_ADCCALIBBEFORESCAN );
#endif /* __VARS_IN_EEPROM__ */

      if( AdcCalibBeforeScan )
	{
	  /* Perform a reset/calibration procedure before each scan... */
	  adc_reset_and_calibrate( TRUE );
	}
      else
	{
#ifdef __VARS_IN_EEPROM__
	  AdcConfReg_2 = eeprom_read( EE_ADCCONFREG2 );
	  AdcConfig    = eeprom_read( EE_ADCCONFIG );
	  AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
	  ADC_SELECT();

	  /* Refresh the Configuration Register before each scan... */
	  adc_init_confreg();

	  /* Refresh the Channel Setup Registers before each scan... */
	  adc_init_csr();

	  ADC_DESELECT();
	}

      /* Send ADC readout in the form of ADC-counts or voltages ? */
      if( (volts & TRUE) == TRUE )
	{
	  /* Readout in volts, if possible */
	  if( adc_calibrated() )
	    {
	      AdcScanVolts = TRUE;
	    }
	  else
	    {
	      AdcScanVolts = FALSE; /* Do a scan nevertheless?.. */
	      //return;             /* ..or not ? */
	    }
	}
      else
	{
	  /* Readout in ADC counts */
	  AdcScanVolts = FALSE;
	}

      /* Start an ADC-channels-to-PDOs scan cycle */
      AdcChanNo = 0;
      AdcScanInProgress = adc_scan_next();
    }
}

/* ------------------------------------------------------------------------ */

void adc_pdo_scan_stop( void )
{
  /* Abort a channel scan cycle in-progress:
     wait for a possibly ongoing ADC conversion... */

  if( (AdcScanInProgress & TRUE) == TRUE )
    {
      if( (AdcConvInProgress & TRUE) == TRUE )
	{
#define __ADC_CLEAN_STOP__
#ifdef __ADC_CLEAN_STOP__
	  /* Wait for the conversion to finish and read out the ADC data */

	  ADC_SELECT();

	  /* Wait for SDO to go low flagging the conversion is done,
	     but use a timeout (ca. 600 ms, sufficient at 1.88 Hz wordrate) */
	  //if( cs5523_await_sdo_low( 60 ) )
	  if( cs5523_await_sdo_low( 120 ) ) // Make that 1200 ms...
	    {
	      /* Generate 8 SCLKs to clear the SDO flag */
	      cs5523_write_byte( 0 );

	      /* Read 24 bits (3 bytes) of conversion data */
	      cs5523_read_byte();
	      cs5523_read_byte();
	      cs5523_read_byte();
	    }

	  ADC_DESELECT();

#else /* !__ADC_CLEAN_STOP__ */

	  /* Is this sufficient ? --> NO!!
	     (ADC config appears to have changed afterwards) */
	  adc_serial_init();

#endif /* !__ADC_CLEAN_STOP__ */
	}
    }

  /* Initialize variables for scanning operations */
  AdcChanNo         = 0;
  AdcScanInProgress = FALSE;
  AdcConvInProgress = FALSE;
  AdcLatchBeingSet  = FALSE;
  AdcLatchSet       = FALSE;
}

/* ------------------------------------------------------------------------ */

void adc_pdo_scan( void )
{
  /* Handle an on-going ADC channel scan, or start up
     a channel scan cycle when ADC-readout-on-change is enabled */

  if( (AdcScanInProgress & TRUE) == TRUE )
    {
      /* Read out next ADC channel */
      AdcScanInProgress = adc_scan_next();
    }
  else
    {
#ifdef __VARS_IN_EEPROM__
      /* Refresh some global variables before every scan */
      AdcReadoutOnChange = eeprom_read( EE_ADCREADOUTONCHANGE );
#endif /* __VARS_IN_EEPROM__ */

      /* Do we have to scan continuously ? (if yes, then start
	 a new scan immediately when the previous one finished) */
      if( AdcReadoutOnChange )
	{
#ifdef __VARS_IN_EEPROM__
	  /* Refresh some global variables before every scan */
	  AdcDeltaScanEnabled  = eeprom_read( EE_ADCDELTASCANENABLED );
	  AdcWindowScanEnabled = eeprom_read( EE_ADCWINDOWSCANENABLED );
	  AdcWindowCounterInit = eeprom_read( EE_ADCWINDOWCOUNTERINIT );
#endif /* __VARS_IN_EEPROM__ */

	  if( AdcDeltaScanEnabled || AdcWindowScanEnabled )
	    {
	      /* Yes, but this call to 'adc_pdo_scan_start()' is not a forced
		 readout, so the parameter is set to FALSE, unless... */
	      //adc_pdo_scan_start( TRUE, FALSE );

	      /* ...this is the first scan cycle after the node
		 has been set to 'Operational' state, in which case
		 the reference ADC counts ('last-sent') need to be initialized
		 ('AdcInitRefCount' in that case has been set elsewhere to
		  'TRUE') and read-out of the ADC-channels is forced */
	      if( (AdcInitRefCount & TRUE) == TRUE )
		adc_pdo_scan_start( TRUE, TRUE );
	      else
		adc_pdo_scan_start( TRUE, FALSE );
	    }
	}
    }
}

/* ------------------------------------------------------------------------ */

static BOOL adc_scan_next( void )
{
  BYTE pdo_data[8];

  if( (AdcConvInProgress & TRUE) == TRUE )
    {
      ADC_SELECT();

      /* ! Make sure no delay is necessary here
	   (due to optocouplers in the interface) !
	   ###Not necessary because we don't deselect the ADC during a scan */
      //timer2_delay_mus( AdcOptoDelay );

      /* Conversion in progress: check if done */
      if( ADC_SDO_LOW() )
	{
	  /* SDO went low --> conversion ready ! */

	  if( (AdcLatchBeingSet & TRUE) == TRUE )
	    {
	      /* This conversion only served to set the A1A0 latches...,
		 but we *have* to read out the ADC data */

	      /* Now latch this data */
	      ADC_CLEAR_MUX_LATCH();

	      /* Need to insert a delay... */
	      //timer2_delay_mus( CS23_ELMB_SIGNAL_RISETIME );
	      timer2_delay_mus( AdcOptoDelay );

	      ADC_SET_MUX_LATCH();

	      /* Generate 8 SCLKs to clear the SDO flag */
	      cs5523_write_byte( 0 );

	      /* Read 24 bits (3 bytes) of (dummy) ADC conversion data */
	      cs5523_read_byte();
	      cs5523_read_byte();
	      cs5523_read_byte();

	      ADC_DESELECT();

	      AdcLatchBeingSet  = FALSE;
	      AdcLatchSet       = TRUE;

	      AdcConvInProgress = FALSE;
	    }
	  else
	    {
	      /* This conversion results in real data
		 that we're interested in... */
	      BYTE   adc_stat;
	      BOOL   send_pdo;
	      UINT16 adc_count;

⌨️ 快捷键说明

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