CAN总线详解及STM32的CAN通信编程指南

2023-11-15

对于CAN通信而言,本人之前也未接触了解过,由于实习的技术要求,因此也花费了一段时间对CAN通信进行学习,并且实现了基于STM32的CAN环回静默模式通信,因此写一遍比较详细的文章对该内容进行总结。本文的参考资料有STM32的中文参考手册、协议手册等。话不多说开始吧!

什么是CAN?

CAN是一种通信的方式,就是用来传递数据的,是属于串行通信的一种,是异步的半双工通讯,根据通信速率的不同可以分为高速CAN和低速CAN,主要的区别是在于对总线电平和数据传输速率(波特率)的定义,分别遵循ISO的不同标准。

低速CAN   通信速率 10-125Kbps,总线长度可达1000米。

高速CAN(ISO11898)通信速率125kbps~1Mbps,总线长度≤40米  经典CAN 。

CAN FD     通信速率可达5Mbps,并兼容经典CAN,遵循ISO 11898-1 做数据收发。

CAN的总线组成为:CAN控制器(芯片内的CAN外设),CAN收发器(CAN的收发器芯片),

CAN_High和CAN_Low两根线构成的总线结构

对于CAN_High、CAN_Low是共同组成一组差分的信号线,CAN网络中的物理信号是基于差分信号进行传输的,其终端的电阻是在高速CAN中防止信号反射和振铃。

低速的CAN是属于开环总线,高速的CAN是属于闭环总线。对于CAN总线有以下特点:多主控制,每个设备都是可以主动的发送数据,当然这一点就会涉及到优先级的问题,这个问题会在后面详细介绍。在CAN中是没有类似于地址的信息,数据是以广播的形式,所以这个特点也就涉及到CAN的ID相关信息。

写到现在,可以简单的回答一下几个问题:一个节点的MCU向总线上那么多的节点的某一个节点

发送消息的?一个节点又是如何知道某个信息是发送给自己或者不是发送给自己呢?这个就会涉及到CAN的ID 和CAN控制器的过滤器的内容啦。

CAN的简洁的物理层必须要配上一套更加复杂的协议

CAN的总线是使用差分信号,其物理媒介是一对双绞线,这样差分信号的优点可以实现对干扰信号的抵消,总线上是CAN_High、CAN_Low.通过电位差来判断总线的电平,当然在这个地方高速CAN和低速CAN是不一样的。

 在经典CAN及高速CAN中:

 显性电平:总线上逻辑0表示显性,遇0得0,显性最强  差分信号的电压差一般为2V

 隐形电平:总线上逻辑1表示隐形,隐形的攻击性不强 差分信号的电压差一般为0

在低速CAN中

显性电平:逻辑0表示显性 显性的电压差一般为3V

隐形电平:逻辑1表示隐性 隐性的电压差一般为-1.5V

刚刚说到,显性电平是逻辑0,并且是具有正的电压差的,因此显性电平是具有优先权的,只要有一个节点输出显性电平,总线上即为显性电平。但是隐性电平是需要所有的节点都输出隐性电平,总线上才是才是隐形电平。从逻辑上来说这是一种与逻辑,其物理的实现是通过集电极开路电路实现的。

说到这些电平是需要CAN的收发器实现的,目前CAN的收发器芯片有TAJ1050、TJA1042、SIST1050T。CAN收发器芯片能够将微控制器的逻辑电平转换为CAN总线所使用的物理层电平,并负责将数据发送到总线上,同时接收总线上的数据并将其转换为适合微控制器处理的逻辑电平。收发器芯片还包含其他功能,如滤波、保护电路等,以确保可靠的通信。有了CAN的收发器实现差分信号到逻辑信号的转换之后,我们就可以基于CAN的控制器实现CAN的帧的通信。CAN的协议定义了五种类型的帧。

对于CAN的帧有数据帧、遥控帧、错误帧、过载帧、间隔帧。我们今天主要是针对标准的数据帧进行实现。

数据帧是由七段来组成的,当然数据帧又分为标准帧CAN2.0A、扩展帧CAN2.0B 

帧起始:表示数据帧开始的段,是以显性信号表示,SOF发出后会产生一个跳变沿用于整个CAN网络的时间同步。

仲裁段:表示该帧优先级的段,该部分和CAN的过滤器相关,标准格式ID有11个位,从ID28到ID18被依次发,ID禁止设置高7位为隐性

