STM32CubeMX学习笔记-CAN接口使用

STM32CubeMX学习笔记-CAN接口使用

  • CAN总线传输协议
    • 1.CAN 总线传输特点
    • 2.位时序和波特率
    • 3.帧的种类
    • 4.标准格式数据帧和遥控帧
    • 从STM32F407参考手册中可以看出主要特性如下
      • CAN模块基本控制函数
      • CAN模块消息发送
      • CAN模块消息接收
      • 标识符筛选
      • 发送中断的事件源和回调函数
  • CubeMX项目设置
      • Basic Parameters 组,基本参数。
      • Advanced Parameters 组,高级参数。
  • 代码

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.标准格式数据帧和遥控帧

在这里插入图片描述
标准格式数据帧和遥控帧的结构如图 18-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。
数据帧或遥控帧结束后,后面一般是帧间空间或过载帧,用于分隔开数据帧或遥控帧。

从STM32F407参考手册中可以看出主要特性如下

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

具有 16位自由运行的定时器,可以定时触发通信,可以在最后两个数据字节发送时间戳。
每个CAN模块有两个FIFO单元,每个FIFO有3个接收邮箱,每个FIFO有独立的断地址。
两个CAN 模块共用 28 个筛选器组,筛选器用于配置可接收ID 列表或掩码。数据和遥控帧根据ID被筛选,只有通过筛选的才进入接收邮箱。的筛选完全由硬件完成减少处理器的负担。

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

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

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

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 发生上溢-

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

中断事件类型宏中断事件说明回调函数
CAN IT RX FIFOO MSG PENDINGFIFO1接收新消息HAL CAN RxFifo1MsgPendingCallback()
CAN IT RX FIFOO FULLFIFO1满HAL CAN RxFifo1FullCallback0()
CAN IT RX FIFOO OVERRUNFIFO1 发生上溢-

5.状态改变或错误中断(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()

CubeMX项目设置

CAN总线的APB1时钟树设置
在这里插入图片描述
CAN功能的模式与参数设置
在这里插入图片描述

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 模块的测试模式(见图 18-7)。这里设置为 Loopback,使用其自发自功能进行 CAN 收发功能的测试。

CAN总线的波特率计算
在这里插入图片描述
Time Quanta in Bit Segment 1,位段1的时间片个数为 m,范围为1~16,这里设置为
Time Quanta in Bit Segment 2,位段2 的时间片个数为n,范围为1~8,这里设置为
ReSynchronization Jump Width (SJW),再同步跳转宽度,设置范围为1~4,这里设置为
CAN通信的波特率由同步段、BS1、BS2 的时间片个数决定(见图18-3),波特率计算公式如上图所示

注意,STM32F407 的 CAN 控制器在闭环 CAN 网络中波特率范围是 125kbit/s1Mbit/s如果计算的实际波特率不在这个范围内,则需要调整分频系数或各位段的时间片个数。

开启CAN总线中断允许
在这里插入图片描述

代码

canl.c文件

#include"can1.h"//库文件用明
#include "main.h"
uint8_t CAN1_RX_BUF[CAN1_REC_LEN]//接收缓冲,最大CAN1_REC_LEN个字节.末字节为换行符
uint16_t CAN1_RX_STA;//接收状态标记

//是对CubeMx中设置的波特率等参数进行初始化和帧模式、ID、过滤器等高级应用进行设置
//这是CubeMX参数中没有的 特别是过滤器的设置



void CAN_User_Init(CAN_HandleTypeDef* hcan)//CAN总线用户初始化函数
{
	CAN_FilterTypeDef sFilterConfig;
	HAL_StatusTypeDef HAL_Status;
	TxMeg.IDE = CAN_ID_STD;//扩展帧标识(STD标准帧/EXT扩展帧)
	TxMeg.RTR = CAN_RTR_DATA;//远程帧标识(DATA数据帧/REMOTE远程帧)
	sFilterConfig.FilterBank=0;//过虑器
	sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;//设为IDLIST列表模式/IDMASK屏蔽横式
	sFilterConfig.FilterScale= CAN_FILTERSCALE_32BIT;//过滤器位宽既
	sFilterConfig.FilterIdHigh =CAN1_ID_H;//32位基础ID设置(高16位)
	sFilterConfig.FilterIdLow =CAN1_ID_L;//32位基础ID设置(低16位)
	sFilterConfig.FilterMaskIdHigh = CAN1_MASK_H;//32位屏蔽MASK设置(高16位)
	sFilterConfig.FilterMaskIdLow = CAN1_MASK_L;//32位屏蔽MASK设置(低16位)
	sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO1;//接收到的报文放入FIFO1位置
	sFilterConfig.FilterActivation = ENABLE;//ENABLE谢活过滤器,DISABLE禁止过滤器
	sFilterConfig.SlaveStartFilterBank =0;//过滤器组设置(单个CAN总线时无用)
	HAL_Status=HAL_CAN_ConfigFilter(hcan,&sFilterConfig);//将以上结构体参数设置到CAN寄存器中

}


//接收回调函数(函数名不可改) CAN总线收到数据后会进入中断回调函数

void HAL_CAN_RxFifolMsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	uint8_t Data[8]//接收缓存数组
	HAL_StatusTypeDef HAL_RetVal;//判断状态的枚举
	HAL_RetVal=HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO1,&RxMeg,Data);//接收邮箱中的数据
	if(HAL_OK==HAL_RetVal){//判断接收是否成功
	//接收成功后的数据处理程序,写在此处。(数据在Data数组中)
	//以下2行是采用简单的寄存器查寻方式处理接收数据,每次只接收1位。在实际项目中的复杂接收程序可自行编写。
	CAN1_RX_BUF[e]=Data[e]//将接收到的数据放入缓存数组(因只用到1个数据,所以只存放在数据[O]位置)
	CAN1_RX_STA++//数据接收标志位加1
}





