PIC16F887 SPI CAN 传输,操作MCP2515

时间:2021-10-10 19:36:19

主函数:

#include <pic.h>
#include <mcp2515_887.h>
#include <Can_887.h>

#define uchar unsigned char
#define uint unsigned int
#define nop() asm("nop")
#define CS RD1//标签为CANCSRH4
#define RESET RD0 //标签为RESETCAN

__CONFIG (CP_OFF &WDTE_OFF& BOREN_OFF&PWRTE_OFF &FOSC_HS&WRT_OFF&LVP_OFF&CPD_OFF);

void Init_Int(void);//初始化中断
void Init_Can(void);//初始化CAN通讯
void interrupt ISR(void);//中断处理函数
void delay(unsigned int n);//毫秒延时函数
void CAN_Set_Var(uchar address,uchar mask,uchar dat);//修改寄存器的值,mask为掩码
void Init_Spi(void);//初始化SPI
void SPISendByte(unsigned char dat);//SPI 发送一个字节数据
char SPIRecvByte(void);//SPI 读取一个字节数据
void CAN_Write_SS(uchar address ,uchar Value);//往MCP2515写一个字节数
char CAN_Read_SS(uchar address);//从MCP2515读一个字节数
//void CAN_Send_End(void);//CAN发送程序
void CAN_Send(unsigned char *CAN_TX_Buf);//发送数据
void SPIReset(void);//SPI复位
void CAN_writetxb0id(unsigned int txb0id);

unsigned char dummy;
unsigned char cansentbuf[8];
unsigned char canrecbuf[8];

void main()
{

Init_Int();//初始化中断

//SPI init
Init_Spi();//初始化SPI

//can init
RESET=0;
delay(100);
RESET=1;
delay(100);



Init_Can();//初始化CAN通讯

CAN_writetxb0id(0x0025);
cansentbuf[0]=1;
cansentbuf[1]=0;
cansentbuf[2]=0x29;
cansentbuf[3]=0;
cansentbuf[4]=0;
cansentbuf[5]=0;
cansentbuf[6]=0;
cansentbuf[7]=0;
//for(bats2chloop=3;bats2chloop<8;bats2chloop++)
//{
//cansentbuf[bats2chloop]=0;
//}
//cansentbuf[5]=batleft;
//cansentbuf[6]=batright;


/*发一帧数据*/
CAN_Send(cansentbuf);


while(1)
{
//发送数据
CAN_writetxb0id(0x0025);//帧ID
//cansentbuf[0]=1;
//cansentbuf[1]=0;
//cansentbuf[2]=0x29;
//cansentbuf[3]=0;
//cansentbuf[4]=0;
//cansentbuf[5]=0;
//cansentbuf[6]=0;
//cansentbuf[7]=0;
CAN_Send(cansentbuf);

//CAN_Send(cansentbuf);
//delay(100);

//SPISendByte(0XAA);
//SPISendByte(0X00);
//SPISendByte(0X00);
delay(100);
}


}


//初始化中断
void Init_Int(void)
{
OPTION_REG = 0b00000000;//B口弱上拉,RB0为下降沿触发中断
TRISB = 0b00000001;//设定RB0为输入,其余为输出
INTCON = 0b10010000;//允许RB0/INT中断
}

//初始化SPI
void Init_Spi(void)
{
TRISC=0b00010000;//RC5/SDO为输出,RD4/SDI为输入,RC3/SCK为输出

//SSPSTAT_SMP=0;//在数据输出时间的中间采样输入数据
//CKE:SPI 时钟边沿选择位   CKP = 0: STAT_CKE=1 在SCK 引脚的上升沿发送数据
//SSPSTAT=0X80;//在数据输出时间的末尾采样输入数据
SSPSTAT=0X40;//在数据输出时间的中间采样输入数据  bit 7,SMP=0,采样位

//SSPEN=1;//SPI串口使能
//CKP=0;//空闲时钟为低电平
//SSPCON+=0b0001;//SPI主控模式,时钟为Fosc/16
/*SSPEN=1;使能串行端口;CKP=2,时钟空闲状态为高电平
SSPM<3:0>=0001,主控模式,时钟=Fosc/16
*/
//SSPCON=0x31;
SSPCON=0x21;//bit 4,CKP:时钟极性选择位,0 = 时钟空闲状态为低电平

TRISD=0b00000000;//RD1输出;RD0输出;
}