控制段:表示数据的字节数和保留位的段,控制段是由6个位构成的,四个位为DLC,称数据长度码,表示后面要表示的数据的字节数,还有两个保留位

数据段:数据的内容,一帧可以发送0-8字节的数据

CRC段:检查帧的传输错误的段,由15个位的CRC顺序和一个位的CRC界定符构成

ACK段:表示确认正确接收的段,该段由两位组成,其中一位是界定符,对于发送单元而言在该段发两个隐性位,接收段在ACK Slot段发送显性位,通知发送单元是正常接收结束

帧结束:是以七个隐性电平表示数据帧的结束 

对CAN的位时序介绍:在CAN总线上我们是读取电平来实现表征数据0、1。对于没有时钟线的CAN总线里,是以“位时序”的机制,实现对电平的正确采样,位数据是由四段组成的:

同步段SS:1Tq

传播时间段PTS:1~8Tq

相位缓冲段PBS1:1~8 Tq

相位缓冲段PBS2:2~8Tq

此外因时钟的频率偏差,传送延迟等,各单元有同步午餐,SJW为再补偿宽度,其实我们对位同步而言不需要太深入的了解其实现,该部分主要是由硬件自动完成,我们在程序设计中该部分主要是对我们的CAN波特率进行了设置,以STM32F103C8T6为例子

//CAN初始化
//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq
//tbs2:时间段2的时间单元.   范围:CAN_BS2_1tq~CAN_BS2_8tq;
//tbs1:时间段1的时间单元.   范围:CAN_BS1_1tq ~CAN_BS1_16tq
//brp :波特率分频器.范围:1~1024;  tq=(brp)*tpclk1
//波特率=Fpclk1/((tbs1+tbs2+1)*brp);
//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
//Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);
//则波特率为:36M/((8+9+1)*4)=500Kbps

在STM32中的位时序和CAN的标准位时序有一点区别,在STM32中 包含三段,分别是同步段SYNC-SEG、位段BS1、位段BS2.采样的点是在BS1、BS2的交界处,同步段的固定长度是1Tq,对BS1、BS2可以在位时序寄存器上CAN——BTR设置他们的时间长度,它们可以在重新同步期间增加或者缩短。SJW也可以在位时序寄存器中配置。

BS1段时间:

TS1=Tq x (TS1[3:0] + 1),

BS2段时间:

TS2= Tq x (TS2[2:0] + 1),

一个数据位的时间:

T1bit =1Tq+TS1+TS2 =1+ (TS1[3:0] + 1)+ (TS2[2:0] + 1)= N Tq

其中单个时间片的长度Tq与CAN外设的所挂载的时钟总线及分频器配置有关,CAN1和CAN2外设都是挂载在APB1总线上的,而位时序寄存器CAN_BTR中的BRP[9:0]寄存器位可以设置CAN外设时钟的分频值,所以:

Tq = (BRP[9:0]+1) x TPCLK

其中的PCLK指APB1时钟,默认值为45MHz。

最终可以计算出CAN通讯的波特率:

BaudRate = 1/N Tq

通过设置这些参数确定我们CAN总线的整体波特率。该部分也是我们在CAN的初始化过程中需要进行设置的。

关于报文寻址的问题

CAN网络中的通信基于与内容相关的寻址,因为CAN节点本身是没有ID的,但是可以通过ID区分CAN报文,所有CAN节点都会收到总线广播发送的所有CAN报文,每个接收方都根据自己的需求自行的选择CAN/报文。

STM32F103的CAN回环通信

stm32f103C8T6的最小系统板只有一个CAN的控制器,没有收发器,因此我们在实验中只能选择其回环模式进行测试。

CAN2.0A:只能处理标准数据帧且扩展帧的内容会识别错误

CAN2.0B  Active可以处理标准数据帧和扩展数据帧,

CAN2.0B Passive 只能出来标准数据帧且扩展帧的内容会忽略

STM32的CAN控制器功能如下:

 bxCAN模块可以完全自动的接收和发送CAN报文

我们可以通过控制、状态、配置寄存器实现

1.配置CAN参数,如波特率

2.请求发送报文

3.处理报文接收

4.管理中断

5.获取诊断信息

