STM32之一种双通路CAN总线消息备份冗余处理方法(十三)
STM32F407 系列文章 - Dual-CANBus-ProMethod(十三)
目录
前言
一、现状分析
二、解决思路
1.应用场景网络结构图
2.数据发送流程
3.数据接收流程
4.用到的模块
1.CAN网络速率及时间片分配
2.CAN网络消息ID组成
3.设备节点定义
4.数据格式说明
5.消息格式说明
6.FIFO队列
7.CAN发送流程
8.CAN接收流程
9.节点CAN消息冗余过滤原则
10.节点CAN消息冗余过滤机制
总结
前言
在一些对系统可靠性要求很高的应用中、或者传输环境较差的场景下,如何保证CAN总线组网通信中数据传输无缺损或者缺损率极低,是本文章主要解决的问题。
一、现状分析
在一些重要系统应用中,如飞行器、航天航空等环境,经常需要使用CAN总线来传输数据,传输过程中有可能受空间干扰或电源波动等原因,会导致某一帧数据信息缺损、错乱或者丢失。
现有技术主要是从硬件电路的可靠性出发,在节点接收端和发送端电路上增加对CAN电路的保护,如电源上增加滤波、隔离电路,在数字通信接口增加隔离电路,增强电路稳定性。这种方式,在节点单一、传输环境简单、数据信息少量的情况下,CAN总线传输的过程中比较可靠有效。但是涉及到传输环境复杂、数据量较大的情况下时,就缺乏一种保护措施,来保证数据传输的可靠性。
本文给出一种方式,采用双通路CAN总线冗余消息处理来传输数据,通过在CAN消息的发送端增加缓存机制和进行冗余备份,在接收端采用查重过滤机制来完成对数据信息处理。
二、解决思路
1.应用场景网络结构图
网络结构图中节点表示各单机设备,各节点设备通过CAN总线网络组网,采用CAN1和CAN2双总线组网机制。本文以一些重要场合为实施应用场景,通过CAN总线线缆网,对各节点设备ID分配采用互斥性设计,需保持其唯一性。各节点与各节点之间通过CAN通讯协议,以实现对各节点之间的信息通讯与控制。
CAN总线是一个广播通用通道,各类信息均在总线上传输,为了避免无关信息对各执行节点产生干扰,各节点单机必须对CAN总线节点信息进行过滤处理,只响应与本节点相关信息。单机节点在收到控制信息后,无论信息来自哪条总线,首先确认是否为重复信息,如果不是重复信息则执行动作。
2.数据发送流程
设备节点发送CAN信息处理过程 ,如下图所示。
某节点需要向外发送CAN消息时,将发送的CAN消息先存入CAN1和CAN2消息FIFO队列中,然后在主函数main()中设置while()循环,通过不间断查询方式判断CAN发送邮箱是否有空闲的(CAN发送邮箱有3个,且每个邮箱只能装一个报文)。若有空邮箱,则划出一条CAN消息从FIFO队列中出栈进入CAN发送邮箱中,等待发送;若发送邮箱都被占用,则等待下一次主循环判断CAN发送邮箱是否有空闲。设置每个邮箱优先级相同,消息依次发送,发送成功后将当前被占用的邮箱置空,等待接收CAN信息,此时CAN消息已发送CAN1和CAN2总线上;发送失败后,不设置丢弃此信息,邮箱被继续占用等待下一次发送(即CAN总线上负载率不高时)。
解释说明:将某节点向外发送CAN的消息先存入FIFO队列中,这个是对于大系统,即节点设备较多或数据量较大的情况下必须使用的,为防止某时刻CAN总线上负载率高时CAN消息丢失,对于简单系统,2、3个节点设备或少数据量的不需要存入FIFO缓存队列中,直接放入CAN发送邮箱使用。
3.数据接收流程
设备节点接收CAN信息处理过程 ,如下图所示。
总线上有数据时,设备节点通过CAN接收中断触发,接收到有效报文,被存储在3级邮箱深度的FIFO中。只要接收到有效报文时,接收回调函数会被调用,应用程序通过读取FIFO输出邮箱,来读取FIFO中最先收到的报文,等这个读完之后,才能读下一个报文。读取报文数据时,通过判断CAN句柄指针地址,判断是CAN1地址区接受的数据还是CAN2。然后对读取到的报文数据进行解析和检查是否是新消息,防止CAN1、CAN2总线上的重复消息,避免二次执行;对收到数据ID与缓存队列2中的数据ID依次进行对别,当前收到的数据ID的时间点与缓存队列2中的数据ID时间戳在8毫秒内,且二者ID相同则认为时重复消息,当丢弃此消息;若收到数据ID的时间点与缓存队列2中数据ID时间戳大于8毫秒或者二者ID不相同时,则认为时新消息,当把此消息放入缓存队列1作消息预处理使用,同时此消息ID和此消息时间戳放入缓存队列2,作判重使用。
解释说明:接收邮箱FIFO完全由硬件来管理,从而节省了CPU的处理负荷,简化了软件并保证了数据的一致性。8毫秒内判断是否为新消息,此8毫秒规定是基于系统CAN总线上最短发数周期和线路延时。
4.用到的模块
为实现上述流程图,所用到的模块有。
1.CAN网络速率及时间片分配
为保证总线为负载较低,总线速率设定为500Kbps,要求各单机节点的时钟晶振为8MHz的整数倍,时间片分配方案如下表所示。
位速率 | 每位时间片数 | 时间片分配 | ||
同步段 | 传播段+相位缓冲段1 | 相位缓冲段2 | ||
500Kbps | 10 | 1 | 5 | 4 |
注:位时间tBit=1s/500kbps=2000ns/bit;晶振时钟周期T=1s/8MHz=125ns。
2.CAN网络消息ID组成
CAN总线通讯采用CAN2.0B标准的扩展帧格式,29位标识符组成定义见表2。不遵循此规范的ID为非法指令,终端节点应予以丢弃或上报异常。总线上各节点单机在处理相应的消息时,采用:“消息代号(D26~D22)”+“消息源设备(D21~D16)”+“消息目的(D15~D10)”三者结合的方式来判断是否该类型的消息。
D28~D27 | D26~D22 | D21~D16 | D15~D10 | D9~D8 | D7~D0 |
消息优先级类型 | 消息代号 | 消息源 设备ID | 消息目的设备ID | 用于传输的总线编号 | 可用于传输数据或数据帧内编号 |
00-重要控制 01-一般控制 10-重要测试 11-一般测试 | 0~31 由总线协议确定 | 0~63 由实际终端节点情况确定 | 0~63 由实际终端节点情况确定 | 00-CAN1 01-CAN2 | 0~255 由待传输的数据量决定 |
3.设备节点定义
CAN1总线和CAN2总线内部设备节点的ID分配采用互斥性设计,需保持其唯一性。节点ID定义见下表。
ID | 设备含义 |
000001 (1) | 设备节点1 |
000010 (2) | 设备节点2 |
000011 (3) | 设备节点3 |
… | … |
4.数据格式说明
协议消息组织与传输以字节为单位进行,在多字节传输时,CAN总线先发送低字节后发送高字节;例如,如发送0x12AB,则先发送0xAB,再发送0x12。在每个字节8个bit中,则先发送高位,再发送低位。
字节号定义:
位序号定义:
消息内各数据类型如下表所示。
序号 | 数据类型对照 | 本文 标注 | 对应C/C++语言(32位机器) | 用途 |
1 | 布尔型 | BOOL | bool,unsigned char | 表示bool型逻辑变量 |
2 | 单字节有符号整数 | I8 | char | 表示-128~+127的整数 |
3 | 单字节无符号整数 | U8 | unsigned char | 表示0~255的整数,或者ASCII字符 |
4 | 双字节有符号整数 | I16 | short | 表示-32768~+32767的整数 |
5 | 双字节无符号整数 | U16 | unsigned short | 表示0~65535的整数 |
6 | 四字节有符号整数 | I32 | int | 表示-2147483648~2147483647的整数 |
7 | 四字节无符号整数 | U32 | unsigned int | 表示0~4294967295的整数 |
8 | 单精度浮点数 | F32 | float | IEEE-754标准 |
9 | 双精度浮点数 | F64 | double | IEEE-754标准 |
5.消息格式说明
CAN消息根据待传输的有效数据长度,由一个或多个CAN总线数据帧完成传输。组成一条消息的不同数据帧拥有相同的消息代号,数据帧编号从0开始依次增长。消息说明的格式如下表所示。
消息名称 | 消息格式说明 | 版 本 | 版本号 | |||||||
信 源 | 信息发送方 | 信 宿 | 信息接收方 | |||||||
消息优先级 | 紧急控制、一般测试等 | 消息代号 | 节点间通信的唯一消息代号 | |||||||
数据长度 | 实际使用的字节数 | 总线网络 | 传输时使用的总线网络 | |||||||
发送频率 | 发送周期或事件条件 | 转发情况 | 明确是否转发 | |||||||
消息ID | 总线数据帧的标识符(二进制和十六进制形式) | |||||||||
数据内容信息 | ||||||||||
帧序号 | 名 称 | 数据类型 | 长度 | 值域 | 含义 | |||||
0~255 | 数据内容名称 | int、float等类型 | 字节数 | 取值范围 | 数据的物理意义 | |||||
附 注 | 1.所有的总线消息均依据此格式进行规定和说明; 2.有数据内容以字节为基本单位,并遵循约定的存储方式。 |
6.FIFO队列
队列是一种先进先出(FIFO)的线性表,它只允许在表的一端插入元素,另一端删除元素。其中,允许插入的一端称为队尾(rear),允许删除的一端称为队头(front)。a[1]为队头元素,a[5]为队尾元素。最早进入队列的元素也会最早出来,只有当最先进入队列的元素都出来以后,后进入的元素才能退出。循环FIFO队列示意图如下。
7.CAN发送流程
主程序查询到发送邮箱有空闲状态的,选择1个空闲邮箱(Freelevel=1)将一帧CAN数据填充进去,将此空闲邮箱状态设置为繁忙(Freelevel=0),并设置CAN数据长度和发送数据位,然后将此邮箱请求预定(此处每个邮箱优先级相同),邮箱被预定发送后,等待总线空闲,发送成功后,邮箱置空,若发送失败,返回预定发送。整个CAN发送流程如下图所示。
注:CAN发送流程图中,实线表示单个邮箱执行流程;可强制执行和发送失败处虚线表示程序可设置,而未设置执行。
8.CAN接收流程
CAN接收到的有效报文,被存储在3级邮箱深度的FIFO中。CAN接收流程为:FIFO为空时,收到有效报文存入邮箱1(存入FIFO的一个邮箱,这个由硬件控制,我们不需要理会),收到有效报文存入邮箱2,收到有效报文存入邮箱3,在收到有效报文时溢出。这个流程里面,我们没有考虑从FIFO读出报文的情况,实际情况是,我们必须在FIFO溢出之前,读出至少1个报文,否则下个报文到来,将导致FIFO溢出,从而出现报文丢失。每读出1个报文,相应的邮箱就置空,直到FIFO空。CAN接收流程如下图所示。
9.节点CAN消息冗余过滤原则
在整个CAN总线网络中,通过CAN总线设备节点的标识符过滤功能,利用消息帧ID的D10~D15是否与本设备节点编号一致来过滤无关消息。各节点单机必须对CAN总线节点信息进行过滤处理,只响应与本节点相关信息。
10.节点CAN消息冗余过滤机制
为保证CAN总线消息可靠性,部分CAN数据帧采用了双总线通道(CAN1总线和CAN1总线)同时发送的策略,各节点单机在接收CAN消息数据时,需要过滤以上冗余信息,具体过滤机制建议如下:
- 对于来自不同总线通道(CAN1总线、CAN2总线)且ID相同(这里指除了总线编号(D9~D8)之外的ID信息)进行冗余过滤;
- 过滤时间门限建议设置为8ms,即8ms内的相同消息只取一条;
- 对于同一总线通道的CAN消息不进行过滤;
- 过滤后的有效CAN消息才进入接收队列进行后续处理。
5.工程化实现
上面给出的一种双通路CAN总线消息备份冗余处理方法,实现思路及过程已讲述清楚,这里给出其C语言工程化实现的关键代码,详细工程代码见文末链接处。
//消息滤波处理结构
typedef struct
{CAN_EXT_ID ID[MAX_ID_CHECK_LIST]; // 消息IDunsigned int RecvTime[MAX_ID_CHECK_LIST]; // 收到的时间unsigned char ListIndex;
}CAN_Msgs_Recv_Time;
static CAN_Msgs_Recv_Time RecvIDList = {0};
/*** @brief 检查是新消息 还是两条总线上重发的消息此函数在中断处使用* @param CAN_EXT_ID: CAN帧的扩展ID定义* @retval 无*/
//
uint8_t Is_New_CAN_Msg(CAN_EXT_ID ID)
{uint8_t bRet = 1; // 新消息//if((ID.s.res&STD_CAN_MSG) != STD_CAN_MSG) // 仅对扩展帧进行重复帧筛选{for(int i = 0; i < MAX_ID_CHECK_LIST; i++){// 两个消息ID相同 且接收的时间间隔小于8ms则认为是重复消息if((ID_IGNORE_CAN_BUS(RecvIDList.ID[i].id) == ID_IGNORE_CAN_BUS(ID.id)) && (g_1msTick - RecvIDList.RecvTime[i]) <= 8) {//仅屏蔽不同总线的can消息if(RecvIDList.ID[i].s.res != ID.s.res) {bRet = 0;break;}}}// 新消息 写入队列if(bRet == 1) {RecvIDList.ListIndex = ((RecvIDList.ListIndex+1) >= MAX_ID_CHECK_LIST)?0:RecvIDList.ListIndex+1;RecvIDList.ID[RecvIDList.ListIndex].id = ID.id;RecvIDList.RecvTime[RecvIDList.ListIndex] = g_1msTick;}} return bRet;
}
总结
下面提供的代码,基于STM32F407ZGT芯片编写,可直接在原子开发板上运行,也可运行在各工程项目上,但需要注意各接口以及相应的引脚应和原子开发板上保持一致。
相应的代码链接:单片机STM32F407-Case程序代码例程-CSDN文库
相关文章:

