Linux矩阵键盘驱动程序,中断服务程序中控制中断的问题,希望友人帮助

[复制链接]
查看11 | 回复9 | 2021-1-27 06:19:20 | 显示全部楼层 |阅读模式
主芯片使用s3c2440,arm芯片
内核版本使用的是linux-2.6.30.4
驱动程序使用模块装载方式
这是一个6×7的矩阵键盘,6行设置成中断模式的IO口,外接10k上拉电阻;
常态下6行端口都成高电平;
7列为扫描口,设置为输出模式的IO口,外接二极管;
常态下7列端口都设置成低电平;
以上参见函数port_init();
当按键按下时,某行和某列接通,某一行端口被拉低,产生下降沿(使用下降沿中断),即确定了行端口,进入中断服务程序;
在中断服务程序中,通过端口的0111111(低电平依次移动在不同的列扫描端口上),来确认接通的是列端口;
参见函数key_scan();
问题是列扫描过程中会产生新的下降沿中断信号,为了避免这种情况,我在列扫描之前使用函数disable_irq(),来关闭中断;但是这个函数不好用,不但关闭中断而且这个函数执行完,就立即退出了中断服务程序,后面的键盘扫描都没执行;
查过资料disable_irq函数应该是能保证接下来的程序能继续执行的,会不会是2.6.30内核版本问题;
有没有别的方法解决?
希望大家能帮我解决这个问题或提出好的建议!
structbutton_desc
{
intpin;
intset_outp;
};
structbutton_irq_desc
{
intirq;
intpin;
intset_eint;
intset_inp;
introw;
char*name;
};
staticstructbutton_irq_descbutton_cfg_row[]=//6个IO口作为,中断口
{
{IRQ_EINT1,S3C2410_GPF1,S3C2410_GPF1_EINT1,S3C2410_GPF1_INP,1,"KEY1"},
{IRQ_EINT2,S3C2410_GPF2,S3C2410_GPF2_EINT2,S3C2410_GPF2_INP,2,"KEY2"},
{IRQ_EINT3,S3C2410_GPF3,S3C2410_GPF3_EINT3,S3C2410_GPF3_INP,3,"KEY3"},
{IRQ_EINT4,S3C2410_GPF4,S3C2410_GPF4_EINT4,S3C2410_GPF4_INP,4,"KEY4"},
{IRQ_EINT5,S3C2410_GPF5,S3C2410_GPF5_EINT5,S3C2410_GPF5_INP,5,"KEY5"},
{IRQ_EINT6,S3C2410_GPF6,S3C2410_GPF6_EINT6,S3C2410_GPF6_INP,6,"KEY6"},
};
staticstructbutton_descbutton_cfg_col[]=
{
{S3C2440_GPJ0,S3C2440_GPJ0_OUTP},
{S3C2440_GPJ1,S3C2440_GPJ1_OUTP},
{S3C2440_GPJ2,S3C2440_GPJ2_OUTP},
{S3C2440_GPJ3,S3C2440_GPJ3_OUTP},
{S3C2440_GPJ4,S3C2440_GPJ4_OUTP},
{S3C2440_GPJ5,S3C2440_GPJ5_OUTP},
{S3C2440_GPJ6,S3C2440_GPJ6_OUTP},
{S3C2440_GPJ7,S3C2440_GPJ7_OUTP},
};
staticintkey_scan(void)
{
inti,row,col,ret=0;
for(col=0;colname);
disable_irq(button_cfg_row->irq);
//disable_irq(),关闭中断,问题就出在这,中断是关闭了,但程序也从这退出了,
//接下来扫描键盘的工作都没执行;
//如果不执行这句,不关中断,在整个按键按下的过程中总是不断的在进入这个中断服务程序,
//产生n多个按键按下的信号;
printk("1\n");
for(i=0;iirq);
returnIRQ_RETVAL(IRQ_HANDLED);
}
staticintEmbedSky_buttons_open(structinode*inode,structfile*file)
{
inti;
interr;
port_init();
for(i=0;i=0;i--)
{
disable_irq(button_cfg_row.irq);
free_irq(button_cfg_row.irq,(void*)&button_cfg_row);
}
printk("buttonopenErr%d\n",err);
return-EBUSY;
}
printk("buttonopenok\n");
return0;
}

分 -->
回复

使用道具 举报

千问 | 2021-1-27 06:19:20 | 显示全部楼层
踩一下
回复

使用道具 举报

千问 | 2021-1-27 06:19:20 | 显示全部楼层
你可以写个判断语句,产生下一个中断前判断当前中断是否为前一个中断,是则不执行。或者,你在处理完一个中断之后,来一个长延迟。丢弃后来多余的信号
回复

使用道具 举报

千问 | 2021-1-27 06:19:20 | 显示全部楼层
硬件有抖动的,这种按键驱动不应当使用中断来检测,尝试改成中断+轮循方式吧。
我做过类似的按键驱动,最初是在优龙的YLP2440上做的,后来移植到友善之臂的QQ2440上,再后来在某智能设备上使用,一直挺好用的,实现方案就是中断+轮循。
回复

使用道具 举报

千问 | 2021-1-27 06:19:20 | 显示全部楼层
引用3楼armed的回复:硬件有抖动的,这种按键驱动不应当使用中断来检测,尝试改成中断+轮循方式吧。
我做过类似的按键驱动,最初是在优龙的YLP2440上做的,后来移植到友善之臂的QQ2440上,再后来在某智能设备上使用,一直挺好用的,实现方案就是中断+轮循。

能讲细点不?我也遇到这样的问题,按一次键响应好几次。
轮循怎么用?

回复

使用道具 举报

千问 | 2021-1-27 06:19:20 | 显示全部楼层
最好的方法是在关闭中断后,启动定时器进行去抖,在定时到函数中进行键盘扫描,扫描完成后再重新打开中断。
回复

使用道具 举报

千问 | 2021-1-27 06:19:20 | 显示全部楼层
我正在做键盘扫描,不知道这些大侠做完了,能否提供源码参考!
回复

使用道具 举报

千问 | 2021-1-27 06:19:20 | 显示全部楼层
中断中应该首先清中断标志。
disable_irq()应该可以在中断中调用的,我在2.6.27.8中用是没问题的。
建议改成这样的思路:在中断中禁用中断并调度任务队列,在中断底半部中延时去抖,扫描完按键之后再开中断。
回复

使用道具 举报

千问 | 2021-1-27 06:19:20 | 显示全部楼层
中断+定时器就可以解决问题!
回复

使用道具 举报

千问 | 2021-1-27 06:19:20 | 显示全部楼层
用中断方式,会出现按键联动,而且因为按键抖动没处理好,会出现“按一次按键,响应还几次”的情况。这种情况最终会严重影响服务AP运行。
而且你在中断服务处理函数中,用直接延时的方式去抖动,会系统变慢,严重情况可能出现意想不到的结果。
个人觉得最好的方式采用定时扫描的方式。可以每隔200mS扫描一次键盘,根据前后两次扫描结果的一致性判断是否出现按键抖动,这样的方式相对而言占用资源少,而且按键比较好处理。我们以前也是用中断加定时器轮询,结果很容易出现按键联动,后来才采用定时扫描的方式,而且系统运行很稳定。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行