零基础国产GD32单片机编程入门(十五)CAN通讯详解及实战含源码

news2024/11/13 14:37:21

文章目录

    • 一.概要
    • 二.CAN网络基本组成
    • 三.GD32单片机CAN结构与特点
      • 1.GD32F103单片机CAN基本结构图
      • 2.GD32F103单片机CAN基本特点
    • 四.CAN协议帧格式
    • 五.GD32F103C8T6的CAN通讯波特率
    • 六.GDF103C8T6的CAN接收过滤器配置
    • 七.配置一个CAN通讯数据收发例程
    • 八.工程源代码下载
    • 九.小结

一.概要

CAN全称是(Controller Area Network),控制器局域网络,是ISO国际标准化的串行通信协议,CAN是国际上应用最广泛的现场总线之一。

CAN通信只有两根信号线,分别是CAN_High和CAN_Low,CAN 控制器根据这两根线上的电位差来判断总线电平。总线申平分为显性电平和隐性申平,二者必居其一。发送方通过使总线电平发生变化,将消息发送给接收方。

CAN总线在车上应用非常广泛:
在这里插入图片描述

本文介绍了GD32单片机CAN口的基本概念,内部结构,波特率配置,接收滤波配置以及用CAN口进行数据通讯的例程。

二.CAN网络基本组成

一个典型的CAN网络由多个节点组成,每个节点至少包含一个CAN控制器和一个CAN收发器。此外,网络还需要适当的物理介质,如电缆和连接器来连接各个节点。
GD32F103单片机是自带CAN控制器,只要外面挂一个CAN收发器(TJA1050/TJA1042等)就能组成一个CAN节点,实现跟其他节点CAN通讯。
在这里插入图片描述

三.GD32单片机CAN结构与特点

1.GD32F103单片机CAN基本结构图

在这里插入图片描述
CAN内核
是CAN控制器的核心,包含了一系列的控制和状态寄存器,通过配置这些寄存器可以设定CAN控制器的工作模式、波特率、错误检测和恢复策略等关键参数。内核还负责处理总线上的仲裁、错误检测、帧发送和接收等工作。

发送邮箱
是用于临时存储待发送报文的缓冲区,每个邮箱可以容纳一个完整的CAN报文,并附带相关控制信息。在GD32的某些系列产品中,如F1、F4等,提供了至少3个发送邮箱,这样可以同时准备多个报文并发发送,提高通信效率。

接收FIFO
是用于暂存从CAN总线上接收到的有效报文。当CAN控制器接收到报文时,会将其放入接收FIFO中,应用程序可以从FIFO中取出并处理这些报文。FIFO设计可以避免在接收过程中丢失数据,特别是在短时间内连续接收到多个报文的情况下。

接收过滤功能
是用于筛选从CAN总线上接收到的报文,只有经过过滤器匹配的报文才会被存入接收FIFO中,这样可以减少不必要的处理器负载,并允许系统只关注感兴趣的特定报文。过滤器可以根据标识符、标识符掩码等多种规则进行配置,没有通过过滤的帧,直接丢弃。

2.GD32F103单片机CAN基本特点

CAN总线协议2.0A和2.0B;
通信波特率最大为1Mbit/s;
支持时间触发CAN通信(Time-trigger communication);
中断使能和清除。
发送功能
3个发送邮箱;
支持优先级发送;
支持发送时间戳。
接收功能
2个深度为3的接收FIFO;
在非GD32F10x CL系列产品中,具有14个过滤器;
在GD32F10x CL系列产品中,具有28个过滤器;
FIFO锁定功能。
时间触发通信
在时间触发通信模式下取消自动重传;
16位定时器;
接收时间戳;
发送时间戳。

四.CAN协议帧格式

数据帧是使用最多的帧,结构上由7段组成,其中根据仲裁段ID码长度的不同,分为标准帧(CAN2.0A)和扩展帧(CAN2.0B),标识符(ID)长度不同:标准格式为11位,扩展格式为29位。

在这里插入图片描述

数据帧格式:
在这里插入图片描述
1.起始域
SOF=帧开始

2.仲裁域
ID=标识符
RTR=远程请求位,区分数据帧和遥控帧

3.控制域
IDE=扩展标志位,区分标准格式和扩展格式
r0=保留位,为后续协议升级留下空间
DLC=数据长度

