STM32的CAN通信的收发库函数解读

这篇具有很好参考价值的文章主要介绍了STM32的CAN通信的收发库函数解读。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STM32的CAN通信的收发函数:

// 发送函数
uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage);

// 接收函数
void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage);

CAN发送消息结构体定义:

typedef struct {
    uint32_t StdId;  /* 存储报文的标准标识符11位,0-0x7FF. */
    uint32_t ExtId;  /* 存储报文的扩展标识符29位,0-0x1FFFFFFF. */
                     /* ExtId与StdId这两个成员根据IDE位配置,只有一个是有效的。*/
    uint8_t IDE;     /* 存储IDE扩展标志 */
                     /* 当它的值为宏CAN_ID_STD时表示本报文是标准帧,使用StdId成员存储报文ID; 
                        当它的值为宏CAN_ID_EXT时表示本报文是扩展帧,使用ExtId成员存储报文ID。*/
    uint8_t RTR;     /* 存储RTR远程帧标志*/
                     /* 当它的值为宏CAN_RTR_Data时表示本报文是数据帧;
                        当它的值为宏CAN_RTR_Remote时表示本报文是遥控帧, 
                        由于遥控帧没有数据段,所以当报文是遥控帧时,下面的Data[8]成员的内容是无效的。*/
    uint8_t DLC;     /* 存储报文数据段的长度,0-8, 当报文是遥控帧时DLC值为0。 */
    uint8_t Data[8]; /* 存储报文数据段的内容 */
} CanTxMsg;

       当需要使用CAN发送报文时,先定义一个上面发送类型的结构体,然后把报文的内容按成员赋值到该结构体中,最后调用库函数CAN_Transmit把这些内容写入到发送邮箱即可把报文发送出去。 

CAN接收消息结构体定义:

typedef struct {
    uint32_t StdId;  /* 存储了报文的标准标识符11位,0-0x7FF. */
    uint32_t ExtId;  /* 存储了报文的扩展标识符29位,0-0x1FFFFFFF. */
                     /* ExtId与StdId这两个成员根据IDE位配置,只有一个是有效的。*/
    uint8_t IDE;     /* 存储了IDE扩展标志 */
                     /* 当它的值为宏CAN_ID_STD时表示本报文是标准帧,使用StdId成员存储报文ID; 
                        当它的值为宏CAN_ID_EXT时表示本报文是扩展帧,使用ExtId成员存储报文ID。*/
    uint8_t RTR;     /* 存储了RTR远程帧标志*/
                     /* 当它的值为宏CAN_RTR_Data时表示本报文是数据帧;
                        当它的值为宏CAN_RTR_Remote时表示本报文是遥控帧, 
                        由于遥控帧没有数据段,所以当报文是遥控帧时,下面的Data[8]成员的内容是无效的。*/
    uint8_t DLC;     /* 存储报文数据段的长度,0-8, 当报文是遥控帧时DLC值为0。 */
    uint8_t Data[8]; /* 存储了报文数据段的内容 */
    uint8_t FMI;     /* 存储了筛选器的编号,表示本报文是经过哪个筛选器存储进接收FIFO的,可以用它简化软件处理,0-0xFF */
} CanRxMsg;

CAN发送消息函数:

/**
 * @brief  Initiates the transmission of a message.
 * @param  CANx:      where x can be 1 or 2 to to select the CAN peripheral.
 * @param  TxMessage: pointer to a structure which contains CAN Id, CAN
 *                    DLC and CAN data.
 * @retval The number of the mailbox that is used for transmission
 *                    or CAN_TxStatus_NoMailBox if there is no empty mailbox.
 */
