STM32F407单片机HAL库CAN2不能接收数据解决方法

这篇具有很好参考价值的文章主要介绍了STM32F407单片机HAL库CAN2不能接收数据解决方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  最近在使用stm32F407的片子调试can通信,直接在正点原子的代码上修改调试,调试can1的时候,基本没啥问题,收发都正常,使用查询模式和中断模式都可以。但是当修改到can2的时候,可以正常发送数据,但是中断函数始终进不去。折腾了一两个小时终于搞定了。下面将解决过程分享给大家。

  首先先上代码,这个代码是运行成功的代码,在后面我再详细介绍要注意的地方。

CAN_HandleTypeDef   g_canx_handler;     /* CANx句柄 */
CAN_TxHeaderTypeDef g_canx_txheader;    /* 发送参数句柄 */
CAN_RxHeaderTypeDef g_canx_rxheader;    /* 接收参数句柄 */
CAN_DATA_TypeDef    g_can_rx_data;      /* CAN接收数据句柄 */
CAN_DATA_TypeDef    g_can_tx_data;      /* CAN发送数据句柄 */

uint8_t can_init( uint32_t tsjw, uint32_t tbs2, uint32_t tbs1, uint16_t brp, uint32_t mode )
{
    g_canx_handler.Instance = CANx;                    /* 使用CAN1/CAN2 */
    g_canx_handler.Init.Prescaler = brp;                /* 分频系数(Fdiv)为brp+1 
    g_canx_handler.Init.Mode = mode;                    /* 模式设置 */
    g_canx_handler.Init.SyncJumpWidth = tsjw;           /* 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ */
    g_canx_handler.Init.TimeSeg1 = tbs1;                /* tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ */
    g_canx_handler.Init.TimeSeg2 = tbs2;                /* tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ */
    g_canx_handler.Init.TimeTriggeredMode = DISABLE;    /* 非时间触发通信模式 */
    g_canx_handler.Init.AutoBusOff = DISABLE;           /* 软件自动离线管理 */
    g_canx_handler.Init.AutoWakeUp = DISABLE;           /* 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位) */
    //报文自动传送开启后,当数据发送失败时,can芯片会自动重发数据,直到数据发送成功,会造成程序假死状态。
    g_canx_handler.Init.AutoRetransmission = DISABLE;    /* 禁止报文自动传送 */
    g_canx_handler.Init.ReceiveFifoLocked = DISABLE;    /* 报文不锁锁定,FIFO装满后新的覆盖旧的,如果设置报文锁定后,FIFO装满后新的就会被丢弃*/
    g_canx_handler.Init.TransmitFifoPriority = DISABLE; /* 优先级由报文标识符决定 */
    if ( HAL_CAN_Init( &g_canx_handler ) != HAL_OK )
    {
        return 1;
    }    
    /* 使用中断接收 */
    __HAL_CAN_ENABLE_IT( &g_canx_handler, CAN_IT_RX_FIFO0_MSG_PENDING ); /* FIFO0消息挂号中断允许 */
    HAL_NVIC_EnableIRQ( CANx_RX0_IRQn );                        /* 使能CAN中断 */
    HAL_NVIC_SetPriority( CANx_RX0_IRQn, 7, 0 );                /* 抢占优先级7,子优先级0 */  

    CAN_FilterTypeDef sFilterConfig;
    sFilterConfig.FilterBank = FILTER_ADDR;                   /* 过滤器地址  当只使用CAN1时,此地址范围为0--13,,当使用CAN2时,CAN1也会工作,相当于CAN2就是从机 */
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x0000;                      /* 32位ID */
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;                  /* 32位MASK */
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;    /* 过滤器0关联到FIFO0 */
    sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;       /* 激活滤波器0 */
    sFilterConfig.SlaveStartFilterBank = FILTER_ADDR;         /* 从机滤波器起始地址,当只使用can1时,没有从机 此值无效*/

    /* 过滤器配置 */
    if ( HAL_CAN_ConfigFilter( &g_canx_handler, &sFilterConfig ) != HAL_OK )
    {
        return 2;
    }
    /* 启动CAN外围设备 */
    if ( HAL_CAN_Start( &g_canx_handler ) != HAL_OK )
    {
        return 3;
    }
    return 0;
}

