| 
 
| 本帖最后由 futao_uestc 于 2010-6-27 16:00 编辑 
 本人原本打算实现4节点通信问题,A、B、C节点连于总线:单片机通过模拟SPI与2515相连,2515的TXCAN和RXCAN与250相连,250连于总线,终端电阻120欧姆,没有加电容,另外在外部中断1连一按钮,按钮按下发送一数据帧;D节点除了上述连接,在STC自带的SPI通过MAX3232连串口通于计算机。
 现在是测试D节点和B节点的通信,D节点:总线差分电压一直处于1.52~1.44V之间,TXCAN是400mV~-480mV之间,RXCAN是4.08V~4V之间。B节点的CANH和CANL直接与D节点对应相连,RXCAN是800mV~-880mV之间,TXCAN是2.96V~2.8V之间。请问问题是出在哪里,现在用串口助手发数据一直收不到数据??????
 程序是发送两个字节数据,只发送扩展数据帧,并通过数据帧的第一字节判断数据操作,高4位为命令,低4位为节点代号!!!
 
 
 //节点D
 #include<reg51.h>
 
 #define RXFNSIDHADD 0x40  //0x10代表A节点,0x20代表B节点,0x30代表C节点,0x40代表D节点
 #define RXFNSIDH 0x0A  //标准标识符为****1010101,其中最高四位代表节点,扩展标识符为110011001100110011
 #define RXFNSIDL 0xAB  //报文滤波仅用于扩展帧
 #define RXFNEID8 0x33  //屏蔽位全为1
 #define RXFNEID0 0x33
 #define RXMNSIDH 0xFF
 #define RXMNSIDL 0xE3
 #define RXMNEID8 0xFF
 #define RXMNEID0 0xFF
 #define TXBNSIDH 0x0A      //发送数据帧,扩展帧,标识符为****1010101,110011001100110011
 #define TXBNSIDL 0xAB
 #define TXBNEID8 0x33
 #define TXBNEID0 0x33
 #define TXBNDLC 0x02      //数据长度为2
 #define JIEDIAN 0x04    //节点D
 #define MAXNUM 8        //队列长度
 
 //队列结构定义
 typedef struct queue_type
 {
 char queue[ MAXNUM ]; //队列元素
 char front;      //队头指针
 char rear;      //队尾指针
 } queuetype;
 
 void writeuartbuffer( queuetype *queuesed, char datah, char datal );
 void readuartbuffer( queuetype *queuerec );
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 //变量设置
 bit txflag = 0;
 bit rxflag = 0;
 bit errorflag = 0;
 sbit SCK = P2^7;
 sbit SI = P2^6;
 sbit SO = P2^5;
 sbit CS = P2^4;
 sbit RESET = P2^3;
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////
 queuetype *queuerec,*queuesed; //定义接收和发送队列
 //初始化队列
 void initqueue( queuetype *q )
 {
 q->front = 0;
 q->rear = 0;
 }
 //测试队列是否满,检验是否还可以装两个字节
 char queueman( queuetype *q )
 {
 if( ( ( q->rear + 1) % MAXNUM == q->front ) || ( ( q->rear + 2 ) % MAXNUM == q->front) )
 return 1;      //队列已满
 else
 return 0;
 }
 //入队列
 void enterqueue( queuetype *q , char x )
 {
 q->rear = ( q->rear + 1 ) % MAXNUM;
 q->queue[ q->rear ] = x;
 }
 //测试队列是否空,检验队列中是否还有两个字节
 char queuekong( queuetype *q )
 {
 if( ( q->front == q->rear ) || ( q->front == ( q->rear + 1 ) % MAXNUM ) )
 return 1;       //队列为空
 else
 return 0;
 }
 //出队列
 char deletequeue( queuetype *q )
 {
 q->front = ( q->front + 1 ) % MAXNUM;
 return( q->queue[ q->front ] );
 }
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
 void delay( void )
 {
 char i,j;
 for( i = 0; i < 0x0F; i ++ )
 for( j = i; j < 0xFF; j ++);
 }
 void cancomhead( void )
 {
 EA = 0;
 CS = 0;
 }
 void cancomend( void )
 {
 CS = 1;
 EA = 1;
 }
 
 //模拟SPI向外接收一个字节
 char simspiin( void )
 {
 char i, buffer;
 SCK = 1;
 for( i = 0x00; i < 0x08; i ++ )
 {
 SCK = 0;
 buffer = buffer << 1;
 if( SO == 1 )
 buffer = buffer | 0x01;
 else
 buffer = buffer | 0x00;
 SCK = 1;
 }
 return buffer;
 }
 //模拟SPI向外发送一个字节
 void simspiout( char buffer )
 {
 char i;
 SCK = 1;
 for( i = 0x00; i < 0x08; i ++ )
 {
 SCK = 0;
 if( ( buffer & 0x80 ) == 0x00 ) SI = 0;
 else SI = 1;
 SCK = 1;
 buffer = buffer << 1;
 }
 }
 
 //2515复位指令
 void canreset(void)
 {
 cancomhead();
 simspiout( 0xC0 );
 cancomend();
 }
 //2515读指令
 char canread( char add )
 {
 char dat;
 cancomhead();
 simspiout( 0x03 );
 simspiout( add );
 dat = simspiin();
 cancomend();
 return dat;
 }
 //2515写指令
 void canwrite( char add,char dat )
 {
 cancomhead();
 simspiout( 0x02 );
 simspiout( add );
 simspiout( dat );
 cancomend();
 }
 //2515请求发送rts
 void canrts( char txbadd )
 {
 cancomhead();
 simspiout(txbadd);
 cancomend();
 }
 //2515读状态
 char canreadstat( void )
 {
 char dat;
 cancomhead();
 simspiout( 0xA0 );
 dat = simspiin();
 cancomend();
 return dat;
 }
 //2515位修改
 void canbite( char address, char shadow, char dat)
 {
 cancomhead();
 simspiout( 0x05 );
 simspiout( address );
 simspiout( shadow );
 simspiout( dat );
 cancomend();
 }
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //发送数据帧格式设置
 void txinit( void )
 {
 canwrite( 0x32, TXBNSIDL );
 canwrite( 0x42, TXBNSIDL );
 canwrite( 0x52, TXBNSIDL );
 
 canwrite( 0x33, TXBNEID8 );
 canwrite( 0x43, TXBNEID8 );
 canwrite( 0x53, TXBNEID8 );
 
 canwrite( 0x34, TXBNEID0 );
 canwrite( 0x44, TXBNEID0 );
 canwrite( 0x54, TXBNEID0 );
 
 canwrite( 0x35, TXBNDLC );
 canwrite( 0x45, TXBNDLC );
 canwrite( 0x55, TXBNDLC );
 }
 
 //屏蔽和滤波初始化
 void filterinit( void )
 {
 canwrite( 0x00, RXFNSIDHADD+RXFNSIDH );
 canwrite( 0x04, RXFNSIDHADD+RXFNSIDH );
 canwrite( 0x08, RXFNSIDHADD+RXFNSIDH );
 canwrite( 0x10, RXFNSIDHADD+RXFNSIDH );
 canwrite( 0x14, RXFNSIDHADD+RXFNSIDH );
 canwrite( 0x18, RXFNSIDHADD+RXFNSIDH );
 
 canwrite( 0x01, RXFNSIDL );
 canwrite( 0x05, RXFNSIDL );
 canwrite( 0x09, RXFNSIDL );
 canwrite( 0x11, RXFNSIDL );
 canwrite( 0x15, RXFNSIDL );
 canwrite( 0x19, RXFNSIDL );
 canwrite( 0x02, RXFNEID8 );
 canwrite( 0x06, RXFNEID8 );
 canwrite( 0x0A, RXFNEID8 );
 canwrite( 0x12, RXFNEID8 );
 canwrite( 0x16, RXFNEID8 );
 canwrite( 0x1A, RXFNEID8 );
 canwrite( 0x03, RXFNEID0 );
 canwrite( 0x07, RXFNEID0 );
 canwrite( 0x0B, RXFNEID0 );
 canwrite( 0x13, RXFNEID0 );
 canwrite( 0x17, RXFNEID0 );
 canwrite( 0x1B, RXFNEID0 );
 canwrite( 0x20, RXMNSIDH );
 canwrite( 0x24, RXMNSIDH );
 
 canwrite( 0x21, RXMNSIDL );
 canwrite( 0x25, RXMNSIDL );
 canwrite( 0x22, RXMNEID8 );
 canwrite( 0x26, RXMNEID8 );
 canwrite( 0x23, RXMNEID0 );
 canwrite( 0x27, RXMNEID0 );
 }
 //////////////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 //can初始化
 void caninit( void )
 {
 RESET = 0;
 delay();
 RESET = 1;
 canreset();
 delay();
 canwrite( 0x0F,0x80 );//CANCTRL:配置模式;终止发送中止;禁止单触发;禁止CLKOUT
 
 canwrite( 0x2A, 0x04 );//SJW=1TQ,TQ=625ns;晶振16MHz,波特率为160KHz,位时间10TQ
 canwrite( 0x29, 0xD9 );//PS2由CNF3的PHSEG22:PHSEG20决定;采样三次PS1=4TQ;传播段=2TQ
 canwrite( 0x28, 0x02 );//禁止唤醒;PS2=3TQ
 canbite( 0x60, 0x64, 0x40 );//RXB0CTL:接收扩展帧,滚存禁止
 canbite( 0x70, 0x60, 0x40 );//RXB1CTL:接收扩展帧
 filterinit(); //屏蔽和滤波设置
 txinit();     //发送数据帧设置
 canwrite( 0x2D, 0x00 );//E**复位
 canwrite( 0x2B, 0x23 );//使能:错误条件变化中断;接收缓冲器满中断
 canwrite( 0x2C, 0x00 );//清所有中断标志
 canwrite( 0x0F, 0x00 );//CANCTRL:正常工作模式;终止发送中止;禁止单触发;禁止CLKOUT
 }
 //can报文发送
 void cansend( char TXBNSIDHADD, char TXBND1, char TXBND2 )
 {
 char state;
 state = canreadstat();    //读状态
 if( ( state & 0x80 ) == 0x80 )   //发送缓冲区2空
 {
 canbite( 0x50, 0x08, 0x00 ); //清报文发送请求位
 canwrite( 0x51, TXBNSIDH+TXBNSIDHADD );  //装载标志符
 canwrite( 0x56, TXBND1 );   //装载发送缓冲区数据
 canwrite( 0x57, TXBND2 );
 canrts( 0x84 );    //请求发送
 delay();
 }
 else if( ( state & 0x20 ) == 0x20 )
 {
 canbite( 0x40, 0x08, 0x00 );
 canwrite( 0x41, TXBNSIDH+TXBNSIDHADD );
 canwrite( 0x46, TXBND1 );
 canwrite( 0x47, TXBND2 );
 canrts( 0x82 );
 delay();
 }
 else if( ( state & 0x08 )==0x08 )
 {
 canbite( 0x30, 0x08, 0x00 );
 canwrite( 0x31, TXBNSIDH+TXBNSIDHADD );
 canwrite( 0x36, TXBND1 );
 canwrite( 0x37, TXBND2 );
 canrts( 0x81 );
 delay();
 }
 }
 //检验是否可以发送报文
 char cansendinit( void )
 {
 char state;
 state = canreadstat();//读状态
 if( ( ( state & 0x80 ) == 0x80 )||( ( state & 0x20 ) == 0x20 )||( ( state & 0x08 ) == 0x08 ) )   //发送缓冲区有空
 {
 txinit();//发送数据帧设置
 return 1;
 }
 else
 return 0;
 }
 
 //从接收缓冲器读数据,并对接收的数据进行处理判断
 //如果要想总线发送数据,直接发送
 //如果要上传上位机,将数据压入队列
 void canreceive()
 {
 if( rxflag == 1 )
 {
 char state,datah,datal,databiteh,databitel;
 EA = 0;
 rxflag = 0;
 state = canreadstat();//读状态
 if( ( state & 0x01 ) == 0x01 )
 {
 datah=canread( 0x66 );//读取第1字节
 datal=canread( 0x67 );//读取第2字节
 canbite( 0x2C, 0x01, 0x00 );//清中断标志
 }
 else if( ( state & 0x02 ) == 0x02 )
 {
 datah = canread( 0x76 );
 datal = canread( 0x77 );
 canbite( 0x2C, 0x02, 0x00 );
 }
 databiteh = datah & 0xF0;
 databitel = datah & 0x0F;
 if( databiteh == 0x10 )
 {
 writeuartbuffer( queuesed, 0x30+JIEDIAN, datal ); //向上位机发送0011****,表示收到数据
 while( cansendinit() ) //判断是否有发送缓冲区为空
 cansend( databitel << 4, 0xF0+databitel, datal); //如果最高4位为0001,向规定节点发送数据帧
 }
 else if( databiteh == 0xF0 )
 writeuartbuffer( queuesed, 0x30+JIEDIAN, datal );//向上位机发送0011****,表示收到数据
 else if( ( databiteh == 0x40 ) || ( databiteh == 0x00 ) || ( databiteh == 0x30 ) || ( databiteh == 0x20 ) )
 writeuartbuffer( queuesed, datah, datal ); //转发给uart
 
 EA = 1;
 }
 }
 
 //将队列中的数据送入发送缓冲器
 void cantransmit()
 {
 if( txflag == 1 )
 {
 EA = 0;
 txflag = 0;
 
 readuartbuffer( queuerec );
 EA = 1;
 }
 }
 //外部中断0
 void canint0( void ) interrupt 0
 {
 char state,stateicod;
 IE0 = 0; //清外部中断标志
 state = canread( 0x0E );
 stateicod = state & 0x0E; //读取CANSTAT.ICOD位,判断优先级
 if( stateicod == 0x02 )
 errorflag = 1;
 else
 rxflag = 1;
 }
 //错误处理
 void error( void )
 {
 if( errorflag == 1 )
 {
 char state;
 
 EA = 0;
 errorflag = 0;
 state = canread( 0x2D );      //读错误标志寄存器E**
 if( ( state & 0x80 ) == 0x80 )
 {
 writeuartbuffer( queuesed, JIEDIAN, 0x01 );  //接收缓冲器1溢出,向上位机发送0000**** 00000001
 canreceive();
 canbite( 0x2D, 0x80, 0x00 ); //复位E**的RX1OVR位
 canbite( 0x2C, 0x20, 0x00 );  //清除CANNINTF的错误中断标志位
 }
 else if((state & 0x40) == 0x40 )
 {
 writeuartbuffer( queuesed, JIEDIAN, 0x00 );  //接收缓冲器0溢出,向上位机发送0000**** 00000000
 canreceive();
 canbite( 0x2D, 0x40, 0x00 ); //复位E**的RX0OVR位
 canbite( 0x2C, 0x20, 0x00 );  //清除CANNINTF的错误中断标志位
 }
 else if( ( state & 0x20 ) == 0x20 )
 {
 caninit();      //若总线关闭,can复位
 TCON = 0x00;   //设置外部中断0为电平触发,并清外部中断标志
 IE = 0x91;     //开总中断,允许串口中断,禁止定时/计数器中断,允许外部中断0
 }
 else if( ( state & 0x1F ) != 0x00 )
 {
 writeuartbuffer( queuesed, JIEDIAN, 0x03 ); //错误数小于255且错误条件变化时,向上位机发送0000**** 00000011
 canbite( 0x2C, 0x20, 0x00); //清除CANNINTF的错误中断标志位
 }
 else
 {
 writeuartbuffer( queuesed, JIEDIAN, 0xFF );   //其他未知错误,向上位机发送0000**** 11111111
 canbite( 0x2C, 0x20, 0x00 ); //清除CANNINTF的错误中断标志位
 }
 
 EA = 1;
 }
 }
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 //UART初始化
 void uartinit( void )
 {
 //串口采用模式1,允许接收
 SCON = 0x50;
 //定时器1,模式2
 TMOD = 0x20;
 //定时器1付值,波特率9600
 TH1 = 0xFD;
 TL1 = 0xFD;
 //定时器1启动
 TCON = 0x40;
 //设置串口中断
 ES = 1;
 }
 //UART发送程序
 void uartsend( queuetype *queuesed )
 {
 char temp;
 ES = 0; //去除串口中断
 while( queuekong( queuesed ) == 0 )
 {
 temp = deletequeue( queuerec );//只要队列非空,取队首元素
 SBUF = temp;  //发送数据
 while( TI == 0 ); //等待发送完成中断
 TI = 0; //去除发送完成中断
 queuesed->front = ( queuesed->front + 1 ) % MAXNUM;//指向下一个元素
 }
 ES = 1;   //使能串口中断
 }
 //UART中断程序
 void uartint( void ) interrupt 4
 {
 if( RI == 1 )
 {
 char uartbuffer;
 //去除中断
 RI = 0;
 //接收数据
 uartbuffer = SBUF;
 if( queueman( queuerec ) == 0 )
 {
 enterqueue( queuerec, uartbuffer);//uart接收数据压入接收缓冲器
 txflag = 1;
 }
 }
 }
 /////////////////////////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //将接收队列的数据装入发送缓冲区发送
 void readuartbuffer( queuetype *queuerec )
 {
 char datacheckh,datacheckl,checkh,checkl;
 while( ( queuekong( queuerec ) == 0 ) )//队列中存在两字节时
 {
 datacheckh = deletequeue( queuerec );//取队首元素
 checkh = datacheckh & 0xF0;//取字节高四位
 checkl = datacheckh & 0x0F;
 //字节低四位为0x01/0x02/0x03/0x04且高四位为0x10/0x20/0x30/0x40/0x00/0xF0时,断定为数据帧的第一字节
 if( ( ( checkl == 0x01 ) || ( checkl == 0x02 ) || ( checkl == 0x03 ) || ( checkl == 0x04 ) ) && ( ( checkh == 0x10 ) || ( checkh == 0x20 ) || ( checkh == 0x30 ) || ( checkh == 0x40 ) || ( checkh == 0x00 ) || ( checkh == 0xF0 ) ) )
 {
 queuerec->front = ( queuerec->front + 1 ) % MAXNUM;//指向下一个元素
 datacheckl = deletequeue( queuerec ); //取下一字节数据
 while( cansendinit() )
 cansend( checkl << 4, datacheckh, datacheckl );   //将数据发往指定节点
 }
 else
 queuerec->front = ( queuerec->front + 1 ) % MAXNUM;//指向下一个元素
 }
 }
 //将接收缓冲区数据压入发送队列
 void writeuartbuffer( queuetype *queuesed, char datah, char datal )
 {
 if( queueman( queuesed ) == 0 )
 {
 enterqueue( queuesed, datah );
 queuesed->rear = ( queuesed->rear + 1 ) % MAXNUM; //指向下一个元素
 enterqueue( queuesed, datal );
 }
 // else
 //  queuesed->front = ( queuesed->front + 1 ) % MAXNUM;//指向下一个元素
 uartsend( queuesed );
 }
 //////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 //主函数
 void main()
 {
 initqueue( queuerec ); //初始化队列
 initqueue( queuesed );
 
 uartinit();  //UART初始化
 
 //TCON = 0x00;//设置外部中断0为电平触发,并清外部中断标志
 IT0 = 0;//外部中断0为电平触发
 IE0 = 0;//清外部中断标志
 //IE = 0x81;//开总中断,禁止串口中断,禁止定时/计数器中断,允许外部中断0
 EX0 = 1;//允许外部中断0
 EA = 1; //开总中断
 
 caninit();   //can初始化
 while( 1 )
 {
 canreceive();
 cantransmit();
 error();
 }
 }
 | 
 |