搜索
bottom↓
回复: 0

状态机矩阵键盘扫描卡死的问题

[复制链接]

出0入0汤圆

发表于 2013-9-1 11:57:44 | 显示全部楼层 |阅读模式
最近学习马超老师的矩阵键盘扫描程序,发现一个问题不知道怎么解决,求助一下大家!
问题:扫描期间会出现卡在某一行或一直扫描某一行的现象
把代码贴出来大家给指点一下:
----------------------------------------------
CUP:        ATmega16L
编译环境:GCCAVR
晶振频率:7372800
-----------------------------------------------
#ifndef   __KEYSCAN_H__
#define   __KEYSCAN_H__

#include<avr/io.h>
#include<avr/interrupt.h>
#include"usart.h"
#include"com_fun.h"
/****************************************
    +-------------------------------+
    |        键盘布局            |
    +-------------------------------+
    |      Px3 Px2 Px1 Px0   |
    |       |    |     |     |      |
    |  Px4- 1   2   3   A      |
    |  Px5- 4   5   6   B      |
    |  Px6- 7   8   9   C      |
    |  Px7- *   0   #   D     |
   +-------------------------------+
*****************************************/
#define KEY_PORT PORTA
#define KEY_PIN  PINA
#define KEY_DDR  DDRA

#define KEY_STATE_0  0     //
#define KEY_STATE_1  1     //
#define KEY_STATE_2  2     //

#define NO_KEY    255
#define K1_1      1
#define K1_2      2
#define K1_3      3
#define K1_4      4
#define K2_1      5
#define K2_2      6
#define K2_3      7
#define K2_4      8
#define K3_1      9
#define K3_2      10
#define K3_3      11
#define K3_4      12
#define K4_1      13
#define K4_2      14
#define K4_3      15
#define K4_4      16
#define KEY_MASK  0b11110000

extern unsigned char KEY_TEMP;
extern unsigned char KEY_STIME_OK;
extern unsigned char KEY_STIME_COUNTER;

void KEY_Init(void);
unsigned char KEY_Scan(void);
unsigned char KEY_Get(void);

void Timer0_Init(void);
//#pragma interrupt_handler time0_comp_isr:20


#endif
/****************end of header*************************/
unsigned char KEY_TEMP = 0;
unsigned char KEY_STIME_OK = 0;
unsigned char KEY_STIME_COUNTER = 0;
/*----------------------------------------------------------------
- 功能描述:定时器0初始化
- 隶属模块:4×4矩阵键盘扫描程序模块
- 函数属性:外部
- 参数说明:无
- 返回说明:无
- 注:暂无
-----------------------------------------------------------------*/
void Timer0_Init(void)
{
        /*T/C0初始化*/
        TCCR0 = 0x00;   
        TCNT0 = 0x00;   //T/C0的计数值寄存器
       
        OCR0  = 0xe6;             //0xE6=230,(230)/115.2kHz = 2ms
        TIMSK = (1<<OCIE0);   //使能T/C0比较匹配中断(允许位)
        TCCR0 = 0x7c;                 //CTC模式
                                         //64分频时钟(7.3728MHz/64=115.2kHz)
        SREG  =(1<<7);  //全局中断开
}
/*----------------------------------------------------------------
- 功能描述:定时器0比较中断服务程序,2ms中断5次后确定有键按下
- 隶属模块:4×4矩阵键盘扫描程序模块
- 函数属性:外部
- 参数说明:无
- 返回说明:无
- 注:暂无
-----------------------------------------------------------------*/
ISR(TIMER0_COMP_vect)
{
        if(++KEY_STIME_COUNTER >= 5)
        {
                KEY_STIME_COUNTER = 0;
                KEY_STIME_OK = 1;       //10ms时间到(可以确定按键状态)
        }
}
/*----------------------------------------------------------------
- 功能描述:键盘接口初始化
- 隶属模块:4×4矩阵键盘扫描程序模块
- 函数属性:外部
- 参数说明:无
- 返回说明:无
- 注:暂无
-----------------------------------------------------------------*/
void KEY_Init(void)
{
        /*键盘接口初始化*/
        KEY_DDR  = 0x0f;      //列输入,上拉有效;行输出。
        KEY_PORT = 0xff;
        Timer0_Init();           //键盘初始化的同时初始化timer0
}
/*----------------------------------------------------------------
- 功能描述:基于状态机的矩阵键盘扫描读取
- 隶属模块:4×4矩阵键盘扫描程序模块
- 函数属性:内部
- 参数说明:无
- 返回说明:无
- 注:3种状态
-----------------------------------------------------------------*/
unsigned char KEY_Scan(void)
{
        static unsigned char KEY_STATE = 0;
        static unsigned char KEY_VALUE = 0;
        static unsigned char KEY_LINE = 0;
               unsigned char KEY_CODE = NO_KEY;
               unsigned char i;
        switch(KEY_STATE)
        {
                case 0:
                        KEY_LINE = 0b00000001;            //0b00000001 第一行
                        for(i=0;i<4;i++)
                        {
                                KEY_PORT = ~KEY_LINE;  //按位取反后第一行、低电平
                                KEY_PORT = ~KEY_LINE;  //重复一次,保证电平稳定
                                KEY_VALUE = (KEY_MASK & KEY_PIN);//KEY_MASK低四位全为0
                                asm("nop");//稍作延时
                                asm("nop");
                                asm("nop");
                                asm("nop");
                                asm("nop");
                                if(KEY_VALUE == KEY_MASK)     //无键按下
                                {
                                        KEY_LINE <<= 1;             //继续扫描第二行
                                }
                                else                                        //有键按下转入下一状态
                                {
                                        KEY_STATE = 1;
                                        //KEY_STATE ++;
                                        break;
                                }
                        }
                        break;
                case 1:
                        if(KEY_VALUE == (KEY_MASK & KEY_PIN))//再次读取列电平确保按键稳定
                        {
                                switch(KEY_LINE | KEY_VALUE)
                                {
                                        case 0b11101000:              //0b11101110 第一行,第一列
                                                KEY_CODE = K1_1;break;
                                        case 0b11100100:              //0b11011110 第一行,第二列
                                                KEY_CODE = K1_2;break;
                                        case 0b11100010:              //0b11011110 第一行,第三列
                                                KEY_CODE = K1_3;break;
                                        case 0b11100001:              //0b01111110 第一行,第四列
                                                KEY_CODE = K1_4;break;
                                        case 0b11011000:              //0b11101101 第二行,第一列
                                                KEY_CODE = K2_1;break;
                                        case 0b11010100:              //0b11011101 第二行,第二列
                                                KEY_CODE = K2_2;break;
                                        case 0b11010010:              //0b10111101 第二行,第三列
                                                KEY_CODE = K2_3;break;
                                        case 0b11010001:              //0b01111101 第二行,第四列
                                                KEY_CODE = K2_4;break;
                                        case 0b10111000:              //0b11101011 第三行,第一列
                                                KEY_CODE = K3_1;break;
                                        case 0b10110100:              //0b11011011 第三行,第二列
                                                KEY_CODE = K3_2;break;
                                        case 0b10110010:              //0b10111011 第三行,第三列
                                                KEY_CODE = K3_3;break;
                                        case 0b10110001:              //0b01111011 第三行,第四列
                                                KEY_CODE = K3_4;break;
                                        case 0b01111000:              //0b11100111 第四行,第一列
                                                KEY_CODE = K4_1;break;
                                        case 0b01110100:              //0b11010111 第四行,第二列
                                                KEY_CODE = K4_2;break;
                                        case 0b01110010:              //0b10110111 第四行,第三列
                                                KEY_CODE = K4_3;break;
                                        case 0b01110001:              //0b01110111 第四行,第四列
                                                KEY_CODE = K4_4;break;
                                        default :break;
                                }
                                KEY_STATE = 2;
                                //KEY_STATE ++;
                        }
                        else
                                KEY_STATE = 0;
                                //KEY_STATE --;
                        break;
                case 2:
                        KEY_PORT = 0x0f;                   //0b00001111
                        KEY_PORT = 0x0f;                   //0b00001111
                        if((KEY_MASK & KEY_PIN) == KEY_MASK)
                                KEY_STATE = 0;
                        break;
                       
                default : break;
        }
        return KEY_CODE;
}
/*----------------------------------------------------------------
- 功能描述:矩阵键盘键值编码获取
- 隶属模块:4×4矩阵键盘扫描程序模块
- 函数属性:外部
- 参数说明:无
- 返回说明:激活按键的键值编码
- 注:
-----------------------------------------------------------------*/
unsigned char KEY_Get(void)
{
        while(1)
        {
                Delay(1);/*必须在此处延时,否则无法进入扫描*/
                if(KEY_STIME_OK == 1)
                {
                        //USART1_Put_Inf("进入扫描程序:",KEY_TEMP);
                        KEY_STIME_OK = 0;
                        //KEY_STIME_COUNTER = 0;
                        KEY_TEMP = KEY_Scan();
                       
                        if(KEY_TEMP != NO_KEY)
                        {
                                return KEY_TEMP;
                        }
                }
        };
}
/***********************end of c file********************************/

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 09:36

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表