//CAN发送数据数(参数:总线名,ID,数据数组,数量,返回值,O成功HAL_OK,1参数错误HAL_ERROR,2发送失败HAL_BUSY)
//示例,CAN1_SendNormalData(&hcan1,0,CAN_buffer,8);//CAN发送教据面教
uint8_t CAN1_SendNormalData(CAN_HandleTypeDef* hcan,uint16_t ID,uint8_t *pData,uint16_t Len)
{
	HAL_StatusTypeDef HAL_RetVal;//判断状态的枚举
	uint16_t SendTimes,SendCNT=0;
	uint8_t FreeTxNum=0;
	uint32_t CAN_TX_BOX0;
	TxMeg.StdId=ID;
		if(!hcan||!pData||!Len)
		{
			USART1_printf("\n\rCAN发送失败!\n\r");//串口发送
			return HAL_ERROR;//如果总线名、数据、数量任何一个为O则返回值为1
		}
}
//在应用程序中直接调用此发送函数,但是操作比较麻烦所以可以使用以下CAN总线专用的printf函数



//CAN总线通信,使用CAN1,这是CAN专用的printf函数
//调用方法:CAN1_printf("123");//向CAN发送字符123
void CAN1_printf (char *fmt, ...)
{
	char buff[CAN1_REC_LEN+1]//用于存放转换后的数据[长度]
	uint16_t i=0;
	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	vsnprintf(buff,CAN1_REC_LEN+1,fmt, arg_ptr);//数据转换
	i=strlen(buff)//得出数据长度
	if(strlen(buff)>CAN1_REC_LEN)i=CAN1_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)
	CAN1_SendNorma1Data(&hcan1,CAN1_HOST_ID,(uint8_t *)buff,i);//CAN发送数据函数(ID为ex12)
	va_end(arg_ptr);
}

can.h

#include"../usart/usart.h"//因用到USART1_printf在级外媸显示CAN状态信息

extern CAN_HandleTypeDef hcanl;//产明的HAL岸结神体
CAN_TxHeaderTypeDef TXMeg;//CAN发送设置相关结构体
CAN_RxHeaderTypeDef RxMeg;//CAN接收说置相关结构体

#define CAN1_ID_H		0×0000//32位基础工D设置(高16位)
#define CAN1_ID_L		0×0000//32位基础ID设置(低16位)
#define CAN1_MASK_H		0×0000 //32位屏瓶MASK设置(高16位)
#define CAN1_MASK_L 	0×0000 //32位屏丽MASK设置(低16位)
#define CAN1_REC_LEN 	200//定义CAN1最大换收字节数
#define CANl_HOST_ID 	0x12//CAN总线本设备工D(只要不与其他设音冲突,可由由设置)

