Arduino开发实例-多机CAN-Bus通信(基于MCP2515)

多机CAN-Bus通信(基于MCP2515)

在本文中,将使用 Microchip MCP2515 CAN 总线模块和 Arduino 板进行基于CAN总线通信协议通信。 实例中使用一对 CAN 总线模块 MCP2515,我们将在一定的距离内发送 DHT11 传感器数据。 通常情况下,CAN 的通信速度范围从 50 Kbps 到 1Mbps,距离范围可以从 1Mbps 的 40 米到 50kpbs 的 1000 米。

1、CAN简单介绍

控制器局域网(Controller Area Network)也称为CAN-BUS,是一种常见的工业总线,具有传输距离长、通信速度中等、可靠性高等特点。 它常见于现代机床和汽车诊断总线。

CAN总线是博世(Bosch)开发的汽车总线,允许微控制器和设备在没有主机的情况下在车内相互通信。

CAN总线是一种基于消息的协议,专为汽车应用而设计,但现在也用于航空航天、工业自动化和医疗设备等其他领域。

CAN总线于 1994 年成为国际标准 (ISO 11898),专为机动车辆电子控制器之间的快速串行数据交换而开发。 它连接各个系统和传感器,作为传统多线织机的替代品。 它允许汽车组件在高达 1Mbps 的单线或双线网络数据总线上进行通信。

在现代车辆系统中,有超过 60 到 100 个传感器单元用于传感和交换信息。 同样,汽车制造商也在不断地通过增加自动驾驶、安全气囊系统、ABS(防制动系统)、远程信息处理、变速箱控制、电池管理系统、巡航控制系统等功能来使他们的汽车更智能。 数据在非常高速的标准汽车通信协议中是必需的。 UART、SPI 和 I2C 等标准通信协议对于该系统来说并不可靠。 因此,需要一个像 CAN 协议这样的汽车通信协议,以实现单次高速和 1000 次数据传输。

在这里插入图片描述

CAN BUS 的工作原理

CAN 总线使用两条专用线进行通信。 电线称为 CAN 高和 CAN 低。 CAN 控制器通过这两条线连接到网络上的所有组件。 每个网络节点都有一个唯一的标识符。 总线上的所有 ECU 都是有效并行的,这就是为什么所有节点一直都能看到所有数据的原因。 节点仅在检测到自己的标识符时才响应。 可以从网络中删除单个节点而不影响其他节点。

当 CAN 总线处于空闲模式时,两条线路都承载 2.5V。 当数据位正在传输时,CAN 高电平线变为 3.75V,CAN 低电平线下降到 1.25V,从而在线路之间产生 2.5V 的差分。

在这里插入图片描述

CAN 电源可以通过 CAN 总线提供。 或者CAN总线模块的电源可以单独安排。 电源线可以与 CAN 总线完全分开,从而将两条 2 线电缆用于网络,也可以将其集成到与 CAN 总线相同的电缆中,从而形成一条 4 线电缆。

CAN 总线通信的特性允许所有模块在总线上传输和接收数据。 任何模块都可以传输数据,所有其余模块都可以接收这些数据。 首先将 CAN 总线带宽分配给最安全的关键系统非常重要。 节点通常被分配到多个优先级之一。 称为仲裁的过程决定任何消息的优先级。

大多数汽车 CAN 网络以 250 kB/s 或 500 kB/s 的总线速度运行。

CAN Bus应用

CAN Bus协议应用广泛,比如:

  • 用于传输安全气囊、防抱死制动、电动助力转向等。
  • 用于音频-视频系统。
  • 用于电梯和自动扶梯。
  • 用于运动相机。
  • 用于自动门。
  • 用于望远镜和咖啡机。
  • 用于带有飞行状态传感器的飞机
  • 导航系统,以及对飞机发动机控制系统的飞行数据分析
  • 燃油系统、线性执行器和泵。
  • 用于窗户、门和镜子的调整。
  • 用于铁路应用,例如有轨电车、有轨电车、地铁、轻型铁路、长途火车等。

CAN Bus与 SPI 及I2C的比较

I2C SPI CAN
速度 标准:100Kbps,快速:400 Kbps,高速:3.4Mbps 3Mbps 至 10Mbps 10KBps 至 1MBps
类型 同步 同步 异步
接线 2 线(SDA、SCL) 4 线 (MISO, MOSI, SCK, CS) 2 线(CAN_H, CAN_L)
双工模式 半双工 全双工 半双工

2、MCP2515介绍

MCP2515 CAN 总线控制器是一个简单的模块,支持 CAN 协议 2.0B 版,可用于 1Mbps 的通信。

在这里插入图片描述

该特定模块基于 MCP2515 CAN 控制器 IC 和 TJA1050 CAN 收发器 IC。 MCP2515 IC 是一款独立的 CAN 控制器,具有用于与微控制器通信的集成 SPI 接口。 TJA1050 IC,它充当 MCP2515 CAN 控制器 IC 和物理 CAN 总线之间的接口。

在这里插入图片描述

该模块有一个 8 MHz 晶体振荡器。 甚至还提供 16 MHz 版本。 可以连接一个跳线,这将提供 120 欧姆的终止。 CAN_H 和 CAN_L 是两个螺钉,可以将电线连接到远处以与其他 CAN 模块通信。

以下是 MCP2515 CAN 模块的原理图:

在这里插入图片描述