uint8_t CAN_Transmit(CAN_TypeDef *CANx, CanTxMsg *TxMessage)
{
  uint8_t transmit_mailbox = 0;
  /* 参数检查 */
  assert_param(IS_CAN_ALL_PERIPH(CANx));       // 检查CANx是否是有效的CAN接口
  assert_param(IS_CAN_IDTYPE(TxMessage->IDE)); // 检查TxMessage中的IDE是否是有效的标识符类型
  assert_param(IS_CAN_RTR(TxMessage->RTR));    // 检查TxMessage中的RTR是否是有效的标识符类型
  assert_param(IS_CAN_DLC(TxMessage->DLC));    // 检查TxMessage中的DLC是否是有效的标识符类型

  /* 选择一个空的发送邮箱 */
  /*逐个检查发送邮箱是否为空,为空则记录邮箱号,否则检查下一个;
  如果所有邮箱都非空,则给邮箱号赋值CAN_TxStatus_NoMailBox,表示没有非空邮箱*/
  if ((CANx->TSR & CAN_TSR_TME0) == CAN_TSR_TME0)
  {
    transmit_mailbox = 0;
  }
  else if ((CANx->TSR & CAN_TSR_TME1) == CAN_TSR_TME1)
  {
    transmit_mailbox = 1;
  }
  else if ((CANx->TSR & CAN_TSR_TME2) == CAN_TSR_TME2)
  {
    transmit_mailbox = 2;
  }
  else
  {
    transmit_mailbox = CAN_TxStatus_NoMailBox;
  }

  /*如果存在空邮箱,开始设置发送消息结构体*/
  if (transmit_mailbox != CAN_TxStatus_NoMailBox)
  {
    /* 设置消息的标识符 */
    CANx->sTxMailBox[transmit_mailbox].TIR &= TMIDxR_TXRQ; // 清除发送邮箱的发送标志位,为了确保在消息设置完毕之前不会意外地发送出去
    if (TxMessage->IDE == CAN_Id_Standard)                 // 检查IDE,分辨要发送的消息的类型(标准帧和扩展帧)
    {
      /*要发送的消息是标准帧*/
      assert_param(IS_CAN_STDID(TxMessage->StdId)); // 检查标准帧的有效性
      // 将标准标识符的值左移21位,并与RTR进行或操作,然后设置到对应的传输邮箱的TIR寄存器中
      CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->StdId << 21) |
                                                 TxMessage->RTR);
    }
    else
    {
      /*要发送的消息是扩展帧*/
      assert_param(IS_CAN_EXTID(TxMessage->ExtId)); // 检查扩展帧的有效性
      // 将扩展标识符的值左移3位,并与IDE、RTR进行或操作,然后设置到对应的传输邮箱的TIR寄存器中
      CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) |
                                                 TxMessage->IDE |
                                                 TxMessage->RTR);
    }

    /* 设置消息的数据长度 */
    /*对数据长度进行处理和设置,确保传输邮箱的 TDTR 寄存器的数据长度字段与消息的数据长度一致。*/
    /* 通过与操作,将 TxMessage->DLC 的高 4 位全部清零,只保留低 4 位的值。
       确保 DLC 的值不超过 4 位的掩码。*/
    TxMessage->DLC &= (uint8_t)0x0000000F; 
    /* 保留 TDTR 寄存器的高 28 位,将低 4 位设置为 0,
       清除传输邮箱中 TDTR 寄存器(数据长度寄存器)的低 4 位。*/                          
    CANx->sTxMailBox[transmit_mailbox].TDTR &= (uint32_t)0xFFFFFFF0;
    /* 将 DLC 的值设置给传输邮箱的 TDTR 寄存器。
       通过或操作,将上述清除低 4 位值的 TDTR 寄存器与消息的数据长度(经过掩码操作后的 TxMessage->DLC)进行或操作,
       将 DLC 的值写入到 TDTR 寄存器的低 4 位中,完成数据长度的设置。*/ 
    CANx->sTxMailBox[transmit_mailbox].TDTR |= TxMessage->DLC;       

    /* 设置消息的数据内容 */
    /*将数据的高4位和低4位分别设置到对应的传输邮箱的TDLR和TDHR寄存器中。
      函数通过位操作将数据字节按照大端字节序进行转换,使得数据在传输时按照正确的顺序排列*/
    CANx->sTxMailBox[transmit_mailbox].TDLR = (((uint32_t)TxMessage->Data[3] << 24) |
                                               ((uint32_t)TxMessage->Data[2] << 16) |
                                               ((uint32_t)TxMessage->Data[1] << 8) |
                                               ((uint32_t)TxMessage->Data[0]));
    CANx->sTxMailBox[transmit_mailbox].TDHR = (((uint32_t)TxMessage->Data[7] << 24) |
                                               ((uint32_t)TxMessage->Data[6] << 16) |
                                               ((uint32_t)TxMessage->Data[5] << 8) |
                                               ((uint32_t)TxMessage->Data[4]));
    /* 置位发送邮箱的发送标志位,请求发送 */
    CANx->sTxMailBox[transmit_mailbox].TIR |= TMIDxR_TXRQ;
  }
  /*函数返回所使用的传输邮箱的编号,如果没有空闲的传输邮箱可用,则返回CAN_TxStatus_NoMailBox*/
  return transmit_mailbox;
}

CAN接收消息函数:文章来源地址https://www.toymoban.com/news/detail-729794.html

/**
 * @brief  Receives a message.
 * @param  CANx:       where x can be 1 or 2 to to select the CAN peripheral.
 * @param  FIFONumber: Receive FIFO number, CAN_FIFO0 or CAN_FIFO1.
 * @param  RxMessage:  pointer to a structure receive message which contains
 *                     CAN Id, CAN DLC, CAN datas and FMI number.
 * @retval None.
 */
void CAN_Receive(CAN_TypeDef *CANx, uint8_t FIFONumber, CanRxMsg *RxMessage)
{
  /* 参数检查 */
  assert_param(IS_CAN_ALL_PERIPH(CANx)); // 检查CANx是否为有效的CAN接口
  assert_param(IS_CAN_FIFO(FIFONumber)); // 检查FIFONumber是否为有效的FIFO编号
  /* 标识符检测 */
  // 获取接收到报文的IDE
  RxMessage->IDE = (uint8_t)0x04 & CANx->sFIFOMailBox[FIFONumber].RIR;
  if (RxMessage->IDE == CAN_Id_Standard) // 判断是否是标准帧
  {
    // 获取标准帧的标准ID
    RxMessage->StdId = (uint32_t)0x000007FF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 21);
  }
  else // 接收到的是扩展帧
  {
    // 获取扩展帧的扩展ID
    RxMessage->ExtId = (uint32_t)0x1FFFFFFF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 3);
  }

  // 获取远程帧标志位
  RxMessage->RTR = (uint8_t)0x02 & CANx->sFIFOMailBox[FIFONumber].RIR;
  // 获取数据位长度
  RxMessage->DLC = (uint8_t)0x0F & CANx->sFIFOMailBox[FIFONumber].RDTR;
  // 获取筛选器编号
  RxMessage->FMI = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDTR >> 8);
  // 获取数据内容
  RxMessage->Data[0] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDLR;
  RxMessage->Data[1] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 8);
  RxMessage->Data[2] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 16);
  RxMessage->Data[3] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 24);
  RxMessage->Data[4] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDHR;
  RxMessage->Data[5] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 8);
  RxMessage->Data[6] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 16);
  RxMessage->Data[7] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 24);
  /* 释放接收FIFO */
  /* 释放FIFO0 */
  if (FIFONumber == CAN_FIFO0)
  {
    CANx->RF0R |= CAN_RF0R_RFOM0;
  }
  /* 释放FIFO1 */
  else /* FIFONumber == CAN_FIFO1 */
  {
    CANx->RF1R |= CAN_RF1R_RFOM1;
  }
}

