CAN协议介绍

目录

 CAN简介

分类:(按传输速率和距离)

特点:(高可靠性)

应用领域: 

CAN的 物理层 介绍 

总线拓扑图 

 电平标准

 CAN控制器与收发器

CAN 协议层 介绍

CAN帧 种类介绍

*CAN数据帧介绍

CAN 位时序 

 CAN仲裁机制

STM32 CAN控制器 介绍

 CAN控制器介绍

CAN控制器的模式

 CAN控制器的框图

CAN控制器 位时序

 CAN控制器 寄存器 的介绍

CAN控制和状态寄存器

 CAN邮箱寄存器

CAN过滤器寄存器 

CAN 库函数 和 驱动流程

 小实验:CAN收发实验

硬件接线 

 文件代码


 CAN简介

        CAN协议,全称为Controller Area Network(控制器局域网络),是一种广泛应用的串行通信协议,CAN协议是一种基于差分信号(两根线:抗干扰的能力好)异步串行通信协议,采用双绞线作为传输介质,具有高性能、高可靠性和独特的设计特点。

IIC、SPI、串口都不是利用的差分信号的通信协议。传输距离都小于40米。

分类:(按传输速率和距离)

  • 低速CANISO11519通信速率 10~125Kbps,总线长度可达 1000 米。
  • 高速CANISO11898通信速率 125Kbps~1Mbps,总线长度 40 米。

特点:(高可靠性)

  • 多主控制:支持多主方式,即任何一个节点都可以在总线上发送数据其他节点根据需要进行接收。当两个以上的节点同时开始发送数据时,会根据标识符(ID)决定优先级(仲裁)
其他通信协议的模式
串口1对1
IIC

主要:

1主1从,1主多从;

多主多从(这里不好用)

SPI1主1从;1主多从
  • 系统柔软性:与总线相连的单元没有类似于地址的信息,因此在总线上增加单元时,连接在总线上的其他单元的软硬件及应用层都不需要改变。
  • 通信速度快、距离远:数据传输速率较高,标准速率为125kbps,扩展速率可达1Mbps,且通信距离远,最远可达10KM(速率低于5Kbps)。
  • 错误检测与恢复:具有错误检测、错误通知和错误恢复功能,能够确保数据传输的可靠性。

当节点接收到数据的时候,其他节点会进行检测,如果发现错误的数据,会进行销毁。

  • 故障封闭功能:能够判断出错误的类型,并将引起故障的单元从总线上隔离出去。 

应用领域: 

CAN协议因其高效、可靠的特点,被广泛应用于多个领域:

汽车领域:用于实现车辆中各个控制单元(ECU)之间的通信,如发动机控制、车身控制、传动系统控制等。

工业自动化:用于机器人、物流设备、生产线等各种设备之间的通信与控制。

航空航天:用于飞机中的各种子系统之间的数据通信,如飞行控制系统、引擎控制系统、仪表盘、通信系统等。

船舶领域:用于实现船舶各种设备的可靠通信,包括远程控制、安全监测、航程分析、巡回检测等系统。

智能家居:连接各种智能设备,如照明设备、空调系统、安防系统等,实现设备的互联互通。

智能医疗:连接医疗设备,如监护仪、呼吸机等,实现设备间的快速通信。

CAN的 物理层 介绍 

 CAN网络通常由CAN控制器、CAN收发器、双绞线 和 终端电阻 组成。

  • CAN控制器:负责处理数据的收发和协议转换。
  • CAN收发器:负责将控制器的数字信号转换为差分信号进行传输,同时也负责将总线上的差分信号转换为数字信号供控制器处理。
  • 终端电阻 :在高速CAN总线的两端分别连接一个电阻,称为终端电阻。终端电阻的主要作用:匹配总线阻抗提高信号质量减少回波反射。一般来说,终端电阻的阻值为120Ω

总线拓扑图 

闭环CAN总线—高速CAN协议:

高速CAN拓扑图说明: 

  • 所有的CAN节点都连接在CAN总线上,每个节点都有CAN控制器,通过CANRX,CANTX与CAN收发器进行连接,CAN收发器通过CANH和CANL连接到总线上。CAN总线有两根线,所有的CAN接到这2根线上。
