STM32CubeMX学习笔记15---CAN总线

1、CAN简介

CAN总线网络的结构有闭环和开环两种形式
        闭环结构的CAN总线网络,总线两端各连接一个1202的电阻。这种CAN总线网络由ISO11898标准定义,是高速、短距离的CAN网络,通信速率为125kbit/s到1Mbit/s。在1Mbit/s通信速率时,总线最长40m。

        开环结构的CAN总线网络,两根信号线独立,各自串联一个2.2k·的电阻这种CAN总线网路由ISO11519-2标准定义,是低速、远距离的CAN网络,通信速率最高125kbit/s。在40kbit/s速率时,总线最长距离可达1000m。

两种结构的CAN网络信号线的典型电压值

两根信号线的电压差CANH-CANL表示CAN总线的电平,与传输的逻辑信号1或0对应。对应于逻辑1的称为隐性(Recessive)电平,对应于0的称为显性(Dominant)电平。对应于逻辑1和逻辑0,开环结构和闭环结构CAN 网络的CANH和CANL 的电压值不样,隐性电平和显性电平的电压值也不一样。

 CAN总线传输协议

 1.CAN 总线传输特点

        CAN 总线的数据传输有其自身的特点,主要有以下几点。
        CAN 总线上的节点既可以发送数据又可以接收数据,没有主从之分。但是在同一个时刻,只能有一个节点发送数据,此他节点只他接收数据。
        CAN 总线上的节点没有地址的概念。CAN 总线上的数据是以帧为单位传输的,韩分为数据帧、耀控赣等多种懒类型,帧包含需要传输的数据或控制信息。CAN 总线具有“线与”的特性,也就是当有两个节点同时向总线发送信号时,一个送显性电平《逻辑 0),另一个发送隐性儿平《逻辑 1),则总线量现为显性电平。这个特性被用于总线仲裁,也就是哪个节点优先占用总线进行发送操作。每个帧有一个标识符(ldentifier,以下简称 ID)ID 不是地址,它表示传输数据的型,也可以用于总线仲裁时确定优先级。例如,在汽车的 CAN 总线上,假设用于碰检测的节点输出数据顿的ID为01,车内温度检测节点发送数据的TD为05等每个CAN 节点都接收数据,但是可以对接收的根据ID进行过滤。只有节点需要数据才会被接收并进一步处理,不需要的数据会被自动舍弃。例如,假设安全气囊控制器只接受碰撞检测节点发出的ID为01 的,这种D 的过滤是由件完成的,以安全气囊控制器在发生碰撞时能及时响应。
        CAN 总线通信是半双工的,即总线不能同时发送和接收。在多个节点竞争总线进行发送时,通过 ID 的优先级进行仲裁,党争胜出的节点继续发送,竞争失败的节点立刻进入接收状态。
        CAN 总线没有用于同步的时钟信号,所以需要规定 CAN 总线通信的波特率,所有点都使用相同的波特率进行通信。

 2.位时序和波特率

        一个 CAN 网络需要规定一个通信的波特率,各节点都以相同的波特率进行数据通信。位时序指的是一个节点采集 CAN 总线上的一个位数据的时序,位时序如图 18-3 所示。通过位序的控制,CAN 总线可以进行位同步,以吸收节点时钟差异产生的波特率误差,保证接收数据的准确性。

 

(1)同步段(SYNC SEG):在这个时间段内,总线上应该发生一次位信号的跳变。如果节点在同步段检测到总线上的一个跳变沿,就表示节点与总线是同步的。同步段长度固定为1个tq。tq(timequantum)被称为时间片,tq由CAN控器的时钟领率Fcan决定。在STM32F407中,两个CAN控制器在APB1总线上,CAN 控制器有预分频器,APB1总线的时钟信号PCLK1经分频后得到Fcan。

(2)位段1(Bit Scgment 1,BS1):定义了采样点的位置。在BS1 结束的时间点对总线采样,得到的电平就是这个位的电平。BS1的初始长度是1到16个tq,但它的长度可以在再同步(resynchronization)的时候被自动加长,以补偿各节点频率差异导致的正相位漂移。

(3)位段2(Bit Segment 2,BS2):定义了发送点的位置。BS2 的初始长度是1到8个tq,再同步时可以被自动缩短,以补偿负相位漂移。

CAN 控制器可以自动对位时序进行再同步,再同步时自动调整 BS1和BS2的长度,位段加长或缩短的上限称为再同步跳转宽SW的取值是1到4个tq。

3.帧的种类

4.标准格式数据帧和遥控帧

 