有三个发送邮箱来发送报文,发送调度器是根据优先级来决定那个邮箱的报文被发送。通过接收过滤器对广播的报文进行过滤,过滤器是和接收的邮箱进行连接的,在STM32F103中有14个位宽可变/可配置的标识符过滤器组,有两个接收的FIFO,每个FIFO都可以存放3个完整的报文。

对于CAN的控制器有三种工作模式:

初始化模式   该模式下对寄存器进行配置

正常模式       CAN总线同步,开始数据的接收和发送

睡眠模式        当我们复位后是进入睡眠模式,可降低功耗

同样的CAN的控制器有以下测试模式

静默模式:只向总线发送1不能发送0,可以从总线接收数据,可以实现对总线的统计。

环回模式:发送的数据直接到输入(总线可以监测数据),不能从总线接收数据,可用于自检

环回静默模式:发送的数据直接到输入(总线不可监测到数据),也不能从总线接收到数据 可用于自检并且不影响总线

 发送处理的流程如下:

 

接收处理的流程如下:

CAN的初始化结构体

CAN的外设功能非常的多,涉及的寄存器也是十分的丰富,我们可以通过标准库里面的各种结构体函数及库函数对这些控制过程实现简化。

/* Initialization and Configuration functions *********************************/ 
uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct);
void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct);//初始化CAN的过滤器
void CAN_StructInit(CAN_InitTypeDef* CAN_InitStruct);//初始化CAN的控制器
void CAN_SlaveStartBank(uint8_t CAN_BankNumber); //启动CAN从机过滤器
void CAN_DBGFreeze(CAN_TypeDef* CANx, FunctionalState NewState);//控制CAN控制器的调试模式
void CAN_TTComModeCmd(CAN_TypeDef* CANx, FunctionalState NewState);//控制CAN控制器的TT-COM模式

/* Transmit functions *********************************************************/
uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage);//用于CAN消息的发送
uint8_t CAN_TransmitStatus(CAN_TypeDef* CANx, uint8_t TransmitMailbox);//用于获取CAN消息发送状态
void CAN_CancelTransmit(CAN_TypeDef* CANx, uint8_t Mailbox);//取消发送

/* Receive functions **********************************************************/
void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage);//CAN消息接收
void CAN_FIFORelease(CAN_TypeDef* CANx, uint8_t FIFONumber);//清空缓冲区
uint8_t CAN_MessagePending(CAN_TypeDef* CANx, uint8_t FIFONumber);//获取CAN接收FIFO中待处理的消息数量

/* Operation modes functions **************************************************/
uint8_t CAN_OperatingModeRequest(CAN_TypeDef* CANx, uint8_t CAN_OperatingMode);
uint8_t CAN_Sleep(CAN_TypeDef* CANx);
uint8_t CAN_WakeUp(CAN_TypeDef* CANx);

/* Error management functions *************************************************/
uint8_t CAN_GetLastErrorCode(CAN_TypeDef* CANx);
uint8_t CAN_GetReceiveErrorCounter(CAN_TypeDef* CANx);
uint8_t CAN_GetLSBTransmitErrorCounter(CAN_TypeDef* CANx);

