📄 main.c
字号:
#include <pic16f87x.h> //定义PIC16F877相关寄存器的地址
#include <mcp2510.h> // MCP2510寄存器定义,主要定义寄存器的地址
// =========常数和变量定义=========
#define READ 0x03 // 读MCP2510指令代码
#define WRITE 0x02 // 写MCP2510指令代码
#define RESET 0xC0 // 复位MCP2510指令代码
#define RTS 0x80 // MCP2510请求发送指令代码
#define STA2510 0xA0 // 读MCP2510状态指令代码
#define BITMOD 0x05 // MCP2510位修改指令代码
int a[12]; // SPI发送或接收数据寄存器
int b[8]; //发送或接收的数据
int c[8]; //发送或接收的数据
int i; // 临时变量
int count; // 发送接收计数器
int count1=0; // 用于测试
int RecID_H=0;
int RecID_L=0;
int DLC=8;
void SPIINT(); //定义SPI中断函数
void TMR1INT(); //定义定时器中断函数
void CCP1INT(); //定义CCP中断函数
void SPIEXCHANGE(int count); //执行SPI传送
void WAIT_SPI(); //SPI访问延时函数
void RESET2510(); //复位MCP2510函数
int RD2510(int adress,int n); // MCP2510读函数
void WR2510(int adress,int n); //MCP2510写函数
void RTS2510(int RTSn); //MCP2510复位函数
int GETS2510(); //读取MCP2510芯片状态
void BM2510(int adress,int mask,int data); //位修改操作函数
void SETNORMAL(); //设置MCP2510为正常模式函数
void TXCOMPLETE(int adress); //判断是否发送完毕
void TXMSG(int DLC); //发送报文函数
int RXMSG(); //接收报文函数
void INIT2510(); //初始化MCP2510函数
void INIT877(); //初始化PIC16F877函数
void INITSPI(); //初始化SPI函数
void ACK(); //应答函数
void wait(); //等待延时延时
// =========================主程序======= ======================================
/*主要的操作流程为:使能相关的中断、SPI、定时器,打开中断;初始化PIC16F877微处理器;初始化SPI接口;初始化MCP2510 CAN控制器;执行接收发送报文循环。*/
main(void)
{
int l,detect=0;
SSPIE=1; //使能SSP中断
TMR1IE=1; //使能定时器中断
CCP1IE=1; //使能CCP1中断
CCP2IE=1; //使能CCP2中断
PEIE=1; //使能所有未屏蔽的外围器件
ei(); //开中断
INIT877(); //初始化PIC16F877微处理器
INITSPI(); //初始化SPI接口
INIT2510(); //初始化MCP2510 CAN控制器
flag1=0;
flag2=0;
CCP1CON=0x05; //CCP捕捉模式,每个上升沿
CCP2CON=0x04; //CCP捕捉模式,每个下降沿
while(1) {
RXMSG(); //接收报文
TXMSG(8); //发送报文
}
}
// =====================中断服务程序==========================================
// SPI中断服务子程序:首先设定SSPIF=0;将SSPBUF寄存器的值暂存在a[]中,
void SPIINT()
{
SSPIF=0; //SSP中断标志位
a[i++]=SSPBUF; //SSP是MCU的SPI数据寄存器,数据暂存a[]中
count-=1;
if(count>0) SSPBUF=a[i]; //未发送完,继续
else RE2=1; //否则,片选信号置高电平
return;
}
//定时器TMR1中断服务子程序
void TMR1INT()
{
TMR1IF=0;
T1CON=0;
if(!flag1){
TMR1H=0xfe; // 512 μs 脉冲宽度
TMR1L=0x00;
T1CON=0x01;
PORTD=0xff; // 输出所有通道
flag1=1;
}
else {
flag1=0;
PORTD=0;
T1CON=0;
}
return;
}
// CCP1中断服务子程序
void CCP1INT()
{
CCP1IF=0;
T1CON=0x01; //使能定时器1
return;
}
// CCP2中断服务子程序
void CCP2INT()
{
CCP2IF=0;
T2CON=0x01; //使能定时器2
return;
}
//中断入口,保护现场,判中断类型
void interrupt INTS()
{
di();
if(TMR1IF) TMR1INT(); // 定时器TMR1中断
else if(CCP1IF) CCP1INT(); // 电压过零捕捉中断1
else if(CCP2IF) CCP2INT(); // 电压过零捕捉中断2
else if(SSPIF) SPIINT(); // SPI接口中断
ei();
}
// ================================子程序分析======= =============================
/*****************************************************************************************
启动SPI传送,判断count是否大于0,若大于0说明有数据传送;然后将变量a[]中的数据依次放入到SSPBUFF寄存器中。若count等于0,则直接返回。
*****************************************************************************************/
void SPIEXCHANGE(count)
int count;
{
if(count>0)
{ //有数据可送?
i=0;
RE2=0; //片选位置低电平,启动MCP2510
SSPBUF=a[i]; //送数,将a[i]中的数值放入SSPBUF寄存器中
count-=count; //count递减
}
else
; //否则,空操作,并返回
return;
}
/*****************************************************************************************
等待SPI传送完成,判断count是否为0,若为0,则延时完成。
*****************************************************************************************/
void WAIT_SPI()
{
do{
;
}while(count>0); // 当count!=0时,等待 to add "CLRWDT"
return;
}
/*****************************************************************************************
对MCP2510芯片进行复位 ,复位操作就是通过SPI的传送函数,将RESET指令写入到MCP2510中。这个函数主要实现了MCP2510复位指令的操作,主要通过调用SPIEXCHANGE()函数来实现。具体的流程见图5.11-7。
*****************************************************************************************/
void RESET2510()
{
a[0]=RESET; //将复位指令放入到a[0]中,RESET=0xC0
count=1; //count=1,说明SPIEXCHANGE函数仅仅发送一个字节
SPIEXCHANGE(count); // 送复位指令 ,传送0xC0
WAIT_SPI(); //等待
return;
}
/*****************************************************************************************
读取从地址"adress"开始的寄存器中的数据,共n个,存放在数组b[n]中。操作的过程,首先通过SPI传送函数将READ=0x03指令传送到MCP2510,然后传送要读取的数据的地址,最后从SO引脚读取相应的 数据。参数address为读取的源地址,n是取出数据的数据,b[j]读取数据后放的目的地址。这个函数主要实现了MCP2510读指令的操作,主要通过调用SPIEXCHANGE()函数来实现。具体的流程见图5.11-2。
*****************************************************************************************/
int RD2510(adress,n)
int adress;
int n;
{
int j;
a[0]=READ; //读指令READ=0x03
a[1]=adress; //读操作的目的地址
for(j=0;j<n;j++) //循环语句
a[j+2]=0;
count=n+2; //指令、地址和要得到的数据量n
SPIEXCHANGE(count); //执行SPI传送函数
WAIT_SPI(); //SPI延时函数
for(j=0;j<n;j++)
b[j]=a[j+2]; //读出的数据存到数组b[]中
return;
}
/*****************************************************************************************
向从地址"adress"开始的寄存器写入数据,共n个,数据存放数组b[n]中。操作过程为首先通过SPI的传送函数将WRITE=0x02写入MCP2510;然后写入要写的地址;最后就是要写入的数据。参数:adress:写入的目的地址;n要写入的数目。这个函数主要实现了MCP2510写指令的操作,主要通过调用SPIEXCHANGE()函数来实现。具体的流程见图5.11-3。
****************************************************************************************/
void WR2510(adress,n)
int adress;
int n;
{
int j;
a[0]=WRITE; //读指令WRITE=0x02
a[1]=adress; //要写入的目的地址
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -