STM32CubeMX生成代码学习笔记(四)CAN总线配置及无法进入接收中断问题(已解决)

1. 问题描述

按以下方式使用CubeMX配置STM32F103C8T6的CAN总线后,发送数据正常,接收则一直无法进入接收中断,先记录该问题于此,如日后解决会更新该文章。如有前辈在看过我的代码后能够发现我的问题,也很欢迎在评论区加以指正,感激不尽。

2.CAN配置

  1. CubeMX CAN波特率配置
    波特率配置为1Mhz,系统时钟为64M,APB1则为32M。
    在这里插入图片描述

  2. CAN其他配置
    在这里插入图片描述

  3. NVIC配置
    在这里插入图片描述

  4. 生成代码后打开源代码,在CAN.C中添加屏蔽器设置代码

CAN_RxPacketTypeDef CanRxPacket;
CAN_TxPacketTypeDef CanTxPacket;
void CAN_Filter_Config(void)
{
    CAN_FilterTypeDef sFilterConfig;
    CAN_FilterRegTypeDef IDH = {0};
    CAN_FilterRegTypeDef IDL = {0};

#if CAN_ID_TYPE_STD_ENABLE
    IDH.Sub.STID = (CAN_BASE_ID >> 16) & 0xFFFF;		// 标准ID高16位
    IDL.Sub.STID = (CAN_BASE_ID & 0xFFFF);				// 标准ID低16位
#else
    IDH.Sub.EXID = (CAN_BASE_ID >> 16) & 0xFFFF;		// 扩展ID高16位
    IDL.Sub.EXID = (CAN_BASE_ID & 0xFFFF);				// 扩展ID低16位
    IDL.Sub.IDE  = 1;									// 扩展帧标志位置位
#endif
    sFilterConfig.FilterBank           = 0;												// 设置过滤器组编号
#if CAN_FILTER_MODE_MASK_ENABLE
    sFilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;							// 屏蔽位模式
#else
    sFilterConfig.FilterMode           = CAN_FILTERMODE_IDLIST;							// 列表模式
#endif
    sFilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;							// 32位宽
    sFilterConfig.FilterIdHigh         = IDH.value;										// 标识符寄存器一ID高十六位,放入扩展帧位
    sFilterConfig.FilterIdLow          = IDL.value;										// 标识符寄存器一ID低十六位,放入扩展帧位
    sFilterConfig.FilterMaskIdHigh     = IDH.value;										// 标识符寄存器二ID高十六位,放入扩展帧位
    sFilterConfig.FilterMaskIdLow      = IDL.value;										// 标识符寄存器二ID低十六位,放入扩展帧位
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;								// 过滤器组关联到FIFO0
    sFilterConfig.FilterActivation     = ENABLE;										// 激活过滤器
    //sFilterConfig.SlaveStartFilterBank = 11;											// 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效
    if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
    {
        Error_Handler();
    }
}

CAN.H添加

typedef struct
{
	uint32_t mailbox;
	CAN_TxHeaderTypeDef hdr;
	uint8_t payload[8];
}CAN_TxPacketTypeDef;

typedef struct
{
	CAN_RxHeaderTypeDef hdr;
	uint8_t payload[8];
}CAN_RxPacketTypeDef;

extern	CAN_RxPacketTypeDef CanRxPacket;
extern CAN_TxPacketTypeDef CanTxPacket;
typedef union
{
    __IO uint32_t value;
    struct
    {
        uint8_t REV : 1;			//< [0]    
        uint8_t RTR : 1;			//< [1]     
        uint8_t IDE : 1;			//< [2]    
        uint32_t EXID : 18;			//< [21:3] 
        uint16_t STID : 11;			//< [31:22] 
    } Sub;
} CAN_FilterRegTypeDef;

#define CAN_BASE_ID 	0						
#define CAN_FILTER_MODE_MASK_ENABLE 1		 
#define CAN_ID_TYPE_STD_ENABLE      1       

#define CAN_Target_ID	0x01

extern uint8_t	CAN_TX_Sign;


void CAN_Init(void);
void CAN_SetTxPacket(uint16_t	Target_Id);
  1. 添加发送函数
uint8_t CAN_Transmit(CAN_TxPacketTypeDef* packet)
{
	if(HAL_CAN_AddTxMessage(&hcan, &packet->hdr, packet->payload, &packet->mailbox) != HAL_OK)
		return 1;
	return 0;
}
  1. 添加初始化代码
void CAN_Init(void)
{
	CAN_Filter_Config();
	HAL_CAN_Start(&hcan);
	HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);					// 使能CAN接收中断
}

将初始化代码加入main.c

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_TIM2_Init();
  MX_ADC1_Init();
  MX_I2C1_Init();
  MX_USART2_UART_Init();
  MX_USART1_UART_Init();
  MX_CAN_Init();
  /* USER CODE BEGIN 2 */
	CAN_Init();//CAN初始化
  1. 添加用户发送函数
void CAN_SetTxPacket(uint16_t	Target_Id)
{
	CanTxPacket.hdr.StdId = Target_Id;		// 标准ID
//	CanTxPacket.hdr.ExtId = 0x10F01234;		// 扩展ID
	CanTxPacket.hdr.IDE = CAN_ID_STD;			// 标准ID类型
//	CanTxPacket.hdr.IDE = CAN_ID_EXT;			// 扩展ID类型
	CanTxPacket.hdr.DLC = 8;					// 数据长度
	CanTxPacket.hdr.RTR = CAN_RTR_DATA;		// 数据�??
//	CanTxPacket.hdr.RTR = CAN_RTR_REMOTE;		// 远程�??
	CanTxPacket.hdr.TransmitGlobalTime = DISABLE;

	CAN_Transmit(&CanTxPacket);
}
  1. stm32f1xx_it.c中添加接收中断回传函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle)
{
	
    // CAN数据接收
    if (canHandle->Instance == CAN1)
    {
			if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &CanRxPacket.hdr, CanRxPacket.payload) == HAL_OK)		// 获得接收到的数据头和数据
			{
				if(!CAN_TX_Sign)
					CAN_TX_Sign	=	1;
				HAL_CAN_ActivateNotification(canHandle, CAN_IT_RX_FIFO0_MSG_PENDING);						// 再次使能FIFO0接收中断
      }
    }
}
  1. main.cwhile(1)中添加用户代码
/* USER CODE BEGIN 3 */
		if(CAN_TX_Sign)
		{
			CAN_SetTxPacket(0x102);
			CAN_TX_Sign	=	0;
		}
		HAL_Delay(10);
  }
  /* USER CODE END 3 */

3. 测试:

前期问题描述:调试时在HAL_CAN_IRQHandler(&hcan);处设置断点,用电脑通过CAN分析器发送数据,使用Jlink进行Debug未进入CAN的接收中断。使用单片机给电脑发送数据正常。

问题解决:重新查看了CAN的收发代码,在接收时HAL库函数是通过过滤ID来判断是否进入中断来接收数据的,因此接收时,只有指定正确的ID才能够进入中断。本机ID设置位置如下:
CAN.h

#define CAN_BASE_ID 	0						//< CAN标准ID,最大11位,也就是0x7FF

4.例程

整理了一下CAN总线收发的代码单独形成了一个例程,可直接测试使用
https://download.csdn.net/download/weixin_44087298/34875003
烧录方式:SWD,可在STM32_HAL_CAN.ioc中自行修改

  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

食熊鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值