CAN通讯协议详解

阅读引言: 本篇博文想给需要的人介绍一下CAN总线, 这个也算是我从B站学习记得笔记分享吧也算是。简单的介绍了CAN总线的大致内容, 简述支持CAN功能的STM32的简单使用例程。本视频的中的图片内容均来自B站爱上半导体博主的内容。

CAN高质量教学视频

目录

1.CAN总线详细讲解

2.STM32的CAN总线通信的简单引入



1.CAN总线详细讲解


  • CAN通讯总线的简单介绍

Can 总线应用最多的是汽车领域,Can 是Control every network 的首字母缩写,意思是控制器局域网

CAN通讯协议详解_第1张图片

控制器局域网, 该通信总线应用最多的是汽车领域。

CAN通讯协议详解_第2张图片

局域网,想必大家都很熟悉,就是把几台电脑连到一个路由器上, 这样这几台电脑就可以通讯了

CAN通讯协议详解_第3张图片

那CAN 和这个也类似,这里的控制器在汽车中的专业术语叫Ecu, 电子控制单元

CAN通讯协议详解_第4张图片意思是电子控制单元,它可以看作是一台超小型的计算机,它内部集成了供电系统,单片机驱动系统是汽车里面最小的控制模块,为了能让Ecu之间进行通讯,

CAN通讯协议详解_第5张图片ECU是汽车中的最小控制单元

为了能让ECU之间能够进行通信, 人们设计了can通讯, 为了减少线束的数量

CAN通讯协议详解_第6张图片

而如果不使用看总线,ECU之间是点对点通信的, 那将使用数倍长的铜线,而且线数还非常杂乱,而通过Can 这么多Ecu 只需要挂载到看总线上就可以组成局域网通讯了,大大减少了线束的长度,那接下来我们就来说,一下看总线到底是如何通讯的。

CAN通讯协议详解_第7张图片

  • CAN的通讯实现

CAN通讯协议详解_第8张图片

要进行看通讯,需要专门的看收发芯片,这是单片机的发送和接收线,它的逻辑一是高电平逻辑理应是低电平,这种普通逻辑我们很好理解

CAN通讯协议详解_第9张图片

但是经过CAN收发器之后,普通信号就会被转化成差分信号,差分线是用2根线表示一个信号

CAN通讯协议详解_第10张图片

如果我们使用单片机给CAN收发器发送一个低电平,它的2根线分别输出3.5伏和1.5伏,它们的电压差是两伏,这是显示电平表示逻辑零而当我们给它发送高电平,平时,它的2根线输出的都是2.5伏压差,电压差是零伏,表示逻辑一,这就是差分信号

CAN通讯协议详解_第11张图片

同样的看收发器,也可以把接收到的差分信号转化成普通电瓶信号,然后再发给单片机,那采用差分信号有什么好处呢?

CAN通讯协议详解_第12张图片

那这样有什么好处呢?如果只有一根线,但某一点受到干扰,它的电瓶就会发生跳变,这样就会导致传输出现错误,所以不能进行长距离传输,而看通讯采用的差分信号是2根线共同作用

CAN通讯协议详解_第13张图片

而CAN通讯采用的时两根线共同作用,而且是双脚线缠绕,这样即使是受到干扰,也是2根线同时受到干扰,它们的压差也会保持不变,这样就能保证传递的信息不受干扰,所以看信号可以传输的距离很长,可达1000米

CAN通讯协议详解_第14张图片

CAN通讯协议详解_第15张图片

CAN通讯协议详解_第16张图片

  • CAN的数据帧

那接下来我们来说一下CAN通讯到底在传递什么可以看一下,这是一帧标准的数据帧

CAN通讯协议详解_第17张图片

第一位是起始位,它一定得是逻辑0

CAN通讯协议详解_第18张图片

接下来的11位是识别码根据是11位识别码就能知道这一张信息是发给哪一个设备呢,每一个设备都有属于自己的11位识别码

CAN通讯协议详解_第19张图片

CAN通讯协议详解_第20张图片

接下来的一位是用来区分数据帧或者远程请求帧,如果是远程请求帧,这一位是一,而我们这是一串数据帧,这里就必须得是零

CAN通讯协议详解_第21张图片

接下来的6位是控制码,它是控制数据长度的,先说它的第一位, IDE位,第一位用来区分标准格式和拓展格式,

CAN通讯协议详解_第22张图片

CAN通讯协议详解_第23张图片

在标准格式当中,有11位识别码,这一位是逻辑零而在拓展格式中,它的识别码有11位,这一位是逻辑0

下面一位是预留位,它是逻辑零

CAN通讯协议详解_第24张图片

接下来的4位是DLC 位及数据长度代码,它的二进制编码是零到八,

CAN通讯协议详解_第25张图片

CAN通讯协议详解_第26张图片

如果是一则后面的数据位,就只有一个字节8位,而如果它的值是八则后面的数据位就是8个字节64位

