- 打卡等级:常住居民III
- 打卡总天数:167
- 最近打卡:2025-10-15 15:04:29
高级会员
- 积分
- 776
|
发表于 2025-9-22 14:38:17
|
显示全部楼层
MCP2515.C
#include "mcp2515.h"
// 延时函数(约10us@11.0592MHz)
void Delay10us(unsigned int t)
{
while(t--)
{
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
}
}
// SPI发送一个字节
unsigned char SPI_SendByte(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
MCP2515_SCK = 0; // 时钟线拉低
if(dat & 0x80) MCP2515_MOSI = 1; // 发送高位
else MCP2515_MOSI = 0;
dat <<= 1; // 移位
MCP2515_SCK = 1; // 时钟线拉高,从机采样
}
return 0;
}
// SPI接收一个字节
unsigned char SPI_ReceiveByte(void)
{
unsigned char i, dat=0;
for(i=0;i<8;i++)
{
MCP2515_SCK = 0; // 时钟线拉低
dat <<= 1; // 移位
MCP2515_SCK = 1; // 时钟线拉高
if(MCP2515_MISO) dat |= 0x01; // 接收数据
}
return dat;
}
// 写MCP2515寄存器
void MCP2515_WriteReg(unsigned char addr, unsigned char dat)
{
MCP2515_CS = 0; // 片选拉低
SPI_SendByte(CMD_WRITE); // 发送写命令
SPI_SendByte(addr); // 发送寄存器地址
SPI_SendByte(dat); // 发送数据
MCP2515_CS = 1; // 片选拉高
Delay10us(1);
}
// 读MCP2515寄存器
unsigned char MCP2515_ReadReg(unsigned char addr)
{
unsigned char dat;
MCP2515_CS = 0; // 片选拉低
SPI_SendByte(CMD_READ); // 发送读命令
SPI_SendByte(addr); // 发送寄存器地址
dat = SPI_ReceiveByte(); // 接收数据
MCP2515_CS = 1; // 片选拉高
Delay10us(1);
return dat;
}
// 软件复位MCP2515
void MCP2515_Reset(void)
{
MCP2515_CS = 0;
SPI_SendByte(CMD_RESET);
MCP2515_CS = 1;
Delay10us(100); // 等待复位完成
}
// 设置MCP2515工作模式
unsigned char MCP2515_SetMode(unsigned char mode)
{
unsigned char i;
MCP2515_WriteReg(REG_CANCTRL, mode); // 写入模式配置
Delay10us(10); // 等待模式切换
// 检查模式是否设置成功
for(i=0;i<10;i++)
{
if((MCP2515_ReadReg(REG_CANSTAT) & 0xE0) == (mode & 0xE0))
{
return 0; // 成功
}
Delay10us(10);
}
return 1; // 失败
}
// 初始化MCP2515(500kbps,16MHz晶振)
void MCP2515_Init(void)
{
// 初始化SPI引脚
MCP2515_CS = 1;
MCP2515_SCK = 1;
MCP2515_MOSI = 0;
MCP2515_Reset(); // 软件复位
// 进入配置模式
while(MCP2515_SetMode(MODE_CONFIG));
// 配置波特率(500kbps @16MHz)
MCP2515_WriteReg(REG_CNF1, 0x01); // CNF1: BRP=1 (分频2)
MCP2515_WriteReg(REG_CNF2, 0xB6); // CNF2: 采样点=87.5%
MCP2515_WriteReg(REG_CNF3, 0x05); // CNF3: PHSEG2=6TQ
// 关闭滤波,接收所有标准帧
MCP2515_WriteReg(0x02, 0x00); // RXM0SIDH
MCP2515_WriteReg(0x03, 0x00); // RXM0SIDL
// 使能接收中断
MCP2515_WriteReg(REG_CANINTE, 0x01); // 使能RX0中断
// 进入正常工作模式
MCP2515_SetMode(MODE_NORMAL);
// 初始化外部中断0(接收中断)
IT0 = 1; // 下降沿触发
EX0 = 1; // 使能外部中断0
EA = 1; // 使能总中断
}
// 发送数据(标准帧,ID=0x123)
unsigned char MCP2515_Send(unsigned char *data, unsigned char len)
{
unsigned char i;
// 检查发送缓冲区是否空闲
if(MCP2515_ReadReg(REG_TXB0CTRL) & 0x08)
{
return 1; // 发送缓冲区忙
}
// 限制数据长度(最大8字节)
if(len > 8) len = 8;
// 写入数据到TXB0缓冲区
MCP2515_CS = 0;
SPI_SendByte(CMD_WRITE);
SPI_SendByte(0x31); // TXB0D0地址
// 写入数据
for(i=0;i<len;i++)
{
SPI_SendByte(data);
}
MCP2515_CS = 1;
// 写入标准帧ID(0x123)
MCP2515_WriteReg(0x32, 0x12); // TXB0SIDH
MCP2515_WriteReg(0x33, 0x60); // TXB0SIDL (ID低3位+IDE=0)
MCP2515_WriteReg(0x35, len); // 数据长度
// 请求发送
MCP2515_CS = 0;
SPI_SendByte(CMD_RTS_TX0);
MCP2515_CS = 1;
return 0; // 发送成功
}
// 检查是否有接收数据
unsigned char MCP2515_CheckReceive(void)
{
return (MCP2515_ReadReg(REG_CANINTF) & 0x01); // 检查RX0中断标志
}
// 接收数据
unsigned char MCP2515_Receive(unsigned char *data, unsigned char *len)
{
unsigned char i;
// 检查是否有数据
if(!(MCP2515_ReadReg(REG_CANINTF) & 0x01))
{
return 1; // 无数据
}
// 读取数据长度
MCP2515_CS = 0;
SPI_SendByte(CMD_READ_RX0);
SPI_ReceiveByte(); // 跳过SIDH
SPI_ReceiveByte(); // 跳过SIDL
SPI_ReceiveByte(); // 跳过EID8
SPI_ReceiveByte(); // 跳过EID0
*len = SPI_ReceiveByte() & 0x0F; // 读取数据长度
// 限制最大长度
if(*len > 8) *len = 8;
// 读取数据
for(i=0;i<*len;i++)
{
data = SPI_ReceiveByte();
}
MCP2515_CS = 1;
// 清除中断标志
MCP2515_WriteReg(REG_CANINTF, 0x00);
return 0; // 接收成功
}
// 外部中断0服务函数(接收中断)
void EX0_ISR(void) interrupt 0
{
// 可在这里添加接收提示代码
// 例如:设置接收标志位
}
|
|