STM32之一种双通路CAN总线消息备份冗余处理方法(十三)
STM32F407 系列文章 - Dual-CANBus-ProMethod(十三) 目录 前言 一、现状分析 二、解决思路 1.应用场景网络结构图 2.数据发送流程 3.数据接收流程 4.用到的模块 1.CAN网络速率及时间片分配 2.CAN网络消息ID组成 3.设备节点定义 4.数据格式说明…...

从零开始:使用VSCode搭建Python数据科学开发环境
引言 在数据科学领域,一个高效、稳定的开发环境是成功的关键。本文将详细介绍如何使用Visual Studio Code搭建一个完整的Python数据科学开发环境。通过本指南,您将学会: 安装和配置VSCode,包括基本设置和快捷键配置设置Python开…...
C#语言的字符串处理
C#语言的字符串处理 引言 在现代编程中,字符串处理是一项重要的技能,几乎在所有编程语言中都有应用。C#语言作为一种强类型的、面向对象的编程语言,提供了丰富的字符串处理功能。这使得开发人员能够方便地进行文本操作,比如字符…...

《安富莱嵌入式周报》第348期:开源低功耗测试仪,开源创意万用表,续航100-300小时,开源PCB电机,自制shell和网络协议栈,开源水培自动化系统
周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版: https://www.bilibili.com/video/BV1Tzr9Y3EQ7/ 《安富莱嵌入式周报》第348期:开源低功…...
npm发布流程说明
一、进入要发布的项目根目录,初始化为npm包 npm initname:最重要的字段之一,项目名称(少于214个字节)。没有name和version不能进行安装; version:最重要的字段之一,项目版本。没有n…...
缓存-文章目录
关于缓存系列文章: 缓存学习总结1(缓存分类) 缓存学习总结2(服务器本地缓存) 缓存学习总结3(服务器内存缓存)推荐使用 缓存学习总结4(分布式缓存) 关于redis系列文章…...
LeetCode 3297.统计重新排列后包含另一个字符串的子字符串数目 I:滑动窗口
【LetMeFly】3297.统计重新排列后包含另一个字符串的子字符串数目 I:滑动窗口 力扣题目链接:https://leetcode.cn/problems/count-substrings-that-can-be-rearranged-to-contain-a-string-i/ 给你两个字符串 word1 和 word2 。 如果一个字符串 x 重新…...
如何在 Ubuntu 24.04 上安装 Memcached 服务器教程
简介 Memcached 是一个高性能、分布式的内存缓存系统,旨在通过减少数据库负载来加速动态 Web 应用程序。它通过将数据和对象缓存在 RAM 中来实现这一点,从而最大限度地减少了从数据库或其他慢速存储层重复获取数据的需要。 本教程的目标是手把手教你如…...
《深度学习模型在鸿蒙分布式框架下的跨设备高效之旅》
在人工智能领域,深度学习模型的训练与推理通常需要强大的计算资源和大量的数据支持。而鸿蒙系统的分布式框架为解决这一问题提供了新的思路和方法,使得深度学习模型能够在多个设备之间实现高效的训练与推理。 鸿蒙分布式框架概述 鸿蒙系统是一款面向万…...
[python3]Excel解析库-xlutils
xlutils 是一组用于处理 Excel 文件的 Python 库,它实际上是 xlrd 和 xlwt 的扩展,提供了额外的功能来操作 Excel 文件。xlutils 主要由三个部分组成:xlutils.copy、xlutils.filter 和 xlutils.view,它们分别用于复制和修改现有 E…...
Springboot Bean创建流程、三种Bean注入方式(构造器注入、字段注入、setter注入)、循坏依赖问题
文章目录 1 Bean 创建流程1.1 Bean的扫描注册1.2 创建Bean的顺序 2 三种Bean注入方式2.1 构造器注入 | Constructor Injection(推荐)2.2 字段注入 | Field Injection(常用)2.3 方法注入 | Setter Injection2.4 三种方式注入顺序 3…...

