这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 怎么用非阻塞的方式从键盘读字符?

共7条 1/1 1 跳转至

怎么用非阻塞的方式从键盘读字符?

菜鸟
2007-09-15 16:45:56     打赏

想在vxworks设计一个轮询程序,每隔几个毫秒从键盘读入一个字符,如果没有键盘输入,则执行其他代码,工作在非阻塞方式下,请问各位大虾该怎么做??
1。之前采用read函数,但此函数对读键盘是阻塞的,(查了一下资料,用ioctl函数设置非阻塞只对socket有效,对其他i/o无效,不知我的理解对不对?)总是阻塞在read。。
2。本来想尝试用kbhit函数和getchar函数一起使用,但编译器不识别kbhit,感觉vxworks库函数中没有kbhit这个函数,或者是我没找到,请教各位大虾,帮一把,谢谢了!




关键词: 怎么     用非     阻塞     方式     键盘     字符    

菜鸟
2007-09-17 08:07:23     打赏
2楼

大虾们都跑哪去拉?自己顶一个


菜鸟
2007-09-17 16:25:53     打赏
3楼
vxWorks 下没有类似DOS下的kbHit函数。但是可以自己做一个:
目的是为了不阻塞地读键盘码-可以考虑用一个单独的task专门截获按键输入,形成以下几种方式:1. 消息队列,2. 环型缓冲。
1. 如果采用消息队列,则先判断消息队列中的消息个数,等于0就做别的事情,有消息就读出来进行处理。
2. 如果采用环型缓冲,这种数据结构一端读一段写是天然互斥的,键盘截获task截获按键后写入环型缓冲,工作task则读环型缓冲,判断读得的个数,如果>0则读到了按键内容,按你的控制要求依次处理各个按键输入。如果=0,则没有得到按键输入。
把上述的键盘截获task和数据处理任务合起来,就可以形成自己的kbhit函数了。


另外,还有一种搞法,不知道合不合你的要求,既然你的工作task是每隔几个ms就扫描一下键盘,再看是否有按键决定处理键盘事件还是做别的事情,所以,可以这样考虑:
键盘是有中断的,在键盘中断的ISR里面将获得的键盘代码直接通过消息队列发送给你的工作task。而你的工作task则采用一个带超时的msgQReceive,假如超时时间为2个tick。则调用msgQReceive时,如果键盘ISR已经发送了按键消息,则马上返回,得到了键盘码,进行处理,如果没有,则进入阻塞,2个tick之内的任何时刻有按键输出,马上返回,得到键盘码,如果没有,则2个tick一结束,工作任务就绪,得到执行,msgQreceive返回没有得到消息,进行其它事情的处理。这种做法不会遗漏任何键盘输入,响应也快,但是就是工作任务总要等几个体tick,而且你得改键盘驱动,不再采用标准的IO函数如read进行键盘读取。当然了,只要按键可以通过消息给出来,你完全可以不等,把msgQreceive的等待参数设置为0,有消息没消息都立即返回,也不会阻塞。

希望能对你有点帮助。。。




菜鸟
2007-09-17 16:28:50     打赏
4楼
哦,另外,read阻塞与否,只与驱动实现有关,因为read最终调用的是驱动注册的设备的read函数。,,,当然了,多数设备的read函数都是会导致阻塞的。read一个fd,首先在fd table里面找到该fd对应的drv,再把read的参数传递给并执行drv的read函数。同样,ioctl有什么样的功能,也完全是由drv来实现的。

菜鸟
2007-09-18 08:42:28     打赏
5楼

非常感谢yaopg的真诚相助,昨晚尝试用键盘中断的方式进行处理,可是键盘输入总是不能产生中断,直接打印到显示器,不知什么原因,代码如下:
/****************/
main()
{
  int i;
intConnect((VOIDFUNCPTR*)INUM_TO_IVEC(1+0x20),(VOIDFUNCPTR)key_ISR,0);
intEnable(1);   //键盘中断级别1;
while()               //不停循环是为了让程序不死
  {  
    taskDelay(6);
    i=i%100;
  }
}

void key_ISR()
{
   logMsg("This is a ISR!",0,0,0,0,0,0);
}

再次请教yaopg大虾,十分感谢!


菜鸟
2007-09-18 09:30:15     打赏
6楼
xiaojunliu :

你好!
 
看了你上面的代码,觉得有下面几个问题,仅供参考:
1. 你采用了main函数,在vxWorks 6.x的RTP任务里面是有main函数,但它不能直接调用intConnect之类的系统函数。vxWorks 5.x以及不采用RTP的6.x都不需要main函数。
2. intConnect是有返回值的,你的中断挂接不一定成功了,需要做一下返回值判断,建议编程中尽可能多地对有可能返回错误的系统API调用进行返回值判断,可以增强程序健壮性。
3. 在x86体系中应该使用intEnablePIC进行IRQ使能,如果是PPC等,就没有这个问题了。
4. “INUM_TO_IVEC(1+0x20)”直接使用数字的表述方法不太好,最好使用board.h或者config.h中的宏定义。以免出线纰漏和移植时的麻烦。
5. 某些CPU体系的vxWorks实现,如x86,不支持在一个IRQ上同时挂多个ISR,如果已经挂了一个,必须解挂再挂新的。如果要挂多个,有专门的函数,比如,pciIntConnect,通过ISR链表的方式实现,中断一发生,链表中的所有ISR都得到执行,是为共享中断。但是,如果是PPC等,可以直接挂多个ISR,因为PPC基于一个异常基址,内部已经做了中断共享的数据结构。看到你说到显示屏,看来是包含了PC_CONSOLE组件,那么可以肯定地,键盘中断已经被使用了。
6. 对于上面的实现:只要中断挂成功上了,不管你的main函数是否退出,ISR一样会被触发。所以,测试程序可以不用一直循环。(可能对你的意思理解有误)
7. 要改的话,可以考虑在键盘驱动的ISR里面添加代码,而不是增挂一个ISR。又或者直接使用IO函数来read,变成消息队列或者环型缓冲。会通用且方便一些。另外,环型缓冲对于具有串行特性的应用是一个堪称完美的数据结构,在一般的操作系统中,对中断中的调试、串行(如串口、CAN,USB等)通信驱动中被采用,典型的:vxWorks、windows中的串口驱动使用的是环型缓冲,vxWorks的logMsg,linux的printk都是使用的环型缓冲。天然互斥保证了数据完整性,天然不阻塞的特性避免了复杂的系统API调用又保证了效率,非常值得一试。
仅供参考:)


菜鸟
2007-09-19 08:39:54     打赏
7楼
再次感谢yaopg大虾的指教,我采用一个任务(级别高一点),然后用read函数,设置opt_raw模式,然后让它阻塞,这样当有键盘字符输入的话,立马相应,然后再用switch语句进行操作,尝试了一下,没有什么问题。
真的很感谢yaopg的不吝指教,谢谢!

共7条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]