4.数据域
0~8字节的长度

5.CRC域
CRC=循环几余校验码

6.ACK域
ACK=响应位

7.结束域
EOF=帧结束

CAN通信标准帧还是扩展帧,选择使用哪种帧类型取决于具体的应用需求。如果需要传输较小数据量且标识符长度不超过11位,可以选择CAN标准帧。而对于需要传输更大数据量和更长标识符的应用,则应选用CAN扩展帧,一般CAN通信双方之间会先约定好采用标准帧还是扩展帧协议。

五.GD32F103C8T6的CAN通讯波特率

由于CAN属于异步通讯,没有时钟信号线,连接在同一个总线网络中的各个节点会像串口异步通讯那样,节点间使用约定好的波特率进行通讯。
同时,CAN还使用“位同步”的方式来抗干扰、吸收误差,实现对总线电平信号进行正确的采样,确保通讯正常。

如下所述把名义上的每位时间分为3段:
● 同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元(1 x tCAN)。
● 时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。
其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
● 时间段2(BS2):定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。

位时序
在这里插入图片描述

CAN波特率计算公式:
在这里插入图片描述

在这里插入图片描述

我们以GD32F103C8T6为例,CAN时钟是挂在APB1上,APB1时钟是54M,

BAUDPSC[9:0] : 波特率分频器 (Baud rate prescaler) ,这个寄存器我们配置成23。
BS2[2:0]: 时间段2 (Time segment 2) ,这个寄存器我们配置成2。
BS1[3:0] : 时间段1 (Time segment 1) ,这个寄存器我们配置成4。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

根据波特率公式:

tBS1 = tq * (BS1[3:0] + 1)。
tBS2 = tq * (BS2[2:0] + 1)。
tq = (BAUDPSC[9:0] + 1) x tPCLK。
tPCLK=1/54000000。
波特率=1/(tq + tBS1+tBS2)
=1/tq*(1+(BS1[3:0] +1)+(BS2[2:0] )+1)
=54000000/((BAUDPSC[9:0] + 1)*(1+(BS1[3:0] + 1)+(BS2[2:0] + 1)))

波特率计算结果就是
54000000/((23+1)*(1+(2+1)+(4+1)))=250000bps。

一般CAN波特率都是250k,500k,1M,125k,我们只要参照250K波特率的配置,改下波特率分频器就很方便能改大改小,都是倍数关系。

六.GDF103C8T6的CAN接收过滤器配置

CAN的过滤器的配置是对CAN接收到的报文进行过滤的配置,在GD32芯片中,可以对CAN的报文进行过滤,从而省略MCU的处理过程。在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的优先级相关的。发送者以广播的形式把报文发送给所有的接收者。节点在接收报文时,根据标识符的值决定是否需要该报文,如果需要,就拷贝到SRAM里,如果不需要,报文就被丢弃且无需软件的干预。

为满足这一需求,CAN为应用程序提供了14个位宽可变的、可配置的过滤器组(13~0),每个过滤器组由2个32位寄存器,CAN_FxDATA0和CAN_ FxDATA1组成。以便只接收那些软件需要的报文。硬件过滤的做法节省了MCU开销,否则就必须由软件过滤从而占用一定的MCU开销。

每个过滤器组的位宽都可以单独设置,以满足应用程序的不同需求。根据位宽的不同,可以配置为1个32位过滤器和2个16位过滤器。
● 1个32位过滤器,包括:SFID[10:0]、EFID[17:0]、FF(帧格式 0:标准格式帧 1:扩展格式帧 ) 和FT(帧种类 0:数据帧 1:遥控帧 )位
在这里插入图片描述
● 2个16位过滤器,包括:SFID[10:0]、FF(帧格式 0:标准格式帧 1:扩展格式帧 ) 和FT(帧种类 0:数据帧 1:遥控帧 )和EFID[17:15]位
在这里插入图片描述

CAN过滤器还可以分为掩码模式和列表模式。

掩码模式:
对于一个接收数据帧的标识符(Identifier),掩码模式用来指定哪些位必须与预设的标识符相同,哪些位无需判断。

列表模式 :
对于一个接收数据帧的标识符(Identifier),列表模式用来表示与预设的标识符列表中能够匹配则通过,否则丢弃。

例如:

