⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 can_self.c

📁 CAN总线上挂接两个节点
💻 C
字号:
/**************************************************************************************
项	目:基于CAN总线的收发通信(节点1)
说	明:主程序部分
功	能:CAN总线上挂接两个节点,当其中一个节点(节点1)的按键按下时,除了自身的数码管1、2
		显示加一,还向节点2发送一个远程帧;节点2接收到远程帧后想总线发送一个数据帧,如果
		节点2的按键被按下时,除了自身的数码管1、2显示加一,还会向总线发送数据帧,使得节点
		2的数码管3、4显示与其保持一致。
//      CAN主要参数:       PeliCAN模式,扩展帧EFF模式                         
//      29位标示码结构:发送一个远程帧                          
//      本节点的接收代码寄存器值: 0x55,0x22,0x33,0x44
//		本节点的屏蔽代码寄存器值:0x00,0xff,0x00,0xff;可以接收节点2的数据               
//      目的节点地址:0x11,0x22,0x33,0x44;可以被节点1接收   
模	块: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,即待发送的数据增1
    TXD_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] =  RBSR0;
        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-4显示接收数据子程序		
	}	
}

///////////////////////////////////////////////
//函数:init_mcu
//说明:单片机I/O口初始化
//		主要是各中断寄存器的初始化
//入口:无
//返回:无
///////////////////////////////////////////////
void init_mcu(void)
{
    SJA_RST = 1;	//CAN总线复位管脚复位无效
    SJA_CS = 0;		//CAN总线片选有效
    EX1 = 1;	//开MCU外部中断INT1
    IT1 = 0;	//MCU外部中断INT1设置为电平触发,该中断口连接CAN总线接收中断口
    IT0 = 1;	//MCU外部中断INT0设置为下降沿触发
    EX0 = 1;	//开MCU外部中断INT0
    EA = 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] = 0x55;
    ACRR[1] = 0x22;
    ACRR[2] = 0x33;
    ACRR[3] = 0x44;	

// 接收屏蔽寄存器
    AMRR[0] = 0x00;
    AMRR[1] = 0Xff;
    AMRR[2] = 0x00;
    AMRR[3] = 0xff;	

// 使用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 CAN
    BTR0 = 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   = 0x08;	//MOD.3=0--双滤波器模式
		state  = MODR;
     }
    while( state & 0x01 );
}

///////////////////////////////////////////////
//函数: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 )	//若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] = 0xc8;	//.7=0--扩展帧;.6=1--远程传送请求; 
    TX_buffer[1] = 0x11;	//本帧信息的ID
    TX_buffer[2] = 0x22;
    TX_buffer[3] = 0x33;
    TX_buffer[4] = 0x44;

	//初始化发送数据单元
    TX_buffer[5]  = Txd_data;	//发送的第1个字节数据,也是数码管要显示的数据(计数结果)
    TX_buffer[6]  = 0x22;	//2
    TX_buffer[7]  = 0x33;	//3
    TX_buffer[8]  = 0x44;	//4
    TX_buffer[9]  = 0x55;	//5
    TX_buffer[10] = 0x66;	//6
    TX_buffer[11] = 0x77;	//7
    TX_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,发送缓冲器被锁。等待直到SR.2=1

    LED_RED = !LED_RED;	//熄灭LED1
    LED_GRE = !LED_GRE;	//点亮LED2

	//将待发送的一帧数据信息存入SJA1000的相应寄存器中
    TBSR0  = 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 = 0x01;	//置位发送请求
    EA  = 1; 	//重新开启中断
}

///////////////////////////////////////////////
//函数:delay
//说明:延时子函数
//入口:uchar time:延时时间time us
//返回:无
///////////////////////////////////////////////
void delay(uchar time)
{
    while(time--);
}

///////////////////////////////////////////////
//函数:led_show
//说明:数码管显示函数
//		注意控制P2口的高4位时,不要影响P2口的低4位值
//入口:uchar wela:		wela=1--高两位显示发送数据
//						wela=0--低两位显示接收数据
//		uchar number:	要显示的数据
//返回:无
///////////////////////////////////////////////
void led_show(uchar wela,uchar number)  
{
    uchar digit;
    uchar temp;

	if(wela)	//高位显示,即数码管1-2
	{
		temp = 0x7b;	//temp=01111011B
	}
	else		//低位显示,即数码管3-4
	{
		temp = 0xde;	//temp=11011110B
	}

//数码管个位显示
	digit = number%10;
    P0 = led[digit];
	P2 = (temp | 0x0f) & P2;			//开个位
	delay(5);
	P2 = 0xff;	
	P0 = 0xff;			//关闭个位
//数码管十位显示
	number /= 10;
	digit = number%10;
    P2 = ((temp << 4) | 0x0f) & P2;		//开十位
	P0 = led[digit];
	delay(5);
	P2 = 0xff;		//关闭十位
    P0 = 0xff;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -