CAN总线自收发程序

CAN总线自收发程序 


//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

//描述:

// INT0按键程序+显示程序+CAN自收发程序 &

// 数码管1-2(从右至左)显示本节点计数结果,数码管3-4显示接收到的数据 &

// 十进制显示 &

// CAN主要参数: PeliCAN模式,扩展帧EFF模式 &

// 29位标示码结构: &

// 发送数据结构:计数结果,0x02,0x03,0x04,0x05,0x06,0x07,0x08 &

// 接收数据结构: 待显示数据+其它7个字节的数据 &

// 本节点的地址: 0x11,0x22,0x33,0x00;可以接收全部节点的数据 &

// 目的节点地址:0x01,0x02,0x03,0x00;可以被能接收全部节点数据的节点接收 &



//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

//【声明】 此程序仅用于学习与参考,引用请注明版权和作者信息! &

//【声明】 作者: PIAE小组 &


#include <reg52.h>
#include <intrins.h>
#include <can_selfdef.h>

void INT0_Counter( void ) interrupt 0 using 1
{//INT0按键为计数按键

    EA = 0;
    Txd_data++; //存储计数结果,并为待发送的数据

    TXD_flag = 1;//要发送数据标志位

    EA = 1;
}

void CAN_RXD( void ) interrupt 2
{//接收数据函数,在中断服务程序中调用


    uchar data Judge;
    EA = 0;//关CPU中断

    IE0 = 0;

    Judge = IR;
    if( Judge & 0x01)
    {//IR.0 = 1 接收中断

        RX_buffer[0] = RBSR;
        RX_buffer[1] = RBSR1;
        RX_buffer[2] = RBSR2;
        RX_buffer[3] = RBSR3;
        RX_buffer[4] = RBSR4;
        RX_buffer[5] = RBSR5;
        RX_buffer[6] = RBSR6;
        RX_buffer[7] = RBSR7;
        RX_buffer[8] = RBSR8;
        RX_buffer[9] = RBSR9;
        RX_buffer[10] = RBSR10;
        RX_buffer[11] = RBSR11;
        RX_buffer[12] = RBSR12;
        RXD_flag = 1;//置有接收标志

        CMR = 0X04;
        Judge = ALC;//释放仲裁随时捕捉寄存器

        Judge = ECC;//释放错误代码捕捉寄存器

    }
    IER = 0x01;// .0=1--接收中断使能;

    EA = 1;//打开CPU中断

}

void main(void)
{
//CPU初始化

    SJA_RST = 1;//CAN总线复位管脚,复位无效

    SJA_CS = 0;//CAN总线片选有效

    EX1 = 1;
    IT1 = 0;//CAN总线接收中断

    IT0 = 1;//外部中断0负边沿触发

    EX0 = 1;//打开外部中断0

    EA = 1; //打开总中断

    SJA_CS = 1;//CAN总线片选无效,使对数据总线的操作不会影响SJA1000。

//CPU初始化


    CAN_init( ); //SJA1000初始化,对 SJA1000寄存器的读写是采用外部寄存器寻址方式,所以不需要程序单独控制片选有效无效

    _nop_();
    _nop_();
    while(1)
    {
        _nop_();
        _nop_();
        Rxd_deal();//接收处理程序

        Txd_deal();//发送处理程序

        led_seg7(1,Txd_data);
        led_seg7(3,Rxd_data);

    }

}


//*********************处理函数********************************



void Rxd_deal(void)
{ 接收处理程序//

    if( RXD_flag )
    {
        EA = 0;//关闭CPU中断

        RXD_flag = 0;
        Rxd_data = RX_buffer[5];
        EA = 1;
     }
} 接收处理程序//


void Txd_deal(void)
{//发送处理函数,主要是准备数据,并且调用发送函数

    if( TXD_flag == 1 )
    {
        _nop_();
        TXD_flag = 0;
        TX_buffer[5] = Txd_data;//

        CAN_TXD();
        _nop_();
        _nop_();
     }
}

//*********************处理函数********************************



//*********************CAN子函数***********************


void CAN_init( void )
{//SJA1000 的初始化

    uchar bdata Judge;
    uchar ACRR[4];
    uchar AMRR[4];
    ACRR[0] = 0x11;
    ACRR[1] = 0x22;
    ACRR[2] = 0x33;
    ACRR[3] = 0x44;//接收代码寄存器,节点1

    AMRR[0] = 0xff;
    AMRR[1] = 0Xff;
    AMRR[2] = 0xff;
    AMRR[3] = 0xff;//接收屏蔽寄存器。 只接收主机发送的信息

    do
    {// .0=1---reset MODRe,进入复位模式,以便设置相应的寄存器

     //防止未进入复位模式,重复写入

        MODR = 0x09;
    Judge = MODR ;
    }
    while( !(Judge & 0x01) );
    CDR = 0x88;// CDR.3=1--时钟关闭, .7=0---basic CAN, .7=1---Peli CAN

    BTR0 = 0x31;
    BTR1 = 0x1c;//总线波特率设定

    IER = 0x01;// .0=1--接收中断使能; .1=0--关闭发送中断使能

    OCR = 0xaa;// 配置输出控制寄存器

    CMR = 0x04;//释放接收缓冲器


    ACR = ACRR[0];
    ACR1 = ACRR[1];
    ACR2 = ACRR[2];
    ACR3 = ACRR[3];//初始化标示码


    AMR = AMRR[0];
    AMR1 = AMRR[1];
    AMR2 = AMRR[2];
    AMR3 = AMRR[3];//初始化掩码

    do
    {//确保进入自接收模式

    MODR = 0x04;
    Judge = MODR;
     }
    while( !(Judge & 0x04) );

}//SJA1000 的初始化



