RT-Thread-CAN通信

1. 简述

开发硬件:正点原子STM32F407
开发软件:RT-Thread Studio
RTT版本:4.0.3
RTT参考文档

2. STM32CubeMx配置

基于芯片创建工程,使用STM32CubeMx配置时钟和CAN外设。

1

2. 打开CAN驱动框架

2

3. 设置drivers/board.h

#define BSP_USING_CAN
#define BSP_USING_CAN1

4. 设置drivers/stm32f4xx_hal_conf_bak.h

#define HAL_CAN_MODULE_ENABLE

5. 移植drv_can.h和drv_can.c

5.1 下载文件

drv_can.h和drv_can.c下载链接
将drv_can.h放到drivers/include目录,将drv_can.c放到drivers目录。

5.2 修改文件

我设置STM32F407的APB1时钟频率为42MHz,需要在drv_can.c修改配置。
波特率 = APB1/(1+CAN_BS1_TQ+CAN_BS2_TQ)/分频系数。
这里我只修改了1M和500K的通信速率。

#elif defined (SOC_SERIES_STM32F4)/* 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_2TQ | CAN_BS1_9TQ  | CAN_BS2_5TQ | 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)}
    /* APB1 42MHz APB1/(1+CAN_BS1_15TQ+CAN_BS2_5TQ)/最后一位 */
    {CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_15TQ  | CAN_BS2_5TQ | 2)},   //通过
    {CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ  | CAN_BS2_5TQ | 4)},
    {CAN500kBaud, (CAN_SJW_2TQ | CAN_BS1_15TQ  | CAN_BS2_5TQ | 4)}, //通过
    {CAN250kBaud, (CAN_SJW_2TQ | CAN_BS1_15TQ  | CAN_BS2_5TQ | 8)},
    {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)}
};

6. 测试代码

测试代码如下,默认通信速率为1M。

/*
 * 程序清单:这是一个 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);

7. 设置通信速率

/* drivers/drv_can.c */
int rt_hw_can_init(void)
{
	struct can_configure config = CANDEFAULTCONFIG;
	......
	drv_can1.device.config = config;
}
/* components/drivers/include/drivers/can.h */
#define CANDEFAULTCONFIG \
{                        \
	CAN1MBaud,            \
	RT_CANMSG_BOX_SZ,     \
	RT_CANSND_BOX_NUM,    \
	RT_CAN_MODE_NORMAL,   \
};

分析完源码后,发现CAN的通信速录由CANDEFAULTCONFIG 设定,最简单的修改如下。

#define CANDEFAULTCONFIG \
{                        \
	CAN500kBaud,          \ //修改速率为500K
	RT_CANMSG_BOX_SZ,     \
	RT_CANSND_BOX_NUM,    \
	RT_CAN_MODE_NORMAL,   \
};
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
RT-Thread作品秀】基于RT-Thread的CAN数据采集终端作者:tlled 概述在测试产品中,需要监听CAN通信上的数据,之前通过CAN适配器连接到电脑,在上位机上监听,但是在户外测试使用PC机不是很方便,使用ART-PI板卡外接显示屏,来显示要查看的设备总线的数据,以图形的方式显示出来,方便查看,我这次要实现的功能是显示显示十个测距传感器的距离,以条形的方式显示每个距离,同时显示测距传感器中最近的一个距离以数字的方式显示。 开发环境硬件:RT-Thread ART-PI STM32H750开发板,DIY 7寸电容触摸显示屏和CAN转换器 RT-Thread版本:RT-Thread 4.0.3 开发工具及版本:RT-Thread Studio 版本2.0.0 RT-Thread使用情况概述内核部分:线程创建,信号量,消息队列 组件部分:串口,CAN,I2C,LCD 软件包部分:FT6236驱动,peripheral_samples中的can_sample 例程,TouchGFX 4.15 其他:无 硬件框架硬件框图如下: 硬件说明: 1、LCD显示屏部分是根据ART-PI显示接口,绘制的转接驱动板,按照7寸的硬件驱动要求,绘制硬件电路设计电路PCB板。 2、显示触摸屏使用I2C协议的电容触摸屏。 3、CAN驱动是使用的mcp2551收发器芯片转接小板 软件框架说明软件总体流程图: 软件部分说明: 修改LCD和触摸屏驱动程序,能够正常显示和触摸。 使用TouchGFX组件,设计显示的界面。 创建消息队列,用于将CAN通信接收到的消息发送给TouchGFX组件,实现数据传输。 CAN通信接收处理。 软件模块说明演示效果https://www.bilibili.com/video/BV1bi4y1w74V/ 代码地址https://gitee.com/gtizhanghui/art-pi-prj 比赛感悟这次项目是在RT-Thread Studo软件创建ART-PI板卡对应的例程上进行修改的,也是第一次使用这个软件创建项目工程到下载板卡上运行,相比之前使用其他的编译工具,这个软件更方便,功能也更强大,可以直接在软件包里面找到相应设备的驱动直接可以应用到项目中,外设组件和设备驱动也可以应用,确实很方面。 这次项目中使用的TouchGFX与板卡之间的数据交互的实现,花费了较多的时间,通过网上查看资料,通过论坛的帮助,最终解决了问题,收获了不少。 CAN通信部分使用的例程修改的,这部分还好,就是使用硬件滤波功能时,会有报错提示。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lljwork2021

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

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

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

打赏作者

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

抵扣说明:

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

余额充值