stm32f103 需用的IO口:PA2~PA7
思路:PA2~PA4设置为输出且输出低,PA5~PA7设置为上拉输入,当检测到PA5~PA7中任意一个IO口电平为低时,可以推测得到是PA5~PA7中的某一列有按键按下,得到列 j 的值,接着反转状态,即PA2~PA4设置为上拉输入,PA5~PA7设置为输出且输出低,检测PA2~PA4的电平,得到 行 i 的值,通过 i 和j 的值,找到具体某一行某一列的按钮,输出相应的信息。
图一,3*3矩阵按钮原理图
当设置IO口为上拉输入时,该IO口的电平一直为高,当外界输入高电平时,该IO口的电平仍然是高,所以不能检测出是否有高电平的输入,即不能检测到按键是否按下。当外界输入低电平时,该IO口的电平就会明显降低,所以在上拉输入的状态下,低电平会很容易的被检测出来,也就很容易的判断出是哪一行(列)按下。
(1)判断是哪一列
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0XFF; //清零PA2~7
GPIOA->CRL|=0X88833300; //配置PA2~4输出 PA5~7输入
GPIOA->ODR|=1<<5;
GPIOA->ODR|=1<<6;
GPIOA->ODR|=1<<7; //PA5~7上拉输入
PAout(2)=0;
PAout(3)=0;
PAout(4)=0; //PA2~PA4 输出低电平
if((PAin(5)==0)||(PAin(6)==0)||(PAin(7)==0)) //PAin(n)可以检测IOA(n)的电平状态
{
delay_ms(10);
if(PAin(5)==0)
j=1;
if(PAin(6)==0)
j=2;
if(PAin(7)==0)
j=3;
}
else
j=0;
需要说明的是,GPIOA->CRL|=0X88833300; 只可以将PA5~7设置为上拉(下拉)输入,而具体的设置为上拉或下拉需要更改对应ODR寄存器中的某一位
由图知,在输入状态下,ODR对应的某一位等于0 即设置为下拉输入,等于1即设置为上拉输入。
检测IO口的电平状态可以直接使用PAin(n),同理让某个IO口输出高低电平可使用PAout(n)=1/0,
stm32f103x.h 中 的部分宏定义如下所示
1 // 单独操作GPIO的某一个IO口,n(0~16),n表示具体是哪一个IO口
2 #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
3 #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
4
5 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
6 #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
7
8 #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
9 #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
10
11 #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
12 #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
13
14 #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
15 #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
16
17 #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
18 #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
19
20 #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
21 #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
所以可以直接使用PAin(n) PAout(n).
(2)判断是哪一行
//翻转状态
GPIOA->CRL&=0XFF; //清零PA2~7
GPIOA->CRL|=0X33388800; //配置PA5~7输出 PA2~4输入
GPIOA->ODR|=1<<2;
GPIOA->ODR|=1<<3;
GPIOA->ODR|=1<<4; //PA2~4上拉
PAout(5)=0;
PAout(6)=0;
PAout(7)=0; //PAout(n)为低电平
if((PAin(2)==0)||(PAin(3)==0)||(PAin(4)==0))
{
delay_ms(10);
if(PAin(2)==0)
i=1;
if(PAin(3)==0)
i=2;
if(PAin(4)==0)
i=3;
}
else
i=0;
判断是哪一行与判断是那一列的原理是一样的。
(3)key.c代码如下
#include "key.h"
#include "delay.h"
u8 KEY_Init(void)
{
u8 i=0,j=0; //i:行 j:列
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0XFF; //清零PA2~7
GPIOA->CRL|=0X88833300; //配置PA2~4输出 PA5~7输入
GPIOA->ODR|=1<<5;
GPIOA->ODR|=1<<6;
GPIOA->ODR|=1<<7; //PA5~7上拉
PAout(2)=0;
PAout(3)=0;
PAout(4)=0; //PAout(n)为低电平
if((PAin(5)==0)||(PAin(6)==0)||(PAin(7)==0))
{
delay_ms(10);
if(PAin(5)==0)
j=1;
if(PAin(6)==0)
j=2;
if(PAin(7)==0)
j=3;
}
else
j=0;
//翻转状态
GPIOA->CRL&=0XFF; //清零PA2~7
GPIOA->CRL|=0X33388800; //配置PA5~7输出 PA2~4输入
GPIOA->ODR|=1<<2;
GPIOA->ODR|=1<<3;
GPIOA->ODR|=1<<4; //PA2~4上拉
PAout(5)=0;
PAout(6)=0;
PAout(7)=0; //PAout(n)为低电平
if((PAin(2)==0)||(PAin(3)==0)||(PAin(4)==0))
{
delay_ms(10);
if(PAin(2)==0)
i=1;
if(PAin(3)==0)
i=2;
if(PAin(4)==0)
i=3;
}
else
i=0;
//判断 按键数字
if(i==1)
{
if(j==1)
return 1;
if(j==2)
return 2;
if(j==3)
return 3;
}
if(i==2)
{
if(j==1)
return 4;
if(j==2)
return 5;
if(j==3)
return 6;
}
if(i==3)
{
if(j==1)
return 7;
if(j==2)
return 8;
if(j==3)
return 9;
}
else
return 0;
}
主函数如下
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "key.h"
//ALIENTEK Mini STM32开发板范例代码2
//按键输入实验
//技术支持:www.openedv.com
//广州市星翼电子科技有限公司
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
uart_init(72,9600);
while(1)
{
u8 t=KEY_Init();
delay_ms(300);
if(t==1)
{
printf("1\r\n");
}
if(t==2)
{
printf("2\r\n");
}
if(t==3)
{
printf("3\r\n");
}
if(t==4)
{
printf("4\r\n");
}
if(t==5)
{
printf("5\r\n");
}
if(t==6)
{
printf("6\r\n");
}
if(t==7)
{
printf("7\r\n");
}
if(t==8)
{
printf("8\r\n");
}
if(t==9)
{
printf("9\r\n");
}
if(t==0)
printf("没有按键按下\r\n");
}
}