stm32以中断方式扫描矩阵键盘

矩阵键盘

普通的按键,都是一个IO口控制一个按键,但是当按键数量变多时,单片机可能没有那么多的IO口来供给按键使用,这时候就需要用到矩阵键盘,比如45的矩阵键盘,用到了4+5共9根IO口线,可以控制45=20个按键。相应的,程序也要复杂些。
在这里插入图片描述

在这里插入图片描述

cubemx配置

X0到X3这4个IO口配置为低电平输出,无上拉,无下拉,即推挽方式,速度为中
Y0到Y4这5个IO口配置为EXTI外部中断模式,上拉,下降沿触发。
在这里插入图片描述

编程思路

1 X0~3配置为输出低电平
2 Y0~4配置为下降沿中断,但是芯片内部配置了上拉,所以无按键触发时不会进中断。
3 当有按键按下,比如X2Y4按下时,X2路的低电平会进入到Y4路,触发下降沿中断。
4 在Y4中断内,将Y4配置为低电平输出,而X0~3配置为上拉输入,记录下Y值为4
5 逐一检测X0~3的电平,哪一路为低,即对应的为X键值,本例X值为2
6 综合x=2, y=4, 即可知道是哪一个按键按下了。

代码编写

定义一个结构体,有按键触发时,active置1,x,y分别记录行列值,num是最后的键值。

typedef struct KEYBOARD_TYPEDEF
{
  u8 active;
  u8 x;
  u8 y;
  u8 num;
}KEYBOARD_Typedef;

KEYBOARD_Typedef keyboard;

以Y4为例,列出一路中断如下:

void EXTI15_10_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */
    if(__HAL_GPIO_EXTI_GET_FLAG(KEY_Y4_Pin))
    {
        delay_us(10);
        if(KEY_Y4_READ() != 0)
        {
            HAL_GPIO_EXTI_IRQHandler(KEY_Y4_Pin);
            return;
        }
        delay_us(10);
        if(KEY_Y4_READ() != 0)
        {
            HAL_GPIO_EXTI_IRQHandler(KEY_Y4_Pin);
            return;
        }
        delay_us(10);
        if(KEY_Y4_READ() != 0)
        {
            HAL_GPIO_EXTI_IRQHandler(KEY_Y4_Pin);
            return;
        }
        keyboard.active = 1;
        keyboard.y = 4;
    }
    keyboard_scan();
  /* USER CODE END EXTI15_10_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(KEY_Y4_Pin);
  /* USER CODE BEGIN EXTI15_10_IRQn 1 */

  /* USER CODE END EXTI15_10_IRQn 1 */
}

增加了几次延时,作为键盘消抖的判断
确认不是误触发后,active置1,并相应的y值。
最后调用键盘扫描函数,来确认X的键值。
.
.

引脚功能模式切换

//切换GPIO引脚的方向
//port 端口号
//pin号
//dir 方向,0为输入,1为输出, 2为EXTI
void pin_io_switch(GPIO_TypeDef *port, u32 pin, u8 mode)
{
    switch(mode)
    { 
        case GPIO_IN://输入
            GPIO_InitStruct.Pin = pin;
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_PULLUP;
            HAL_GPIO_Init(port, &GPIO_InitStruct);
            break;
        case GPIO_OUT://输出
            GPIO_InitStruct.Pin = pin;
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
            HAL_GPIO_Init(port, &GPIO_InitStruct);
            break;
        case GPIO_EXTI:
            GPIO_InitStruct.Pin = pin;
            GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
            GPIO_InitStruct.Pull = GPIO_PULLUP;
            HAL_GPIO_Init(port, &GPIO_InitStruct);
            break;
    }
}

.
.
本函数用来确认X轴的键值。