void HAL_CAN_MspInit( CAN_HandleTypeDef* hcan )
{
    if ( CANx == hcan->Instance )       /* 如果地址为CANx 的地址 */
    {        
        CAN_RX_GPIO_CLK_ENABLE();       /* CAN_RX脚时钟使能 */
        CAN_TX_GPIO_CLK_ENABLE();       /* CAN_TX脚时钟使能 */     
        CANx_CLK_ENABLE();              /* 使能CAN时钟 */        

        GPIO_InitTypeDef gpio_init_struct;
        gpio_init_struct.Pin = CAN_TX_GPIO_PIN;
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;
        gpio_init_struct.Pull = GPIO_PULLUP;
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
        gpio_init_struct.Alternate = GPIO_AF9_CANx;
        HAL_GPIO_Init( CAN_TX_GPIO_PORT, &gpio_init_struct ); /* CAN_TX脚 模式设置 */
        gpio_init_struct.Pin = CAN_RX_GPIO_PIN;       
        HAL_GPIO_Init( CAN_RX_GPIO_PORT, &gpio_init_struct ); /* CAN_RX脚 模式设置 */
    }
}
void CANx_RX0_IRQHandler( void )
{
    HAL_CAN_IRQHandler( &g_canx_handler );      /* 调用HAL库 CAN 中断入口函数*/
}
void  HAL_CAN_RxFifo0MsgPendingCallback( CAN_HandleTypeDef* hcan )
{
    HAL_CAN_GetRxMessage( hcan, CAN_RX_FIFO0, &g_canx_rxheader, g_can_rx_data.buf );  /* 读取数据 */
}

  下面是头文件

//#define USE_CAN1        1               /* 使用can1口,如果要使用can2,将此宏定义屏蔽 */

#ifdef USE_CAN1
/* CAN1 引脚 定义 */
#define CAN_RX_GPIO_PORT                GPIOD
#define CAN_RX_GPIO_PIN                 GPIO_PIN_0
#define CAN_RX_GPIO_CLK_ENABLE()        do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0)     /* PD口时钟使能 */

#define CAN_TX_GPIO_PORT                GPIOD
#define CAN_TX_GPIO_PIN                 GPIO_PIN_1
#define CAN_TX_GPIO_CLK_ENABLE()        do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0)     /* PD口时钟使能 */

#define CANx                            CAN1
#define CANx_RX0_IRQn                   CAN1_RX0_IRQn
#define CANx_CLK_ENABLE()               __HAL_RCC_CAN1_CLK_ENABLE()
#define CANx_RX0_IRQHandler             CAN1_RX0_IRQHandler
#define GPIO_AF9_CANx                   GPIO_AF9_CAN1

#define FILTER_ADDR                     0                                               /* 滤波器地址 */

#else

/* CAN2 引脚 定义 */
#define CAN_RX_GPIO_PORT                GPIOB
#define CAN_RX_GPIO_PIN                 GPIO_PIN_5
#define CAN_RX_GPIO_CLK_ENABLE()        do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)     /* PB口时钟使能 */

#define CAN_TX_GPIO_PORT                GPIOB
#define CAN_TX_GPIO_PIN                 GPIO_PIN_6
#define CAN_TX_GPIO_CLK_ENABLE()        do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)     /* PB口时钟使能 */

#define CANx                            CAN2
#define CANx_RX0_IRQn                   CAN2_RX0_IRQn
#define CANx_CLK_ENABLE()               __HAL_RCC_CAN1_CLK_ENABLE(); __HAL_RCC_CAN2_CLK_ENABLE()
#define CANx_RX0_IRQHandler             CAN2_RX0_IRQHandler
#define GPIO_AF9_CANx                   GPIO_AF9_CAN2

#define FILTER_ADDR                     14                                               /* 滤波器地址 */
#endif

  这里通过一个宏定义来控制使用can1还是can2.
hal库can接收中断,STM32学习笔记,软件技巧,C语言学习笔记,can2,数据,407,中断,hal
  为了方便代码的编写,在头文件中将can1和can2配置时需要改动的地方都用宏定义来表示,这样切换can1和can2的时候,程序中的代码就不需要改动了。

  can1和can2最大的区别首先就是 IO口不一样,can1使用的是PD0、PD1,can2使用的是PB5,、PB6,接下来不一样的就是中断源和中断函数入口。下面就就是can的时钟,这里要注意一个就是使用can1的时候,开启can1的时钟就行,但是使用can2的时候,也必须开启can1的时钟。大多数can2调试不通的原因就是这个。