//中断服务程序
void interrupt ISR(void)
{
//if(INTF==1)//如果是INT中断才执行以下程序
//{
//
//INTF==1;//清中断标志位
//}

uchar Sta_Int,i;
Sta_Int=CAN_Read_SS(0X2C);//读中断标志寄存器
CAN_Write_SS(0X2C,0x00);//清除所有中断标志位

/*如果为接收缓冲器0中断*/
if(Sta_Int & 0x01)
{
for(i=0;i<12;i++)
{
//Put_Char(CAN_Read_SS(0x60+i));
}
//com_fs=com_fs+12
}

}

//延时(n)ms
void delay(unsigned int n)
{
unsigned int j;
char k;
for(j=0;j<n;j++)
for(k=246;k>0;k--)
nop();
}








//SPI 读取一个字节数据
char SPIRecvByte(void)
{
//从MISO线上读取一个数据字节
char BUF;
//SPISendByte(0x01);
//SPISendByte(0x80|0x00);
//nop();//延时
//SPISendByte(0);//给SSPBUF一个0,才能开始读取SSPBUF的数据

SSPBUF=0x00;
delay(2);
BUF=SSPBUF;
delay(20);

return BUF;
}

//SPI 发送一个字节数据
void SPISendByte(unsigned char dat)
{
SSPBUF=dat;//往缓冲里面写入dat
//while(!SSPIF)//等待写入成功
//SSPIF=0;//SSPIF清零
delay(20);
}

//往MCP2515指定地址addr写一个字节数据value
void CAN_Write_SS(uchar address ,uchar Value)
{
CS=0;
SPISendByte(0x02);//写命令
SPISendByte(address);//写地址
SPISendByte(Value);//写数据
CS=1;
}


//从MCP2515指定地址addr读取一个字节数据value
char CAN_Read_SS(uchar address)
{
char BUF;
CS=0;
//delay(5);

SPISendByte(0x03);//读命令
SPISendByte(address);//读地址
BUF=SPIRecvByte();//读一个字节数据
CS=1;
return BUF;
}

//SPI复位
void SPIReset(void)
{
//CS=LOW;
//WriteSPI(CAN_RESET);
//CS=HIGH;
CS=0;
SSPBUF=0XC0;//CAN_RESET=0XC0
//RESET=1;
//RESET=0;
delay(20);
//RESET=1;
CS=1;
}

/**修改寄存器的值**/
//mask为掩码
void CAN_Set_Var(uchar address,uchar mask,uchar dat)
{
//CS=1;//片选
//delay(10);
CS=0;
delay(10);
SPISendByte(0x05);//位修改命令 CAN_BIT_MODIFY
//CANCTRL——CAN 控制寄存器(地址:XFh)
SPISendByte(address);//地址为0fH
SPISendByte(mask);//掩码为E0H,修改CANCTRL的高三位
SPISendByte(dat);
CS=1;//片选
}