到了这里,关于STM32的CAN通信的收发库函数解读的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • stm32f407单片机上通过HAL库实现can总线数据的收发

      最近在使用can总线,由于这个以前接触的比较少,所以调试代码的时候直接是下载的正点原子的例程,在这个基础上修改调试的。现在将调试中遇到的问题,总结一下,避免以后踩坑。目前写了一个查询方式的,一个中断方式的。项目代码下载地址: https://download.csdn.n

    2024年02月09日
    浏览(37)
  • stm32毕设 单片机与GSM的手机短信收发系统(源码+论文)

    Hi,大家好,这里是丹成学长,今天向大家介绍一个 单片机项目 毕业设计 单片机与GSM的手机短信收发系统(源码+论文) 大家可用于 课程设计 或 毕业设计 🧿 项目分享:见文末! 使用单片机控制GSM,首先:单片机下载完程序后,先不要接GSM,先让单片机和电脑通信,利用串口

    2024年04月25日
    浏览(25)
  • STM32——CAN通信

    STM32F103有两个CAN,都分别有自己的发送接收邮箱。 发送邮箱共有3个来发送报文,发送调度器根据优先级决定哪个邮箱的报文先被发送。 共有2个接收FIFO,每个FIFO都可以存放3个完整的报文。它们完全由硬件来管理。 CAN通信通过CAN_H、CAN_L两根线实现通信,电平特性分为显性电

    2024年02月08日
    浏览(36)
  • STM32—CAN通信

    🎀 文章作者:二土电子 🌸 关注文末公众号获取其他资料和工程文件! 🐸 期待大家一起学习交流! CAN全称是Controller Area Network,控制器局域网络,是ISO国际标准化的串行通信协议。CAN是国际上应用最广泛的现场总线之一。CAN通信只有两根信号线,分别是CAN_H和CAN_L,CAN 控制

    2024年02月16日
    浏览(31)
  • STM32CubeMX+STM32F407+FreeRTos+LAN8720 以太网通信实现数据收发功能

    目录 前言 一、STM32CubeMX配置 二、修改代码 三、硬件测试 总结 该工程应用的以太网芯片是LAN8720,代码是基于STM32CUbeMx6.2.1配置生成的,在CubeMx中配置了ETH和LWIP,还有串口1和FREERTOS,最后通过创建任务函数实现udp的以太网数据收发功能。在测试中,可以在电脑的DOS窗口ping通在

    2024年02月08日
    浏览(48)
  • 【STM32】STM32F103C8T6串口通信,实现3个串口收发数据

    串口通信(Serial Communications)实现单片机与电脑或者其它外设进行通信,通信时只需两根线(TX,RX)就可以实现数据传输。STM32f103有三个串口,分别为串口1(RX PA10, TX PA 9),串口2(RX PA3,TX PA2),串口3(RX PB11,TX PB10)。 以下代码是配置三个串口: usart.c usart.h main.c 注意,

    2024年02月12日
    浏览(36)
  • 【零基础 STM32通过CAN通信驱动Maxon电机】第三章 STM32 CAN通信回环模式测试及Maxon电机通信

    第三章 STM32 CAN通信回环模式测试及Maxon电机通信 正点原子官方给的CAN通信例程需要lcd显示屏和两块板子,本章修改代码,仅用一块STM32进行回环模式的测试。 首先下载修改后的程序,运行并烧录(接线方式和运行方式与上一章完全相同)。注意板子右侧的接线帽要接正确,

    2024年01月21日
    浏览(31)
  • CAN总线详解及STM32的CAN通信编程指南

    对于CAN通信而言,本人之前也未接触了解过,由于实习的技术要求,因此也花费了一段时间对CAN通信进行学习,并且实现了基于STM32的CAN环回静默模式通信,因此写一遍比较详细的文章对该内容进行总结。本文的参考资料有STM32的中文参考手册、协议手册等。话不多说开始吧!

    2024年02月11日
    浏览(27)
  • 入门stm32:STM32hal库实现ESP8266与手机通信(不定长数据收发和ESP8266使用的一些问题)

    目录 前言 一、stm32cubeMX的串口配置 二、空闲中断+dma接收 三、ESP8266.c和ESP8266.h ESP8266.h ESP8266.c 注意事项 四、与手机通信例程 步骤:  例程代码main.c 运行结果 五、相关问题 总结 相关的app和源码         前提: 1.掌握串口通信和ESP8266的使用方法 串口通信:单片机串口通信

    2024年02月04日
    浏览(60)
  • STM32进阶学习(6)-通信协议之CAN详解

    CAN通信的背景可以追溯到上世纪80年代初,当时汽车制造商面临着一个共同的挑战: 如何有效地传输和共享大量的传感器数据和控制信息 。 传统的电缆布线方式非常复杂且容易出错,而且无法满足日益增长的数据传输需求。 为了解决这个问题,德国的汽车制造商奔驰(Mer

    2024年02月03日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包