DSP28377S_CAN通信

article/2025/8/30 0:34:31

CAN通信

  • CAN通信的由来
    • CAN通信格式
    • CAN通信配置
    • 实验验证
    • 结束语
    • 参考资料目录

CAN通信的由来

为适应“减少线束的数量”、“通过多个LAN,进行大量数据的高速通信”的需要,1986 年德国电气商博世公司开发出面向汽车的CAN 通信协议。CAN属于现场总线的范畴,它是一种有效支持分布式控制或实时控制的串行通信网络。

CAN通信格式

CAN通信共有5种,分别为数据帧、遥控帧、错误帧、过载帧、帧间隔。数据帧格式由下图所示,分为标准格式和拓展格式,笔者目前仅使用到标准数据帧,使用其中的64bits数据段进行CAN节点间的数据交互,以ID号区分数据类型。注意ACK!实际波形中彼己电平高度不一
在这里插入图片描述

CAN通信配置

①初始化CAN的映射GPIO,使用TI封装好的函数初始化CAN,选择CAN时钟源,设置波特率,使能CAN中断触发源,开启CAN;

void InitCana(void)
{InitCanaGpio();//// Initialize the CAN controller//CANInit(CANA_BASE);//// Setup CAN to be clocked off the M3/Master subsystem clock//CANClkSourceSelect(CANA_BASE, 0);//// Set up the bit rate for the CAN bus.  This function sets up the CAN// bus timing for a nominal configuration.  You can achieve more control// over the CAN bus timing by using the function CANBitTimingSet() instead// of this one, if needed.// In this example, the CAN bus is set to 500 kHz.  In the function below,// the call to SysCtlClockGet() is used to determine the clock rate that// is used for clocking the CAN peripheral.  This can be replaced with a// fixed value if you know the value of the system clock, saving the extra// function call.  For some parts, the CAN peripheral is clocked by a fixed// 8 MHz regardless of the system clock in which case the call to// SysCtlClockGet() should be replaced with 8000000.  Consult the data// sheet for more information about CAN peripheral clocking.//CANBitRateSet(CANA_BASE, 200000000, 200000);    // 波特率200kbps//// Enable interrupts on the CAN peripheral.  This example uses static// allocation of interrupt handlers which means the name of the handler// is in the vector table of startup code.  If you want to use dynamic// allocation of the vector table, then you must also call CANIntRegister()// here.//CANIntEnable(CANA_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);//// Enable the CAN for operation.//CANEnable(CANA_BASE);//// Enable CAN Global Interrupt line0//CANGlobalIntEnable(CANA_BASE, CAN_GLB_INT_CANINT0);
}

②确定收发缓存数组、ID号;

//  CAN通信
unsigned char ucRXMsgData1[8];   // CAN接受数据
unsigned char ucTXMsgData2[8];   // CAN发送数据
unsigned char ucTXMsgData3[8];   // CAN发送数据
unsigned char ucTXMsgData4[8];   // CAN发送数据
unsigned char ucTXMsgData5[8];   // CAN发送数据
unsigned char ucTXMsgData6[8];   // CAN发送数据tCANMsgObject sRXCANMessage1 = {RX_MSG_OBJ_ID1, 0, 2, 8, ucRXMsgData1};    // CAN接收结构体  MSG_OBJ_RX_INT_ENABLE = 2
tCANMsgObject sTXCANMessage2 = {TX_MSG_OBJ_ID2, 0, 1, 8, ucTXMsgData2};    // CAN发送结构体  MSG_OBJ_TX_INT_ENABLE = 1
tCANMsgObject sTXCANMessage3 = {TX_MSG_OBJ_ID3, 0, 1, 8, ucTXMsgData3};    // CAN发送结构体  MSG_OBJ_TX_INT_ENABLE = 1
tCANMsgObject sTXCANMessage4 = {TX_MSG_OBJ_ID4, 0, 1, 8, ucTXMsgData4};    // CAN发送结构体  MSG_OBJ_TX_INT_ENABLE = 1
tCANMsgObject sTXCANMessage5 = {TX_MSG_OBJ_ID5, 0, 1, 8, ucTXMsgData5};    // CAN发送结构体  MSG_OBJ_TX_INT_ENABLE = 1
tCANMsgObject sTXCANMessage6 = {TX_MSG_OBJ_ID6, 0, 1, 8, ucTXMsgData6};    // CAN发送结构体  MSG_OBJ_TX_INT_ENABLE = 1

③根据自己的通信机制,封装好CAN通信收发函数;

