MCP2515的中文资料网上有很多,此,仅讨论具体的一些使用。先看下,在用ARM(LPC21XX)做控制器的情况下,用GPIO口模拟SPI总线的代码。
1.先看下SPI总线的时序图。
SPI总线有四根线,CS,SCK,MISO,MOSI,是一种环形总线结构,如下图。
CS是片选。
SCK是串行时钟。
MISO是主输入从输出。
MOSI是主输出从输入。
时序图如下:(参照MCP2515的数据手册)
SPI的输入时序:
SPI的输出时序:
2.分析下:
Commands and data are sent to the device via the SI pin, with data being clocked in on the rising edge of SCK. Data is driven out by the MCP2515 (on the SO line) on the falling edge of SCK.
命令和数据通过SI脚发到设备上,数据在SCK的上升沿写入。数据在SCK的下降沿从SO脚输出。
3.相应代码如下:(代码经使用是可行的,给出仅做参考)
/******************************************************************************
*名称: WriteSPI() 写SPI一个字节
*功能: 写SPI一个字节
P0.11 CS
P0.12 SO
P0.13 SI
P1.22 SCK
******************************************************************************/
void WriteSPI (uint8 data)
{
uint8 i;
IO1CLR = IO1CLR | (1 << 22); //SK=0
for ( i="0"; i<8 ;i++ )
{
i = i; //延时
if ( (data & 0x80)==0 )
{
IO0CLR = IO0CLR | (1 << 13); //SI=0
}
else
{
IO0SET = IO0SET | (1 << 13); //SI=1
}
i = i;
IO1SET = IO1SET | (1 << 22); //SK=1
i = i;
data = data << 1;
IO1CLR = IO1CLR | (1 << 22); //SK=0
}
}
/******************************************************************************
*名称: ReadSPI() 读SPI一个字节
*功能: 读SPI一个字节
P0.11 CS
P0.12 SO
P0.13 SI
P1.22 SCK
******************************************************************************/
uint8 ReadSPI ( void )
{
uint8 i;
uint32 bdata1,bdata2;
uint8 cdata = 0;
IO1CLR = IO1CLR | (1 << 22); //SK=0
for ( i="0"; i<8 ;i++ )
{
i = i; //延时
i = i;
IO1SET = IO1SET | (1 << 22); //SK=1
cdata = cdata << 1;
bdata1 = IO0PIN & 0x00001000; //SO
i = i;
bdata2 = IO0PIN & 0x00001000;
if ( bdata1 != bdata2) return 0x00; //验证下
if ( bdata1)
{
cdata = cdata | 0x01;
}
else
{
cdata = cdata & (~0x01);
}
IO1CLR = IO1CLR | (1 << 22); //SK=0
}
return cdata;
}
1.首先,MCP2515的资料都在这,里面有MCP2515的数据手册,一些示例代码,有些代码是可以直接拷贝使用的。
2.SPI指令集
MCP2515有两个接收缓冲器,三个发送缓冲器, SPI 接口。驱动的代码一部分要完成SPI接口的指令集,有表及执行时序。
相应的函数
void MCP2515Reset (void); //复位
uint8 MCP2515Read (uint8 addr); //读
void MCP2515ReadRXBuf (uint8 addr, uint8 *str, uint8 num); //读RX缓冲器
void MCP2515Write (uint8 addr, uint8 data); //写
void MCP2515LoadTXBuf (uint8 addr, uint8 *str, uint8 num); //装载TX缓冲器
void MCP2515ReqTx (uint8 addr); //请求发送报文
uint8 MCP2515RdStus (void); //读状态
uint8 MCP2515RxStus (void); //RX状态
void MCP2515BitModify (uint8 addr, uint8 mask, uint8 data); //位修改
3.就是CAN的收发数据了,共有两个接收缓冲器,三个发送缓冲器,可以通过中断来收发数据,当发送缓冲器满或接收缓冲器有有效数据时产生中断。
BOOL CANSendMsg( int Channel, UINT16 Identifier, UINT8* Msg, UINT8 MsgSize )
BOOL CANGetMsg( int Channel, UINT16* pIdentifier, UINT8* Msg, UINT8* pMsgSize )
注意:一定要确保初始化成功,本人在调试的过程中就遇到,如果初始化没成功,程序会一会执行正确,一会不正常的情况。
改变工作模式时,新的工作模式须等到所有当前报文发送完毕之后才生效。必须通过读取CANSTAT.OPMODE位来验证新的工作模式。
比如:
do
{
MCP2515Write( MCP_CANCTRL, 0x80); //CAN工作在配置模式
j = MCP2515Read( MCP_CANSTAT ) & 0xF0; //验证是否已经进入配置模式
}while(j!=0x80);