硬件接线:

开发板(CAN控制器)

CAN收发器
PA(CAN_TX)CAN_TX
PA(CAN_RX)CAN_RX
5.5VVCC
GNDGND
CAN收发器CAN总线
CANHCANH
CANLCANL

开环CAN总线-低速CAN总线 :

 电平标准

CAN使用差分信号进行数据传输,根据 CAN_H 和 CAN_L 上的 电位差 来判断 总线电平

高速CAN: 

  • 显性电平表示逻辑 0 ,通常 CAN_H CAN_L 2V 的压差;
  • 隐性电平表示逻辑 1 ,通常 CAN_H CAN_L 0V 的压差。

低速CAN:

  • 显性电平表示逻辑 0 ,通常 CAN_H CAN_L 3V 的压差;
  • 隐性电平表示逻辑 1 ,通常 CAN_H CAN_L -1.5 的压差。
  • 显性电平在通信中具有优先权,能够覆盖隐性电平,确保数据的正确传输。
  • 隐性电平则作为总线的空闲或监听状态存在,等待有节点发送数据。

电平图: 

 CAN控制器与收发器

CAN的控制器在后续会详细的讲:这节主要讲CAN的收发器

高速CAN的收发器:(本章主要讲这个)

TJA1050收发器-正面
TJA1050收发器-背面

原理图:

 到这里可以完成:通过CAN总线发送010101的信号,组成各种数据帧,进行数据的传输,发送给其他的设备。

CAN 协议层 介绍

定义:CAN帧:前面介绍 通过CAN总线的差分信号 发送0和1,有一坨的010101组成的数据包,这就是数据帧。 

