RT-Thread版本:4.1.0
RT-Thread Studio版本:2.2.8
开发板:正点原子阿波罗F429IGT6
踩了两天的坑终于爬出来了,不得不说RTT的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 设备使用例程
* 例程导出了 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
教程到此结束,有问题欢迎评论,本人高强度冲浪;
如果对你有帮助请点赞收藏!感谢!