void CANA_TX(void)
{unsigned int T_switch = 0;  // 选择数据发送CANA_TX_FRAME_CNT = CANA_TX_FRAME_CNT + 1;      // 帧计数自增
//    CANA_TX_FRAME_CNT = CANA_TX_FRAME_CNT & 0xFF;   // 帧计数达到255后清零,循环计数T_switch = CANA_TX_FRAME_CNT % 5;switch(T_switch){case 0:ucTXMsgData2[0] = CAN_CNT_delta & 0xFF;    // 帧计数ucTXMsgData2[1] = 0; // ...此处略去ucTXMsgData2[2] = 0; // ...此处略去ucTXMsgData2[3] = 0; // ...此处略去ucTXMsgData2[4] = 0; // ...此处略去ucTXMsgData2[5] = 0; // ...此处略去ucTXMsgData2[6] = 0; // ...此处略去ucTXMsgData2[7] = 0; // ...此处略去CanaMessageSet(TX_MSG_OBJ_ID2, &sTXCANMessage2, MSG_OBJ_TYPE_TX);break;case 1:ucTXMsgData3[0] = CAN_CNT_delta & 0xFF;    // 帧计数ucTXMsgData3[1] = 0; // ...此处略去ucTXMsgData3[2] = 0; // ...此处略去ucTXMsgData3[3] = 0; // ...此处略去ucTXMsgData3[4] = 0; // ...此处略去ucTXMsgData3[5] = 0; // ...此处略去ucTXMsgData3[6] = // ...此处略去ucTXMsgData3[7] = // ...此处略去CanaMessageSet(TX_MSG_OBJ_ID3, &sTXCANMessage3, MSG_OBJ_TYPE_TX);break;case 2:ucTXMsgData4[0] = CAN_CNT_delta & 0xFF;    // 帧计数ucTXMsgData4[1] = // ...此处略去ucTXMsgData4[2] = // ...此处略去ucTXMsgData4[3] = // ...此处略去ucTXMsgData4[4] = // ...此处略去ucTXMsgData4[5] = // ...此处略去ucTXMsgData4[6] = // ...此处略去ucTXMsgData4[7] = // ...此处略去CanaMessageSet(TX_MSG_OBJ_ID4, &sTXCANMessage4, MSG_OBJ_TYPE_TX);break;case 3:ucTXMsgData5[0] = CAN_CNT_delta & 0xFF;    // 帧计数ucTXMsgData5[1] = // ...此处略去ucTXMsgData5[2] = // ...此处略去ucTXMsgData5[3] = // ...此处略去ucTXMsgData5[4] = // ...此处略去ucTXMsgData5[5] = // ...此处略去ucTXMsgData5[6] = // ...此处略去ucTXMsgData5[7] = // ...此处略去CanaMessageSet(TX_MSG_OBJ_ID5, &sTXCANMessage5, MSG_OBJ_TYPE_TX);break;case 4:ucTXMsgData6[0] = CAN_CNT_delta & 0xFF;    // 帧计数ucTXMsgData6[1] = // ...此处略去ucTXMsgData6[2] = // ...此处略去ucTXMsgData6[3] = // ...此处略去ucTXMsgData6[4] = // ...此处略去ucTXMsgData6[5] = // ...此处略去ucTXMsgData6[6] = // ...此处略去ucTXMsgData6[7] = // ...此处略去CanaMessageSet(TX_MSG_OBJ_ID6, &sTXCANMessage6, MSG_OBJ_TYPE_TX);CANA_TX_Active_Flag = 0;break;default:break;}if(CANA_TX_FRAME_CNT >= 254){CANA_TX_FRAME_CNT = 0;}
}
void CANA_RX(void)
{if((CANA_errorFlag == 0) && (CANA_RX_Flag == 1)){RX_FRAME_CANA.CNT = (Uint16)ucRXMsgData1[0]; // 字节1RX_FRAME_CANA.x= (Uint16)(((ucRXMsgData1[1] & 0xF0) >> 4) & 0x0F);   // 字节2HRX_FRAME_CANA.xx = (Uint16)ucRXMsgData1[1] & 0x0F;          // 字节2LRX_FRAME_CANA.xxx= (Uint16)(((ucRXMsgData1[2] & 0xF0) >> 4) & 0x0F);    // 字节3HRX_FRAME_CANA.xxxx= (Uint16)ucRXMsgData1[2] & 0x0F;               // 字节3LRX_FRAME_CANA.xxxxx= ((Uint16)(ucRXMsgData1[3] & 0xFF)) * 0.2;      // 字节4RX_FRAME_CANA.xxxxxx= ((Uint16)(ucRXMsgData1[4] & 0xFF)) * 196.08;  // 字节5RX_FRAME_CANA.xxxxxxx= ((int)(((ucRXMsgData1[5] & 0xFF) << 8 ) | (ucRXMsgData1[6] & 0xFF))) * 0.02;    // 字节6 字节7}
}

④使用中断服务函数,传输接收发送结构体;

interrupt void CANA0_ISR(void)
{/************************************************************Description:CANA0中断服务程序用于检测中断产生原因,发送接收上位机数据************************************************************/uint32_t status;//// Read the CAN-A interrupt status to find the cause of the interrupt//status = CANIntStatus(CANA_BASE, CAN_INT_STS_CAUSE);//// If the cause is a controller status interrupt, then get the status//if(status == CAN_INT_INT0ID_STATUS){//// Read the controller status.  This will return a field of status// error bits that can indicate various errors.  Error processing// is not done in this example for simplicity.  Refer to the// API documentation for details about the error status bits.// The act of reading this status will clear the interrupt.//status = CANStatusGet(CANA_BASE, CAN_STS_CONTROL);//// Check to see if an error occurred.//if(((status  & ~(CAN_ES_TXOK | CAN_ES_RXOK)) != 7) &&((status  & ~(CAN_ES_TXOK | CAN_ES_RXOK)) != 0)){//// Set a flag to indicate some errors may have occurred.//CANA_errorFlag = 1;}}//// Check if the cause is the CAN-A receive message object 1//else if(status == RX_MSG_OBJ_ID1){//// Get the received message//CANMessageGet(CANA_BASE, RX_MSG_OBJ_ID1, &sRXCANMessage1, true);//// Getting to this point means that the RX interrupt occurred on// message object 1, and the message RX is complete.  Clear the// message object interrupt.//CANIntClear(CANA_BASE, RX_MSG_OBJ_ID1);//// Since the message was received, clear any error flags.//CANA_errorFlag = 0;CANA_RX_Flag = 1;CANA_TX_Active_Flag = 1;Timer_CANA_TX_1ms = 0;}//// Check if the cause is the CAN-A send message object 1//else if(status == TX_MSG_OBJ_ID2){//// Getting to this point means that the TX interrupt occurred on// message object 1, and the message TX is complete.  Clear the// message object interrupt.//CANIntClear(CANA_BASE, TX_MSG_OBJ_ID2);//// Since the message was sent, clear any error flags.//CANA_errorFlag = 0;}//// Check if the cause is the CAN-A send message object 1//else if(status == TX_MSG_OBJ_ID3){//// Getting to this point means that the TX interrupt occurred on// message object 1, and the message TX is complete.  Clear the// message object interrupt.//CANIntClear(CANA_BASE, TX_MSG_OBJ_ID3);//// Since the message was sent, clear any error flags.//CANA_errorFlag = 0;}//// Check if the cause is the CAN-A send message object 1//else if(status == TX_MSG_OBJ_ID4){//// Getting to this point means that the TX interrupt occurred on// message object 1, and the message TX is complete.  Clear the// message object interrupt.//CANIntClear(CANA_BASE, TX_MSG_OBJ_ID4);//// Since the message was sent, clear any error flags.//CANA_errorFlag = 0;}//// Check if the cause is the CAN-A send message object 1//else if(status == TX_MSG_OBJ_ID5){//// Getting to this point means that the TX interrupt occurred on// message object 1, and the message TX is complete.  Clear the// message object interrupt.//CANIntClear(CANA_BASE, TX_MSG_OBJ_ID5);//// Since the message was sent, clear any error flags.//CANA_errorFlag = 0;}//// Check if the cause is the CAN-A send message object 1//else if(status == TX_MSG_OBJ_ID6){//// Getting to this point means that the TX interrupt occurred on// message object 1, and the message TX is complete.  Clear the// message object interrupt.//CANIntClear(CANA_BASE, TX_MSG_OBJ_ID6);//// Since the message was sent, clear any error flags.//CANA_errorFlag = 0;}//// If something unexpected caused the interrupt, this would handle it.//else{//// Spurious interrupt handling can go here.//}//// Clear the global interrupt flag for the CAN interrupt line//CANGlobalIntClear(CANA_BASE, CAN_GLB_INT_CANINT0);//// Acknowledge this interrupt located in group 9//PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;}

实验验证

采用上位机(PC)发1帧,下位机(DSP)应答5帧的方式,实现遥控与遥测,要想实现更为精准的定时,则可以采取其他的方式,比如TT-CAN等。上位机发送间隔6ms,下位机应答间隔1ms。上位机数据帧ID(00000000001),下位机数据帧ID(00000000010、00000000011、00000000100、00000000101、00000000110)。使用ZLG的示波器,因为他自带CAN通信解码功能,使用起来非常方便。
上位机遥控帧:
在这里插入图片描述
下位机遥测帧①
在这里插入图片描述
下位机遥测帧⑤
在这里插入图片描述

结束语

笔者对于CAN的使用,仅停留在数据帧这一简单的帧种类上,以后若是有项目需要,则再补充学习其他的帧种类。TI对于CAN的支持比较到位,我们可以直接调用相应的函数,即可实现功能。当然规则越明细,开发人员对其标准化程度会越高,但使用灵活度、自由度变差。

参考资料目录

《TMS320F2837xS Delfino Microcontrollers Datasheet》Memory章节
《TMS320F2837xS Delfino Microcontrollers Technical Reference Manual》CAN章节
RENESAS应用手册《CAN入门书》
C2000Ware有关CAN的所有例程


http://chatgpt.dhexx.cn/article/9mjPTt0o.shtml

相关文章

【CAN】CAN通信基础

1、CAN 总线与 CANopen 概述 CAN&#xff08;Controller Area Network&#xff09;总线是BOSCH为解决现代汽车中众多的控制与测试仪器之间的数据交换而开发的一种串行数据通信协议&#xff0c;通信介质可以是双绞线、同轴电缆或光导纤维。 通信速率可达 1MBPS。 CAN 协议的一个…

通信接口CAN

CAN通信 目前&#xff08;2021年6月&#xff09;我用到的CAN电路原理图&#xff1a; 判断电路有没有接好&#xff0c;其中一个标准就是&#xff0c;测量接入的电阻阻值是不是60Ω。上图两个60.4Ω之间&#xff0c;可以接一个电容到GND。 1. Bit Timing(位时序) 参考连接 …

STM32之CAN通信

23.1关于 CAN 23.1.1 CAN 电气特性与协议 控制器局域网&#xff08;Controller Area Network&#xff0c;CAN&#xff09;&#xff0c;是由德国BOSCH&#xff08;博世&#xff09;公司开发&#xff0c;是目前国际上应用最为广泛的现场总线之一。其特点是可拓展性好&#xff0…

FPGA实现CAN通信

FPGA实现CAN通信 1、CAN协议物理层和协议层 2、传输的波特率 3、FPGA实现思路 4、FPGA实现代码 1、CAN物理层和协议层 CAN与串口类似&#xff0c;都是异步通信&#xff0c;利用两根差分线来进行信号的传输。 在多节点进行数据传输时主要分为遵循ISO11898标准的高速短距离闭环形…

关于CAN通信速率设置

一、 CAN时钟周期&#xff08;Tq&#xff09;2*晶振时钟*BRP&#xff08;波特率预分频值 baudrate prescaler&#xff09; 一个CAN时间称为一个时间量子 Tq 1&#xff09;同步段&#xff08;Synchronization Segment&#xff09;&#xff1a;1个Tq&#xff0c;tSS 2&#x…

nano的CAN通信

我买的是微雪的树莓派用的SPI转CAN。现在用在jetson nano上。我看了一下俩模块的芯片用的都是一样的&#xff0c;引脚也都对得上&#xff0c;所以我就打算拿这个模块给nano做can通信。 具备CAN功能&#xff0c;使用SPI接口CAN控制器MCP2515&#xff0c;搭配收发器SN65HVD230。 …

CAN通信基础知识

CAN是Controller Area Network 的缩写&#xff08;以下称为CAN&#xff09;&#xff0c;是ISO国际标准化的串行通信协议。由德国电气商博世公司在1986 年率先提出。此后&#xff0c;CAN 通过ISO11898 及ISO11519 进行了标准化。现在在欧洲已是汽车网络的标准协议。 CAN协议经过…

CAN通信详解

本章我们将向大家介绍如何使用STM32自带的CAN控制器来实现两个开发板之间的CAN通讯&#xff0c;并将结果显示在TFTLCD模块上。本章分为如下几个部分&#xff1a; 30.1 CAN简介 30.2 硬件设计 30.3 软件设计 30.4 下载验证 30.1 CAN简介 CAN 是Controller Area Network 的…

CAN通信总结

CAN通信总结 基本介绍 ​ 1. CAN通过两条通信线&#xff08;双绞线&#xff09;产生的电压差传输数据&#xff0c;一个CAN网络里的所有节点都挂在这两条通信线上&#xff0c;使用差分信号半双工通信。 ​ 2. CAN总线是广播类型的总线。所有节点都将始终接收所有通信&#xf…

CAN 通信原理学习

文章目录 CAN通信一&#xff1a;基本概述1.1 can总线是什么1.2 can总线协议的特点1.3 can的网络通信结构1.3.11.3.2 can协议网络层次 二&#xff1a;socket can在通信网络中的应用三 一个程序 CAN通信 一&#xff1a;基本概述 1.1 can总线是什么 CAN 是 Controller Area Net…

CAN通信协议

在 CAN 协议中&#xff0c;所有的消息都以固定的格式发送。总线空闲时&#xff0c;所有与总线相连的单元都可以开始发送新消息。两个以上的单元同时开始发送消息时&#xff0c;根据标识符&#xff08;Identifier 以下称为 ID&#xff09;决定优先级。ID 并不是表示发送的目的地…

CAN通信讲解(1)——基本知识

本文注意参考了《CAN入门书》&#xff0c;源于此书图片不再特殊标注 目录 1.1 CAN总线背景1.2 CAN总线定义1.3 CAN总线信号特性1.4 CAN总线传输1.5 OSI基本参照模型和CAN总线协议 1.1 CAN总线背景 为减少汽车线束数量&#xff0c;1986年&#xff0c;博世开发出面向汽车的CAN通…

CAN通信

通讯方式 UART&#xff1a;(Universal Asynchronous Receiver Transmitter&#xff1a;通用异步收发器/异步串行通信口)&#xff0c;是一种通用的串行数据总线&#xff0c;用于异步通信&#xff0c;支持全双工。它包括了RS232、RS499、RS423、RS422和RS485等接口标准规范和总线…

CAN通信----基本原理

STM32标准库开发 文章链接&#xff1a; STM32F103标准库开发----目录 STM32F103标准库开发----CAN总线通信实验----初始化/波特率 STM32F103标准库开发----CAN总线通信实验----发送和接收 资源链接&#xff1a; 本例程已经调试成功&#xff0c;下载即可使用。 STM32F103标准库…

CAN通信详解(全)

本章我们将向大家介绍如何使用STM32自带的CAN控制器来实现两个开发板之间的CAN通讯&#xff0c;并将结果显示在TFTLCD模块上。本章分为如下几个部分&#xff1a; 30.1 CAN简介 30.2 硬件设计 30.3 软件设计 30.4 下载验证 30.1 CAN简介 CAN 是Controller Area Network 的缩…

Tomcat优化禁用AJP协议

登录tomcat 在服务状态页面中可以看到&#xff0c;默认状态下会启用AJP服务&#xff0c;并且占用8009端口。 什么是AJP呢&#xff1f; AJP&#xff08;Apache JServer Protocol&#xff09; AJPv13协议是面向包的。WEB服务器和Servlet容器通过TCP连接来交互&#xff1b;为了…

tomcat启动出现错误:Failed to destroy end point associated with ProtocolHandler[“ajp-nio-8009“](解决非常简单)

tomcat启跑不起来而且报了很多莫名其妙的错误不知道从哪里找起 启动服务器出现这个错误 console提示&#xff1a;Failed to destroy end point associated with ProtocolHandler[“ajp-nio-8009”] 直接看web.xml的url-pattern这个属性是不是哪一个少了‘/’ 或者 如果没有…

Java安全-Tomcat AJP 文件包含漏洞(CVE-2020-1938)幽灵猫漏洞复现

Tomcat AJP 文件包含漏洞&#xff08;CVE-2020-1938&#xff09; CVE-2020-1938 又名GhostCat ApacheTomcat服务器中被发现存在文件包含漏洞&#xff0c;攻击者可利用该漏洞读取或包含Tomcat 上所有 webapp 目录下的任意文件 该漏洞是一个单独的文件包含漏洞&#xff0c;依赖…

Aapache Tomcat AJP 文件包含漏洞-(CVE-2020-1938/CNVD-2020-10487)

漏洞编号 CVE-2020-1938 CNVD-2020-10487 靶机环境 Vulhub虚拟靶场 vulhub-master/tomcat/CVE-2020-1938 启动docker&#xff1a; 启动成功&#xff1a; 0x00 漏洞简介 2月20日&#xff0c;国家信息安全漏洞共享平台&#xff08;CNVD&#xff09;发布了Apache Tomcat文件包含漏…

Apache-Tomcat-Ajp漏洞测试与修复

说明 Apache Tomcat会开启AJP连接器,方便与其他Web服务器通过AJP协议进行交互。由于Tomcat本身也内含了HTTP服务器&#xff0c;因此也可以视作单独的Web服务器。此漏洞为文件包含漏洞&#xff0c;攻击者可利用该漏洞读取或包含 Tomcat 上所有 webapp 目录下的任意文件&#xf…