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

📄 adc_elmb.c

📁 AVR平台下的CanOpen协议桟源码包括应用
💻 C
📖 第 1 页 / 共 5 页
字号:
      //for( i=0; i<4; ++i, ++ptr ) microvolts[i] = *ptr;
    }
  else
    {
      /* Bipolar measurement: use signed numbers ! */
      INT16 *padc_cnt;
      INT32 adc_volts_l;
      float adc_volts_f;
      INT32 *ptr;

      /* Interpret the UINT16 as an INT16 */
      padc_cnt    = (INT16 *) &adc_count;

      /* Do the ADC-count to microVolts calculation */
      adc_volts_f = (((float)(*padc_cnt)) / 32767.0) * fullscale;

      /* Cast to an INT32 */
      adc_volts_l = (INT32) adc_volts_f;

      /* Copy the INT32 into the BYTE array */
      ptr = (INT32 *) microvolts;
      *ptr = adc_volts_l;
    }
}

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

BYTE adc_status( BYTE *status )
{
  *status = AdcError;
  return 1; /* Return number of bytes */
}

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

BOOL adc_get_config( BYTE subindex, BYTE *nbytes, BYTE *par )
{
  *nbytes = 1;

#ifdef __VARS_IN_EEPROM__
  AdcChans     = eeprom_read( EE_ADCCHANS );
  AdcConfig    = eeprom_read( EE_ADCCONFIG );
  AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif

  switch( subindex )
    {
    case 0:
      /* Number of entries */
      par[0] = 21;
      break;

    case 1:
      par[0] = AdcChans;
      break;

    case 2:
      par[0] = ((AdcConfig & CS23_CSR_WORDRATE_MASK) >>
	        CS23_CSR_WORDRATE_SHIFT);
      break;

    case 3:
      par[0] = ((AdcConfig & CS23_CSR_GAIN_MASK) >>
		CS23_CSR_GAIN_SHIFT);
      break;

    case 4:
      par[0] = (AdcConfig & CS23_CSR_UNIPOLAR);
      break;

    case 6:
      {
	if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;

	ADC_SELECT();

	/* Read the Configuration Register */
	cs5523_read_reg( CS23_CMD_CONFIG_REG, 0, par );

	ADC_DESELECT();

	*nbytes = 4;
      }
      break;

    case 7:
    case 8:
    case 9:
    case 10:
    case 11:
    case 12:
    case 13:
    case 14:
      {
	BYTE reg, phys_chan_no;

	if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;

	if( subindex & 1 ) reg = CS23_CMD_OFFSET_REG;
	else reg = CS23_CMD_GAIN_REG;

	phys_chan_no = (subindex - 7) >> 1;

	ADC_SELECT();

	/* Read Register */
	cs5523_read_reg( reg, phys_chan_no, par );

	ADC_DESELECT();

	*nbytes = 4;
      }
      break;

    case 15:
    case 16:
    case 17:
    case 18:
      {
	BYTE csr_data[4*2*2], *csr, i;

	if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;

	ADC_SELECT();

	/* Read current CSR content */
	cs5523_read_csr( csr_data );

	ADC_DESELECT();

	subindex -= 15;

	/* Extract required CSR data */
	csr = &csr_data[subindex << 2];
	for( i=0; i<4; ++i ) par[i] = csr[i];

	*nbytes = 4;
      }
      break;

    case 19:
      {
	BYTE wordrate_id;
	wordrate_id = ((AdcConfig & CS23_CSR_WORDRATE_MASK) >>
		       CS23_CSR_WORDRATE_SHIFT);
	par[0] = HZ_WORDRATE[wordrate_id];
      }
      break;

    case 20:
      {
	BYTE   adc_range_id;
	float  v_range_f;
	UINT32 v_range_l;
	UINT32 *ptr;

	adc_range_id = ((AdcConfig & CS23_CSR_GAIN_MASK) >>
			CS23_CSR_GAIN_SHIFT);

	/* Beware: the conversion from float to UINT32 does NOT
	   work on V_FULLSCALE (which is stored flash) directly !
	   (a compiler feature?) */
	v_range_f = V_FULLSCALE[adc_range_id];
	v_range_l = (UINT32) v_range_f;

	/* Copy result to the output BYTE array */
	ptr       = (UINT32 *) par;
	*ptr      = v_range_l;

	// The following also works:
	//BYTE *ptr, i;
	//ptr = (BYTE *) &v_range_l;
	//for( i=0; i<4; ++i, ++ptr ) par[i] = *ptr;

	*nbytes = 4;
      }
      break;

    case 21:
      par[0] = AdcOptoDelay;
      break;

    default:
      return FALSE;
    }

  return TRUE;
}

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

