|
PIC16F87X在CAN通信中的应用
9.3 软件清单 // ========CAN通信程序======= #include <pic.h> #include <pic16f87x.h> #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; // for test int RecID_H=0; int RecID_L=0; int DLC=8; void SPIINT(); void TMR1INT(); void CCP1INT(); void SPIEXCHANGE(int count); void WAIT_SPI(); void RESET2510(); int RD2510(int adress,int n); void WR2510(int adress,int n); void RTS2510(int RTSn); int GETS2510(); void BM2510(int adress,int mask,int data); void SETNORMAL(); void TXCOMPLETE(int adress); void TXMSG(int DLC); int RXMSG(); void INIT2510(); void INIT877(); void INITSPI(); void ACK(); void wait(); // ========主程序======= main(void) { int l,detect=0; SSPIE=1; TMR1IE=1; CCP1IE=1; CCP2IE=1; PEIE=1; ei(); // 开中断 INIT877(); // 初始化PIC16F877芯片 INITSPI(); // 初始化SPI接口 INIT2510(); // 初始化MCP2510芯片 flag1=0; flag2=0; CCP1CON=0x05; CCP2CON=0x04; while(1) { RXMSG(); TXMSG(8); } } // ========中断服务程序======= // SPI中断服务子程序 void SPIINT() { SSPIF=0; a[i++]=SSPBUF; // 数据暂存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; return; } // CCP2中断服务子程序 void CCP2INT() { CCP2IF=0; T1CON=0x01; 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传送 void SPIEXCHANGE(count) int count; { if(count>0) { // 有数据可送? i=0; RE2=0; // 片选位置低电平 SSPBUF=a[i]; // 送数 } else ; // 否则,空操作,并返回 return; } // 等待SPI传送完成 void WAIT_SPI() { do{ ; }while(count>0); // 当count!=0时,等待 to add "CLRWDT" return; } // 对MCP2510芯片进行复位 void RESET2510() { a[0]=RESET; count=1; SPIEXCHANGE(count); // 送复位指令 WAIT_SPI(); return; } // 读取从地址"adress"开始的寄存器中的数据,共n个,存放在数组b[n]中 int RD2510(adress,n) int adress; int n; { int j; a[0]=READ; a[1]=adress; for(j=0;j<n;j++) a[j+2]=0; count=n+2; // 指令、地址和要得到的数据量n SPIEXCHANGE(count); WAIT_SPI(); for(j=0;j<n;j++) b[j]=a[j+2];// 数据存到数组b[]中 return; } // 向从地址"adress"开始的寄存器写入数据,共n个,数据存放数组b[n]中 void WR2510(adress,n) int adress; int n; { int j; a[0]=WRITE; a[1]=adress; for(j=0;j<n;j++) a[j+2]=b[j]; count=n+2; // 指令、地址和要写入的数据量n SPIEXCHANGE(count); WAIT_SPI(); return; } // MCP2510芯片请求发送程序 void RTS2510(RTSn) int RTSn; { a[0]=RTS^RTSn; count=1; SPIEXCHANGE(count); // 发送MCP2510芯片,请求发送指令 WAIT_SPI(); return; } // 读取MCP2510芯片的状态 int GETS2510() { a[0]=STA2510; a[1]=0; count=2; SPIEXCHANGE(count); // 读取MCP2510芯片状态 WAIT_SPI(); b[0]=a[1]; // 状态存到数组b[]中 return; } // 对MCP2510芯片进行位修改子程序 void BM2510(adress,mask,data) int adress; int mask; int data; { a[0]=BITMOD; // 位修改指令 a[1]=adress; // 位修改寄存器地址 a[2]=mask; // 位修改屏蔽位 a[3]=data; // 位修改数据 count=4; SPIEXCHANGE(count); WAIT_SPI(); return; } // 设置MCP2510芯片为正常操作模式 void SETNORMAL() { int k=1; BM2510(CANCTRL,0xe0,0x00); // 设置为正常操作模式 do { RD2510(CANSTAT,1); k=b[0]&0xe0; }while(k); // 确认已进入正常操作模式 return; } // 对MCP2510进行初始化 void INIT2510() { RESET2510(); // 使芯片复位 b[0]=0x02; b[1]=0x90; b[2]=0x07; WR2510(CNF3,3); // 波特率为 125 kbps b[0]=0x00; b[1]=0x00; WR2510(RXM0SIDH,2); b[0]=0x00; b[1]=0x00; WR2510(RXF0SIDH,2); // RX0接收,屏蔽位为0,过滤器为0 b[0]=0x00; WR2510(CANINTE,1); // CAN中断不使能 SETNORMAL(); // 设置为正常操作模式 return; } // MCP2510芯片发送完成与否判断,邮箱号为adress void TXCOMPLETE(adress) int adress; { int k=1; do { RD2510(adress,1); k=b[0]&0x08; }while(k); // 确认是否已发送完毕 to add CLRWDT return; } // 初始化PIC16F877芯片 void INIT877() { PORTA=0; PORTB=0; PORTC=0; PORTD=0; PORTE=0; TRISA=0xff; TRISB=0xfd; TRISC=0xd7; // SCK, SD输出,SDI:输入 TRISD=0; TRISE=0x03; // 片选CS信号输出 PORTA=0xff; PORTB=0x03; // RST=1 PORTC=0; PORTD=0xff; PORTE=0x04; return; } // 初始化SPI接口 void INITSPI() { SSPCON=0x11; SSPEN=1; // SSP使能 SSPSTAT=0; return; } // 发送数据子程序 void TXMSG(int DLC) { for(i=0;i<DLC;i++) b[i]=c[i]; WR2510(TXB0D0,DLC); b[0]=DLC; WR2510(TXB0DLC,1); b[0]=0x03; b[1]=RecID_H; b[2]=RecID_L; WR2510(TXB0CTRL,3); RTS2510(0x01); // 请求发送 TXCOMPLETE(TXB0CTRL); //等待发送完毕 return; } // 接收数据子程序 int RXMSG() { int k; RD2510(CANINTF,1); k=b[0]&0x01; if(k==1) { BM2510(CANINTF,0x01,0x00); RD2510(RXB0SIDH,2); RecID_H=b[0]; RecID_L=b[1]&0xe0; RD2510(RXB0DLC,1); DLC=b[0]&0x0f; RD2510(RXB0D0,DLC); for(i=0;i<DLC;i++) c[i]=b[i]; return 1; } return 0; }
|