• 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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    以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 */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    增加了几次延时,作为键盘消抖的判断
    确认不是误触发后,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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    .
    .
    本函数用来确认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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

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

  • 相关阅读:
    2022年Java秋招面试必看的 | Linux 面试题
    P1226 【模板】快速幂
    【亲测有效】C盘容量满了,给C盘扩容!!!
    Spring MVC 框架学习(七)---- 后端接口小练习(计算器与登陆拦截)
    面试之Java String 编码相关
    RH8WEB服务器
    2022 世界人工智能大会|人工智能与开源技术先锋论坛成功举办
    VUE全家桶 (Vue-cli、Vue-route、Vuex)学习笔记
    acwing算法基础之数据结构--哈希表算法
    python采集财经数据信息并作可视化~
  • 原文地址:https://blog.csdn.net/13011803189/article/details/126249580