can usb tool下载_「CAN波形分析」 一次CAN波形分析之旅

Prepare

CAN通信协议使用了有一段时间了,但都是基于软件层面的使用,对于其波形不是很了解,正好这段时间比较闲,是时候补补硬知识。

开始之前,先介绍一下设备:

  • 咸鱼淘来的古董级别示波器GDS-2202。200MHz,数据记录长度是12500个点(每个点40ns,总记录长度是500us)
4f1e741aa2190c7fc00e6bdffddb8add.png
  • EK-LM4F120XL开发板。也就是现在的EK-TM4C123GXL,板载MCU是TM4C1233H6PM,对应原来的老型号LM4F120H5QR
78109b54013750285eb123b068f97261.png
  • CAN收发器,TJA1050模块
d05e2bf8af30f233ed3bb9db5acde891.png

Ongoing

软件准备

用CCS9.0导入TI提供的CAN驱动库,每隔1秒钟发送一个CAN信息:

  • 波特率:500 kb/s
  • ID(Normal): 0x220
  • 信息长度 :4 bytes
  • 数据:0x12, 0x34, 0x56, 0x78
int main(void){ tCANMsgObject sCANMessage; unsigned char ucMsgData[4];  // 初始化系统时钟 SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // 配置CAN Tx和Rx引脚 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); GPIOPinConfigure(GPIO_PE4_CAN0RX); GPIOPinConfigure(GPIO_PE5_CAN0TX); GPIOPinTypeCAN(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5); // 使能CAN模块时钟 SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0); // 初始化CAN模块 CANInit(CAN0_BASE); // 设置CAN波特率 CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 500000); // 使能CAN中断 CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS); CANRetrySet(CAN0_BASE, false); // 使能CAN中断 IntEnable(INT_CAN0); // 使能CAN模块 CANEnable(CAN0_BASE); // 初始化CAN报文 *(unsigned long *)ucMsgData = 0; sCANMessage.ulMsgID = 0x220; // CAN message ID sCANMessage.ulMsgIDMask = 0; // no mask needed for TX sCANMessage.ulFlags = MSG_OBJ_TX_INT_ENABLE; // enable interrupt on TX sCANMessage.ulMsgLen = sizeof(ucMsgData); // size of message is 4 sCANMessage.pucMsgData = ucMsgData; // ptr to message content ucMsgData[0] = 0x12; ucMsgData[1] = 0x34; ucMsgData[2] = 0x56; ucMsgData[3] = 0x78; for(;;) { // 发送CAN报文 CANMessageSet(CAN0_BASE, 1, &sCANMessage, MSG_OBJ_TYPE_TX); // 延时1秒钟 SimpleDelay(); } return(0);}

编译,通过板载调试器下载代码,复位运行代码。

硬件准备

示波器探头CH1连接TJA1050的CANH引脚,探头CH2连接CANL引脚,地跟开发板的GND连接,使用边沿触发模式捕获波形:

cd1c380d1831872ceb63e36ef009073e.png

分析

为了方便分析,将波形保存成CSV格式。该CSV文件记录了波形信息和数据,从第17行开始,就是波形的数据,如下图:

a9e0215cf05d96613f8edc774ad158b4.png

使用Matplotlib导入CSV,绘制折线图,代码如下:

 import csvimport matplotlibimport matplotlib.pyplot as pltimport matplotlib.collections as collectionsfrom matplotlib.ticker import MultipleLocatorimport numpy as npimport pandas as pdax = plt.subplot()#将x主刻度标签设置为125的倍数xmajorLocator = MultipleLocator(125) ax.xaxis.set_major_locator(xmajorLocator)#y轴数据raw_canh = pd.read_csv("canh.csv")raw_canl = pd.read_csv("canl.csv")#x轴数据t = np.arange(130, 12000, 1)ax.plot(t, raw_canh[130:12000], raw_canl[130:12000])ax.xaxis.grid(True)plt.show()

运行,效果如下,

6fe58bd12713d1dbcb2e00f381725d89.png

局部放大波形图,

b109572801ffd4ec1656cc1c87bd9f06.png

接下来的工作就是PS了,参照CAN2.0B的Spec,找到每一位的定义。首先是整个数据帧(Data Frame)的定义,

a716778301cca09f1a8fcdb3543a97cb.png

进一步细化每个字段(Field):

8fb20a05aab24e2350a2dec373823cad.png

将差分信号转换为实际的二进制值,十六进制值。这里需要补充一点知识,CAN信号电压与实际逻辑的关系,很好记忆,波形像口张开的(O),表示逻辑0(显示);另外一种则表示逻辑1(隐性)。如下图:

f5506cccaee9669cd2269cbc0ab4dea9.png

根据上面的信息,我们可以进一步得到以下数据,

f89b558d3108c23af524807c5670b764.png

如果你很细心的看上面图,就会发现一个问题,有些十六进制为什么是有9位?因为有一位是填充位(Bit Stuffing),CAN2.0的协议规定,连续5个显性/隐性电平后,要填充一位隐性/显性电平。如上图中的仲裁字段(Arbitration Field),连续5个'0'后,填充一个'1'。

Post

分析到这里接近尾声了,还有一个疑问,这个CRC校验是怎么算出来的呢?从CAN2.0的Spec了解到,CRC的计算的值从SOF开始,到数据字段(Data Field),多项式:

P(x) = x15+ x14+ x10+ x8+ x7+ x4+ x3+ 1

通过在线CRC计算网站,输入我们的数据,计算CRC的值:

3df05a3eeef04311243b3cb9b9afa983.png

如我们所料,计算的CRC值是正确的!

-----------------------------------------------------------------------------------END

[参考资料]

  • http://www.ti.com/tool/EK-TM4C123GXL
  • https://elearning.vector.com/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值