CAN总线的发送or接收失败问题

CAN总线的发送or接收失败问题

在调试中遇到了这样的问题:在用CAN总线分析仪接收调试板发出的数据时,接收不到数据。但是程序拿到另外一块类似板中一切正常。

原因分析

在程序没问题的基础上,想到是硬件的问题,如是开始了以下问题检查

  • 电路板线路是否接错,尤其是RX与TX是否接反、CANH与CANL是否接反,是否短接
  • 收发器供电是否正常

经检查后均不是上述问题,于是用示波器对总线电平进行测量

在这里插入图片描述
在这里插入图片描述

  • 发现有电平跳变说明不是硬件电路的问题。我的波特率位125Kbps,所以位时间是8微秒,所以上面的报文结构位7个显性位,11个隐性位,应该为错误帧;但是过一段时间波形变换为如下所示:

在这里插入图片描述
在这里插入图片描述
报文变为一位显性,25位隐性电平,这个电平形式我始终不知道是什么。

软件问题

既然硬件没有问题那就从软件着手。

/*************************************************************/
/*                       CAN发送                            */
/*************************************************************/
Bool MSCANSendMsg(struct can_msg msg)
{
  unsigned char send_buf, sp;
    unsigned char num;    
   if(msg.len > 8)     // 检查数据长度
    return(FALSE);      //返回true和false所以要用bool型,在以后 if(fucn(x,y))//可以用来作if语句的判断,while(fucn(x,y))//也可以做循环条件的判断
  // 检查总线时钟是否同步
  if(CANCTL0_SYNCH==0)
    return(FALSE);
send_buf = 0;
  do
  {
    CANTBSEL=CANTFLG;      // 寻找空闲的缓冲器
    send_buf=CANTBSEL;//等待该寄存器有值,即等待相关报文缓冲器为空
    num++;
    if(num>10)
    break;
  }
  while(!send_buf); 
  // 写入标识符
  CANTIDR0 = (unsigned char)(msg.id>>3);//id为8位
  CANTIDR1 = (unsigned char)(msg.id<<5);
  
   if(msg.RTR)                 //Remote Transmission Request 远程传输请求
    // RTR = 阴性
    CANTIDR1 |= 0x10;
    
  // 写入数据
  for(sp = 0; sp < msg.len; sp++)
    *((&CANTDSR0)+sp) = msg.data[sp];//数据段寄存器,包含将要发送的数据

  // 写入数据长度
  CANTDLR = msg.len; 
  
  // 写入优先级
  CANTTBPR = msg.prty;         //ransmit Buffer Priority Register (TBPR)
  
  // 清 TXx 标志 (缓冲器准备发送)
  CANTFLG = send_buf;
  
  return(TRUE);
  
}

在调试时程序总是进到寻找空闲的缓冲器这个do while循环里,跳不出来,所以定义了个num变量让它自加到10跳出循环;但是还是不通,于是想从 CAN初始化程序 入手:

/*************************************************************/
/*                        初始化CAN                         */
/*************************************************************/

void INIT_CAN(void) //按照dz60寄存器改编的程序
{
  if(CANCTL0_INITRQ==0)      // 查询是否进入初始化状态   
    CANCTL0_INITRQ =1;        // 进入初始化状态

  while (CANCTL1_INITAK==0);  //等待进入初始化状态,初始化模式确认

  CANBTR0_SJW = 3;            //设置同步跳转宽度,总线计时寄存器,现在设为4
  CANBTR0_BRP = 3  ;            //设置波特率预分频器-prescaler value ,
  CANBTR1_TSEG_10 = 6;
  CANBTR1_TSEG_20 = 7;
        //设置时段1-7个和时段2-8个的Tq个数 ,总线频率为125kb/s,1/125K=bit time=(prescaler value)*(1+tseg1+tseg2)/Fcanclk=4*(7+8+1)/8M

// 关闭滤波器                                  
  CANIDMR0 = 0xFF;//不比较
  CANIDMR1 = 0xFF;
  CANIDMR2 = 0xFF;
  CANIDMR3 = 0xFF;
  CANIDMR4 = 0xFF;
  CANIDMR5 = 0xFF;
  CANIDMR6 = 0xFF;
  CANIDMR7 = 0xFF; 

  CANCTL1 = CANCTL1_CLKSRC_MASK | CANCTL1_CANE_MASK;             //使能MSCAN模块,设置为一般运行模式、使用总线时钟源 环回自测禁止
  

  CANCTL0 = 0x00;             //返回一般模式运行

  while(CANCTL1_INITAK);      //等待回到一般运行模式

  while(!CANCTL0_SYNCH);    //等待总线时钟同步

  CANRIER_RXFIE = 0;          //禁止接收中断
}

改了两个位置

  • 第一个位置改了同步跳转宽度
 CANBTR0_SJW = 3;            //设置同步跳转宽度,总线计时寄存器,现在设为4

同步跳转宽度是CAN总线机制中为了寻找同步而在缓冲段增加或减少时间的上限值。总线中能通信的基础是各个节点的波特率一致,然而各个节点的波特率又不能达到百分百相同,所以CAN总线允许各节点波特率有微小偏差,而对位时间的微调就能微调波特率,使该节点与总线波特率一致,所以同步跳转宽度越大,波特率的波动范围就越大,容错率提高,也就是说这个值越大,对总线中个节点的波特率的要求就越松。

  • 第二个位置改变了缓冲段一与缓冲段二的时长
  CANBTR1_TSEG_10 = 6;
  CANBTR1_TSEG_20 = 7;

将缓冲段一设置为7个Tq时长,将缓冲段二设置为8个Tq时长,这样采样点就在该位的中间位置,利于采样

  • 再进行调试时能够很好地接收到数据:

在这里插入图片描述

  • 总结

要有一定的判断力,我在调试时已经测出总线上有电平跳变时,依然怀疑是硬件的问题而在电路板上浪费了大量时间,没有想到要改程序。要试着从不同方向入手,不要用同样的方法去得到同样的错误结论。

  • 10
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值