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

📄 pdo.c

📁 AVR平台下的CanOpen协议桟源码包括应用
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ------------------------------------------------------------------------
File   : pdo.c

Descr  : Functions for CANopen PDO handling, which call node-specific device
         routines; the calls comply to the "CANopen Device Profile for
	 I/O Modules" (CiA DSP-401).

History: 19JUL.00; Henk B&B; Definition; for the time being only ADC
                             device routines are called.
	   AUG.00; Henk B&B; Addition of digital input and output.
	   NOV.00; Henk B&B; Addition of analogue output (DAC).
	 29NOV.00; Henk B&B; 'digin_pdo_on_cos()' not called for
	                     PDO transmission type 254.
--------------------------------------------------------------------------- */

#include "general.h"
#include "adc.h"
#include "can.h"
#include "dac.h"
#include "digio.h"
#include "eeprom.h"
#include "objects.h"
#include "pdo.h"
#include "store.h"
#include "timer103.h"

/* ------------------------------------------------------------------------ */
/* Some PDO communication parameters and the PDO mappings are constant
   in this application, and can thus be stored in program memory;
   this information is here just for reference, it is not essential
   for correct operation, although it can be read out by SDO messages;
   in the data arrays below the RPDO parameters are stored behind
   the TPDO parameters */

/* Per PDO the corresponding COB-ID (default predefined CANopen values..),
   here: TPDO1, TPDO2 and TPDO3, and RPDO1 and RPDO2 */
const UINT16 PDO_COBID[TPDO_CNT + RPDO_CNT] = { 0x180, 0x280, 0x380,
						0x200, 0x300 };

/* Per PDO the number of mapped objects */
const BYTE   PDOMAP_CNT[TPDO_CNT + RPDO_CNT] = { 2, 2, 2, 2, 2 };

/* Per PDO the mapped objects */
const UINT32 PDOMAP[TPDO_CNT + RPDO_CNT][2] =
{
  { 0x60000108L, 0x60000208L }, /* Digital Inputs: 1-8, 9-16 */
  { 0x64040008L, 0x64040118L }, /* Analog Inputs: chan number, 24-bit data */
  { 0x24040008L, 0x24040128L }, /* Analog Inputs: chan number, 40-bit data */
  { 0x62000108L, 0x62000208L }, /* Digital Outputs: 1-8, 9-16 */
  { 0x64110008L, 0x64110110L }  /* Analog Outputs: chan number, 16-bit data */
};

/* ------------------------------------------------------------------------ */
/* Globals */

/* Transmit-PDO and Receive-PDO communication parameters,
   stored in one array: first the TPDO parameters, then the RPDO parameters */
static PDO_COMM_PAR PdoCommPar[TPDO_CNT + RPDO_CNT]; /* (stored in EEPROM) */
static PDO_COMM_PAR *TPdoCommPar = &PdoCommPar[0];
static PDO_COMM_PAR *RPdoCommPar = &PdoCommPar[TPDO_CNT];

/* For timer-triggered PDO transmissions */
BOOL                TPdoOnTimer[TPDO_CNT];           /* (stored in EEPROM) */

/* Keeps track of time for the timer-triggered PDO transmissions
   (Timer1 is used to update these counters) */
UINT16              TPdoTimerCntr[TPDO_CNT];

/* ------------------------------------------------------------------------ */
/* Local prototypes */

static void pdo_load_config( void );

static BOOL pdo_get_comm_par( BYTE pdo_no,
			      BYTE od_subind,
			      BYTE *nbytes,
			      BYTE *par );

static BOOL pdo_get_mapping( BYTE pdo_no,
			     BYTE od_subind,
			     BYTE *nbytes,
			     BYTE *par );

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

void pdo_init( void )
{
  BYTE i;

  /* Initialize PDO configuration parameters */
  pdo_load_config();

#ifdef __VARS_IN_EEPROM__
  for( i=0; i<TPDO_CNT+RPDO_CNT; ++i )
    {
      BYTE byt;
      if( eeprom_read( EE_PDO_TTYPE+i ) != PdoCommPar[i].transmission_type )
	eeprom_write( EE_PDO_TTYPE+i, PdoCommPar[i].transmission_type );
      byt = (BYTE) (PdoCommPar[i].event_timer & (UINT16) 0x00FF);
      if( eeprom_read( EE_PDO_ETIMER_LO+i ) != byt )
	eeprom_write( EE_PDO_ETIMER_LO+i, byt );
      byt = (BYTE) ((PdoCommPar[i].event_timer & (UINT16) 0xFF00) >> 8);
      if( eeprom_read( EE_PDO_ETIMER_HI+i ) != byt )
	eeprom_write( EE_PDO_ETIMER_HI+i, byt );
    }
#endif /* __VARS_IN_EEPROM__ */

  /* Set timer stuff for Transmit-PDOs */
  TIMER1_DISABLE();
  for( i=0; i<TPDO_CNT; ++i )
    {
      TPdoOnTimer[i]    = ((PdoCommPar[i].transmission_type >= 254) &&
			   (PdoCommPar[i].event_timer > (UINT16)0));
      TPdoTimerCntr[i]  = (UINT16) 0;

#ifdef __VARS_IN_EEPROM__
      if( eeprom_read( EE_TPDO_ONTIMER+i ) != TPdoOnTimer[i] )
	eeprom_write( EE_TPDO_ONTIMER+i, TPdoOnTimer[i] );
#endif /* __VARS_IN_EEPROM__ */
    }
  TIMER1_ENABLE();

  /* If Remote Frames are not required adjust
     the CAN-controller's configuration */
  can_rtr_enable( pdo_rtr_required() );
}

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

