STM32 CAN的HAL库简单使用

一、CAN的基本知识

1. 物理层

  1. 差分信号
  2. ISO11898标准:高速、短距离“闭环网络”,它的总线最大长度为40m,通信速度最高为1Mbps,总线的两端各要求有一个“120欧”的电阻。
  3. ISO11519-2标准:低速、远距离“开环网络”它的最大传输距离为1km,最高通讯速率为125kbps,两根总线是独立的、不形成闭环,要求每根总线上各串联有一个“2.2千欧”的电阻。
  4. 逻辑1时(隐性电平):CAN_High和CAN_Low线上的电压均为2.5v,即它们的电压差VH-VL=0V;
  5. 逻辑0时(显性电平):CAN_High的电平为3.5V,CAN_Low线的电平为1.5V,即它们的电压差为VH-VL=2V。

请添加图片描述
假如有两个CAN通讯节点,在同一时间,一个输出隐性电平,另一个输出显性电平,类似I2C总线的“线与”特性将使它处于显性电平状态,显性电平的名字就是这样来的。

2. 协议层

① 数据位格式
  1. CAN时钟的最小周期称为最小时间单元Time Quantum(Tq)
  2. 同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)和相位缓冲段2(PBS2)。每个段都占有数量不同的Tq,一个完整的bit,由8~25个Tq组成,除了SS段是固定的1Tq之外,其他的段占有Tq的数量都是可调的。
  3. 通过确定一个数据位的总Tq,可以计算波特率:
    例如:而每个数据位由19个Tq组成,波特率可得
    1 x 1 0 6 / 19 = 52631.6 ( b p s ) 1x10^6/19 = 52631.6 (bps) 1x106/19=52631.6(bps)
② STM32数据位格式

STM32的CAN外设,数据位格式与标准的略有不同,分为三段:
在这里插入图片描述
在STM32CubemX中波特率的计算,
Time Quanta in Bit Segment 1是位段1
Time Quanta in Bit Segment 2是位段2
在这里插入图片描述
按上图的配置计算波特率:
CAN总线在时钟树的APB1总线上,当前的总线频率为30MHz
经过10分频后,CAN的1Tq为大概为333.33ns
BS1段设置为1Tq,BS2段设置为4Tq,可得1bit的总时间为
SYNC(1)+ BS1(1) + BS2(4) = 6Tq
波特率为:
B a u d r a t e = 1 / 6 T q = 1 / ( 333.33 ∗ 6 ) = 1 / ( 1999 ) ≈ 499.99 K b i t / s Baudrate = 1/6Tq = 1/(333.33*6) = 1/(1999)≈499.99K bit/s Baudrate=1/6Tq=1/(333.336)=1/(1999)499.99Kbit/s

3. CAN 通信帧

  1. 帧种类
帧格式含义
数据帧用于节点向外传送数据
遥控帧用于向远端节点请求数据
错误帧用于向远端节点通知校验错误,请求重新发送上一个数据
过载帧用于通知远端节点:本节点尚未做好接收准备
帧间隔用于将数据帧及遥控帧与前面的帧分离开来
  1. 数据帧格式为:帧起始(SOF段一个显性位(逻辑0))、 仲裁段、控制段、数据段、CRC段、ACK段和帧结束(EOF段以7个连续的隐性位(逻辑1)结束)
    在这里插入图片描述3. 仲裁段: 内容为数据帧的CAN ID(标识符),数据帧具有标准格式和扩展格式两种
    标准格式的CAN的ID为11位、扩展帧格式为29位。
    当两个节点同时发送报文时,若首先出现隐性电平,则会失去对总线的占有权,进入接收状态,在CAN通信中0是显性电平,所以CAN的ID越小,其优先级越高。

二、STM的CAN使用

1. CAN 过滤器

参考链接:https://blog.youkuaiyun.com/qq_35480173/article/details/98878309

①两种过滤模式
模式优点缺点
列表模式能精确地过滤每个指定的CAN ID有数量限制
掩码模式取决于屏蔽码,有时无法完全精确到每一个CAN ID,部分不期望的CAN ID有时也会收到数量取决于屏蔽码,最多无上限
②过滤寄存器
  1. CAN_FM1R寄存器中的FBMx位:”0”表示掩码模式,”1”表示列表模式。
    下图的每一个位对应地表示这28个过滤器的工作模式
    在这里插入图片描述
  2. CAN_FS1R寄存器表示CAN ID的位宽:0:16位宽 1:32位宽
    在这里插入图片描述
  3. CAN_FxR1和CAN_FxR2 两个寄存器
    列表模式-16位宽模式下: 写入4个标准CAN ID
    列表模式-32位宽模式下: 写入2个CAN ID
    掩码模式-16位宽模式: 2对验证码+屏蔽码组合来用,但它只能对标准CAN ID进行过滤
    掩码模式-32位宽模式: CAN_FxR1用做32位宽的验证码,而CAN_FxR2则用作32位宽的屏蔽码
    注意:下面STID表示标准ID有11位,EXID为扩展ID有18位(扩展帧ID总共29位).
    然后是RTR,表示是否为远程帧(遥控帧)。IDE,表示扩展帧标识。

    在这里插入图片描述

2. CAN 初始化和配置

下面以常用的32位掩码模式为例解释CAN的初始化配置和过滤器配置

1. CAN初始化

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