标准格式数据帧和遥控帧的结构如上图 所示,它们都有 11位的ID。数据传输带有ID的0到8字节的数据:遥控只有 D,没有数据,用于请求数据。
数据帧可以分为以下几段。
(1)帧起始 (Start Of Frame,SOF)。帧起始只有一个位,是一个显性电平(逻辑0),表示一个帧的开始。
(2)仲裁段(Arbitration Field)。仲裁段包括11位的ID和RTR位,共12位。多个节点竞争总线发送数据时,根据仲裁段的数据决定哪个节点优先占用总线。哪个ID 先出现显性电平(逻辑 0),对应的节点就占用总线。所以,ID数值小的优先级更高。如果两个节点发送数据帧ID相同,再根据仲裁段最后的RTR位裁决。
RTR(Remote Transmit equest)是远程传输请求,RTR位用于区分数据帧和遥控帧。数据帧的RTR位是显性电平(逻辑 0),遥控的 RTR位是隐性电平(逻辑 1)。所以,具有相同ID的数据帧和遥控帧竞争总线时,数据帧优先级更高。
(3)控制段。控制段包括IDE位、RB0位和4位的DLC,共6位。
IDE是标识符扩展位(Identifier Extension Bit),用于表示是标准格式,还是扩展格式标准格式帧的IE是显性电平(逻辑0),扩展格式的IDE是隐性电平(逻辑1)。RBO是保留位,默认为显性电平。
DLC是4个位的数据长度编码(Data Length Code),编码数值为0到8,表示后面数据段的字节数。遥控帧的DLC编码数值总是0,因为遥控不传输数据。
(4)数据段。数据段里是数据帧需要传输的数据,可以是0到8字节,数据的字节个数由DLC 编码确定。遥控没有数据段。
(5)CRC段。CRC段共16位,其中前 15位是CRC校验码,最后一位总是隐性电平,是CRC段的界定符(Delimiter)。
(6)ACK段。ACK段包括一个ACK位(Acknowledge Bit)和一个ACK 段界定符。发送节点发送的 ACK 位是隐性电平,接收节点接收的 ACK 位是显性电平。
(7)帧结束(End of Frame,EOF)。顿结束是结束段,由7个隐性位表示EOF。
数据帧或遥控帧结束后,后面一般是帧间空间或过载帧,用于分隔开数据帧或遥控帧。

CAN模块基本控制函数

HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef *hcan);        //CAN 模块初始化,主要是配置 CAN 总线通信参数
void HAL_CAN_MspInit(CAN_HandleTypeDef *hcan);                    //CAN模块初始化MSP函数,在HAL_CAN_Init()里被调用。需要用户程序重新实现,用于引脚GPIO 配置,中断优先级配置
HAL_StatusTypeDef HAL_CAN_Start(CAN_HandleTypeDef *hcan);        //启动CAN模块
HAL_StatusTypeDef HAL_CAN_Stop(CAN_HandleTypeDef *hcan);        //停止CAN模块,允许重新访问配置寄存器
HAL_StatusTypeDef HAL_CAN_RequestSleep(CAN_HandleTypeDef *hcan);//使CAN模块在完成当前操作后进入睡眠模式
HAL_StatusTypeDef HAL_CAN_WakeUp(CAN_HandleTypeDef *hcan);        //将CAN模块从睡眠模式唤醒
uint32_t HAL_CAN_IsSleepActive(CAN_HandleTypeDef *hcan);        //查询 CAN 模块是否处于睡眠模式,返回值为1表示模块处于睡眠模式

一个CAN模块需要先用函数HAL_CAN_Init()进行外设初始化,模块处于初始化模式,可进行筛选器组的配置。执行函数HAL_CAN_Init()启动CAN 模块进入正常模式,模块可以在正常模式和睡眠模式之间切换。执行 HAL_CAN_Stop将停止CAN模块。

CAN模块消息发送
一个 CAN 模块有 3 个发送邮箱。发送数据时,用户需要选择一个空闲的发送邮箱,将标识符ID、数据长度和数据(最多8 字节)写入邮箱,然后 CAN 模块会自动控制将邮箱内的数据发送出去。
用户可以设置自动重发,也就是在出现错误后自动重发,直到成功发送出去。如果禁止自动重发,则发送失败后不再重发,会通过发送状态寄存器 CAN TSR 相应的位指示错误原因如仲裁丢失或发送错误。

函数HALCAN GetTxMailboxesFreeLevel()用于查询一个CAN模块空闲的发送邮箱个数如果有空闲的发送邮箱,就可以使用函数 HAL CAN AddTxMessage0向发送邮箱写入一条消息然后由CAN模块启动发送过程。

CAN 模块发送数据是将消息写入模块的发送邮箱,然后由 CAN 控制器将邮箱内的消息发送出去。CAN 模块发送消息只有 HAL CAN AddTxMessage0这一个函数,不像串口、SPI等其“外设有中断模式、DMA 方式的专用函数。
将消息写入邮箱后,可以用函数 HAL CAN ISTxMessagePending0查询邮箱里的消息是否发送出去了。

CAN模块消息接收

每个CAN模块有两个接收FIFO(Receive FIFO)每个FIFO(本章后面都将“接收FIFO简称为“FIFO”)有 3 个邮箱。FIFO 完全由硬件管理,当有邮箱接收到有效消息时,就会产生相应的事件中断标志,可以产生 CANRX 硬件中断。FIFOO和FIFO1有各自的中断地址。从邮箱中读出消息后,邮箱就自动释放。如果一个 FIFO的3个邮箱都接收到消息而没有及时读出,再有消息进入时就会产生上溢。根据是否设置 FIFO 锁定,有两种处理情况。
如果禁止FIFO锁定,则新传入的消息会覆盖 FIFO中存储的最后一条消息。
如果启用 FIFO锁定,则新传入的消息会被舍弃。