void tpdo_scan( void )
{
  /* Handle ongoing multi-PDO transmissions (non-standard CANopen...),
     change-of-state PDO transmissions,
     and timer-triggered PDO transmission(s) */

  /* Ongoing multi-transmission Transmit-PDO: Analog Inputs */
  adc_pdo_scan();

  /* Some PDO(s) are to be sent on a change-of-state of the I/O:
     Transmit-PDO: Digital Inputs */
  digin_pdo_on_cos();

#ifdef __VARS_IN_EEPROM__
  TPdoOnTimer[TPDO_DIGITAL_IN] = eeprom_read( EE_TPDO_ONTIMER +
					      TPDO_DIGITAL_IN );
  TPdoOnTimer[TPDO_ANALOG_IN]  = eeprom_read( EE_TPDO_ONTIMER +
					      TPDO_ANALOG_IN );
  TPdoOnTimer[TPDO_ANALOG_IN_V]= eeprom_read( EE_TPDO_ONTIMER +
					      TPDO_ANALOG_IN_V );
#endif /* __VARS_IN_EEPROM__ */

  /* Timer-triggered Transmit-PDO: Digital Inputs */
  if( TPdoOnTimer[TPDO_DIGITAL_IN] )
    {
#ifdef __VARS_IN_EEPROM__
      PdoCommPar[TPDO_DIGITAL_IN].event_timer =
	((UINT16) eeprom_read( EE_PDO_ETIMER_LO + TPDO_DIGITAL_IN )) |
	(((UINT16) eeprom_read( EE_PDO_ETIMER_HI + TPDO_DIGITAL_IN )) << 8);
#endif /* __VARS_IN_EEPROM__ */

      /* If timer period expired... */ 
      if( TPdoTimerCntr[TPDO_DIGITAL_IN] >=
	  PdoCommPar[TPDO_DIGITAL_IN].event_timer )
	{
	  digin_pdo();

	  TIMER1_DISABLE();
	  TPdoTimerCntr[TPDO_DIGITAL_IN] = (UINT16) 0;
	  TIMER1_ENABLE();
	}
    }

  /* Timer-triggered Transmit-PDO: Analog Inputs
     (prioritize physical value read-out) */
  if( TPdoOnTimer[TPDO_ANALOG_IN_V] )
    {
#ifdef __VARS_IN_EEPROM__
      PdoCommPar[TPDO_ANALOG_IN_V].event_timer =
	((UINT16) eeprom_read( EE_PDO_ETIMER_LO + TPDO_ANALOG_IN_V )) |
	(((UINT16) eeprom_read( EE_PDO_ETIMER_HI + TPDO_ANALOG_IN_V )) << 8);
#endif /* __VARS_IN_EEPROM__ */

      /* If timer period expired start an ADC scan */ 
      if( TPdoTimerCntr[TPDO_ANALOG_IN_V] >=
	  PdoCommPar[TPDO_ANALOG_IN_V].event_timer )
	{
	  /* Readout in volts (or ADC-counts if not calibrated),
	     and forced if necessary */
	  adc_pdo_scan_start( TRUE, TRUE );

	  TIMER1_DISABLE();
	  TPdoTimerCntr[TPDO_ANALOG_IN_V] = (UINT16) 0;
	  TIMER1_ENABLE();
	}
    }
  else
    {
      if( TPdoOnTimer[TPDO_ANALOG_IN] )
	{
#ifdef __VARS_IN_EEPROM__
	  PdoCommPar[TPDO_ANALOG_IN].event_timer =
	    ((UINT16) eeprom_read( EE_PDO_ETIMER_LO + TPDO_ANALOG_IN )) |
	    (((UINT16) eeprom_read( EE_PDO_ETIMER_HI + TPDO_ANALOG_IN )) << 8);
#endif /* __VARS_IN_EEPROM__ */

	  /* If timer period expired start an ADC scan */ 
	  if( TPdoTimerCntr[TPDO_ANALOG_IN] >=
	      PdoCommPar[TPDO_ANALOG_IN].event_timer )
	    {
	      /* Readout in ADC-counts, and forced if necessary */
	      adc_pdo_scan_start( FALSE, TRUE );

	      TIMER1_DISABLE();
	      TPdoTimerCntr[TPDO_ANALOG_IN] = (UINT16) 0;
	      TIMER1_ENABLE();
	    }
	}
    }
}

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