//初始化CAN通讯
void Init_Can(void)
{
/**复位MCP2515**/
SPIReset();
delay(20);

/**设置为配置模式**/
//CAN_Set_Var(0x0F,0XE0,0X80);

CAN_Write_SS(RXM0SIDH, 0x00);
CAN_Write_SS(RXM0SIDL,0x00);

CAN_Write_SS(RXF0SIDH,0x00);
CAN_Write_SS(RXF0SIDL,0x00);

/**设置通讯速率 晶振16M 速率125K**/
//CAN_Write_SS(0x2A,0X03);
//CAN_Write_SS(0x29,0XB9);
//CAN_Write_SS(0x28,0X04);

//设置波特率为125Kbps
//set CNF1,SJW=00,长度为1TQ,BRP=49,TQ=[2*(BRP+1)]/Fsoc=2*50/8M=12.5us,16M
CAN_Write_SS(CNF1,CAN_125Kbps);//CNF1=0X03
//set CNF2,SAM=0,在采样点对总线进行一次采样,PHSEG1=(2+1)TQ=3TQ,PRSEG=(0+1)TQ=1TQ
CAN_Write_SS(CNF2,0x80|PHSEG1_3TQ|PRSEG_1TQ);//3,1;6,2
//set CNF3,PHSEG2=(2+1)TQ=3TQ,同时当CANCTRL.CLKEN=1时设定CLKOUT引脚为时间输出使能位
CAN_Write_SS(CNF3,PHSEG2_3TQ);//3;7

//set TXB0,设置发送缓冲器0的标识符和发送的数据,以及发送的数据长度
CAN_Write_SS(TXB0SIDH,0x06);//设置发送缓冲器0的标准标识符,待修改***
CAN_Write_SS(TXB0SIDL,0x00);//用到标准标识符
CAN_Write_SS(TXB0DLC,DLC_8);//设置发送数据的长度为8个字节,DLC_1
//CAN_Write_SS(TXB0D0,0x1E);//有待修改及确定是否使用
//CAN_Write_SS(TXB0D1,0x10);//有待修改及确定是否使用

/*set TXB1
CAN_Write_SS(TXB1SIDH,0x50); //Set TXB0 SIDH
CAN_Write_SS(TXB1SIDL,0x00); //Set TXB0 SIDL
CAN_Write_SS(TXB1DLC,0x40 | DLC_8); //Set DLC = 3 bytes and RTR bit*/


//设置接收缓冲器0的标识符和初始化数据
CAN_Write_SS(RXB0SIDH,0x00);//设置接收缓冲器0的标准标识符,待修改***
CAN_Write_SS(RXB0SIDL,0x60);//用到标准标识符
CAN_Write_SS(RXB0CTRL,0x60);//仅仅接收标准标识符的有效信息,FIILHIT0=0表示RXB0 ,采用FILHIT0
CAN_Write_SS(RXB0DLC,DLC_8);//设置接收数据的长度为8个字节

CAN_Write_SS(RXF0SIDH,0xFF);//初始化接收滤波器0,待修改***
CAN_Write_SS(RXF0SIDL,0xE0);
CAN_Write_SS(RXM0SIDH,0xFF);//初始化接收屏蔽器0,待修改***
CAN_Write_SS(RXM0SIDL,0xE0);

//设置接收缓冲器0中断
CAN_Write_SS(CANINTF,0x00);//清空中断标志位
CAN_Write_SS(CANINTE,0x01);//接收缓冲器0满中断使能位

CAN_Write_SS(CANCTRL,REQOP_NORMAL | CLKOUT_ENABLED);//设置正常模式

delay(10);
dummy=CAN_Read_SS(CANSTAT);
if (OPMODE_NORMAL != (dummy && 0xE0))
CAN_Write_SS(CANCTRL,REQOP_NORMAL | CLKOUT_ENABLED);//判断进入正常工作模式
//CAN_Write_SS(CANCTRL,0x00);//选定正常工作模式



////0x00 仅接收标准或扩展标识符
////0x60 关闭接收所有数据
//CAN_Write_SS(0x60,0X60);
//
////滤波
//CAN_Write_SS(0x00,0);
//CAN_Write_SS(0x01,0);
//CAN_Write_SS(0x02,0);
//CAN_Write_SS(0x03,0);
//
////屏蔽
//CAN_Write_SS(0x20,0);
//CAN_Write_SS(0x21,0);
//CAN_Write_SS(0x22,0);
//
////接收数据产生中断
//CAN_Write_SS(0x2B,0X01);
//
////环回模式
////CAN_Set_Var(0x0F,0XE0,0X40);
////工作模式
//CAN_Set_Var(0x0F,0XE0,0);
}


