历史上的今天
返回首页

历史上的今天

今天是:2025年03月23日(星期日)

正在发生

2021年03月23日 | S3C6410开发板按键驱动代码分析及测试代码分析

2021-03-23 来源:eefocus

在本文中,我们对S3C6410开发板按键驱动代码的实现过程进行分析,然后通过一个实例对按键功能进行测试。在本文的资源中包含了设备驱动的源码和测试的源码。


一、设备驱动源码分析

按键的设备驱动主要实现了模块的初始化、模块的卸载、设备打开、设备关闭、设备读取、设备阻塞功能。


1、模块初始化

模块的初始化的源码如下所示。


static int __init dev_init(void)

{

int ret;

 

ret = misc_register(&misc);

 

printk (DEVICE_NAME"tinitializedn");

 

return ret;

}


这段代码只实现了一个功能,就是使用misc_register()函数向内核注册按键的混杂设备。


2、模块卸载

模块卸载的代码比较简单,如下所示。


static void __exit dev_exit(void)

{

misc_deregister(&misc);

}


模块卸载代码实现的功能是将按键的混杂设备从内核中取消注册。


3、设备打开

设备打开代码主要实现了按键对应的GPIO接口的初始化。


static int s3c64xx_buttons_open(struct inode *inode, struct file *file)

{

    int i;

    int err = 0;

    

    for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {

if (button_irqs[i].irq < 0) {

continue;

}

        err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH, 

                          button_irqs[i].name, (void *)&button_irqs[i]);

        if (err)

            break;

    }

 

    if (err) {

        i--;

        for (; i >= 0; i--) {

    if (button_irqs[i].irq < 0) {

continue;

    }

    disable_irq(button_irqs[i].irq);

            free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

        }

        return -EBUSY;

    }

 

    ev_press = 1;

    

    return 0;

}


在这段代码中,使用request_irq()函数用来初始化GPIO接口,主要是开启了GPIO接口的输入中断功能,将中断号与中断处理函数、中断描述结构体绑定在一起。其中,button_irqs[i].irq是中断号,buttons_interrupt是中断处理函数,(void *)&button_irqs[i]是指向中断描述结构体的指针,函数还将中断的模式设置为双边沿触发。当按下或松开按键时,会产生下降沿或上升沿,就会触发中断,中断会把相应的中断描述结构体保持下来,并转到buttons_interrupt函数去处理中断。


buttons_interrupt()函数的源码如下所示。


static irqreturn_t buttons_interrupt(int irq, void *dev_id)