extern uint8_t CAN1_RX_BUF[CAN1_REC_LEN];//接收缓冲,最大CAN1_REC_LEN个字节.末字节为换行符
extern uint16_t CAN1_RX_STA;//接收状态标记

void CAN_User_Init(CAN_HandleTypeDef* hcan );//CAN用F初化面
void HAL_CAN_RxFifolMsgPendingCallback(CAN_HandleTypeDef+hcan);//CAN接收国我函就
uint8_t CAN1_SendNormalData(CAN_HandleTypeDef* hcan,uint16_t ID,uint8_t *pData,uint16_t Len);
void CAN1_printf(char *fmt,..);//CAN 通信.使用CAN1.这是CAN用的printf函数

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

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

相关文章

庖丁解牛:NIO核心概念与机制详解 04 _ 分散和聚集

文章目录 Pre概述分散/聚集 I/O分散/聚集的应用聚集写入Code Pre 庖丁解牛:NIO核心概念与机制详解 01 庖丁解牛:NIO核心概念与机制详解 02 _ 缓冲区的细节实现 庖丁解牛:NIO核心概念与机制详解 03 _ 缓冲区分配、包装和分片 概述 分散/聚…

C++二分查找算法:有序矩阵中的第 k 个最小数组和

本文涉及的基础知识点 二分查找算法合集 本题的简化 C二分查找算法:查找和最小的 K 对数字 十分接近m恒等于2 题目 给你一个 m * n 的矩阵 mat,以及一个整数 k ,矩阵中的每一行都以非递减的顺序排列。 你可以从每一行中选出 1 个元素形成…

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(3)

FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(3) 工程目的IIC时序图IIC 读写操作方法汇总正点原子IIC实验工程整体框图和模块功能简介,如表下图所示: IIC 驱动模块设计时钟规划状态跳转流程单次写操作的波形图如下图所示&…

程序员带你入门人工智能

随着人工智能技术的飞速发展,越来越多的程序员开始关注并学习人工智能。作为程序员,我们可能会对如何开始了解人工智能感到困惑。今天,我将向大家介绍一些如何通过自学了解人工智能的经验和方法,帮助大家更好地入门这个充满挑战和…

【Java集合】聊聊Hashmap的哈希函数、扩容、树化

