STM32-CAN配置与库函数解析,实现环回模式通信

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

STM32-CAN配置与库函数解析

CAN总线介绍:https://blog.csdn.net/weixin_46251230/article/details/129147612

STM32-CAN控制器介绍:https://blog.csdn.net/weixin_46251230/article/details/129150872

STM32CubeMx配置

因为bxCAN是挂载在APB1总线上的,所以设置APB1总线的时钟为36M

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

选择CAN接口进行配置

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

勾选主CAN模式,这里并不是主机的意思

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

配置位时间参数

根据STM32参考手册里位时间特性的介绍,来配置最小时间单位Tq

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

在位时间参数里可以配置分频系数,这个系数没有下拉列表,需要自己写,APB1 36MHz时钟来到这里经过分频再给后面使用,根据实际通信速度来配置,例如可以设置为4分频,那36MHz/4 = 9MHz

同步段因为固定为1个时间单元,所以不用配置

根据采样点最好在一个位的50% ~ 80%位置采样,所以时间段1可以配置长一点,其范围为1到16个时间单元,这里可根据下拉列表选择11个时间单元

时间段2的设置就要注意不要让总和超过最大Tq数,因为同步段+时间段1+时间段2的Tq数范围是8 ~ 25个,不过配置工具已经把参数规定好了,所以不用担心超出的问题,这里可以设置为6个时间单元,则会自动计算出一个位占用的时间(Time for one Bit)为2000ns

计算过程

36MHz/4 = 9MHz,因为同步段(1个Tq)+时间段1(11个Tq)+时间段2(6个Tq)=18个Tq

所以 9MHz/18 = 0.5MHz,即每一个Tq的频率就是0.5MHz,转为时间就为 1/0.5MHz = 1/500000Hz = 0.000002s = 2us = 2000ns

而2000ns的速率就是500KHz

重新同步跳跃宽度(SJW)可设置范围是1 ~ 4个时间单元,这里可以选择2

配置基础参数

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

接收FIFO锁定模式:选择Enable(锁定)时,当接收FIFO满时,新接收到的报文就丢弃,软件可以读到FIFO中最早收到的3个报文。

​ 选择Disable(不锁定)时,那么FIFO中最后收到的报文就被新报文所覆盖。这样,最新收到的报文不会被丢弃掉。

发送FIFO优先级:未使能就按邮箱序号进行发送

配置工作模式

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

正常模式就需要两个或更多的实验板来进行通信

环回模式就只使用一个实验板就可以测试通信

本次实验使用环回模式

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

NVIC中断配置

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

CAN发送使用轮询的方式,接收就用RX0中断方式

GPIO配置

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

因为CAN收发器的STB接到了单片机的PC13引脚,所以将PC13配置为推挽输出模式

stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线

上面配置完就可以生成Keil工程进行代码编写

生成的CAN初始化函数如下:

void MX_CAN_Init(void)
{
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = 4;
  hcan.Init.Mode = CAN_MODE_LOOPBACK;
  hcan.Init.SyncJumpWidth = CAN_SJW_2TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_11TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_6TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = DISABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = DISABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  hcan.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    Error_Handler();
  }
}

CAN使用到的库函数介绍

1、配置过滤器

CAN_FilterTypeDef结构体就是过滤器的一些参数设置

HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig);

2、发送数据

CAN_TxHeaderTypeDef结构体是对发送报文进行组帧,aData数组存放着要发送的数据,pTxMailbox指针是返回控制器使用了哪个邮箱进行发送

HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox);

3、中止发送请求

HAL_StatusTypeDef HAL_CAN_AbortTxRequest(CAN_HandleTypeDef *hcan, uint32_t TxMailboxes);

4、获取空邮箱的个数

uint32_t HAL_CAN_GetTxMailboxesFreeLevel(CAN_HandleTypeDef *hcan);

5、接收数据

RxFifo指定用于接收报文的FIFO缓存,CAN_RxHeaderTypeDef结构体定义接收报文的格式,aData数组存放接收到的报文

HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[]);

6、获取接收FIFO满的个数