void CAN_TXD( void )
{
    uchar data Judge;
    uchar data TX_buffer[ N_can ] ;

//初始化标示码头信息

    TX_buffer[0] = 0x88;//.7=0扩展帧;.6=0数据帧; .3=1数据长度

    TX_buffer[1] = 0x01;//本节点地址

    TX_buffer[2] = 0x02;//

    TX_buffer[3] = 0x03;//

    TX_buffer[4] = 0x00;//

//初始化标示码头信息


//初始化发送数据单元

    TX_buffer[5] = Txd_data;
    TX_buffer[6] = 0x22;
    TX_buffer[7] = 0x33;
    TX_buffer[8] = 0x44;//

    TX_buffer[9] = 0x55;//

    TX_buffer[10] = 0x66;//

    TX_buffer[11] = 0x77;//

    TX_buffer[12] = 0x88;//



//初始化数据信息

    EA = 0; //关中断

    do
    {
        Judge = SR;
        LED_RED = 0;//

    }
    while( Judge & 0x10 ); //SR.4=1 正在接收,等待

    
    do
    {
        Judge = SR;
        LED_RED = 0;//

    }
    while(!(Judge & 0x08)); //SR.3=0,发送请求未处理完,等待


    do
    {
        Judge = SR;
        LED_RED = 0;//

    }
    while(!(Judge & 0x04)); //SR.2=0,发送缓冲器被锁。等待


    LED_RED = !LED_RED;
    LED_GRE = !LED_GRE;//灯闪烁


    TBSR = TX_buffer[0];
    TBSR1 = TX_buffer[1];
    TBSR2 = TX_buffer[2];
    TBSR3 = TX_buffer[3];
    TBSR4 = TX_buffer[4];
    TBSR5 = TX_buffer[5];
    TBSR6 = TX_buffer[6];
    TBSR7 = TX_buffer[7];
    TBSR8 = TX_buffer[8];
    TBSR9 = TX_buffer[9];
    TBSR10 = TX_buffer[10];
    TBSR11 = TX_buffer[11];
    TBSR12 = TX_buffer[12];

    CMR = 0x10;//置位自发送接收请求

    EA = 1;

}

void Delay(uchar delay_time)
{//延时程序

    while(delay_time--)
    {}
}

//*********************CAN子函数*************************


 void led_seg7(uchar from,uchar number) //from(1_4):数码管显示起始位置(从右到左),number:显示的数

{
    uchar digit,temp_l;
    uchar temp_h=0x7f;
    temp_h = _cror_(temp_h,from-1); //确定从哪一位开始显示,即确定高四位

    temp_h = temp_h & 0xf0; //取高四位

    temp_l = P2 & 0x0f; //取P2的低四位

    P2 = temp_h | temp_l; //设定P2口


    if(number==0)
    {
        P0 = led[0];
        Delay(5);
        P0 = 0xff;
    }
    else
    {
        while(number)
    {
            digit = number%10 ;
     number /= 10;
            P0 = led[digit] ;
     Delay(5);
            temp_h = P2 & 0xf0; //取P2的高四位

            temp_h = temp_h | 0x0f; //拼装 temp_h,进行位选

     temp_h = _cror_(temp_h,1);
     temp_h = temp_h & 0xf0; //取高四位

            temp_l = P2 & 0x0f; //取P2的低四位

            P0 = 0xff;
            P2 = temp_h | temp_l; //设定P2口

        }//while结束

    }//else结束

}



------------------------------

//对管脚分配进行了定义

//对子函数进行了声明


# define uchar unsigned char
# define uint unsigned int

# define NOP5        {_nop_();_nop_();_nop_();_nop_();_nop_();}/*延时5us*/

#define N_can 13//一帧字节数

bit TXD_flag = 0;// 若为1,要求发送处理

bit RXD_flag = 0; //有无数据可以接收;0无 ,1有



uchar code led[]={0xC0,0xDE,0xA2,0x8A,0x9C,0x89, 0x81,0xDA,0x80,0x88, 0xFF,0xBF}; // 0,1,2,3,4,5,6, 7, 8, 9, off

             //编码规则是gfedcba ,其中g为小数点,控制dp,这里都设为1,不亮


uchar RX_buffer[13]; //接收的数据

uchar TX_buffer[13]; //接收的数据

uchar Txd_data = 0;//CAN总线要发送的数据,也是要在数码管1-2位置显示的数据

