在这个项目中,我们将学习MCP2515 CAN控制器模块,如何接口MCP2515 CAN总线控制器与Arduino,最后如何使两个Arduino板之间的通信与两个MCP2515 CAN控制器和CAN协议。
介绍
简单CAN控制区域网是一种总线标准,它允许微控制器及其外围设备不需要主机或计算机就可以进行通信。
由Robert Bosch GmbH开发,可以协议是Main用于汽车之间的用于控制单元和其组件之间的通信。
例如,发动机控制单元是汽车中主要的控制装置。该单元连接到许多传感器和执行器,如空气流量,压力,温度,阀门控制,电机空气控制等。这些模块与控制单元之间通过CAN总线进行通信。
为了对CAN总线、CAN控制器等重要方面有一点了解,MCP2515 CAN总线控制器模块是很有帮助的。
还读:spi通信基础知识。
MCP2515 CAN总线控制模块简介
MCP2515 CAN总线控制器是一个简单的模块,支持CAN协议版本2.0B,可以用于1Mbps的通信。为了建立一个完整的通信系统,您将需要两个CAN总线模块。
项目中使用的模块如下图所示。
MCP2515是一个独立的CAN控制器,集成了SPI接口,用于与微控制器通信。
在TJA1050 IC上,它作为MCP2515 CAN控制器IC和物理CAN总线之间的接口。
下图显示了典型MCP2515模块上的组件和引脚。
MCP2515 CAN总线模块的原理图
在查看模块的原理图之前,您需要了解关于ICS i.E.MCP2515和TJA1050的几件事。
MCP2515 IC是主控制器,内部由三个主要子组件组成:CAN模块,控制逻辑和SPI块。
CAN模块负责在CAN总线上传输和接收消息。控制逻辑通过接口所有块来处理MCP2515的设置和操作。SPI块负责SPI通信接口。
来看看TJA1050 IC,因为它作为MCP2515 CAN控制器和物理CAN总线之间的接口,这个IC负责从控制器获取数据并将其中继到总线。
下图是MCP2515 CAN模块的原理图,显示了MCP2515 IC和TJA1050 IC在模块上是如何连接的。
MCP2515与Arduino接口电路图
以下图像显示了与Arduino的接口MCP2515 Can模块的电路图,以及两个Arduino通过CAN协议之间的可能通信。
如果MCP2515模块的引脚不清楚,下面的图像可能有用。
组件的要求
- arduino uno x 2 [在这里买]
- MCP2515 x 2
- USB连接线x 2
- 连接电线
电路设计
如前所述,CAN控制器IC促进SPI通信协议与任何微控制器接口。将MCP2515模块的SPI引脚SCK, MOSI (SI), MISO (SO), CS与Arduino对应的SPI引脚连接(见电路图)。
做两个这样的连接:一对作为发射器,另一对作为接收器。现在这个发射器和接收器之间的通信,连接每个MCP2515模块的CANH和CANL引脚。
代码
在进入代码之前,需要下载MCP2515模块的库。有很多图书馆,但我用过这特别的一个。
下载并将提取的内容放在Arduino的库目录中。
由于通信涉及到发送模块和接收模块,所以代码又分为发送代码和接收代码。
发射机的代码
接收方代码
工作
这个项目的工作非常简单,所有的工作都由库(SPI和CAN)完成。由于CAN是基于消息的通信,您需要在0到8字节之间发送消息。
在本项目中,发射机发送的信息为1 1 2 3 0 5 6 7。该信息通过CAN总线传输,接收机接收到该信息并显示在其串行监视器上。
此外,0TH.和图4TH.接收机分别提取上述序列中的1位和0位,并将Arduino 2引脚连接的LED开关ON和OFF。
应用程序
如前所述,CAN在汽车领域得到了广泛的应用。其中一些应用包括:
- 电子换档系统
- 自动化主界面(如工业)
- 医疗设备
- 机器人
- 汽车启动/停止汽车发动机
15反应
感谢您的信息。获得2个Arduinos + MCP彼此交谈是有趣和简单的。连接到车辆的Obdii端口时会发生挑战。那是根据我的经验,事情变得更加复杂:
-车辆可以使用标准的can帧或扩展帧(我不确定Seeed库是否适用于扩展的can帧)。
-即使是使用标准CAN帧的车辆,当你发送PID请求例如引擎的转速,似乎车辆没有收到数据。
任何指引吗?
谢谢,
戴夫
如果您还没有找到答案,那么大多数较新的汽车都有防火墙,因此您不能从OBD端口获得某些数据,除非您实际使用OBD协议来获得DTC pid。例如,与ECU直接连接的老式汽车应该可以工作。
嘿!你举的这个例子似乎很不错。我只是想知道我能不能把一个Arduino同时编码成发射器和接收器。
谢谢! !
Paul.
嗨。我追求的是类似于宝拉的东西。在我的情况下,我感兴趣的是从一个Arduino运行两个CAN模块-在双总线车(HSCAN=500kbps, MSCAN=125kbps)或作为一个隔离的CAN桥接-例如,当一个电液动力转向泵从一个不同的模型,需要广播的CAN翻译工作,但一定不能看到新车辆的原始信息。虽然SPI适用于多个模块,但我想我很难找到一个同时支持多个CAN接口的库。
路加福音
可能你已经找到了这个,但如果你需要它:
你可以像这样创建2个不同的对象来连接到2个MC2515 shiles:
mcp_can can_one(spicspin1);
MCP_CAN CAN_TWO (spiCSPin2);
例如,你需要两个CS引脚
spiCSPin1 = 10
spiCSPin2 = 9
您将这些连接到每个CAN模块上的相应CS引脚
而另一个SPI引脚(11,12,13)连接到两个模块
SPI是一个总线,所以每个从设备只需要一个额外的引脚。
所以,你可以用不同的速度初始化这两个模块的CANbus。等等,你可以分别读和写。
如果你依赖中断引脚来通知你收到的消息,你可能需要额外的引脚。在这种情况下,您可以使用引脚2和3。否则,您可以依赖这两个模块的频繁轮询。然而,也要考虑到编程是更复杂的2模块和MCU可能超载
你好,
我的项目像这样,然而我使用35tem。传感器。但我不会写代码。ı怎么写?
嗨
如果我需要发送消息,然后接收一个答案,将答案重新打包到不同的数据包并将其发送回-如何在一个单一的草图?
我在一个大学项目中,在我们建造了一个电流摩托车,可以用罐头进行通信。我使用了一半的项目来试图阅读公共汽车可以,但它甚至无法通过Begin.Can循环。从我在网上看到的东西,它可能是由于晶体是8oookhz,图书馆是为16000khz制作的。你能帮助我吗?
对你来说可能为时已晚,但其他人可能会发现这种有用。功能MCP2515_CONFIGRETE接受晶体频率作为第二个参数...... 8MHz只通过MCP_8MHz
/ *********************************************************************************************************
**函数名称:MCP2515_CONFIGRATE
**说明:设置波特率
*********************************************************************************************************/
mcp2515_can::mcp2515_configRate(const byte canSpeed, const byte clock) {
字节集,CFG1,CFG2,CFG3;
= 1;
开关(时钟){
案例(MCP_16MHz):
开关(canSpeed) {
案例(CAN_5KBPS):
cfg1 = MCP_16MHz_5kBPS_CFG1;
cfg2 = MCP_16MHz_5kBPS_CFG2;
cfg3 = mcp_16mhz_5kbps_cfg3;
休息;
案例(CAN_10KBPS):
cfg1 = mcp_16mhz_10kbps_cfg1;
cfg2 = MCP_16MHz_10kBPS_CFG2;
cfg3 = MCP_16MHz_10kBPS_CFG3;
休息;
案例(CAN_20KBPS):
cfg1 = MCP_16MHz_20kBPS_CFG1;
cfg2 = MCP_16MHz_20kBPS_CFG2;
cfg3 = mcp_16mhz_20kbps_cfg3;
休息;
案例(CAN_25KBPS):
cfg1 = mcp_16mhz_25kbps_cfg1;
cfg2 = mcp_16mhz_25kbps_cfg2;
cfg3 = mcp_16mhz_25kbps_cfg3;
休息;
案例(CAN_31K25BPS):
cfg1 = mcp_16mhz_31k25bps_cfg1;
cfg2 = MCP_16MHz_31k25BPS_CFG2;
cfg3 = MCP_16MHz_31k25BPS_CFG3;
休息;
案例(CAN_33KBPS):
cfg1 = MCP_16MHz_33kBPS_CFG1;
cfg2 = mcp_16mhz_33kbps_cfg2;
cfg3 = mcp_16mhz_33kbps_cfg3;
休息;
案例(CAN_40KBPS):
cfg1 = MCP_16MHz_40kBPS_CFG1;
cfg2 = mcp_16mhz_40kbps_cfg2;
cfg3 = mcp_16mhz_40kbps_cfg3;
休息;
案例(CAN_50KBPS):
cfg1 = MCP_16MHz_50kBPS_CFG1;
cfg2 = MCP_16MHz_50kBPS_CFG2;
cfg3 = MCP_16MHz_50kBPS_CFG3;
休息;
案例(CAN_80KBPS):
cfg1 = mcp_16mhz_80kbps_cfg1;
cfg2 = MCP_16MHz_80kBPS_CFG2;
cfg3 = MCP_16MHz_80kBPS_CFG3;
休息;
案例(CAN_83K3BPS):
cfg1 = mcp_16mhz_83k3bps_cfg1;
cfg2 = MCP_16MHz_83k3BPS_CFG2;
cfg3 = MCP_16MHz_83k3BPS_CFG3;
休息;
案例(CAN_95KBPS):
cfg1 = MCP_16MHz_95kBPS_CFG1;
cfg2 = mcp_16mhz_95kbps_cfg2;
cfg3 = MCP_16MHz_95kBPS_CFG3;
休息;
案例(CAN_100KBPS):
cfg1 = MCP_16MHz_100kBPS_CFG1;
cfg2 = mcp_16mhz_100kbps_cfg2;
cfg3 = mcp_16mhz_100kbps_cfg3;
休息;
案例(CAN_125KBPS):
cfg1 = MCP_16MHz_125kBPS_CFG1;
cfg2 = MCP_16MHz_125kBPS_CFG2;
cfg3 = MCP_16MHz_125kBPS_CFG3;
休息;
案例(CAN_200KBPS):
cfg1 = mcp_16mhz_200kbps_cfg1;
cfg2 = mcp_16mhz_200kbps_cfg2;
cfg3 = mcp_16mhz_200kbps_cfg3;
休息;
案例(CAN_250KBPS):
cfg1 = MCP_16MHz_250kBPS_CFG1;
cfg2 = mcp_16mhz_250kbps_cfg2;
cfg3 = mcp_16mhz_250kbps_cfg3;
休息;
案例(CAN_500KBPS):
cfg1 = MCP_16MHz_500kBPS_CFG1;
cfg2 = mcp_16mhz_500kbps_cfg2;
cfg3 = mcp_16mhz_500kbps_cfg3;
休息;
案例(CAN_666KBPS):
cfg1 = mcp_16mhz_666kbps_cfg1;
cfg2 = MCP_16MHz_666kBPS_CFG2;
cfg3 = MCP_16MHz_666kBPS_CFG3;
休息;
案例(CAN_1000KBPS):
cfg1 = MCP_16MHz_1000kBPS_CFG1;
cfg2 = MCP_16MHz_1000kBPS_CFG2;
cfg3 = mcp_16mhz_1000kbps_cfg3;
休息;
默认:
设置= 0;
休息;
}
休息;
案例(MCP_8MHz):
开关(canSpeed) {
案例(CAN_5KBPS):
cfg1 = MCP_8MHz_5kBPS_CFG1;
cfg2 = mcp_8mhz_5kbps_cfg2;
cfg3 = MCP_8MHz_5kBPS_CFG3;
休息;
案例(CAN_10KBPS):
cfg1 = MCP_8MHz_10kBPS_CFG1;
cfg2 = mcp_8mhz_10kbps_cfg2;
cfg3 = MCP_8MHz_10kBPS_CFG3;
休息;
案例(CAN_20KBPS):
cfg1 = mcp_8mhz_20kbps_cfg1;
cfg2 = MCP_8MHz_20kBPS_CFG2;
cfg3 = mcp_8mhz_20kbps_cfg3;
休息;
案例(CAN_31K25BPS):
cfg1 = MCP_8MHz_31k25BPS_CFG1;
cfg2 = mcp_8mhz_31k25bps_cfg2;
cfg3 = mcp_8mhz_31k25bps_cfg3;
休息;
案例(CAN_40KBPS):
cfg1 = MCP_8MHz_40kBPS_CFG1;
cfg2 = MCP_8MHz_40kBPS_CFG2;
cfg3 = mcp_8mhz_40kbps_cfg3;
休息;
案例(CAN_50KBPS):
cfg1 = MCP_8MHz_50kBPS_CFG1;
cfg2 = MCP_8MHz_50kBPS_CFG2;
cfg3 = MCP_8MHz_50kBPS_CFG3;
休息;
案例(CAN_80KBPS):
cfg1 = MCP_8MHz_80kBPS_CFG1;
cfg2 = MCP_8MHz_80kBPS_CFG2;
cfg3 = mcp_8mhz_80kbps_cfg3;
休息;
案例(CAN_100KBPS):
cfg1 = MCP_8MHz_100kBPS_CFG1;
cfg2 = MCP_8MHz_100kBPS_CFG2;
cfg3 = MCP_8MHz_100kBPS_CFG3;
休息;
案例(CAN_125KBPS):
cfg1 = mcp_8mhz_125kbps_cfg1;
cfg2 = MCP_8MHz_125kBPS_CFG2;
cfg3 = mcp_8mhz_125kbps_cfg3;
休息;
案例(CAN_200KBPS):
cfg1 = MCP_8MHz_200kBPS_CFG1;
cfg2 = MCP_8MHz_200kBPS_CFG2;
cfg3 = MCP_8MHz_200kBPS_CFG3;
休息;
案例(CAN_250KBPS):
cfg1 = MCP_8MHz_250kBPS_CFG1;
cfg2 = MCP_8MHz_250kBPS_CFG2;
cfg3 = mcp_8mhz_250kbps_cfg3;
休息;
案例(CAN_500KBPS):
cfg1 = MCP_8MHz_500kBPS_CFG1;
cfg2 = MCP_8MHz_500kBPS_CFG2;
cfg3 = MCP_8MHz_500kBPS_CFG3;
休息;
案例(CAN_1000KBPS):
cfg1 = mcp_8mhz_1000kbps_cfg1;
cfg2 = MCP_8MHz_1000kBPS_CFG2;
cfg3 = MCP_8MHz_1000kBPS_CFG3;
休息;
默认:
设置= 0;
休息;
}
休息;
默认:
设置= 0;
休息;
}
如果(集){
mcp2515_setRegister (MCP_CNF1 cfg1);
MCP2515_SetRegister(MCP_CNF2,CFG2);
MCP2515_SetRegister(MCP_CNF3,CFG3);
返回MCP2515_OK;
} 别的 {
返回MCP2515_FAIL;
}
}
假设我想通过4个CAN模块连接4个Arduino。
那么发送一个可以直接到1个特定的CAN接收器发送可以信息的首选方法是什么?
它不是具有地址的Arduino,它是应用程序。当您的特定Arduino使用修复ID运行“应用程序”时,可以解决此问题。
因此,您需要设计有关您想要发送的消息的应用程序。例如:打开灯ID 0x45,关闭灯ID 0x46。打开喇叭,0x10 -发送每10ms如果没有喇叭关闭。在汽车中,通常你发送每X毫秒一条信息来点亮前灯,如果信息没有发送,灯就会熄灭。这取决于应用程序的安全功能。
你好,
我已经复制了准确的发射器和接收器代码,并下载了上述的相关库。
然而,在编译错误消息时“不能声明变量CAN为抽象类型MCP_CAN”
有人能帮我解决这个错误吗
你好,
你找到解决办法了吗?
我有同样的错误
你能分享一下如何修复它吗?
我在例子中找到了答案。
# include
# include“mcp2518fd_can.h”
const int SPI_CS_PIN = 9;
mcp2515_can可以(SPI_CS_PIN);//设置CS引脚
现在工作。
这是否支持python编程?