标识符筛选
STM32F4 的两个 CAN 控制器有28个共用的标识符筛选器组(Filter Bank),可以完全用硬件方式对接收的帧 ID 进行筛选,只允许符合条件的顿进入接收邮箱,自动放弃不符合条件的帧。
每个筛选器组包含两个32位寄存器,分别是 CAN FXR1和CAN FXR2。这两个寄存器可以被配置为两个32位长度筛选器或4个16位长度筛选器,筛选器可以是掩码模式或列表模式所以一个筛选器组有4种配置模式。

(1)1个32位筛选器标识符掩码模式。在这种模式下,寄存器 CAN_FxR1 存储一个32 位I,这个ID与11 位标准 ID(STID[10:0])、18 位扩展ID(EXID[17:0])、IDE 位、RTR位的位置对应关系如图 18-8 中的模式(1)所示。IDE为0时表示标准格式,否则表示扩展格式帧。

CAN FxR2 存储一个 32 位掩码,如果掩码为 1,则表示该位必须与D中的位一致,如果为 0,则表示不用一致。

(2)2个32位筛选器一一标识符列表模式。在这种模式下,寄存器CAN FxR1和CAN FxR2各存储一个 32位ID,ID的组成与模式(1)相同。只有匹配这两个ID 的才能通过筛选。
(3)2个16位筛选器一标识符码模式。在这种模式下,寄存器CAN FxR1的高16位组成一个ID,低16 位组成一个掩码;寄存器 CAN FxR2的高 16 位组成一个ID,低16 位组成一个掩码。
(4)4个16 位筛选器一一标识符列表模式。在这种模式下,寄存器 CAN FxR1 表示2个16位ID,寄存器CAN FxR2表示2个16位ID。16位ID的组成如图18-8 中的模式(4)所示用户可以为一个FIFO 设置多个筛选器组,但是一个筛选器组只能配置给一个 FIFO。如果为 FIFO 设置了筛选器,并且接收的帧与所有筛选器都不匹配,那么该帧会被丢弃。只要通过了一个筛选器,帧就会被存入接收邮箱。

举例 1:设置滤波器,采用一个 32 位滤波器的标识符屏蔽模式,将 CANID设置为 0x028A,接收标准帧、数据帧。

再次强调 :在标识符屏蔽模式下,过滤器组 x的第一个标识符寄存器(CAN_FXR1)用来保存与报文ID比较的完整标识符。第二个标识符寄存器(CAN_FXR2)用来表示屏蔽位,即表明报文 ID 要与第一个标识符寄存器中的哪几位比较,值为1的寄存器位就是屏蔽位(参与比较,位必须匹配才能通过滤波器),值为 0的寄存器位不参与比较。

答:标识符寄存器CAN FxR1设置:

第0位保留,置0;第一位为报文的 RTR 位置0(数据);第 2位是报文的IDE 位置0(标准帧)。
报文的扩展ID保存在第 3~20位(共18位),全部设置为 0。
报文的标准ID保存在第21~32位(共11位),设置为0x028A。

标识符寄存器CAN FxR2设置:

第0位保留,置 0;第一位屏蔽位(参与比较)置 1;第二位屏蔽位(参与比较)置1。
报文的扩展ID 保存在第 3~20 位(共 18位),不参与比较全部设置为0。
报文的标准ID保存在第 21~32 位(共 11位),参与比较,全部设置为1。

函数 HAL CAN ConfigFilter()用于设置 CAN 模块的标识符筛选器,应该在执行 HAL_CAN_Start()启动一个 CAN模块之前调用这个函数

结构体 CAN_Filter_TypeDef 类型指针,它保存了筛选器的设置这个结构体定义如下,各成员变量的意义见注释:

typedef struct
{
  uint32_t FilterIdHigh;          /*CAN_EXR1寄存器的高16位,取值范围为0~0XEEEE*/
  uint32_t FilterIdLow;           /*CAN_EXR1寄存器的低16位,取值范围为0~0XEEEE */
  uint32_t FilterMaskIdHigh;      /*CAN EXR2寄存器的高 16位,取值范围为0~0XEEEE*/
  uint32_t FilterMaskIdLow;       /*CAN_ExR2寄存器的低16位,取值范围为0~0XEEEE*/
  uint32_t FilterFIFOAssignment;  /*筛选器应用于哪个FIFO,使用宏 CAN FILTER_FIEOO或CANFILTER_EIEO1 */
  uint32_t FilterBank;            /*筛选器组编号,具有双CAN模块的MCU有28个筛选器组,编号范围为0~27 */
  uint32_t FilterMode;            /*筛选器模式,ID 掩码模式(AN_FILTERMODE IDMASK)或ID列表模式(CAN_EILTERMODE_IDLIST)*/
  uint32_t FilterScale;           /*筛选器长度,即32位(CAN_FILTERSCALE 32BIT)或16位(CAN FILTERSCALE_16BIT) */
  uint32_t FilterActivation;      /*是否启用此筛选器,ENABLE 或者 DISABLE*/
  uint32_t SlaveStartFilterBank;  /*/设置应用于从CAN 控制器的筛选器的起始编号*/
} CAN_FilterTypeDef;

