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

📄 elmbmain.c

📁 AVR平台下的CanOpen协议桟源码包括应用
💻 C
字号:
/* ------------------------------------------------------------------------
File   : ELMBmain.c

Descr  : Embedded Local Monitor Board (ELMB) application main function.

History: 05APR.00; Henk B&B; Start of development, based on an earlier
                             version for the first prototype LMB.
	 APR-OCT00;Henk B&B; Ongoing additions/upgrades.
	 17OCT.01; Henk B&B; Do watchdog mechanism in main loop;
	                     add refresh of 'node_state' variable.
	 17MAY.02; Henk B&B; Prepare for ELMB128 with ATmega128 processor.
	   MAY.03; Henk B&B; CAN-message reception under interrupt; here
	                     messages are read from buffers in RAM (see can.c);
			     enable/disable interrupt where necessary;
			     always do 'periodic jobs' even when a CAN-message
			     is handled, to prevent message-handling to take
			     all processor time.
--------------------------------------------------------------------------- */

#include "general.h"
#include "adc.h"
#include "can.h"
#include "crc.h"
#include "dac.h"
#include "digio.h"
#include "eeprom.h"
#include "guarding.h"
#include "objects.h"
#include "pdo.h"
#include "sdo.h"
#include "store.h"
#include "timer103.h"
#include "watchdog.h"

#ifdef __RS232__
#include <stdio.h>
#include "uart.h"
#endif /* __RS232__ */

/* CANopen state of this node;
   the variable could maintain a constant value for a long
   (continuous) period of time and thus is vulnerable to SEU
   (Single Event Upset by radiation) */
BYTE NodeState;

/* Readable version string in flash */
const char * const version_str = VERSION_STRING;

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

