對於MCP2515 DataSheet還不太清楚的話,可以看看上一篇針對DataSheet有些說明~
整理一下要如何驅動MCP2515來實現CANBus通訊:
#define CANSTAT 0x0E
#define CANCTRL 0x0F
#define BFPCTRL 0x0C
#define TEC 0x1C
#define REC 0x1D
#define CNF3 0x28
#define CNF2 0x29
#define CNF1 0x2A
#define CANINTE 0x2B
#define CANINTF 0x2C
#define EFLG 0x2D
#define TXRTSCTRL 0x0D
#define RXF0SIDH 0x00
#define RXF0SIDL 0x01
#define RXF0EID8 0x02
#define RXF0EID0 0x03
#define RXF1SIDH 0x04
#define RXF1SIDL 0x05
#define RXF1EID8 0x06
#define RXF1EID0 0x07
#define RXF2SIDH 0x08
#define RXF2SIDL 0x09
#define RXF2EID8 0x0A
#define RXF2EID0 0x0B
#define RXF3SIDH 0x10
#define RXF3SIDL 0x11
#define RXF3EID8 0x12
#define RXF3EID0 0x13
#define RXM0SIDH 0x20
#define RXM0SIDL 0x21
#define RXM0EID8 0x22
#define RXM0EID0 0x23
#define RXM1SIDH 0x24
#define RXM1SIDL 0x25
#define RXM1EID8 0x26
#define RXM1EID0 0x27
#define TXB0CTRL 0x30
#define TXB0SIDH 0x31
#define TXB0SIDL 0x32
#define TXB0EID8 0x33
#define TXB0EID0 0x34
#define TXB0DLC 0x35
#define TXB0D0 0x36
#define TXB0D1 0x37
#define TXB0D2 0x38
#define TXB0D3 0x39
#define TXB0D4 0x3A
#define TXB0D5 0x3B
#define TXB0D6 0x3C
#define TXB0D7 0x3D
#define RXB0CTRL 0x60
#define RXB0SIDH 0x61
#define RXB0SIDL 0x62
#define RXB0EID8 0x63
#define RXB0EID0 0x64
#define RXB0DLC 0x65
#define RXB0D0 0x66
#define RXB0D1 0x67
#define RXB0D2 0x68
#define RXB0D3 0x69
#define RXB0D4 0x6A
#define RXB0D5 0x6B
#define RXB0D6 0x6C
#define RXB0D7 0x6D
/* CNF1 */
#define SJW_1TQ 0x40
#define SJW_2TQ 0x80
#define SJW_3TQ 0x90
#define SJW_4TQ 0xC0
/* CNF2 */
#define BTLMODE_CNF3 0x80
#define BTLMODE_PH1_IPT 0x00
#define SMPL_3X 0x40
#define SMPL_1X 0x00
#define PHSEG1_8TQ 0x38
#define PHSEG1_7TQ 0x30
#define PHSEG1_6TQ 0x28
#define PHSEG1_5TQ 0x20
#define PHSEG1_4TQ 0x18
#define PHSEG1_3TQ 0x10
#define PHSEG1_2TQ 0x08
#define PHSEG1_1TQ 0x00
#define PRSEG_8TQ 0x07
#define PRSEG_7TQ 0x06
#define PRSEG_6TQ 0x05
#define PRSEG_5TQ 0x04
#define PRSEG_4TQ 0x03
#define PRSEG_3TQ 0x02
#define PRSEG_2TQ 0x01
#define PRSEG_1TQ 0x00
/* CNF3 */
#define PHSEG2_8TQ 0x07
#define PHSEG2_7TQ 0x06
#define PHSEG2_6TQ 0x05
#define PHSEG2_5TQ 0x04
#define PHSEG2_4TQ 0x03
#define PHSEG2_3TQ 0x02
#define PHSEG2_2TQ 0x01
#define PHSEG2_1TQ 0x00
#define SOF_ENABLED 0x80
#define WAKFIL_ENABLED 0x40
#define WAKFIL_DISABLED 0x00
#define DLC_0 0x00
#define DLC_1 0x01
#define DLC_2 0x02
#define DLC_3 0x03
#define DLC_4 0x04
#define DLC_5 0x05
#define DLC_6 0x06
#define DLC_7 0x07
#define DLC_8 0x08
#define CAN_RESET 0xC0
#define CAN_READ 0x03
#define CAN_WRITE 0x02
#define CAN_RTS 0x80
#define CAN_RTS_TXB0 0x81
#define CAN_RTS_TXB1 0x82
#define CAN_RTS_TXB2 0x84
#define CAN_RD_STATUS 0xA0
#define CAN_BIT_MODIFY 0x05
#define CAN_RX_STATUS 0xB0
#define CAN_RD_RX_BUFF 0x90
#define CAN_LOAD_TX 0X40
static void StartSPI(void)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
}
static void SPI_Tx(uint8_t data)
{
HAL_SPI_Transmit(&hspi1, &data, 1, 10);
}
static void SPI_Tx(uint8_t data)
{
HAL_SPI_Transmit(&hspi1, &data, 1, 10);
}
static uint8_t SPI_Rx(void)
{
uint8_t retVal;
HAL_SPI_Receive(&hspi1, &retVal, 1, 10);
return retVal;
}
void MCP2515_WriteByte(uint8_t address, uint8_t data)
{
StartSPI();
SPI_Tx(CAN_WRITE);
SPI_Tx(address);
SPI_Tx(data);
StopSPI();
}
uint8_t MCP2515_ReadByte (uint8_t address)
{
uint8_t redata;
StartSPI();
SPI_Tx(CAN_READ);
SPI_Tx(address);
retVal = SPI_Rx();
StopSPI();
return redata;
}
int MCP2515_SetConfigMode(void) //配置模式
{
MCP2515_WriteByte(CANCTRL, 0x80);
uint8_t t = 10;
do { //檢查CANSTAT是否已進入配置模式
if((MCP2515_ReadByte(CANSTAT) & 0xE0) == 0x80)
return 1;
t--;
} while(t > 0);
return 0;
}
int MCP2515_SetNormalMode(void) //正常模式
{
MCP2515_WriteByte(CANCTRL, 0x00);
uint8_t t = 10;
do {
if((MCP2515_ReadByte(CANSTAT) & 0xE0) == 0x00)
return 1;
t--;
} while(t > 0);
return 0;
}
int MCP2515_SetLoopMode(void) //loop mode
{
MCP2515_WriteByte(CANCTRL, 0x40);
uint8_t t = 10;
do {
if((MCP2515_ReadByte(CANSTAT) & 0xE0) == 0x40)
return 1;
t--;
} while(t > 0);
return 0;
}
void MCP2515_ResetBus(void)
{
StartSPI();
SPI_Tx(CAN_RESET);
StopSPI();
}
int MCP2515_InitSys(void)
{
MCP2515_ResetBus(); //Reset
MCP2515_SetConfigMode(); //IntoConfig mode
// Set TQ
MCP2515_WriteByte(CNF1,0x03);
MCP2515_WriteByte(CNF2, 0x80|PHSEG1_3TQ|PRSEG_1TQ);
MCP2515_WriteByte(CNF3, PHSEG2_3TQ);
// Set CANBUS ID
MCP2515_WriteByte(TXB0SIDH, 0x11);
MCP2515_WriteByte(TXB0SIDL, 0xE8); //bit3 EXIDE set 1
MCP2515_WriteByte(TXB0EID8, 0xFF);
MCP2515_WriteByte(TXB0EID0, 0xFF);
// Clear Receive Register
MCP2515_WriteByte(RXB0SIDH, 0x00);
MCP2515_WriteByte(RXB0SIDL, 0x00);
MCP2515_WriteByte(RXB0EID8, 0x00);
MCP2515_WriteByte(RXB0EID0, 0x00);
MCP2515_WriteByte(RXB0CTRL, 0x40);
MCP2515_WriteByte(RXB0DLC, DLC_8);
// Set Filter
MCP2515_WriteByte(RXF0SIDH, 0x11);
MCP2515_WriteByte(RXF0SIDL, 0xE8);
MCP2515_WriteByte(RXF0EID8, 0xFF);
MCP2515_WriteByte(RXF0EID0, 0xFF);
// Set Mask
MCP2515_WriteByte(RXM0SIDH, 0x00);
MCP2515_WriteByte(RXM0SIDL, 0x00);
MCP2515_WriteByte(RXM0EID8, 0x00);
MCP2515_WriteByte(RXM0EID0, 0x00);
// Config Interrupt
MCP2515_WriteByte(CANINTE, 0x01);
MCP2515_WriteByte(CANINTF, 0x00);
// Exit ConfigMode
//MCP2515_SetNormalMode(); //手上有兩組可以設置為正常模式
MCP2515_SetLoopMode();
}
void CAN_SendBuffer(uint8_t *CANTxBUFF,uint8_t len)
{
uint8_t j,dleaytime,count;count = 0;
while(count<len) //Read TXB0CTRL State wait TxREQ clean to 0
{
dleaytime=0;
while((MCP2515_ReadByte(TXB0CTRL)&0x08)&&(dleaytime<50))
{
HAL_Delay(1);dleaytime++;
}
for(j=0;j<8;) //Reload data to TXB0D0-D7
{
MCP2515_WriteByte(TXB0D0+j,CANTxBUFF[count++]);
j++;
if(count>=len)
{
break;
}
}
}
MCP2515_WriteByte(TXB0DLC, 8); //Set DataDLC 這邊將資料長度設為8Byte
StartSPI();
MCP2515_WriteByte(TXB0CTRL, 0x08); //Request Send Data
StopSPI();
}
uint8_t CAN_ReceiveBuffer(uint8_t *CANRXBuff)
{
unsigned char i=0,len=0,temp=0;
temp = MCP2515_ReadByte(CANINTF); //Read Interrupt Register Buffer
if(temp&0x01)
{
len=MCP2515_ReadByte(RXB0DLC);
while(i<len)
{
CANRXBuff[i] = MCP2515_ReadByte(RXB0D0+i);
i++;
}
}
MCP2515_WriteByte(CANINTF, 0x00); //Receive Data Finish , need set 0 to Clear Interrupt Flag
return len;
}
uint8_t CAN_RX_BUFF[8];
uint8_t CAB_TX_BUFF[8] = {0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01};//要傳送的資料
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_SPI1_Init();
State = MCP2515_InitSys(); //初始化MCP2515
while (1)
{
CAN_SendBuffer(CAB_TX_BUFF, 8);
HAL_Delay(1000);
CAN_ReceiveBuffer(CAN_RX_BUFF);
HAL_UART_Transmit(&huart2, (uint8_t *)CAN_RX_BUFF, 8, 100); //透過USART顯示在電腦上
}
}