1.中断和中断事件
一个CAN模块有4个中断,对应4个ISR。例如,CAN1的4个中断及其ISR如表18-7所示,下面都以CAN1为例说明。

在CubeMX为CAN模块的4个硬件中断生成的ISR中,都调用了函数HAL_CAN IRQHandler0:这是 CAN 中断处理通用函数。函数 HAL CAN IRQHandler0会根据中断使能寄存器、中断标志寄存器的内容判断具体发生了哪个中断事件,再调用相应的回调函数。CAN 的HAL 驱动程字中为常用的中断事件定义了回调函数,只要搞清楚中断事件与回调函数的对应关系,编程时重新实现关联的回调函数,就可以对某个中断事件做出处理。

发送中断的事件源和回调函数
发送中断(CAN1 TX)只有一个中断事件源CAN IT TX MAILBOX EMPTY,在3个发送邮箱中任何一个发送完成时都产生该事件中断,但是3 个邮箱有各自的回调函数

1.发送中断(CAN1 TX)的中断事件源和回调函数
发送中断(CAN1 TX)只有一个中断事件源CAN IT TX MAILBOX EMPTY,在3个发送邮箱中任何一个发送完成时都产生该事件中断,但是3 个邮箱有各自的回调函。

中断事件类型宏中断事件说明回调函数
CAN IT TX MAILBOX EMPTY邮箱0发送完成HAL CAN TxMailbox0CompleteCallback()
CAN IT TX MAILBOX EMPTY邮箱1发送完成HAL CAN TxMailbox1CompleteCallback()
CAN IT TX MAILBOX EMPTY邮箱2发送完成HAL CAN TxMailbox2CompleteCallback()

2.中止邮箱发送的回调函数
发送中断(CAN1 TX)只有一个中断事件源CAN IT_TX_MAILBOX_EMPTY,在3个发送邮箱中任何一个发送完成时都产生该事件中断,但是3 个邮箱有各自的回调函数

中断事件类型宏中断事件说明回调函数
HAL CAN AbortTxRequest()邮箱0发送被中止HAL CAN_TxMailbox0AbortCallback()
HAL CAN AbortTxRequest()邮箱1发送被中止HAL CAN_TxMailbox1AbortCallback()
HAL CAN AbortTxRequest()邮箱2发送被中止HAL CAN_TxMailbox2AbortCallback()

3.FIFO0 接收中断(CAN1 RX0)的中断事件源和回调函数
FIFO0接收中断(CAN1 RX0)是在 FIFO0 接收消息、满或上溢时触发的中断。这个中断也有3 个中断事件源,对应的回调函数

中断事件类型宏中断事件说明回调函数
CAN IT RX FIFOO MSG PENDINGFIFO0接收新消息HAL CAN RxFifo0MsgPendingCallback()
CAN IT RX FIFOO FULLFIFO0满HAL CAN RxFifo0FullCallback0()
CAN IT RX FIFOO OVERRUNFIFO0 发生上溢-

4.状态改变或错误中断(CAN1 SCE)的中断事件源和回调函数
状态改变或错误中断(CAN1 SCE)在 CAN 模块发生状态改变或错误时触发,例如,CAN模块进入睡眠状态或从睡眠状态被唤醒,或出现总线错误等。

中断事件类型宏中断事件说明回调函数
CAN IT SLEEP ACKCAN模块进入睡眠状态HAL CAN SleepCallback()
CAN IT WAKEUP检测到消息,被唤醒HAL CAN WakeUpFromRxMsgCallback()
CAN IT ERROR CAN IT BUSOFF 等多种有多种错误事件源,通过错误状态寄存器 CAN ESR的内容判断具体错误类型HAL CAN ErrorCallback()

    以上转自他人,原文链接:https://blog.csdn.net/weixin_41226265/article/details/134094701

 2、硬件设置

LED2指示系统正常运行,CAN口发送和接收数据,并将接收到的数据通过串口打印出来。

  • LED2指示灯
  • USART1
  • CAN口PA11、PA12

 3、 STM32CubeMX设置

  • RCC设置外接HSE,时钟设置为72M
  • PE5设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
  • USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
  • 激活CAN,配置CAN参数,预分频设置为9,段1设置为8,段2设置为7,同步跳转宽度设置为1,其他保持默认,即波特率为 36MHz/((8+7+1)*9)=250KHz

