C编程实现键盘LED灯闪烁

在《Shell脚本实现键盘LED灯闪烁》一文中,我们已感受到了控制的乐趣,一步步向硬件逼近,这次我们在Linux下使用C语言进行系统调用来实现该功能。这里面会涉及到应用层定时器和ioctl系统调用来控制键盘LED灯状态。

关于应用层定时器需要涉及到信号机制,其包含有alarm闹钟和timer定时器两种,其与信号机制分别说明如下(这两种均是自动循环的,即不需要处理函数里再设置一遍定时器超时设置):

1.alarm

运行man alarm命令后有关于该函数的使用说明,其函数原型如下:

#include
unsigned int alarm(unsigned int seconds);

当设定的时间到了后会发出SIGALRM信号,需要对应的信号处理函数配套处理。

2.timer

运行man setitimer命令后有相关说明,本次会用到的函数原型如下:

#include
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
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

这signal函数除了与定时器配套外,还可以捕获其他信号,执行man 7 signal命令可以查看到。 

好了,关于定时器部分就说到这。而关于键盘LED灯控制,我们需要用到TTY设备的ioctl系统调用函数,该函数是标准的字符设备接口(可以不实现),其接口原型(执行man ioctl)如下:

#include
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灯闪烁的源码:

#include
#include
#include
#include
#include

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

你可能感兴趣的:(C编程实现键盘LED灯闪烁)