【笔记】使用RT-Thread Studio配置STM32F429实现CAN收发

RT-Thread版本:4.1.0

RT-Thread Studio版本:2.2.8

开发板:正点原子阿波罗F429IGT6

踩了两天的坑终于爬出来了,不得不说RTT的can驱动做的真是一言难尽,程序源码会放在最后,免费下载,不要钱的,如果对您有帮助请点赞收藏,话不多说直接开始。

目录

创建工程

RT-Thread studio配置

board.h新增CAN宏定义

CubeMX配置

基础配置

CAN配置

增加can_test.c

细节修改

将CubeMX生成的can.c加入构建

修改RT-Thread源码的两处代码

drv_can.c修改

drivers\can.h修改

下载验证

可能出现的错误以及解决办法

开启can设备出错:

解决办法一:

解决办法二:

解决办法三:

写入失败

解决办法一:

解决办法二:

结束


创建工程

RT-Thread studio配置

ctrl+S保存,关闭rtt setting

board.h新增CAN宏定义

注意,关于CAN的宏定义在board.h里是找不到的,所以需要自己添加,位置无所谓。

/*-------------------------- CAN CONFIG BEGIN --------------------------*/

#define BSP_USING_CAN
#define BSP_USING_CAN1
/*#define BSP_USING_CAN2*/

/*-------------------------- CAN CONFIG END --------------------------*/

CubeMX配置

基础配置

不多解释

CAN配置

打开就行,不需要做任何其他修改。

默认引脚不对,要根据原理图修改,429的分别是PA11 PA12

最后,每个外设生成独立的.c/.h文件,这一步很重要,后边要用!!!

生成,退出CubeMX。

增加can_test.c

添加官方测试代码

CAN设备 (rt-thread.org)

/*
 * 程序清单:这是一个 CAN 设备使用例程
 * 例程导出了 can_sample 命令到控制终端
 * 命令调用格式:can_sample can1
 * 命令解释:命令第二个参数是要使用的 CAN 设备名称,为空则使用默认的 CAN 设备
 * 程序功能:通过 CAN 设备发送一帧,并创建一个线程接收数据然后打印输出。
*/

#include <rtthread.h>
#include "rtdevice.h"

#define CAN_DEV_NAME       "can1"      /* CAN 设备名称 */

static struct rt_semaphore rx_sem;     /* 用于接收消息的信号量 */
static rt_device_t can_dev;            /* CAN 设备句柄 */

/* 接收数据回调函数 */
static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
{
    /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
    rt_sem_release(&rx_sem);

    return RT_EOK;
}

static void can_rx_thread(void *parameter)
{
    int i;
    rt_err_t res;
    struct rt_can_msg rxmsg = {0};

    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(can_dev, can_rx_call);

#ifdef RT_CAN_USING_HDR
    struct rt_can_filter_item items[5] =
    {
        RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr 为 - 1,设置默认过滤表 */
        RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr 为 - 1 */
        RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr 为 - 1 */
        RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  /* std,match ID:0x486,hdr 为 - 1 */
        {0x555, 0, 0, 0, 0x7ff, 7,}                                       /* std,match ID:0x555,hdr 为 7,指定设置 7 号过滤表 */
    };
    struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有 5 个过滤表 */
    /* 设置硬件过滤表 */
    res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
    RT_ASSERT(res == RT_EOK);
#endif

    while (1)
    {
        /* hdr 值为 - 1,表示直接从 uselist 链表读取数据 */
        rxmsg.hdr = -1;
        /* 阻塞等待接收信号量 */
        rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        /* 从 CAN 读取一帧数据 */
        rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));
        /* 打印数据 ID 及内容 */
        rt_kprintf("ID:%x", rxmsg.id);
        for (i = 0; i < 8; i++)
        {
            rt_kprintf("%2x", rxmsg.data[i]);
        }

        rt_kprintf("\n");
    }
}