mybatisX插件的使用,以及打包成配置
装mybatisX插件; idea连接数据库; 点击mybatisx-generator,设置自己装mybatisX插件; idea连接数据库; 点击mybatisx-generator,设置自己要的包和类; 如果要把自己的配置设置成一个自定义模板&a…...

【初阶数据结构】线性表之单链表
文章目录 前言 一、单链表的概念与结构 1.概念 2.结点 3.性质 二、实现单链表 1.结构的定义 2.链表的打印和结点的申请 3.单链表的尾插和头插 4.单链表的尾删和头删 5.单链表的查找 6.指定位置之前插入数据和指定位置之后插入数据 7.删除pos结点和删除pos之后的结…...

CentOS7通过yum安装JDK
CentOS7通过yum安装JDK 1、卸载自带的JDK 查看已安装的JDK rpm -qa | grep java删除已安装的JDK yum -y remove java-1.8.0-openjdk*验证是否删除成功 查不到版本信息则已删除成功 java -version2、安装JDK sudo yum install java-1.8.0-openjdk java-1.8.0-openjdk-deve…...
c# 常见的几种取整场景
软件取整,通常指的是在计算机软件中对数值进行取整操作,即将一个浮点数或小数转换为整数,同时确定如何处理小数部分。取整操作在编程和数学计算中非常常见,不同的取整方法适用于不同的场景。 常见的取整方法 向零取整(…...

数据库回滚:大祸临头时
原文地址 什么是数据库回滚? 数据库技术中,回滚是通过撤销对数据库所做的一项或多项更改,将数据库返回到先前状态的操作。它是维护数据完整性和从错误中恢复的重要机制。 什么时候需要数据库回滚? 数据库回滚在以下几个场景中很…...

【GoLang】两个字符串如何比较大小?以及字典顺序的比较规则
在 Go 语言中,字符串的比较是基于字典顺序进行的。 字典顺序的比较规则: 比较两个字符串从左到右逐个字符的Unicode码点值, 若比较结果不相等则将此结果作为字符串大小的结果, 若比较结果相等则比较下一位, 若其中一个…...

5G学习笔记之SNPN系列之UE入网和远程配置
参考:3GPP 23.501 5.30.2.10 Onboarding of UEs for SNPNs 小小协议搬运工 目录 0. NPN系列 1. 概述 2. SNPN作为ONN 2.1 DCS参与的入网主鉴权 2.2 DCS不参与的入网主鉴权 2.3 UE入网 3. PLMN作为ONN 4. 远程配置 0. NPN系列 1. NPN概述 2. NPN R18 3. 【SNPN系列】…...

C#版OpenCv常用函数大全
OpenCvSharp 是 OpenCV 的NET封装,提供了丰富的图像处理和计算机视觉功能。以下是一些常用函数及其详细说明。 1. 图像读取与显示 Cv2.ImRead 功能:读取图像文件并返回一个 Mat 对象。用法:Mat image Cv2.ImRead("path/to/image.jpg&…...

Spring Boot教程之五十二:CrudRepository 和 JpaRepository 之间的区别
Spring Boot – CrudRepository 和 JpaRepository 之间的区别 Spring Boot建立在 Spring 之上,包含 Spring 的所有功能。由于其快速的生产就绪环境,使开发人员能够直接专注于逻辑,而不必费力配置和设置,因此如今它正成为开发人员…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...