CAN通讯协议详解_第27张图片

接下来是16位Crc 码及循环冗余校验位,它是为了确保数据的准确性而设置的,首先是15位Crc 校验码设备接收端会根据数据计算出它的Crc 位,如果计算出来的和接收到的Crc 不一致,说明数据存在问题,就会重新发送一遍,数据帧下面一位是Crc 的界定符,他是逻辑一目的是为了把后面的信息隔开

CAN通讯协议详解_第28张图片

然后是2位Ac k 码,第一位是Ac k 确认操发送端发送的是逻辑一而接收端,回复的是逻辑0应来表示应答,第2位是Ac k 界定位,它一定是逻辑一作用是把后面的数据隔开

CAN通讯协议详解_第29张图片

最后是7位结束位,这7位都是逻辑一表示数据帧传输结束

CAN通讯协议详解_第30张图片

这就是一串标准数据帧,如果用差分信号表示它的电瓶是这样的。

CAN通讯协议详解_第31张图片

因为看总线上挂载了很多设备,如果是2个设备同时发送信息,此时哪一个设备发送的信息优先呢,这就得看11位的识别码了,它不仅是设备的唯一识别码,而且还代表了优先级,比如这两帧数据是同时发出的

CAN通讯协议详解_第32张图片

CAN通讯协议详解_第33张图片

应该以哪一个为准呢,当总线上同时出现逻辑零和逻辑一的时候,总线会被制为逻辑零,此后上面那个数据帧就不会再发送了好了,这就是我对开通讯的理解,希望对你理解有帮助

CAN通讯协议详解_第34张图片

CAN通讯协议详解_第35张图片

CAN通讯协议详解_第36张图片


2.STM32的CAN总线通信的简单引入


CAN(Controller Area Network)是一种高级串行通信总线,常用于工业控制、汽车电子等领域。STM32微控制器系列中的许多型号都内置了CAN控制器,能够方便地实现CAN总线通信。本文将介绍STM32的CAN总线通信原理以及如何在STM32上实现CAN通信的方法。

CAN总线通信基本原理:

CAN总线是一种基于多主机、分布式、多节点的串行通信系统,支持高速数据传输和优先级控制。CAN总线使用两根不同的线路:CANH和CANL,以差分信号的形式传输数据。CAN总线采用CSMA/CD(Carrier Sense Multiple Access/Collision Detection)的冲突检测机制,可以避免冲突发生。

要在STM32上实现CAN总线通信,首先需要对CAN硬件进行配置和初始化,然后可以使用相应的API函数进行数据的发送和接收。

CAN通讯协议详解_第37张图片

以下是一个使用STM32的CAN总线实现数据发送和接收的示例代码:

#include "stm32xxxx.h"
​
CAN_HandleTypeDef hcan1;
​
void CAN_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  
  // 使能CAN时钟
  __HAL_RCC_CAN1_CLK_ENABLE();
  
  // 配置CAN引脚
  GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF_CAN1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  // 配置CAN控制器
  hcan1.Instance = CAN1;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.AutoBusOff = ENABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = DISABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_3TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
  
  HAL_CAN_Init(&hcan1);
}
​
void CAN_SendData(uint8_t* pData, uint32_t size)
{
  CAN_TxHeaderTypeDef TxHeader;
  
  TxHeader.StdId = 0x123;
  TxHeader.ExtId = 0;
  TxHeader.IDE = CAN_ID_STD;
  TxHeader.RTR = CAN_RTR_DATA;
  TxHeader.DLC = size;
  TxHeader.TransmitGlobalTime = DISABLE;
  
  uint32_t TxMailbox;
  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, pData, &TxMailbox);
  
  // 等待发送完成
  while (HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) != 3) {}
}
​
void CAN_ReceiveData(void)
{
  CAN_RxHeaderTypeDef RxHeader;
  uint8_t RxData[8];
  
  HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, RxData);
  
  // 处理接收到的数据
}
​
int main(void)
{
  HAL_Init();
  CAN_Init();
  
  while (1)
  {
    // 主循环代码
    
    // 发送数据
    uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
    CAN_SendData(data, sizeof(data));
    
    // 接收数据
    CAN_ReceiveData();
  }
}

在上述代码中,我们首先初始化了CAN硬件(通过CAN_Init函数)。然后,我们使用HAL_CAN_AddTxMessage函数发送数据,使用HAL_CAN_GetRxMessage函数接收数据。在主循环中,我们可以编写其他代码并调用CAN_SendData和CAN_ReceiveData函数来进行数据的发送和接收。

通过配置CAN的控制器和引脚,以及编写相应的代码,我们可以轻松地在STM32上实现CAN总线通信。使用CAN总线可以实现高速的分布式数据通信,适用于许多应用领域,如工业控制、汽车电子等。

你可能感兴趣的:(物联网,stm32,嵌入式硬件,CAN通讯)