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

📄 adc_elmb.c

📁 AVR平台下的CanOpen协议桟源码包括应用
💻 C
📖 第 1 页 / 共 5 页
字号:
	      ADC_DESELECT();

	      /* Should only generate a next PDO when the previous one
		 has been sent */
	      if( can_transmitting(C91_TPDO2) )
		{
		  /* A TPDO2 transmission is in progress, so wait... */
		  return TRUE;
		}

	      /* Set to FALSE only if message can be sent... */
	      AdcConvInProgress = FALSE;

	      ADC_SELECT();

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

	      /* Read 24 bits (3 bytes) of ADC conversion data */
	      pdo_data[3] = cs5523_read_byte();
	      pdo_data[2] = cs5523_read_byte();
	      adc_stat    = cs5523_read_byte();

	      ADC_DESELECT();

#ifdef __VARS_IN_EEPROM__
	      AdcConfig = eeprom_read( EE_ADCCONFIG );
#endif
	      /* Replace the status byte with a byte containing
		 the ADC-configuration (wordrate, gain, uni/bipolar)
		 and one bit with an 'or' of the OF and OD bits
		 (here bit 7, the highest bit) */
	      if( adc_stat & CS23_DATA_ERROR )
		pdo_data[1] = AdcConfig | ADC_ERR_CONVERSION;
	      else
		pdo_data[1] = AdcConfig;

	      /* Put the ADC channel number in the message */
	      pdo_data[0] = AdcChanNo;

	      /* The ADC-count as a 16-bit (unsigned) integer */
	      adc_count = (((UINT16) pdo_data[2]) |
			   (((UINT16) pdo_data[3]) << 8));

	      if( AdcReadoutOnChange )
		{
		  /* Do the necessary checks to determine whether
		     the data is to be sent */
		  send_pdo = FALSE;

		  /* Delta-change check */
		  if( AdcDeltaScanEnabled )
		    send_pdo = adc_delta_check( adc_count );

		  /* Upper/lower limit check */
		  if( AdcWindowScanEnabled && send_pdo == FALSE )
		    send_pdo = adc_window_check( adc_count );
		}
	      else
		{
		  send_pdo = TRUE;
		}

	      /* Send data when required */
	      if( send_pdo )
		{
		  if( AdcScanVolts )
		    {
		      BYTE microvolts[4];
		      BYTE i, *ptr;

		      /* Convert the ADC-count to microVolts */
		      adc_convert_to_volts( adc_count, microvolts );

		      /* Copy the resulting value into the output array */
		      ptr = &pdo_data[2];
		      for( i=0; i<4; ++i, ++ptr ) *ptr = microvolts[i];

		      /* Send as a Transmit-PDO3 CAN-message */
		      can_write( C91_TPDO3, C91_TPDO3_LEN, pdo_data );
		    }
		  else
		    {
		      /* Send as a Transmit-PDO2 CAN-message */
		      can_write( C91_TPDO2, C91_TPDO2_LEN, pdo_data );
		    }
		}

	      /* Next time, next channel
		 (SEE-protected version of '++AdcChanNo;') */
	      AdcChanNo = (AdcChanNo & (ADC_MAX_INPUTS-1)) + 1;

#ifdef __VARS_IN_EEPROM__
	      AdcChans = eeprom_read( EE_ADCCHANS );