列表匹配ID为0x200,掩码为0x000,则所有ID号都能通过
列表匹配ID为0x200,掩码为0x700,则ID为0x200~0x2FF均可通过
列表匹配ID为0x200,掩码为0x7FF,则只有0x200能通过

一般初学,掩码配置为0就可以了,就可以接收CAN总线上的所有帧。

七.配置一个CAN通讯数据收发例程

板子先与CAN转TTL板子连接
PA12 <------>TX-Can转TTL TX
PA11 <------>RX-Can转TTL RX
GND <------> -Can转TTL GND
5V <------> -Can转TTL VCC

Can转TTL与USB转CAN用杜邦线对接,CAN_H对接,CAN_L对接,USB转CAN插电脑

在这里插入图片描述

主要代码

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

FlagStatus receive_flag;//判断数据是否有接收到
uint8_t transmit_number = 0x0;
can_receive_message_struct receive_message;//接收数据结构体
can_trasnmit_message_struct transmit_message;//发送数据结构体
#define CAN0_USED
#define CANX CAN0//CAN0

//CAN设置,250kbps
void can_networking_init(void)
{
    can_parameter_struct            can_parameter;
    can_filter_parameter_struct     can_filter;
    
    can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
    can_struct_para_init(CAN_FILTER_STRUCT, &can_filter);
    /* initialize CAN register */
    can_deinit(CANX);
    /* initialize CAN */
    can_parameter.time_triggered = DISABLE;
    can_parameter.auto_bus_off_recovery = DISABLE;
    can_parameter.auto_wake_up = DISABLE;
    can_parameter.no_auto_retrans = DISABLE;
    can_parameter.rec_fifo_overwrite = DISABLE;
    can_parameter.trans_fifo_order = DISABLE;
    can_parameter.working_mode = CAN_NORMAL_MODE;
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1 = CAN_BT_BS1_5TQ;
    can_parameter.time_segment_2 = CAN_BT_BS2_3TQ;
    /* baudrate 250kbps */
    can_parameter.prescaler = 24;
    can_init(CANX, &can_parameter);

    /* initialize filter */
#ifdef  CAN0_USED
    /* CAN0 filter number */
    can_filter.filter_number = 0;
#else
    /* CAN1 filter number */
    can_filter.filter_number = 15;
#endif
    /* initialize filter */    
    can_filter.filter_mode = CAN_FILTERMODE_MASK;
    can_filter.filter_bits = CAN_FILTERBITS_32BIT;
    can_filter.filter_list_high = 0x0000;
    can_filter.filter_list_low = 0x0000;
    can_filter.filter_mask_high = 0x0000;
    can_filter.filter_mask_low = 0x0000;  
    can_filter.filter_fifo_number = CAN_FIFO1;
    can_filter.filter_enable = ENABLE;
    can_filter_init(&can_filter);
}
//CAN接收中断使能
void nvic_config(void)
{
    nvic_irq_enable(CAN0_RX1_IRQn,0,0);

}
//PA11,PA12配置成CAN口
void gpio_config(void)
{
    /* enable CAN clock */
    rcu_periph_clock_enable(RCU_CAN0);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_AF);
    /* configure CAN0 GPIO */
    gpio_init(GPIOB,GPIO_MODE_IPU,GPIO_OSPEED_50MHZ,GPIO_PIN_8);
    gpio_init(GPIOB,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_9);  
	gpio_pin_remap_config(GPIO_CAN_PARTIAL_REMAP, ENABLE);//can口
	

}
int main(void)
{
		rcu_ahb_clock_config(RCU_AHB_CKSYS_DIV1);//AHB主频是1分频
		systick_config();//系统主频108MHZ,采用外部晶振,由两个宏决定(__SYSTEM_CLOCK_108M_PLL_HXTAL与HXTAL_VALUE)
		rcu_periph_clock_enable(RCU_AF);//管脚复用时钟alternate function clock使能
		gpio_config();//CAN GPIO配置
		nvic_config();//中断配置
		can_networking_init();//配置250kbps
		/* enable CAN receive FIFO1 not empty interrupt */
		can_interrupt_enable(CANX, CAN_INT_RFNE1);
		/* initialize transmit message */
		can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &transmit_message);
		transmit_message.tx_sfid = 0x321;
		transmit_message.tx_efid = 0x01;
		transmit_message.tx_ft = CAN_FT_DATA;
		transmit_message.tx_ff = CAN_FF_STANDARD;//标准帧
		transmit_message.tx_dlen = 8;
		/* initialize receive message */
		can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &receive_message);
		can_message_transmit(CANX, &transmit_message);//发送数据
	
    while(1)
    {
			if(receive_flag==SET)//判断是否有数据收到,CAN0_RX1_IRQHandler函数中置位
			{
				receive_flag=RESET;
				transmit_message.tx_sfid=receive_message.rx_sfid;
				memcpy(transmit_message.tx_data,receive_message.rx_data,8);//把接收数据拷贝到发送结构体
				can_message_transmit(CANX, &transmit_message);//发送数据
				delay_1ms(1000); 
			}			

    }

}

