首页 > 解决方案 > 用CAN总线对STM32微控制器编程的问题

问题描述

我是 STM32 微控制器和 CAN 总线通信协议的新手,我正在编写 STM32F103xx 微控制器。我想使用 CAN 总线将数据传输到同一系列的另一个微控制器。

我设置了所有必要的设置,但是在调试代码时它卡在传输挂起函数中并且不传输。我希望传输数据,但事实并非如此。

我不相信我的硬件有问题。

PS:我已经尝试过 CAN 处理程序的正常模式和 LOOPBACK 模式,但它们都不起作用。

int main(void)
{
    HAL_Init();

    SystemClock_Config();

    uint32_t BUTTON_0;
    uint32_t BUTTON_1;

    uint8_t Data_0[5] = "aaaaa";
    uint8_t Data_1[5] = "ZZZZZ";

    MX_GPIO_Init();
    MX_CAN_Init();

    if(HAL_CAN_Init(&hcan) != HAL_OK){
        Error_Handler();
    }

    if(HAL_CAN_Start(&hcan) != HAL_OK){
        Error_Handler();
    }

    while (1)
    {       
        TxHeader.DLC   = 5;
        TxHeader.StdId = 0x65D;
        TxHeader.IDE   = CAN_ID_STD;
        TxHeader.RTR   = CAN_RTR_DATA;

        BUTTON_0 = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);

        BUTTON_1 = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);

        if (BUTTON_0 == 0U){

            if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, Data_0, &TxMailbox) != HAL_OK ){
                Error_Handler();
            }

        }

        if (BUTTON_1 == 0U){

            if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, Data_1, &TxMailbox) != HAL_OK){
                Error_Handler();
            }

        }

        while (HAL_CAN_IsTxMessagePending(&hcan, TxMailbox));

        if (BUTTON_0 && BUTTON_1 == 0U){
            printf("Please Press a Button");
        }
    }
}

标签: stm32can-busstm32f1stm32cubemx

解决方案


您正在使用 STM32CubeF1 HAL 库(可能通过 STM32CubeMX)。请查看相应的 用户手册 - 第 9.2.1 节推荐以下程序:

  1. 通过执行以下命令初始化 CAN 低级资源HAL_CAN_MspInit()
    • 使用启用 CAN 接口时钟__HAL_RCC_CANx_CLK_ENABLE()
    • 配置 CAN 引脚
      • 启用 CAN GPIO 的时钟
      • 将 CAN 引脚配置为备用功能开漏
    • 如果使用中断 [...]
  2. HAL_CAN_Init()使用函数初始化 CAN 外设。此函数诉诸HAL_CAN_MspInit()低级初始化。
  3. 使用以下配置函数配置接收过滤器:
    • HAL_CAN_ConfigFilter()
  4. HAL_CAN_Start()使用函数启动 CAN 模块。在这个级别,节点在总线上处于活动状态:它接收消息,并且可以发送消息。
  5. 要管理消息传输,可以使用以下 Tx 控制功能:
    • HAL_CAN_AddTxMessage()请求传输新消息。
    • [...]
    • HAL_CAN_IsTxMessagePending()检查 Tx 邮箱中是否有消息待处理。
    • [...]
  6. 当 CAN Rx FIFO 接收到消息时,可以使用该HAL_CAN_GetRxMessage()函数检索它。函数 HAL_CAN_GetRxFifoFillLevel() 允许知道有多少 Rx 消息存储在 Rx Fifo 中。
  7. 调用该HAL_CAN_Stop()函数会停止 CAN 模块。
  8. 去初始化是通过HAL_CAN_DeInit()函数来​​实现的。

[...]

轮询模式操作/传输:

  • 使用 . 监控 Tx 邮箱的可用性,直到至少有一个 Tx 邮箱空闲HAL_CAN_GetTxMailboxesFreeLevel()
  • 然后使用 请求传输消息HAL_CAN_AddTxMessage()

您的代码示例没有显示从中调用的子函数,main()因此您必须检查自己:-)

  • CAN/GPIO 时钟在分配相应寄存器之前已启用。
  • GPIO 引脚按照推荐配置。

另一个想法 - 是不是你必须HAL_CAN_GetTxMailboxesFreeLevel()在启动 CAN 后检查,甚至在添加第一条消息进行传输之前?

步骤 (2.)、(4.)、(5.) 已由您的代码处理,步骤 (3.)、(6.)、(7.)、(8.) 与您的代码无关问题(但仅限于接收/ deinit)。


如果您不想自己完成所有手动工作,也可以使用以下工具之一作为起点。这两种工具都远非完美(我们的一些 StackOverflow 同行根本不同意推荐它们),但它们通常已经提供了包含您需要的大多数相关步骤的基本结构:


推荐阅读