一、代码设计
- 最常用的矩阵代码
#include<stm32f10x.h>
#include "delay.h"
#include "sys.h"
#define KEY_IN() (GPIO_ReadInputData(GPIOA)&0x00f0)
void KEY_Init(){
GPIO_InitTypeDef a;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
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;
GPIO_Init(GPIOA, &a);
GPIO_SetBits(GPIOA,GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);
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);
}
int key_scan_lie(){
u8 i=0;
u16 pin=0x0001;
for(;i<4;i++,pin<<=1){
GPIO_SetBits(GPIOA,pin);
if(KEY_IN() == 0xf0){
GPIO_ResetBits(GPIOA,pin);
return 4-i;
}
GPIO_ResetBits(GPIOA,pin);
}
return (-16);
}
u8 key4x4_scan(){
u8 key_value = 0;
if(KEY_IN()!=0xf0){
delay_ms(20);
if( (key_value=KEY_IN()) != 0xf0){
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;
}
- 可管脚不连续的矩阵开关;八个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)
#define KEY_IN_0() GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)
#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)
void KEY_Init(){
GPIO_InitTypeDef a;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
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;
GPIO_Init(GPIOA, &a);
GPIO_SetBits(GPIOA,GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);
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);
}
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_OUT_0(1);
key_y = key_scan(0) == -1 ? 4 : -1;
KEY_OUT_0(0);
if(key_y != -1) goto done;
KEY_OUT_1(1);
key_y = key_scan(0) == -1 ? 3 : -1;
KEY_OUT_1(0);
if(key_y != -1) goto done;
KEY_OUT_2(1);
key_y = key_scan(0) == -1 ? 2 : -1;
KEY_OUT_2(0);
if(key_y != -1) goto done;
KEY_OUT_3(1);
key_y = key_scan(0) == -1 ? 1 : -1;
KEY_OUT_3(0);
}
done: while(key_scan(0)!= -1);
key_value= (key_x== -1 || key_y== -1) ? 0 : key_x*4 + key_y;
}
return key_value;
}
二、总结
-
输出寄存器IDR的使用说明:在未配置任何模式下读取Pin是1状态(感觉是高阻态) -
在STM32F103C8T6核心板使用时读出管脚不对劲,PA14的管脚为0;PA14原理是被SWD下载口占用,所有才不一样;参考链接 -
矩阵开关的思想: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,上拉输入读入变化,即“ 有变化 ”。找出要找的位置;
-
我采用的是:上拉输入推挽输出0,3输出0,1输出0的无变化找位置;还有等待尝试…
|