/* Interrupts and flags management functions **********************************/
void CAN_ITConfig(CAN_TypeDef* CANx, uint32_t CAN_IT, FunctionalState NewState);
FlagStatus CAN_GetFlagStatus(CAN_TypeDef* CANx, uint32_t CAN_FLAG);
void CAN_ClearFlag(CAN_TypeDef* CANx, uint32_t CAN_FLAG);
ITStatus CAN_GetITStatus(CAN_TypeDef* CANx, uint32_t CAN_IT);
void CAN_ClearITPendingBit(CAN_TypeDef* CANx, uint32_t CAN_IT);
		CAN_InitTypeDef CAN_InitStruct;
		CAN_InitStruct.CAN_TTCM=DISABLE;//非时间触发通信模式
		CAN_InitStruct.CAN_ABOM =DISABLE;//软件自动离线管理
		CAN_InitStruct.CAN_AWUM=DISABLE;//睡眠模式通过软件自动唤醒
		CAN_InitStruct.CAN_NART=DISABLE;//使用报文自动传送
		CAN_InitStruct.CAN_RFLM=DISABLE;//报文不锁定,新的报文可以对旧报文覆盖
		CAN_InitStruct.CAN_TXFP=DISABLE;//报文的优先级可以由标识符决定
		CAN_InitStruct.CAN_Mode=mode;//回环模式
		CAN_InitStruct.CAN_SJW=tsjw;
		CAN_InitStruct.CAN_BS1=tbs1;
		CAN_InitStruct.CAN_BS2=tbs2;
		CAN_InitStruct.CAN_Prescaler=brp;
		CAN_Init (CAN1,&CAN_InitStruct);

		CAN_FilterInitTypeDef CAN_FilterInitStruct;
		CAN_FilterInitStruct.CAN_FilterNumber=0;//选择过滤器0
    CAN_FilterInitStruct.CAN_FilterActivation=ENABLE;//激活过滤器0
		CAN_FilterInitStruct.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
		CAN_FilterInitStruct.CAN_FilterIdHigh=0x0000;
		CAN_FilterInitStruct.CAN_FilterIdLow=0x0000;
		CAN_FilterInitStruct.CAN_FilterMaskIdHigh=0x0000;
		CAN_FilterInitStruct.CAN_FilterMaskIdLow=0x0000;
		CAN_FilterInitStruct.CAN_FilterMode= CAN_FilterMode_IdMask;
		CAN_FilterInitStruct.CAN_FilterScale=CAN_FilterScale_32bit;
		CAN_FilterInit(&CAN_FilterInitStruct);

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CAN总线详解及STM32的CAN通信编程指南 的相关文章

  • 你为什么没有男朋友

    一月 放寒假 买票回家 小A托老乡学长代买 请饭答谢 一来二去 学长遂成男友 一月 放寒假 你自己半夜去车站排队 然后 就没有然后了 二月 同学聚会 小B与当年暧昧的男同学的再续前缘 老同学遂成男友 二月 你在家帮你妈做卫生 然后 就没有然
  • Stream流的常用方法

    目录 一 遍历 1 属性遍历 2 对象遍历 3 遍历设值 二 过滤 1 简单过滤 2 多条件过滤 三 去重 四 统计 五 截取 六 跳过 七 排序 1 普通排序 2 指定排序 八 最值 1 集合确定不为空 2 集合可能为空 九 统计 十 L
  • 织梦DEDECMS EXCEL数据批量导入文章插件 支持自定义模型和字段 2021/09/13更新

    插件介绍 本插件为织梦EXCEL批量导入数据插件 支持tag导入 目前只有UTF版本 GBK版本自行转码 默认只支持普通文章模型 不包括自定义字段 需要另外模型或者添加新字段的可以联系客服收费修改 支持自定义字段和自定义模型 使用前 请先备

