STM32 HAL库 CAN通讯相关设定

这两天去面试,突然问我CAN的相关功能,但是做过一次早就忘记了,正好用HAL库重新做一遍,留下个记忆。

正常配置引脚,配置功能。

第一栏是配置时钟的,通过配置能设置波特率(主要功能,里面具体的TQ方面请自行查找),因为我的总线是42MHz的,直接分频42,这样TQ就是整数,方便设置波特率。因为低速和高速CAN的速率区分线就是125K,这样设置成125K可以同时应用在两种不同总线情况下(可以后续改)。最后一个是补偿机制的,相当于一个可设定频率的可调带宽滤波器,可以类比成系口袋的绳,越大容错越高,但是风险也越大(意外的杂波)。

第二栏是CAN总线的一些功能。第一个是时间戳,使能就能用时间戳;第二个是自动离线管理,当发送或接收错误超过一定值就离线了;第三个是自动唤醒,低功耗用的;第四个是报文自动重传,当发送失败了就一直发送到成功;第五个是FIFO锁,使能后满了就不收后边的报文,关闭就会覆盖原来的报文;第六个是报文发送优先级的功能,这个是配置邮箱中多个未发送报文的以ID的优先级发送还是以存进来的顺序发送。这栏功能根据自己的需求选,个人认为时间戳、自动离线、自动重传这三个作用比较大,我选择这三个启用。

第三栏是模式选择,CAN总线有正常模式、环回模式、静默模式和环回静默模式。正常模式不说了,环回是TX可以发到自己的RX上,RX接收不到外边的报文,用来自测试数据发送的。静默是只能接收,发送隐性位,像是做CAN分析仪的在监控的时候就可以用这个模式。环回静默就相当于两个都结合一下,对外只能发隐性位,自己发送的自己能接收,不能接收外部的报文。这几个功能取决于产品用途和调试阶段吧。

中断有四个,TX一般不用,自己看情况使用;RX0 RX1取决于用了那个FIFO,用0就勾0,用1就勾1;SCE是错误中断,自己发着玩没啥问题,实际产品肯定要在这里做功能的。

CAN.C里要去配置一下,默认生成的没有过滤器的设置,所以自己建一下,建ID和mask,内容要根据实际的来,看是标准帧还是扩展帧,还有掩码相关的部分也要自己配置。

#define CAN1_ID_H 0X0000
#define CAN1_ID_L 0X0000
#define CAN1_MASK_H 0X0000
#define CAN1_MASK_L 0X0000

void MX_CAN1_Init(void)
{
  /* USER CODE BEGIN CAN1_Init 0 */
  CAN_FilterTypeDef  CAN1_sFilterConfig;  //建立一个CAN1的配置结构体
  /* USER CODE END CAN1_Init 0 */

  /* USER CODE BEGIN CAN1_Init 1 */

  /* USER CODE END CAN1_Init 1 */
  hcan1.Instance = CAN1;
  hcan1.Init.Prescaler = 42;
  hcan1.Init.Mode = CAN_MODE_NORMAL;
  hcan1.Init.SyncJumpWidth = CAN_SJW_2TQ;
  hcan1.Init.TimeSeg1 = CAN_BS1_3TQ;
  hcan1.Init.TimeSeg2 = CAN_BS2_4TQ;
  hcan1.Init.TimeTriggeredMode = ENABLE;
  hcan1.Init.AutoBusOff = ENABLE;
  hcan1.Init.AutoWakeUp = DISABLE;
  hcan1.Init.AutoRetransmission = ENABLE;
  hcan1.Init.ReceiveFifoLocked = DISABLE;
  hcan1.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN CAN1_Init 2 */
  /*过滤器配置*/
  CAN1_sFilterConfig.FilterIdHigh = CAN1_ID_H;  //ID设置
  CAN1_sFilterConfig.FilterIdLow = CAN1_ID_L;
  CAN1_sFilterConfig.FilterMaskIdHigh = CAN1_MASK_H;//掩码设置
  CAN1_sFilterConfig.FilterMaskIdLow = CAN1_MASK_L;
  CAN1_sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;//选择的FIFO,这个和中断有关系
  CAN1_sFilterConfig.FilterBank = 0;//从0到13,共14个给1用
  CAN1_sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;//这个还有个list 那个是完全符合的过滤
  CAN1_sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  CAN1_sFilterConfig.FilterActivation = ENABLE;
  CAN1_sFilterConfig.SlaveStartFilterBank = 14;//共14个
  while(HAL_CAN_ConfigFilter(&hcan1, &CAN1_sFilterConfig)!=HAL_OK);//配置函数
  while(HAL_CAN_Start(&hcan1)!= HAL_OK);//can开始
  while(HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING)!=HAL_OK);//can中断
  /* USER CODE END CAN1_Init 2 */

}

#define CAN2_ID_H 0X0000
#define CAN2_ID_L 0X0000
#define CAN2_MASK_H 0X0000
#define CAN2_MASK_L 0X0000

