51单片机的按键状态机

通过按键扫描的方法 发现长按显示效果难以实现,在此引入状态机程序

如上图问题这时可以引入状态机

#include "key.h"
#include "stc15f2k60s2.h"

#define key_state_0 0//无触动
#define key_state_1 1//按下
#define key_state_2 2//长按

unsigned char rd_key(void)
{
    static unsigned char key_state =0;
    unsigned char key_press = 0;
    unsigned char key_return= 0;
    unsigned char key1,key2;

/***************确定列*********************/
    P44=1;P42=1;P35=1;P34=1;P33=0;P32=0;P31=0;P30=0;
    if(P44==0){key1 = 0x70;}//0111 0000
    if(P42==0){key1 = 0xB0;}//1011 0000
    if(P35==0){key1 = 0xD0;}//1101 0000
    if(P34==0){key1 = 0xE0;}//1110 0000
    if((P44==1)&&(P42==1)&&(P35==1)&&(P34==1)){key1 = 0xF0;}//11110000

/***************确定行********************/
    P44=0;P42=0;P35=0;P34=0;P33=1;P32=1;P31=1;P30=1;
    if(P33==0){key2 = 0x07;}//0000 0111
    if(P32==0){key2 = 0x0B;}//0000 1011
    if(P31==0){key2 = 0x0D;}//0000 1101
    if(P30==0){key2 = 0x0E;}//0000 1110
    if((P33==1)&&(P32==1)&&(P31==1)&&(P30==1)){key2 = 0x0F;}//0000 1111

    key_press = key1|key2;//确定按键

    switch(key_state)
    {
        case key_state_0 :
                if(key_press != 0xFF)//有按键按下
                {
                    key_state = key_state_1;
                }
                break;
        case key_state_1 :
                if(key_press != 0xFF)//确定按下按键状态1
                {
                    if(key_press==0x7E){key_return = 7;}//s7
                    if(key_press==0x7D){key_return = 6;}//s6
                    if(key_press==0x7B){key_return = 5;}//s5
                    if(key_press==0x77){key_return = 4;}//s4

                    if(key_press==0xBE){key_return = 11;}//s
                    if(key_press==0xBD){key_return = 10;}//s
                    if(key_press==0xBB){key_return = 9;}//s
                    if(key_press==0xB7){key_return = 8;}//s

                    if(key_press==0xDE){key_return = 15;}//s
                    if(key_press==0xDD){key_return = 14;}//s
                    if(key_press==0xDB){key_return = 13;}//s
                    if(key_press==0xD7){key_return = 12;}//s

                    if(key_press==0xEE){key_return = 19;}//s
                    if(key_press==0xED){key_return = 18;}//s
                    if(key_press==0xEB){key_return = 17;}//s
                    if(key_press==0xE7){key_return = 16;}//s
                    key_state = key_state_2; 
                }
                else  
                    key_state = key_state_0;//误触返回状态0  
                break;
        case key_state_2 ://持续状态 2  
                    if(key_press == 0xFF)
                    {
                        key_state = key_state_0;//非长按返回状态0
                    }
                    break;

    }

        return key_return ;
}

在此可以较容易实现按键三种状态的检测

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于51单片机的NEC协议状态机编程示例: ```c #include <reg51.h> #define IR_IN P3_2 // NEC协议定义的高低电平时间 #define T1 560 #define T2 1690 #define T3 45000 #define T4 22500 // 状态定义 #define STATE_IDLE 0 #define STATE_START 1 #define STATE_BIT 2 // 全局变量 unsigned char ir_state = STATE_IDLE; // 初始化为IDLE状态 unsigned char ir_code = 0; unsigned char ir_count = 0; void delay_us(unsigned int us) { while(us--) { _nop_(); } } // NEC协议解码函数 void ir_decode(unsigned char code) { // 解码操作 } void ir_timer_handler() { static unsigned int ir_timer_count = 0; static unsigned char ir_last_state = 0; // 读取当前状态 unsigned char ir_cur_state = IR_IN; // 状态转移 switch (ir_state) { case STATE_IDLE: if (ir_cur_state == 0 && ir_last_state == 1) { ir_timer_count = 0; ir_state = STATE_START; } break; case STATE_START: if (ir_cur_state == 1 && ir_last_state == 0) { if (ir_timer_count >= T1 && ir_timer_count <= T2) { ir_code = 0; ir_count = 0; ir_state = STATE_BIT; } else { ir_state = STATE_IDLE; } } break; case STATE_BIT: if (ir_cur_state == 1 && ir_last_state == 0) { if (ir_timer_count >= T1 && ir_timer_count <= T2) { ir_code >>= 1; if (ir_timer_count > T2 - T1) { ir_code |= 0x80; } ir_count++; if (ir_count >= 8) { ir_decode(ir_code); ir_state = STATE_IDLE; } } else { ir_state = STATE_IDLE; } } break; default: ir_state = STATE_IDLE; break; } // 更新last_state并清零计数器 ir_last_state = ir_cur_state; ir_timer_count = 0; } void main() { TMOD = 0x01; // 定时器0工作在模式1 TH0 = 0xFC; // 定时器初值 TL0 = 0x67; ET0 = 1; // 打开定时器0中断 EA = 1; // 打开总中断 while(1) { // 等待中断处理 } } // 定时器0中断 void timer0_isr() interrupt 1 { TH0 = 0xFC; // 定时器初值 TL0 = 0x67; ir_timer_handler(); // 处理红外信号 } ``` 以上代码通过定时器0中断处理来实现NEC协议的红外信号解码。整个解码过程是通过状态机实现的,分为三个状态:IDLE、START和BIT。在IDLE状态下,等待红外信号开始;在START状态下,检测红外信号开始;在BIT状态下,解码红外信号。在定时器中断处理函数中,会根据当前状态和红外信号的高低电平时间来进行状态转移和解码操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值