本帖最后由 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();
}
} |
|