hal库can接收中断,STM32学习笔记,软件技巧,C语言学习笔记,can2,数据,407,中断,hal
  在can的控制器中,存储访问控制器是由can1控制的,当使用can2的时候,can2要访问存储访问控制器时,必须通过can1才能访问,所以使用can2的时候,can1为主机,can2为从机。所以使用can2时,时钟使能的宏定义是将can1和can2的的时钟都开启的。

#define CANx_CLK_ENABLE()  __HAL_RCC_CAN1_CLK_ENABLE(); __HAL_RCC_CAN2_CLK_ENABLE()

  正常情况下,使用can2时,只需要开启can1的时钟,就能使用了,但是实际测试的时候发现,can2只能发送数据,不能接收数据。最后查找了找了半天原因才发现是滤波器地址选择引起的。
hal库can接收中断,STM32学习笔记,软件技巧,C语言学习笔记,can2,数据,407,中断,hal
  这个是正点原子默认的过滤器配置值。关于这两个值的含义可以直接在代码中看官方的解释。
hal库can接收中断,STM32学习笔记,软件技巧,C语言学习笔记,can2,数据,407,中断,hal
  通过注释大概可以知道当使用一个can时FilterBank的值范围是0–13,当使用双路时它的范围是0–27。当使用一个can时 SlaveStartFilterBank的值是没意义的,当使用双路时它的值是0–27。

  看了这个解释之后其实还是不知道具体啥意思,是怎么用的。通过我实际测试之后,我对这两个值的理解如下:

  1.当只使用can1时,FilterBank的值必须在0到13之间,一旦这个值大于13,那么can1就不能进入接收中断。 SlaveStartFilterBank这个值在使用can1时,系统内部是忽略这个值的。不管设置多少就可以,无所谓。

  2.当使用can2时,由于can2读取数据需要依赖can1,所以要使用can2,就必须要使用can1,那么此时就是两路can,此时FilterBank的值用来设置过滤器的地址,这个值从0到27都可以。接下来 SlaveStartFilterBank的值就很关键了,这个值的含义是,从机滤波器的起始地址,那么当使用can2时,can2就是从机,那么这个值就是can2滤波器的起始地址,而上面FilterBank这个值是要使用的滤波器地址。 这里要注意的是,SlaveStartFilterBank的值一定要小于等于FilterBank的值。也就是滤波器起始地址一定要比要使用的滤波器地址小。

  如果按照上面代码中的设置,那么滤波器的地址设置为0,滤波器的起始地址设置为14,那么can2从滤波器起始地址14开始查找数据,它永远也找不到0号滤波器,所以就接收不到数据。

  就是因为这两个值的原因,导致使用can2的时候,一直收不到数据。为了写代码时方便一点,这里直接将这两个值设置为一样的。滤波器起始地址和要使用的滤波器地址一样,这样不管怎么设置都不会错。
hal库can接收中断,STM32学习笔记,软件技巧,C语言学习笔记,can2,数据,407,中断,hal
  在头文件中直接用宏定义设置这个值,由于使用can1的时候,值不能超过13,所以can1的值直接设置为0。当使用can2的时候,直接将值设置为14。

  这个滤波器的值设置好之后,can2使用起来就正常了。希望这个小小的坑大家都不要踩。为了一个地址值,折腾了好几个小时。文章来源地址https://www.toymoban.com/news/detail-598143.html

