网络拓扑结构为5个20Kbps的主CAN节点,通过5个LPC2119+PCA82AC250(网关)将波特率降低至12kbps、5Kbps已适应远距离传输,网关采用透明传输,使用 缓冲区存储转发, 20K→5K使用一个大缓冲区,可存储800帧报文, 5K→20K使用一个小缓冲区,可存储80帧报文, 5个网关通过5K的CAN总线联网,手拉手式连接,短线,5个主节点可能同时向 网关发送事件信息,每个主节点约有12个事件约60帧的报文向CAN总线发送,很可能是同时发送的,即肯定为发送总线竞争; 经多次测试发现,低速口多次发生“仲裁丢失中断”,导致各节点不同收到所有 网络上的事件信息,如果只有一个节点发送事件信息,250个事件约1000帧也不 会出现丢帧现象; 疑问:即使出现竞争,CAN协议2.0不是规定要自动重发的吗?应该可以保证数据都能发送到总线上?以下是相关代码:
/**********中断发送程序***********/ void __irq can_isr(void) { uint32 dev = 0; uCANICR k; for (dev=0; dev<CAN_MAX_NUM; dev++) { k = CANICR(dev); if (k.Bits.RI_BIT != 0){ //rcvdata_fromcanbus(dev); if (CAN1 == dev) { struct Low2High *ptr=&LowSpeed2Highbuf; if (ptr->full == 0) { ptr->buf[ptr->start] = RxBUF(dev); if (++ptr->start >= SIZEOF_LOW_HIGH) ptr->start = 0; if (ptr->start == ptr->end) ptr->full = _FULL_; }else ON_RCAN_LED(); RelCanRecBuf(dev); }else if (CAN2 == dev){ struct High2Low *ptr=&HighSpeed2Lowbuf; if (ptr->full == 0) { ptr->buf[ptr->start] = RxBUF(dev); if (++ptr->start >= SIZEOF_HIGH_LOW) ptr->start = 0; if (ptr->start == ptr->end) ptr->full = _FULL_; }else ON_RCAN_LED(); RelCanRecBuf(dev); } } /* if ((k.Bits.TI1_BIT != 0) || (k.Bits.TI2_BIT != 0) || (k.Bits.TI3_BIT != 0)) { } */
if (k.Bits.ALCBIT_BIT != 0) { flag[dev] |= 1<<2; } if (k.Bits.BEI_BIT != 0) { CanBufOffLinePrg(dev); } if (k.Bits.DOI_BIT != 0) { flag[dev] |= 1<<4; ClrCanDataOver(dev); } } VICVectAddr = 0x00; }
/*高速口数据转发至低速口*/ void SendHigh2LowData2Bus(void) {
struct High2Low *ptr=&HighSpeed2Lowbuf;
if ((ptr->start != ptr->end) || ptr->full == _FULL_ ) { if (CANGSR(CAN1).Bits.TBS_BIT != 0){ if (BegainSend2CANBus(CAN1, &ptr->buf[ptr->end]) != 1){ TCAN_LEDGlint(); if (++ptr->end >= SIZEOF_HIGH_LOW) { ptr->end = 0; } ptr->full = 0; } } } } /*低速口转发至高速口*/ void SendLow2HighData2Bus(void) { struct Low2High *ptr=&LowSpeed2Highbuf;
if ((ptr->start != ptr->end) || ptr->full == _FULL_) { if (ptr->full ==_FULL_) print("low to high is fullx0dx0a"); if (CANGSR(CAN2).Bits.TBS_BIT != 0){ if (BegainSend2CANBus(CAN2, &ptr->buf[ptr->end]) != 1){ TCAN_LEDGlint(); if (++ptr->end >= SIZEOF_LOW_HIGH) { ptr->end = 0; } ptr->full = 0; } } } }
/* ******************************************************************************** **函数名称:BegainSend2CANBus **函数功能:启动发送 **入口参数:cannum:CAN控制器通道号ptr:发送缓冲区指针 **出口参数:1: erro 0:right **函数说明:选择发送缓冲区 ** ******************************************************************************** */ uint32 BegainSend2CANBus(uint32 cannum, struct ObjectMessage *ptr) { uint32 status = 0; uCANCMR Temp;
Temp.Word = 0; if (0 != CANSR(cannum).Bits.TBS1_BIT) { if (0 == CANSR(cannum).Bits.TS1_BIT) { CANTFI1(cannum) = ptr->RFS_TFI; CANTID1(cannum) = ptr->ID; CANTDA1(cannum) = ptr->CANRDA; CANTDB1(cannum) = ptr->CANRDB; Temp.Bits.STB1_BIT = 1; }else{ status = 1; } } else if (0 != CANSR(cannum).Bits.TBS2_BIT){ if (0== CANSR(cannum).Bits.TS2_BIT) { CANTFI1(cannum) = ptr->RFS_TFI; CANTID1(cannum) = ptr->ID; CANTDA1(cannum) = ptr->CANRDA; CANTDB1(cannum) = ptr->CANRDB; Temp.Bits.STB2_BIT = 1; }else{ status = 1; } }else if (0 != CANSR(cannum).Bits.TBS3_BIT){ if (0 == CANSR(cannum).Bits.TS3_BIT) { CANTFI1(cannum) = ptr->RFS_TFI; CANTID1(cannum) = ptr->ID; CANTDA1(cannum) = ptr->CANRDA; CANTDB1(cannum) = ptr->CANRDB; Temp.Bits.STB3_BIT = 1; }else{ status = 1; } }else{ status = 1; } if (status == 0){ if(CANMOD(cannum).Bits.SM_BIT != 0) { CanQuitSM(cannum); } Temp.Bits.TR_BIT = 1; CANCMR(cannum).Word = Temp.Word; } return status; }
/*主函数,只处理转发机制,*/ int main(void) { TargetInit();
while (1) { SendHigh2LowData2Bus(); SendLow2HighData2Bus(); feeddog(); } return 1; } /*************************************/ 在打印数据过程中发现有数据错位的现象发送 /*打印函数*/ void printfMessage(struct ObjectMessage *Msg) { unsigned int i=0; unsigned char DLC=0; unsigned char buf[8]; memset(buf, 0, 8); DLC = Msg->RFS_TFI.Bits.DLC_BIT; //print("TFI=%#X ", Msg->RFS_TFI); print("ID=%#X: x0dx0a", Msg->ID); switch (DLC){ case 8: buf[7] = Msg->CANRDB.Bits.Data4_BIT; case 7: buf[6] = Msg->CANRDB.Bits.Data3_BIT; case 6: buf[5] = Msg->CANRDB.Bits.Data2_BIT; case 5: buf[4] = Msg->CANRDB.Bits.Data1_BIT; case 4: buf[3] = Msg->CANRDA.Bits.Data4_BIT; case 3: buf[2] = Msg->CANRDA.Bits.Data3_BIT; case 2: buf[1] = Msg->CANRDA.Bits.Data2_BIT; case 1: buf[0] = Msg->CANRDA.Bits.Data1_BIT; break; default: print("DLC=%dx0dx0ax0dx0a", DLC); return; } for(i=0;i<DLC;i++){ print("f%d=%#x,", i, buf); } print("x0dx0ax0dx0a"); }
void SendLow2HighData2Bus(void) { struct Low2High *ptr=&LowSpeed2Highbuf;
if (ptr->TxBusy) return; if ((ptr->start != ptr->end) || ptr->full == _FULL_) { //if (CANGSR(CAN2).Bits.TBS_BIT != 0){ if (BegainSend2CANBus(CAN2, &ptr->buf[ptr->end]) != 1){ //TCAN_LEDGlint(); ptr->TxBusy = 1;//开始向高速CAN口发送报文 //在此打印由5K总线收到并发送给20K的数据帧 printfMessage(&ptr->buf[ptr->end]); if (++ptr->end >= SIZEOF_LOW_HIGH) { ptr->end = 0; } ptr->full = 0; }else { print("2:busyx0dx0a"); } //} } }
/************************************************/ /*打印结果如下(出错即丢帧时)*/
//事件1,2帧 ID=0X1C880100: f0=0x5,f1=0x1,f2=0x9,f3=0xed,f4=0x2a,f5=0xb9,f6=0x49,f7=0x1,
ID=0XC840100: f0=0,f1=0,f2=0x1,f3=0,f4=0,f5=0,f6=0,f7=0,
//事件2,2帧 ID=0X1C888200: f0=0x5,f1=0x82,f2=0x9,f3=0xec,f4=0x2a,f5=0xb9,f6=0x49,f7=0x1,
ID=0XC848200: f0=0,f1=0,f2=0x1,f3=0,f4=0,f5=0,f6=0,f7=0,
//事件3,2帧 ID=0X1C888300: f0=0xb,f1=0x83,f2=0x9,f3=0xec,f4=0x2a,f5=0xb9,f6=0x49,f7=0x1,
ID=0XC848300: f0=0,f1=0,f2=0x1,f3=0,f4=0,f5=0,f6=0,f7=0,
//事件4,2帧 ID=0X1C888100: f0=0xb,f1=0x81,f2=0x9,f3=0xed,f4=0x2a,f5=0xb9,f6=0x49,f7=0x1,
ID=0XC848100: f0=0,f1=0,f2=0x1,f3=0,f4=0,f5=0,f6=0,f7=0,
//事件5,2帧 ID=0X1C880100: f0=0xb,f1=0x1,f2=0x9,f3=0xee,f4=0x2a,f5=0xb9,f6=0x49,f7=0x1,
ID=0XC840100: f0=0,f1=0,f2=0x1,f3=0,f4=0,f5=0,f6=0,f7=0,
//事件6,2帧 ID=0X1C888200: f0=0xb,f1=0x82,f2=0x9,f3=0xed,f4=0x2a,f5=0xb9,f6=0x49,f7=0x1,
ID=0XC848200: f0=0,f1=0,f2=0x1,f3=0,f4=0,f5=0,f6=0,f7=0,
//事件7,2帧 //本帧出错,f0~f7的内容应与其它事件信息一样即 //f0应为0xb,貌似f0数据丢失,而后续的向前移动了一个字节,导致节点 //无法正确识别数据帧格式,导致事件丢失 ID=0X44: f0=0x81,f1=0x9,f2=0xed,f3=0x2a,f4=0xb9,
ID=0XC848100: f0=0,f1=0,f2=0x1,f3=0,f4=0,f5=0,f6=0,f7=0,
//事件8,2帧 //同上,本节点正好丢失的2个事件,就是7,8 ID=0XC4: f0=0x83,f1=0x9,f2=0xed,f3=0x2a,f4=0xb9,
ID=0XC848300: f0=0,f1=0,f2=0x1,f3=0,f4=0,f5=0,f6=0,f7=0,
//不知道为什么帧内数据为出错 还有次打印出 DLC=11;不解中,收帧函数有bug???
以上为程序基本流程, 现在在多个节点同时发送数据时,就会出现大量丢帧现在 各位看客有没有好的建议和解决方案!!! 谢谢
|