哈希函数 hashmap是开发中常用的一个集合,除了一些基本的属性、put、get等流程,本篇文章主要介绍下哈希函数、扩容、树化的一些细节。 而hash函数就是hashmap的重中之重。 static final int hash(Object key) {int h;return (key null) ? 0 : (h key…

YOLOv8改进 | EIoU、SIoU、WIoU、DIoU、FoucsIOU等二十余种损失函数

一、本文介绍 这篇文章介绍了YOLOv8的重大改进,特别是在损失函数方面的创新。它不仅包括了多种IoU损失函数的改进和变体,如SIoU、WIoU、GIoU、DIoU、EIOU、CIoU,还融合了“Focus”思想,创造了一系列新的损失函数。这些组合形式的…

Halcon Solution Guide I basics(1): Guide to Halcon Methods(Halcon解决方案)

文章目录 文章专栏前言文章解读基础解决方案字符串格式化 文章专栏 Halcon开发 前言 今天来看Halcon的第一章内容,Halcon解决方案 文章解读 基础解决方案 Halcon大部分的应用都使用了三种常用的算子应用用于图像的预处理。 Image Acquisition:图像加…

6 Redis的慢查询配置

1、redis的命令执行流程 redis的慢查询只针对步骤3 默认情况下,慢查询的阈值是10ms 在配置文件中进行配置 //这个参数的单位为微秒 //如果将这个值设置为负数,则会禁用慢日志功能 //如果将其设置为0,则会强制记录每个命令 slowlog-log-slow…

[python]python筛选excel表格信息并保存到另一个excel

目录 关键词平台说明背景所需库1.安装相关库2.代码实现sourcetarget1 关键词 python、excel、DBC、openpyxl 平台说明 项目Valuepython版本3.6 背景 从一个excel表中遍历删选信息并保存到另一个excel表 所需库 1.openpyxl :是一个用于读写 Excel 文件的 Pyt…

2023.11.17 关于 Spring Boot 日志文件

目录 日志文件作用 常见的日志框架说明 门面模式 日志的使用 日志的级别 六种级别 日志级别的设置 日志的持久化 使用 Lombok 输出日志 实现原理 普通打印和日志的区别 日志文件作用 记录 错误日志 和 警告日志(发现和定位问题)记录 用户登录…

牛客::栈的压入、弹出序列

栈的压入、弹出序列 题目 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列&…

三、LED闪烁

通过LED的闪烁实验,详解Keil MDK中创建mm32单片机的工程的步骤。 1、开发环境 (1)Keil MDK: V5.38.0.0 (2)MCU: mm320163D7P。 2、Keil工程的创建 (1)打开Keil MDK。 (2)点击“Project”→“New μVision Project...”。 (3)选择工程保存地址及工程文件名&…

RE2文本匹配实战

引言 今天我们来实现RE2进行文本匹配,模型实现参考了官方代码https://github.com/alibaba-edu/simple-effective-text-matching-pytorch。 模型实现 RE2模型架构如上图所示。它的输入是两个文本片段,所有组件参数除了预测层和对齐层外都是共享的。上图…

变周期控制思路

举例&#xff1a;热值调节的过程中&#xff0c;调节周期在偏差较小时&#xff0c;可以设置较大些&#xff0c;调节周期在偏差较大时&#xff0c;可以设置较小些。并且在偏差较大时&#xff0c;立刻进入调节&#xff08;计时器清零&#xff09;。 -350<偏差<600&#xff0…

华为麒麟服务器--硬盘问题

记录以下今天处理的服务器&#xff1a; 情况说明&#xff1a;linux 系统&#xff0c;不知道什么原因系统就突然不能用了&#xff08;据说是前段时间断电来着&#xff0c;但是机房有应急电源&#xff09;。 系统环境&#xff1a; 服务器&#xff1a;华为RH2288H V3 服务器 服…

设计模式(二)-创建者模式(2-0)-简单工厂模式

一、简单工厂模式定义 客户端不需要关注创建实例的过程。于是需要通过工厂模式&#xff0c;要把创建对象过程和使用对象进行分离。所以客户端只要使用对象即可&#xff0c;而创建对象过程由一种类来负责&#xff0c;该类称为工厂类。 由于创建实例的方式是在静态方法里实现的…

文件钓鱼-后缀隐藏文件捆绑文件压缩释放技巧

0x00 文件钓鱼 简单说下文件样本钓鱼的目的&#xff0c;为诱导用户安装木马文件&#xff0c;达到控制或者窃取某些信息的目的&#xff0c;抛开邮件的真实性。木马的伪造是一个比较关键的点&#xff0c;下面简要说下三种木马文件伪装的技巧 0x01 水坑攻击与鱼叉攻击的概念 水坑…

VMware——WindowServer2012R2环境mysql5.7.14解压版安装主从复制(图解版)

目录 一、服务器信息二、192.168.132.33主服务器上安装mysql&#xff08;主&#xff09;2.1、环境变量配置2.2、安装2.2.1、修改配置文件内容2.2.2、初始化mysql并指定超级用户密码2.2.3、安装mysql服务2.2.4、启动mysql服务2.2.5、登录用户管理及密码修改2.2.6、开启远程访问 …

AD教程 (十九)PCB板框的评估和层叠设置

AD教程 &#xff08;十九&#xff09;PCB板框的评估和层叠设置 板子越小&#xff0c;层数越少&#xff0c;成本越低 PCB板框评估 器件摆放 CtrlA 选中全部器件点击工具&#xff0c;选择器件摆放&#xff0c;选择在矩形区域排列 框定矩形区域&#xff0c;器件就会摆放在框定的矩…

Unity Meta Quest 一体机开发(七):配置玩家 Hand Grab 功能

文章目录 &#x1f4d5;教程说明&#x1f4d5;玩家物体配置 Hand Grab Interactor⭐添加 Hand Grab Interactor 物体⭐激活 Hand Grab Visual 和 Hand Grab Glow⭐更新 Best Hover Interactor Group &#x1f4d5;配置可抓取物体&#xff08;无抓取手势&#xff09;⭐刚体和碰撞…
最新文章