MCP2515 IC 是主控制器,内部由三个主要子组件组成:CAN 模块、控制逻辑和 SPI 模块。 CAN 模块负责在 CAN 总线上发送和接收消息。 控制逻辑通过连接所有模块来处理 MCP2515 的设置和操作。 SPI Block 负责 SPI 通信接口。 TJA1050 IC 负责从控制器获取数据并将其中继到总线上。

MCP2515具有如下特性:

  • 使用高速CAN收发器TJA1050
  • 尺寸:40×28mm
  • 用于扩展Multi CAN总线接口的SPI控制
  • 8MHZ晶振
  • 120Ω终端电阻
  • 具有独立按键、LED指示灯、电源指示灯
  • 支持 1 Mb/s CAN 操作
  • 低电流待机操作
  • 最多可连接112个节点

3、硬件准备

本次实例使用的硬件如下:

序号 组件 描述 数量
1 Arduino 开发板 Arduino Nano Atmega328开发板 1
2 Arduino 开发板 Arduino Uno Atmega328开发板 1
3 CAN模块 MCP2515 2
4 LCD显示器 JHD1622A 16X2 LCD 显示模块 1
5 I2C模块 16x2 LCD I2C模块 1
6 温度湿度传感器 DHT11 1
7 连接线 杜邦线 30
8 面包板 面包板 2

4、硬件接线

下面将 MCP2515 CAN 总线模块与 Arduino 连接并测试 CAN 通信协议。 我们将借助一对 Arduino 板和 MCP2515 CAN 模块通过 CAN 总线传输 DHT11 传感器数据。 简单的接线如下:

在这里插入图片描述

由Arduino UNO Board、CAN 模块和I2C LCD组成的上部是接收器部分。 同样,由Arduino Nano Board、CAN Module和DHT11 传感器组成的底部是发射器部分。

发送器和接收器部分在 MCP2515 CAN 总线模块的帮助下相互连接。 发射器的 CAN_H 和 CAN_L 分别连接到接收器的 CAN_H 和 CAN_L。

具体接线如下下表:

MCP2515 引脚 Arduino 引脚
VCC 5V
GND GND
CS D10
SO D12
SI D11
SCK D13
INT D2

5、驱动实现

本次使用的CAN Bus驱动库如下:

该驱动库有如下特点:

  • 以高达 1 Mb/s 的速度实现 CAN V2.0B
  • 高达 10 MHz 的 SPI 接口
  • 标准(11 位)和扩展(29 位)数据和远程帧
  • 两个带有优先消息存储的接收缓冲区

DHT11驱动库如下:

CAN数据发送端代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <SPI.h> //Library for using SPI Communication 
#include <mcp2515.h> //Library for using CAN Communication (https://github.com/autowp/arduino-mcp2515/)
#include <DHT.h> //Library for using DHT sensor

#define DHTPIN 8
#define DHTTYPE DHT11

struct can\_frame canMsg;

MCP2515 mcp2515(10);

DHT dht(DHTPIN, DHTTYPE); //initilize object dht for class DHT with DHT pin with STM32 and DHT type as DHT11


void setup()
{
while (!Serial);
Serial.begin(9600);
SPI.begin(); //Begins SPI communication
dht.begin(); //Begins to read temperature & humidity sesnor value

mcp2515.reset();
mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ); //Sets CAN at speed 500KBPS and Clock 8MHz
mcp2515.setNormalMode();
}


void loop()
{
int h = dht.readHumidity(); //Gets Humidity value
int t = dht.readTemperature(); //Gets Temperature value

canMsg.can_id = 0x036; //CAN id as 0x036
canMsg.can_dlc = 8; //CAN data length as 8
canMsg.data[0] = h; //Update humidity value in [0]
canMsg.data[1] = t; //Update temperature value in [1]
canMsg.data[2] = 0x00; //Rest all with 0
canMsg.data[3] = 0x00;
canMsg.data[4] = 0x00;
canMsg.data[5] = 0x00;
canMsg.data[6] = 0x00;
canMsg.data[7] = 0x00;

mcp2515.sendMessage(&canMsg); //Sends the CAN message
delay(1000);
}

CAN数据接收端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <SPI.h> //Library for using SPI Communication 
#include <mcp2515.h> //Library for using CAN Communication (https://github.com/autowp/arduino-mcp2515/)
#include <LiquidCrystal\_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x3F for a 16 chars and 2 line display

struct can\_frame canMsg;

MCP2515 mcp2515(10); // SPI CS Pin 10


void setup()
{
Serial.begin(9600); //Begins Serial Communication at 9600 baudrate
SPI.begin(); //Begins SPI communication
lcd.init();
lcd.clear();
lcd.backlight(); // Make sure backlight is on
lcd.setCursor(0, 0);
lcd.print("CANBUS TUTORIAL");
delay(3000);
lcd.clear();

mcp2515.reset();
mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ); //Sets CAN at speed 500KBPS and Clock 8MHz
mcp2515.setNormalMode(); //Sets CAN at normal mode
}


void loop()
{
if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) // To receive data (Poll Read)
{
int x = canMsg.data[0];
int y = canMsg.data[1];

lcd.setCursor(0, 0); //Display Temp & Humidity value received at 16x2 LCD
lcd.print("Humi: ");
lcd.print(x);
lcd.setCursor(0, 1);
lcd.print("Temp: ");
lcd.print(y);
delay(1000);
lcd.clear();
}
}

文章来源: https://iotsmart.blog.csdn.net/article/details/127980503