BOOL adc_set_config( BYTE subindex, BYTE nbytes, BYTE *par )
{
  /* If 'nbytes' is zero it means the data set size was
     not indicated in the SDO message */

  /* Can't do anything if the ADC is in use... */
  if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;

#ifdef __VARS_IN_EEPROM__
  AdcChans     = eeprom_read( EE_ADCCHANS );
  AdcConfig    = eeprom_read( EE_ADCCONFIG );
  AdcConfReg_2 = eeprom_read( EE_ADCCONFREG2 );
  AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif

  switch( subindex )
    {
    case 1:
      if( nbytes > 1 || par[0] > ADC_MAX_INPUTS ) return FALSE;

      AdcChans = par[0];

      break;

    case 2:
      {
	if( nbytes > 1 || par[0] > CS23_WORDRATE_7 ) return FALSE;

	AdcConfig &= ~CS23_CSR_WORDRATE_MASK;
	AdcConfig |= (par[0] << CS23_CSR_WORDRATE_SHIFT);

	/* Prepare wordrate-dependent setting for ADC Configuration Register */
	if( par[0] == CS23_WORDRATE_61 ||
	    par[0] == CS23_WORDRATE_84 ||
	    par[0] == CS23_WORDRATE_101 )
	  AdcConfReg_2 = ADC_CNFREG_2_CHOP4096;
	else
	  AdcConfReg_2 = ADC_CNFREG_2_CHOP256;

	ADC_SELECT();

	/* Write the updated setting to the Config Register */
	adc_init_confreg();

	ADC_DESELECT();
      }
      break;

    case 3:
      if( nbytes > 1 || par[0] > CS23_GAIN_2V5 ) return FALSE;

      AdcConfig &= ~CS23_CSR_GAIN_MASK;
      AdcConfig |= (par[0] << CS23_CSR_GAIN_SHIFT);

      break;

    case 4:
      if( nbytes > 1 || par[0] > 1 ) return FALSE;

      if( par[0] == 1 )
	AdcConfig |= CS23_CSR_UNIPOLAR;
      else
	AdcConfig &= ~CS23_CSR_UNIPOLAR;

      break;

    case 5:
      {
	BYTE adc_conf_reg[3];

	if( nbytes > 1 || par[0] > 1 ) return FALSE;

	if( par[0] == 1 )
	  adc_conf_reg[1] = ADC_CNFREG_1 | CS23_CNF_POWER_SAVE;
	else
	  adc_conf_reg[1] = ADC_CNFREG_1 & (~CS23_CNF_POWER_SAVE);

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

	ADC_SELECT();

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

	ADC_DESELECT();
      }
      break;

    case 6:
      {
	if( !(nbytes == 4 || nbytes == 0) ) return FALSE;

	ADC_SELECT();

	/* Write the Configuration Register */
	cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, par );

	ADC_DESELECT();
      }
      break;

    case 7:
    case 8:
    case 9:
    case 10:
    case 11:
    case 12:
    case 13:
    case 14:
      {
	BYTE reg, phys_chan_no;

	if( !(nbytes == 4 || nbytes == 0) ) return FALSE;

	if( subindex & 1 ) reg = CS23_CMD_OFFSET_REG;
	else reg = CS23_CMD_GAIN_REG;

	phys_chan_no = (subindex - 7) >> 1;

	ADC_SELECT();

	/* Write Register */
	cs5523_write_reg( reg, phys_chan_no, par );

	ADC_DESELECT();
      }
      break;

    case 15:
    case 16:
    case 17:
    case 18:
      {
	BYTE csr_data[4*2*2], *csr, i;

	if( !(nbytes == 4 || nbytes == 0) ) return FALSE;

	ADC_SELECT();

	/* Read current CSR content */
	cs5523_read_csr( csr_data );

	subindex -= 15;

	/* Adjust CSR content */
	csr = &csr_data[subindex << 2];
	for( i=0; i<4; ++i ) csr[i] = par[i];

	/* Write new CSR content */
	cs5523_write_csr( 4, csr_data );

	ADC_DESELECT();
      }
      break;

    case 21:
      if( nbytes > 1 || par[0] < 10 ) return FALSE;

      AdcOptoDelay = par[0];

      break;

    default:
      return FALSE;
    }

