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