/* CAN1 init function */
void MX_CAN1_Init(void)
{

  /* USER CODE BEGIN CAN1_Init 0 */

  /* USER CODE END CAN1_Init 0 */

  /* USER CODE BEGIN CAN1_Init 1 */

  /* USER CODE END CAN1_Init 1 */
  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 14;
  hcan1.Init.Mode = CAN_MODE_NORMAL;            //正常模式
  hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;       
  hcan1.Init.TimeSeg1 = CAN_BS1_4TQ;            //BS1时间段
  hcan1.Init.TimeSeg2 = CAN_BS2_1TQ;            //BS2时间段
  hcan1.Init.TimeTriggeredMode = DISABLE;
  hcan1.Init.AutoBusOff = ENABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = DISABLE;      //自动重发
  hcan1.Init.ReceiveFifoLocked = DISABLE;       
  hcan1.Init.TransmitFifoPriority = ENABLE;     //发送使用FIFO
  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }

  // 过滤只接收0x000018xx的CAN ID
  uint32_t mask = 0xffffff00;
	mask <<= 3;
	mask |= 0x02;   //设置只接受数据帧
  /* USER CODE BEGIN CAN1_Init 2 */
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;  //掩码模式
  sFilterConfig.FilterIdHigh = ((0x00001871 << 3) >> 16) & 0xffff;   //配置ID        
  sFilterConfig.FilterIdLow = ((0x00001871 << 3) & 0xffff) | CAN_ID_EXT;  //配置扩展帧
  sFilterConfig.FilterMaskIdHigh = (mask >> 16) & 0xffff;
  sFilterConfig.FilterMaskIdLow = (mask & 0xffff);         //配置掩码
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;      //32位宽度
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;  //FIFO0
  sFilterConfig.FilterBank = 0;                           //过滤器0
  sFilterConfig.SlaveStartFilterBank = 14;            //从属CAN2实例的起始过滤器库,单CAN没有用,
                                                      //过滤器Min_Data = 0 和最大值 Max_Data = 27 
  sFilterConfig.FilterActivation = ENABLE;
  if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
	  Error_Handler();
  }
  //使能FIFO接收中断
  if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
  {
	  Error_Handler();
  }
  /* USER CODE END CAN1_Init 2 */

}

void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(canHandle->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspInit 0 */

  /* USER CODE END CAN1_MspInit 0 */
    /* CAN1 clock enable */
    __HAL_RCC_CAN1_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**CAN1 GPIO Configuration
    PB8     ------> CAN1_RX
    PB9     ------> CAN1_TX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* CAN1 interrupt Init */
    HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
  /* USER CODE BEGIN CAN1_MspInit 1 */

  /* USER CODE END CAN1_MspInit 1 */
  }
}

2. CAN接收和发送
//CAN 接收回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	if(hcan->Instance == CAN1)
	{
		HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, rxdata);
	}
}
//CAN 发送函数
HAL_StatusTypeDef UserCan_Transmit(uint32_t Id, uint32_t IDE, uint32_t RTR, uint32_t DLC, uint8_t *data)
{
	CAN_TxHeaderTypeDef txHeader;
	txHeader.StdId = Id;	 
	txHeader.ExtId = Id;	 
	txHeader.IDE = IDE;//CAN_ID_STD;
	txHeader.RTR = RTR;//CAN_RTR_DATA;
	txHeader.DLC = DLC;//8;
	txHeader.TransmitGlobalTime = DISABLE;
	return HAL_CAN_AddTxMessage(&hcan1, &txHeader, data, &TxMailboxNumber);
}
### STM32 HAL CANFD 过滤器的配置 在STM32微控制器系列中,CAN FD(Controller Area Network with Flexible Data-rate)协议扩展了传统CAN总线的功能,允许更高的数据传输速率和更大的有效载荷。为了有效地管理接收到的数据帧并减少不必要的处理开销,在HAL中正确配置CAN FD过滤器至关重要。 #### 配置CAN FD过滤器的关键要素 对于基于HAL的应用程序来说,初始化结构体`CAN_FilterConfTypeDef`用于定义具体的筛选条件[^1]: ```c CAN_FilterConfTypeDef sFilterConfig; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 设置为标识符掩码模式 sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 使用32位宽度的过滤器组 sFilterConfig.FilterIdHigh = 0x0000 << 5; // 根据具体需求调整此值 sFilterConfig.FilterIdLow = 0x0000; // 同样依据实际应用设定 sFilterConfig.FilterMaskIdHigh = 0x0000 << 5; // 掩码高位部分 sFilterConfig.FilterMaskIdLow = 0x0000; // 掩码低位部分 sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 将匹配到的信息分配给指定队列 sFilterConfig.FilterActivation = ENABLE; // 开启该过滤规则 sFilterConfig.BankNumber = 14; // 指定使用的过滤银行号 ``` 上述代码片段展示了如何创建一个简单的过滤器实例来捕获特定范围内的标准格式消息。需要注意的是,当涉及到更复杂的场景时——比如支持多个不同的ID或是采用扩展格式的消息,则可能需要进一步定制这些参数以满足项目的特殊要求[^2]。 #### 初始化CAN外设并与过滤器关联 完成过滤器对象构建之后,下一步就是将其应用于相应的硬件资源之上,并启动整个接收流程: ```c if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK){ Error_Handler(); } // 启动CAN模块以及RX FIFO中断服务函数 if(HAL_CAN_Start(&hcan)!= HAL_OK || \ HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_RX_FIFO1_MSG_PENDING )!= HAL_OK ){ Error_Handler(); } ``` 这段C语言源代码负责激活之前所描述过的过滤机制,并开启必要的事件通知以便及时响应新到达的有效负载。值得注意的是,这里假设已经存在了一个名为`Error_Handler()`的方法用来处理任何可能出现的操作失败情况;同时也要确保在此之前完成了对全局变量`hcan`的相关成员属性赋值工作,例如波特率、操作模式等基本设置项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值