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

📄 canopdriver.c

📁 CanOpen节点的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*******************************************************************************

    CANopDriver.c - Functions for CANopenNode
    
    Copyright (C) 2004  Janez Paternoster, Slovenia

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


    Author: janez.paternoster@siol.net

    History:
    2004/06/25 [JP]  File Created
    2004/08/09 [JP]  Revised, many changes (interrupt and init routines), added setup 'defines'

*******************************************************************************/

#include <p18cxxx.h>  
#include <string.h>

#include "CANopDriver.h"
#include "CANopErrors.h"
#ifdef CO_ALLOW_FLASH_WRITE
   #include "memcpyram2flash.h"
#endif

//following is not real header file, because it contains variable definitions,
//it may be included only at this point
#include "CANopObjDict.h"


/*******************************************************************************
   Variables used in CANopen
*******************************************************************************/
//CANopen nodeID
   unsigned char CO_NodeID = CO_DEFAULT_NODE_ID;
   
//CANopen Bit rate
   unsigned char CO_BitRate = CO_DEFAULT_BIT_RATE;
   
//timer variable increments every 1ms
   volatile unsigned int CO_Timer16Value;
   
//NMT operating state of node
   volatile unsigned char CO_NMToperatingState;

//Variables used in High Interrupt
#pragma udata access CO_udata_access
   near unsigned char CO_IsrHighIndex;          //index of matched CANid
   near unsigned char CO_IsrHighRxNoOfBytes;    //number of bytes in recived message
   near volatile struct{                        //signals from IsrHigh to IsrLow or ProcessMain
      unsigned char ResetComm    :1;
      union{
         unsigned char byte;
         struct{
            unsigned char NMTlength         :1;
            unsigned char NMTcmd            :1;
            unsigned char HeartBeatLength   :1;
            unsigned char SyncLength        :1;
            unsigned char SDOlength         :1;
            unsigned char PDOlength         :1;
         }bits;
      }Error;
   }CO_IsrHighSignal;
#pragma udata

//SDOs
   unsigned char CO_SDOrequest;        //0=ready for new communication, 1=busy, 0xFF=abort
   unsigned char CO_SDORXdata[8];      //data arrived from bus 
   unsigned char CO_SDOTXdata[8];      //data transmitted to bus 
       
//PDOs
#pragma udata CO_udata=0x100  //some variables are in separate section to avoid section overflow
  #define CO_SIZE_OF_RPDO_DATA    8    //value must match size of one CO_RPDO member   !!!
  #if CO_NO_RPDO > 0
   volatile tData8bytes CO_RPDO[CO_NO_RPDO];         //Data
   volatile unsigned char CO_RPDOlength[CO_NO_RPDO]; //length of recive PDOs in bytes, calculated from mapping parameters
   volatile unsigned char CO_RPDOcount[CO_NO_RPDO];  //counter of recived PDOs, incremented each time PDO is recived, may be erased
  #endif
  #if CO_NO_TPDO > 0
   volatile tData8bytes CO_TPDO[CO_NO_TPDO];         //Data
   volatile unsigned char CO_TPDOlength[CO_NO_TPDO]; //length of transmit PDOs in bytes, calculated from mapping parameters
   volatile unsigned char CO_tTPDOwait[CO_NO_TPDO];  //timer used for trigger PDO sending
  #endif

#pragma udata

//Sync
   volatile struct{
      unsigned int period;
      unsigned int periodTimeout;
      unsigned int window;
   }CO_SYNC;
   
//HeartBeat Consumer
  #if CO_NO_CONS_HEARTBEAT > 0
   volatile unsigned int CO_HBcons_TimerValue[CO_NO_CONS_HEARTBEAT];
   volatile unsigned char CO_HBcons_NMTstate[CO_NO_CONS_HEARTBEAT];
  #endif
  
//Emergency message control and Error codes
   volatile struct{
      char CheckErrors     :1;
      char EmergencyToSend :1;
      unsigned int EmergencyErrorCode;
      unsigned char CodeVal;
   }ErrorControl;
   rom unsigned int ErrorCodesTable[] = ERROR_CODES;
   unsigned char CO_EmergencyTXdata[8];      //data transmitted to bus 
   
   
//Status LEDs
   struct {
      unsigned char On          :1;
      unsigned char Off         :1;
      unsigned char Flickering  :1;
      unsigned char Blinking    :1;
      unsigned char SingleFlash :1;
      unsigned char DoubleFlash :1;
      unsigned char TripleFlash :1;
   } CO_StatusLED;
   