int can_sample(int argc, char *argv[])
{
    struct rt_can_msg msg = {0};
    rt_err_t res;
    rt_size_t  size;
    rt_thread_t thread;
    char can_name[RT_NAME_MAX];

    if (argc == 2)
    {
        rt_strncpy(can_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
    }
    /* 查找 CAN 设备 */
    can_dev = rt_device_find(can_name);
    if (!can_dev)
    {
        rt_kprintf("find %s failed!\n", can_name);
        return RT_ERROR;
    }

    /* 初始化 CAN 接收信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);

    /* 以中断接收及发送方式打开 CAN 设备 */
    res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
    RT_ASSERT(res == RT_EOK);
    /* 创建数据接收线程 */
    thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        rt_kprintf("create can_rx thread failed!\n");
    }

    msg.id = 0x78;              /* ID 为 0x78 */
    msg.ide = RT_CAN_STDID;     /* 标准格式 */
    msg.rtr = RT_CAN_DTR;       /* 数据帧 */
    msg.len = 8;                /* 数据长度为 8 */
    /* 待发送的 8 字节数据 */
    msg.data[0] = 0x00;
    msg.data[1] = 0x11;
    msg.data[2] = 0x22;
    msg.data[3] = 0x33;
    msg.data[4] = 0x44;
    msg.data[5] = 0x55;
    msg.data[6] = 0x66;
    msg.data[7] = 0x77;
    /* 发送一帧 CAN 数据 */
    size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
    if (size == 0)
    {
        rt_kprintf("can dev write data failed!\n");
    }

    return res;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(can_sample, can device sample);

此时编译下载,然后打开msh,输入list_device

可以看到can设备,此时还需要修改一写文件才能完成can的配置

细节修改

将CubeMX生成的can.c加入构建

然后导航栏会出现C/C++项目

然后切换到C/C++项目

如果没找到can.c,回cubemx

添加构建,每次修改cubemx都要添加一次,咋说呢,很无语。

修改RT-Thread源码的两处代码

drv_can.c修改

rtt官方给的驱动有点问题,主要就是波特率配置的不对,修改两处地方。

参考正点原子的配置修改:

can_init(CAN_SJW_1TQ, CAN_BS2_6TQ, CAN_BS1_8TQ, 6, CAN_MODE_NORMAL); /* CAN初始化, 普通(0)/回环(1)模式, 波特率500Kbps */

可以看到是1,6,8,6,我们也按这个来,改为:

#else  /* APB1 45MHz(max) */
static const struct stm32_baud_rate_tab can_baud_rate_tab[] =
{
//    {CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ  | CAN_BS2_5TQ | 3)},
//    {CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ  | CAN_BS2_5TQ | 4)},
    {CAN500kBaud, (CAN_SJW_1TQ | CAN_BS1_6TQ  | CAN_BS2_8TQ | 6)},
//    {CAN250kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ  | CAN_BS2_5TQ | 12)},
//    {CAN125kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ  | CAN_BS2_5TQ | 24)},
//    {CAN100kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ  | CAN_BS2_5TQ | 30)},
//    {CAN50kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ  | CAN_BS2_5TQ | 60)},
//    {CAN20kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ  | CAN_BS2_5TQ | 150)},
//    {CAN10kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ  | CAN_BS2_5TQ | 300)}
};
#endif

其他波特率暂时没用到,先屏蔽。

drivers\can.h修改

文件地址rtt_can_test\rt-thread\components\drivers\include\drivers\can.h

下载验证

烧录下载,然后msh控制台发送can_sample命令

不会报错,使用CANL和CANH与另一台开发板连接,现象如下:

发送:

接收:

可能出现的错误以及解决办法

开启can设备出错:

解决办法一:

查看cubemx生成的can.c是否加入构建,每次打开关闭cubemx都需要添加构建

解决办法二:

查看can收发引脚是否配置正确

解决办法三:

查看开发板的跳线帽是否接对,正确接法:

写入失败

解决办法一:

查看波特率配置是否正确

解决办法二:

查看另一台设备can模式是否处于正常模式

结束

代码仓库地址: 

godmial/rtt_can_test: 正点原子阿波罗F429使用RT-Thread studio实现CAN收发 (github.com)

压缩包:

【免费】正点原子阿波罗F429使用RT-Threadstudio实现CAN收发资源-优快云文库

不要积分的!!!

参考文章:

RT-Thread studio上创建一个STM32F103的CAN通讯功能_rtthread can例程-优快云博客

RT-Thread-CAN通讯异常显示can dev write data failed!RT-Thread问答社区 - RT-Thread

教程到此结束,有问题欢迎评论,本人高强度冲浪;

如果对你有帮助请点赞收藏!感谢!

### 如何在 RT-Thread配置 CAN 驱动 #### 准备工作 为了确保 CAN 设备能够正常运行于 RT-Thread 系统之上,需先完成必要的准备工作。这包括但不限于确认硬件连接正确以及安装相应的开发环境。 #### 修改 `can.h` 文件以适应特定需求 对于某些应用场景而言,可能需要扩展标准的 CAN 接口定义来满足特殊的功能要求。例如,在处理消息接收时指定不同的 FIFO(First In First Out),可以通过向结构体 `struct rt_can_filter_item` 添加成员变量 `rxfifo` 来实现这一功能[^2]: ```c struct rt_can_filter_item { ... rt_int32_t rxfifo; /* Add a configuration item that CAN_FIFO0/CAN_FIFO1 */ }; ``` 此改动允许开发者更灵活地控制数据流的方向和存储位置。 #### 解决常见错误提示 "can dev write data failed" 当遇到此类报错信息时,通常意味着存在发送失败的情况。造成该现象的原因多种多样,比如波特率设置不当、滤波器参数不合理或是物理层通信出现问题等。针对这类问题的具体排查方法可参见相关论坛讨论[^1]。 #### 使用 HAL 库简化驱动程序编写过程 如果发现通过传统方式难以集成 CAN 功能,则可以考虑采用 HAL (Hardware Abstraction Layer) 库来进行底层交互。这种方式不仅降低了复杂度,还提高了代码移植性和维护性。具体实践案例可见于基于 GM6020 的项目描述中提到的手动引入 HAL 库的做法[^4]。 #### 学习资源推荐 考虑到初学者可能会觉得直接上手较为棘手,建议参考官方提供的培训资料,这些材料往往包含了详细的讲解视频、幻灯片演示文稿及完整的实例源码,有助于加深理解并快速入门[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值