#endif
	      /* Are we done with the current scan cycle ? */
	      if( AdcChanNo == AdcChans )
		{
		  /* Yes, we're done... */
		  AdcForcedReadout = FALSE;
		  AdcInitRefCount  = FALSE;
		  return FALSE;
		}
	    }
	}
      else
	{
	  /* Conversion in progress...
	     check for possible timeout... */

	  /* ###Do not deselect/select during a conversion: may cause noise */
	  //ADC_DESELECT();

	  if( timer0_timeout(ADC_ELMB) )
	    {
	      /* Conversion timed out ! */
	      AdcError |= ADC_ERR_TIMEOUT;

	      /* CANopen Error Code 0x5000: device hardware */
	      can_write_emergency( 0x00, 0x50, EMG_ADC_CONVERSION, AdcChanNo,
				   0, 0, ERRREG_MANUFACTURER );

	      AdcConvInProgress = FALSE;

	      //adc_serial_init();
	      adc_reset_and_calibrate( TRUE );

	      /* Stop this scan... */
	      return FALSE;
	    }

	  /* Wait some more... */
	  return TRUE;
	}
    }

  ADC_SELECT();

  if( (AdcChanNo & 0x0F) == 0 && (AdcLatchSet & TRUE) == FALSE )
    {
      BYTE bank_no, log_chan;

      bank_no = AdcChanNo/16;

      /* Change of 16-chan inputs bank: select bank,
	 by initiating a (dummy) conversion;
	 LC 5 to 8 contain the proper setting of A1-A0
	 (set during initialization) to accomplish this */

      /* The Logical Channel to use (4, 5, 6 or 7) */
      log_chan = ((4 + bank_no) << CS23_CMD_LOGCHAN_SELECT_SHIFT);

      /* Initiate the conversion */
      cs5523_start_conversion_cmd( CS23_CMD_NORMAL_CONVERSION | log_chan );

      /* When conversion done, don't send data... */
      AdcLatchBeingSet = TRUE;
    }
  else
    {
      BYTE a1a0, cs1cs0;
      BYTE csr_data[1*2*2];

#ifdef __VARS_IN_EEPROM__
      AdcConfig    = eeprom_read( EE_ADCCONFIG );
      AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
      /* Set A1-A0 and physical channel in LC 1 (+2)
	 while maintaining proper wordrate and gain */
      a1a0        = AdcChanNo & 3;
      cs1cs0      = (AdcChanNo>>2) & 3;
      csr_data[0] = (AdcConfig | ((cs1cs0 << CS23_CSR_PHYSCHAN_SEL_LO_SHIFT) &
				  CS23_CSR_PHYSCHAN_SEL_LO_MASK));
      csr_data[1] = ((a1a0 << CS23_CSR_A1A0_SHIFT) |
		     ((cs1cs0 >> CS23_CSR_PHYSCHAN_SEL_HI_SHIFT) &
		      CS23_CSR_PHYSCHAN_SEL_HI_MASK));
      csr_data[2] = 0x00;
      csr_data[3] = 0x00;
      cs5523_write_csr( 1, csr_data );

      /* Start a conversion of LC 1 */
      cs5523_start_conversion_cmd( CS23_CMD_NORMAL_CONVERSION | 0 );

      /* At next 16-chan inputs bank, first do a conversion to set latch */
      AdcLatchSet = FALSE;
    }

  /* ###Do not deselect/select during a conversion: may cause noise */
  //ADC_DESELECT();

  AdcConvInProgress = TRUE;

  /* Set a timeout on the conversion of about 800 ms... */
  //timer0_set_timeout_10ms( ADC_ELMB, 80 );
  timer0_set_timeout_10ms( ADC_ELMB, 120 ); // Make that 1200 ms... */

  return TRUE;
}

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