#ifdef __VARS_IN_EEPROM__
  /* Store values in EEPROM, if changed */
  if( eeprom_read( EE_ADCCHANS ) != AdcChans )
    eeprom_write( EE_ADCCHANS, AdcChans );
  if( eeprom_read( EE_ADCCONFIG ) != AdcConfig )
    eeprom_write( EE_ADCCONFIG, AdcConfig );
  if( eeprom_read( EE_ADCCONFREG2 ) != AdcConfReg_2 )
    eeprom_write( EE_ADCCONFREG2, AdcConfReg_2 );
  if( eeprom_read( EE_ADCOPTODELAY ) != AdcOptoDelay )
    eeprom_write( EE_ADCOPTODELAY, AdcOptoDelay );
#endif /* __VARS_IN_EEPROM__ */

  if( subindex == 3 || subindex == 4 )
    /* Recalibrate using the new setting of Input Range or uni/bipolar! */
    adc_reset_and_calibrate( TRUE );

  return TRUE;
}

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

BOOL adc_reset_and_calibrate( BYTE send_emergency )
{
  BOOL result;

  /* Initialise (hardware) error status */
  AdcError &= ~ADC_ERR_IN_HARDWARE;

  /* Perform calibration only if reset succeeded */
  if( (result = adc_reset( send_emergency )) == TRUE )
    result = adc_set_calib_regs( send_emergency );

  return result;
}

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

BOOL adc_reset( BOOL send_emergency )
{
  BOOL reset_result;
  BYTE err_id;

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

#ifdef __VARS_IN_EEPROM__
  AdcConfReg_2 = eeprom_read( EE_ADCCONFREG2 );
  AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif

  /* Select ADC */
  ADC_SELECT();

  /* Initialize the ADC's serial port interface */
  cs5523_serial_init();

  /* Reset the ADC */
  reset_result = cs5523_reset( &err_id );

  /* Initialize Channel Setup Registers */
  adc_init_csr();

  /* Initialize Configuration Register:
     Chop Frequency:  256 Hz (at freq <= 30 Hz), 4096 Hz (other freq)
     		      (recommended by Crystal, CS5523 datasheet pg 14)
     Depth Pointer : 001 (read/write 1 CSR at a time) */
  adc_init_confreg();

  /* Deselect ADC */
  ADC_DESELECT();

  if( reset_result == FALSE )
    {
      /* Reset failed */
      AdcError |= ADC_ERR_RESET;

      /* Generate emergency message ? */
      if( send_emergency )
	{
	  /* CANopen Error Code 0x5000: device hardware */
	  can_write_emergency( 0x00, 0x50, EMG_ADC_RESET, 0, err_id, 0,
			       ERRREG_MANUFACTURER );
	}

      return FALSE;
    }
  return TRUE;
}

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

static BOOL adc_set_calib_regs( BOOL send_emergency )
{
  BOOL   result;
  BYTE   adc_range_id;
  BYTE   phys_chan_no;
  BYTE   calibcnst_b[4], gainreg_b[4];
  UINT32 calibcnst_l, gainreg_l;
  float  calibcnst_f, gainreg_f;

  /* First do a 'pure' self-calibration:
     the calibration factors are applied to the resulting gains */
  result = adc_self_calibrate( send_emergency );

  /* Apply calibration parameters (when available !)
     to adjust the value of the Gain Registers:
     for each ADC physical channel (4x):
     1. Read the gain factor from EEPROM

⌨️ 快捷键说明

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