void CAN_writetxb0id(unsigned int txb0id)
{
CAN_Write_SS(TXB0SIDH,(txb0id>>3));//设置发送缓冲器0的标准标识符,待修改***
CAN_Write_SS(TXB0SIDL,(0x00FF&(txb0id<<5)));//用到标准标识符
}




//CAN发送数据程序
void CAN_Send(unsigned char *CAN_TX_Buf)
{
unsigned char tempdata;
tempdata=CAN_Read_SS(CAN_RD_STATUS);
CAN_Write_SS(TXB0D0,CAN_TX_Buf[0]);
CAN_Write_SS(TXB0D1,CAN_TX_Buf[1]);
CAN_Write_SS(TXB0D2,CAN_TX_Buf[2]);
CAN_Write_SS(TXB0D3,CAN_TX_Buf[3]);
CAN_Write_SS(TXB0D4,CAN_TX_Buf[4]);
CAN_Write_SS(TXB0D5,CAN_TX_Buf[5]);
CAN_Write_SS(TXB0D6,CAN_TX_Buf[6]);
CAN_Write_SS(TXB0D7,CAN_TX_Buf[7]);
if(tempdata&0x04)//判断TXREQ标志位
{
delay(5);
CAN_Write_SS(TXB0CTRL,0);//清除TXREQ标志位
while(CAN_Read_SS(CAN_RD_STATUS)&0x04);//等待TXREQ清零
}
CS=0;
SPISendByte(CAN_RTS_TXB0);//发送缓冲器0请求发送
CS=1;
}
头文件1:

#ifndef__CAN_H__
#define__CAN_H__
//write your header here

#include <pic.h>

#define CAN_10Kbps 0x31
#define CAN_25Kbps 0x13
#define CAN_50Kbps 0x09
#define CAN_100Kbps 0x04
#define CAN_125Kbps 0x07
#define CAN_250Kbps 0x01
#define CAN_500Kbps 0x00
#endif

头文件2:

#ifndef__2515_h__
#define__2515_h__
//write your header here
//#pragma nolist
/*********************************************************************
* CAN MCP2510 C definitions file *
*********************************************************************
* Filename: 2515REGS.h *
* Date: 06/17/03 *
* File Version: 1.00 (Beta) *
*********************************************************************
* Functions: *
* Header file *
*********************************************************************
* Revision History: *
* 06/17/03 Updated from MCP2510.inc which was for the 756 board *
*********************************************************************/


/*******************************************************************
* Register Definitions *
*******************************************************************/

/* Configuration Registers */
#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

/* Recieve Filters */
#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 RXF4SIDH 0x14
#define RXF4SIDL 0x15
#define RXF4EID8 0x16
#define RXF4EID0 0x17
#define RXF5SIDH 0x18
#define RXF5SIDL 0x19
#define RXF5EID8 0x1A
#define RXF5EID0 0x1B

/* Receive Masks */
#define RXM0SIDH 0x20
#define RXM0SIDL 0x21
#define RXM0EID8 0x22
#define RXM0EID0 0x23
#define RXM1SIDH 0x24
#define RXM1SIDL 0x25
#define RXM1EID8 0x26
#define RXM1EID0 0x27

/* Tx Buffer 0 */
#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

/* Tx Buffer 1 */
#define TXB1CTRL 0x40
#define TXB1SIDH 0x41
#define TXB1SIDL 0x42
#define TXB1EID8 0x43
#define TXB1EID0 0x44
#define TXB1DLC 0x45
#define TXB1D0 0x46
#define TXB1D1 0x47
#define TXB1D2 0x48
#define TXB1D3 0x49
#define TXB1D4 0x4A
#define TXB1D5 0x4B
#define TXB1D6 0x4C
#define TXB1D7 0x4D

