×
单片机 > 单片机程序设计 > 详情

PIC16F877A在CAN通信中的应用程序

发布时间:2020-06-08 发布时间:
|

PIC16F877A在CAN通信中的应用程序


// ========CAN通信程序=======  
#include     
#include     
#include                // 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    count=n+2;                    // 指令、地址和要得到的数据量n  
    SPIEXCHANGE(count); 
    WAIT_SPI(); 
    for(j=0;j    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    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, SDO:输出,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    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        return 1; 
    } 
    return 0; 





『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机中断源的扩展方法