//variable for reciving CAN messages
   unsigned int CO_RXCAN_ID[3+CO_NO_RPDO+CO_NO_CONS_HEARTBEAT];
      //filled at CanInit, IDs are << 5 to match the RXBnSIDx register bit order: 
      //   0=NMT ID, 1=SYNC ID, 2=SDO ID,
      //   3...(2+CO_NO_RPDO)=RPDO ID, 
      //   (3+CO_NO_RPDO)...(2+CO_NO_RPDO+CO_NO_CONS_HEARTBEAT)=Heartbeat consumer ID

//variables for transmitting CAN messages
   //filled at CanInit, IDs are << 5 to match the RXBnSIDx register bit order: 
   //PDOs through Hardware transmit buffer 0, interrupt driven
   #if CO_NO_TPDO > 0
      unsigned char CO_TXCAN_PDOsendReq;   //flag variable for request sending message
      CO_CanMessage CO_TXCAN_PDOmsgs[CO_NO_TPDO];
   #endif
   
   //Emergencies, SDOs, Heartbeats and User defined msgs through Hardware transmit buffer 1, interrupt driven
   unsigned char CO_TXCAN_OtherSendReq;   //flag variable for request sending message
   CO_CanMessage CO_TXCAN_OtherMsgs[CO_NO_USR_CAN_BUFF+2];
      //   0...(CO_NO_USR_CAN_BUFF-1)=User defined messages, 
      //   (CO_NO_USR_CAN_BUFF)=SDO, (CO_NO_USR_CAN_BUFF+1)=HeartBeat
   #if(CO_NO_USR_CAN_BUFF+2) > 8
      #error define_CO_NO_USR_CAN_BUFF CO_NO_USR_CAN_BUFF too big
   #endif

   //SYNCs and Emergency through Hardware transmit buffer 2, interrupt driven
   unsigned char CO_TXCAN_SEMsendReq;   //flag variable for request sending message
   CO_CanMessage CO_TXCAN_SEMmsgs[2];


   
/*******************************************************************************
   CAN bit rates and Timer2 setup
*******************************************************************************/
#if CO_OSCILATOR_FREQ == 16
   #define TIMER2PRESCALE     0     //0=1:1, 1=1:4, 2=1:16
   #define TIMER2POSTSCALE    16    //1...16
   #define TIMER2PR2          249   //0...255
#elif CO_OSCILATOR_FREQ == 20
   #define TIMER2PRESCALE     1     //0=1:1, 1=1:4, 2=1:16
   #define TIMER2POSTSCALE    10    //1...16
   #define TIMER2PR2          124   //0...255
#elif CO_OSCILATOR_FREQ == 32
   #define TIMER2PRESCALE     1     //0=1:1, 1=1:4, 2=1:16
   #define TIMER2POSTSCALE    16    //1...16
   #define TIMER2PR2          124   //0...255
#elif CO_OSCILATOR_FREQ == 40
   #define TIMER2PRESCALE     1     //0=1:1, 1=1:4, 2=1:16
   #define TIMER2POSTSCALE    10    //1...16
   #define TIMER2PR2          249   //0...255
#else
   #error define_CO_OSCILATOR_FREQ CO_OSCILATOR_FREQ not supported
#endif

rom struct{    
   UNSIGNED8  BRP;         //(1...64) Baud Rate Prescaler 
   UNSIGNED8  SJW;         //(1...4) SJW time
   UNSIGNED8  PROP;        //(1...8) PROP time
   UNSIGNED8  PhSeg1;      //(1...8) Phase Segment 1 time
   UNSIGNED8  PhSeg2;      //(1...8) Phase Segment 2 time
}CO_BitRateData[8] = 
#if CO_OSCILATOR_FREQ == 16
   {50,  1, 4, 8, 3, //CAN=10kbps
    25,  1, 4, 8, 3, //CAN=20kbps
    10,  1, 4, 8, 3, //CAN=50kbps
    4,   1, 4, 8, 3, //CAN=125kbps
    2,   1, 4, 8, 3, //CAN=250kbps
    1,   1, 4, 8, 3, //CAN=500kbps
    1,   1, 2, 4, 3, //CAN=800kbps
    1,   1, 2, 3, 2};//CAN=1000kbps
#elif CO_OSCILATOR_FREQ == 20
   {50,  1, 6, 8, 5, //CAN=10kbps
    25,  1, 6, 8, 5, //CAN=20kbps
    10,  1, 6, 8, 5, //CAN=50kbps
    5,   1, 4, 8, 3, //CAN=125kbps
    2,   1, 6, 8, 5, //CAN=250kbps
    1,   1, 6, 8, 5, //CAN=500kbps
    1,   1, 3, 5, 3, //CAN=800kbps     //combination does not work
    1,   1, 2, 4, 3};//CAN=1000kbps
