C编程实现键盘LED灯闪烁
在《Shell脚本实现键盘LED灯闪烁》一文中,我们已感受到了控制的乐趣,一步步向硬件逼近,这次我们在Linux下使用C语言进行系统调用来实现该功能。这里面会涉及到应用层定时器和ioctl系统调用来控制键盘LED灯状态。
关于应用层定时器需要涉及到信号机制,其包含有alarm闹钟和timer定时器两种,其与信号机制分别说明如下(这两种均是自动循环的,即不需要处理函数里再设置一遍定时器超时设置):
1.alarm
运行man alarm命令后有关于该函数的使用说明,其函数原型如下:
#include <unistd.h> unsigned int alarm(unsigned int seconds);
当设定的时间到了后会发出SIGALRM信号,需要对应的信号处理函数配套处理。
2.timer
运行man setitimer命令后有相关说明,本次会用到的函数原型如下:
#include <sys/timer.h> int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
其中which是设置的定时器类型,分别对应如下:
- ITIMER_REAL:实时定时器,发SIGALRM信号;
- ITIMER_VIRTUAL:应用进程执行时间定时器,发SIGVTALRM信号;
- ITIMER_PROF:应用进程执行和内核交互时间定时器,发SIGPROF信号。
从上面可以看出,同一时间只能有3个定时器存在,分别对应3种类型。那么上面的信号要如何处理呢?执行man signal命令有相关的函数原型如下:
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
这signal函数除了与定时器配套外,还可以捕获其他信号,执行man 7 signal命令可以查看到。 好了,关于定时器部分就说到这。
而关于键盘LED灯控制,我们需要用到TTY设备的ioctl系统调用函数,该函数是标准的字符设备接口(可以不实现),其接口原型(执行man ioctl)如下:
而关于键盘LED灯控制,我们需要用到TTY设备的ioctl系统调用函数,该函数是标准的字符设备接口(可以不实现),其接口原型(执行man ioctl)如下:
#include <sys/ioctl.h> int ioctl(int d, int request, ...);
其中d为相应的设备描述符号,request是命令码,…是命令码对应的参数值。对于Keyboard的LED,我们使用到KDSETLED这个命令码,而其对应的设备是/dev/console,这里的d就对应open这个设备的返回值,而…对应传入的值,恢复未定义状态是0xff,而键盘右上角3个灯(Number lock,Caps Lock,Scroll Lock)全亮对应0x07。
下面是实现C编程控制PC键盘LED灯闪烁的源码:
下面是实现C编程控制PC键盘LED灯闪烁的源码:
#include <stdio.h> #include <sys/time.h> #include <signal.h> #include <linux/kd.h> #include <sys/ioctl.h> void slam_alarm_handler(int a) { int tty = open("/dev/console", 0), led; if(tty<3) { perror("open:"); exit(0); } led = 0x07; if(ioctl(tty,KDSETLED,led)>0) perror("ioctl led on:"); sleep(1); led = 0xff; if(ioctl(tty,KDSETLED,led)>0) perror("ioctl led off:"); close(tty); } int main(void) { /* The struct itimerval * it_interval:means interval everytime after first time * it_value:means the first time interval * The ITIMER_REAL timer come with SIGALRM signal */ struct itimerval t; t.it_interval.tv_usec = 0; t.it_interval.tv_sec = 2; t.it_value.tv_usec = 0; t.it_value.tv_sec = 2; if(setitimer(ITIMER_REAL, &t, NULL) < 0) { printf("Setitimer failed.\n"); exit(-1); } signal(SIGALRM, slam_alarm_handler); while(1) { sleep(2); } exit(0); }
相应的Makefile文件内容如下:
all: gcc -o timer_keyboard_led_flash timer_keyboard_led_flash.c clean: rm -rf timer_keyboard_led_flash
对应的源码文件目录树如下:
/home/xinu/xinu/c_cpp/timer_keyboard_led_flash/
├── Makefile
└── timer_keyboard_led_flash.c
编译生成的文件后,执行时需要root用户权限,在ubuntu下需sudo ./timer_keyboard_led_flash命令去执行。
参考网址:
http://www.cppblog.com/jerryma/archive/2012/01/31/164704.html
http://jpkc.zju.edu.cn/k/505/pdf/nihe4.pdf
http://blog.csdn.net/fanwenbo/article/details/2645362
http://falldog7.blogspot.com/2008/05/linux-timer.html
http://ubuntuforums.org/showthread.php?t=1372521
/home/xinu/xinu/c_cpp/timer_keyboard_led_flash/
├── Makefile
└── timer_keyboard_led_flash.c
编译生成的文件后,执行时需要root用户权限,在ubuntu下需sudo ./timer_keyboard_led_flash命令去执行。
参考网址:
http://www.cppblog.com/jerryma/archive/2012/01/31/164704.html
http://jpkc.zju.edu.cn/k/505/pdf/nihe4.pdf
http://blog.csdn.net/fanwenbo/article/details/2645362
http://falldog7.blogspot.com/2008/05/linux-timer.html
http://ubuntuforums.org/showthread.php?t=1372521
评论
发表评论