void pdo_on_nmt( BYTE nmt_request )
{
  switch( nmt_request )
    {
    case NMT_START_REMOTE_NODE:
      {
	/* Immediately start first timer-triggered read out, if enabled... */
	BYTE pdo_no;
	TIMER1_DISABLE();
	for( pdo_no=0; pdo_no<TPDO_CNT; ++pdo_no )
	  {
#ifdef __VARS_IN_EEPROM__
	    PdoCommPar[pdo_no].event_timer =
	      ((UINT16) eeprom_read( EE_PDO_ETIMER_LO + pdo_no )) |
	      (((UINT16) eeprom_read( EE_PDO_ETIMER_HI + pdo_no )) << 8);
#endif /* __VARS_IN_EEPROM__ */

	    TPdoTimerCntr[pdo_no] = PdoCommPar[pdo_no].event_timer;
	  }
	TIMER1_ENABLE();
      }

      /* In case of ADC-readout-on-change we need to initialize
	 the ADC reference values ('last-sent' values) */
      adc_init_delta_references();

      break;

    case NMT_STOP_REMOTE_NODE:
    case NMT_ENTER_PREOPERATIONAL_STATE:
    case NMT_RESET_COMMUNICATION:
    case NMT_RESET_NODE:
      /* Do everything necessary to stop
	 ongoing channel scan operations properly */
      adc_pdo_scan_stop();

      break;

    default:
      break;
    }
}

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

void tpdo_on_sync( void )
{
  /* Send PDO(s) on the reception of a SYNC object:
     only if PDO(s) has (have) appropriate transmission type */

#ifdef __VARS_IN_EEPROM__
  PdoCommPar[TPDO_DIGITAL_IN].transmission_type =
    eeprom_read( EE_PDO_TTYPE + TPDO_DIGITAL_IN );
  PdoCommPar[TPDO_ANALOG_IN].transmission_type =
    eeprom_read( EE_PDO_TTYPE + TPDO_ANALOG_IN );
  PdoCommPar[TPDO_ANALOG_IN_V].transmission_type =
    eeprom_read( EE_PDO_TTYPE + TPDO_ANALOG_IN_V );
#endif /* __VARS_IN_EEPROM__ */

  /* Transmit-PDO: Digital Inputs */
  if( PdoCommPar[TPDO_DIGITAL_IN].transmission_type == 1 )
    {
      digin_pdo();
    }

  /* Transmit-PDO: Analog Inputs (prioritize physical value read-out) */
  if( PdoCommPar[TPDO_ANALOG_IN_V].transmission_type == 1 )
    {
      /* Readout in volts (or ADC-counts if not calibrated),
	 and forced if necessary */
      adc_pdo_scan_start( TRUE, TRUE );
    }
  else
    {
      if( PdoCommPar[TPDO_ANALOG_IN].transmission_type == 1 )
	{
	  /* Readout in ADC-counts, and forced if necessary */
	  adc_pdo_scan_start( FALSE, TRUE );
	}
    }
}

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

void tpdo1_on_rtr( void )
{
  /* Remote Transmission Request for Transmit-PDO1: Digital Inputs */

#ifdef __VARS_IN_EEPROM__
  PdoCommPar[TPDO_DIGITAL_IN].transmission_type =
    eeprom_read( EE_PDO_TTYPE + TPDO_DIGITAL_IN );
#endif /* __VARS_IN_EEPROM__ */

  /* Only if TPDO1 has appropriate transmission type */
  if( PdoCommPar[TPDO_DIGITAL_IN].transmission_type >= 253 )
    {
      digin_pdo();
    }
}

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

void tpdo2_on_rtr( void )
{
  /* Remote Transmission Request for Transmit-PDO2: Analog Inputs */

#ifdef __VARS_IN_EEPROM__
  PdoCommPar[TPDO_ANALOG_IN].transmission_type =
    eeprom_read( EE_PDO_TTYPE + TPDO_ANALOG_IN );
#endif /* __VARS_IN_EEPROM__ */

  /* Only if TPDO2 has appropriate transmission type */
  if( PdoCommPar[TPDO_ANALOG_IN].transmission_type >= 253 )
    {
      /* Readout in ADC-counts, and forced if necessary */
      adc_pdo_scan_start( FALSE, TRUE );
    }
}

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

void tpdo3_on_rtr( void )
{
  /* Remote Transmission Request for Transmit-PDO3: Analog Inputs in volts */

#ifdef __VARS_IN_EEPROM__
  PdoCommPar[TPDO_ANALOG_IN_V].transmission_type =
    eeprom_read( EE_PDO_TTYPE + TPDO_ANALOG_IN_V );
#endif /* __VARS_IN_EEPROM__ */

  /* Only if TPDO3 has appropriate transmission type */
  if( PdoCommPar[TPDO_ANALOG_IN_V].transmission_type >= 253 )
    {
      if( adc_calibrated() )
	{
	  /* Readout in volts, and forced if necessary */
	  adc_pdo_scan_start( TRUE, TRUE );
	}
      else
	{
	  /* CANopen Error Code 0x5000: device hardware */
	  can_write_emergency( 0x00, 0x50, EMG_ADC_NO_CALIB,
			       0, 0, 0, ERRREG_MANUFACTURER );
	}
    }
}

⌨️ 快捷键说明

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