Bit Timings Parameters 组,定位时间参数
Time Quanta in Bit Segment 1,位段1的时间片个数为 m,范围为1~16,这里设置为8
Time Quanta in Bit Segment 2,位段2 的时间片个数为n,范围为1~8,这里设置为7
ReSynchronization Jump Width (SJW),再同步跳转宽度,设置范围为1~4,这里设置为7
CAN通信的波特率由同步段、BS1、BS2 的时间片个数决定,波特率计算公式如下图所示

Basic Parameters 组,基本参数。
Time Triggered Communication Mode (TTCM 位),时间触发通信模式。设置为 Disabl表示禁止时间触发通信模式,若启用 TTCM,则在发送或接收消息时,会加上一个内部计数器的计数值。

Automatic Bus-O Management (ABOM 位),自动的总线关管理。设置为 Disable 表示不使用自动的总线关闭。
Automatic Wake-Up Mode (AWUM 位),自动唤限模式。这个参数用于控制 CAN模在睡眠模式下接收消息时的行为,如果设置为 Enabie,则表示只要接收消息,就通过硬件自动退出睡眠模式。

Automatic Retransmission (NART 位),自动重发。若设置为 Enable, CAN 模将自动重发消息,直到发送成功为止,若设置为 Disable,则无论发送结果如何,消息只发送一次。这个设定值实际是对 NART 位值取反,因为NART 表示禁止自动重发。

Receive Fifo Locked Mode (RFLM 位),接收PFO锁定模式。若设置为 Disable,表FIFO 上溢不锁定,下一条新消息覆盖前一条消息。若设置为 Enable,则表示上溢后锁定,丢弃下一条新消息

Transmit Fifo Priority (TXFP 位),发送 FIFO 优先级。若设置为 Disable,表示消息先级由标识符决定;若设置为 Enable,表示优先级由请求顺序决定。