//中断服务程序
void CAN0_RX1_IRQHandler(void)
{
    /* check the receive message */
    can_message_receive(CAN0, CAN_FIFO1, &receive_message);
    if((0x321 == receive_message.rx_sfid)&&(CAN_FF_STANDARD == receive_message.rx_ff)){//接收ID为0x321的标准帧
        receive_flag = SET;
    }
}

实验效果
打开电脑上位机,通过电脑CAN上位机发送标准帧给板子,ID是0x321,内容是0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,板子就会改变发送的标准帧内容,发回给电脑上位机。红色的是电脑发送的数据,绿色的是板子发送的数据。
在这里插入图片描述

八.工程源代码下载

通过网盘分享的文件:17.CAN通信.zip
链接: https://pan.baidu.com/s/1utJ9uCSTfq3LcdMOi6ug-A 提取码: eut2
如果链接失效,可以联系博主给最新链接
程序下载下来之后解压就行
CSDN代码

九.小结

CAN协议因其高性能、可靠性和灵活性而逐渐被广泛应用于工业控制、航空航天、船舶、医疗设备、智能家居等领域。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2115773.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器之心 | 挑战Transformer的Mamba是什么来头?作者博士论文理清SSM进化路径

本文来源公众号“机器之心”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;挑战Transformer的Mamba是什么来头&#xff1f;作者博士论文理清SSM进化路径 对 SSM 感兴趣的研究者不妨读一下这篇博士论文。 在大模型领域&#xff0c;…

仕考网:2025年公务员国考备考技巧

公务员考试掌握好备考技巧非常重要&#xff0c;尤其是国考这种竞争比较激烈的考试&#xff0c;仕考网为大家分享一些备考技巧&#xff0c;希望能对大家有所帮助。 1. 在提升行测分数时&#xff0c;可以采用大量的练习题、整理题以及关注往年核心考点的方式。无论处于准备过程的…

JsonPath全英文文档学习

JsonPath全英文文档学习 1、文档地址2、引入依赖3、浏览翻译问题修复4、文档学习4.1、Operator4.2、Functions4.3、Filter 运算符4.4、json示例 5、实战5.1、获取json数组下的多个元素5.2、获取json数组下的多个元素&#xff08;循环遍历时无元素自动占位&#xff09;5.3、获取…

面了阿里大模型算法岗,出门秒挂。。。

最近这一两周看到不少互联网公司都已经开始秋招提前批面试了。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些…

基于springboot+enum配置化实践

前言 Springboot/Springcloud作为微服务开发的经典框架&#xff0c;我想任何一个developer不会排斥。同时&#xff0c;市场越来越多的业务开发均围绕Springboot/Springcloud而展开&#xff0c;也让它成为Java开发的“硬通货”。 基于Spring&#xff0c;诸多低代码的平台的活跃…

基于SpringBoot的校园跑腿系统+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

spring项目整合log4j2日志框架(含log4j无法打印出日志的情况,含解决办法)

Spring整合Log4j2的整体流程 1&#xff09;导入log4j-core依赖 <!--导入日志框架--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.20.0</version></dependenc…

Linux中的gdb调试器

目录 一、程序的两种模式 二、gdb的常用调试命令 一、程序的两种模式 程序通常有两种模式&#xff0c;分别是debug模式和release模式 debug模式可以调试&#xff0c;但是release模式不支持调试&#xff0c;因为debug模式添加了调试信息&#xff0c;因此debug的程序大小比rel…

[苍穹外卖]-05Redis快速入门