void main( void )
{
  BYTE   mcucsr;
  BOOL   hard_reset, watchdog_brownout_jtag_reset;
  BYTE   object_no;
  BYTE   dlc;
  BYTE   *can_data;
  BYTE   adc_result;
  BYTE   i;
  UINT16 crc;

  watchdog_init();    /* In case of a free-running watchdog timer,
			 need to configure it a.s.a.p. */
  watchdog_disable(); /* Disable it if possible... */

  /* Wait for at least 800 ms
     (for the ADC's 32.768 kHz crystal to become stable) */
  for( i=0; i<80; ++i ) timer2_delay_ms( 10 );

  WDR(); /* In case of a free-running watchdog timer */

 reset_node:

  /* Was it a power-on or external reset (hard reset) ? */
  mcucsr = MCUCSR;
  hard_reset = FALSE;
  if( mcucsr & (BIT(PORF) | BIT(EXTRF)) )
    hard_reset = TRUE;
  else
    hard_reset = FALSE;

  /* Was it any other 'suspicious' source of reset ? */
  if( mcucsr & (BIT(WDRF) | BIT(BORF) | BIT(JTRF)) )
    watchdog_brownout_jtag_reset = TRUE;
  else
    watchdog_brownout_jtag_reset = FALSE;

  /* Clear all reset flag bits */
  MCUCSR = 0;

  /* Initialize CANopen node state value */
  NodeState = NMT_INITIALISING;

  /* Switch off Analog Comparator (saves power) */
  ACSR |= BIT( ACD );

  /* Initialize PORTB (system-part) */
  DDRB  = PORTB_DDR_OPERATIONAL;
  PORTB = PORTB_DATA_OPERATIONAL;

  /* Initialize PORTD (system-part) */
  DDRD  = PORTD_DDR_OPERATIONAL;
  PORTD = PORTD_DATA_OPERATIONAL;

  /* Initialize PORTE (system-part) */
  DDRE  = PORTE_DDR_OPERATIONAL;
  PORTE = PORTE_DATA_OPERATIONAL;

  /* Global interrupt enable */
  SEI();

#ifdef __RS232__
  uart_init( BAUD_9600 );
  printf( "ELMB says: hello world\n\n" );
#endif /* __RS232__ */

  /* Initialize Timer0 for general-purpose time-outs */
  timer0_init();

  /* Initialize Timer1 for Master/Slave Activity Monitoring test,
     Life Guarding, Timer-triggered PDO transmissions, etc. */
  timer1_init();

  /* Initialize digital I/O stuff */
  digio_init( hard_reset );

  /* Initialize DAC stuff */
  dac_init( hard_reset );

  WDR(); /* In case of a free-running watchdog timer */

  /* Reset and initialize the ADC(s) */
  adc_result = adc_init();

  WDR(); /* In case of a free-running watchdog timer */

  /* Check the CRC added to the code in FLASH, if present */
  crc_master( &crc );

  /* (Re)enable watchdog timer and/or Slave monitoring mechanism */
  watchdog_init();

 reset_communication:

  /* Go to state NMT_PREOPERATIONAL */
  NodeState = NMT_PREOPERATIONAL;

  /* Initialize and configure the CAN-controller and message buffer */
  can_init( TRUE );

  /* Initialize PDO stuff */
  pdo_init();

  /* Initialize Node Guarding and Life Guarding stuff */
  guarding_init();

  /* Send a CANopen Bootup message */
  can_write_bootup();

  WDR(); /* In case of a free-running watchdog timer */

  /* Report it when a watchdog, brownout or JTAG reset occurred
     (include MCUCSR content) */
  if( watchdog_brownout_jtag_reset )
    {
      /* CANopen Error Code 0x5000: device hardware */
      can_write_emergency( 0x00, 0x50, EMG_IRREGULAR_RESET,
			   mcucsr, 0, 0, ERRREG_MANUFACTURER );
    }

  /* Check if EEPROM configuration retrieval went okay during
     the various device initializations and report it if not */
  store_check_load_status();

  /* Report problems that occurred during hardware initialization */
  if( adc_result == FALSE )
    {
      BYTE stat;
      adc_status( &stat );
      /* CANopen Error Code 0x5000: device hardware */
      can_write_emergency( 0x00, 0x50, EMG_ADC_INIT,
			   stat, 0, 0, ERRREG_MANUFACTURER );
    }

  /* Report CRC errors */
  if( crc != 0 )
    {
      /* CANopen Error Code 0x5000: device hardware */
      can_write_emergency( 0x00, 0x50, EMG_CRC,
			   1, 0, 0, ERRREG_MANUFACTURER );
    }

  /* The following is not according to CANopen:
     to optionally go immediately to state NMT_OPERATIONAL
     (possibly making life simpler for a host application?) */
  NodeState = canopen_init_state();

  /* Application loop */
  while(1)
    {
      /* Refresh some registers, to be more rad-tolerant... */
      CAN_INT_DISABLE();
      DDRB  = PORTB_DDR_OPERATIONAL;
      PORTB = PORTB_DATA_OPERATIONAL;
      CAN_INT_ENABLE();

      /* Do the watchdog function */
      watchdog();

      /* Check for CAN-controller errors */
      can_check_for_errors();

      if( NodeState == NMT_OPERATIONAL )
	{
	  /* Refresh some more registers, to be more rad-tolerant...
	     The 'system' I/O-pin functions change during Slave ISP
	     ==> Slave ISP only to be done when *NOT* in state OPERATIONAL!
	     The registers are also partly user-defined, so that part
	     in principle is unknown here and is kept as is;
	     refresh of other pins to be done by the respective device
	     functions (such as ADC, Digital I/O, DAC) */
	  DDRD  = (DDRD & PORTD_USERBITS_MASK) | PORTD_DDR_OPERATIONAL;
	  PORTD = (PORTD & PORTD_USERBITS_MASK) | PORTD_DATA_OPERATIONAL;
	  DDRE  = (DDRE & PORTE_USERBITS_MASK) | PORTE_DDR_OPERATIONAL;
	  PORTE = (PORTE & PORTE_USERBITS_MASK) | PORTE_DATA_OPERATIONAL;

	  /* Handle PDO transmissions for data scanning,
	     change-of-state, and timer-triggered events */
	  tpdo_scan();
	}
      else
	{
	  /* Provide some protection against SEE bitflips in 'NodeState':
	     it basically has only 3 values: STOPPED (0x04),
	     OPERATIONAL (0x05) or PRE-OPERATIONAL (0x7F),
	     of which STOPPED is probably a rare condition...;
	     we assume a single bitflip in the byte may have occurred */

	  /* Upper nibble contains 0x7? -> state should be 0x7F */
	  if( (NodeState & 0x70) == 0x70 ) NodeState = NMT_PREOPERATIONAL;

	  /* Lower nibble is all 1? -> state should be 0x7F */
	  if( (NodeState & 0x0F) == 0x0F )
	    NodeState = NMT_PREOPERATIONAL;
	  else
	    {
	      /* If not, assume NMT_OPERATIONAL is the most likely state */
	      if( NodeState & 0x01 ) NodeState = NMT_OPERATIONAL;
	    }
	}

      lifeguarding_and_heartbeat( NodeState );

      /* Poll for (a) new CAN-message(s)... */
      if( can_msg_available() == FALSE )
	{
	  /* Jump to begin of 'while'-loop */
	  continue;
	}

      /* A CAN-message is to be processed, so get the object identifier,
	 DLC and (a pointer to) the data bytes (if any) from the buffer */
      object_no = can_read( &dlc, &can_data );

      /* Reset the Life Guarding time-out counter (a message was received)
	 but should actually be done through Node Guarding only...
	 (according to CANopen standard) */
      TIMER1_DISABLE();
      LifeGuardCntr = 0;
      TIMER1_ENABLE();

      /* Process the CAN-message depending on the node's current state */
      switch( NodeState )
	{
	case NMT_OPERATIONAL:
	  /* Node responds to all known messages */

	  switch( object_no )
	    {
	    case C91_SYNC:
	      /* 'SYNC' request for data */
	      tpdo_on_sync();

	      /* Message handled: jump to start of while loop */
	      continue;

	    case C91_TPDO1_RTR:
	      /* 'RTR' request for Transmit-PDO1 */
	      tpdo1_on_rtr();

	      /* Message handled: jump to start of while loop */
	      continue;

	    case C91_TPDO2_RTR:
	      /* 'RTR' request for Transmit-PDO2 */
	      tpdo2_on_rtr();

	      /* Message handled: jump to start of while loop */
	      continue;

	    case C91_TPDO3_RTR:
	      /* 'RTR' request for Transmit-PDO3 */
	      tpdo3_on_rtr();

	      /* Message handled: jump to start of while loop */
	      continue;

	    case C91_RPDO1:
	      /* Receive-PDO1 */
	      rpdo1( dlc, can_data );

	      /* Message handled: jump to start of while loop */
	      continue;

	    case C91_RPDO2:
	      /* Receive-PDO2 */
	      rpdo2( dlc, can_data );

	      /* Message handled: jump to start of while loop */
	      continue;

	    default:
	      break;
	    }

	  /* Respond to SDO, NMT and NodeGuarding messages as well,
	     so no 'break' here... */

	case NMT_PREOPERATIONAL:
	  /* Node does not respond to PDOs */

	  switch( object_no )
	    {
	    case C91_SDORX:
	      /* Object Dictionary access */
	      if( dlc == C91_SDORX_LEN ) sdo_server( can_data );

	      /* Message handled: jump to start of while loop */
	      continue;

	    default:
	      break;
	    }

	  /* Respond to NMT and NodeGuarding messages as well,
	     so no 'break' here... */

	case NMT_STOPPED:
	  /* Node is stopped: it only responds to NMT and NodeGuarding
	     messages, not to PDOs and SDOs */

	  switch( object_no )
	    {
	    case C91_NMT:
	      {
		BYTE node_id, nmt_request;

		node_id = can_data[1];

#ifdef __VARS_IN_EEPROM__
		NodeID = eeprom_read( EE_NODEID );
#endif /* __VARS_IN_EEPROM__ */

		/* Handle NMT message if correct and
		   addressed to this node or broadcast */
		if( dlc == C91_NMT_LEN && (node_id == NodeID || node_id == 0) )
		   {
		     nmt_request = can_data[0];

		     /* Ignore requests that don't change the node state */
		     if( (nmt_request == NMT_START_REMOTE_NODE &&
			  NodeState   == NMT_OPERATIONAL) ||
			 (nmt_request == NMT_STOP_REMOTE_NODE &&
			  NodeState   == NMT_STOPPED) ||
			 (nmt_request == NMT_ENTER_PREOPERATIONAL_STATE &&
			  NodeState   == NMT_PREOPERATIONAL) )
		       break;

		     /* Properly cancel any ongoing activities if necessary */
		     pdo_on_nmt( nmt_request );

		     switch( nmt_request )
		       {
		       case NMT_START_REMOTE_NODE:
			 NodeState = NMT_OPERATIONAL;
			 break;

		       case NMT_STOP_REMOTE_NODE:
			 NodeState = NMT_STOPPED;
			 break;

		       case NMT_ENTER_PREOPERATIONAL_STATE:
			 NodeState = NMT_PREOPERATIONAL;
			 break;

		       case NMT_RESET_NODE:
			 /* Parameters in Manufacturer-specific Profile
			    and Standardised Device Profile area are set
			    to their default values */

			 goto reset_node;

			 break;

		       case NMT_RESET_COMMUNICATION:
			 /* Parameters of the Communication Profile Area
			    are set to their power-on defaults */

			 goto reset_communication;

			 break;

		       default:
			 break;
		       }
		     /* Update node state in NodeGuard message buffer
			(which may be sent automatically) */
		     CAN_INT_DISABLE();
		     can_write_reg( C91_MSGS_I + (C91_NODEGUARD*C91_MSG_SIZE),
				    NodeState | (NodeGuardToggle & 0x80) );
		     CAN_INT_ENABLE();
		   }
	      }
	      break;

	    case C91_NODEGUARD_RTR:
	      /* Remote Transmission Request for Node Guard object */
	      nodeguarding( NodeState );
	      break;

	    default:
	      /* Ignore all other messages... */
	      break;
	    }
	  break;

	default:
	  /* Unknown node state: not possible.... */
	  break;
	}
    }
}

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

⌨️ 快捷键说明

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