uint32_t HAL_CAN_GetRxFifoFillLevel(CAN_HandleTypeDef *hcan, uint32_t RxFifo);

CAN通信实现(环回模式)

CAN.h

进行宏定义,定义结构体类型

//发送接收状态宏定义
#define CAN_SEND_OK     0
#define CAN_SEND_FAIL   1

#define CAN_REC_OK      0
#define CAN_REC_FAIL    1

//定义结构体类型
typedef struct
{
    uint32_t uiOperate_Mode;        //操作模式
    uint8_t ucRec_Flag;             //接收标志位
    uint8_t ucSend_Buf[8];          //发送缓存
    uint8_t ucRec_Buf[8];           //接收缓存

    void (*CAN_Init)(void);
    void (*CAN_Config)(void);
    uint8_t (*CAN_Send_Msg)(uint8_t* pSend_Buf,uint8_t LEN);
    uint8_t (*CAN_Rec_Msg)(uint8_t* pRec_Buf);

}CAN_Test_T;

/* extern variables-----------------------------------------------------------*/
extern CAN_Test_T CAN_Test;

CAN.c

配置过滤器并启动CAN

/**
 * @name   CAN_Config
 * @brief  CAN配置
 * @param  None
 * @retval None   
 */
static void CAN_Config(void)
{
    //CAN过滤器参数配置
    CAN_FilterTypeDef CAN_FilterTypeDefSture;

    CAN_FilterTypeDefSture.FilterBank  = 0;                             //配置过滤器0(F1共有14个,0-13)
    CAN_FilterTypeDefSture.FilterScale = CAN_FILTERSCALE_16BIT;         //配置为16位过滤器
    CAN_FilterTypeDefSture.FilterMode  = CAN_FILTERMODE_IDMASK;         //屏蔽位模式
    //ID号为0x00,屏蔽位为0x00,说明任何ID都接收
    CAN_FilterTypeDefSture.FilterIdLow      = 0x00;                     //FR1
    CAN_FilterTypeDefSture.FilterMaskIdLow  = 0x00;
    CAN_FilterTypeDefSture.FilterIdHigh     = 0x00;                     //FR2
    CAN_FilterTypeDefSture.FilterMaskIdHigh = 0x00;   
    CAN_FilterTypeDefSture.FilterFIFOAssignment = CAN_FILTER_FIFO0;     //过滤器0关联到FIFO0
    CAN_FilterTypeDefSture.FilterActivation = ENABLE;                   //激活过滤器0
    CAN_FilterTypeDefSture.SlaveStartFilterBank = 14;

    //启动过滤器
    if(HAL_CAN_ConfigFilter(&hcan,&CAN_FilterTypeDefSture) != HAL_OK)
    {
      printf("CAN配置过滤器成功!");
      System.Error_Handler();
    }

    //使能FIFO0接收到一个新报文中断,具体为FIFO0的挂起中断
    if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
    {
      printf("CAN使能FIFO0接收到一个新报文中断");
      System.Error_Handler();
    }

    //启动CAN
    if(HAL_CAN_Start(&hcan) != HAL_OK)
    {
      printf("CAN启动失败!");
      System.Error_Handler();
    }

    printf("配置成功,CAN成功启动!\r\n");
}

CAN发送报文,可在主函数中调用

/**
 * @name   CAN_Send_Msg
 * @brief  CAN发送信息
 * @param  pSend_Buf:发送缓存指针
 *          LEN:发送报文长度
 * @retval CAN_SEND_OK:发送成功
 *          CAN_SEND_FAIL:发送失败
 */