CAN帧 种类介绍

  • 数据帧(Data Frame):数据帧是CAN总线上用于传输用户数据的帧,包括必要的帧头、标识符、控制位、数据长度代码、数据域、CRC校验码 和 应答域等部分,是CAN通信中最基本和最重要的帧类型。
  • 遥控帧(Remote Frame):遥控帧用于向总线上的其他节点请求发送具有相同标识符的数据帧,它没有数据域,仅通过标识符来指定所需的数据。遥控帧的帧结构与数据帧相似,但缺少数据部分。
  • 错误帧(Error Frame:当CAN总线上的任何节点检测到通信错误时,会发送错误帧来通知其他节点。错误帧包含错误标志和错误界定符,用于指示错误的存在和类型。
  • 过载帧(Overload Frame:过载帧用于在连续的数据帧或远程帧之间提供额外的延时,以指示接收节点尚未准备好接收下一个帧。当接收节点因内部条件限制而无法立即接收数据时,会发送过载帧来请求发送节点暂停发送。
  •  帧间隔(Interframe Space:帧间用于隔离 数据帧 与前面的帧,确保它们之间的时间间隔足够长,以避免总线上的冲突和数据丢失。帧间隔包括连续三个隐性位(间隔段)和可能存在的空闲段,用于将数据帧或远程帧与前面的帧分隔开来。

*CAN数据帧介绍

数据帧由7段组成。数据帧又分为标准帧(CAN2.0A)扩展帧(CAN2.0B),主要体现在仲裁段和控制段

帧头(起始帧)
功能 :表示数据帧的开始。
特点 :由一个显性位(0) Dominant Bit )构成,此时 CAN_H 为高电平(如 3.5V ), CAN_L 为低电平(如1.5V ),二者之间的电位差形成信号
仲裁段(Arbitration Field
功能 确定发送优先级,并包含 标识符( Identifier 用于 唯一标识 发送者和接收者之间的通信关系。
组成:
  • 标准数据帧的仲裁场由 11位 ID 和 1RTR位(远程发送请求位)组成。RTR位用于区分数据帧 (显性电平)遥控帧(隐性电平)
  • 扩展数据帧中,还包含SRRSubstituted Remote Request,替代的远程请求)和 IDE位 (Identifier Extension,标识符扩展)。SRR位用于指示发送方是否发送了远程请求帧,IDE位用于指示标识符字段是否使用了扩展格式(29位)。
控制段(Control Field

组成:包含IDE位、r0 和 数据长度代码(DLC),用于定义数据帧中数据域的长度。

功能

  • DLC占 4位,其取值范围为 08个 字节,表示数据帧中包含的数据字节数
  • IDE位:用于指示标识符字段是否使用了扩展格式(29位)。
数据段(Data Field
功能 :包含要传输的数据,是数据帧的主体部分。
特点 :数据域的长度可以根据 DLC 字段的值从  到 8 个字节不等,数据从最高位( MSB )开始传输。
CRC段(CRC Field
功能 :用于检测数据帧的传输错误
特点
  • CRC(循环冗余校验)是一种通过对数据进行计算生成的校验码发送方在发送数据帧时会根据数据计算出CRC值,并将其添加到数据帧的CRC段中。接收方在接收到数据帧后会重新计算CRC值,并与接收到的CRC值进行比较,以确认数据在传输过程中是否发生错误。
  • CCR界定符:
应答段(ACK Field
功能 用来 确认数据帧的正常接收。
组成 ACK槽(ACK Slot) 和  ACK界定符  两个位构成。当接收节点成功解析了数据帧并确认无误后,会在ACK 槽中发送一个显性位作为应答信号
帧结束(Frame End
功能 :表示数据帧的结束
特点 :由 7 个连续的隐性位(1)构成,标志着数据帧的传输完成。

CAN 位时序 

        由于CAN总线不能像人眼一样可以直观的判断电位。只能通过固定的采样时间来获取此刻的电平。为实现这一操作:CAN总线以位同步机制,实现对电平的正确采样。

所谓采样点读取总线电平,并将读到的电平作为位值的点。位置在 PBS1 结束处。 

         通常将每一位的数据分成四段同步段(SS)、传播时间段(PTS)、 相位缓冲段1(PBS1)相位缓冲段2(PBS2),每段又由多个位时序Tq(时间单位,1Tq = 5us,这个值可以自己设置)组成。

CAN总线通过 时钟同步机制 来确保 各个节点在通信过程中保持同步。时钟同步机制包括硬同步再同步两种:

  • 硬同步: 硬同步 只在帧的起始位(SOF)处进行 当接收节点检测到帧起始位的下降沿时,会将其与自身的位时间进行对齐,从而实现同步。

  • 再同步
  • 再同步在帧的后续数据位中进行。
  • 如果接收节点检测到数据位的跳变沿不在自身的同步段内,则会通过延长或缩短相位缓冲段的时间来调整自身的位时间,以重新获得同步
  • 再同步时,PBS1PBS2中增加或者减少的时间被称为“ 再同步补偿宽度(SJW),其范围:1~4Tq

情况1:

情况2: 

 CAN仲裁机制

  • CAN总线处于空闲状态,最先开始发送消息的单元获得发送权
  • 多个单元同时开始发送时,从仲裁段(报文ID)的第一位开始进行仲裁。仲裁原理如下

标识符优先级:

  • CAN总线中传输的数据帧的起始部分为数据的 标识符(ID)。这个标识符不仅用于区分消息,还表示消息的优先级CAN 2.0标准中,标识符可以是11位或29位(对于扩展帧)标识符的数值越小,优先级越高。
  • 例如,在11位标识符的情况下,ID0x000的消息具有最高优先级,而ID0x7FF的消息具有最低优先级。

逐位仲裁:

  • 当两个或两个以上的节点同时开始传送报文时,就会产生总线访问冲突。此时,各节点会按照标识符的位顺序逐位进行仲裁。
  • 仲裁过程:每个节点都会将自己发送的电平与总线上的电平进行比较。如果电平相同,则节点继续发送下一位;如果电平不同,则优先级低的节点停止发送,而优先级高的节点继续发送。
  • 这种 仲裁方式是非破坏性的,即优先级低的节点在仲裁过程中不会破坏总线上已经存在的数据。

显性电平优先:

CAN总线上,显性电平(逻辑0)的优先级 高于隐性电平(逻辑1。因此,在仲裁过程中,如果某个节点发送的是隐性电平,但检测到总线上存在显性电平,那么该节点就会知道有更高优先级的消息正在发送,并主动停止发送。

一旦仲裁结束,优先级最高的节点获得总线控制权开始传输数据其他节点则成为接收节点监听总线上的数据,并会自动检测总线空闲,在第一时间再次尝试发送。

STM32 CAN控制器 介绍

 CAN控制器介绍

        STM32的bxCAN(参考手册中22章详细介绍),即基本扩展CANBasic Extend CAN,是STM32微控制器系列中集成的CAN控制器模块。

CAN控制器的介绍
协议支持
支持 CAN 协议 2.0A(只能识别标准的数据帧) 和  2.0B(既能识别标准数据帧又能识别扩展的数据帧) 的主动模式
  高波特率
波特率(两个节点的波特率相同才能进行通信)最高可达 1 兆位 / 秒。
时间触发通信

支持时间触发通信功能,CAN的硬件内部定时器可以在TX/RX的帧起始位的采样点位置生成时间戳。

发送功能
  • 具有3个发送邮箱,发送报文优先级特性可软件配置
  • 记录发送SOFStart Of Frame,帧起始)时刻的时间。
接收功能
  • 具有3级深度的2FIFOFirst In First Out,先进先出队列),每个FIFO都可以存放3个完整的报文,完全由硬件管理
  • 共有14个位宽可变的过滤器组(部分STM32型号可能支持更多),由整个CAN共享,用于筛选有效报文。
  • 记录接收SOF时刻的时间。
  • 支持禁止自动重传模式。

CAN控制器的模式

工作模式:

CAN控制器的工作模式有三种:初始化模式、正常模式和睡眠模式。

控制器的工作模式
睡眠模式
在睡眠模式下, CAN 控制器的时钟停止,以降低功耗。但 软件仍然可以访问邮箱寄存器
初始化模式
在初始化模式下,禁止 报文的接收和发送,并且 CANTX 引脚 输出隐性位(高电平)。此时,可以对CAN 控制器的相关 寄存器 进行配置,如位时间特性( CAN_BTR )和控制( CAN_MCR )等。
正常模式
作为总线的正常节点,可以向总线发送或接收数据。

测试模式:

CAN控制器的测试模式有三种:静默模式、环回模式和环回静默模式,主要用于特定的测试或调试目的,以确保CAN控制器的功能正常。

测试模式
静默模式
特点
  • 在静默模式下,CAN控制器可以正常地接收数据帧和远程帧,但只能发出隐性位,而不能真正发送报文。
  • 这意味着,虽然CAN控制器在尝试发送数据,但实际上它并没有CAN总线上产生任何显性位,因此不会对总线上的其他节点产生影响。

应用场景

  • 静默模式通常用于分析CAN总线的活动,而不会对总线上的其他通信造成干扰。
  • 开发人员可以使用此模式来观察总线上的数据流,而无需担心他们的测试设备会发送出不必要的报文。
环回模式
特点
  • 在环回模式下,CAN控制器把发送的报文当作接收的报文并保存(如果可以通过接收过滤)。
  • 这意味着,当CAN控制器发送一个报文时,它会立即在自己的接收缓冲区中看到这个报文,就像它是从总线上接收到的一样。
应用场景
  • 环回模式通常用于自测试,以验证CAN控制器的发送和接收功能是否正常
  • 通过发送一个报文并检查它是否被正确接收,开发人员可以确保CAN控制器的硬件和固件都按预期工
环回静默模式
特点
  • 环回静默模式结合了静默模式和环回模式的特点。
  • 在该模式下,CANRX引脚 与 CAN总线断开,同时CANTX引脚被驱动到隐性位状态
  • 这意味着,虽然CAN控制器在尝试发送报文,但它实际上并没有在CAN总线上产生任何显性位,并且它会将发送的报文视为接收到的报文。
应用场景
  • 环回静默模式通常用于热自测试,即可以在不影响 CANTX 和 CANRX 所连接的整个CAN系统的情况下进行测试。
  • 这种模式允许开发人员在不干扰总线上的其他通信的情况下,验证CAN控制器的发送和接收功能

 CAN控制器的框图

CAN 控制内核
包含各种控制 / 状态 / 配置寄存器,用于配置 CAN 控制器的模式、波特率等参数。
发送邮箱( Transmit Mailbox
用来缓存待发送的 CAN 报文 STM32 等微控制器通常具有多个发送邮箱
(如 3 ),以支持同时缓存多个报文。
接收 FIFO First In First Out
缓存接收到的 有效CAN 报文 CAN 控制器通常具有多个接收 FIFO (如 2
),以提高接收效率。
接收过滤器( Receive Filter
筛选接收到的 CAN 报文,只将符合特定条件的报文保存到接收 FIFO 。这
有助于减少 CPU 的处理负担,提高系统的响应速度。

  • 发送处理过程 

说明:邮箱不用时处于空置的状态,当缓存待发送的报文时,邮箱处于挂号状态,两个邮箱会进行优先级的排序,若此时邮箱处于最高优先级,进入预定状态。等待CAN总线处于空闲状态,进行发送报文。发送成功或失败,邮箱都会再次处于空置状态。 

  •  接收处理过程

说明:1个FIFO可以接收3个邮箱,收到1个有效报文时,进入挂号1的状态,在接收到1个时进入挂号2,再次接收到1个时进入挂号3状态,如果这是再有有效报文时,会溢出。当释放邮箱会先进来的最后释放,依次释放邮箱。 

有效报文 指的是(数据帧直到 EOF 段的最后一位都没有错误),且通过过滤器组对标识符过滤。
  •  接收过滤器

        当总线上报文数据量很大时,总线上的设备会频繁获取报文,占用CPU。过滤器的存在,选择性接收有效报文,减轻系统负担。

        STM32的CAN控制器支持配置过滤器组,每个过滤器组包含2个 32位 的寄存器CAN_FxR1CAN_FxR2,用于存储要筛选的ID或掩码。对于STM32F103C8T6,如果只有一个CAN控制器,则可以配置14过滤器组,对应的编号为013

分类:

模式\位宽16位(标准帧)32位(扩展帧)
屏蔽位模式

标识符列表模式

屏蔽位模式:可以选择出一组符合条件的报文,寄存器内容功能相当于是否符合条件。

标识符列表模式:可以选择出几个特定ID的报文。寄存器内容功能就是标识符本身。

CAN控制器 位时序

举例: 

  • TS1=8TS2=7BRP=3波特率 = 36000 / [( 9 + 8 + 1 ) * 4] = 500Kbps
  • 注意:通信双方波特率需要一致才能通信成功。
  • 波特率的定义: 是通信系统中用于衡量信号传输速率的参数。单位时间内传输的符号(Symbol)数量,单位为波特(Baud,Bd)。例如,波特率为9600 Bd表示每秒传输9600个符号。

符号与比特的区别:

  • 符号(Symbol):通信中可能代表一个或多个比特,具体取决于调制方式(如2-FSK、QPSK、16-QAM等)。

  • 比特率(Bit Rate):每秒传输的比特数(bps),与波特率的关系为

  • 比特率=波特率×每符号携带的比特数比特率=波特率×每符号携带的比特数

 CAN控制器 寄存器 的介绍

CAN控制和状态寄存器

  • CAN主控制寄存器 (CAN_MCR) 

  • CAN发送状态寄存器 (CAN_TSR) 

  • CAN位时序寄存器 (CAN_BTR) 

 CAN邮箱寄存器

  •  发送邮箱标识符寄存器 (CAN_TIxR) (x=0..2)

  • 发送邮箱数据长度和时间戳寄存器 (CAN_TDTxR) (x=0..2) 

  • 发送邮箱低字节数据寄存器 (CAN_TDLxR) (x=0..2) 

 三个邮箱:报文包含08个字节数据,且从字节0开始。

  • 发送邮箱高字节数据寄存器 (CAN_TDHxR) (x=0..2)

  • 接收FIFO邮箱标识符寄存器 (CAN_RIxR) (x=0..1) 

  • 接收FIFO邮箱数据长度和时间戳寄存器 (CAN_RDTxR) (x=0..1) 

  • 接收FIFO邮箱低字节数据寄存器 (CAN_RDLxR) (x=0..1) 

  • 接收FIFO邮箱高字节数据寄存器 (CAN_RDHxR) (x=0..1) 

CAN过滤器寄存器 

  •  CAN 过滤器 主控寄存器 (CAN_FMR)

  •  CAN 过滤器模式寄存器 (CAN_FM1R)

  • CAN 过滤器位宽寄存器 (CAN_FS1R) 

  • CAN 过滤器FIFO关联寄存器 (CAN_FFA1R) 

  • CAN 过滤器激活寄存器 (CAN_FA1R) 

  • CAN 过滤器组i的寄存器x (CAN_FiRx) (互联产品中i=0..27,其它产品中i0..13;x=1..2)
  • 互联型产品中共有28组过滤器i=0..27;在其它产品中共有14组过滤器i=0..13。每组过滤器由2个32位的寄存器,CAN_FiR[2:1]组成。
  • 只有在CAN_FAxR寄存器相应的FACTx位清’0’,或CAN_FMR寄存器的FINIT位为’1’时,才能修改相应的过滤器寄存器。

CAN 库函数 和 驱动流程

  • 常用库函数

  •  驱动流程

 小实验:CAN收发实验

 实验目的:

  • 使用 回环模式 实现自发自收;
  • 两个CAN设备实现收发。

硬件清单:TJA1050、开发板、ST-Link、USB转TTL

硬件接线 

在stm32F103C8T6开发板上:CAN_TX和CAN_RX的GPIO口 

 文件代码

  • can.c文件代码
#include "can.h"
#include "stdio.h"

CAN_HandleTypeDef can_handle = {0};
void can_init(void){
    
    can_handle.Instance =CAN1; 
//CAN的工作模式和位时序(波特率)的配置
    can_handle.Init.Mode = CAN_MODE_LOOPBACK;      //工作模式(静默、回环、静默回环):回环模式
    
    can_handle.Init.Prescaler = 4;                 //配置波特率500bps 的  BRP[9:0] + 1
    can_handle.Init.TimeSeg1 = CAN_BS1_9TQ;        //配置波特率500bps 的  TS1[3:0] + 1
    can_handle.Init.TimeSeg2 = CAN_BS2_8TQ;        //配置波特率500bps 的  TS2[2:0] + 1
    //上述 BRP[9:0] TS1[3:0] TS2[2:0] 在CAN_BTR寄存器中定义。tq = ([BRP[9:0]+1])*Tpclk(CAN时钟挂载在APB1总线上36MHz)
    can_handle.Init.SyncJumpWidth = CAN_SJW_2TQ;   //配置再同步补偿宽度  SJW 
    
    //其他工作模式的配置
    can_handle.Init.AutoBusOff              =DISABLE;  //禁止自动离线管理
    can_handle.Init.AutoRetransmission      =DISABLE;  //禁止自动重发
    can_handle.Init.AutoWakeUp              =DISABLE;  //禁止自动唤醒
    can_handle.Init.ReceiveFifoLocked       =DISABLE;  //禁止接受FIFO锁定
    can_handle.Init.TimeTriggeredMode       =DISABLE;  //禁止时间触发通信模式
    can_handle.Init.TransmitFifoPriority    =DISABLE;  //禁止发送FIFO优先级
    HAL_CAN_Init(&can_handle);
   
//配置过滤器       
    CAN_FilterTypeDef can_configfilter = {0};
    can_configfilter.FilterMode = CAN_FILTERMODE_IDMASK;       //过滤器的模式:(掩码)屏蔽模式or列表模式。屏蔽模式
    can_configfilter.FilterScale = CAN_FILTERSCALE_32BIT;      //配置过滤器的位数:数据帧扩展格式,ID有28位
    
    can_configfilter.FilterBank = 0;                           //非互联型开发板,只有14组过滤器,这里选择第一组过滤器
    //每组过滤寄存器内有两个寄存器:CAN_FxR1和CAN_FxR2,这里不进行过滤,设置为0。
    can_configfilter.FilterIdHigh = 0;
    can_configfilter.FilterIdLow = 0;
    can_configfilter.FilterMaskIdHigh = 0;
    can_configfilter.FilterMaskIdLow = 0;
    
    can_configfilter.FilterFIFOAssignment = CAN_FILTER_FIFO0;  //选择接收过滤后有效报文的接收FIFO或FIFO1
    can_configfilter.SlaveStartFilterBank = 14;                //固定值,记住
 
    can_configfilter.FilterActivation = CAN_FILTER_ENABLE;     //使能过滤器
    HAL_CAN_ConfigFilter(&can_handle,&can_configfilter);
    
//让CAN正常工作
    HAL_CAN_Start(&can_handle);
}

//利用MSP初始化MCU外设,CLOCK、GPIO、NVIC
void HAL_CAN_MspInit(CAN_HandleTypeDef *hcan){
    __HAL_RCC_CAN1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
       
    GPIO_InitTypeDef gpio_initstruct;
    
    //TXD端口 GPIOA GPIO_PIN_12
    gpio_initstruct.Pin = GPIO_PIN_12;
    gpio_initstruct.Mode = GPIO_MODE_AF_PP;        //复用推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP;
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &gpio_initstruct);
    
    //RXD端口的配置 GPIOA GPIO_PIN_11
    gpio_initstruct.Pin = GPIO_PIN_11;
    gpio_initstruct.Mode = GPIO_MODE_AF_INPUT;        //复用输入
    gpio_initstruct.Pull = GPIO_PULLUP;
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &gpio_initstruct);
    
}

void can_send_data(uint32_t id, uint8_t *buf ,uint8_t len){
    
    CAN_TxHeaderTypeDef tx_header = {0};
    uint32_t tx_mail = CAN_TX_MAILBOX0;   //发送的邮箱编号
    tx_header.ExtId = id;               //拓展帧的ID
    tx_header.DLC = len;                //数据的长度
    tx_header.IDE = CAN_ID_EXT;         //数据帧还是拓展帧
    tx_header.RTR = CAN_RTR_DATA;       //远程请求发送:数据帧还是遥控帧
    HAL_CAN_AddTxMessage(&can_handle,&tx_header,buf,&tx_mail);
    
    //判断邮箱是否发送成功
    while(HAL_CAN_GetTxMailboxesFreeLevel(&can_handle) != 3);  //当三个邮箱中都不是空的时候,等待
    
    //校验是否发送成功
    uint8_t i = 0;
    printf("发送数据:\r\n");
    for(i = 0;i<len;i++)
        printf("%X",buf[i]);
    printf("\r\n");
    
}

uint16_t can_receive_data(uint8_t *buf){
    
    CAN_RxHeaderTypeDef rx_header = {0};
    
    if(HAL_CAN_GetRxFifoFillLevel(&can_handle,CAN_FILTER_FIFO0) == 0)    //FIFO中的没有空位
        return 0 ;
    
    HAL_CAN_GetRxMessage(&can_handle,CAN_FILTER_FIFO0,&rx_header,buf);
    
    //校验是否接收成功
    uint8_t i = 0;
    printf("接收数据:\r\n");
    for(i = 0;i< rx_header.DLC;i++)
        printf("%X",buf[i]);
    printf("\r\n");
    
    return rx_header.DLC;
}
  •  can.h文件代码
#ifndef __CAN_H__
#define __CAN_H__
#include "stm32f1xx.h"

void can_init(void);
void can_send_data(uint32_t id, uint8_t *buf ,uint8_t len);
uint16_t can_receive_data(uint8_t *buf);

#endif
  • mian.c文件代码 
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "can.h"
#include "key.h"

uint8_t data_send[8] = {0,1,2,3,4,5,6,7};
uint8_t data_receive[8];

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    uart1_init(115200);
    printf("hello,world\n");
    can_init();
    key_init();
    
    uint8_t key_num = 0;
    while(1)
    { 
        key_num = key_scan(); 
        if(key_num == 1){
            for(uint8_t i = 0;i< 8;i++)
                data_send[i]++;
            can_send_data(12345678,data_send,8);
        }
        
        can_receive_data(data_send);
    }
}

注意:如何实现两个CAN设备间的通信?

  1. 上面函数中配置的CAN控制器的工作模式是回环模式,用于检测CAN控制器的接收和发送功能是否正常。
  2. 当检测CAN的回环模式下,代码能正常的接收和发送。进行下一步,将CAN控制器的工作模式配置成正常模式,实现两个CAN设备间的收发。

接线:

  1. CAN_TX要和收发器上的TX连接,CAN—RX和收发器上的RX连接。
  2. 两个收发器上的CANH接在一起,CANL接在一起。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值