在调试中遇到了这样的问题:在用
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时长,这样采样点就在该位的中间位置,利于采样
再进行调试时能够很好地接收到数据:
要有一定的判断力,我在调试时已经测出总线上有电平跳变时,依然怀疑是硬件的问题而在电路板上浪费了大量时间,没有想到要改程序。要试着从不同方向入手,不要用同样的方法去得到同样的错误结论。