static uint8_t CAN_Send_Msg(uint8_t* pSend_Buf,uint8_t LEN)
{
  uint8_t i = 0;
  static uint8_t ucTestData = 0;
  uint32_t uiTxMailBox;           //接收CAN发送数据成功时返回的邮箱号(0-2)

  //定义CAN TX消息头参数
  CAN_TxHeaderTypeDef CAN_TxHeaderTypeDefStrue = 
  {
    0x88,           //标准标识符-11位
    0x00,           //拓展标识符-29位
    CAN_ID_STD,     //设置为标准格式
    CAN_RTR_DATA,   //设置为数据帧
    8,              //发送数据的长度 0 ~ 8
    DISABLE         //不使用捕获时间戳计数器
  };

  //判断工作模式
  if(CAN_Test.uiOperate_Mode == CAN_MODE_LOOPBACK)
  {
    printf("\r\nCAN工作在环回模式,使用一块实验板来测试\r\n");
  }
  else
  {
    printf("\r\nCAN工作在正常模式,需要两块以上的实验板才能测试\r\n");
  }

  //设置要发送的报文
  printf("CAN要发送的报文如下:\r\n");
  for(i=0;i<8;i++)
  {
    printf("%#.2x ",ucTestData);
    CAN_Test.ucSend_Buf[i] = ucTestData++;
  }
  printf("\r\n");

  //将消息添加到第一个空闲的Tx邮箱并激活相应的传输要求
  if(HAL_CAN_AddTxMessage(&hcan,&CAN_TxHeaderTypeDefStrue,pSend_Buf,&uiTxMailBox) != HAL_OK)
  {
    return CAN_SEND_FAIL;
  }

  //通过检查空闲邮箱个数确认是否发送完成
  Timer6.usDelay_Timer = 0;
  do
  {
    //超时处理
    if(Timer6.usDelay_Timer >= TIMER_1s)
    {
      printf("CAN发送超时\r\n");
      return CAN_SEND_FAIL;
    }
  } while (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3); //如果3个发送邮箱都不是空闲的话,就说明数据还在发送
  
  //发送成功
  return CAN_SEND_OK;
}

CallBack.c

重写FIFO0挂起中断,接收CAN消息

因为是环回模式,所以主函数中发送的数据会被中断接收,通过HAL_CAN_GetRxMessage函数放到CAN_Test.ucRec_Buf缓存中

/**
 * @name   HAL_CAN_RxFifo0MsgPendingCallback
 * @brief  CAN接收FIFO0 挂起中断
 * @param  *_hcan:CAN结构体指针
 * @retval None   
 */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan_)
{
  //定义CAN Rx消息头参数
  CAN_RxHeaderTypeDef CAN_RxHeaderTypeDefStrue;

  //CAN接收消息
  if(HAL_CAN_GetRxMessage(&hcan,CAN_RX_FIFO0,&CAN_RxHeaderTypeDefStrue,CAN_Test.ucRec_Buf) == HAL_OK)
  {
    CAN_Test.ucRec_Flag = TRUE;
  }
  LED.LED_Fun(LED3,LED_Flip);
}

System.c

主函数中,判断触摸按键1是否按下,是则发送一次数据,通过接收标志位判断中断是否已经完成数据接收,是则打印出数据

/**
 * @name   Run
 * @brief  系统运行
 * @param  None
 * @retval None   
 */
static void Run()
{
  //计数
  static uint16_t usCAN_Send_OK_Cnt = 0;
  static uint16_t usCAN_Send_Fail_Cnt = 0;
  static uint16_t usCAN_Rec_OK_Cnt = 0;

  //发送数据
  if(KEY1.KEY_Flag == TRUE)
  {
    KEY1.KEY_Flag = FALSE;

    //发送
    if(CAN_Test.CAN_Send_Msg(CAN_Test.ucSend_Buf,8) == CAN_SEND_OK)
    {
      printf("CAN发送数据成功次数:%u\r\n",++usCAN_Send_OK_Cnt);
    }
    else
    {
      printf("CAN发送数据失败次数:%u\r\n",++usCAN_Send_Fail_Cnt);
    }
  }

  //接收数据
  if(CAN_Test.ucRec_Flag == TRUE)
  {
    CAN_Test.ucRec_Flag = FALSE;
    printf("CAN接收数据成功次数:%u\r\n",++usCAN_Rec_OK_Cnt);
    //打印接收到的数据
    CAN_Test.CAN_Rec_Msg(CAN_Test.ucRec_Buf); 
  }
}

实验结果

每触摸一次按键,就成功发送一次数据,并成功接收一次数据
stm32 can标准库,STM32物联网项目,stm32,单片机,嵌入式硬件,CAN总线文章来源地址https://www.toymoban.com/news/detail-783539.html

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

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

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

