📄 j1939_16.c
字号:
/*
j1939_6.c
This file contains the library routines for the J1939 C Library for PIC16
devices. Please refer to the J1939 C Library User Guide for information
on configuring and using this library.
This file requires the following files to be linked:
spi16.c
This file requires the following header files:
pic.h (HI-TECH)
j1939cfg.h
j1939pro.h
j1939_16.h
mcp2515.h
spi16.h
Version Date Description
----------------------------------------------------------------------
v1.00 2003/12/11 Initial release
v1.01 2004/01/28 Corrected Request/Response mechanism
Copyright 2004 Kimberly Otten Software Consulting
*/
#include <pic.h>
#include "j1939cfg.h" // Also includes spi16.h, mcp2515.h, J1939_16.h, and j1939pro.h
// Internal definitions
#define ADDRESS_CLAIM_TX 1
#define ADDRESS_CLAIM_RX 2
// Global variables. Some of these will be visible to the CA.
J1939_RX_QUEUE_BANK unsigned char CA_Name[J1939_DATA_LENGTH];
unsigned char CommandedAddress;
unsigned char CommandedAddressSource;
#ifdef J1939_ACCEPT_CMDADD
J1939_RX_QUEUE_BANK unsigned char CommandedAddressName[J1939_DATA_LENGTH];
#endif
unsigned char ContentionWaitTime;
unsigned char J1939_Address;
J1939_FLAG J1939_Flags;
J1939_TX_QUEUE_BANK J1939_MESSAGE OneMessage;
J1939_RX_QUEUE_BANK unsigned char RXHead;
J1939_RX_QUEUE_BANK unsigned char RXTail;
J1939_RX_QUEUE_BANK unsigned char RXQueueCount;
J1939_RX_QUEUE_BANK J1939_MESSAGE RXQueue[J1939_RX_QUEUE_SIZE];
J1939_TX_QUEUE_BANK unsigned char TXHead;
J1939_TX_QUEUE_BANK unsigned char TXTail;
J1939_TX_QUEUE_BANK unsigned char TXQueueCount;
J1939_TX_QUEUE_BANK J1939_MESSAGE TXQueue[J1939_TX_QUEUE_SIZE];
// Code definitions for common functions, to make it a little easier to read.
#define SELECT_MCP J1939_CS_PIN = 0;
#define UNSELECT_MCP J1939_CS_PIN = 1;
// Function Prototypes
#ifdef J1939_ACCEPT_CMDADD
unsigned char CA_AcceptCommandedAddress( void );
#endif
/*********************************************************************
CompareName
This routine compares the passed in array data NAME with the CA's
current NAME as stored in CA_Name.
Parameters: unsigned char * Array of NAME bytes
Return: -1 - CA_Name is less than the data
0 - CA_Name is equal to the data
1 - CA_Name is greater than the data
*********************************************************************/
#ifndef J1939_POLL_MCP
#pragma interrupt_level 0
#endif
signed char CompareName( J1939_RX_QUEUE_BANK unsigned char *OtherName )
{
unsigned char i;
for (i = 0; (i<J1939_DATA_LENGTH) && (OtherName[i] == CA_Name[i]); i++);
if (i == J1939_DATA_LENGTH)
return 0;
else if (CA_Name[i] < OtherName[i] )
return -1;
else
return 1;
}
/*********************************************************************
CopyName
This routine copies the CA's NAME into the message buffer's data array.
We can afford to make this a function, since another function is always
called after this is done, and we won't be using any additional stack
space.
Parameters: None
Return: None
*********************************************************************/
void CopyName(void)
{
unsigned char i;
for (i=0; i<J1939_DATA_LENGTH; i++)
OneMessage.Msg.Data[i] = CA_Name[i];
}
/*********************************************************************
SetAddressFilter
This routine sets filter 2 to the specified value (destination address).
It is used to allow reception of messages sent to this node specifically
or simply to the global address if this node does not have an address
(Address will be J1939_GLOBAL_ADDRESS).
NOTE: We can only use one stack level from here, so MCP_Write calls
have been replaced by their equivalent inline code.
Parameters: unsigned char J1939 Address of this CA
Return: None
*********************************************************************/
#ifndef J1939_POLL_MCP
#pragma interrupt_level 0
#endif
void SetAddressFilter( unsigned char Address )
{
unsigned char Status;
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_WRITE );
WRITESPI( MCP_CANCTRL );
WRITESPI( MODE_CONFIG + J1939_CLKOUT + J1939_CLKOUT_PS );
#else
WriteSPI( MCP_WRITE );
WriteSPI( MCP_CANCTRL );
WriteSPI( MODE_CONFIG + J1939_CLKOUT + J1939_CLKOUT_PS );
#endif
UNSELECT_MCP;
// MCP_Write( MCP_CANCTRL, MODE_CONFIG + J1939_CLKOUT + J1939_CLKOUT_PS );
do
{
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_READ );
WRITESPI( MCP_CANSTAT );
READSPI( Status );
#else
WriteSPI( MCP_READ );
WriteSPI( MCP_CANSTAT );
Status = ReadSPI();
#endif
UNSELECT_MCP;
} while ((Status & MODE_MASK) != MODE_CONFIG);
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_WRITE );
WRITESPI( MCP_RXF2EID8 );
WRITESPI( Address );
#else
WriteSPI( MCP_WRITE );
WriteSPI( MCP_RXF2EID8 );
WriteSPI( Address );
#endif
UNSELECT_MCP;
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_WRITE );
WRITESPI( MCP_CANCTRL );
WRITESPI( MODE_NORMAL + J1939_CLKOUT + J1939_CLKOUT_PS );
#else
WriteSPI( MCP_WRITE );
WriteSPI( MCP_CANCTRL );
WriteSPI( MODE_NORMAL + J1939_CLKOUT + J1939_CLKOUT_PS );
#endif
UNSELECT_MCP;
// MCP_Write( MCP_CANCTRL, MODE_NORMAL + J1939_CLKOUT + J1939_CLKOUT_PS );
}
/*********************************************************************
MCP_Modify
This function modifies the designated MCP address.
Parameters: unsigned char Address Address of the MCP register.
unsigned char Mask Bits to modify in the register
unsigned char Data Data value for the MCP register.
Return: None
*********************************************************************/
/*
This function has been brought in-line to save stack space.
void MCP_Modify( unsigned char Address, unsigned char Mask, unsigned char Data )
{
SELECT_MCP;
WriteSPI( MCP_BITMOD );
WriteSPI( Address );
WriteSPI( Mask );
WriteSPI( Data );
UNSELECT_MCP;
}
*/
/*********************************************************************
MCP_Write
This function writes a value to the designated MCP address.
Parameters: unsigned char Address Address of the MCP register.
unsigned char Data Data value for the MCP register.
Return: None
*********************************************************************/
void MCP_Write( unsigned char Address, unsigned char Data )
{
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_WRITE );
WRITESPI( Address );
WRITESPI( Data );
#else
WriteSPI( MCP_WRITE );
WriteSPI( Address );
WriteSPI( Data );
#endif
UNSELECT_MCP;
}
/*********************************************************************
SendOneMessage
This routine sends the message located at the pointer passed in. It
also uses the message's data length field to determine how much of the
data to load. At this point, all of the data fields, such as data
length, priority, and source address, must be set. This routine will
set up the CAN bits, such as the extended identifier bit and the
remote transmission request bit.
NOTE: Only transmit buffers 0 and 1 are used, to guarantee that the
messages appear on the bus in the order that they are sent to the
MCP2515.
Parameters: J1939_MESSAGE far * Pointer to message to send
Return: None
*********************************************************************/
#ifndef J1939_POLL_MCP
#pragma interrupt_level 0
#endif
void SendOneMessage( J1939_TX_QUEUE_BANK J1939_MESSAGE *MsgPtr )
{
// unsigned char oldSIDL;
unsigned char MCP_Load;
unsigned char Loop;
unsigned char MCP_Send;
unsigned char Temp;
// Set up the final pieces of the message and make sure DataLength isn't
// out of spec.
MsgPtr->Msg.Res = 0;
MsgPtr->Msg.RTR = 0;
if (MsgPtr->Msg.DataLength > 8)
MsgPtr->Msg.DataLength = 8;
// Put PDUFormat into the structure to match the J1939-CAN format. This
// involves splitting the original value in PDUFormat into two pieces,
// leaving some holes for the TXBnSIDL register, and setting the EXIDE bit.
// oldSIDL = MsgPtr->Msg.PDUFormat;
MsgPtr->Msg.PDUFormat_Top = MsgPtr->Msg.PDUFormat >> 5; // Put the top three bits into SID5-3
Temp = MsgPtr->Msg.PDUFormat & 0x03; // Save the bottom two bits.
MsgPtr->Msg.PDUFormat = (MsgPtr->Msg.PDUFormat & 0x1C) << 3;// Move up bits 4-2 into SID2-0.
MsgPtr->Msg.PDUFormat |= Temp | 0x08; // Put back EID17-16, set EXIDE.
// Decide which transmit buffer to use. Lower chip select, and then
// do a Read Status command. Look at the transmit status bits
// to see which buffer is ready. We may need a time-out here.
MCP_Load = 0;
while (MCP_Load == 0)
{
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_READ_STATUS );
READSPI( Temp );
#else
WriteSPI( MCP_READ_STATUS );
Temp = ReadSPI();
#endif
UNSELECT_MCP;
if (!(Temp & 0x04))
{
MCP_Load = MCP_LOAD_TX0;
MCP_Send = MCP_RTS_TX0;
}
else if (!(Temp & 0x10))
{
MCP_Load = MCP_LOAD_TX1;
MCP_Send = MCP_RTS_TX1;
}
}
// Load the message buffer. Lower the chip select line, and point
// the loader to TXB0SIDH. Send out the first 5 bytes of the message,
// then send out whatever part of the data is necessary. Then raise
// the chip select line.
SELECT_MCP;
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( MCP_Load );
#else
WriteSPI( MCP_Load );
#endif
for (Loop=0; Loop<J1939_MSG_LENGTH+MsgPtr->Msg.DataLength; Loop++)
{
Temp = MsgPtr->Array[Loop];
#ifdef SPI_USE_ONLY_INLINE_DEFINITIONS
WRITESPI( Temp );
#else
WriteSPI( Temp );
#endif
}
UNSELECT_MCP;
// Now tell the MCP to send the message. Lower the chip select line,
// and send the RTS command for the selected buffer. Then raise the
// chip select line.
SELECT_MCP;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -