马老师状态机按键程序请教!
#define key_input PIND.7 // 按键输入口#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
char read_key(void)
{
static char key_state = 0;
char key_press, key_return = 0;
key_press = key_input; // 读按键I/O电平
switch (key_state)
{
case key_state_0: // 按键初始态
if (!key_press) key_state = key_state_1; // 键被按下,状态转换到键确认态
break;
case key_state_1: // 按键确认态
if (!key_press)
{
key_return = 1; // 按键仍按下,按键确认输出为“1”
key_state = key_state_2; // 状态转换到键释放态
}
else
key_state = key_state_0; // 按键已抬起,转换到按键初始态
break;
case key_state_2:
if (key_press) key_state = key_state_0; //按键已释放,转换到按键初始态
break;
}
return key_return;
}
马老师:
看了你的状态机程序,有不怎么明白的。以前都是用的检测按键按下了延时10毫秒,再检测是否还按下,按下了再处理。用的都是软件死延时,用这个状态机程序的话是不是就不用在检测按键按下后插入10MS延时了,就直接可以按键处理了。 当然不用插入10MS延时,利用定时器产生10ms的标志,每隔10ms再去检测一次按键,这样做CPU的效率很高,要知道10ms单片机可以做很多的事情了. 恩 时基 比如下面,我定时 10MS 中断, 然后再主程序里检测 if(flag_10ms) { 按键处理 }啊? 还是直接就把扫描程序写在中断里呢?
void timer0_serves () interrupt 1 using 1
{
TH0 = 0XXX;
TL0 = 0XXX;
flag_10ms = 1;
} 取其标志就可以,当然不能将扫描程序写在中断里!!!! bit flag_keyscan = 0;
void key_scan(void)
{
....
....
}
int main(void)
{
while(1)
{
if(flag_keyscan)//10MS定时到,调用扫描
{
flag_keyscan = 0 ;
key_scan();
调用键盘扫描程序,
}
}
}
void timer0_init (void) interrupt 1
{
TH0 = 0XXX;//10ms
TL0 = 0XXX;
flag_keyscan = 1;
}
是这样写的吗,大概的结构示意,写在主函数里10MS调用下扫描程序,然后根据扫描的键值进行处理。谢谢 回复【5楼】fangmcu 方谭
取其标志就可以,当然不能将扫描程序写在中断里!!!!
-----------------------------------------------------------------------
这个回答不全面,容易造成误解。
将状态机按键扫描放在10毫秒定时中断中也是可以的,其最明显的优点是可以少用一个标志变量。
有许多的人喜欢将LED的动态扫描、按键扫描放在定时中断函数里直接处理。但是我个人并不推荐这样的设计。
首先,2个主要的因素需要注意:
1。LED的动态扫描,按键扫描要求的定时间隔在实际应用中并不要求十分严格。比如看本例的按键扫描,设计是10ms扫描一次。但实际上9.8\9.9\10\10.1\10.2....甚至11ms扫描一次也没问题。都能非常正确的扫描到按键的情况。
2。另外一个原则就是设计的中断服务函数执行时间应该尽量的短。这样假如系统中使用多个中断的话,就是不采用中断嵌套的方式,也能够保证系统能够及时响应各个中断的请求。
所以我喜欢在定时中断中只使用一个标志变量,这样中断服务函数执行时间是最快的,就不会阻塞其它中断的及时响应,而在主程序中判断标志变量,然后再去扫描按键。尽管此时扫描的间隔已经不是严格意义上的10ms,或多或少都有一些延误,而且延误也是不确定的,但都不会影响按键扫描的正确性(一个按键的过程至少在300ms以上)。 谢谢马老师,你严谨注学态度,真令我佩服. 这个需要学习 很好的帖子 顶起! 另一个思路。10ms定时,在定时器先读一次,利用2次10ms中断读出按键值。有去抖功效。 在主程序里按键,程序大了。根本保障不了10ms
10ms为心脏。 马老师解释的真好,关键是还能细心解答这种小问题,谢谢!
我也是刚刚有点明白状态机,和楼主的状态大概差不多。
我的理解是:
* 状态机就是把一个顺序的事情,分解成不同的阶段。当然这些状态是互斥的,即在同一时刻,只能处于1中状态。
* 把1件事情分成n个阶段,就变成n个时间序列,这样就把原来必须执行完整个事情,变为每次执行事件的1/n。
* 主程序工作在循环扫描中,比如每隔固定时间间隔(比如10ms)处理事情,而上面的1/n也许只需要1ms,这样主程序就有9ms做其他工作。注意的是1/n的完成事件必须小于固定时间间隔(比如10ms)。
* 每次扫描时,继续上次的阶段(比如2/n,或者3/n),执行完记录当前的阶段,以便下一次从当前的状态开始。
阶段1
|
阶段2
|
阶段3
...
阶段n 10ms后
阶段1
|
其他事情
|
10ms后
阶段2
|
其他事情
10ms后
... 我的程序都会用到马老师的状态机按键扫描,实时性好呀。。 mark 这个按键程序,学习了!多谢 我的程序也是参考马老师的,一直在用! 学习下, mark Mark:状态机,按键扫描。。 受教 machao 发表于 2010-4-7 21:16 static/image/common/back.gif
回复【5楼】fangmcu 方谭
取其标志就可以,当然不能将扫描程序写在中断里!!!!
---------------------------- ...
在定时器中断定义一个变量,这种方法是不错,不过,当主函数里在执行其他程序时,中断产生的标志位,也不一定能及时响应(稍微有点延迟)去执行相应的处理(比如主函数里不断的执行LED点阵屏显示函数) 学习一下...... machao 发表于 2010-4-7 21:16 static/image/common/back.gif
回复【5楼】fangmcu 方谭
取其标志就可以,当然不能将扫描程序写在中断里!!!!
---------------------------- ...
这样挺好 不知不觉用了状态机还不知道,看了马老师的书才豁然开朗! 刚接触状态机正在探索中 {:lol:}考研状态机中。。。 {:smile:}{:smile: mark........ mark....... 中断里放标志,我觉得很好,经常这样干 yzvip7 发表于 2011-9-10 23:29 static/image/common/back.gif
另一个思路。10ms定时,在定时器先读一次,利用2次10ms中断读出按键值。有去抖功效。 在主程序里按键,程序 ...
觉得这种方式最好!我一直用这种方式,程式简捷。 mark,学习了 mark mark {:loveliness:} 这个要mark一下
页:
[1]