void keyboard_scan(void)
{
    u16 i,j;
    u8 x0, x1, x2, x3;
    u8 temp, current;
    
    if(keyboard.active == 0)
    return;

	//关中断
    HAL_NVIC_DisableIRQ(EXTI3_IRQn);	
    HAL_NVIC_DisableIRQ(EXTI4_IRQn);
    HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
    HAL_NVIC_DisableIRQ(EXTI15_10_IRQn);

	//X0~3切换为输入状态
    pin_io_switch(KEY_X0_PORT, KEY_X0_Pin, GPIO_IN);    //X0  PC13
    pin_io_switch(KEY_X1_PORT, KEY_X1_Pin, GPIO_IN);    //X1  PC14
    pin_io_switch(KEY_X2_PORT, KEY_X2_Pin, GPIO_IN);    //X2  PC15
    pin_io_switch(KEY_X3_PORT, KEY_X3_Pin, GPIO_IN);    //X3  PB7

	//只将相应的一路Y口切换为输出状态,Y的数值,在中断函数中设置过
    switch(keyboard.y)
    {
        case 0:
            pin_io_switch(KEY_Y0_PORT, KEY_Y0_Pin, GPIO_OUT);
            KEY_Y0_SET(0);  //Y0  PB6
            break;
        case 1:
            pin_io_switch(KEY_Y1_PORT, KEY_Y1_Pin, GPIO_OUT);
            KEY_Y1_SET(0);  //Y0  PB5
            break;
        case 2:
            pin_io_switch(KEY_Y2_PORT, KEY_Y2_Pin, GPIO_OUT);
            KEY_Y2_SET(0);  //Y0  PB4
            break;
        case 3:
            pin_io_switch(KEY_Y3_PORT, KEY_Y3_Pin, GPIO_OUT);
            KEY_Y3_SET(0);  //Y0  PB3
            break;
        case 4:
            pin_io_switch(KEY_Y4_PORT, KEY_Y4_Pin, GPIO_OUT);
            KEY_Y4_SET(0);  //Y0  PA15
            break;
    }

    //读取X轴的状态
    x0 = KEY_X0_READ();   //X0  PC13
    x1 = KEY_X1_READ();   //X1  PC14
    x2 = KEY_X2_READ();   //X2  PC15
    x3 = KEY_X3_READ();   //X3  PB7
    if(x0 == 0)
        keyboard.x = 3;     //X方向从左开始为x3, x2, x1, x0
    else if(x1 == 0)
        keyboard.x = 2;     //与电路图上相反,下一版电路要把方向改过来,改为x0,x1,x2,x3
    else if(x2 == 0)
        keyboard.x = 1;
    else 
        keyboard.x = 0;
    keyboard.num = keyboard.y*4 + keyboard.x; //计算键值,0~19

	//将Y口配置为EXTI,上拉
    pin_io_switch(KEY_Y0_PORT, KEY_Y0_Pin, GPIO_EXTI);
    pin_io_switch(KEY_Y1_PORT, KEY_Y1_Pin, GPIO_EXTI);
    pin_io_switch(KEY_Y2_PORT, KEY_Y2_Pin, GPIO_EXTI);
    pin_io_switch(KEY_Y3_PORT, KEY_Y3_Pin, GPIO_EXTI);
    pin_io_switch(KEY_Y4_PORT, KEY_Y4_Pin, GPIO_EXTI);
    
    //将X口配置为输出,低电平
    pin_io_switch(KEY_X0_PORT, KEY_X0_Pin, GPIO_OUT);
    pin_io_switch(KEY_X1_PORT, KEY_X1_Pin, GPIO_OUT);
    pin_io_switch(KEY_X2_PORT, KEY_X2_Pin, GPIO_OUT);
    pin_io_switch(KEY_X3_PORT, KEY_X3_Pin, GPIO_OUT);
    KEY_X0_SET(0);
    KEY_X1_SET(0);
    KEY_X2_SET(0);
    KEY_X3_SET(0);
    HAL_NVIC_EnableIRQ(EXTI3_IRQn);
    HAL_NVIC_EnableIRQ(EXTI4_IRQn);
    HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}

最后在主程序中检查keyboard.active,若不为0,则表示有按键按下,此时需要做相应处理,并且将keyboard中的各成员清零。

  • 7
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32中,可以使用外部中断来处理矩阵键盘的按键触发事件。外部中断/事件控制器(EXTI)是STM32F10x系列微控制器中的一个模块,它包含多达20个用于产生事件/中断请求的边沿检测器。每根输入线都可以单独进行配置,以选择中断或事件类型以及相应的触发事件(上升沿触发、下降沿触发或边沿触发)\[2\]。 为了处理矩阵键盘的外部中断,可以定义一个结构体来记录按键触发时的相关信息。例如,可以定义一个名为KEYBOARD_Typedef的结构体,其中包含active、x、y和num等字段。当按键触发时,active字段可以被置为1,x和y字段可以记录行列值,num字段可以记录最后的键值\[3\]。 通过配置外部中断和编写相应的中断服务函数,可以实现对矩阵键盘的外部中断处理。具体的实现方式和代码细节可能会因具体的STM32型号和开发环境而有所不同,建议参考相关的STM32开发文档和示例代码进行具体的配置和编程。 #### 引用[.reference_title] - *1* *3* [stm32中断方式扫描矩阵键盘](https://blog.csdn.net/13011803189/article/details/126249580)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [【STM32】4*4矩阵键盘(外部中断触发方式)](https://blog.csdn.net/qq_52561717/article/details/120893098)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值