/* Tx Buffer 2 */
#define TXB2CTRL 0x50
#define TXB2SIDH 0x51
#define TXB2SIDL 0x52
#define TXB2EID8 0x53
#define TXB2EID0 0x54
#define TXB2DLC 0x55
#define TXB2D0 0x56
#define TXB2D1 0x57
#define TXB2D2 0x58
#define TXB2D3 0x59
#define TXB2D4 0x5A
#define TXB2D5 0x5B
#define TXB2D6 0x5C
#define TXB2D7 0x5D

/* Rx Buffer 0 */
#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

/* Rx Buffer 1 */
#define RXB1CTRL 0x70
#define RXB1SIDH 0x71
#define RXB1SIDL 0x72
#define RXB1EID8 0x73
#define RXB1EID0 0x74
#define RXB1DLC 0x75
#define RXB1D0 0x76
#define RXB1D1 0x77
#define RXB1D2 0x78
#define RXB1D3 0x79
#define RXB1D4 0x7A
#define RXB1D5 0x7B
#define RXB1D6 0x7C
#define RXB1D7 0x7D


/*******************************************************************
* Bit register masks *
*******************************************************************/

/* TXBnCTRL */
#define TXREQ 0x08
#define TXP 0x03

/* RXBnCTRL */
#define RXM 0x60
#define BUKT 0x04

/* CANCTRL */
#define REQOP 0xE0
#define ABAT 0x10
#defineOSM 0x08
#define CLKEN 0x04
#define CLKPRE 0x03

/* CANSTAT */
#define REQOP 0xE0
#define ICOD 0x0E

/* CANINTE */
#define RX0IE 0x01
#define RX1IE 0x02
#define TX0IEE 0x04
#define TX1IEE 0x80
#define TX2IEE 0x10
#define ERRIE 0x20
#define WAKIE 0x40
#define MERRE 0x80

/* CANINTF */
#define RX0IF 0x01
#define RX1IF 0x02
#define TX0IFF 0x04
#define TX1IFF 0x80
#define TX2IFF 0x10
#define ERRIF 0x20
#define WAKIF 0x40
#define MERRF 0x80

/* BFPCTRL */
#define B1BFS 0x20
#define B0BFS 0x10
#define B1BFE 0x08
#define B0BFE 0x04
#define B1BFM 0x02
#define B0BFM 0x01

/* CNF1 Masks */
#define SJW 0xC0
#define BRP 0x3F

/* CNF2 Masks */
#define BTLMODE 0x80
#define SAM 0x40
#define PHSEG1 0x38
#define PRSEG 0x07

/* CNF3 Masks */
#define WAKFIL 0x40
#define PHSEG2 0x07

/* TXRTSCTRL Masks */
#define TXB2RTS 0x04
#define TXB1RTS 0x02
#define TXB0RTS 0x01


/*******************************************************************
* Bit Timing Configuration *
*******************************************************************/

/* 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


/*******************************************************************
* Control/Configuration Registers *
*******************************************************************/

/* CANINTE */
#define RX0IE_ENABLED 0x01
#define RX0IE_DISABLED 0x00
#define RX1IE_ENABLED 0x02
#define RX1IE_DISABLED 0x00
#define G_RXIE_ENABLED 0x03
#define G_RXIE_DISABLED 0x00

#define TX0IE_ENABLED 0x04
#define TX0IE_DISABLED 0x00
#define TX1IE_ENABLED 0x08
#define TX2IE_DISABLED 0x00
#define TX2IE_ENABLED 0x10
#define TX2IE_DISABLED 0x00
#define G_TXIE_ENABLED 0x1C
#define G_TXIE_DISABLED 0x00

#define ERRIE_ENABLED 0x20
#define ERRIE_DISABLED 0x00
#define WAKIE_ENABLED 0x40
#define WAKIE_DISABLED 0x00
#define IVRE_ENABLED 0x80
#define IVRE_DISABLED 0x00

