stm32 F103C8T6 4x4矩阵键盘使用

首先感谢 江科大 的stm32入门课程 受益匪浅。推荐有兴趣的朋友去看看。

先看看我用的矩阵键盘是啥样的(很常见的一种)

接线如图(其他型号根据自己需求接上GPIO口)

代码基于stm大善人的代码修改而来,讲的很详细,非常感谢。

直接上代码:

头文件Key4x4.h

复制代码
#ifndef __KEY4x4_H
#define __KEY4x4_H

void KEY_4x4_Init(void); 
void KEY_Scan(void);
u16 Key_Read(void);

#endif

主体文件Key4x4.c

复制代码
#include "stm32f10x.h"
#include "Delay.h"

u8 anxia = 0;
u8 key = 1;
u16 line[4] = {0x00fe , 0x00fd , 0x00fb ,0x00f7};
u16 off = 0x00ff; // 全部引脚置为1
u16 keys[16] = {
    49, 50, 51, 65,
    52, 53, 54, 66,
    55, 56, 57, 67,
    42, 48, 35, 68,
};

void KEY_4x4_Init(void){
    
    GPIO_InitTypeDef GPIO_InitStructre;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); // 使能 GPIOA 的时钟
    
    // 第一组
    GPIO_InitStructre.GPIO_Pin  = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
    GPIO_InitStructre.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
    GPIO_InitStructre.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA , &GPIO_InitStructre);
    GPIO_SetBits(GPIOA , GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
    // 第二组数据
    GPIO_InitStructre.GPIO_Pin  = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
    GPIO_InitStructre.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA , &GPIO_InitStructre);
    GPIO_SetBits(GPIOA , GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    
}

void Do_Click(uint16_t gpio_pin_x , u8 num){
    anxia = 1;
    key = num;
    while(!GPIO_ReadInputDataBit(GPIOA , gpio_pin_x));
}

void KEY_Click_Listener(u8 num){
    if((GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_4)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_5)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_7)==0)){
        Delay_ms(10);
        if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_4)){
            Do_Click(GPIO_Pin_4 , num+0);
        }else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_5)){
            Do_Click(GPIO_Pin_5 , num+1);
        }else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)){
            Do_Click(GPIO_Pin_6 , num+2);
        }else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_7)){
            Do_Click(GPIO_Pin_7 , num+3);
        }else {
            anxia = 0;
            GPIO_Write(GPIOA , off);
        }
    }
}

void KEY_Scan(){
    // 第一行 1111 1110
    GPIO_Write(GPIOA , line[0]);
    KEY_Click_Listener(1);
    // 第二行
    GPIO_Write(GPIOA , line[1]);
    KEY_Click_Listener(5);
    // 第三行
    GPIO_Write(GPIOA , line[2]);
    KEY_Click_Listener(9);
    // 第四行
    GPIO_Write(GPIOA , line[3]);
    KEY_Click_Listener(13);
}

u16 Key_Read(){
    return keys[key-1];
}

主要代码说明:

初始化配置 (KEY_4x4_Init):

  • 使能GPIOA模块的时钟。
  • 配置GPIOA的前四个引脚(GPIO_Pin_0至GPIO_Pin_3)为推挽输出模式,用于键盘行线的扫描。
  • 设置GPIOA的后四个引脚(GPIO_Pin_4至GPIO_Pin_7)为上拉输入模式,用于检测键盘列线的状态。
