论文部分内容阅读
摘要:μC/OS-II是一个基于抢占式的实时多任务内核,可固化、可剪裁、具有高稳定性和可靠性,μC/OS-II作为一个操作系统内核,它没有设备驱动程序管理部分。文章着重阐述了如何为μC/OS-II添加设备驱动程序管理模块,并给出了在NEC PD78F0376 平台下串口驱动程序的范例。
关键词: μC/OS-II;驱动设备管理;串口驱动
中图分类号:TP316文献标识码:A文章编号:1009-3044(2007)06-11649-02
1 引言
uC/OS-II 是一个简单、高效的嵌入式实时操作系统内核,被应用到各种嵌入式系统中。目前,它支持 x86、ARM、PowerPC、MIPS 等众多体系结构,并有上百个商业应用实例,其稳定性和可用性是经过实践验证的。uC/OS-II仅仅是操作系统内核,没有象其它嵌入式操作系统一样提供了文件系统管理和驱动设备管理部分,所以对于在uC/OS-II操作系统下开发应用程序的人员来说,应用程序是直接调用设备的底层函数,这就需要开发应用程序的人员能够比较了解底层的细节,一旦硬件设备较多,需要访问硬件设备的应用程序较多,应用程序开发人员要自己解决驱动程序的管理问题就比较麻烦。而拥有了驱动设备管理模块,驱动程序的安装可交给底层开发人员来完成,应用程序的开发人员就可以通过统一的接口函数来访问底层,同时也方便多个设备驱动程序的统一管理。
2 驱动设备管理模块的设计
驱动设备管理模块相当于操作系统和底层设备驱动程序的桥梁,一方面底层的相关函数在执行的时候可能需要操作系统提供的资源,另一方面,上层应用程序是通过操作系统来获取对底层设备的信息和对其操作的权力,在设计中,建立了驱动设备列表和驱动程序描述表来实现上述两个主要功能。下面对这两个表作详细介绍:
驱动设备列表是一个双向链表,驱动设备列表的大小是动态的,因此可以任意向其中添加新设备,应用程序通过设备来访问驱动设备列表,来找到该设备在驱动程序描述表对应的索引号,再从驱动程序描述表里面找到该设备的底层操作函数。链表设备的结构体定义如下:
typedef struct dlnode{
struct dlnode *next;
struct dlnode *previous;
unsigned short drvNum;
DEV_HDR *head;
} DL_NODE;
驱动设备列表程序中提供了3个主要功能函数供底层开发人员和应用程序的开发人员使用
(1)添加设备 dlladd(unsigned char drvName )
此函数向链表中添加新的节点,与此同时也会向操作系统申请操作该设备的需要的信号量的资源,以及存储数据所用的缓冲区,申请缓冲区的大小是由该设备的特性所决定,这个可以由底层设计人员在设备加入函数中设定。
(2)卸载设备 dlldelect(unsigned char drvName )
当开发人员决定卸载这个设备的时候就调用此函数,它在链表中删除这个设备对应得节点,并且释放该设备申请的各种资源。
(3)查找unsigned short dllGet(UNIT8 drvName)
这个函数主要是提供给应用程序的开发人员使用,对于应用程序的开发人员来说通过设备名来查找设备索引号。
驱动程序描述表主要是存储驱动程序底层函数的入口点,它不同于驱动设备列表,结构上来说它不是动态的,它向操作系统申请了固定的空间来存储这个表,故这个表的大小由底层开发人员根据可能需要的最多的设备数量来设定,整个表由多个结构体DRV_ENTRY组成,表的定义为DRV_ENTRY DrvTable[MAX_DEV];每个设备都是以结构体DRV_ENTRY的形式在表中存储,如果一个设备对应DrvTable中的第i成员DrvTable[i] ,那么I 就是它的索引号结构体定义如下:
typedef struct {
unsigned char drvName;
unsigned char in_use;
FUNCPTR de_open ;
FUNCPTR de_close ;
FUNCPTR de_read ;
FUNCPTR de_write ;
FUNCPTR de_ioctrl ;/ *de_open,……de_ioctrl就是该设备对应的不同底层函数的入口*/
}DRV_ENTRY ;
驱动程序描述表的主要功能是应用程序根据设备索引号来找到该表中对应的设备,并且找到该设备的底层函数入口,该设备的底层函数入口是在设备安装到表里的时候加入的,用户调用该安装程序传入实参来安装各种设备的驱动程序,设备安装函数如下:
unsigned char DrvInstall
(unsigned char i, FUNCPTR popen, FUNCPTR pclose,FUNCPTR pread, FUNCPTR pwrite, FUNCPTRpioctrl) // 传入的参数为底层函数
{ unsigned char *err;
unsigned char i ;
DRV_ENTRY *pDrvEntry= NULL;
OSSemPend (pdevtable_event, WAIT_FOREVER, err);/*此信号量在添加设备函数 dllall中定义并初始化*/
if(*err == OS_NO_ERR)
return(FALSE);
else{
pDrvEntry = &DrvTable[i];//查找与索引号对应的设备
pDrvEntry->in_use = TURE;
pDrvEntry->de_open = popen; // 将底层函数的入口放在表中pDrvEntry->de_close= pclose;
pDrvEntry->de_read = pread;
pDrvEntry->de_write = pwrite;
pDrvEntry->de_ioctrl = pioctrl;
OSSemPost (pdevtable_event); // 释放该信号量
if(*pDrvEntry != NULL)
return(FALSE);
else
return(TRUE);} }
除了设备安装函数之外,还有设备删除,显示设备信息等函数,它们都是对驱动程序描述表的操作,结构和设备安装函数类似。
3 驱动设备管理功能的具体应用
3.1 串口驱动程序简介
串行通信是两个设备之间的一种通讯标准,两个设备通过收、发数据信号线线进行全双工数据通讯,数据在一根数据信号线上一位一位地进行传输,每一位数据都占据一个固定的时间长度。这种通信方式的特点是,使用的数据线少,在远距离通信中可以节约通信成本,其传输速度比并行传输慢。串口驱动程序主要是对设备的串行接口进行控制,使其能够通过串行接口与通讯另一方进行数据交换,它的分5个主要部分组成:串行接口的初始化,串行接口的关闭,读取串行接口的数据,向串行接口发送数据,串行接口的通讯参数设定,这5个部分的功能就对应open,close ,red ,write ,ctrl这5个底层通用接口函数,在NEC PD78F0376 平台下分别UART_init,UART_close,UART_read,UART_SendChar,UART_ctrl。其中UART_read为读取串行接口的数据操作,它的具体结构如下:
void UART_read(unsigned char *p)
{while(buffer.status != RX_FULL);
//检查缓冲区标志位,看是否已经满
DI(); //进入临界区
memcpy(p, buffer.buffer,UART_BUFFERSIZE);
//接收缓冲区数据
EI();//退出临界区
prx_uart = buffer.buffer;
//重新将接收缓冲区数据的指针移到缓冲区开始的位置
}UART_read为向串行接口发送数据,它的具体结构如下
UART_SendChar (unsigned char *ucData){
TXB6 = *ucData;//将要传输的数据写入到发送寄存器
while(!STIF6); //等待传输标志位指示传输完成
STIF6=0;//清零传输标志位
3.2 将串口驱动程序加入操作系统中
这个部分由底层开发人员完成,它的主要工作有:初始化驱动设备列表,在驱动设备列表中加入一个名叫UART的设备 dlladd(UART ),在这个函数在申请系统资源的同时,返回该设备地索引号,并将在驱动程序描述表中该设备的结构体inuse状态置为TURE,该设备在驱动设备列表和驱动程序描述表中已经建立,执行DrvInstall(UART ,UART_init,UART_close,UART_read,UART_SendChar,UART_ctrl),这个步骤是将串口驱动程序函数的入口加入到驱动程序描述表中,最后要将串口接收的中断服务程序加入到操作系统中去。
3.3 应用程序通过设备驱动程序管理模块访问设备
应用程序需要知道要访问的设备的设备名,访问串口设备执行dllGet(UART),该函数返回该设备在驱动程序描述表中的索引号I,根据索引号执行DrvFind(I),该函数返回驱动程序描述表与该设备对应的设备入口结构体drventry;在这个结构体中就有该设备的底层函数入口,要执行设备相应的操作如打开,调用Drvopen (drventry)即可,这对应用程序开发者来说是较为方便的
4 结语
文章给出的设备驱动程序管理模块其作用是为上层控制设备驱动程序带来方便,并不针对某个特定的开发环境,仅要求在μC/OS-II操作系统下,具有通用性,实际的底层开发人员还需要根据硬件环境的不同自己编写open,close ,red ,write ,ctrl等底层操作函数。
参考文献:
[1]周启平,张扬. VxWorks下设备驱动程序及BSP开发指南[M].北京: 中国电力出版社,2004.
[2]任哲. 嵌入式实时操作系统μC/OS-Ⅱ原理及应用[M].北京: 北京航空航天大学出版社, 2005.
[3](美)Jean J.Labrosse,邵贝贝译.嵌入式实时操作系统μC/OS-II(第2版).北京: 中国电力出版社,2001.
[4]刘乐善,叶济忠,叶永坚.微型计算机接口技术原理及应用.武汉: 华中理工大学出版社,2000.
[5]孙涵芳 Intel 16位单片机[M].北京: 北京航空航天大学出版社.
[6]J. Glenn Brookshear. Computer Science: An Overview, Sixth Edition, 北京:人民邮电出版社,2003.
[7]王开铸.C语言数据结构程序设计[M].哈尔滨: 哈尔滨工业大学出版社,2003.
本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。
关键词: μC/OS-II;驱动设备管理;串口驱动
中图分类号:TP316文献标识码:A文章编号:1009-3044(2007)06-11649-02
1 引言
uC/OS-II 是一个简单、高效的嵌入式实时操作系统内核,被应用到各种嵌入式系统中。目前,它支持 x86、ARM、PowerPC、MIPS 等众多体系结构,并有上百个商业应用实例,其稳定性和可用性是经过实践验证的。uC/OS-II仅仅是操作系统内核,没有象其它嵌入式操作系统一样提供了文件系统管理和驱动设备管理部分,所以对于在uC/OS-II操作系统下开发应用程序的人员来说,应用程序是直接调用设备的底层函数,这就需要开发应用程序的人员能够比较了解底层的细节,一旦硬件设备较多,需要访问硬件设备的应用程序较多,应用程序开发人员要自己解决驱动程序的管理问题就比较麻烦。而拥有了驱动设备管理模块,驱动程序的安装可交给底层开发人员来完成,应用程序的开发人员就可以通过统一的接口函数来访问底层,同时也方便多个设备驱动程序的统一管理。
2 驱动设备管理模块的设计
驱动设备管理模块相当于操作系统和底层设备驱动程序的桥梁,一方面底层的相关函数在执行的时候可能需要操作系统提供的资源,另一方面,上层应用程序是通过操作系统来获取对底层设备的信息和对其操作的权力,在设计中,建立了驱动设备列表和驱动程序描述表来实现上述两个主要功能。下面对这两个表作详细介绍:
驱动设备列表是一个双向链表,驱动设备列表的大小是动态的,因此可以任意向其中添加新设备,应用程序通过设备来访问驱动设备列表,来找到该设备在驱动程序描述表对应的索引号,再从驱动程序描述表里面找到该设备的底层操作函数。链表设备的结构体定义如下:
typedef struct dlnode{
struct dlnode *next;
struct dlnode *previous;
unsigned short drvNum;
DEV_HDR *head;
} DL_NODE;
驱动设备列表程序中提供了3个主要功能函数供底层开发人员和应用程序的开发人员使用
(1)添加设备 dlladd(unsigned char drvName )
此函数向链表中添加新的节点,与此同时也会向操作系统申请操作该设备的需要的信号量的资源,以及存储数据所用的缓冲区,申请缓冲区的大小是由该设备的特性所决定,这个可以由底层设计人员在设备加入函数中设定。
(2)卸载设备 dlldelect(unsigned char drvName )
当开发人员决定卸载这个设备的时候就调用此函数,它在链表中删除这个设备对应得节点,并且释放该设备申请的各种资源。
(3)查找unsigned short dllGet(UNIT8 drvName)
这个函数主要是提供给应用程序的开发人员使用,对于应用程序的开发人员来说通过设备名来查找设备索引号。
驱动程序描述表主要是存储驱动程序底层函数的入口点,它不同于驱动设备列表,结构上来说它不是动态的,它向操作系统申请了固定的空间来存储这个表,故这个表的大小由底层开发人员根据可能需要的最多的设备数量来设定,整个表由多个结构体DRV_ENTRY组成,表的定义为DRV_ENTRY DrvTable[MAX_DEV];每个设备都是以结构体DRV_ENTRY的形式在表中存储,如果一个设备对应DrvTable中的第i成员DrvTable[i] ,那么I 就是它的索引号结构体定义如下:
typedef struct {
unsigned char drvName;
unsigned char in_use;
FUNCPTR de_open ;
FUNCPTR de_close ;
FUNCPTR de_read ;
FUNCPTR de_write ;
FUNCPTR de_ioctrl ;/ *de_open,……de_ioctrl就是该设备对应的不同底层函数的入口*/
}DRV_ENTRY ;
驱动程序描述表的主要功能是应用程序根据设备索引号来找到该表中对应的设备,并且找到该设备的底层函数入口,该设备的底层函数入口是在设备安装到表里的时候加入的,用户调用该安装程序传入实参来安装各种设备的驱动程序,设备安装函数如下:
unsigned char DrvInstall
(unsigned char i, FUNCPTR popen, FUNCPTR pclose,FUNCPTR pread, FUNCPTR pwrite, FUNCPTRpioctrl) // 传入的参数为底层函数
{ unsigned char *err;
unsigned char i ;
DRV_ENTRY *pDrvEntry= NULL;
OSSemPend (pdevtable_event, WAIT_FOREVER, err);/*此信号量在添加设备函数 dllall中定义并初始化*/
if(*err == OS_NO_ERR)
return(FALSE);
else{
pDrvEntry = &DrvTable[i];//查找与索引号对应的设备
pDrvEntry->in_use = TURE;
pDrvEntry->de_open = popen; // 将底层函数的入口放在表中pDrvEntry->de_close= pclose;
pDrvEntry->de_read = pread;
pDrvEntry->de_write = pwrite;
pDrvEntry->de_ioctrl = pioctrl;
OSSemPost (pdevtable_event); // 释放该信号量
if(*pDrvEntry != NULL)
return(FALSE);
else
return(TRUE);} }
除了设备安装函数之外,还有设备删除,显示设备信息等函数,它们都是对驱动程序描述表的操作,结构和设备安装函数类似。
3 驱动设备管理功能的具体应用
3.1 串口驱动程序简介
串行通信是两个设备之间的一种通讯标准,两个设备通过收、发数据信号线线进行全双工数据通讯,数据在一根数据信号线上一位一位地进行传输,每一位数据都占据一个固定的时间长度。这种通信方式的特点是,使用的数据线少,在远距离通信中可以节约通信成本,其传输速度比并行传输慢。串口驱动程序主要是对设备的串行接口进行控制,使其能够通过串行接口与通讯另一方进行数据交换,它的分5个主要部分组成:串行接口的初始化,串行接口的关闭,读取串行接口的数据,向串行接口发送数据,串行接口的通讯参数设定,这5个部分的功能就对应open,close ,red ,write ,ctrl这5个底层通用接口函数,在NEC PD78F0376 平台下分别UART_init,UART_close,UART_read,UART_SendChar,UART_ctrl。其中UART_read为读取串行接口的数据操作,它的具体结构如下:
void UART_read(unsigned char *p)
{while(buffer.status != RX_FULL);
//检查缓冲区标志位,看是否已经满
DI(); //进入临界区
memcpy(p, buffer.buffer,UART_BUFFERSIZE);
//接收缓冲区数据
EI();//退出临界区
prx_uart = buffer.buffer;
//重新将接收缓冲区数据的指针移到缓冲区开始的位置
}UART_read为向串行接口发送数据,它的具体结构如下
UART_SendChar (unsigned char *ucData){
TXB6 = *ucData;//将要传输的数据写入到发送寄存器
while(!STIF6); //等待传输标志位指示传输完成
STIF6=0;//清零传输标志位
3.2 将串口驱动程序加入操作系统中
这个部分由底层开发人员完成,它的主要工作有:初始化驱动设备列表,在驱动设备列表中加入一个名叫UART的设备 dlladd(UART ),在这个函数在申请系统资源的同时,返回该设备地索引号,并将在驱动程序描述表中该设备的结构体inuse状态置为TURE,该设备在驱动设备列表和驱动程序描述表中已经建立,执行DrvInstall(UART ,UART_init,UART_close,UART_read,UART_SendChar,UART_ctrl),这个步骤是将串口驱动程序函数的入口加入到驱动程序描述表中,最后要将串口接收的中断服务程序加入到操作系统中去。
3.3 应用程序通过设备驱动程序管理模块访问设备
应用程序需要知道要访问的设备的设备名,访问串口设备执行dllGet(UART),该函数返回该设备在驱动程序描述表中的索引号I,根据索引号执行DrvFind(I),该函数返回驱动程序描述表与该设备对应的设备入口结构体drventry;在这个结构体中就有该设备的底层函数入口,要执行设备相应的操作如打开,调用Drvopen (drventry)即可,这对应用程序开发者来说是较为方便的
4 结语
文章给出的设备驱动程序管理模块其作用是为上层控制设备驱动程序带来方便,并不针对某个特定的开发环境,仅要求在μC/OS-II操作系统下,具有通用性,实际的底层开发人员还需要根据硬件环境的不同自己编写open,close ,red ,write ,ctrl等底层操作函数。
参考文献:
[1]周启平,张扬. VxWorks下设备驱动程序及BSP开发指南[M].北京: 中国电力出版社,2004.
[2]任哲. 嵌入式实时操作系统μC/OS-Ⅱ原理及应用[M].北京: 北京航空航天大学出版社, 2005.
[3](美)Jean J.Labrosse,邵贝贝译.嵌入式实时操作系统μC/OS-II(第2版).北京: 中国电力出版社,2001.
[4]刘乐善,叶济忠,叶永坚.微型计算机接口技术原理及应用.武汉: 华中理工大学出版社,2000.
[5]孙涵芳 Intel 16位单片机[M].北京: 北京航空航天大学出版社.
[6]J. Glenn Brookshear. Computer Science: An Overview, Sixth Edition, 北京:人民邮电出版社,2003.
[7]王开铸.C语言数据结构程序设计[M].哈尔滨: 哈尔滨工业大学出版社,2003.
本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。