精华内容
下载资源
问答
  • stm32 矩阵键盘

    2013-08-19 23:19:29
    stm32 矩阵键盘 绝对可用 带有注释
  • stm32矩阵键盘

    2013-08-29 17:35:09
    stm32矩阵键盘,扫描模式,自己写的,很简洁
  • STM32矩阵键盘

    2018-04-02 23:44:48
    基于STM32的精简版矩阵键盘,通俗易懂,实用性非常好!
  • STM32 矩阵键盘

    2013-08-31 23:28:23
    采用STM3210FVCT6 矩阵键盘 扫描方式
  • stm32矩阵键盘扫描

    2015-08-09 10:24:21
    stm32矩阵键盘扫描程序,亲测可用,GPIOA口,原理与51单片机类似
  • STM32 矩阵键盘 程序 可以实现任意不连续引脚配置的完美设置 并且显示 显示采用JLX12864G-086-PC 引脚任意配置 完美显示
  • STM32矩阵键盘测试代码以及完整工程 使用的是正点原子的精英版测试的,可通过串口发送所按下的按键的键值 工程完整,注释清楚,可以直接使用 方便移植 此次的实验GPIO口链接图: C4------------>PC0 C3-...
  • stm32矩阵键盘按键扫描程序亲测可用,PA0~PA7为矩阵键盘接口,PA9PA10为串口
  • STM32矩阵键盘实现方法收集, STM32用矩阵键盘,不带外部中断,可以多个按键同时按下 C代码: STM32用矩阵键盘,不带外部中断,可以多个按键同时按下
  • STM32 矩阵键盘扫描实验

    热门讨论 2011-05-15 09:45:27
    STM32 矩阵键盘扫描实验,完整程序,高度的可移植性,可以接到任意IO口。 4*4 与4*3 扫描读按键程序
  • STM32F103矩阵键盘实验,按下那个键,串口输入显示,双去抖
  • STM32矩阵键盘实现

    2015-06-25 00:23:07
    基于STM32矩阵键盘实现,可用于开发板外置键盘的使用
  • STM32矩阵键盘代码

    2016-12-16 08:43:17
    该程序是STM32F103系列的矩阵键盘代码,本人使用过
  • STM32矩阵键盘不带外部中断可以多个按键同时按下 C代码STM32矩阵键盘不带外部中断可以多个按键同时按下 /* 矩阵键盘 .h 文件 */ #ifndef _COMMON_H #define _COMMON_H #include " /* 4*4 矩阵键盘 */ void ...
  • STM32矩阵键盘的实现

    2018-06-24 11:04:45
    STM32中断的方式实现矩阵按键。使用外部中断5_9,外部中断接口接PC8~PC5。
  • stm32矩阵键盘程序

    2016-07-25 13:43:46
    最简单的矩阵键盘程序代码,扫描只有九行代码,通俗易懂,方便移植,
  • STM32 矩阵键盘驱动

    2015-08-08 17:03:10
    32矩阵键盘驱动,包含.c 和 .h文件。无按键返回-1,其余对应0~15.
  • STM32矩阵键盘 一、实现效果   同时可实现 按键消抖 松手 二、使用方法  ① 包含正点原子的sys.h  ② 制作.h .c文件 -源码见 “二”  ③ 把 key_scan 函数 放入 5ms 的定时器中断,可自实现 按键消抖  ④ 按...

    STM32矩阵键盘(HAL库)

    根据 源博客 基于 STM32F407 使用 4*4 矩阵键盘(附完整程序) 改编而来

    一、实现效果

      同时可实现 按键消抖 松手检测

    二、使用方法

     ① 包含正点原子的sys.h
     ② 制作.h .c文件 -源码见 “二”
     ③ 把 key_scan 函数 放入 5ms 的定时器中断,可自实现 按键消抖
     ④ 接线方法
    接线方法
     ⑤ 按键值keyval可这么用 :

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        if(htim==(&htim1))  //1ms定时
        {
            ms++;
            if (!(ms%5)) 
                key_scan();
        }
    }
    
    while (1)
    {
    	if (Key_val == 1) //**按键扫描**
    	{
    		while (Key_val == 1); //**松手检测**
    		xxxxxxxxxx //自己的逻辑代码块
    	]
    }
    

    三、源代码

    ①.c文件

    #include "matrix_key.h"
    #include "sys.h"
    #include "stm32f4xx.h"                  // Device header
    
    
    u8 Key_val = 0xff;
    
    void key_scan()
    {
    	uint16_t temp, flag = 0;
        static u8 key_state = 0;
        
        switch (key_state){
        case 0:{
        /*=========================以下代码是按键扫描程序=========================*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET); // 先清空引脚状态
    	/*----------------------------Scan the 1st ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_SET);   // 设置PD0~2为1
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);                       // 设置PD3为0    二进制编码为 0111
        if((GPIOD->IDR & 0xF0) != 0xF0)
        {key_state = 1;flag = 1;}
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
    	/*----------------------------Scan the 2nd ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_3, GPIO_PIN_SET);   
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);     
        if((GPIOD->IDR & 0xF0) != 0xF0)
        {key_state = 1;flag = 1;}
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
    	/*----------------------------Scan the 3rd ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_SET);   
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_RESET); 
        if((GPIOD->IDR & 0xF0) != 0xF0)
        {key_state = 1;flag = 1;}
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
    	/*----------------------------Scan the 4th ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_SET);   
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0, GPIO_PIN_RESET);   
        if((GPIOD->IDR & 0xF0) != 0xF0)
        {key_state = 1;flag = 1;}
        if (flag == 0)
            Key_val = 0xff;
        }break;
        
        case 1:{
    	/*=========================以下代码是按键扫描程序=========================*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET); // 先清空引脚状态
    	/*----------------------------Scan the 1st ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_SET);   // 设置PD0~2为1
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);                       // 设置PD3为0    二进制编码为 0111
        if((GPIOD->IDR & 0xF0) != 0xF0){      
            flag = 1;
            temp = (GPIOD->IDR & 0xF7);                                         // GPIOD->IDR寄存器为端口输入数据寄存器
            switch(temp){                                                        // 用来读取GPIO口的电平状态
                case 0xE7 : Key_val = 1;key_state = 2;break;
                case 0xD7 : Key_val = 2;key_state = 2;break;
                case 0xB7 : Key_val = 3;key_state = 2;break;
                case 0x77 : Key_val = 4;key_state = 2;break;
                default  : Key_val = 0xff;key_state = 0;break;
            }}
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
    	/*----------------------------Scan the 2nd ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_3, GPIO_PIN_SET);   
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);                       
    	
        if((GPIOD->IDR & 0xF0) != 0xF0){
            flag = 1;
            temp = (GPIOD->IDR & 0xFB);
            switch(temp){
                case 0xEB : Key_val = 5;key_state = 2;break;
                case 0xDB : Key_val = 6;key_state = 2;break;
                case 0xBB : Key_val = 7;key_state = 2;break;
                case 0x7B : Key_val = 8;key_state = 2;break;
                default  : Key_val = 0xff;key_state = 0; break;
            }}
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
    	/*----------------------------Scan the 3rd ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_SET);   
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_RESET);                       
    	
        if((GPIOD->IDR & 0xF0) != 0xF0){
            flag = 1;
            temp = (GPIOD->IDR & 0xFD);
            switch(temp){
                case 0xED : Key_val = 9;key_state = 2;break;
                case 0xDD : Key_val = 10;key_state = 2;break;
                case 0xBD : Key_val = 11;key_state = 2;break;
                case 0x7D : Key_val = 12;key_state = 2;break;
                default   : Key_val = 0xff;key_state = 0; break;
            }}
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
    	/*----------------------------Scan the 4th ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_SET);   
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0, GPIO_PIN_RESET);                       
        if((GPIOD->IDR & 0xF0) != 0xF0){
            flag = 1;
            temp = (GPIOD->IDR & 0xFE);
            switch(temp){
                case 0xEE : Key_val = 13;key_state = 2;break;
                case 0xDE : Key_val = 14;key_state = 2;break;
                case 0xBE : Key_val = 15;key_state = 2;break;
                case 0X7E : Key_val = 16;key_state = 2;break;
                default  : Key_val = 0xff; key_state = 0;break;
            }}
        if (!flag) Key_val = 0xff;
        }break;
        case 2:{
        /*=========================以下代码是按键扫描程序=========================*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET); // 先清空引脚状态
    	/*----------------------------Scan the 1st ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2, GPIO_PIN_SET);   // 设置PD0~2为1
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET);                       // 设置PD3为0    二进制编码为 0111
        if((GPIOD->IDR & 0xF0) == 0xF0)
            key_state = 0;
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
    	/*----------------------------Scan the 2nd ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_3, GPIO_PIN_SET);   
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);     
        if((GPIOD->IDR & 0xF0) != 0xF0)
            key_state = 0;
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
    	/*----------------------------Scan the 3rd ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_SET);   
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_RESET); 
        if((GPIOD->IDR & 0xF0) != 0xF0)
            key_state = 0;
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);
    	/*----------------------------Scan the 4th ROW----------------------------*/
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_SET);   
    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_0, GPIO_PIN_RESET);   
        if((GPIOD->IDR & 0xF0) != 0xF0)
            key_state = 0;
        }
        }
    }
    
    

    ②.h文件

    #ifndef __MATRIX_KEY_H
    #define __MATRIX_KEY_H
    
    void key_scan(void);
    
    #endif
    
    
    
    展开全文
  • STM32矩阵键盘程序

    2014-03-04 16:59:18
    键盘程序,stm32
  • STM32 矩阵键盘扫描

    2017-07-27 03:49:45
    可以 任意管脚 数据结构实现 只需添加管脚无需其他修改 即可返回按键值
  • 矩阵键盘矩阵键盘简介矩阵键盘扫描原理端口的配置相关函数的编写主函数与其他串口的接线与矩阵键盘的接线load与运行调试 矩阵键盘简介 什么是矩阵键盘 矩阵键盘是单片机外部设备中所使用的排布类似于矩阵的键盘组,...

    矩阵键盘简介

    1. 什么是矩阵键盘
      矩阵键盘是单片机外部设备中所使用的排布类似于矩阵的键盘组,由于电路设计时需要更多的外部输入,单独的控制一个按键需要浪费很多的IO资源,所以就有了矩阵键盘,常用的矩阵键盘有4X4和8X8,其中用的最多的是4X4。
    2. 矩阵键盘的原理
      矩阵键盘又称为行列式键盘,它是用4条I/O线作为行线,4条I/O线作为列线组成的键盘。
      在行线和列线的每一个交叉点上,设置一个按键。这样键盘中按键的个数是4×4个。
      这种行列式键盘结构能够有效地提高单片机系统中I/O口的利用率。由于单片机IO端口具有线与的功能,因此当任意一个按键按下时,行和列都有一根线被线与,通过运算就可以得出按键的坐标从而判断按键键值。

    矩阵键盘扫描原理

    在这里插入图片描述

    1. 行扫描的原理:因为如果有按键按下的话,某一个输入的引脚就会跟对应的输出引脚连接,因为输出为高电平,所以对应的输入引脚会被拉高,读取引脚的状态,判断哪个引脚被拉高就可以知道哪一行有按键按下了;总的来说是通过高四位输出高电平来对矩阵键盘进行逐行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一行按键被按下。
    2. 再通过列操作模块:
    #define KEY_CLO0_OUT_LOW  GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_RESET)
    #define KEY_CLO1_OUT_LOW  GPIO_WriteBit(GPIOB,GPIO_Pin_13,Bit_RESET)
    #define KEY_CLO2_OUT_LOW  GPIO_WriteBit(GPIOB,GPIO_Pin_14,Bit_RESET)
    #define KEY_CLO3_OUT_LOW  GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_RESET)
    
    #define KEY_CLO0_OUT_HIGH  GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET) 
    #define KEY_CLO1_OUT_HIGH  GPIO_WriteBit(GPIOB,GPIO_Pin_13,Bit_SET)
    #define KEY_CLO2_OUT_HIGH  GPIO_WriteBit(GPIOB,GPIO_Pin_14,Bit_SET)
    #define KEY_CLO3_OUT_HIGH  GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_SET)
    
    

    来进行列扫描。

    端口的配置

    介绍完矩阵键盘的扫描原理了我们该通过keli来实现我们想要的功能啦,首先我们要进行的就是对我们所需要的端口进行配置,如下:

    
    //端口的配置
    void key_init(){
    
    	GPIO_InitTypeDef GPIO_InitStruture;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //打开PB时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); //打开PE时钟
    	
    	//定义PB12、PB13、PB14、PB15为推挽输出 
    	GPIO_InitStruture.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_InitStruture.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
    	GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB,&GPIO_InitStruture);
    	
    	//定义PD8、PD9、PD10、PD11为上拉输入 分别定义为四行
    	GPIO_InitStruture.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStruture.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;
    	GPIO_Init(GPIOD,&GPIO_InitStruture);
    }
    

    相关函数的编写

    配置完我们所需要的端口,接下来我们就应该编写相关函数啦。

    1. 行扫描函数:
    //如果为1,代表没有按键被按下,如果为0,代表有按键被按下
    char KEY_ROW_SCAN(void)
    {
        //读出行扫描状态
        Key_row[0] = GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_8)<<3;
        Key_row[0] = Key_row[0] | (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_9)<<2);
        Key_row[0] = Key_row[0] | (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_10)<<1);
        Key_row[0] = Key_row[0] | (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11));
        
    	if(Key_row[0] != 0x0f)         //不是1111,代表肯定有一个0行
        {
          delay_ms(10);                    //消抖
          if(Key_row[0] != 0x0f)
    		  //0111 1011 1101 1110
            {   
                    //printf("Key_Row_DATA = 0x%x\r\n",Key_row[0]);
                    switch(Key_row[0])
                    {
                        case 0x07:         //0111 判断为该列第1行的按键按下
                            return 1;
                        case 0x0b:         //1011 判断为该列第2行的按键按下
                            return 2;
                        case 0x0d:         //1101 判断为该列第3行的按键按下
                            return 3;
                        case 0x0e:         //1110 判断为该列第4行的按键按下
                            return 4;
                        default :
                            return 0;
                    }
            }
            else return 0;
        }
        else return 0;
    }
    
    1. 按键扫描函数:
    char KEY_SCAN(void)
    {    
        char Key_Num=0;            //1-16对应的按键数
        char key_row_num=0;        //行扫描结果记录
        
        KEY_CLO0_OUT_LOW;        
        if( (key_row_num=KEY_ROW_SCAN()) != 0 )
        { 
            while(KEY_ROW_SCAN() != 0);  //消抖
            Key_Num = 0 + key_row_num;
        }
        KEY_CLO0_OUT_HIGH;
        
        KEY_CLO1_OUT_LOW;        
        if( (key_row_num=KEY_ROW_SCAN()) != 0 )
        { 
            while(KEY_ROW_SCAN() != 0);
            Key_Num = 4 + key_row_num;
        }
        KEY_CLO1_OUT_HIGH;
        
        KEY_CLO2_OUT_LOW;    
        if( (key_row_num=KEY_ROW_SCAN()) != 0 )
        { 
            while(KEY_ROW_SCAN() != 0);
        Key_Num = 8 + key_row_num;
        }
        KEY_CLO2_OUT_HIGH;
        
        KEY_CLO3_OUT_LOW;    
        if( (key_row_num=KEY_ROW_SCAN()) != 0 )
        {
            while(KEY_ROW_SCAN() != 0);
            Key_Num = 12 + key_row_num;
        }
        KEY_CLO3_OUT_HIGH;
        
        return Key_Num;
    }
    

    主函数与其他

    1. 主函数:
    #include "stm32f10x.h"
    #include "delay.h"
    #include "led.h"
    #include "key16.h"
    #include "stdio.h"
    #include "usart.h"
    
    
    int main(void)
    {
    	vu8 key=0;
    	char key_confirm;
    	led_init();
    	delay_init();
    	key_init();
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    	uart_init(115200);
    	
    	while(1)
    	{
    		key_confirm = KEY_SCAN();
    		if(key_confirm>0&&key_confirm<17){
    			printf("Key_NUM = %d \r\n",key_confirm); //按下1-16个按键的操作
          printf("= = = = = = = = = = = \r\n");		
    		}	
    	}	
    
    }
    
    1. key.c:
    #include "key16.h"
    #include "delay.h"
    
    
    uint8_t Key_row[1]={0xff};   //定义一个数组,存放行扫描状态
    
    //端口的配置
    void key_init(){
    
    	GPIO_InitTypeDef GPIO_InitStruture;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //打开PB时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); //打开PE时钟
    	
    	//定义PB12、PB13、PB14、PB15为推挽输出 
    	GPIO_InitStruture.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_InitStruture.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
    	GPIO_InitStruture.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB,&GPIO_InitStruture);
    	
    	//定义PD8、PD9、PD10、PD11为上拉输入 分别定义为四行
    	GPIO_InitStruture.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStruture.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;
    	GPIO_Init(GPIOD,&GPIO_InitStruture);
    	
    
    }
    
    /***
     *函数名:KEY_ROW_SCAN
     *功  能:按键行扫描
     *返回值:1~4,对应1~4行按键位置
     */
    //如果为1,代表没有按键被按下,如果为0,代表有按键被按下
    char KEY_ROW_SCAN(void)
    {
        //读出行扫描状态
        Key_row[0] = GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_8)<<3;
        Key_row[0] = Key_row[0] | (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_9)<<2);
        Key_row[0] = Key_row[0] | (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_10)<<1);
        Key_row[0] = Key_row[0] | (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11));
        
    	if(Key_row[0] != 0x0f)         //不是1111,代表肯定有一个0行
        {
          delay_ms(10);                    //消抖
          if(Key_row[0] != 0x0f)
    		  //0111 1011 1101 1110
            {   
                    //printf("Key_Row_DATA = 0x%x\r\n",Key_row[0]);
                    switch(Key_row[0])
                    {
                        case 0x07:         //0111 判断为该列第1行的按键按下
                            return 1;
                        case 0x0b:         //1011 判断为该列第2行的按键按下
                            return 2;
                        case 0x0d:         //1101 判断为该列第3行的按键按下
                            return 3;
                        case 0x0e:         //1110 判断为该列第4行的按键按下
                            return 4;
                        default :
                            return 0;
                    }
            }
            else return 0;
        }
        else return 0;
    }
    
    /***
     *函数名:KEY_SCAN
     *功  能:4*4按键扫描
     *返回值:0~16,对应16个按键
     */
    char KEY_SCAN(void)
    {    
        char Key_Num=0;            //1-16对应的按键数
        char key_row_num=0;        //行扫描结果记录
        
        KEY_CLO0_OUT_LOW;        
        if( (key_row_num=KEY_ROW_SCAN()) != 0 )
        { 
            while(KEY_ROW_SCAN() != 0);  //消抖
            Key_Num = 0 + key_row_num;
        }
        KEY_CLO0_OUT_HIGH;
        
        KEY_CLO1_OUT_LOW;        
        if( (key_row_num=KEY_ROW_SCAN()) != 0 )
        { 
            while(KEY_ROW_SCAN() != 0);
            Key_Num = 4 + key_row_num;
            //printf("Key_Clo_2\r\n");
        }
        KEY_CLO1_OUT_HIGH;
        
        KEY_CLO2_OUT_LOW;    
        if( (key_row_num=KEY_ROW_SCAN()) != 0 )
        { 
            while(KEY_ROW_SCAN() != 0);
        Key_Num = 8 + key_row_num;
            //printf("Key_Clo_3\r\n");
        }
        KEY_CLO2_OUT_HIGH;
        
        KEY_CLO3_OUT_LOW;    
        if( (key_row_num=KEY_ROW_SCAN()) != 0 )
        {
            while(KEY_ROW_SCAN() != 0);
            Key_Num = 12 + key_row_num;
        }
        KEY_CLO3_OUT_HIGH;
        
        return Key_Num;
    }
    
    
    1. key.h:
    #ifndef _KEY16_H
    #define _KEY16_H
    
    #include "sys.h"
    #include "stm32f10x.h"
    
    #include <string.h>
    
    
    void key_init();
    char KEY_SCAN(void);
    char KEY_ROW_SCAN(void);
    void HW_KEY_FUNCTION(void);
    
    
    #define KEY_CLO0_OUT_LOW  GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_RESET)
    #define KEY_CLO1_OUT_LOW  GPIO_WriteBit(GPIOB,GPIO_Pin_13,Bit_RESET)
    #define KEY_CLO2_OUT_LOW  GPIO_WriteBit(GPIOB,GPIO_Pin_14,Bit_RESET)
    #define KEY_CLO3_OUT_LOW  GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_RESET)
    
    #define KEY_CLO0_OUT_HIGH  GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET) 
    #define KEY_CLO1_OUT_HIGH  GPIO_WriteBit(GPIOB,GPIO_Pin_13,Bit_SET)
    #define KEY_CLO2_OUT_HIGH  GPIO_WriteBit(GPIOB,GPIO_Pin_14,Bit_SET)
    #define KEY_CLO3_OUT_HIGH  GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_SET)
    
    
    #endif
    
    

    串口的接线与矩阵键盘的接线

    1. 首先我们先接串口,把串口的VCC和GND分别接到主板上的3.3V和GND上(注意要把串口上的插线帽调整到3.3V,不然容易把板子烧坏,板子烧坏了那可就成大xx了),然后再把串口上的TXD和RXD分别连到主板的RXD和TXD。
    2. 然后我们来接矩阵键盘,要用到八根线,R1 ~ R4分别连到主板上的PD8 ~ PD11,C1 ~ C4分别连到主板上的PB12 ~ PB15.
      在这里插入图片描述

    load与运行调试

    好啦,所有准备工作都完成啦!!又到了我们激动人心的时刻啦!!
    运行成功图如下:
    在这里插入图片描述
    over。

    展开全文
  • 有的单片机应用需要使用的按键数量比较多,比如:密码锁,这时如果按照之前的设计,一个GPIO控制一个按键的话,有点浪费单片机资源,这时候我们常常需要使用矩阵键盘。常见的矩阵键盘有如下两种:后面的为薄膜按键。...

    点击上方“嵌入式从0到1”,选择“置顶/星标公众号

    干货福利,第一时间送达!

    有的单片机应用需要使用的按键数量比较多,比如:密码锁,这时如果按照之前的设计,一个GPIO控制一个按键的话,有点浪费单片机资源,这时候我们常常需要使用矩阵键盘。

    常见的矩阵键盘有如下两种:

    0ef580b86a5535db092168dec88ca743.png
    9fd3c2829547d6b1a24c8742b2de6089.png

    后面的为薄膜按键。
    上图中,
    上面的按键按照5行*4列的布局排布,所以整个矩阵键盘共计引出了9(5+4)个引脚;
    下面的按键按照4行*4列的布局排布,所以整个矩阵键盘共计引出了8(4+4)个引脚;由此可以看出,按键数量越多,节省的IO口越多。

    直插按键和薄膜按键两种方式的实现原理一样,本文我们以薄膜按键为例进行讲解。

    薄膜按键(Metal dome array),是一块带触点的PET薄片(包括金属弹片也叫锅仔片),用在PCB、FPC等线路板上作为开关使用,在使用者与仪器之间起到一个重要的触感型开关的作用。与传统的硅胶按键相比,薄膜按键具有更好的手感、更长的寿命,可以间接地提高使用导电膜的各类型开关的生产效率。薄膜按键上的触点位于PCB板上的导电部位(大部分位于线路板上的金手指上方),当按键受到外力按压时,触点的中心点下凹,接触到PCB上的线路,从而形成回路,电流通过,整个产品就得以正常工作。

    薄膜按键与传统硅胶按键相比较具有以下优势:

    1. 触感更好,使用寿命更长久;
    2. 按键键薄、柔软、防护性能好;
    3. 薄膜按键触板位于导电部位,按下会凹进去进而接触到PCB上的线路从而触发开关;
    4. 导电薄膜上面布满了金属点进行连接,按下薄膜按键就能启动对应的功能;
    5. 薄膜按键以成本低、工艺简单和手感好。
    c127d8490738ea051cb5742a99ebd17e.png

    有专门定制薄膜按键的商家,可以随意定制外观。

    ae1fb63076b43c01cdbbf136bfca3738.png

    薄膜按键的内部结构如下图所示:

    b50ce82094c86825963b2c5b429ca6f2.png

    注:图片来源于网络,侵权请后台联系号主删除。

    有的矩阵键盘后面有3M背胶,可撕下粘纸,粘贴在光滑表面上,方便固定。

    硬件连接

    adfe006ad1d98b634f41c751b77c338b.png
    87ebb3b23f134868955f6f2c467e4ec5.png
    STM32核心板排线引脚号4*4矩阵键盘
    PC21行1
    PC12行2
    PC03行3
    PC134行4
    PB95列1
    PB86列2
    PB77列3
    PB68列4

    按键扫描原理

    对于4*4的薄膜按键,只需要8个标准IO口,即可实现16个按键扫描,独立输入。

    各种矩阵键盘的驱动方式类似,我们以4*4的矩阵键盘为例,看看它的驱动方式。

    矩阵按键扫描原理:

    行列扫描:

    • 我们先将四行对应的GPIO引脚设为输出模式,并输出高电平;
    • 将四列对应的GPIO引脚设为下拉输入模式,没有按键按下状态时,这四个引脚读取默认返回0;
    daec9145f6a2f541ead2b4e6dd687fd6.png
    • 如果有一个按键被按下,那么这四列中就会有一个GPIO引脚读取返回1,此时能够得到被按下的键所在的列
    08ff943b647c9d8a1651808269d014a7.png

    假如被点击的按键为第三行第三列的按键

    • 为了进一步知道,被按下的键所在行,我们依次改变输出高电平的行,比如先让第一行输出高电平,另外三行输出低电平,如果四列的GPIO返回的值没有高电平,则被按下的键不在第一行;
    fcaca6a4b4399b67ce45483a43ea69f8.png
    • 类似上一步操作,接下来让第二行输出高电平,然后其他行输出低电平;
    d62f821ed43ea89fab0c624b7e6a0c85.png
    • 然后第三行输出高电平,其他行低电平;第四行输出高电平,其他行输出低电平;当某行为高电平时,四列对应的GPIO读取有返回1,则该行即为被按下行
    2102151c3437d37184bf0ede47f0b793.png
    • 由于上面得出了被按下的列和行,那么行列的交叉即可得出被按下的键。上面实例可知,我们被按下的键为第三行、第三列对应的键。

    这种方式获得按键键值的方式即为行列扫描

    按键扫描的代码实现如下:

    /*假定Row为输出,Col为输入;如果有按键被按下,则输入(Col)一定有非0值;四个输出(Row)依次改变,每次仅有一个IO为高电平,如果此时输入(Col)不为0的,那么即可确定此行列值即为按键值;*/int Value44Key(void)      //定义矩阵键盘的返回值,返回值对应相关功能,{  int KeyValue = 0;      //KeyValue是最后返回的按键数值    GPIORow_Output(0);    //全部置高    if(KEY44_Scan()!=0)    //如果没有按键按下,返回值为-1  {    return -1;  }  else            //有按键按下  {    delay_ms(5);      //延时5ms去抖动    if(KEY44_Scan() == 0x00)  //如果延时5ms后输入0, 则刚刚是抖动产生的    {      return -1;    //所以还是返回 -1    }  }   GPIORow_Output(1);    //第一行置高   switch(KEY44_Scan())    //对应的输入值判断不同的按键值  {    case COL1_KEY_PRES:      KeyValue = 1;      break;    case COL2_KEY_PRES:      KeyValue = 2;      break;    case COL3_KEY_PRES:      KeyValue = 3;      break;    case COL4_KEY_PRES:      KeyValue = 4;      break;  }   GPIORow_Output(2);    //第二行置高  switch(KEY44_Scan())    //对应的输入值判断不同的按键值  {    case COL1_KEY_PRES:      KeyValue = 5;      break;    case COL2_KEY_PRES:      KeyValue = 6;      break;    case COL3_KEY_PRES:      KeyValue = 7;      break;    case COL4_KEY_PRES:      KeyValue = 8;      break;  }   GPIORow_Output(3);    //第三行置高  switch(KEY44_Scan())    //对应的输入值判断不同的按键值  {    case COL1_KEY_PRES:      KeyValue = 9;      break;    case COL2_KEY_PRES:      KeyValue = 10;      break;    case COL3_KEY_PRES:      KeyValue = 11;      break;    case COL4_KEY_PRES:      KeyValue = 12;      break;  }   GPIORow_Output(4);    //第四行置高  switch(KEY44_Scan())    //对应的输入值判断不同的按键值  {    case COL1_KEY_PRES:      KeyValue = 13;      break;    case COL2_KEY_PRES:      KeyValue = 14;      break;    case COL3_KEY_PRES:      KeyValue = 15;      break;    case COL4_KEY_PRES:      KeyValue = 16;      break;  }   return KeyValue;}

    这种行列扫描的方式实现的按键驱动,实际应用中,如果程序过于复杂,那么按键键值的获取可能不是很及时,有时可能会出现按下无响应的状态。

    STM32的外部中断特别多,每个GPIO都可以作为外部中断,各位可以尝试一下,使用中断的方式,如何实现矩阵键盘的驱动呢?


    f34eef4d0863530752390b9c7b767125.png
    757ea40779711f743bbbe5fcc22a5236.gif

    传统美德不能丢, 

    偷偷摸摸请点赞, 

    明目张胆请在看89e580ba5d5d5f1d12daf243ee397f86.png

    展开全文
  • stm32f103开发板。 消抖。 col列,Pin配置为PP推挽输出模式; row行,Pin配置为Input模式,启用内部上拉电阻
  • STM32 矩阵键盘控制数码管

    千次阅读 2019-10-14 18:52:34
    在以往的32博客中,见过了数码管和矩阵键盘,今天就将他们结合起来,如何用矩阵键盘去控制数码管。 我们都知道数码管可以显示从0-9十位数字,也可以显示从A-F的字母,将数码管和2*2矩阵键盘结合起来也就是使用四个...

    在以往的32博客中,见过了数码管和矩阵键盘,今天就将他们结合起来,如何用矩阵键盘去控制数码管。
    我们都知道数码管可以显示从0-9十位数字,也可以显示从A-F的字母,将数码管和2*2矩阵键盘结合起来也就是使用四个按键分别控制加,减,置0和全部点亮。
    加减的功能不用多说也就是从0加到F,如果继续增加的话又从0开始,减也是一样,置0也就是将数据恢复为初始状态,全部点亮是为了检验数码管是否可以正常工作。
    话不多说,咱们来看一下代码实现

    key.c:设置按键

    #include "key.h"
    #include "delay.h"
    #include "usart.h"
     	    
    
    //PB5~7设置成数入
    //PB8~10设置成输出
    void KEY_Init1(void)
    {
    	RCC->APB2ENR|=1<<3;    
    	JTAG_Set(SWD_ENABLE);	
    	GPIOB->CRL&=0XFF0FFFFF;	
    	GPIOB->CRL|=0X00800000;
     // GPIOB->ODR|=1<<5;  
      GPIOB->CRL&=0XF0FFFFFF;	 
    	GPIOB->CRL|=0X08000000;
    	//GPIOB->ODR|=1<<6;
      GPIOB->CRL&=0X0FFFFFFF;		  
    	GPIOB->CRL|=0X80000000;
    	//GPIOB->ODR|=1<<7;
    	GPIOB->CRH&=0XFFFFFFF0;	
    	GPIOB->CRH|=0X00000003;
    	GPIOB->ODR|=1<<8;
    	GPIOB->CRH&=0XFFFFFF0F;		  
    	GPIOB->CRH|=0X00000030;
    	GPIOB->ODR|=1<<9;
    	GPIOB->CRH&=0XFFFFF0FF;		  
    	GPIOB->CRH|=0X00000300;
    	GPIOB->ODR|=1<<10;
    		key9_Out=1;key8_Out=1;
    } 
    void KEY_Init2(void)
    {
    	GPIOB->CRL&=0XFF0FFFFF;		  
    	GPIOB->CRL|=0X00300000;
    	GPIOB->ODR|=1<<5;
      GPIOB->CRL&=0XF0FFFFFF;		  
    	GPIOB->CRL|=0X03000000;
    	GPIOB->ODR|=1<<6;
      GPIOB->CRL&=0X0FFFFFFF;	
    	GPIOB->CRL|=0X30000000;
    	GPIOB->ODR|=1<<7;
    	GPIOB->CRH&=0XFFFFFFF0;	  
    	GPIOB->CRH|=0X00000008;
    	//GPIOB->ODR|=1<<8;
    	GPIOB->CRH&=0XFFFFFF0F;	  
    	GPIOB->CRH|=0X00000080;
    	//GPIOB->ODR|=1<<9;
    	GPIOB->CRH&=0XFFFFF0FF;	
    	GPIOB->CRH|=0X00000800;
      //GPIOB->ODR|=1<<10;	
    		key6_Out=1;key5_Out=1;
    } 
    
    u8 KEY_Scan1()
    {	 
    	u8 H=0;
    	GPIOB->ODR&=~(1<<5);
    	GPIOB->ODR&=~(1<<6);
    	KEY_Init1();
    	if(key5_In==1||key6_In==1)
    	{
    		delay_ms(10);
    		if(key5_In==1)    
    			H=1;
    		if(key6_In==1)   
    			H=2;
    		return H*10;
    	}
    	else 
    	 return 0;
    }
    u8 KEY_Scan2()
    {	 
    	u8 L=0;
        GPIOB->ODR&=~(1<<8);
    	GPIOB->ODR&=~(1<<9);
      KEY_Init2();
      if(key8_In==1||key9_In==1)
    	{
    	   delay_ms(10);
    		if(key8_In==1)    
    		     L=1;
    		else if(key9_In==1)    
    			   L=2;
    	  return L;
    	}
    	else return 0;
    }
    
    u8 KEY_Out(void)
    {
    	u8 t=0,p=1;
    	while((KEY_Scan1()==0||KEY_Scan2()==0))
    	{
    		t=KEY_Scan1()+KEY_Scan2();
    		if(t!=0)
    		{
    			if(t==11)
    				return KEY1H_PRES;
    			else if(t==12)
    				return KEY2H_PRES;
    		}
    	}
    }
    

    SMG.h

    #ifndef __SMG_H
    #define __SMG_H 
    #include "sys.h"
    #include "delay.h"
    
    u8 SMG_Init(void);
    	 
    #endif
    

    key.h:控制按键

    #ifndef __KEY_H
    #define __KEY_H	 
    #include "sys.h"
    
    #define KEY1H_PRES	1 
    #define KEY2H_PRES	2	
    #define KEY1L_PRES	1 
    #define KEY2L_PRES	2	
    
    #define key5_In  PBin(5)   	//PB5
    #define key6_In  PBin(6)	  	//PB6 
    	  //PB7
    #define key5_Out  PBout(5)
    #define key6_Out  PBout(6)
    
    #define key8_In  PBin(8)   	
    #define key9_In  PBin(9)	  	 
    
    #define key8_Out  PBout(8)    //PB8
    #define key9_Out  PBout(9)    //PB9
    	 
    void KEY_Init1(void);
    void KEY_Init2(void);
    u8 KEY_Scan1();
    u8 KEY_Scan2();
    u8 KEY_Out(void);
    #endif
    

    light.c:主函数

    #include "sys.h"
    #include "usart.h"		
    #include "delay.h"	
    #include "led.h" 
    #include "key.h"
    #include "smg.h"
    int main(void)
    {		   
    	static u8 k=0;
    	u8 r;
    	delay_init(72);
    	LED_Init();		  	 	//³õʼ»¯ÓëLEDÁ¬½ÓµÄÓ²¼þ½Ó¿Ú
    	while(1)
    	{
    		r=KEY_Out();
    		if(r==KEY2H_PRES)
    		{
    			if(k==0)
    				k=9;
    			else
    				k--;
    		}
    		else if(r==KEY1H_PRES)
    		{
    			if(k==9)
    			  k=0;
    		  else
    			  k++;
    		}
    		else
    			break;
    		switch(k)
    		{
    			case 0: 
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFF3F;
    				break;
    			}
    			case 1:
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFF06;
    				break;
    			}
    			case 2:
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFF5B;
    				break;
    			}
    			case 3:
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFF4F;
    				break;
    			}
    			case 4:
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFF66;
    				break;
    			}
    			case 5:
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFF6D;
    				break;
    			}
    			case 6:
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFF7D;
    				break;
    			}
    			case 7:
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFF07;
    				break;
    			}
    			case 8:
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFFFF;
    				break;
    			}
    			case 9:
    			{
    				GPIOA->ODR&=0x0000;
    				GPIOA->ODR|=0xFF6F;
    				break;
    			}
    		}
    	} 
    }
    
    展开全文
  • STM32矩阵键盘扫描

    2021-03-24 15:41:49
    #ifndef __KEY_H #define __KEY_H #include "sys.h" #include "delay.h" #define Pin0 GPIO_Pin_0 #define Pin1 GPIO_Pin_1 #define Pin2 GPIO_Pin_2 #define Pin3 GPIO_Pin_3 #define Pin4 GPIO_Pin_4 ...

空空如也

空空如也

1 2 3 4 5 ... 16
收藏数 307
精华内容 122
关键字:

stm32矩阵键盘