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)如下:

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

#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命令去执行。 

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stxinu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值