相信大家在学习裸机开发时已经很熟悉各种外设的使用了,现在我们要使用rt-thread操作系统,那么这些外设的操作与裸机操作有什么差别呢。
事实上即便有操作系统也是可以直接使用裸机操作方式去操作的,但是这样做有几个缺点,一是代码看起来比较不统一,显得很乱,二是软件没有分层,耦合严重,不利于维护,三是裸机操作属于不受操作系统管控的部分,在对硬件资源的占用上,裸机操作可能会与操作系统操作产生冲突导致异常。
rt-thread提供了一套设备驱动框架,只需要按规范去注册驱动,就可以直接使用rt-thread提供的系统函数去操作硬件了。这样代码就会显得很统一,硬件与驱动也分层了,全部由操作系统调度也不会导致冲突了。目前rt-thread提供的设备模型框架如下图所示,我们要做的就是完成具体设备驱动在rt-thread设备驱动框架上的注册。
首先来了解一下在rt-thread上是如何访问和操作设备的,以应用程序读取设备为例。首先应用程序通过 rt_device_find()
接口查找到设备,在rt-thread里是通过设备名称字符串去查找的,如果能够找到则使用rt_device_open()
去打开设备,在打开设备时也可以选择是按只读,只写或读写方式去打开。接着使用rt_device_read()
去读取设备数据,当不需要使用该设备时可以通过rt_device_close()
来关闭设备。
以上这些都是操作系统层面对于设备的操作,那么具体是怎么操作到硬件的呢。可以看到最终访问设备用的是rt_device_read()
,因此具体操作肯定也就在这个函数里面。实际上具体设备的驱动和操作系统的驱动函数是有个对应的,而用来实现这种对应的就是rt_device_register()函数,通过这个函数就可以将种类繁多的驱动注册到设备驱动框架上,之后就可以使用统一的操作函数了。
接下来就讲讲如何去注册,首先得知道rt-thread有几种设备类型 ,因为不同设备类型,它们的操作系统层面驱动是不一样的,因此在注册时需要做的工作也不一样。
我们先看看rt-thread里的device结构,可以发现跟具体设备驱动有关的只有rt_device_ops,也就是设备的操作方法。
再来看看rt_device_ops的内容
这下很明确了,只有这些操作是跟设备有关的,所以只要实现这些函数就可以了。现在我们可以知道该如何操作了 ,总结下步骤:
- 先创建一个rt_device设备,如rt_device_t usr_dev
- 完成rt_device_ops里的各个操作函数,如hw_init(),hw_open(),hw_close(),hw_read(),hw_write()等
- 注册函数,usr_dev.ops->init=hw_init,usr_dev.ops->open=hw_open......
- 使用rt_device_register注册到设备框架
- 之后便可以按操作系统标准方式去操作usr_dev
下面给出一段注册示例代码供参考
#include <rtthread.h>
#include <rtdevice.h>
#define usr_dev_name "usr_dev"
rt_device_t usr_dev;
/*无需打开关闭的类型,open()与close()省去*/
static void hw_init(void)
{}
static void hw_read(void)
{}
static void hw_write(void)
{}
int usr_dev_register(void)
{
usr_dev.type=RT_Device_Class_Miscellaneous;//杂类设备
usr_dev.ops->init=hw_init;
usr_dev.ops->read=hw_read;
usr_dev.ops->write=hw_write;
return rt_device_register(usr_dev,usr_dev_name,RT_DEVICE_FLAG_RDWR);
}
INIT_DEVICE_EXPORT(usr_dev_register);//自动初始化
然后是操作示例代码供参考
#include <rtthread.h>
#include <rtdevice.h>
#define op_dev_name "usr_dev"
static rt_device_t op_dev==RT_NULL;
int test_usr_dev(void)
{
op_dev=rt_device_find(op_dev_name);
rt_device_open(op_dev,RT_DEVICE_FLAG_RDWR);
char testch;
rt_device_read(op_dev,0,&testch,1);
if(testch!='Y')
{
rt_device_write(op_dev,0,'Y',1);
}
rt_device_close(op_dev);
return 0;
}