IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32玩矩阵开关(输入和输出) -> 正文阅读

[嵌入式]STM32玩矩阵开关(输入和输出)

一、代码设计

  1. 最常用的矩阵代码
#include<stm32f10x.h>
#include "delay.h"
#include "sys.h"

/********************************
    硬件连接:
    PA0 ----------> C4
    PA1 ----------> C3
    PA2 ----------> C2
    PA3 ----------> C1
    PA4 ----------> R1
    PA5 ----------> R2
    PA6 ----------> R3
    PA7 ----------> R4
********************************/
/********************************
    矩阵的对应关系:
         A3    A2  A1   A0
          |    |    |    |
A7-->    S1   S2   S3   S4
    
A6-->    S5   S6   S7   S8
    
A5-->    S9   S10  S11  S12
    
A4-->    S13  S14  S15  S16
    
    
********************************/

#define KEY_IN()   (GPIO_ReadInputData(GPIOA)&0x00f0)       //读取按键的输入管脚GPIOA4-7 读出行号

void KEY_Init(){
    GPIO_InitTypeDef a;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   //配置时钟给GPIOA
   
    //   上拉输入模式默认情况下是高电平,用于检测低电平的输入(就是变化结果只有0,要么不变1)
    a.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; 
	a.GPIO_Speed = GPIO_Speed_10MHz; 
	a.GPIO_Mode = GPIO_Mode_IPU;    //上拉输入 必须要配置输出寄存器为1
	GPIO_Init(GPIOA, &a);
    GPIO_SetBits(GPIOA,GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7); //还必须需要配置输出寄存器的值
   
    //key的输出管脚配置
    a.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_0;	
  	a.GPIO_Mode = GPIO_Mode_Out_PP;    //推挽输出
  	a.GPIO_Speed = GPIO_Speed_50MHz;  //高速响应
  	GPIO_Init(GPIOA, &a);    //没有配置输出寄存器,配置模式推挽输出默认未配置输出寄存器情况下为0,故不配置
}

int key_scan_lie(){
    u8 i=0;
    u16 pin=0x0001;   //根据GPIO_Pin_x找的规律
    
    //大体是先送“1”  ,本着“1碰1”上拉输入不变的方式进行扫描;每扫描一次需要重新复原,防止影响别的扫描操作;
    for(;i<4;i++,pin<<=1){
        GPIO_SetBits(GPIOA,pin);   //置为1    
        
        //这样写的原因是:当高电平3.3V遇到高电平3.3V电平变化为高电平;输入管脚为上拉输入模式
        if(KEY_IN() == 0xf0){
            GPIO_ResetBits(GPIOA,pin);  //复原 变0
            return 4-i;     //返回对应的列号
        }
        
        GPIO_ResetBits(GPIOA,pin);  //复原 变0
    }
    
    return (-16); //未扫描出列号的返回值
}

/*****************************
直接调用这个函数即可,返回对应按键的值
*****************************/
u8 key4x4_scan(){
    u8 key_value = 0;
    if(KEY_IN()!=0xf0){
        delay_ms(20);   //消抖,这么没事可说的
        if(  (key_value=KEY_IN()) !=  0xf0){   //赋值并判断
            
            // 先读出数据对应行号   0xe0  0111,0000   即PA7的管脚被变化成0
            switch(key_value){
                case 0xe0: key_value= 0*4 + key_scan_lie() ;  break;
                case 0xd0: key_value= 1*4 + key_scan_lie() ;  break;
                case 0xb0: key_value= 2*4 + key_scan_lie() ;  break;
                case 0x70: key_value= 3*4 + key_scan_lie() ;  break;
            }
            
            while(KEY_IN() != 0xf0);   //等待按键松开
        }
    }
    
    return key_value;   //返回对应的按键值:0表示未按下,负数表示扫描了行但列没扫描成功,正数表示按键按下返回正确的值
}
  1. 可管脚不连续的矩阵开关;八个Pin可以乱连的写法,修改驱动则只需要修改KEY_IN和KEY_OUT
#include<stm32f10x.h>
#include "delay.h"
#include "sys.h"
#include "oled.h"
#include <stdio.h>

#define KEY_IN()   (GPIO_ReadInputData(GPIOA)&0x00f0)       //读取按键的输入管脚GPIOA4-7 读出行号

#define KEY_IN_0()      GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)    //该函数读出的结果只有0和1
#define KEY_IN_1()      GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)
#define KEY_IN_2()      GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)
#define KEY_IN_3()      GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)

#define KEY_OUT_0(x)     do{ if(x){GPIO_SetBits(GPIOA,GPIO_Pin_0);}    \
                            else{GPIO_ResetBits(GPIOA,GPIO_Pin_0);}    \
                        }while(0)                   
#define KEY_OUT_1(x)     do{ if(x){GPIO_SetBits(GPIOA,GPIO_Pin_1);}    \
                            else{GPIO_ResetBits(GPIOA,GPIO_Pin_1);}    \
                        }while(0)                   
#define KEY_OUT_2(x)     do{ if(x){GPIO_SetBits(GPIOA,GPIO_Pin_2);}    \
                            else{GPIO_ResetBits(GPIOA,GPIO_Pin_2);}    \
                        }while(0)                   
