|
发表于 2010-6-12 17:55:10
|
显示全部楼层
我也觉得现在在网上的资料要么是供初学者用的,要么是功能很强,但是只是演示性质(晒),或者是卖广告的。
幸亏我们这个论坛的高手们都不吝赐教啊!代表所有初学者向你们致敬!
再说说楼主所提到的释放CPU、按键处理,我简单地说说我的看法(仅供参考)。
释放CPU:在你所建立的工程不是很复杂并且实时性要求不高的时候,你不懂这个概念的话貌似问题不大,但是倘若你所设计的系统实时性要求较强时,你没有考虑过释放CPU,那你做出来的系统将是问题多多的。
举个例子:做一个简单的门禁系统(真的是很简单的,高手们看到不能偷笑哦),有上位机、下位机,下位机需要串口与上位机进行通讯,两者的通讯协议是多字节的帧结构;下位机需要扫描按键,检查是否有按键按下,按键是由数字键和几个功能键组成;还要LCD显示。
对于这个系统,按键扫描可采用“零耗时扫描”以及查表法来选择返回键码值的方式,这样设计的话,按键消抖处理的延时就可以用定时器来完成,不用CPU去软件延时;键盘扫描利用查表法的话,可以使得程序结构简单,不用太多的重复,也不用一大堆switch{case:……}结构,整个键盘扫描程序就一个循环查表搞定。
与上位机通信这个模块,可以声明两个缓冲区,一个缓冲区(buffer1)是放置当前在接收中的帧,另外一个(buffer2)是放置已经接收完的帧。帧接收工作最好放在串口中断中完成,当接收完成即将buffer1的内容转到buffer2当中去,并将接收完成标志置1,让主程序去处理帧。
如此一来,主程序就没有延时语句,就是循环判断各个标志位,若标志有效才去工作。
按键处理:对于4X4键盘,可能很多像我一样的初学者都用或者用过类似下面程序的方法去扫描。下面说说基于查表法的键盘扫描方法
unsigned char key_check(void)
{
unsigned char code table[]={0x01,0x02,0x03,0x0a,
0x04,0x05,0x06,0x0b,
0x07,0x08,0x09,0x0c,
0x0f,0x00,0x0e,0x0d};
unsigned char temp;
unsigned char key;
unsigned char i,j;
unsigned char key_number=0xff;
unsigned int kk=0;
while(kk<=2)
{
kk=kk+1;
P2=0xff;
P2_4=0;
temp=P2;
temp=temp&0x0f;
if (temp!=0x0f)
{
for(i=100;i>0;i--)
for(j=200;j>0;j--);
temp=P2;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P2;
temp=temp&0x0f;
switch(temp)
{
case 0x07:
key=0;
break;
case 0x0b:
key=4;
break;
case 0x0d:
key=8;
break;
case 0x0e:
key=12;
break;
default:
break;
}
temp=P2;
key_number=table[key];
temp=temp&0x0f;
while(temp!=0x0f) //等待按键放开
{
temp=P2;
temp=temp&0x0f;
}
return key_number;
}
}
P2=0xff;
P2_5=0;
temp=P2;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=100;i>0;i--)
for(j=200;j>0;j--);
temp=P2;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P2;
temp=temp & 0x0f;
switch(temp)
{
case 0x07:
key=1;
break;
case 0x0b:
key=5;
break;
case 0x0d:
key=9;
break;
case 0x0e:
key=13;
break;
}
temp=P2;
key_number=table[key];
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P2;
temp=temp&0x0f;
}
return key_number;
}
}
P2=0xff;
P2_6=0;
temp=P2;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=50;i>0;i--)
for(j=200;j>0;j--);
temp=P2;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P2;
temp=temp & 0x0f;
switch(temp)
{
case 0x07:
key=2;
break;
case 0x0b:
key=6;
break;
case 0x0d:
key=10;
break;
case 0x0e:
key=14;
break;
}
temp=P2;
key_number=table[key];
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P2;
temp=temp & 0x0f;
}
return key_number;
}
}
P2=0xff;
P2_7=0;
temp=P2;
temp=temp & 0x0f;
if (temp!=0x0f)
{
for(i=100;i>0;i--)
for(j=200;j>0;j--);
temp=P2;
temp=temp & 0x0f;
if (temp!=0x0f)
{
temp=P2;
temp=temp & 0x0f;
switch(temp)
{
case 0x07:
key=3;
break;
case 0x0b:
key=7;
break;
case 0x0d:
key=11;
break;
case 0x0e:
key=15;
break;
}
temp=P2;
key_number=table[key];
temp=temp & 0x0f;
while(temp!=0x0f)
{
temp=P2;
temp=temp & 0x0f;
}
return key_number;
}
}
}
return 0xff;
}
查表键盘扫描法:
首先,先建立一个表,
//键盘扫描所用的表格
//格式:输出值、输入值、对应的键码
unchar code KeyScanTable[48]={
0xef,0x0e,0x00,
0xef,0x0d,0x04,
0xef,0x0b,0x08,
0xef,0x07,0x0c,
0xdf,0x0e,0x01,
0xdf,0x0d,0x05,
0xdf,0x0b,0x09,
0xdf,0x07,0x0d,
0xbf,0x0e,0x02,
0xbf,0x0d,0x06,
0xbf,0x0b,0x0a,
0xbf,0x07,0x0e,
0x7f,0x0e,0x03,
0x7f,0x0d,0x07,
0x7f,0x0b,0x0b,
0x7f,0x07,0x0f};
然后在键盘扫描程序里面就只需要一个循环去查表即可(注意下面的程序是没有消抖处理的,是在定时器中断服务程序中调用)
unchar KeyScan_No_Delay()
{
unchar i,base_addr;
unchar data_in;
P2=0x0f;
if(P2==0x0f) //说明没有按键按下
return 0xff;
for(i=0;i<=0x0e;i++)
{
base_addr=i*0x03;
P2=KeyScanTable[base_addr]; //输出
_nop_();
_nop_();
data_in=P2; //读入
if(data_in==KeyScanTable[base_addr+1]) //比较,若相同则返回对应的键码
return KeyScanTable[base_addr+2];
}
}
写地不好,请见谅。
That's all.(别拍砖呐!) |
|