相关文章

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

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

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

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

    2024年01月21日
    浏览(42)
  • STM32 CAN通讯滤波器几种模式的设置

    1. 32位过滤器-标识符屏蔽模式(一组筛选ID)  2. 32位过滤器-标识符列表模式(2个筛选ID)  3. 16位过滤器-标识符屏蔽模式(2组筛选ID)  4. 16位过滤器-标识符列表模式(4个筛选ID)  1. 32位过滤器-标识符屏蔽模式(一组筛选ID) 2. 32位过滤器-标识符列表模式(2个筛选ID)  

    2024年02月13日
    浏览(37)
  • STM32 CAN快速配置(HAL库版本)

    控制器局域网总线(CAN,Controller Area Network)是一种用于实时应用的串行通讯协议总线,它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。CAN协议用于汽车中各种不同元件之间的通信,以此取代昂贵而笨重的配电线束。该协议的健壮性使其用途延伸到其他

    2024年02月09日
    浏览(32)
  • 野火STM32电机系列(三)Cubemx配置CAN通信

    CAN接口: PI9 PB9 1.配置CAN 通信参数 由于F4的 CAN外设挂载在APB1上,时钟配置后APB1的时钟速率为42MHz,目标通信速率为1000KHz,由公式: BaudRate = 1/NominalBitTime NominalBitTime = 1tq + tBS1 +tBS2 设置参数如下: CAN时钟分频参数为7,BS1为4,BS2为1,CAN模式为Nomal模式。 生成工程 在can.c中添加

    2024年02月11日
    浏览(48)
  • STM32 CAN/CANFD软件快速配置(HAL库版本)

    控制器局域网总线(CAN,Controller Area Network)是一种用于实时应用的串行通讯协议总线,它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。CAN协议用于汽车中各种不同元件之间的通信,以此取代昂贵而笨重的配电线束。该协议的健壮性使其用途延伸到其他

    2024年02月09日
    浏览(40)
  • 【STM32】CAN过滤器配置----接收特定ID发来的数据

    滤波器详细配置 (slave_id为只接收的id号): 1、对扩展数据帧进行过滤:(只接收扩展数据帧) 2、对扩展远程帧过滤:(只接收扩展远程帧) 3、对标准远程帧过滤:(只接收标准远程帧) 4、对标准数据帧过滤:(只接收标准数据帧) 5、对扩展帧进行过滤:(只接收扩展帧) 6、对标准帧进行

    2024年02月12日
    浏览(51)
  • STM32F4 CAN驱动配置,以及SEG1,SEG2的最佳配置

    平台:MDK5 单片机型号:STM32F407VG HAL库版本:V1.8.1 该程序在APB1时钟为42M速率的情况下,将CAN配置为500KBps. 通过SystemClock_Config函数,将主频配置为168M(最大),APB1为42M(最大)。CAN的波特率=42M/(1 + TimeSeg1 + TimeSeg2) = 42M/(1+12+8)=500Kbps。 先附上参考链接 https://blog.csdn.net/qfmzhu/article/det

    2024年02月09日
    浏览(36)
  • STM32+收发器实现CAN和485总线

    RS485总线是一种常见的(Recommended Standard)串行总线标准(485是它的标识号),采用平衡发送与差分接收的方式,因此具有抑制共模干扰的能力。CAN是控制器局域网络(Controller Area Network, CAN)的简称,是一种能够实现分布式实时控制的串行通信网络,属于CSMA(多路载波侦听)/CD(冲突检测

    2024年02月05日
    浏览(52)
  • STM32实现UART-CAN融合式高速串口

    STM32的UART硬件电路,在进行线接传输时,一般低于230400bps的波特率,因为单端信号传输的特性,限制了传输距离和传输速度。而在同一块PCB板內进行短距离UART传输,则可以达到2Mbps及至4Mbps的传输速率,所以STM32的UART接口,能支持配置为2M或4M波特率。 如果要实现接线方式的串

    2024年02月04日
    浏览(69)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包