Skip to content

CAN设备

CAN简介

CAN 是控制器局域网络(Controller Area Network, CAN)的简称,是由以研发和生产汽车电子产品著称的德国 BOSCH 公司开发的,并最终成为国际标准(ISO 11898),是国际上应用最广泛的现场总线之一。

关于CAN总线介绍可详细查看RT-Thread官网的介绍:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/can/can?id=can-简介

驱动支持

访问CAN总线设备前,需要保证相关驱动配置已选中。

Windows环境:利用RT-Thread官方env工具直接在代码根目录下执行menuconfig进入配置。

Linux环境:在代码根目录下执行scons --menuconfig进入配置。

CAN驱动所在路径如下:

RT-Thread Components -> Device Drivers -> Using CAN device drivers

访问CAN设备

访问CAN设备,库中提供了以下接口:

函数 描述
rt_device_find() 根据CAN名称查找设备获取设备句柄
rt_device_open() 打开CAN设备,同时初始化CAN设备
rt_device_close() 关闭CAN设备
rt_device_write() CAN发送数据
rt_device_read() CAN接收数据

查找CAN设备

查找CAN设备获取设备句柄,函数原型如下所示:

rt_device_t rt_device_find(const char* name);
  • 参数

    [IN]name:CAN设备名称,目前注册到的系统中的CAN设备名称为"can1"。

  • 返回值

    RT_NULL:失败,设备不存在。

    非RT_NULL:成功,该返回值是操作CAN设备的句柄,在后续的接口中作为函数入参。

打开CAN设备

打开CAN设备,函数原型如下所示:

rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag);
  • 参数

    [IN]dev:CAN设备句柄,查找设备函数的返回值。

    [IN]oflag:打开设备模式标记,CAN 设备驱动框架支持中断接收和中断发送模式,定义值如下:

    #define RT_DEVICE_FLAG_INT_RX       0x100     /* 中断接收模式 */
    #define RT_DEVICE_FLAG_INT_TX       0x400     /* 中断发送模式 */
    
  • 返回值

    0:正常。

    其他:错误,RT-Thread定义的错误类型。

关闭CAN设备

关闭指定CAN设备,函数原型如下所示:

rt_err_t rt_device_close(rt_device_t dev);
  • 参数

    [IN]dev:CAN设备句柄,查找设备函数的返回值。

  • 返回值

0:正常。

其他:错误,RT-Thread定义的错误类型。

CAN发送数据

使用CAN设备发送数据,函数原型如下所示:

rt_size_t rt_device_write(rt_device_t dev, 
                          rt_off_t pos, 
                          void* buffer, 
                          rt_size_t size);
  • 参数

    [IN]dev:CAN设备句柄,查找设备函数的返回值。

    [IN]pos:发送数据偏移,这里没有使用。

    [IN]buffer:发送数据的指针。

    [IN]size:发送数据的长度,buffer指针指向数据内容的长度。

  • 返回值

    0:发送失败。

    其他:实际发送的CAN消息大小。

读取CAN数据

CAN读取数据,函数原型如下所示:

rt_size_t rt_device_read(rt_device_t dev, 
                         rt_off_t pos, 
                         const void* buffer, 
                         rt_size_t size);
  • 参数

    [IN]dev:CAN设备句柄,查找设备函数的返回值。

    [IN]pos:读取数据偏移,这里没有使用。

    [IN]buffer:读取数据的指针。

    [IN]size:读取数据的长度,不能超过buffer指针指向的空间的长度。

  • 返回值

    0:读取失败。

    其他:实际读取的CAN消息大小。

CAN使用示例

使用示例需要配置menuconfig打开配置(默认关闭),路径如下:

wiota APP -> open can, default close(_CAN_APP_)

以下提供CAN测试实例,测试步骤如下:

  1. 根据CAN设备名称,获取CAN设备句柄。
  2. 打开CAN设备。
  3. 使用CAN发送数据。
  4. 使用CAN接收数据。
#include <rtthread.h>
#ifdef _CAN_APP_
#include <rtdevice.h>
#include "uc_can_app.h"
#include "drv_can.h"

#define CAN_DEVICE_NAME    "can1"           // can device name
#define CAN_SEND_DATA                       // enable can send data,if use can recevie data,do not define CAN_SEND_DATA

static rt_device_t can_dev = NULL;          // can device handle 

int can_app_init(void)
{
    rt_err_t ret = RT_EOK;

    // find can device
    can_dev = rt_device_find(CAN_DEVICE_NAME);
    if (!can_dev)
    {
        rt_kprintf("find %s failed!\n", CAN_DEVICE_NAME);
        return RT_ERROR;
    }

    // open can device
    ret = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
    if (ret != RT_EOK)
    {
        rt_kprintf("open %s failed!\n", CAN_DEVICE_NAME);
        return RT_ERROR;
    }

    return ret;
}

void can_app_sample(void)
{
    int ret = 0;
    struct rt_can_msg msg;
    rt_uint8_t data[8] = {0};

    rt_kprintf("can test demo.\r\n");

    ret = can_app_init();
    if(ret != RT_EOK)
    {
        rt_kprintf("init can failed!\n");
        return;
    }

    if (can_dev == RT_NULL)
    {
        rt_kprintf("find %s failed!\n", CAN_DEVICE_NAME);
        return;
    }
    else
    {
#ifdef CAN_SEND_DATA
        while(1)
        {
            for(rt_uint8_t i=0; i<8; i++)
            {
                // fix frame id
                msg.id = i;
                msg.ide = RT_CAN_STDID;
                msg.rtr = RT_CAN_DTR;
                msg.len = 8;

                // fix data
                msg.data[0] = i;
                msg.data[1] = i;
                msg.data[2] = i;
                msg.data[3] = i;
                msg.data[4] = i;
                msg.data[5] = i;
                msg.data[6] = i;
                msg.data[7] = i;

                // can send data
                ret = rt_device_write(can_dev, 0, &msg, sizeof(msg.data));
                if(ret != 0)
                {
                    rt_kprintf("can send data success!\n");
                }
                else
                {
                    rt_kprintf("can send data failed!\n");
                }

                rt_thread_delay(1000);
            }
        }
#else
        while(1)
        {
            // read can data
            ret = rt_device_read(can_dev, 0, data, 8);
            if(ret != 0)
            {
                rt_kprintf("can recv data = ");
                for(rt_uint8_t i=0; i<8; i++)
                {
                    rt_kprintf("%2x ", data[i]);
                }
                rt_kprintf("\r\n");
            }
            else
            {
                rt_kprintf("...\r\n");
            }
            rt_thread_delay(1000);
        }
#endif
    }
}

#endif
Back to top