void MX_CAN2_Init(void)
{

  /* USER CODE BEGIN CAN2_Init 0 */
  CAN_FilterTypeDef  CAN2_sFilterConfig;
  /* USER CODE END CAN2_Init 0 */

  /* USER CODE BEGIN CAN2_Init 1 */

  /* USER CODE END CAN2_Init 1 */
  hcan2.Instance = CAN2;
  hcan2.Init.Prescaler = 42;
  hcan2.Init.Mode = CAN_MODE_NORMAL;
  hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan2.Init.TimeSeg1 = CAN_BS1_3TQ;
  hcan2.Init.TimeSeg2 = CAN_BS2_4TQ;
  hcan2.Init.TimeTriggeredMode = DISABLE;
  hcan2.Init.AutoBusOff = DISABLE;
  hcan2.Init.AutoWakeUp = DISABLE;
  hcan2.Init.AutoRetransmission = DISABLE;
  hcan2.Init.ReceiveFifoLocked = DISABLE;
  hcan2.Init.TransmitFifoPriority = DISABLE;
  if (HAL_CAN_Init(&hcan2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN CAN2_Init 2 */
  /*过滤器配置*/
  CAN2_sFilterConfig.FilterIdHigh = CAN2_ID_H;
  CAN2_sFilterConfig.FilterIdLow = CAN2_ID_L;
  CAN2_sFilterConfig.FilterMaskIdHigh = CAN2_MASK_H;
  CAN2_sFilterConfig.FilterMaskIdLow = CAN2_MASK_L;
  CAN2_sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO1;//这个用的fifo1
  CAN2_sFilterConfig.FilterBank = 14;//上边是0-13 这个是14到27
  CAN2_sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  CAN2_sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  CAN2_sFilterConfig.FilterActivation = ENABLE;
  CAN2_sFilterConfig.SlaveStartFilterBank = 14;
  while(HAL_CAN_ConfigFilter(&hcan2, &CAN2_sFilterConfig)!=HAL_OK);
  while(HAL_CAN_Start(&hcan2)!= HAL_OK);
  while(HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO1_MSG_PENDING)!=HAL_OK);
  /* USER CODE END CAN2_Init 2 */

}

里面有注释,两个都配一下,至此配置结束。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32HAL库提供了一些函数和宏定义,用于配置和操作CAN总线。下面是一些基本的步骤: 1. 启用CAN时钟:在使用CAN之前,需要先启用CAN时钟。可以使用“__HAL_RCC_CANx_CLK_ENABLE()”函数启用CAN时钟,其中“x”是使用的CAN端口号。 2. 配置CAN总线:使用“hcan.Init”结构体配置CAN总线。可以设置CAN的工作模式、传输速率、过滤器等参数。然后使用“HAL_CAN_Init()”函数初始化CAN总线。 3. 配置CAN消息:使用“CanTxMsg”和“CanRxMsg”结构体配置CAN消息。可以设置CAN消息的ID、长度、数据等参数。 4. 发送CAN消息:使用“HAL_CAN_Transmit()”函数发送CAN消息。需要提供CAN总线句柄和CAN消息结构体。 5. 接收CAN消息:使用“HAL_CAN_Receive()”函数接收CAN消息。需要提供CAN总线句柄和CAN消息结构体。 下面是一个简单的示例代码,演示了如何使用STM32HAL库进行CAN通讯: ```c #include "stm32f1xx_hal.h" #include "main.h" CAN_HandleTypeDef hcan; void SystemClock_Config(void); int main(void) { HAL_Init(); SystemClock_Config(); __HAL_RCC_CAN1_CLK_ENABLE(); hcan.Instance = CAN1; hcan.Init.Mode = CAN_MODE_NORMAL; hcan.Init.AutoBusOff = ENABLE; hcan.Init.AutoRetransmission = ENABLE; hcan.Init.AutoWakeUp = DISABLE; hcan.Init.ReceiveFifoLocked = DISABLE; hcan.Init.TimeTriggeredMode = DISABLE; hcan.Init.TransmitFifoPriority = DISABLE; hcan.Init.Prescaler = 4; hcan.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan.Init.TimeSeg1 = CAN_BS1_13TQ; hcan.Init.TimeSeg2 = CAN_BS2_2TQ; HAL_CAN_Init(&hcan); CAN_TxHeaderTypeDef txHeader; txHeader.StdId = 0x123; txHeader.RTR = CAN_RTR_DATA; txHeader.IDE = CAN_ID_STD; txHeader.DLC = 8; uint8_t txData[8] = {0, 1, 2, 3, 4, 5, 6, 7}; uint32_t txMailbox; HAL_CAN_AddTxMessage(&hcan, &txHeader, txData, &txMailbox); CAN_RxHeaderTypeDef rxHeader; uint8_t rxData[8]; HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &rxHeader, rxData); while (1) { } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } ``` 这个示例代码初始化了CAN1总线,并发送了一个长度为8个字节的CAN消息。在主循环中,程序将会一直阻塞,等待接收到CAN消息。需要注意的是,这只是一个简单的示例,实际应用中需要根据具体的需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值