static BOOL adc_delta_check( UINT16 adc_count )
{
  UINT16 adc_delta, adc_diff;

  /* Initialize reference value if necessary ! */
  if( (AdcInitRefCount & TRUE) == TRUE ) AdcRefCount[AdcChanNo] = adc_count;

  if( (AdcForcedReadout & TRUE) == TRUE )
    {
      /* Send the data */
      return TRUE;
    }

  /* Get the delta-change value for this channel from
     the working copy in EEPROM */
  adc_delta = adc_get_delta_cnt( AdcChanNo );

  /* Don't send the data when the delta is zero */
  if( adc_delta == (UINT16) 0 ) return FALSE;

  if( AdcConfig & CS23_CSR_UNIPOLAR )
    {
      /* Unipolar measurement: use unsigned numbers ! */

      if( adc_count > AdcRefCount[AdcChanNo] )
	adc_diff = adc_count - AdcRefCount[AdcChanNo];
      else
	adc_diff = AdcRefCount[AdcChanNo] - adc_count;
    }
  else
    {
      /* Bipolar measurement: use signed numbers ! */
      INT16 *padc_count, *padc_last_sent;
      padc_count     = (INT16 *) &adc_count;
      padc_last_sent = (INT16 *) &AdcRefCount[AdcChanNo];

      if( *padc_count > *padc_last_sent )
	adc_diff = (UINT16) (*padc_count - *padc_last_sent);
      else
	adc_diff = (UINT16) (*padc_last_sent - *padc_count);
    }

  if( adc_diff >= adc_delta )
    {
      BYTE cntr;
      cntr = AdcDeltaCounter[AdcChanNo];
      ++cntr;

      if( cntr >= AdcWindowCounterInit )
	{
	  AdcDeltaCounter[AdcChanNo] = 0;

	  /* Store this value: new reference ! */
	  AdcRefCount[AdcChanNo] = adc_count;

	  /* Send the data */
	  return TRUE;
	}
      else
	{
	  AdcDeltaCounter[AdcChanNo] = cntr;

	  /* Don't send the data (yet) */
	  return FALSE;
	}
    }
  else
    {
      AdcDeltaCounter[AdcChanNo] = 0;

      /* Don't send the data */
      return FALSE;
    }
}

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

static BOOL adc_window_check( UINT16 adc_count )
{
  UINT16 adc_upper, adc_lower;
  BOOL   outside_window;
  CHAR   cntr;

  if( (AdcForcedReadout & TRUE) == TRUE )
    {
      /* Send the data */
      return TRUE;
    }

  /* Get the upper-limit value for this channel from
     the working copy in EEPROM */
  adc_upper = adc_get_upperlimit_cnt( AdcChanNo );

  /* Get the lower-limit value for this channel from
     the working copy in EEPROM */
  adc_lower = adc_get_lowerlimit_cnt( AdcChanNo );

  if( AdcConfig & CS23_CSR_UNIPOLAR )
    {
      /* Unipolar measurement: use unsigned numbers ! */

      if( adc_lower >= adc_upper ) return FALSE;

      if( adc_count > adc_upper || adc_count < adc_lower )
	outside_window = TRUE;
      else
	outside_window = FALSE;
    }
  else
    {
      /* Bipolar measurement: use signed numbers ! */
      INT16 *padc_count, *padc_upper, *padc_lower;
      padc_count = (INT16 *) &adc_count;
      padc_upper = (INT16 *) &adc_upper;
      padc_lower = (INT16 *) &adc_lower;

      if( *padc_lower >= *padc_upper ) return FALSE;

      if( *padc_count > *padc_upper || *padc_count < *padc_lower )
	outside_window = TRUE;
      else
	outside_window = FALSE;
    }

  cntr = AdcWindowCounter[AdcChanNo];

  /* Some checks to counter SEE
     (don't use counter anymore for inside-window cases) */
  //if( cntr > AdcWindowCounterInit )        cntr = AdcWindowCounterInit;
  if( cntr > 0 )                           cntr = 0;
  if( cntr < -(AdcWindowCounterInit + 1) ) cntr = -(AdcWindowCounterInit + 1);

  /* Negative counter values mean 'currently being outside window',
     positive counter values (and zero) mean 'currently being inside window'
     (which is also the initial value) */
  if( outside_window )
    {
      /*if( (AdcForcedReadout & TRUE) == TRUE )
	{
	  AdcWindowCounter[AdcChanNo] = -1;
	  return TRUE;
	}*/

      /* Already reported ? */
      if( cntr == -1 ) return FALSE;

      /* First time outside window from being inside window ?
	 --> initialise counter for this channel */
      if( cntr >= 0 ) cntr = -(AdcWindowCounterInit + 1);

      ++cntr;
      AdcWindowCounter[AdcChanNo] = cntr;

      /* Value -1 means: outside window and reported */
      if( cntr == -1 )
	{
	  /* Send the data */
	  return TRUE;
	}
    }
  else
    {
      /*if( (AdcForcedReadout & TRUE) == TRUE )
	{
	  AdcWindowCounter[AdcChanNo] = 0;
	  return TRUE;
	}*/

      /* Inside window: already reported ? */
      if( cntr == 0 ) return FALSE;

      /* We are 'inside window' */
      AdcWindowCounter[AdcChanNo] = 0;

      /* First time inside window from being outside window ?
	 (no counter used in this case!)
	 --> report it *only* if 'outside-window' has been reported,
	 --> cntr == -1 */
      if( cntr == -1 )
	{
	  /* Send the data */
	  return TRUE;
	}
    }

  return FALSE;
}

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