/* CANINTF */
#define RX0IF_SET 0x01
#define RX0IF_RESET 0x00
#define RX1IF_SET 0x02
#define RX1IF_RESET 0x00
#define TX0IF_SET 0x04
#define TX0IF_RESET 0x00
#define TX1IF_SET 0x08
#define TX2IF_RESET 0x00
#define TX2IF_SET 0x10
#define TX2IF_RESET 0x00
#define ERRIF_SET 0x20
#define ERRIF_RESET 0x00
#define WAKIF_SET 0x40
#define WAKIF_RESET 0x00
#define IVRF_SET 0x80
#define IVRF_RESET 0x00

/* CANCTRL */
#define REQOP_CONFIG 0x80
#define REQOP_LISTEN 0x60
#define REQOP_LOOPBACK 0x40
#define REQOP_SLEEP 0x20
#define REQOP_NORMAL 0x00

#define ABORT 0x10

#define OSM_ENABLED 0x08

#define CLKOUT_ENABLED 0x04
#define CLKOUT_DISABLED 0x00
#define CLKOUT_PRE_8 0x03
#define CLKOUT_PRE_4 0x02
#define CLKOUT_PRE_2 0x01
#define CLKOUT_PRE_1 0x00

/* CANSTAT */
#define OPMODE_CONFIG 0x80
#define OPMODE_LISTEN 0x60
#define OPMODE_LOOPBACK 0x40
#define OPMODE_SLEEP 0x20
#define OPMODE_NORMAL 0x00


/* RXBnCTRL */
#define RXM_RCV_ALL 0x60
#define RXM_VALID_EXT 0x40
#define RXM_VALID_STD 0x20
#define RXM_VALID_ALL 0x00

#define RXRTR_REMOTE 0x08
#define RXRTR_NO_REMOTE 0x00

#define BUKT_ROLLOVER 0x04
#define BUKT_NO_ROLLOVER 0x00

#define FILHIT0_FLTR_1 0x01
#define FILHIT0_FLTR_0 0x00

#define FILHIT1_FLTR_5 0x05
#define FILHIT1_FLTR_4 0x04
#define FILHIT1_FLTR_3 0x03
#define FILHIT1_FLTR_2 0x02
#define FILHIT1_FLTR_1 0x01
#define FILHIT1_FLTR_0 0x00


/* TXBnCTRL */
#define TXREQ_SET 0x08
#define TXREQ_CLEAR 0x00

#define TXP_HIGHEST 0x03
#define TXP_INTER_HIGH 0x02
#define TXP_INTER_LOW 0x01
#define TXP_LOWEST 0x00


/*******************************************************************
* Register Bit Masks *
*******************************************************************/

#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


/*******************************************************************
* CAN SPI commands *
*******************************************************************/

#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


/*******************************************************************
* Miscellaneous *
*******************************************************************/

#define DUMMY_BYTE 0x00
#define TXB0 0x31
#define TXB1 0x41
#define TXB2 0x51
#define RXB0 0x61
#define RXB1 0x71
#define EXIDE_SET 0x08
#define EXIDE_RESET 0x00
//#define CS PORTAbits.RA2
#endif

其中:从PIC18移植到PIC16

PIC18:

//SPI init
SSP1STAT=0X00;//80,40
SSP1CON1=0X21;//0x21

PIC16:

//SSPSTAT_SMP=0;//在数据输出时间的中间采样输入数据
//CKE:SPI 时钟边沿选择位 CKP = 0: STAT_CKE=1 在SCK 引脚的上升沿发送数据
//SSPSTAT=0X80;//在数据输出时间的末尾采样输入数据
SSPSTAT=0X40;//在数据输出时间的中间采样输入数据 bit 7,SMP=0,采样位


//SSPEN=1;//SPI串口使能
//CKP=0;//空闲时钟为低电平
//SSPCON+=0b0001;//SPI主控模式,时钟为Fosc/16
/*SSPEN=1;使能串行端口;CKP=2,时钟空闲状态为高电平
SSPM<3:0>=0001,主控模式,时钟=Fosc/16
*/
//SSPCON=0x31;
SSPCON=0x21;//bit 4,CKP:时钟极性选择位,0 = 时钟空闲状态为低电平
PIC16F887 SPI CAN 传输,操作MCP2515