#define KEY_OUT_3(x)     do{ if(x){GPIO_SetBits(GPIOA,GPIO_Pin_3);}    \
                            else{GPIO_ResetBits(GPIOA,GPIO_Pin_3);}    \
                        }while(0)

/********************************
    矩阵的对应关系:    OUT
         A3    A2  A1   A0    1
          |    |    |    |
IN:A4--> S1   S2   S3   S4
    
A5-->    S5   S6   S7   S8
    
A6-->    S9   S10  S11  S12
    
A7-->    S13  S14  S15  S16
    
    硬件连接输入上图:没变,但可以使矩阵管脚不连续
********************************/
void KEY_Init(){
    GPIO_InitTypeDef a;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   //配置时钟给GPIOA
   
    //   上拉输入模式默认情况下是高电平,用于检测低电平的输入(就是变化结果只有0,要么不变1)
    a.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; 
	a.GPIO_Speed = GPIO_Speed_10MHz; 
	a.GPIO_Mode = GPIO_Mode_IPU;    //上拉输入 必须要配置输出寄存器为1
	GPIO_Init(GPIOA, &a);
    GPIO_SetBits(GPIOA,GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7); //还必须需要配置输出寄存器的值
   
    //key的输出管脚配置
    a.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_0;	
  	a.GPIO_Mode = GPIO_Mode_Out_PP;    //推挽输出
  	a.GPIO_Speed = GPIO_Speed_50MHz;  //高速响应
  	GPIO_Init(GPIOA, &a);    //没有配置输出寄存器,配置模式推挽输出默认未配置输出寄存器情况下为0,故不配置
}

判断的按键输入管脚的状态,-1表示无输入,有输入返回对应的输入管脚口
int key_scan(const int rs){   //行扫描
    int rt=-1;   //返回的结果
    
    rt= KEY_IN_0()==rs ? 0 :  \
        KEY_IN_1()==rs ? 1 :  \
        KEY_IN_2()==rs ? 2 :  \
        KEY_IN_3()==rs ? 3 : -1;
   
    return rt;
}

/*****************************
直接调用这个函数即可,返回对应按键的值
*****************************/
u8 key4x4_scan(){
    u8 key_value=0;
    int key_x=-1,key_y=-1;
    
    if(key_scan(0)!= -1){//按键变动
        delay_ms(20);
        if( (key_x=key_scan(0)) != -1){   //先行扫描结果并赋值, “变”判断条件输入“变”  ,将扫描的结果赋值给key_x
            
            /***     列扫描  ,将扫描的结果赋值给key_y          ****/
            //扫描第4列的
            KEY_OUT_0(1);
            key_y = key_scan(0) == -1 ? 4 : -1;
            KEY_OUT_0(0);   //还原
            if(key_y != -1) goto done;
            
            //扫描第3列的
            KEY_OUT_1(1);
            key_y = key_scan(0) == -1 ? 3 : -1;
            KEY_OUT_1(0);   //还原
            if(key_y != -1) goto done;
            
            //扫描第2列的
            KEY_OUT_2(1);
            key_y = key_scan(0) == -1 ? 2 : -1;
            KEY_OUT_2(0);   //还原
            if(key_y != -1) goto done;
            
            //扫描第1列的
            KEY_OUT_3(1);
            key_y = key_scan(0) == -1 ? 1 : -1;
            KEY_OUT_3(0);   //还原
//            if(key_y != -1) goto done;
        }
           
        done: while(key_scan(0)!= -1);   //等待按键松开
        
        key_value= (key_x== -1 || key_y== -1) ? 0 : key_x*4 + key_y;
           
    }
    return key_value;   //返回对应的键值  0表示未按下,正数表示得到对应的值
}

二、总结

  1. 输出寄存器IDR的使用说明:在未配置任何模式下读取Pin是1状态(感觉是高阻态)

  2. 在STM32F103C8T6核心板使用时读出管脚不对劲,PA14的管脚为0;PA14原理是被SWD下载口占用,所有才不一样;参考链接

  3. 矩阵开关的思想:4个输入和4个输出:2x2的4种方式扫描;

    • 上拉输入,推挽输出0;行变化后扫描列变化
      • 3个给输出端为0,一个输出端给1;(上拉电阻的电平)1对1电平为1,上拉输入无法读入,即“ 没变化 ”。找出要找的位置;
      • 3个给输出端为1,一个输出端给0;(上拉电阻的电平)1对0电平为0,上拉输入读入变化,即“ 有变化 ”。找出要找的位置;
    • 下拉输入,推挽输出1;
      • 3个给输出端为1,一个输出端给0;(下拉电阻的电平)0对0电平为0,下拉输入无法读入,即“ 没变化 ”。找出要找的位置;
      • 3个给输出端为0,一个输出端给1;(下拉电阻的电平)0对1电平为1,上拉输入读入变化,即“ 有变化 ”。找出要找的位置;
  4. 我采用的是:上拉输入推挽输出0,3输出0,1输出0的无变化找位置;还有等待尝试…

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 19:22:29  更:2022-08-19 19:24:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:56:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码