#define ADC_STORE_SIZE 8

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

BOOL adc_store_config( void )
{
  BYTE block[ADC_STORE_SIZE];
  BOOL result = TRUE;

  /* Store ADC delta-change parameters */
  if( adc_store_deltas() == FALSE ) result = FALSE;

  /* Store ADC upper-limit parameters */
  if( adc_store_upperlimits() == FALSE ) result = FALSE;

  /* Store ADC lower-limit parameters */
  if( adc_store_lowerlimits() == FALSE ) result = FALSE;

#ifdef __VARS_IN_EEPROM__
  AdcChans             = eeprom_read( EE_ADCCHANS );
  AdcConfig            = eeprom_read( EE_ADCCONFIG );
  AdcCalibBeforeScan   = eeprom_read( EE_ADCCALIBBEFORESCAN );
  AdcReadoutOnChange   = eeprom_read( EE_ADCREADOUTONCHANGE );
  AdcDeltaScanEnabled  = eeprom_read( EE_ADCDELTASCANENABLED );
  AdcWindowScanEnabled = eeprom_read( EE_ADCWINDOWSCANENABLED );
  AdcWindowCounterInit = eeprom_read( EE_ADCWINDOWCOUNTERINIT );
  AdcOptoDelay         = eeprom_read( EE_ADCOPTODELAY );
#endif /* __VARS_IN_EEPROM__ */

  block[0] = AdcChans;
  block[1] = AdcConfig;
  block[2] = AdcCalibBeforeScan;
  block[3] = AdcReadoutOnChange;
  block[4] = AdcDeltaScanEnabled;
  block[5] = AdcWindowScanEnabled;
  block[6] = AdcWindowCounterInit;
  block[7] = AdcOptoDelay;

  if( store_write_block( STORE_ADC, ADC_STORE_SIZE, block ) == FALSE )
    result = FALSE;

  return result;
}

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

static BOOL adc_load_config( void )
{
  BYTE block[ADC_STORE_SIZE];
  BOOL result = TRUE;

  /* Read the configuration from EEPROM, if any
     (errors in reading this datablock are caught and
      reported by functions in store.c...) */
  if( store_read_block( STORE_ADC, ADC_STORE_SIZE, block ) )
    {
      AdcChans             = block[0];
      AdcConfig            = block[1];
      AdcCalibBeforeScan   = block[2];
      AdcReadoutOnChange   = block[3];
      AdcDeltaScanEnabled  = block[4];
      AdcWindowScanEnabled = block[5];
      AdcWindowCounterInit = block[6];
      AdcOptoDelay         = block[7];
    }
  else
    {
      /* No valid parameters in EEPROM: use defaults */
      AdcChans             = ADC_MAX_INPUTS;
      AdcConfig            = ADC_DFLT_CONV_PARS;
      AdcCalibBeforeScan   = FALSE;
      AdcReadoutOnChange   = FALSE;
      AdcDeltaScanEnabled  = TRUE;
      AdcWindowScanEnabled = FALSE;
      AdcWindowCounterInit = 2;

⌨️ 快捷键说明

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