{

struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;

int down;

int number;

unsigned tmp;

 

udelay(0);

number = button_irqs->number;

switch(number) {

case 0: case 1: case 2: case 3: case 4: case 5:

tmp = readl(S3C64XX_GPNDAT);

down = !(tmp & (1< break;

case 6: case 7:

tmp = readl(S3C64XX_GPLDAT);

down = !(tmp & (1 << (number + 5)));

break;

default:

down = 0;

}

 

if (down != (key_values[number] & 1)) {

key_values[number] = '0' + down;

 

        ev_press = 1;

        wake_up_interruptible(&button_waitq);

    }

 

    return IRQ_RETVAL(IRQ_HANDLED);

}


中断处理函数的重要输入是中断描述结构体dev_id,结构体内部包含了,中断号、按键编号、以及按键名。程序根据按键编号对GPIO数据寄存器的值进行读取,从而判断外部输入电平的状态,并将按键状态保存到key_values[ ]数组中,‘1’代表按键按下,‘0’代表按键没有按下。当按键状态有变化时,程序调用wake_up_interruptible(&button_waitq);将阻塞的内核排队队列唤醒。


4、设备关闭

设备关闭代码如下所示


static int s3c64xx_buttons_close(struct inode *inode, struct file *file)

{

    int i;

    

    for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {

if (button_irqs[i].irq < 0) {

    continue;

}

free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

    }

 

    return 0;

}


功能比较简单,主要是将按键的中断功能禁止。


5、设备读取

设备的读取代码主要是读取8个按键的状态,代码如下。


static int s3c64xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

{

    unsigned long err;

 

    if (!ev_press) {

if (filp->f_flags & O_NONBLOCK)

    return -EAGAIN;

else

    wait_event_interruptible(button_waitq, ev_press);

    }

    

    ev_press = 0;

 

    err = copy_to_user((void *)buff, (const void *)(&key_values), min(sizeof(key_values), count));

 

    return err ? -EFAULT : min(sizeof(key_values), count);

}

代码实现的功能是将设备状态数组key_values[ ]回传到用户程序的buf中。


6、设备阻塞

设备阻塞函数是用来相应用户空间的select()系统调用函数的,代码如下


static unsigned int s3c64xx_buttons_poll( struct file *file, struct poll_table_struct *wait)

{

    unsigned int mask = 0;

    poll_wait(file, &button_waitq, wait);

    if (ev_press)

        mask |= POLLIN | POLLRDNORM;

    return mask;

}


阻塞函数功能比较简单,是在没有按键按下或松开时将程序阻塞,当有按键按下或松开时退出阻塞状态。


二、测试代码分析

编写了一个简单的测试代码对按键的驱动进行测试,代码如下。


int main()

{

int fd_led,fd_key;

fd_set read_set;

int max_fd;

struct timeval timeout;

int ret;

 

char buf[8];

 

fd_led = open("/dev/leds",0);

fd_key = open("/dev/buttons",O_RDONLY);

 

if(fd_led<0||fd_key<0)

{

fprintf(stderr,"can't open leds or buttons!n");

return 1;

}

 

while(1)

{

//清零描述符集合

FD_ZERO(&read_set);

FD_SET(fd_key,&read_set);

max_fd = fd_key;

//设置超时时间

timeout.tv_sec=3;

timeout.tv_usec=0;

ret = select(max_fd+1, &read_set, 0, 0, &timeout);

 

if(ret>0)

{

read(fd_key,buf,8);

if(buf[0]=='1')

{

ioctl(fd_led,1,0);

}

else

{

ioctl(fd_led,0,0);

}

 

if(buf[1]=='1')

{

ioctl(fd_led,1,1);

}

else

{

ioctl(fd_led,0,1);

}

 

if(buf[2]=='1')

{

ioctl(fd_led,1,2);

}

else

{

ioctl(fd_led,0,2);

}

 

if(buf[3]=='1')

{

ioctl(fd_led,1,3);

}

else

{

ioctl(fd_led,0,3);

}

}

}

 

close(fd_key);

close(fd_led);

 

return 0;

}


在这个代码中,通过select()函数将程序阻塞,等待按键的状态变化。当按键状态有变化时,读取按键状态,并根据按键状态对LED灯进行控制。当按键按下时,将相应的LED灯点亮;松开按键时,将相应的LED灯熄灭。


推荐阅读

史海拾趣

静芯微电子(ElecSuper)公司的发展小趣事

静芯微电子深知产品质量对于企业的重要性,因此建立了完善的质量管理体系。公司从原材料采购、生产制造到产品检测等各个环节都实行严格的质量控制和管理,确保每一款产品都符合高标准的质量要求。同时,静芯微电子还引进了先进的检测设备和技术手段,对产品质量进行全面检测和评估。这些措施保证了静芯微电子产品的稳定性和可靠性,赢得了客户的信任和好评。

APC (APC by Schneider Electric)公司的发展小趣事

APC的产品和服务在全球范围内赢得了广泛认可。其InfraStruXure产品线因其集成式的电力、制冷、机架、管理和服务实现了一种开放、具有适应性且集成化的解决方案,赢得了近20个奖项。此外,APC还因其卓越的产品和业务表现,在多个年份赢得了全球100多个奖项。这些奖项不仅证明了APC在电子行业中的领先地位,也反映了其对于创新和质量的不懈追求。

Adamant Co Ltd公司的发展小趣事

品质是电子行业的生命线。Adamant Co Ltd深知这一点,因此在品质管理方面下足了功夫。公司建立了严格的品质管理体系,从原材料采购到产品生产、检测、出厂等各个环节都严格把关。同时,公司还注重品牌建设,通过提升产品形象和服务质量,赢得了客户的信任和口碑。这些努力使得Adamant Co Ltd在行业中树立了良好的品牌形象。

爱浦电子(AIPULNION)公司的发展小趣事

面对日益激烈的市场竞争,爱浦电子始终坚持创新驱动的发展战略。公司不断投入研发资金,引进先进技术和设备,推动产品创新和技术升级。同时,爱浦电子还积极探索新的应用领域和市场机会,拓展产品的应用范围。这些创新举措为公司未来的发展奠定了坚实的基础,也为整个电子行业的发展注入了新的活力。

Belden Wire & Cable公司的发展小趣事

在1902年,Joseph C. Belden在美国芝加哥创立了Belden公司,标志着这家电线电缆公司的诞生。创立初期,公司便专注于电线电缆的研发和生产,凭借其卓越的产品质量和可靠的性能,逐渐在市场上崭露头角。随着业务的发展,Belden逐渐扩大了生产规模,并增设了多个生产基地,以满足不断增长的市场需求。

DLG Hanbit公司的发展小趣事

随着环保意识的提高,DLG Hanbit公司开始注重环保和可持续发展。公司引进了一系列环保设备和技术,减少了生产过程中的污染物排放。同时,公司还积极推广绿色电子产品,帮助客户实现节能减排。这种环保理念不仅提升了公司的社会形象,也为公司的可持续发展奠定了基础。

问答坊 | AI 解惑

大家尽量说说自己使用过哪款DSP和心得

我先说吧 我用过TI的TMS320VC5402和5502,那是第一次接触DSP,有存储器映射的概念 用过LSI的ZSP系列的DSP,发现编译器老有bug 用过ADI的BLACKFIN,编译器还不错,开发较简单,存储器有L1,L2和L3等区分,现在单位要用ADI的最底端DSP,adsp-218x ...…

查看全部问答>

一份AVR单片机产生PWM的技术资料

一份AVR单片机产生PWM的技术资料,英文版的,需要的可以参考…

查看全部问答>

传感器150例

本帖最后由 paulhyde 于 2014-9-15 03:31 编辑 大赛在即,给大家分享点重要资料。肯定能用到  …

查看全部问答>

征婚启事

我,女,25岁,身高170,相貌一般,但是为人大方真诚,乐观自信,在温州从事单片机的开发工作,想找一个以下条件的男朋友(当然,发展的好的话,最好是能终身相伴到老的) 1.身高175以上,本科以上学历(我是本科生) 2.品德优秀,责任感强 3.对 ...…

查看全部问答>

软件开发工程师,急求,兼职亦可

移动软件开发工程师          职位要求: 1、嵌入式平台(WinCE,平台),应用软件开发; 2、熟悉J2ME开发。 3、具有良好的团队精神。 4、一年以上WinCE平台开发经验。 请有意者将简历mail至 suntjl@sina.com ...…

查看全部问答>

请问高手要做一个LCD显示广告语同时带声音

这功能在单片机上可以实现吗?对于单片机用什么方法可以烧写里面的程序? 谢谢各位高手为小弟解答..…

查看全部问答>

移植问题!

把一个windows下的程序移植到Vxworks上,需要做那些工作啊。 现在的代码基本都是ASNI C和C++写。 …

查看全部问答>

初学AVR 各位大侠 帮帮忙

51差不多学完了,现想学AVR  在学校图书馆搜了 ,搜到>就是借不到  ,各位大侠 还有什么好的推荐吗?   还有该怎样学起  ?    …

查看全部问答>

MAX1640的充电电流变小了

昨晚,发完贴,看了一会书后,我又拿起板子看,结果发现,有一些很小的线短路了,额滴神,还是很要命的短路。 这个是因为之前板子割了太多的线,最后补线的时候,线太小了,不小心碰上了而没有察觉。 我立马修复好,然后试图上电,发现正常了很多 ...…

查看全部问答>

TI M3资料 集锦(超好、超全、超完备)

在百度文库花了我一二百金币给大家淘来了些TI M3的资料,希望对大家能有所帮助 [ 本帖最后由 鑫海宝贝 于 2011-4-21 09:41 编辑 ]…

查看全部问答>