Redis入门 Redis是一个基于内存的key-value结构数据库 基于内存存储, 读写性能高适合存储热点数据(热点商品,咨询,新闻)企业应用广泛中文官网: Redis中文网英文网: https://rsdis.io 下载安装: Redis安装包分为Windows版本和Linux版本, Redis的windows版属于绿色软件, 解压后…

sqlmap简介及安装

sqlmap简介及安装 sqlmap 介绍 sqlmap 是一个开源的渗透测试工具&#xff0c;可以用来进行自动化检测&#xff0c;利用SQL注入漏洞&#xff0c;获取数据库服务器的权限。它具有功能强大的检测引擎&#xff0c;针对各种不同类型数据库的渗透测试的功能选项&#xff0c;包括获取…

【Hot100】LeetCode—198. 打家劫舍

目录 1- 思路动规五部曲 2- 实现⭐198. 打家劫舍——题解思路 3- ACM 实现 原题链接&#xff1a;198. 打家劫舍 1- 思路 动规五部曲 1- 定义 dp 数组 int[] dp new int[nums.length]dp[i] 代表考虑下标i 偷的最大金币数 2- 递推公式 当偷 i &#xff1a; dp[i-2] nums[i] 当…

Typora调整图片大小:两种方式zoom或width/height

目录 01 zoom方式02 width/height方式2.1 width方式 2.2 height方式 01 zoom方式 语法: <img src"your-image-url" style"zoom:your-zoom-integer"/> 示例&#xff1a;将图片(./image/market.jpg)调整为原图减少50%大小的命令为&#xff1a; …

[数据集][目标检测]肺炎检测数据集VOC+YOLO格式4983张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4983 标注数量(xml文件个数)&#xff1a;4983 标注数量(txt文件个数)&#xff1a;4983 标注…

github actions CICD简单使用案例

参考&#xff1a; https://developer.aliyun.com/article/1540773 https://github.com/ViggoZ/producthunt-daily-hot/blob/main/.github/workflows/generate_markdown.yml 1、创建github项目 目录&#xff1a; .github/workflows/fetch-news.yml actions执行yaml&#xff08;…

Linux 下 C/C++ 程序编译的过程

目录 一、GCC 工具链二、编译过程1、预处理2、编译3、汇编4、链接 本文将介绍如何将 C/C 语言编写的程序转换成为处理器能够执行的二进制代码的过程&#xff0c;包括四个步骤&#xff1a;预处理&#xff08;Preprocessing&#xff09;编译&#xff08;Compilation&#xff09;汇…

如何通过食堂采购小程序端降低成本,提升效率?

随着数字化管理工具的普及&#xff0c;越来越多的食堂正在引入小程序来优化采购流程&#xff0c;减少成本和提升效率。食堂采购小程序端通过技术手段实现了自动化、智能化的管理方式&#xff0c;为管理者提供了极大的便利。本文将探讨如何利用技术手段开发一个高效的食堂采购小…

【MATLAB】数据和字符串类型转换

数据和字符串类型转换 在 MATLAB 中&#xff0c;支持不同数据类型与字符串类型之间的转换&#xff0c;这需要使用不同的函数来实现。此外&#xff0c;相同的数据&#xff0c;特别是整数&#xff0c;可以用多种格式表示&#xff0c;例如十进制、二进制或十六进制。在 C 语言中&a…

vulhub远程执行命令漏洞CVE-2017-12636

1.打开环境 2.访问目标网站 CVE-2017-12636是一个任意命令执行漏洞&#xff0c;我们可以通过config api修改couchdb的配置query_server&#xff0c;这个配置项在设计、执行view的时候将被运行。 3.在网站中发现一个user表&#xff0c;我们可以带你进去看一下 里面是一个用户名…

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎&#xff0c;细嗅蔷薇。你好朋友&#xff0c;这里是锅巴的C\C学习笔记&#xff0c;常言道&#xff0c;不积跬步无以至千里&#xff0c;希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目&#xff1a; 牛牛发明了一种新的四舍五…

C语言手撕归并——递归与非递归实现(附动画及源码)

&#x1f916;&#x1f4bb;&#x1f468;‍&#x1f4bb;&#x1f469;‍&#x1f4bb;&#x1f31f;&#x1f680; &#x1f916;&#x1f31f; 欢迎降临张有志的未来科技实验室&#x1f916;&#x1f31f; 专栏&#xff1a;数据结构 &#x1f468;‍&#x1f4bb;&#x1f…