随机推荐

  • RabbitMQ交换机(扇出模式、直接模式)学习笔记

    视频地址 什么是交换机 RabbitMQ 消息传递模型的核心思想是 生产者生产的消息从不会直接发送到队列 实际上 通常生产 者甚至都不知道这些消息传递传递到了哪些队列中 情况实际上是这样的 生产者只能将消息发送到交换机 exchange 交
  • centos 安装opencv-python(及其安装错误解决方法)

    pip3 install opencv python 引入模块出错 ImportError libSM so 6 cannot open shared object file No such file or directory Import
  • css 实现背景图片拉伸

    使用css3 属性 background size background size cover 即可实现像桌面壁纸一样拉伸 以下是w3c上面的解释 语法 background size length percentage cover con
  • android反编译-修改别人apk(如何无视R文件,使用新增布局xml drawable等)

    前言 反编译是枯燥无味的 也是危险的 请务必避免包吃包住 17年写的有点乱已经重新排版 1 如果二次打包成APK给其他人使用 本文方案 2 如果只是自己使用或者有耐心的用户听你搞分身或者ROOT的 可以采用XPOSED方案 后续会补上XPO
  • 转:http协议学习系列(响应头---Response Headers)

    HTTP最常见的响应头如下所示 Allow 服务器支持哪些请求方法 如GET POST等 Content Encoding 文档的编码 Encode 方法 只有在解码之后才可以得到Content Type头指定的内容类型 利用gzip压缩文
  • Edge 浏览器『版本回退』和『关闭更新』

    前言 最近 Edge 浏览器又更新了 给整体浏览器页面布局进行大改动 之前苗条的标签页和收藏夹栏瞬间变得臃肿了 我实在无法忍受这种布局 所以我索性直接进行版本回退和设置永久关闭更新 详细步骤请看下文 Edge 浏览器版本回退官方文档 Mic
  • 刷脸支付全面爆发只是时间问题

    支付宝领先的微信支付是依附于电商的绝对优势 另一方面 微信支付凭借其10亿用户的优势 正在与支付宝抗衡 近几年来 移动支付的快速发展带动了支付技术的变革 nfc支付 二维码支付 指纹支付等支付方式活跃在我们的日常生活中 随着人脸识别技术的成
  • 【C++】反向迭代器精讲(以list为例)

    目录 二 全部代码 三 设计思路 1 讨论 2 关于迭代器文档一个小细节 结语 一 前言 如果有小伙伴还未学习普通迭代器 请参考这篇文章中的普通迭代器实现 STL list用法 试做 底层实现 花果山 程序猿的博客 CSDN博客 参考lis
  • 为什么会出现Date类型传到数据库后面的时分秒变为0?

    前言 今天写代码的时候遇到了一个问题 现在来和大家分享一下 创建时间 crea time在数据中是Datetime类型 但是当我在实体类上使用 Temporal 注解来给这个日期类型进行转换时 如果要是用 Temporal Temporal
  • sam文件学习1

    1 FLAG说明 Each bit in the FLAG field is defined as 0x0001 p the read is paired in sequencing 0x0002 P the read is mapped
  • 创建RAM程序,验证程序在DDR上的运行

    前面我们验证了程序运行在SRAM中 也就是程序运行在L2 cache中 但是对于启动操作系统 这并不够 操作系统要必须要足够大的RAM 所以我们必须要程序运行在RAM中 也就是DDR上 环境 CodeWarriorDevelopmentSt
  • jwt的token自动续约_JWT token过期自动续期解决方案

    access token 用于一般的资源请求的token refresh token access token过期后用于刷续期的token 注意设置refresh token的过期时间需比access token的过期时间长 问题场景与解决
  • 【OpenCV图像处理】1.11 形态学操作 - 开操作、闭操作、顶帽、黑帽

    形态学操作 开操作 闭操作 顶帽 黑帽 开操作 open 先腐蚀后膨胀 d s t o p
  • qml使用数组技巧

    在qml中 使用JS数组 修改里面的值 不发出change信号 my array n value 为了得到数组属性通知 你必须使用下面这个技巧 var tmp my array tmp n value 你可以做多个更改 也可以push sp
  • 设计模式:外观模式

    有些人可能炒过股票 但其实大部分人都不太懂 这种没有足够了解证券知识的情况下做股票是很容易亏钱的 刚开始炒股肯定都会想 如果有个懂行的帮帮手就好 其实基金就是个好帮手 支付宝里就有许多的基金 它将投资者分散的资金集中起来 交由专业的经理人进
  • Redis——认识Redis

    简单介绍 Redis诞生于2009年 全称是Remote Dictionary Server 远程词典服务器 是一个基于内存的键值型NoSQL数据库 特征 键值 Key value 型 value支持多种不同数据结构 功能丰富 单线程 每个
  • Qt简单的异步操作实现方法

    Qt简单的异步操作实现方法 在实际应用中 经常会遇到一些耗时操作 导致了主线程的阻塞 这时候可以使用异步操作来避免阻塞 Qt的异步操作需要使用下面的库 include
  • python写邮箱验证工具_Python编写的Linux邮件发送工具

    之前有用过Linux自带的mail工具来定时发送邮件 但是要装mailx还有配mail rc 这还比较正常 关键是到了ubantu下这工具用起来真是操蛋 如果哪天其他的unix like操作系统也有需求 那就太麻烦了 所以我用自带的pyth
  • QT界面布局和设计

    一 设计 对功能和模块进行分析 然后设计对应的模块 将每个模块都用widget展示作为组件 工程结构示例 二 完成模块 代码分别设计各个组件 合适即可 三 主界面连接 主界面连接各个子模块 在这里插入代码片 include AutoFlaw
  • CAN总线详解及STM32的CAN通信编程指南

    对于CAN通信而言 本人之前也未接触了解过 由于实习的技术要求 因此也花费了一段时间对CAN通信进行学习 并且实现了基于STM32的CAN环回静默模式通信 因此写一遍比较详细的文章对该内容进行总结 本文的参考资料有STM32的中文参考手册