#elif CO_OSCILATOR_FREQ == 32
   {64,  1, 8, 8, 8, //CAN=10kbps
    50,  1, 4, 8, 3, //CAN=20kbps
    20,  1, 4, 8, 3, //CAN=50kbps
    8,   1, 4, 8, 3, //CAN=125kbps
    4,   1, 4, 8, 3, //CAN=250kbps
    2,   1, 4, 8, 3, //CAN=500kbps
    2,   1, 2, 4, 3, //CAN=800kbps
    2,   1, 2, 3, 2};//CAN=1000kbps
#elif CO_OSCILATOR_FREQ == 40
   {64,  4, 8, 8, 8, //CAN=10kbps      //combination does not work
    50,  1, 6, 8, 5, //CAN=20kbps
    25,  1, 4, 8, 3, //CAN=50kbps
    10,  1, 4, 8, 3, //CAN=125kbps
    5,   1, 4, 8, 3, //CAN=250kbps
    2,   1, 6, 8, 5, //CAN=500kbps
    1,   1, 8, 8, 8, //CAN=800kbps
    2,   1, 2, 4, 3};//CAN=1000kbps
#else
   #error define_CO_OSCILATOR_FREQ CO_OSCILATOR_FREQ not supported
#endif

/*******************************************************************************
   INIT CAN BUS INTERFACE, executed at node reset
*******************************************************************************/
void CO_InitResetNode(void){
   unsigned char i;
/* Init Timer2 ****************************************************************/
   //timer2 is used for 1ms interrupt. It is also time-base for PWM modules.
   //So if PWM is used, frequency is set here.
   T2CON = ((TIMER2POSTSCALE-1) << 3) | 0x04 | TIMER2PRESCALE;
   PR2 = TIMER2PR2;
   TMR2 = 0;
   //interrupts
   PIR1bits.TMR2IF = 0;
   IPR1bits.TMR2IP = 0;   //low priority interrupt
   PIE1bits.TMR2IE = 1;
   
/* Init Printed Board *********************************************************/
   PCB_BANDWIDTH_IsrLow_INIT;
   PCB_BANDWIDTH_IsrHigh_INIT;
   PCB_RUN_LED_INIT;
   PCB_ERROR_LED_INIT; 

/* Read EEPROM ****************************************************************/
   #ifdef CO_USE_EEPROM
      EECON1bits.EEPGD = 0;
      EECON1bits.CFGS = 0;
      i=sizeof(ODE_EEPROM);
      do{
         i--;
         EEADR = i;
         EECON1bits.RD = 1;
         *((unsigned char*)&ODE_EEPROM + i) = EEDATA;
      }while(i>0);
   #endif
   
/* Init variables *************************************************************/
   CO_Timer16Value = 0;
   CO_StatusLED.On = 1;
   CO_StatusLED.Off = 0;
   ODE_EEPROM.PowerOnCounter++;
}
   
/*******************************************************************************
   INIT CAN BUS INTERFACE, executed at communication reset
*******************************************************************************/
void CO_InitResetComm(void){
   static char i;

   PCB_RUN_LED(CO_StatusLED.Off);
   CO_NMToperatingState = NMT_INTIALIZING;

   CANCON = 0x80;       //request configuration mode
   while((CANSTAT & 0xE0) != 0x80); //wait until configuration mode is set 

/* Setup variables ************************************************************/
   CO_NodeID = ReadNodeID();     
   if(CO_NodeID==0 || CO_NodeID>127){
      ErrorReport(ERROR_WrongNodeIDorBitRate, CO_NodeID);
      CO_NodeID = 1;
   }

   CO_BitRate = ReadBitRate();
   if(CO_BitRate > 7){
      ErrorReport(ERROR_WrongNodeIDorBitRate, CO_BitRate);
      CO_BitRate = 1;
   }
      
   CO_IsrHighSignal.ResetComm = 0;
   CO_IsrHighSignal.Error.byte = 0;
   
   //SDOs
   CO_SDOrequest = 0;
   ODE_Server_SDO_Parameter.COB_ID_Client_to_Server = 0x00000600L + CO_NodeID;
   ODE_Server_SDO_Parameter.COB_ID_Server_to_Client = 0x00000580L + CO_NodeID;
   

⌨️ 快捷键说明

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