RT_Thread设备和驱动-I/O\UART

一、I/O设备模型

 I/O设备模型框架

 

 

 

 

 

 看门狗设备使用序列图

 

 

 I/O设备对象的继承和派生关系示意图。

 

 

设备对象定义:

struct rt_device
{
    struct rt_object          parent;        /* 内核对象基类 */
    enum rt_device_class_type type;          /* 设备类型 */
    rt_uint16_t               flag;          /* 设备参数 */
    rt_uint16_t               open_flag;     /* 设备打开标志 */
    rt_uint8_t                ref_count;     /* 设备被引用次数 */
    rt_uint8_t                device_id;     /* 设备 ID,0 - 255 */

    /* 数据收发回调函数 */
    rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
    rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);

    const struct rt_device_ops *ops;    /* 设备操作方法 */

    /* 设备的私有数据 */
    void *user_data;
};
typedef struct rt_device *rt_device_t;
 创建和注册I/O设备:
rt_device_t rt_device_create(int type, int attach_size);
 当一个动态创建的设备不再需要使用时可以通过如下函数来销毁:
void rt_device_destroy(rt_device_t device);
 注册设备函数:
rt_err_t rt_device_register(rt_device_t dev, const char* name, rt_uint8_t flags);
 访问I/O设备:I/O设备操作方法的映射关系如下图
 
查找设备:
rt_device_t rt_device_find(const char* name);
 初始化设备:
rt_err_t rt_device_init(rt_device_t dev);
 打开/关闭设备:
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);
rt_err_t rt_device_close(rt_device_t dev);
 控制设备:
rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);
 cmd设备命令宏定义:
#define RT_DEVICE_CTRL_RESUME           0x01   /* 恢复设备 */
#define RT_DEVICE_CTRL_SUSPEND          0x02   /* 挂起设备 */
#define RT_DEVICE_CTRL_CONFIG           0x03   /* 配置设备 */
#define RT_DEVICE_CTRL_SET_INT          0x10   /* 设置中断 */
#define RT_DEVICE_CTRL_CLR_INT          0x11   /* 清中断 */
#define RT_DEVICE_CTRL_GET_INT          0x12   /* 获取中断状态 */
 读写设备:
rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos,void* buffer, rt_size_t size);
rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos,const void* buffer, rt_size_t size);
 数据收发回调
rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev,rt_size_t size));
rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_device_t dev,void *buffer));
 设备访问示例:
#include <rtthread.h>
#include <rtdevice.h>

#define IWDG_DEVICE_NAME    "iwg"

static rt_device_t wdg_dev;

static void idle_hook(void)
{
    /* 在空闲线程的回调函数里喂狗 */
    rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, NULL);
    rt_kprintf("feed the dog!\n ");
}

int main(void)
{
    rt_err_t res = RT_EOK;
    rt_uint32_t timeout = 1000;    /* 溢出时间 */

    /* 根据设备名称查找看门狗设备,获取设备句柄 */
    wdg_dev = rt_device_find(IWDG_DEVICE_NAME);
    if (!wdg_dev)
    {
        rt_kprintf("find %s failed!\n", IWDG_DEVICE_NAME);
        return RT_ERROR;
    }
    /* 初始化设备 */
    res = rt_device_init(wdg_dev);
    if (res != RT_EOK)
    {
        rt_kprintf("initialize %s failed!\n", IWDG_DEVICE_NAME);
        return res;
    }
    /* 设置看门狗溢出时间 */
    res = rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &timeout);
    if (res != RT_EOK)
    {
        rt_kprintf("set %s timeout failed!\n", IWDG_DEVICE_NAME);
        return res;
    }
    /* 设置空闲线程回调函数 */
    rt_thread_idle_sethook(idle_hook);

    return res;
}
 I/O设别模型补充图:

 

 二、UART设备

重要的参数:波特率、起始位、数据位、停止位和奇偶检验位。

 

 

 访问串口设备:

1.查找串口设备 ;

rt_device_t rt_device_find(const char* name);
 2.打开串口设备
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflags);
3.读取/接收
rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);
4.写入/发送
rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size);
5.控制
rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg);
6.设置接收回调函数
rt_err_t rt_device_set_rx_indicate(rt_device_t dev, rt_err_t (*rx_ind)(rt_device_t dev,rt_size_t size));
7.设置发送完成回调函数
rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_device_t dev,void *buffer));
8.关闭设备
rt_err_t rt_device_close(rt_device_t dev);
串口设备使用示例:
 
/*
 * 程序清单:这是一个 串口 设备使用例程
 * 例程导出了 uart_sample 命令到控制终端
 * 命令调用格式:uart_sample uart2
 * 命令解释:命令第二个参数是要使用的串口设备名称,为空则使用默认的串口设备
 * 程序功能:通过串口输出字符串"hello RT-Thread!",然后错位输出输入的字符
*/

#include <rtthread.h>

#define SAMPLE_UART_NAME       "uart2"

/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;
static rt_device_t serial;

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

    return RT_EOK;
}

static void serial_thread_entry(void *parameter)
{
    char ch;

    while (1)
    {
        /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */
        while (rt_device_read(serial, -1, &ch, 1) != 1)
        {
            /* 阻塞等待接收信号量,等到信号量后再次读取数据 */
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        }
        /* 读取到的数据通过串口错位输出 */
        ch = ch + 1;
        rt_device_write(serial, 0, &ch, 1);
    }
}

static int uart_sample(int argc, char *argv[])
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];
    char str[] = "hello RT-Thread!\r\n";

    if (argc == 2)
    {
        rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
    }

    /* 查找系统中的串口设备 */
    serial = rt_device_find(uart_name);
    if (!serial)
    {
        rt_kprintf("find %s failed!\n", uart_name);
        return RT_ERROR;
    }

    /* 初始化信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    /* 以中断接收及轮询发送模式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    /* 设置接收回调函数 */
    rt_device_set_rx_indicate(serial, uart_input);
    /* 发送字符串 */
    rt_device_write(serial, 0, str, (sizeof(str) - 1));

    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL)
    {
        rt_thread_startup(thread);
    }
    else
    {
        ret = RT_ERROR;
    }

    return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(uart_sample, uart device sample);
 
 
posted @ 2022-09-09 16:24  shuai2022  阅读(371)  评论(0编辑  收藏  举报