|
最近学习马超老师的矩阵键盘扫描程序,发现一个问题不知道怎么解决,求助一下大家!
问题:扫描期间会出现卡在某一行或一直扫描某一行的现象
把代码贴出来大家给指点一下:
----------------------------------------------
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来反美的!
|