到了这里,关于STM32F407单片机HAL库CAN2不能接收数据解决方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 6、单片机与AT24C02的通讯(IIC)实验(STM32F407)

    IIC简介 I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS公司开发用于连接微控制器及其外围设备。 它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。 IIC是半双工通信方式。 多主机

    2024年02月20日
    浏览(57)
  • 在Proteus中添加元件库所没有的单片机芯片(STM32F407ZGT6为例)

    今天在画仿真图时发现proteus元件库里的stm32系列并没有我所需要的。通过百度才到了官网下载相应的元件,后自己导入到元件库! 1、官网链接为:https://componentsearchengine.com/part-view/STM32F407ZGT6/STMicroelectronics 先注册账号后下载相应的元件即可。 2、解压元件的压缩包 3、打开p

    2024年02月16日
    浏览(47)
  • STM32F407ZGT6单片机连接ST_LINK和USB转TTL的接线方法+舵机接线方法

    目录 1.STM32F407ZG单片机连接ST_LINK 2.STM32F407ZG单片机连接USB转TTL(用于串口通信) 3  舵机 单片机             ST_LINK      9--------------------6      7--------------------2      20------------------3/4      1--------------------7/8  这里附上具体的接线图片: 单片机      USB转TTL TX————

    2024年02月02日
    浏览(44)
  • STM32F407单片机通用24CXXX读写程序(KEIL),兼容24C系列存储器(24C01到24C512),支持存储器任意地址跨页连续读写多个页

    原文链接:https://blog.csdn.net/ba_wang_mao/article/details/108318633 AT24C01,AT24C02,AT24C04,AT24C08,AT24C16,AT24C32,AT24C64,AT24C128,AT24C256…不同的xxx代表不同的容量。 总容量(Byte容量) = 页数 × 页内字节单元数。 对AT24CXXX进行读写操作时,都得先访问存储地址、比如AT24C01写一个字节的I

    2024年04月11日
    浏览(53)
  • STM32F407 CAN模块发送接收数据异常

    现象: 1、CAN模块初始化成CAN_MODE_LOOPBACK模式 CAN模块通过HAL_CAN_AddTxMessage发送数据时,TX管脚能够发出数据,示波器也可以测量到数据波形,CAN使用中断接收HAL_CAN_ActivateNotification或者查询接收HAL_CAN_GetRxMessage都可以接收到正确的数据(和发送的数据一致),但是CAN接口却没有波

    2024年02月12日
    浏览(33)
  • 【STM32F407 ADC+DMA采集压力变送器数据(HAL库)】

    之前项目中需要对麦克传感器的mpm480隔爆压力变送器(4-20ma输出)的数据进行实时采集,使用STM32F407作为控制器,使用信号转换模块将压力变送器4-20ma的输出转换为0-3.3v的信号量,输入到STM32F407板子的ADC1的通道10,并使用DMA2通道0数据流0将采集的多个值从外设直接存入存储器

    2024年02月16日
    浏览(56)
  • 单片机:STM32F4x HAL库软硬SPI驱动ST7735s 1.8寸LCD屏幕

    说明:此篇为学习记录。可能存在错误或者不足。如有问题请指出。 主控芯片:STM32F411CEU6 主控开发板:WeAct STM32F411CEU6最小系统板 TFT-LCD屏幕:合宙1.8寸TFT-LCD,驱动为ST7735s MDK版本:5,32 HAL库版本:1.27.1 STM32CubeMX版本:6.7.0 ST7735s支持8080并口,3线和4线串行接口,模块的驱动方

    2024年02月03日
    浏览(50)
  • 基于stm32F407的hal库,移植FreeRTOS的具体步骤和遇到的问题(看正点原子的视频)

    因为板子是stm32F407的第二版的,所以开始下的资料是旧版本的,但是旧版本的FreeRTOS工程没有hal库的,都是标准库的,这里是下载stm32F407最新版的资料,进行移植。 资料可以在正点原子官网下载,如下: http://www.openedv.com/docs/boards/stm32/index.html 一定要下载最新的资料(开始用

    2024年02月06日
    浏览(72)
  • 从STM32F407到AT32F407(一)

    雅特力公司的MCU有着性能超群,价格优越的巨大优势,缺点是相关资料少一些,我们可以充分利用ST的现有资源来开发它。 我用雅特力的STM32F437开发板,使用原子 stm32f407的开发板自带程序,测试串口程序,原设定串口波特率为115200,但是输出乱码,波特率改成230400,串口输

    2024年02月02日
    浏览(50)
  • STM32F407的介绍

    内核 32位 高性能ARM Cortex-M4处理器 时钟: 高达168MHz,实际还可以超频一点点 stm32f407的主频通过PLL倍频后能够达到168MHz,而且芯片内置一个16MHz的晶振和一个32KHz的晶振,可以满足不同功耗的需求。 支持FPU(浮点运算)和DSP指令 144引脚 114个IO口 存储器容量: 1024K FLASH, 192K

    2024年02月10日
    浏览(42)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包