单片机实现对按键的定时扫描 哪位高手能帮忙把下面按键扫描程序改成用定时器对按键进行定时扫描啊,我用的

2025-03-02 14:42:11
推荐回答(3个)
回答1:

楼主的那个程序我看不太懂:不过根据你的大概意思更改了一下程序,希望对你有帮助!下面是我的程序代码:

/********************************************************************

* 文件名  : 矩阵键盘.c

* 描述    :  该文件实现了 4 * 4 键盘的试验。通过数码管的最后一位来显示

 当前的按键值。

*********************************************************************/

#include

#include

#define uint unsigned int

#define uchar unsigned char

uchar code table[16] = {0x3f,0x06,0x5b,0x4f,

0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,

0x39,0x5e,0x79,0x71}; //用于数码管显示 本程序未用

uchar Key;  //读出的键值

/********************************************************************

* 名称 : Delay_1ms()

* 功能 : 延时子程序,延时时间为 1ms * x

* 输入 : x (延时一毫秒的个数)

* 输出 : 无

***********************************************************************/

void Delay_1ms(uint i)//1ms延时

{

uchar x,j;

for(j=0;j

for(x=0;x<=148;x++);

}

/********************************************************************

* 名称 : delay()

* 功能 : 延时,延时时间大概为140US。

* 输入 : 无

* 输出 : 无

***********************************************************************/

void delay()

{

int i,j;

for(i=0; i<=10; i++)

for(j=0; j<=2; j++);

}

/********************************************************************

* 名称 : Keyscan()

* 功能 : 实现按键的读取。下面这个子程序是按处理 矩阵键盘 的基本方法处理的。

* 输入 : 无

* 输出 : 按键值

***********************************************************************/

uchar Keyscan(void)

{

uchar i,j, temp, Buffer[4] = {0xef, 0xdf, 0xbf, 0x7f};

for(j=0; j<4; j++)

{

P1 = Buffer[j];

temp = 0x01;                                                                                                                                                                    

for(i=0; i<4; i++)

{

if(!(P1 & temp)) 

{

return (i+j*4);   //这里返回的是按键牌排列值!

}

temp <<= 1;

}

}

}

/********************************************************************

* 名称 : InitTimer0()

* 功能 : 用于定时器初始化。

* 输入 : 无

* 输出 : 

***********************************************************************/

unsigned int Timer_1s=0;//定时器中断响应次数变量

//定时时间长度=定时中断响应时间*定时中断响应次数

void InitTimer0()

{

//    AUXR=0x80;  //定时时钟为Sysclk,即晶振时钟 实用于具有单时钟周期的单片机系列

//特别的还需要注意时钟设置在其它模块中的设置,如波特率的定时器1时钟设置

TMOD = 0x21; //定时器0工作于方式1,,16位定时,定时器1为波特率发生器

//特别地,高四位控制定时器1,低四位控制定时器0,

//所以此处需要注意程序中是否并存定时器1工作,如串口就需要定时1的设置为TMOD=0x20

    

    TH0 = 0x0B8; //定时装如初值   //定时1000us 即1ms

    TL0 = 0x00; //定时其它值可由需要重新计算初值

    ET0 = 1; //允许中断

    TR0 = 1; //启动定时器

}

/********************************************************************

* 名称 : Timer0Interrupt()interrupt 1

* 功能 : 定时器中断。

* 输入 : 无

* 输出 : 

***********************************************************************/

void Timer0Interrupt() interrupt 1

{

    TR0 = 0; //关闭定时器

TH0 = 0x0B8; //重装初值

    TL0 = 0x00;

    Timer_1s++; //中断响应次数自加1

if(Timer_1s=20) //可以在此处调节按键的扫描时间

{

/*一下是扫描按键并带返回值的结果*/

P1 = 0xf0;

if(P1 != 0xf0)

{

Delay_1ms(15); //按键消抖

if(P1 != 0xf0)

{

Key = Keyscan();

}

}

}

TR0 = 1; //启动定时器

}

/********************************************************************

* 名称 : Main()

* 功能 : 主函数

* 输入 : 无

* 输出 : 无

***********************************************************************/

void Main(void)

{

                InitTimer0();//初始化定时器

         EA =1;       //开中断

while(1)

{

switch (Key) //判断键值(那一个键按下)

case 0: /*加入需要执行该按键下的程序*/; break;  //假设0号按键被按下

case 1: /*加入需要执行该按键下的程序*/; break; 

case 2: /*加入需要执行该按键下的程序*/; break; 

case 3: /*加入需要执行该按键下的程序*/; break; 

case 4: /*加入需要执行该按键下的程序*/; break; 

case 5: /*加入需要执行该按键下的程序*/; break; 

case 6: /*加入需要执行该按键下的程序*/; break; 

case 7: /*加入需要执行该按键下的程序*/; break; 

case 8: /*加入需要执行该按键下的程序*/; break; 

case 9: /*加入需要执行该按键下的程序*/; break; 

case 10: /*加入需要执行该按键下的程序*/; break; 

case 11: /*加入需要执行该按键下的程序*/; break; 

case 12: /*加入需要执行该按键下的程序*/; break; 

case 13: /*加入需要执行该按键下的程序*/; break; 

case 14: /*加入需要执行该按键下的程序*/; break; 

case 15: /*加入需要执行该按键下的程序*/; break;   

default: break;

}

}

}

回答2:

办法1、直接把你编写的这部分程序拷到中断服务中,注意变量的声明,注意其他位置不好调用keyi()和delay()了。风险是按住键不松开的话,会影响中断的时间。楼上兄弟意识到这个问题,但解决的不够完美。
办法2、针对你的设计,我写了个50mS中断扫描做的行反转读键,你调调看。通过判断按键次数来去抖,松开时处理。如果需要连续处理,也可稍微改动下完成。在main主程序中分支语句处理CurrentKey,处理完后清零即可。【个人认为,我的比较精炼点,欢迎砸砖】

unsigned char CurrentKey;
void ISRForT0(void) interrupt 1
{
unsigned char key;
static unsigned char LastKey=0,dd=0;
TH0=(-50000)>>8;
TL0=(-50000)&0xff;

//P1=0xf0;//无需延时,退出时预置,此处取掉。
key=P1;
P1=key|0xf; P1=key|0xf; P1=key|0xf; P1=key|0xf;//简单延时
key=P1;
P1=0xf0;

if(key==0xff) //键松开处理
{
if(dd>(200/50)) //1、假设200mS抖动,50为实际定时时间。
{
CurrentKey=LastKey; //键值CurrentKey.
dd=0;
}
LastKey=0; //2、不满足抖动条件。
}

if((key==LastKey)&&(dd<100)) dd++;

if((key!=0xff)&&(key!=LastKey)) //新键按下
{LastKey=key; dd=0;} //保存新的按键。

}

回答3:

以TR0为例
void time_init(void)

{

TMOD=0x11;
TH0=(65536-t)/256; //time ms
TL0=(65536-t)%256;
ET0=1;
EA=1;
}

void time_0(void) interrupt 1
{
TH0=(65536-t)/256; //time ms
TL0=(65536-t)%256;
judge();//键扫描
//keyboard_mark=1;//若键扫描执行时间太长则不适用直接调用,加入扫描指针
}
bit keyboard_mark;
void main ()
{
system_set();//端口初始化
time_init();//定时器初始化
TR0=1;
/*
if(keyboard_mark)
{ judge();//键扫描
keyboard_mark=1;}
*/
}