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测试实例,测试步骤如下:
- 根据CAN设备名称,获取CAN设备句柄。
- 打开CAN设备。
- 使用CAN发送数据。
- 使用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