当前位置:文档之家› CAN单节点的自通信程序

CAN单节点的自通信程序

/****************************************************************************** ********项目:基于CAN总线的自收发通信说明:主程序部分功能:外部按键每按下一次,计数值加一,同时计数值在数码管1、2上显示。

在计数值加一后,会使CAN总线上重新发送数据,此时接收端的计数值也同步更新显示在数码管3、4上(为便于观察,接收显示的值比发送值大3)。

// CAN主要参数: PeliCAN模式,扩展帧EFF模式// 29位标示码结构:// 发送数据结构:计数结果,0x02,0x03,0x04,0x05,0x06,0x07,0x08// 接收数据结构: 待显示数据+其它7个字节的数据// 本节点的接收代码寄存器值: 0x11,0x22,0x33,0x44// 本节点的屏蔽代码寄存器值:0x00,0x00,0x00,0x00;可以接收本节点的数据// 目的节点地址:0x11,0x22,0x33,0x44;可以被本节点接收模块:can_self.c作者:PIAE GROUP注释修改者:特权修改时间:08.6.17.******************************************************************************* *******//***感谢PIAE工作组提供的源码,这里特权根据自己的编程习惯做了一些修改并添加详细注释***/#include <reg52.h>#include <intrins.h>#include "define.h"/////////////////////////////////////////////////函数:inter0_key (外部中断INT0)//说明:INT0按键为计数按键// 每按下一次键,计数值加一//入口:按键中断//返回:按键加一///////////////////////////////////////////////void inter0_key(void) interrupt 0{EA = 0; //关闭中断Txd_data++; //计数结果增1,即待发送的数据增1TXD_flag = 1; //发送数据标志位置位,即重新发送数据以更新数码管的显示数值EA = 1; //重新开启中断}/////////////////////////////////////////////////函数:inter1_can_rxd (外部中断INT1)//说明:接收数据函数,在中断服务程序中调用//入口:无//返回:无///////////////////////////////////////////////void inter1_can_rxd( void ) interrupt 2{uchar state;EA = 0; //关CPU中断IE1 = 0; //由于是中断INT1是电平触发方式,所以需要软件将INT1的中断请求标志IE0清零state = IR; //IR为SJA1000的中断寄存器if( state & 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; //CMR.2=1--接收完毕,释放接收缓冲器state = ALC; //释放仲裁随时捕捉寄存器(读该寄存器即可)state = ECC; //释放错误代码捕捉寄存器(读该寄存器即可)}IER = 0x01; // IER.0=1--接收中断使能EA = 1; //重新开启CPU中断}/////////////////////////////////////////////////函数:main//说明:主函数//入口:无//返回:无///////////////////////////////////////////////void main(void){init_mcu();init_sja1000();while(1){rxd_deal(); //接收处理程序txd_deal(); //发送处理程序led_show(0,Txd_data); //数码管1-2显示发送数据子程序led_show(1,Rxd_data+3); //数码管3-4显示接收数据子程序}}/////////////////////////////////////////////////函数:init_mcu//说明:单片机I/O口初始化// 主要是各中断寄存器的初始化//入口:无//返回:无///////////////////////////////////////////////void init_mcu(void){SJA_RST = 1; //CAN总线复位管脚复位无效SJA_CS = 0; //CAN总线片选有效EX1 = 1; //开MCU外部中断INT1IT1 = 0; //MCU外部中断INT1设置为电平触发,该中断口连接CAN总线接收中断口IT0 = 1; //MCU外部中断INT0设置为下降沿触发EX0 = 1; //开MCU外部中断INT0EA = 1; //开MCU总中断SJA_CS = 1; //CAN总线片选无效,使得对数据总线的操作不会影响SJA1000。

}/////////////////////////////////////////////////函数:init_sja1000//说明:独立CAN控制器SJA1000的初始化//入口:无//返回:无///////////////////////////////////////////////void init_sja1000(void){uchar state;uchar ACRR[4];uchar AMRR[4];// 接收代码寄存器ACRR[0] = 0x11;ACRR[1] = 0x22;ACRR[2] = 0x33;ACRR[3] = 0x44;// 接收屏蔽寄存器,只接收主机发送的信息AMRR[0] = 0x00;AMRR[1] = 0X00;AMRR[2] = 0x00;AMRR[3] = 0x00;// 使用do--while语句确保进入复位模式do{MODR = 0x09; // 设置MOD.0=1--进入复位模式,以便设置相应的寄存器state = MODR;}while( !(state & 0x01) );// 对SJA1000部分寄存器进行初始化设置CDR = 0x88; // CDR为时钟分频器,CDR.3=1--时钟关闭, CDR.7=0---basic CAN, CDR.7=1---Peli CANBTR0 = 0x31; // 总线定时寄存器0 ;总线波特率设定BTR1 = 0x1c; // 总线定时寄存器1 ;总线波特率设定IER = 0x01; // IER.0=1--接收中断使能;IER.1=0--关闭发送中断使能OCR = 0xaa; // 配置输出控制寄存器CMR = 0x04; // 释放接收缓冲器// 初始化接收代码寄存器ACR0 = ACRR[0];ACR1 = ACRR[1];ACR2 = ACRR[2];ACR3 = ACRR[3];// 初始化接收屏蔽寄存器AMR0 = AMRR[0];AMR1 = AMRR[1];AMR2 = AMRR[2];AMR3 = AMRR[3];// 使用do--while语句确保进入自接收模式do{MODR = 0x04; //MOD.2=1--进入自接收模式,MOD.3=0--双滤波器模式state = MODR;}while( !(state & 0x04) );}/////////////////////////////////////////////////函数:rxd_deal//说明:接收处理程序;检测接收标志状态位,// 如果置位则进行接收处理//入口:无//返回:无///////////////////////////////////////////////void rxd_deal(void){if( RXD_flag ) //RXD_flag=0说明无数据可以接收,RXD_flag=1说明有数据可以接收{EA = 0; //关闭CPU中断RXD_flag = 0; //RXD_flag清零,以便下次查询Rxd_data = RX_buffer[5]; //CAN总线要接收的数据,也是要在数码管3-4位置显示的数据EA = 1; //重新开启CPU中断}}/////////////////////////////////////////////////函数:txd_deal//说明:发送处理程序;检测发送标志状态位,// 如果置位则进行发送数据处理//入口:无//返回:无///////////////////////////////////////////////void txd_deal(void){if( TXD_flag == 1 )//若TXD_flag=1,要求进行数据的发送处理{_nop_();TXD_flag = 0; //RXD_flag清零,以便下次查询can_txd(); //发送数据帧_nop_();_nop_();} //发送数据帧后,SJA1000将产生接收中断}/////////////////////////////////////////////////函数:can_txd//说明:发送扩展数据帧//入口:无//返回:无///////////////////////////////////////////////void can_txd(void){uchar state;uchar TX_buffer[ N_can ] ; //N_can=13,TX_buffer数组为待传送的数据帧//初始化标示码头信息TX_buffer[0] = 0x88; //.7=0--扩展帧;.6=0--数据帧; .0-.3=100--数据长度为8字节TX_buffer[1] = 0x11; //本节点地址TX_buffer[2] = 0x22;TX_buffer[3] = 0x33;TX_buffer[4] = 0x44;//初始化发送数据单元TX_buffer[5] = Txd_data; //发送的第1个字节数据,也是数码管要显示的数据(计数结果)TX_buffer[6] = 0x22; //2TX_buffer[7] = 0x33; //3TX_buffer[8] = 0x44; //4TX_buffer[9] = 0x55; //5TX_buffer[10] = 0x66; //6TX_buffer[11] = 0x77; //7TX_buffer[12] = 0x88; //8//初始化数据信息EA = 0; //关中断//查询SJA1000是否处于接收状态,当SJA1000不处于接收状态时才可继续执行do{state = SR; //SR为SJA1000的状态寄存器LED_RED = 0; //点亮LED1}while( state & 0x10 ); //SR.4=1 正在接收,等待//查询SJA1000是否处于发送完毕状态do{state = SR;LED_RED = 0; //点亮LED1}while(!(state & 0x08)); //SR.3=0,发送请求未处理完,等待直到SR.3=1//查询发送缓冲器状态do{state = SR;LED_RED = 0; //点亮LED1}while(!(state & 0x04)); //SR.2=0,发送缓冲器被锁。

相关主题