复制代码
// 第一组
    GPIO_InitStructre.GPIO_Pin  = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
    GPIO_InitStructre.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
    GPIO_InitStructre.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA , &GPIO_InitStructre);
    GPIO_SetBits(GPIOA , GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
    // 第二组数据
    GPIO_InitStructre.GPIO_Pin  = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
    GPIO_InitStructre.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOA , &GPIO_InitStructre);
    GPIO_SetBits(GPIOA , GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

按键检测 (KEY_Click_Listener):

  • 检测列线状态,如果有键按下,则调用Do_Click函数记录按键信息并等待按键释放。
  • 使用延时函数Delay_ms来消除抖动。
复制代码
void KEY_Click_Listener(u8 num){
    if((GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_4)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_5)==0)
||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)==0)||(GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_7)==0)){
        Delay_ms(10);
        if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_4)){
            Do_Click(GPIO_Pin_4 , num+0);
        }else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_5)){
            Do_Click(GPIO_Pin_5 , num+1);
        }else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_6)){
            Do_Click(GPIO_Pin_6 , num+2);
        }else if(0 == GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_7)){
            Do_Click(GPIO_Pin_7 , num+3);
        }else {
            anxia = 0;
            GPIO_Write(GPIOA , off);
        }
    }
}
复制代码
void Do_Click(uint16_t gpio_pin_x , u8 num){
    anxia = 1;
    key = num;
    while(!GPIO_ReadInputDataBit(GPIOA , gpio_pin_x));
}

扫描过程 (KEY_Scan):

  • 循环扫描每一行,通过改变行线的状态来检测是否有键按下。
  • 调用KEY_Click_Listener函数来处理每一行的按键检测。

读取按键值 (Key_Read):

  • 返回当前按下的键对应的数值。

补充说明:

复制代码
u16 line[4] = {0x00fe , 0x00fd , 0x00fb ,0x00f7};
u16 off = 0x00ff; // 全部引脚置为1
u16 keys[16] = {
    49, 50, 51, 65,
    52, 53, 54, 66,
    55, 56, 57, 67,
    42, 48, 35, 68,
};

line 定义 了4个16进制的数值分别转成二进制

0000 0000 1111 1110 0x00fe

0000 0000 1111 1101 0x00fd

0000 0000 1111 1011 0x00fb

0000 0000 1111 0111 0x00f7

低4位为行 高四位为列

设置0就是给对应行设置低电平

这样我们在scan的代码就能看出来 扫描的做法就是先给传入的行line[x] 设置低电平

所有列都是高电平当扫描到某一列为低电平时就说明这一列被点击了。

循环从第一列到第四列设置低电平直到检测到某一列也变成低电平

假设1被点击 则1这一列也是低电平

就变成第一行 第一列低电平

这样就能确定1被点击。给对应参数赋值1即可

再根据定义的keys (askII 码表对应数值 )

主要代码就是上面这些,其他代码只要复制 江科大OLED的课件源码即可

使用方式 man.c

复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key4x4.h"

int main(void)
{
    
    /*模块初始化*/
    OLED_Init();        //OLED初始化
    KEY_4x4_Init();
    
    /*OLED显示*/
    OLED_ShowString(1, 1, "in put:");                //1行1列显示字符A
    u8 num = 0;
    while (1)
    {
        KEY_Scan();
        num = Key_Read();
        OLED_ShowChar(1 ,8 ,num);
    }
}
相关推荐
ElePower952722 分钟前
STM32学习(一)
stm32·嵌入式硬件
紫阡星影2 小时前
【模块系列】STM32&1.69TFT屏幕
stm32·单片机·嵌入式硬件
彭某。2 小时前
STM32低功耗模式结合看门狗
stm32·单片机·嵌入式硬件
小菜鸟学代码··11 小时前
STM32文件详解
stm32·单片机·嵌入式硬件
wenchm16 小时前
细说STM32F407单片机IIC总线基础知识
stm32·单片机·嵌入式硬件
嵌入式lover16 小时前
STM32项目之环境空气质量检测系统软件设计
stm32·单片机·嵌入式硬件
kenwblack17 小时前
STM32 SPI读取SD卡
stm32·单片机
1101 110120 小时前
STM32-笔记10-手写延时函数(SysTick)
笔记·stm32·单片机
极客小张21 小时前
基于STM32的智慧农业控制系统设计:python可视化、UART、I2C、TCP/HTTP技术
python·stm32·单片机·物联网·tcp/ip·毕业设计·课程设计
wenchm21 小时前
细说STM32F407单片机通过IIC读写EEPROM 24C02
stm32·单片机·嵌入式硬件