当前位置: 首页 > news >正文

CAN通讯协议详解

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

CAN高质量教学视频

目录

1.CAN总线详细讲解

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



1.CAN总线详细讲解


  • CAN通讯总线的简单介绍

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

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

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

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

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

ECU是汽车中的最小控制单元

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

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

  • CAN的通讯实现

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

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

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

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

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

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

  • CAN的数据帧

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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函数进行数据的发送和接收。

img

以下是一个使用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总线可以实现高速的分布式数据通信,适用于许多应用领域,如工业控制、汽车电子等。

相关文章:

  • 基于Linux操作系统的Docker容器安装MySQL随笔
  • 微软.NET6开发的C#特性——委托和事件
  • vue基本语法总结大全
  • 【开源】JAVA+Vue.js实现高校实验室管理系统
  • Ubuntu 22 部署Zabbix 6.4
  • LeetCode、216. 组合总和 III【中等,组合型枚举】
  • Linux介绍和命令使用
  • 办公软件巨头CCED、WPS面临新考验,新款办公软件异军突起
  • 计算机设计大赛 深度学习 python opencv 火焰检测识别
  • unity-ios-解决内购商品在Appstore上面已配置,但在手机测试时却无法显示的问题
  • 机器学习 | 深入集成学习的精髓及实战技巧挑战
  • 【Android-Compose】手势检测实现按下、单击、双击、长按事件,以及避免频繁单击事件的简单方法
  • 详解计算机软件基本概念
  • VPS与云计算有什么区别?
  • 图数据库neo4j入门
  • Android 架构优化~MVP 架构改造
  • docker-consul
  • Fabric架构演变之路
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • Linux Process Manage
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • PHP 7 修改了什么呢 -- 2
  • V4L2视频输入框架概述
  • Vue2.x学习三:事件处理生命周期钩子
  • Vue实战(四)登录/注册页的实现
  • vue--为什么data属性必须是一个函数
  • Zepto.js源码学习之二
  • 从0实现一个tiny react(三)生命周期
  • 对超线程几个不同角度的解释
  • 仿天猫超市收藏抛物线动画工具库
  • 服务器从安装到部署全过程(二)
  • 关于Flux,Vuex,Redux的思考
  • 关于字符编码你应该知道的事情
  • 手写一个CommonJS打包工具(一)
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (转载)微软数据挖掘算法:Microsoft 时序算法(5)
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .NET 分布式技术比较
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • [ NOI 2001 ] 食物链
  • []我的函数库
  • [<死锁专题>]
  • [AUTOSAR][诊断管理][ECU][$37] 请求退出传输。终止数据传输的(上传/下载)
  • [corCTF 2022] CoRJail: From Null Byte Overflow To Docker Escape
  • [FTP]pureftp部署和优化
  • [hadoop读书笔记] 第十五章 sqoop1.4.6小实验 - 将mysq数据导入HBASE
  • [hdu 3746] Cyclic Nacklace [kmp]
  • [JS真好玩] 掘金创作者必备: 监控每天是谁取关了你?
  • [LeetCode]-Pascal's Triangle III 杨辉三角问题