我是新手,不要嘲笑我,希望这些例程对正在受“天祥”大叔的按键子程序残害的人有所帮助吧
希望大家都能用上状态机。
谢谢马老师的例程。
==================================================================================
独立按键(简单的状态机,无连_发)
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit led=P0^0;
void delay()
{
uint i,j;
for(i=100;i>0;i--)
for(j=118;j>0;j--);
}
uchar readkey()
{
static keystate=0,keytime=0;
uchar keypress,keyreturn=0;
keypress=P1;
switch(keystate)
{
case 0:
if (keypress!=0xff)
{
keystate=1;
}
break;
case 1:
if (keypress!=0xff)
{
keystate=2;
keytime=0;
}
else
keystate=0;
break;
case 2:
if (keypress==0xff)
{
keystate=0;
keyreturn=1;
}
else if (++keytime>=20000)
{
keystate=3;
keytime=0;
keyreturn=2;
}
break;
case 3:
if (keypress==0xff)
{
keystate=0;
}
else
{
if (++keytime>=10000)
{
keytime=0;
keyreturn=2;
}
}
break;
}
return keyreturn;
}
void main()
{
uchar k;
while(1)
{
switch(readkey())
{
case 1:
led=!led;
break;
case 2:
P0=0xfe;
for(k=0;k<8;k++)
{
delay();
P0=P0<<1|0X01;
}
break;
}
}
}
注:该子程序最好在中断设置标志位,10ms进入检测一次即可。本例程没有,为了方便。
=================================================================================================
矩阵键盘状态机(4×4,无连_发)
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define nokey 255
#define keymask 0x0f
sbit cs1=P1^0;
sbit cs2=P1^1;
sbit clk=P1^2;
uchar code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
uchar num,timecount=0;
bit timeok;
void delay_us(uint us)
{
while(--us);
}
//==============================延时子程序==================================
void delay_ms(uint ms)
{
uint i,j;
for(i=ms;i>0;i--)
for(j=118;j>0;j--);
}
//==============================显示子程序=================================
void display(void)
{
P2=tab[num];
cs1=0;
clk=0;clk=1;
cs1=1;
P2=0xfe;
cs2=0;
clk=0;clk=1;
cs2=1;
delay_ms(1);
}
//============================矩阵键盘按键状态机========================
uchar readkeyboard()
{
static uchar keystate=0,keyvalue,keyline;
uchar keyreturn=nokey,i;
switch(keystate)
{
case 0:
keyline=0x10;
for (i=1;i<=4;i++)
{
P0=~keyline;
P0=~keyline;
keyvalue=keymask&P0;
if (keyvalue==keymask)
{
keyline<<=1;
}
else
{
keystate++;
break;
}
}
break;
case 1:
if (keyvalue==(keymask&P0))
{
switch(keyline|keyvalue)
{
case 0x87:keyreturn=0;break;
case 0x8b:keyreturn=1;break;
case 0x8d:keyreturn=2;break;
case 0x8e:keyreturn=3;break;
case 0x47:keyreturn=4;break;
case 0x4b:keyreturn=5;break;
case 0x4d:keyreturn=6;break;
case 0x4e:keyreturn=7;break;
case 0x27:keyreturn=8;break;
case 0x2b:keyreturn=9;break;
case 0x2d:keyreturn=10;break;
case 0x2e:keyreturn=11;break;
case 0x17:keyreturn=12;break;
case 0x1b:keyreturn=13;break;
case 0x1d:keyreturn=14;break;
case 0x1e:keyreturn=15;break;
}
keystate++;
}
else
keystate--;
break;
case 2:
P0=0x0f;
P0=0x0f;
if ((keymask&P0)==keymask)
{
keystate=0;
}
break;
}
return keyreturn;
}
//==============================主程序==========================
void main()
{
uchar keytemp;
TMOD=0x01;
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
EA=1;
ET0=1;
TR0=1;
while(1)
{
if (timeok)
{ keytemp=readkeyboard();
if (keytemp!=nokey)
{
num=keytemp;
}
}
}
}
//=================================中断服务子程序====================
void timer0() interrupt 1
{
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
display();
if (++timecount>=5)
{
timecount=0;
timeok=1;
}
}
================================================================================
以上都是自己写的程序,希望不要喷我,我就是想让初学者的朋友们使用上状态机~
完
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
static 静态局部变量定义
简单的说就是跳出该子程序后变量值不变,类似于全局变量。因为是按键状态的识别,所以不希望跳出子程序后变量的值清零。
bit 是位定义 简单的说该定义后的变量只有两种状态:“0”“1”
uchar是#define uchar unsigned char 的意思
-----------------------------------------------------------------------
1:
bit 明白了,也就是说它的值是两种状态0和1,如果把100这个数据赋给它,它的值也只会是1,是这样理解吗?呵呵
2:
static ...类似于全局变量...,我似乎明白了一半,那为什么不直接在程序最前面直接定义为全局变量啊,全局变量跳出子程序后变量值也不变啊!
呵呵,希望楼主再指教一二!
-----------------------------------------------------------------------
请问一下。dat = (bit)(0x80 & 0x90); 结果是不是等于1呀。如果用到bit是不是非0为1呀。
-----------------------------------------------------------------------
扫描法怎么了 不就多10几个毫秒吗 一样用
//////////////////////////////////////////////////////////////////////////////////
//扫描法:逐行扫描查询 一般用在按键比较少的场合
int keyscan()
{
unsigned char k k_temp;
P1=0xf0; //低位置0,准备查询按键
k=P1; //取得当前P1口状态
if(k!=0xf0) //如果有变化则表示有按键按下
{
delay(10); //延迟 消抖
k_temp=p1;
if(k==k_temp) //确实有键按下
{
k=0xfe;
do //循环扫描每一行
{
p1=k;
if(k!=p1)
{
switch(P1) //判断按键 并返回键值
{
//第1行
case 0x7e:{return 0; break;}
case 0xbe:{return 1; break;}
case 0xde:{return 2; break;}
case 0xee:{return 3; break;}
//第2行
case 0x7d:{return 4; break;}
case 0xbd:{return 5; break;}
case 0xdd:{return 6; break;}
case 0xed:{return 7; break;}
//第3行
case 0x7b:{return 8; break;}
case 0xbb:{return 9; break;}
case 0xdb:{return 10;break;}
case 0xeb:{return 11;break;}
//第4行
case 0x77:{return 12;break;}
case 0xb7:{return 13;break;}
case 0xd7:{return 14;break;}
case 0xe7:{return 15;break;}
}
}
k=_crol_(k,1); //移位 进入下一行扫描
}
while(k!=0xef); //超过列范围 退出扫描
}
}
}
////////////////////////////////////////////////////////////////////////////////
//线反转法 :只需2步便可获得按键位置
unsigned int keyboar()/*线反转法 */
{
static unsigned int a=0;
unsigned char a1=0,b1=0;
/*行线为输入线,列线为输出线 */
v1=v2=v3=v4=0;
h1=h2=h3=h4=1;
if(P2<0xf0)/*检查行是否有按键按下 */
{
delayms(10);
if(P2<0xf0)
{
/*行线为输入线,列线为输出线 */
v1=v2=v3=v4=0;
h1=h2=h3=h4=1;
a1=P2;
/*行线为输出线,列线为输入线 */
h1=h2=h3=h4=0;
v1=v2=v3=v4=1;
b1=P2;
a=a1|b1;
}
}
if (a==0xe7){return 7; }
else if(a==0xeb){return 8; }
else if(a==0xed){return 9; }
else if(a==0xee){return 13;}
else if(a==0xd7){return 4; }
else if(a==0xdb){return 5; }
else if(a==0xdd){return 6; }
else if(a==0xde){return 12;}
else if(a==0xb7){return 1; }
else if(a==0xbb){return 2; }
else if(a==0xbd){return 3; }
else if(a==0xbe){return 11;}
else if(a==0x77){return 0; }
else if(a==0x7b){return 15;}
else if(a==0x7d){return 16;}
else if(a==0x7e){return 10;}
else return 17;
}
///////////////////////////////////////////////////////////////////////////////
中断法:只有按键按下才发出中断 扫描函数写在中断里 用在复杂的系统 或者对实时性要求比较高的场合
void t0()interrupt 0
{
key=keyscan();
}
一周热门 更多>