Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1592224
  • 博文数量: 354
  • 博客积分: 8137
  • 博客等级: 中将
  • 技术积分: 5137
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-26 15:40
文章分类

全部博文(354)

文章存档

2010年(300)

2009年(54)

分类: 嵌入式

2010-08-03 23:37:46

//hnrain 改

//适用于CEPARK 51开发板


/*****************************************************************************************************************
www.cepark.com            电子园 按键高阶攻略设计大赛

名称:        2*4矩阵键盘扫描 (状态机)
功能:        按键0单击时,点亮P0口的第1357个LED,按键1双击时,点亮P0口的2468个LED,按键2三击时,点亮P0口的所有的LED
            按键按下的时间间隔小于200ms。 其他键按下时,LED状态不变
作者:        alger2009
时间:        2009.12.30 星期三
版本:        V1.0
其他:        该开发板的LED不是单个的LED组成,而是LED逻辑卡; 看门狗程序防止程序跑飞
            
*****************************************************************************************************************/

#include "reg52.h"
#include "intrins.h"
#include "key2.h"


/******宏定义***************************************************************************************************/
#define        No_key      255                        //无键按下返回值


/****** 定义全局变量********************************************************************************************/
unsigned char    keyread_flag = 0;                //矩阵键盘扫描标志位
unsigned char num = 0;                        //定时计数器计数变量
unsigned char    outdata = 0;                    //返回值

/******2*4矩阵键盘扫描程序**********************************************************************************************
返回值:key_return    
key_return = 0 单击
key_return = 1 双击
key_return = 2 三击
key_return = 其他,按键无效
************************************************************************************************************************/
unsigned char read_keyboard(void)
{    
    static unsigned char key_state = 0, key_value, key_line;            // 列读取变量,行扫描码
    static unsigned char key_times = 0;                                    //按键击打次数
    static unsigned char Tcount = 0;                                    //按键连击计时变量
    unsigned char key_return = No_key, i;                                //按键返回值
    switch (key_state)
    {
        case 0:    //key you meiyou cunzai jiancha                                    //状态0功能: 按键扫描 连击计时 和连击超时处理
            key_line = 0x10;
            if (key_times != 0)     Tcount++;        //如果不是第一次击打,计时变量加1            
            if (Tcount > 20)                        //若连击按键按下时间间隔大于200毫秒            
            {
                key_times = 0;                        // 按键击打次数归0    
                Tcount = 0;                            // 计时变量归0
            }
            for (i = 0; i < 2; i++)                    // 扫描键盘
            {    
                P2 = ~key_line;                        // 输入行扫描码
                P2 = ~key_line;                        // 重复送一次
             key_value = 0x0f & P2;                // 读列电平
                if (key_value == 0x0f)
                    key_line <<= 1;                    // 没有按键,继续扫描
                else
                {
                    key_state++;                    // 有按键,停止扫描
                    break;                            // 跳出按键扫描
                }
            }
            break;                                    
        case 1:                                        //状态1功能:确认按键 读取按键值
            if (key_value == (0x0f & P2))            // 再次读列电平,若非抖动
            {
                switch (key_line | key_value)        //行扫描码和列电平,确认按键
                {                                    // 键盘编码,返回编码值
                    case 0x1e:                        //单击按键0
                        key_return = 1;
                        break;
                    case 0x1d:
                        {
                             if(key_times == 1 && Tcount < 20)
                                key_return = 2;        //双击按键1
                            else
                                key_times++;        //第一次按下,计数加1
                        }
                        break;
                     case 0x1b:
                        {
                            if(key_times == 2 && Tcount < 20)
                                key_return = 3;        //三击按键2
                            else
                                key_times++;        //第一次或第二次按下,计数加1
                        }
                        break;
                     case 0x17:
                        key_return = 4;
                        break;
                     case 0x27:
                        key_return = 5;
                        break;
                    case 0x2b:
                        key_return = 6;
                        break;
                     case 0x2d:
                        key_return = 7;
                        break;
                     case 0x2e:
                        key_return = 8;
                        break;
                }
                key_state++;                    // 转入等待按键释放状态
            }
            else
                key_state--;                    // 两次列电平不同返回状态0,(消抖处理)
            break;                        
        case 2:                                    //状态2功能:按键释放判定
            P2 = 0x0f;                            // 行线全部输出低电平
            P2 = 0x0f;                            // 重复送一次
            if ( (P2 & 0x0f) == 0x0f)
                key_state = 0;                    // 按键释放,返回状态0
            break;
    }
    return key_return;                            //返回值
}


/******定时器1 定时1毫秒******************************************************************************/
void timer1(void) interrupt 3
{
    TH1 = (65536-1000)/256;
    TL1 = (65536-1000)%256;
    if(++num == 10)
    {keyread_flag = 1;                    //按键扫描允许标志位
     num = 0;    
    }
}


/******定时器初始化**********************************************************************************/
void timer1_initial(void)
{
    TH1 = (65536-1000)/256;
    TL1 = (65536-1000)%256;             //装初始值
    IE = 0x88;                         //开总中断和定时器1中断    
    TMOD = 0x10;                     //工作方式1
    TR1 = 1;                         //启动定时器
}


/******看门狗子程序*********************************************************************************/
void clr_wdt(void)
{
    WDTRST=0x1e;
    WDTRST=0xe1;
}


/******主程序****************************************************************************************/
main(void)
{
    P0 = 0xff;                            //初始化LED端口
    timer1_initial();                    //定时器1初始化
    while(1)
    {    
        if(keyread_flag == 1)            //矩阵扫描标志位允许
        {
            keyread_flag = 0;
            clr_wdt();                    //调用看门狗 (每2的14次方个机器周期内必须调用一次,使看门狗复位)
            outdata = read_keyboard();    //读取矩阵键盘返回值
        }

        if(outdata == 1)            
            P0 = 0xaa;                //单击按键0 点亮第1357个LED
        else if(outdata == 2)        
            P0 = 0x55;                //双击按键1 点亮第2468个LED
        else if(outdata == 3)        
            P0 = 0x00;                //三击按键2 点亮全部LED
    }
}


阅读(4677) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~