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的代码就能看出来 扫描的做法就是先给传入的行linex 设置低电平

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

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

假设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);
    }
}
相关推荐
@晓凡3 小时前
keil5找不到下载器
stm32
振南的单片机世界11 小时前
SysTick硬核拆解:既是HAL_Delay的“心跳”,也是RTOS的“节拍器”
arm开发·stm32·单片机·嵌入式硬件
Lzh编程小栈12 小时前
【嵌入式底层】SPI超透彻详解:通信原理、四线结构、四种模式、寄存器底层 + 面试全集
c语言·stm32·单片机·面试·职场和发展
WWJA王文举15 小时前
RS485通信超时全面排查:终端电阻、A/B线、DE方向控制、串口参数和Modbus一次讲透
stm32·通信协议·rs485
嘉子的秃头日记19 小时前
机械革命“自动修复”无法修复你的电脑
stm32·单片机·电脑
大爱编程♡19 小时前
STM32-SPI
stm32·单片机·嵌入式硬件
hsjiasb1 天前
FreeRTOS学习(二十六)——动态内存管理heap_1到heap_5
stm32·单片机·学习·学习笔记·freertos
LCG元1 天前
STM32+ESP8266+MQTT 物联网气象站:从零搭建温湿度远程监测系统(附完整源码)
stm32·物联网·struts
FakeOccupational1 天前
【电路笔记 STM32】Cortex-M7 内核上的数据缓存(D-Cache)结构+MPU+DMA&Cache+STM32CubeMX配置
笔记·stm32·缓存
殷忆枫1 天前
基于K210与STM32的智能垃圾分类与物联网监管系统
stm32·物联网·分类