Advanced Parameters 组,高级参数。
Operating Mode,用于设置CAN 模块的工作模式,有4种工作模式可选,即正常(Normal静默(Silent)、回环 (Loopback)、回环静默 (Loopback combined with Silent)。其中后3 种是 CAN 模块的测试模式。这里设置为Normal,使用其自发自功能进行 CAN 收发功能的测试。

  •  开启CAN总线中断允许

  •   输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

4、程序编程

在can.c文件下可以看到CAN总线的配置函数,CAN相关函数说明

HAL_CAN_Start	//开启CAN通讯
HAL_CAN_Stop	//关闭CAN通讯
HAL_CAN_RequestSleep	//尝试进入休眠模式
HAL_CAN_WakeUp	//从休眠模式中唤醒
HAL_CAN_IsSleepActive	//检查是否成功进入休眠模式
HAL_CAN_AddTxMessage	//向 Tx 邮箱中增加一个消息,并且激活对应的传输请求
HAL_CAN_AbortTxRequest	//请求中断传输
HAL_CAN_IsTxMessagePending	//检查是否有传输请求在指定的 Tx 邮箱上等待
HAL_CAN_GetRxMessage	//从Rx FIFO 收取一个 CAN 帧

做完CAN的基本配置后,为了收发CAN数据,还需要进行CAN滤波器配置和发送消息句柄、接收消息句柄设置。

关于过滤器的说明与详解,可以参考这个
链接: 再谈STM32的CAN过滤器-bxCAN的过滤器的4种工作模式以及使用方法总结.

  1. CAN滤波器配置
    CAN过滤器是用于处理CAN接收过滤问题的,
/**
 * @brief           CAN过滤器配置  
 * @param[in]          
 * @return          
 */
void CAN_Filter_Config(void)
{
    CAN_FilterTypeDef  sFilterConfig;
    
    /*配置CAN过滤器*/
    sFilterConfig.FilterBank = 0;      //过滤器0               
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x0000;         //32位ID      
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;      //32位MASK    
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
    sFilterConfig.FilterActivation = ENABLE;           //激活滤波器0
    sFilterConfig.SlaveStartFilterBank = 14; 
    
    //过滤器配置 //初始化过滤器
    if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
    {
        while(1){}
				// Error_Handler();
    }

   //启动CAN外围设备
    if (HAL_CAN_Start(&hcan) != HAL_OK)
    {
        while(1){}
				// Error_Handler();
    }
      
    //激活可以RX通知,开启接受邮邮箱0挂起中断
    if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
    {
        while(1){}
			// Error_Handler();
    }
		
   /*配置传输过程*/
//  TXHeader.StdId = 0x321;
//  TXHeader.ExtId = 0x01;
//  TXHeader.RTR = CAN_RTR_DATA;
//  TXHeader.IDE = CAN_ID_STD;
//  TXHeader.DLC = 2;
//  TXHeader.TransmitGlobalTime = DISABLE;		
	
}

新建一个user_can.h和user_can.c文件

#ifndef __user_can_h__
#define __user_can_h__

#include "can.h"

extern uint8_t can_rec_dat[8];	//用于中断接收

void CAN_Filter_Config(void);
uint8_t CAN_Send_Msg(CAN_HandleTypeDef *hcan,uint8_t* msg, uint8_t len, uint8_t std_id);
uint32_t CAN_Receive_Msg(CAN_HandleTypeDef *hcan,uint8_t *buf);

#endif


#include "user_can.h"


//can配置函数,可重新配置CAN

uint8_t CAN1_Mode_Init(uint32_t tsjw,uint32_t tbs2,uint32_t tbs1,uint16_t brp,uint32_t mode)
{
	CAN_InitTypeDef		CAN1_InitConf;
    
    hcan.Instance=CAN1;
	
	  hcan.Init = CAN1_InitConf;
	
    hcan.Init.Prescaler=brp;				//分频系数(Fdiv)为brp+1
    hcan.Init.Mode=mode;					//模式设置 
    hcan.Init.SyncJumpWidth=tsjw;			//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ
    hcan.Init.TimeSeg1=tbs1;				//tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ
    hcan.Init.TimeSeg2=tbs2;				//tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ
    hcan.Init.TimeTriggeredMode=DISABLE;	//非时间触发通信模式 
    hcan.Init.AutoBusOff=DISABLE;			//软件自动离线管理
    hcan.Init.AutoWakeUp=DISABLE;			//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
    hcan.Init.AutoRetransmission=ENABLE;	//禁止报文自动传送 
    hcan.Init.ReceiveFifoLocked=DISABLE;	//报文不锁定,新的覆盖旧的 
    hcan.Init.TransmitFifoPriority=DISABLE;	//优先级由报文标识符决定 
	
    if(HAL_CAN_Init(&hcan)!=HAL_OK)			//初始化
		return 1;
    return 0;
}


/**
 * @brief           CAN过滤器配置  
 * @param[in]          
 * @return          
 */
void CAN_Filter_Config(void)
{
    CAN_FilterTypeDef  sFilterConfig;
    
    /*配置CAN过滤器*/
    sFilterConfig.FilterBank = 0;      //过滤器0               
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x0000;         //32位ID      
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;      //32位MASK    
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //过滤器0关联到FIFO0
    sFilterConfig.FilterActivation = ENABLE;           //激活滤波器0
    sFilterConfig.SlaveStartFilterBank = 14; 
    
    //过滤器配置 //初始化过滤器
    if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
    {
        while(1){}
				// Error_Handler();
    }

   //启动CAN外围设备
    if (HAL_CAN_Start(&hcan) != HAL_OK)
    {
        while(1){}
				// Error_Handler();
    }
      
    //激活可以RX通知,开启接受邮邮箱0挂起中断
    if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
    {
        while(1){}
			// Error_Handler();
    }
		
   /*配置传输过程*/
//  TXHeader.StdId = 0x321;
//  TXHeader.ExtId = 0x01;
//  TXHeader.RTR = CAN_RTR_DATA;
//  TXHeader.IDE = CAN_ID_STD;
//  TXHeader.DLC = 2;
//  TXHeader.TransmitGlobalTime = DISABLE;		
	
}


/**
 * @brief           CAN发送一组数据 
	 @param[in]       hcan1:需要发送的CAN口
 * @param[in]       msg:待发送的数据(最大为8个字节)
 * @param[in]       len:数据帧的长度(最大为8)
 * @param[in]       std_id:CAN_ID
 * @return          0:发送成功   1:发送失败
 */
uint8_t CAN_Send_Msg(CAN_HandleTypeDef *hcan1,uint8_t* msg, uint8_t len, uint8_t std_id)
{	
    CAN_TxHeaderTypeDef	can_tx_header;      
	  uint32_t TxMailbox;
	
    can_tx_header.StdId = std_id;  //指定标准标识符。此参数必须是介于Min_Data=0和Max_Data=0x7FF之间的数字*/      
    can_tx_header.IDE = CAN_ID_STD;    //指定将要传输的消息的标识符类型。用标准即可
    can_tx_header.RTR = CAN_RTR_DATA;  //将要传输的消息的帧类型
    can_tx_header.TransmitGlobalTime = ENABLE;//启动时捕获时间戳计数器值
    can_tx_header.DLC = len;  //将要传输的帧的长度  0-8 

	
    //MailboxesFreeLevel = HAL_CAN_GetTxMailboxesFreeLevel(&hcan);
    while(HAL_CAN_GetTxMailboxesFreeLevel(hcan1)==0); //返回Tx邮箱可用级别:可用Tx邮箱的数量。
    
	if(HAL_CAN_AddTxMessage(hcan1, &can_tx_header, msg, &TxMailbox) != HAL_OK)//发送
	{
		return 1;
	}
    return 0;
}

//普通接收函数
/**
 * @brief           CAN接收一组数据 
	 @param[in]       hcan1:需要接收的CAN口
 * @param[in]       buf:接收的数据存放数组(最大为8个字节)
 * @return          0:接收失败   数据帧的长度(最大为8):接收成功
 */
uint32_t CAN_Receive_Msg(CAN_HandleTypeDef *hcan,uint8_t *buf)
{
 	uint32_t i;
	uint8_t	RxData[8];
	CAN_RxHeaderTypeDef	can_rx_header;      //接收
	
	if(HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO0) != 1)//没有接收到数据,直接退出 
	{
		return 0;
	}

	if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &can_rx_header, RxData) != HAL_OK)
	{
		return 0;
	}
	
    for(i=0;i<can_rx_header.DLC;i++)
    buf[i]=RxData[i];
	  return can_rx_header.DLC;
}


/**
 * @brief           CAN接收回调函数
 */
 
 // can接收buffer,这里用全局变量保存,以便其他函数处理
uint8_t can_rec_dat[8];	

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    CAN_RxHeaderTypeDef	can_rx_header;      //接收
    if(hcan->Instance == CAN1)
    {
        HAL_CAN_GetRxMessage(hcan,CAN_FILTER_FIFO0,&can_rx_header,can_rec_dat);//获取数据存到can_rec_dat
    }
}

main中使用CAN通讯函数

int main()
{
///***省略***///

//		CAN1_Mode_Init(CAN_SJW_1TQ,CAN_BS2_6TQ,CAN_BS1_11TQ,8,CAN_MODE_NORMAL); //CAN初始化,波特率250Kbps   
  CAN_Filter_Config();
	uint8_t tx_buf8[8]={"12345678"};
	uint8_t rx_buf8[8];
  while (1)
  {
		CAN_Send_Msg(&hcan,tx_buf8, strlen((const char *)tx_buf8), 0x01);//CAN发送数据,
		
		if(CAN_Receive_Msg(&hcan,rx_buf8)!=0) //如果接收到数据则打印出来
		{
			printf1("can rx_buf=%s",rx_buf8);
		}
		
//		printf1("can can_rec_dat=%s",can_rec_dat);	//CAN中断接收
		
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

5、下载验证

 程序编译无误后下载到板子上进行验证

6、参考文献

STM32CubeMX学习笔记-CAN接口使用_cubemx stm32 can-CSDN博客

使用STM32Cube MX为STM32 CAN总线快速配置上手教程_HAL库_CAN协议_STM32_附波特率计算工具_can总线滤特率计算工具-CSDN博客

 STM32CUBEMX系列——CAN通讯的配置_stm32cubemx 配置103 can-CSDN博客

链接:https://pan.baidu.com/s/10pxsGElFsUCfuDcg2kwmcA 
提取码:83ue

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【嵌入式——QT】Model/View

【嵌入式——QT】Model/View 基本原理数据模型视图组件代理Model/View结构的一些概念QFileSystemModelQStringListModelQStandardItemModel自定义代理 基本原理 GUI应用程序的一个很重要的功能是由用户在界面上编辑和修改数据&#xff0c;典型的如数据库应用程序&#xff0c;数…

wsl 安装 ubuntu

文章目录 打开Windows PowerShell查看可安装的ubuntu安装相对应的ubuntu将用户添加到sudoers文件中&#xff0c;并赋予了该用户sudo权限。 打开Windows PowerShell 以管理员的身份运行 查看可安装的ubuntu wsl.exe --list --online安装相对应的ubuntu wsl --install 版本…

计算机网络面经-HTTPS加密过程

前言 在上篇文章HTTPS详解一中&#xff0c;我已经为大家介绍了 HTTPS 的详细原理和通信流程&#xff0c;但总感觉少了点什么&#xff0c;应该是少了对安全层的针对性介绍&#xff0c;那么这篇文章就算是对HTTPS 详解一的补充吧。还记得这张图吧。 HTTPS 和 HTTP的区别 显然&am…

安装zabbix

部署Zabbix监控平台 部署一台Zabbix监控服务器&#xff0c;一台被监控主机&#xff0c;为进一步执行具体的监控任务做准备&#xff1a; 安装LNMP环境源码安装Zabbix安装监控端主机&#xff0c;修改基本配置初始化Zabbix监控Web页面修改PHP配置文件&#xff0c;满足Zabbix需求…

2024 GoLand激活,分享几个GoLand激活的方案

文章目录 GoLand公司简介我这边使用GoLand的理由GoLand 最新变化GoLand 2023.3 最新变化AI Assistant 正式版GoLand 中的 AI Assistant&#xff1a;_Rename_&#xff08;重命名&#xff09;GoLand 中的 AI Assistant&#xff1a;_Write documentation_&#xff08;编写文档&…

VScode+Zotero+Latex文献引用联动

一、VScodeLatex联动 1、VScode的安装 2、texlive.iso安装 可以参考以下&#xff0c;也可以忽略所有直接一步一步默认安装 https://zhuanlan.zhihu.com/p/442308176 3、Vscode的插件安装&#xff1a;【latex workshop】 4、打开设置&#xff0c;搜索json&#xff0c;然后点击…

最新基于R语言lavaan结构方程模型(SEM)技术应用

结构方程模型&#xff08;Sructural Equation Modeling&#xff0c;SEM&#xff09;是分析系统内变量间的相互关系的利器&#xff0c;可通过图形化方式清晰展示系统中多变量因果关系网&#xff0c;具有强大的数据分析功能和广泛的适用性&#xff0c;是近年来生态、进化、环境、…

JVM运行时数据区——对象的实例化内存布局与访问定位

文章目录 1、对象的实例化1.1、创建对象的方式1.2、创建对象的步骤 2、对象的内存布局3、对象的访问定位3.1、对象访问的定位方式3.2、使用句柄访问3.3、使用指针访问 4、小结 平时大家经常使用new关键字来创建对象&#xff0c;那么我们创建对象的时候&#xff0c;怎么去和运行…

css 用flex做成田字型

哈喽&#xff0c;各位小伙伴&#xff01;今天给大家来css控制div完成田字型样式&#xff0c;来&#xff0c;看看下面的效果图&#xff1a; 一看就知道你们想要代码了&#xff0c;不急。代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head>&…

Qt/C++音视频开发68-检查是否含有B帧/转码推流/拉流显示/监控拉流推流/海康大华宇视监控

一、前言 为什么需要判断视频文件是否含有B帧&#xff0c;这个在推流的时候很容易遇到这个问题&#xff0c;一般来说&#xff0c;没有B帧的视频文件&#xff0c;解码后的数据帧pts和dts都是顺序递增的&#xff0c;而有B帧的则未必&#xff0c;可能有些需要先解码后面显示&…

uniapp+node.js前后端做帖子模块:发布帖子评论(社区管理平台的小程序)

目录 0前提1.一些准备1.1表帖子表 post帖子评论表 postComment 1.2总体思路 2.前端3.后端4.验证结果 &#x1f44d; 点赞&#xff0c;你的认可是我创作的动力&#xff01; ⭐️ 收藏&#xff0c;你的青睐是我努力的方向&#xff01; ✏️ 评论&#xff0c;你的意见是我进步的…

CVPR 2022 Oral | Bailando: 基于编舞记忆和Actor-Critic GPT的3D舞蹈生成

目录 测试结果&#xff1a; 02 提出的方法 测试结果&#xff1a; 预测有3个步骤&#xff0c;速度比较慢 02 提出的方法 1. 针对舞蹈序列的VQ-VAE和编舞记忆 与之前的方法不同&#xff0c;我们不学习从音频特征到 3D 关键点序列的连续域的直接映射。相反&#xff0c;我们先让…

Springboot 的几种配置文件形式

方式一&#xff1a;多个yml文件 步骤1&#xff1a;创建多个配置文件 application.yml #主配置文件 application-dev.yml #开发环境的配置 application-prod.yml #生产环境的配置 application-test.yml #测试环境的配置步骤2&#xff1a;applicaiton.yml中指定配置 在a…

算法Day05_707.设计链表

推荐阅读 算法day01_ 27. 移除元素、977.有序数组的平方 算法day02_209.长度最小的子数组 算法day03_ 59.螺旋矩阵II 算法Day04_203.移除链表元素 目录 推荐阅读707.设计链表题目思路解法单链表解法双链表解法 707.设计链表 题目 你可以选择使用单链表或者双链表&#xff0c;设…

桶装水系统订水送水软件有哪些实用功能?

桶装水配送系统送水订水小程序预约水票开发定制桶装水管理软件特色; 1、订水软件界面简洁明了&#xff0c;操作简单易上手 2、桶装水管理软件正式版软件的功能全面&#xff0c;涉及到了桶装水后台管理的全部流程 3、财务报表可以自动计算出桶装水销售的详细数据 4、仓库管理、仓…

Android14音频进阶:AudioTrack与AudioFlinger创建数据通道(五十八)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

代码训练LeetCode(3)移除元素

代码训练(3)LeetCode之移除元素 Author: Once Day Date: 2024年3月6日 漫漫长路&#xff0c;才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 27. 移除元素 - 力扣&#xff08;LeetCode&#xff09;力扣 (LeetCode) 全球极客挚爱的技…

Ubuntu 22.04桥接wifi上网,设置静态IP

记录一下整个过程 打开虚拟网络编辑器&#xff0c;配置桥接模式到主机无线网卡&#xff0c;如图 配置虚拟机网络适配器&#xff0c;设置为桥接模式&#xff0c;勾选“复制” 打开虚拟机&#xff0c;打开终端 cd /etc/netplan目录下有 .yaml 配置文件&#xff0c;用vim编辑器打…

《MySQL实战45讲》课程大纲

1MySQL实战45讲-01基础架构&#xff1a;一条SQL查询语句是如何执行的&#xff1f;2MySQL实战45讲-02日志系统&#xff1a;一条SQL更新语句是如何执行的&#xff1f;3MySQL实战45讲-03事务隔离&#xff1a;为什么你改了我还看不见&#xff1f;4MySQL实战45讲-04深入浅出索引&…

基于云效构建部署Springboot项目到ACK

介绍 为了提高项目迭代的速度加速交付产品给客户&#xff0c;我们通常会选择CICD工具来减少人力投入产生的成本&#xff0c;开源的工具比如有成熟的Jenkins&#xff0c;但是本文讲的是阿里云提高的解决方案云效平台&#xff0c;通过配置流水线的形式实现项目的快速部署到服务器…