我自己写了个矩阵键盘扫描的程序,但是不知为什么,每次按下一次按键,总是会串口返回三次信息,有时后两条为0,有时为536,872,356,百思不得其解,求指点
key.c
#include "key.h"
#include "delay.h"
/**
* @brief 按键初始化函数
* @param 无
* @retval 无
*/
void key_init(void)
{
/* 初始化行按键 */
GPIO_InitTypeDef gpio_init_struct;
KEY_GPIO_CLK_ENABLE(); /* KEY时钟使能 */
gpio_init_struct.Pin = KEY5 | KEY6 | KEY7 | KEY8; /* 行引脚 */
gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
HAL_GPIO_Init(KEY_GPIO_PORT, &gpio_init_struct); /* 引脚模式设置,上拉输入 */
/* 初始化列按键 */
gpio_init_struct.Pin = KEY1 | KEY2 | KEY3 | KEY4; /* 列引脚 */
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 输出 */
gpio_init_struct.Pull = GPIO_NOPULL; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(KEY_GPIO_PORT, &gpio_init_struct); /* KEY0引脚模式设置,上拉输入 */
/* 初始化状态 */
HAL_GPIO_WritePin(KEY_GPIO_PORT, KEY1|KEY2|KEY3|KEY4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(KEY_GPIO_PORT, KEY5|KEY6|KEY7|KEY8, GPIO_PIN_SET);
}
void key_init2(void)
{
/* 初始化行按键 */
GPIO_InitTypeDef gpio_init_struct;
KEY_GPIO_CLK_ENABLE(); /* KEY时钟使能 */
gpio_init_struct.Pin = KEY5 | KEY6 | KEY7 | KEY8; /* 行引脚 */
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 输出 */
gpio_init_struct.Pull = GPIO_NOPULL; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(KEY_GPIO_PORT, &gpio_init_struct); /* KEY0引脚模式设置,上拉输入 */
/* 初始化列按键 */
gpio_init_struct.Pin = KEY1 | KEY2 | KEY3 | KEY4; /* 列引脚 */
gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
HAL_GPIO_Init(KEY_GPIO_PORT, &gpio_init_struct); /* 引脚模式设置,上拉输入 */
/* 初始化状态 */
HAL_GPIO_WritePin(KEY_GPIO_PORT, KEY5|KEY6|KEY7|KEY8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(KEY_GPIO_PORT, KEY1|KEY2|KEY3|KEY4, GPIO_PIN_SET);
}
uint8_t key_scan(void)
{
uint8_t line, column, key_value;
key_init ();
/* 查寻键盘口的值是否变化,本来全是1,接通变0,!取反 */
if(!HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY5) ||
!HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY6) ||
!HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY7) ||
!HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY8))
{
if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY5) == 0)/* 第1行 */
{
line = 1;
}
else if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY6) == 0)/* 第2行 */
{
line = 2;
}
else if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY7) == 0)/* 第3行 */
{
line = 3;
}
else if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY8) == 0)/* 第4行 */
{
line = 4;
}
key_init2 ();
/* 查寻键盘口的值是否变化,本来全是1,接通变0,!取反 */
if(!HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY1) ||
!HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY2) ||
!HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY3) ||
!HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY4))
{
if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY1) == 0)/* 第1列 */
{
column = 1;
}
else if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY2) == 0)/* 第2列 */
{
column = 2;
}
else if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY3) == 0)/* 第3列 */
{
column = 3;
}
else if (HAL_GPIO_ReadPin(KEY_GPIO_PORT, KEY4) == 0)/* 第4列 */
{
column = 4;
}
}
key_value = 4*(line-1) + column;
switch (key_value)
{
case 1:
key_value = 1;
break;
case 2:
key_value = 2;
break;
case 3:
key_value = 3;
break;
case 4:
key_value = 'A';/* 65 */
break;
case 5:
key_value = 4;
break;
case 6:
key_value = 5;
break;
case 7:
key_value = 6;
break;
case 8:
key_value = 'B';/* 66 */
break;
case 9:
key_value = 7;
break;
case 10:
key_value = 8;
break;
case 11:
key_value = 9;
break;
case 12:
key_value = 'C';/* 67 */
break;
case 13:
key_value = '#';
break;
case 14:
key_value = 0;
break;
case 15:
key_value = '*';
break;
case 16:
key_value = 'D';/* 68 */
break;
}
/* 等待按键放开 */
while(!HAL_GPIO_ReadPin(KEY_GPIO_PORT,KEY1) ||
!HAL_GPIO_ReadPin(KEY_GPIO_PORT,KEY2) ||
!HAL_GPIO_ReadPin(KEY_GPIO_PORT,KEY3) ||
!HAL_GPIO_ReadPin(KEY_GPIO_PORT,KEY4));
delay_ms (20);//延时20毫秒
}
return (key_value);
}
key.h
#ifndef __KEY_H
#define __KEY_H
#include "sys.h"
#define KEY_GPIO_PORT GPIOA /* 定义IO接口组A */
/* 第一列——第四列 PA3-PA0 */
#define KEY4 GPIO_PIN_0
#define KEY3 GPIO_PIN_1
#define KEY2 GPIO_PIN_2
#define KEY1 GPIO_PIN_3
/* 第一行——第四行 PA7-PA4*/
#define KEY8 GPIO_PIN_4
#define KEY7 GPIO_PIN_5
#define KEY6 GPIO_PIN_6
#define KEY5 GPIO_PIN_7
#define KEY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
void key_init(void); /* 按键初始化函数 */
uint8_t key_scan(void); /* 按键扫描函数 */
#endif
exti.c
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
uint8_t key_flag = 0;/* 按键标志位 */
/**
* @brief KEY1 外部中断服务程序
* @param 无
* @retval 无
*/
void KEY5_INT_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(KEY5_INT_GPIO_PIN); /* 调用中断处理公用函数 清除KEY0所在中断线 的中断标志位 */
__HAL_GPIO_EXTI_CLEAR_IT(KEY5_INT_GPIO_PIN); /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}
/**
* @brief KEY2-4 外部中断服务程序
* @param 无
* @retval 无
*/
void KEY6_8_INT_IRQHandler(void)
{
/* 调用中断处理公用函数 清除KEY1所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行 */
HAL_GPIO_EXTI_IRQHandler(KEY6_INT_GPIO_PIN);
__HAL_GPIO_EXTI_CLEAR_IT(KEY6_INT_GPIO_PIN); /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
HAL_GPIO_EXTI_IRQHandler(KEY7_INT_GPIO_PIN);
__HAL_GPIO_EXTI_CLEAR_IT(KEY7_INT_GPIO_PIN);
HAL_GPIO_EXTI_IRQHandler(KEY8_INT_GPIO_PIN);
__HAL_GPIO_EXTI_CLEAR_IT(KEY8_INT_GPIO_PIN);
}
/**
* @brief 中断服务程序中需要做的事情
在HAL库中所有的外部中断服务函数都会调用此函数
* @param GPIO_Pin:中断引脚号
* @retval 无
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case KEY5_INT_GPIO_PIN:
key_flag = 1;
break;
case KEY6_INT_GPIO_PIN:
key_flag = 1;
break;
case KEY7_INT_GPIO_PIN:
key_flag = 1;
break;
case KEY8_INT_GPIO_PIN:
key_flag = 1;
break;
}
}
/**
* @brief 外部中断初始化程序
* @param 无
* @retval 无
*/
void extix_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
KEY_GPIO_CLK_ENABLE(); /* KEY时钟使能 */
gpio_init_struct.Pin = KEY5 | KEY6 | KEY7 | KEY8;
gpio_init_struct.Mode = GPIO_MODE_IT_FALLING; /* 下降沿触发 */
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY5_INT_GPIO_PORT, &gpio_init_struct); /* 行线配置为下降沿触发中断 */
HAL_NVIC_SetPriority(KEY5_INT_IRQn, 2, 2); /* 抢占2,子优先级2 */
HAL_NVIC_EnableIRQ(KEY5_INT_IRQn); /* 使能中断线1 */
HAL_NVIC_SetPriority(KEY6_8_INT_IRQn, 2, 2); /* 抢占2,子优先级2 */
HAL_NVIC_EnableIRQ(KEY6_8_INT_IRQn); /* 使能中断线15 */
}
exti.h
#ifndef __EXTI_H
#define __EXTI_H
#include "./SYSTEM/sys/sys.h"
/******************************************************************************************/
/* 引脚 和 中断编号 & 中断服务函数 定义 */
#define KEY5_INT_GPIO_PORT GPIOA
#define KEY5_INT_GPIO_PIN GPIO_PIN_4
#define KEY5_INT_IRQn EXTI4_IRQn
#define KEY5_INT_IRQHandler EXTI4_IRQHandler
#define KEY6_INT_GPIO_PORT GPIOA
#define KEY6_INT_GPIO_PIN GPIO_PIN_5
#define KEY6_8_INT_IRQn EXTI9_5_IRQn
#define KEY6_8_INT_IRQHandler EXTI9_5_IRQHandler
#define KEY7_INT_GPIO_PORT GPIOA
#define KEY7_INT_GPIO_PIN GPIO_PIN_6
#define KEY8_INT_GPIO_PORT GPIOA
#define KEY8_INT_GPIO_PIN GPIO_PIN_7
/******************************************************************************************/
void extix_init(void); /* 外部中断初始化 */
#endif
main.c
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "oled.h"
#include "exti.h"
extern uint8_t key_flag;
int main(void)
{
uint8_t key_value;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart1_init(115200); /* 串口1初始化 */
extix_init(); /* 外部中断初始化 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
oled_init(); /* 初始化OLED */
printf("初始化完成");
while(1)
{
if (key_flag == 1)
{
key_flag = 0;
key_value = key_scan();
printf("键值:%d\r\n", key_value);
}
}
}