uchar Rxd_data= 0;//CAN总线要接收的数据,也是要在数码管3-4位置显示的数据



/*P1 口分配*/

/*P2 口分配*/
sbit LED_RED = P2^1;
sbit LED_GRE = P2^2;
sbit SJA_RST = P2^3;//SJA1000复位管脚

sbit SJA_CS = P2^0;//SJA1000片选管脚


/*CAN总线SJA1000寄存器地址定义(用的是PeliCAN模式,扩展帧EFF模式)*/
//为什么地址上0xFE00。FE是因为我们有16位的地址线。P0口是低8位地址,P2口是高8位地址。而P20是接的CS端一定要是为0,所以地址是FE.


uchar xdata MODR _at_ 0xFE00;        // 模式寄存器

uchar xdata CMR     _at_ 0xFE01;        // 命令寄存器

uchar xdata SR     _at_ 0xFE02;        // 状态寄存器

uchar xdata IR     _at_ 0xFE03;        // 中断寄存器

uchar xdata IER     _at_ 0xFE04;        // 中断使能寄存器

uchar xdata BTR0     _at_ 0xFE06;        // 总线定时寄存器0 ;总线波特率的选择

uchar xdata BTR1     _at_ 0xFE07;        // 总线定时寄存器1 ;总线波特率的选择

uchar xdata OCR     _at_ 0xFE08;        // 输出控制寄存器

uchar xdata ACR     _at_ 0xFE10;//16;

uchar xdata ACR1     _at_ 0xFE11;//17;

uchar xdata ACR2     _at_ 0xFE12;//18;

uchar xdata ACR3     _at_ 0xFE13;//19;        // 接收代码(0x16_0x19);接收过滤位的选择*******复位模式

uchar xdata AMR     _at_ 0xFE14;//20;

uchar xdata AMR1     _at_ 0xFE15;//21;

uchar xdata AMR2     _at_ 0xFE16;//22;

uchar xdata AMR3     _at_ 0xFE17;//23;        // 掩码(0x20_0x23); 接收过滤位的选择*******复位模式

uchar xdata CDR     _at_ 0xFE1F;//31;        // 时钟分频器

uchar xdata ALC     _at_ 0xFE0B;//11;        // 仲裁丢失捕捉寄存器

uchar xdata ECC     _at_ 0xFE0C;//12;        // 误码捕捉寄存器


uchar xdata TBSR     _at_ 0xFE10;//16;

uchar xdata TBSR1     _at_ 0xFE11;//17;

uchar xdata TBSR2     _at_ 0xFE12;//18;

uchar xdata TBSR3     _at_ 0xFE13;//19;

uchar xdata TBSR4     _at_ 0xFE14;//20;

uchar xdata TBSR5     _at_ 0xFE15;//21;

uchar xdata TBSR6     _at_ 0xFE16;//22;

uchar xdata TBSR7     _at_ 0xFE17;//23;

uchar xdata TBSR8     _at_ 0xFE18;//24;

uchar xdata TBSR9     _at_ 0xFE19;//25;

uchar xdata TBSR10     _at_ 0xFE1A;//26;

uchar xdata TBSR11     _at_ 0xFE1B;//27;

uchar xdata TBSR12     _at_ 0xFE1C;//28;// 发送缓冲器首地址(0x16_0x28)


uchar xdata RBSR     _at_ 0xFE10;//16;

uchar xdata RBSR1     _at_ 0xFE11;//17;

uchar xdata RBSR2     _at_ 0xFE12;//18;

uchar xdata RBSR3     _at_ 0xFE13;//19;

uchar xdata RBSR4     _at_ 0xFE14;//20;

uchar xdata RBSR5     _at_ 0xFE15;//21;

uchar xdata RBSR6     _at_ 0xFE16;//22;

uchar xdata RBSR7     _at_ 0xFE17;//23;

uchar xdata RBSR8     _at_ 0xFE18;//24;

uchar xdata RBSR9     _at_ 0xFE19;//25;

uchar xdata RBSR10     _at_ 0xFE1A;//26;

uchar xdata RBSR11     _at_ 0xFE1B;//27;

uchar xdata RBSR12     _at_ 0xFE1C;//28;// 接收缓冲器首地址(0x16_0x28)




void CAN_init( void ); // 初始化CAN总线芯片

void CAN_TXD( void );//CAN发送子函数

void Rxd_deal(void);//接收处理函数

void Txd_deal(void);//发送处理函数

void Delay(uchar delay_time);//延时子函数

void led_seg7(uchar from,uchar number);//显示子函数





这里要说一点说是在头文件里是如何对绝对地址进行定义的。
51单片机是16位地址的:P0口对应着低8位地址,P2口对应着高8位地址。源理图上,我们将P20接到了。SJA1000的CS选通端上,所以我们的P20一定要为低电平。那们高位地址的第一位要为0。所以我们看到了 uchar xdata MODR _at_ 0xFE00;   这里的FE就是因为P20口为0。
再说明:_at_   表示为绝对地址的定义。
xdata表示外部RAM


本文来源:http://blog.chinaunix.net/uid-22889411-id-59618.html

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值