📄 can.c
字号:
CIOCON = 0x20; //Drive TX pin Vdd when recessive, disable capture
#ifdef CAN_LOW_INT
IPR3 = 0x00;
#else
IPR3 = 0xFF;
#endif
#ifdef USE_LOOPBACK_MODE
CANCON = (LOOPBACK_MODE & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF)); //Set loopback mode for debug purposes only
while((CANSTAT & MODE_MASK) != (LOOPBACK_MODE & MODE_MASK)); //Wait until loopback mode is set
#else
CANCON = (NORMAL_MODE & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF)); //Set normal mode
while((CANSTAT & MODE_MASK) != (NORMAL_MODE & MODE_MASK)); //Wait until normal mode is set
#endif
PIE3 = CAN_INT_BITS & 0xE3; //Enable CAN interrupts except TX interrupts
PIR3 = 0x18; //Set TXB1 & TXB2 int flags
//Send my address to notify our presence
#ifdef MY_ADDRESS_IS_STANDARD
TXB0SIDL = (unsigned char)(MY_ADDRESS_IDENTIFIER << 5);
TXB0SIDH = (unsigned char)(MY_ADDRESS_IDENTIFIER >> 3); //Load address with MY_ADDRESS_IDENTIFIER standard identifier
TXB0DLC = 0x00; //0 data bytes to send
TXB0CON = 0x00; //Initiate transmission
TXB0REQ = 1;
#else
TXB0EIDL = (unsigned char)(MY_ADDRESS_IDENTIFIER & 0xFF); //Load address with MY_ADDRESS_IDENTIFIER extended identifier
TXB0EIDH = (unsigned char)((MY_ADDRESS_IDENTIFIER >> 8) & 0xFF);
TXB0SIDL = (unsigned char)((MY_ADDRESS_IDENTIFIER >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_2 >> 13) & 0xE0) | 0x08;
TXB0SIDH = (unsigned char)((MY_ADDRESS_IDENTIFIER >> 21) & 0xFF);
TXB0DLC = 0x00; //0 data bytes to send
TXB0CON = 0x00; //Initiate transmission
TXB0REQ = 1;
#endif
return 0;
}
/*********************************************************************
* Function: void CANISR(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: Will modify the RX/TX interrupt flags
* and interrupt enable bits
*
* Overview: Checks if a CAN reception/transmission was complete
* and if so write/read to the CAN RX/TX FIFO buffers
*
* Note: This function is supposed to be called from the ISR
********************************************************************/
void CANISR(void)
{
unsigned char TempCANCON;
if(PIR3 & PIE3)
{
TempCANCON = CANCON;
if(RXB0IF && RXB0IE)
{
RXB0IF = 0; //Clear interrupt flag
CANCON = CANCON & 0xF0 | RXB0Interrupt;
CANGetMessage();
}
else if(RXB1IF && RXB1IE)
{
RXB1IF = 0; //Clear interrupt flag
CANCON = CANCON & 0xF0 | RXB1Interrupt;
CANGetMessage();
}
else if(TXB0IF && TXB0IE)
{
CANCON = CANCON & 0xF0 | TXB0Interrupt;
if(CANPutMessage())
TXB0IE = 0;
else
TXB0IF = 0;
}
else if(TXB1IF && TXB1IE)
{
CANCON = CANCON & 0xF0 | TXB1Interrupt;
if(CANPutMessage())
TXB1IE = 0;
else
TXB1IF = 0;
}
else if(TXB2IF && TXB2IE)
{
CANCON = CANCON & 0xF0 | TXB2Interrupt;
if(CANPutMessage()) //if there wasn't any more messages to send
TXB2IE = 0; //disable interrupts for TXB2 and leave TXB2IF
else //still on so PutCAN() can reenable the interrupt and instantly vector to ISR
TXB2IF = 0; //message was sent, just clear the interrupt flag.
}
else if(ERRIF && ERRIE)
{
ERRIF = 0; //Clear interrupt flag
#ifdef CAN_ERROR_HANDLER_ENABLE
CANErrorHandler();
#endif
//No error handler implemented!!!
}
else if(WAKIF && WAKIE)
{
WAKIF = 0; //Clear interrupt flag
}
CANCON = TempCANCON;
}
}
/*********************************************************************
* Function: void CANGetMessage(void)
*
* PreCondition: <WIN2:WIN0> in the CANCON register has to set
* to reflect the desired RXB registers
*
* Input: None
*
* Output: None
*
* Side Effects: Will modify the RX FIFO Write pointer (RXWPtr)
*
* Overview: Gets the registers for a RXB and puts them in the
* CAN Receive buffer
*
* Note: Care is not taken if buffer is full
********************************************************************/
void CANGetMessage(void)
{
unsigned char i;
if(++RXWPtr >= RXBUF) //If pointer overflowed
RXWPtr = 0; //Clear it
for(i=0;i<14;i++)
{
RXMessage[RXWPtr].Data[i] = *(unsigned char *)(0xF60+i);
}
RXB0FUL = 0;
}
/*********************************************************************
* Function: char CANPutMessage(void)
*
* PreCondition: <WIN2:WIN0> in the CANCON register has to set
* to reflect the desired TXB registers
*
* Input: None
*
* Output: 0 -> A new message has been put in the transmit queue
* 1 -> There was no messages in the TX buffer to send
*
* Side Effects: Will modify the TX buffer磗 Read pointer (TXRPtr)
*
* Overview: Checks if there is any messages to transmit and if so
* place it in the registers reflected by <WIN2:WIN0>
*
* Note: None
********************************************************************/
char CANPutMessage(void)
{
unsigned char i;
if(TXWPtr != TXRPtr) //If there are any more data to send
{
if(++TXRPtr >= TXBUF) //then increment the TX read pointer
TXRPtr = 0;
for(i=0;i<14;i++)
*(unsigned char *)(0xF60+i) = TXMessage[TXRPtr].Data[i];
RXB0RTRRO = 1; //TXREQ = 1;
return 0;
}
else
return 1;
}
/*********************************************************************
* Function: char CANPut(struct CANMessage Message)
*
* PreCondition: None
*
* Input: A CAN message
*
* Output: 1 -> Failed to put a CAN on the buffer, buffer is full
* 0 -> The CAN message is put on the buffer and will be
* transmitted eventually
*
* Side Effects: Will modify the TX Buffer register磗 Write pointer
*
* Overview: Initially checks if at least one buffer slot is available
* and if so push the requested message in the buffer.
* Checks if the TX modules are idle and if they are, reactivate one.
*
* Note: None
********************************************************************/
char CANPut(struct CANMessage Message)
{
unsigned char TempPtr, i;
if(TXWPtr == TXRPtr-1 || (TXWPtr == TXBUF-1 && TXRPtr == 0)) //if all transmit buffers are full return 1
return 1;
//Do not modify the TX pointer until the message has been successfully copied so the CANISR don't
//send a message that isn't ready
if(TXWPtr >= TXBUF-1) //check if transmit write pointer will overflow
{
TempPtr = 0; //and post clear write pointer
}
else
{
TempPtr = TXWPtr+1; //and postincrement write pointer
}
if(Message.NoOfBytes > 8) //Ensure we don't handle more than 8 bytes
Message.NoOfBytes = 8;
TXMessage[TempPtr].Specific.TXBDLC.Byte = Message.NoOfBytes; //Set the data count
if(!Message.Remote) //If dataframe
{
TXMessage[TempPtr].Specific.TXBDLC.Bits.TXRTR = 0; //Clear the Remote Transfer Request bit
for(i = 0; i < Message.NoOfBytes; i++) //Load data registers
{
TXMessage[TempPtr].Specific.TXBD.Array[i] = Message.Data[i];
}
}
else //Remote frame
{
TXMessage[TempPtr].Specific.TXBDLC.Bits.TXRTR = 1; //Set TXRTR bit
}
if(Message.Ext) //Extended identifier
{
TXMessage[TempPtr].Specific.TXBEIDL.Byte = (unsigned char)(Message.Address & 0xFF); // Put address <7:0> in EIDL
TXMessage[TempPtr].Specific.TXBEIDH.Byte = (unsigned char)((Message.Address >> 8) & 0xFF); // Put address <15:8> in EIDH
TXMessage[TempPtr].Specific.TXBSIDL.Byte = (unsigned char)((Message.Address >> 16) & 0x03) | (unsigned char)((Message.Address >> 13) & 0xE0);
TXMessage[TempPtr].Specific.TXBSIDH.Byte = (unsigned char)((Message.Address >> 21) & 0xFF);
TXMessage[TempPtr].Specific.TXBSIDL.Bits.EXIDE = 1;
}
else //Standard identifier
{
TXMessage[TempPtr].Specific.TXBSIDL.Byte = (unsigned char)((Message.Address << 5) & 0xFF); //Put address <2:0> in SIDL
TXMessage[TempPtr].Specific.TXBSIDH.Byte = (unsigned char)((Message.Address >> 3) & 0xFF); //Put address <10:3> in SIDH
TXMessage[TempPtr].Specific.TXBSIDL.Bits.EXIDE = 0;
}
TXMessage[TempPtr].Specific.TXBCON.Byte = Message.Priority & 0x03; //Set the internal priority of the data frame
TXWPtr = TempPtr;
//Reenable an interrupt if it is idle, it doesn't matter if another TX source caught the pending message
//before the source that is enabled here does since the interrupt CHECKS if there are any messages pending
//and if the buffer is empty, it will disable itself again.
if(!TXB0IE) //TXB0 is idle
TXB0IE = 1; //enable TXB0 to fire an interrupt to send the pending message
else if(!TXB1IE) //else if TXB1 is idle
TXB1IE = 1; //same procedure
else if(!TXB2IE) //finally try TXB2
TXB2IE = 1;
return 0;
}
/*********************************************************************
* Function: char CANRXMessageIsPending(void)
*
* PreCondition: None
*
* Input: None
*
* Output: 1 -> At least one received message is pending in the RX buffer
* 0 -> No received messages are pending
*
* Side Effects: None
*
* Overview: Checks if the RX Write pointer is equal to RX Read pointer and
* if so returns 0, else returns 1
*
* Note: Since no care is taken if the buffer overflow
* this function has to be polled frequently to
* prevent a software receive buffer overflow
********************************************************************/
char CANRXMessageIsPending(void)
{
if(RXWPtr != RXRPtr)
return 1;
else
return 0;
}
/*********************************************************************
* Function: struct CANMessage CANGet(void)
*
* PreCondition: An unread message has to be in the buffer
* use RXCANMessageIsPending(void) prior to
* calling this function in order to determine
* if an unread message is pending.
*
* Input: None
*
* Output: The received message
*
* Side Effects: Will modify the RX Buffer register磗 Read pointer
*
* Overview: Pops the the first message of the RX buffer
*
* Note: None
********************************************************************/
struct CANMessage CANGet(void)
{
struct CANMessage ReturnMessage;
unsigned char TempPtr, i;
/*Do not modify the RX pointer until the message has been successfully
copied to prevent ISR to overwrite it (Note. this is not implemented in the ISR yet)*/
if(RXRPtr >= RXBUF-1) //Check if pointer will overflow
{
TempPtr = 0;
}
else
{
TempPtr = RXRPtr+1;
}
ReturnMessage.NoOfBytes = RXMessage[TempPtr].Specific.RXBDLC.Byte & 0x0F; //copy data count
if(RXMessage[TempPtr].Specific.RXBCON.Bits.RXRTRRO) //Remote frame request
{
ReturnMessage.Remote = 1;
}
else //Data frame
{
ReturnMessage.Remote = 0; //Clear remote flag
for(i = 0; i < ReturnMessage.NoOfBytes; i++) //copy data content
ReturnMessage.Data[i] = RXMessage[TempPtr].Specific.RXBD.Array[i];
}
CANCON = CANCON & 0xF0;
ReturnMessage.Address = (unsigned int)(RXMessage[TempPtr].Specific.RXBSIDH.Byte) << 3; //Load the standard identifier into the address
ReturnMessage.Address |= (RXMessage[TempPtr].Specific.RXBSIDL.Byte >> 5);
if(RXMessage[TempPtr].Specific.RXBSIDL.Bits.EXID) //Extended identifier
{
ReturnMessage.Ext = 1; //Set the extended identifier flag
ReturnMessage.Address = (ReturnMessage.Address << 2) | (RXMessage[TempPtr].Specific.RXBSIDL.Byte & 0x03);
ReturnMessage.Address = ReturnMessage.Address << 16; //and copy the extended address
ReturnMessage.Address |= (unsigned int)(RXMessage[TempPtr].Specific.RXBEIDH.Byte) << 8;
ReturnMessage.Address |= RXMessage[TempPtr].Specific.RXBEIDL.Byte;
}
else //Standard identifier
{
ReturnMessage.Ext = 0; //clear the extended identifier flag
}
RXRPtr = TempPtr;
return ReturnMessage;
}
/*********************************************************************
* Function: void CANSetMode(unsigned char Mode)
*
* PreCondition: None
*
* Input: Desired CAN Mode
* (CAN_LISTEN_MODE, CAN_LOOPBACK_MODE
* CAN_DISABLE_MODE, CAN_NORMAL_MODE)
*
* Output: None
*
* Side Effects: None
*
* Overview: Requests to set the desired mode and waits until
* the mode has been set.
*
* Note: If USE_LOOPBACK_MODE is defined the requested
* mode will be loopback mode if the input is
* Normal mode
********************************************************************/
void CANSetMode(unsigned char Mode)
{
#ifdef USE_LOOPBACK_MODE
if(Mode == NORMAL_MODE)
{
CANCON = (LOOPBACK_MODE & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF));
while((CANSTAT & MODE_MASK) != (LOOPBACK_MODE & MODE_MASK));
}
else
#endif
{
CANCON = (Mode & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF));
while((CANSTAT & MODE_MASK) != (Mode & MODE_MASK));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -