OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6710|回复: 30

3*3的矩阵键盘扫描,想通过定时器处理,之前在主函数里面直接调用Key_Scan没有问题,但是在定时器里面扫描就有问题,什么情况呀

[复制链接]

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
发表于 2014-6-23 15:52:46 | 显示全部楼层 |阅读模式
5金钱
/*****************************key.c****************************************/
/********************
  *按键初始化子函数*
********************/
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/*GPIOC时钟使能*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

/*初始化GPIOC0/GPIOC1/GPIOC2,推挽输出*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2);

/*初始化GPIOC3/GPIOC4/GPIOC5,上拉输入*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5); 
}

/***********************************************
  *按键扫描子函数*
  *返回值:键值*
***********************************************/
u8 KEY_Scan(void)
{
u8 KeyVal = 0;

GPIO_Write(GPIOC,0xFFFE);
if((GPIOC->IDR & 0x0038) != 0x0038)
{
delay_ms(5);
if((GPIOC->IDR & 0x0038) != 0x0038)
{
switch((GPIOC->IDR & 0x0038))
{
case 0x0030: KeyVal = 1;break;  
case 0x0028: KeyVal = 2;break;
case 0x0018: KeyVal = 3;break;
}
while((GPIOC->IDR & 0x0038) != 0x0038);
}
}

GPIO_Write(GPIOC,0xFFFD);
if((GPIOC->IDR & 0x0038) != 0x0038)
{
delay_ms(5);
if((GPIOC->IDR & 0x0038) != 0x0038)
{
switch((GPIOC->IDR & 0x0038))
{
case 0x0030: KeyVal = 4;break;  
case 0x0028: KeyVal = 5;break;
case 0x0018: KeyVal = 6;break;
}
while((GPIOC->IDR & 0x0038) != 0x0038);
}
}

GPIO_Write(GPIOC,0xFFFB);
if((GPIOC->IDR & 0x0038) != 0x0038)
{
delay_ms(5);
if((GPIOC->IDR & 0x0038) != 0x0038)
{
switch((GPIOC->IDR & 0x0038))
{
case 0x0030: KeyVal = 7;break;  
case 0x0028: KeyVal = 8;break;
case 0x0018: KeyVal = 9;break;
}
while((GPIOC->IDR & 0x0038) != 0x0038);
}
}

return KeyVal; 
}


/********************************key.h**********************************/
#ifndef __KEY_H__
#define __KEY_H__
#include "stm32f10x.h"

#define PC3 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_3)
#define PC4 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_4)
#define PC5 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)

#define KEY_UpdateFont 1  
#define KEY_Up 2
#define KEY_Plus 3
#define KEY_Left 4  
#define KEY_MakeSure 5
#define KEY_Right 6
#define KEY_Cancel 7  
#define KEY_Down 8
#define KEY_Subtract 9
//
void KEY_Init(void); //按键初始化子函数
u8 KEY_Scan(void); //按键扫描子函数

#endif

/*************************************time.c********************************/
#include "time.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
#include "led.h"
#include "key.h"

//定时器3中断初始化函数
//arr:自动重装载值(0~65535)
//psc:预分频值(0~65535)
void TIM3_Init(u16 arr, u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //定时器3时钟使能

TIM_TimeBaseInitStructure.TIM_Prescaler = psc; //预分频值
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计时
TIM_TimeBaseInitStructure.TIM_Period = arr;   //自动重装载值
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割 tDTS= tCK_INT
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);

TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //开定时器3更新中断

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //定时器3通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级:0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级:3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道使能
NVIC_Init(&NVIC_InitStructure);

TIM_Cmd(TIM3, ENABLE); //开定时器3
}

u8 key;
void TIM3_IRQHandler(void) //定时器3中断服务函数
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //判断是否有更新中断
{
TIM_Cmd(TIM3, DISABLE); //关定时器3
key = KEY_Scan();
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清更新中断标志位
TIM_Cmd(TIM3, ENABLE); //开定时器3
}

/*********************************time.h*******************************/
#ifndef __TIME_H__
#define __TIME_H__
#include "stm32f10x.h"

extern  u8 key;
void TIM3_Init(u16 arr, u16 psc); //定时器3中断初始化函数

#endif

最佳答案

查看完整内容[请看2#楼]

回复【30楼】flyaab: --------------------------------- 后来用的定时器扫描独立按键,没用定时器扫描矩阵按键了
合肥-文盲
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-23 15:52:47 | 显示全部楼层
回复【30楼】flyaab:
---------------------------------
后来用的定时器扫描独立按键,没用定时器扫描矩阵按键了
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-23 15:53:59 | 显示全部楼层
3*3的矩阵键盘扫描,想通过定时器处理,之前在主函数里面直接调用Key_Scan没有问题,但是在定时器里面扫描就有问题,什么情况呀?我定时20ms,有时按下按键LCD乱显示
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-23 16:32:25 | 显示全部楼层
可有人知道为什么呀?或者知道如何使用定时器扫描矩阵键盘?急等用呀,主函数直接调用Key_Scan完全可以正常使用,但我想在定时器里面定时扫描,现在发现按下按键有时候LCD前一个画面还没有清除完,新的画面也没显示完,这是什么原因呀
合肥-文盲
回复

使用道具 举报

20

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
334
金钱
334
注册时间
2012-8-21
在线时间
27 小时
发表于 2014-6-23 16:38:30 | 显示全部楼层
傻,,,在定时器里面用延时,,,delay_ms(5);问题在这里
回复

使用道具 举报

20

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
334
金钱
334
注册时间
2012-8-21
在线时间
27 小时
发表于 2014-6-23 16:39:13 | 显示全部楼层
不做死就不会死,都用了定时器了,就不要用硬延时了,,
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-23 17:16:48 | 显示全部楼层
回复【5楼】lxj19901115:
---------------------------------
直接去掉这个delay_ms(5)????我试试
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-23 17:24:46 | 显示全部楼层
回复【5楼】lxj19901115:
---------------------------------
/***********************************************
  *按键扫描子函数*
  *返回值:键值*
***********************************************/
u8 KEY_Scan(void)
{
u8 KeyVal = 0;

GPIO_Write(GPIOC,0xFFFE);
if((GPIOC->IDR & 0x0038) != 0x0038)
{
// delay_ms(5);
// if((GPIOC->IDR & 0x0038) != 0x0038)
// {
switch((GPIOC->IDR & 0x0038))
{
case 0x0030: KeyVal = 1;break;  
case 0x0028: KeyVal = 2;break;
case 0x0018: KeyVal = 3;break;
}
while((GPIOC->IDR & 0x0038) != 0x0038);
// }
}

GPIO_Write(GPIOC,0xFFFD);
if((GPIOC->IDR & 0x0038) != 0x0038)
{
// delay_ms(5);
// if((GPIOC->IDR & 0x0038) != 0x0038)
// {
switch((GPIOC->IDR & 0x0038))
{
case 0x0030: KeyVal = 4;break;  
case 0x0028: KeyVal = 5;break;
case 0x0018: KeyVal = 6;break;
}
while((GPIOC->IDR & 0x0038) != 0x0038);
// }
}

GPIO_Write(GPIOC,0xFFFB);
if((GPIOC->IDR & 0x0038) != 0x0038)
{
// delay_ms(5);
// if((GPIOC->IDR & 0x0038) != 0x0038)
// {
switch((GPIOC->IDR & 0x0038))
{
case 0x0030: KeyVal = 7;break;  
case 0x0028: KeyVal = 8;break;
case 0x0018: KeyVal = 9;break;
}
while((GPIOC->IDR & 0x0038) != 0x0038);
// }
}

return KeyVal; 
}



这样改吗??定时20ms或者50ms还是出错
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-23 17:27:04 | 显示全部楼层
回复【7楼】合肥-文盲:
---------------------------------
回复【4楼】lxj19901115:
---------------------------------
定时100ms也有问题,几个时间段都试了,20  50  100ms
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-23 17:33:17 | 显示全部楼层
回复【5楼】lxj19901115:
---------------------------------
delay_ms(5);我已经注释掉了  为什么还是不能正常使用按键呢
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-23 17:44:25 | 显示全部楼层
回复【4楼】lxj19901115:
---------------------------------
坐等解决办法
合肥-文盲
回复

使用道具 举报

7

主题

85

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
298
金钱
298
注册时间
2013-10-10
在线时间
5 小时
发表于 2014-6-23 18:34:00 | 显示全部楼层
能不能每定时器中断执行10次再扫描?
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-24 08:56:13 | 显示全部楼层
回复【11楼】祝锦烨:
---------------------------------
是先扫描?再定时中断10次,再扫描??
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-24 08:56:28 | 显示全部楼层
回复【4楼】lxj19901115:
---------------------------------
人呢
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-24 09:37:47 | 显示全部楼层
回复【4楼】lxj19901115:
---------------------------------
可有解决方法????????????????
合肥-文盲
回复

使用道具 举报

20

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
334
金钱
334
注册时间
2012-8-21
在线时间
27 小时
发表于 2014-6-24 10:01:30 | 显示全部楼层
晕,
u16 ADC_Key_GetIdx(void)
{
u8 tw_adc_key_idx;
if(!g_Flag_adc_timer)
{
return c_Key_Null;
}
g_Flag_adc_timer = c_Clear;
tw_adc_key_idx = ADC_ChannelGetKeyIdx();
switch(g_adc_key_status)
{
case c_ADC_Key_Status_IDLE:
{
if(tw_adc_key_idx == c_Key_Null)
{
return c_Key_Null;
}
else
{
g_adc_key_buffer = tw_adc_key_idx;
g_adc_key_status = c_ADC_Key_Status_DB;
g_adc_DBtimerCnt = c_AD_Key_DB;
}
}
break;
case c_ADC_Key_Status_DB:
{
if(g_adc_key_buffer != tw_adc_key_idx)
{
g_adc_key_status = c_ADC_Key_Status_IDLE;
return c_Key_Null;
}
else
{
g_adc_DBtimerCnt--
if(g_adc_DBtimerCnt < 1)
{
g_adc_key_status = c_ADC_Key_Status_PressDown;
}
}

}
break;
case c_ADC_Key_Status_PressDown:
{
if(g_adc_key_buffer != tw_adc_key_idx)
{
g_adc_key_status = c_ADC_Key_Status_IDLE;
return (g_adc_key_buffer | KEY_STAT_PRESS);
}
else 
{
g_adc_key_status = c_ADC_Key_Status_PressUp;
return (g_adc_key_buffer | KEY_STAT_LPRESS_DOWN);
}
}

case c_ADC_Key_Status_PressUp:
{
if(g_adc_key_buffer != tw_adc_key_idx)
{
g_adc_key_status = c_ADC_Key_Status_IDLE;
return (g_adc_key_buffer | KEY_STAT_LPRESS_UP);
}
else 
{
g_adc_key_status = c_ADC_Key_Status_PressUp;
return (g_adc_key_buffer | KEY_STAT_LPRESS_CONTINUE);
}
}

default:
{
g_adc_key_status = c_ADC_Key_Status_IDLE;
}
break;
}
return c_Key_Null;
}


看这个,我写的AD扫键的,核心代码,你看看,
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-24 10:07:17 | 显示全部楼层
回复【15楼】lxj19901115:
---------------------------------
就事论事呀,我的这个矩阵键盘扫描函数出错你说在定时器中断里面用了delay_ms的原因,怎么改才能去除这个原因?你这个貌似也和矩阵键盘定时器扫描沾不上关系呀
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-24 10:08:01 | 显示全部楼层
回复【15楼】lxj19901115:
---------------------------------
请正面回答呀
合肥-文盲
回复

使用道具 举报

20

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
334
金钱
334
注册时间
2012-8-21
在线时间
27 小时
发表于 2014-6-24 10:19:29 | 显示全部楼层
case c_ADC_Key_Status_DB: 

if(g_adc_key_buffer != tw_adc_key_idx) 

g_adc_key_status = c_ADC_Key_Status_IDLE; 
return c_Key_Null; 

else 

g_adc_DBtimerCnt-- 
if(g_adc_DBtimerCnt < 1) 

g_adc_key_status = c_ADC_Key_Status_PressDown; 




break; 
看这个,这个就是你用的那个延时的功能一样的,
在扫到按键状态变化的时候,就延时消抖,而我使用的这个消抖延时,是通过定时器计数去延时的,不用去硬等,而是可以用等消抖的这些时间去干别的事情,,g_adc_DBtimerCnt 这个就是消抖计数,当g_adc_DBtimerCnt这个为0的时候,说明消抖时间完了,那么在判断一次键值,如果相同,就确认按键,而g_Flag_adc_timer这个是扫键的定时器标志,就好比你在中断里用的定时间隔,,
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-24 11:05:47 | 显示全部楼层
回复【18楼】lxj19901115:
---------------------------------
算了,我不用定时器扫描了,我就在主函数中调用Key_Scan,或者在调用的时候扫描一次
合肥-文盲
回复

使用道具 举报

126

主题

820

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1683
金钱
1683
注册时间
2012-10-28
在线时间
62 小时
发表于 2014-6-24 11:37:56 | 显示全部楼层
回复【19楼】合肥-文盲:
---------------------------------
不用定时器,可以了吗?
在主程序中调用,应该是可以得,我就用过。程序不大应该可以。
坚持学习!就能成功!
回复

使用道具 举报

7

主题

85

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
298
金钱
298
注册时间
2013-10-10
在线时间
5 小时
发表于 2014-6-24 11:48:03 | 显示全部楼层
定义一个全局变量flag,每次定时器中断flag++,当flag%10==0时再扫描,这是51的办法哈。
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-24 12:47:13 | 显示全部楼层
回复【21楼】祝锦烨:
---------------------------------
不用定时器扫描了,扫出一堆问题,直接在主函数要用按键的地方Key_Scan一次啊
合肥-文盲
回复

使用道具 举报

7

主题

85

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
298
金钱
298
注册时间
2013-10-10
在线时间
5 小时
发表于 2014-6-24 17:53:51 | 显示全部楼层
回复【22楼】合肥-文盲:
---------------------------------
真正开发的时候在while(1)里来扫描按键的不多吧
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-25 09:09:22 | 显示全部楼层
回复【20楼】1501697860:
---------------------------------
不用定时器可以正常扫描,估计还是要用定时器,你写过定时器扫描矩阵键盘吗
合肥-文盲
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-25 09:09:33 | 显示全部楼层
回复【23楼】祝锦烨:
---------------------------------
合肥-文盲
回复

使用道具 举报

126

主题

820

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1683
金钱
1683
注册时间
2012-10-28
在线时间
62 小时
发表于 2014-6-25 14:05:40 | 显示全部楼层
回复【24楼】合肥-文盲:
---------------------------------
用过,就是在10MS定时器中调用键盘扫描程序
坚持学习!就能成功!
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-25 14:46:07 | 显示全部楼层
回复【26楼】1501697860:
---------------------------------
那给个源码参考参考?
合肥-文盲
回复

使用道具 举报

126

主题

820

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1683
金钱
1683
注册时间
2012-10-28
在线时间
62 小时
发表于 2014-6-25 17:24:55 | 显示全部楼层
回复【27楼】合肥-文盲:
---------------------------------
不好意思,上份工作的事,不在手上
坚持学习!就能成功!
回复

使用道具 举报

86

主题

984

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1850
金钱
1850
注册时间
2013-4-15
在线时间
163 小时
 楼主| 发表于 2014-6-26 08:59:38 | 显示全部楼层
回复【28楼】1501697860:
---------------------------------
这个写过不就记得思路了吗
合肥-文盲
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
31
金钱
31
注册时间
2014-12-19
在线时间
2 小时
发表于 2015-1-12 14:40:26 | 显示全部楼层
回复【2楼】合肥-文盲:
---------------------------------
楼主,时间有点长了,我也写了一个用定时器扫描矩阵按键扫描的程序,貌似和你一样的现象。不知道你解决了没有???
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-27 05:27

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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