STM32F103学习笔记——薄膜矩阵键盘扫描

本文最后更新于:2022年5月29日 上午

使用STM32F103C8T6读取薄膜矩阵键盘(列扫描),串口显示键盘按下对应的按键值。

一、薄膜矩阵键盘介绍

我买的薄膜矩阵键盘,原理图如下:

QHy3ZV.png

左边的为行,右边的为列,扫描的原理:行为输入,列为输出。先让第一列为高电平,其他列为低电平,读取行的电平进行判断哪一个按键被按下;然后再设置第二列为高电平,其他列为低电平,再读取行的电平进行判断·····。

二、驱动代码

1,矩阵键盘

(1)keyboard.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef __KEYBOARD_H
#define __KEYBOARD_H

#include "stm32f10x.h"

//Pin definition
/*******************************************************/
#define COLUMN_KEY_GPIO_PORT GPIOA
#define COLUMN_KEY_GPIO_CLK RCC_APB2Periph_GPIOA
#define C1_PIN GPIO_Pin_8
#define C2_PIN GPIO_Pin_9
#define C3_PIN GPIO_Pin_10
#define C4_PIN GPIO_Pin_11


#define ROW_KEY_GPIO_PORT GPIOB
#define ROW_KEY_GPIO_CLK RCC_APB2Periph_GPIOB
#define R1_PIN GPIO_Pin_12
#define R2_PIN GPIO_Pin_13
#define R3_PIN GPIO_Pin_14
#define R4_PIN GPIO_Pin_15
/************************************************************/

void KeyBoard_Init(void);
char Key_scan(void);

#endif /* __KEYBOARD_H */

(2)keyboard.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/**
******************************************************************************
* @file keyboard.c
* @author Soso
* @date 2019-12-18
* @brief Matrix keyboard driver configuration.
******************************************************************************
*/

#include "keyboard.h"
#include "systick.h"

extern uint8_t key_flag;

void KeyBoard_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;

/* Enable KeyGPIO port clock */
RCC_APB2PeriphClockCmd(COLUMN_KEY_GPIO_CLK|ROW_KEY_GPIO_CLK,ENABLE);

/* Column Key GPIO Configuration */
GPIO_InitStruct.GPIO_Pin = C1_PIN|C2_PIN|C3_PIN|C4_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(COLUMN_KEY_GPIO_PORT,&GPIO_InitStruct);

/* Row Key GPIO Configuration */
GPIO_InitStruct.GPIO_Pin = R1_PIN|R2_PIN|R3_PIN|R4_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(ROW_KEY_GPIO_PORT,&GPIO_InitStruct);

GPIO_SetBits(COLUMN_KEY_GPIO_PORT,C1_PIN|C2_PIN|C3_PIN|C4_PIN);
GPIO_ResetBits(ROW_KEY_GPIO_PORT,R1_PIN|R2_PIN|R3_PIN|R4_PIN);
}


char Key_scan(void)
{
uint16_t temp = 0;
char Key_val = 0;

/*************************** Column 1 ***************************/
GPIO_SetBits(COLUMN_KEY_GPIO_PORT,C1_PIN);
GPIO_ResetBits(COLUMN_KEY_GPIO_PORT,C2_PIN|C3_PIN|C4_PIN);

temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;

if(temp != 0x0000)
{
delay_ms(5);
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
if(temp != 0x0000)
{
key_flag = 1;
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
switch(temp)
{
case 0x1000: Key_val = '1';break;
case 0x2000: Key_val = '4';break;
case 0x4000: Key_val = '7';break;
case 0x8000: Key_val = '*';break;
}
}
while(temp != 0x0000)
{
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
}
}

/*************************** Column 2 ***************************/
GPIO_SetBits(COLUMN_KEY_GPIO_PORT,C2_PIN);
GPIO_ResetBits(COLUMN_KEY_GPIO_PORT,C1_PIN|C3_PIN|C4_PIN);

temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;

if(temp != 0x0000)
{
delay_ms(5);
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
if(temp != 0x0000)
{
key_flag = 1;
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
switch(temp)
{
case 0x1000: Key_val = '2';break;
case 0x2000: Key_val = '5';break;
case 0x4000: Key_val = '8';break;
case 0x8000: Key_val = '0';break;
}
}
while(temp != 0x0000)
{
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
}
}

/*************************** Column 3 ***************************/
GPIO_SetBits(COLUMN_KEY_GPIO_PORT,C3_PIN);
GPIO_ResetBits(COLUMN_KEY_GPIO_PORT,C1_PIN|C2_PIN|C4_PIN);

temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;

if(temp != 0x0000)
{
delay_ms(5);
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
if(temp != 0x0000)
{
key_flag = 1;
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
switch(temp)
{
case 0x1000: Key_val = '3';break;
case 0x2000: Key_val = '6';break;
case 0x4000: Key_val = '9';break;
case 0x8000: Key_val = '#';break;
}
}
while(temp != 0x0000)
{
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
}
}

/*************************** Column 4 ***************************/
GPIO_SetBits(COLUMN_KEY_GPIO_PORT,C4_PIN);
GPIO_ResetBits(COLUMN_KEY_GPIO_PORT,C1_PIN|C2_PIN|C3_PIN);

temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;

if(temp != 0x0000)
{
delay_ms(5);
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
if(temp != 0x0000)
{
key_flag = 1;
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
switch(temp)
{
case 0x1000: Key_val = 'A';break;
case 0x2000: Key_val = 'B';break;
case 0x4000: Key_val = 'C';break;
case 0x8000: Key_val = 'D';break;
}
}
while(temp != 0x0000)
{
temp = GPIO_ReadInputData(ROW_KEY_GPIO_PORT) & 0xF000;
}
}

return Key_val;
}

/*********************************************END OF FILE*********************************************/

2,串口调式模块

(1)usart.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef __USART_H
#define __USART_H

#include "stm32f10x.h"
#include "stdio.h"

//Pin definition
/*******************************************************/
#define DEBUG_USART USART3
#define DEBUG_USART_CLK RCC_APB1Periph_USART3
#define DEBUG_USART_AF RCC_APB2Periph_AFIO
#define DEBUG_USART_GPIO_CLK RCC_APB2Periph_GPIOB
#define DEBUG_USART_BAUDRATE 115200

#define DEBUG_USART_RX_GPIO_PORT GPIOB
#define DEBUG_USART_RX_PIN GPIO_Pin_11

#define DEBUG_USART_TX_GPIO_PORT GPIOB
#define DEBUG_USART_TX_PIN GPIO_Pin_10


#define DEBUG_USART_IRQ USART3_IRQn
#define DEBUG_USART_IRQHandler USART3_IRQHandler

/************************************************************/

void USART_Config(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);

void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);

#endif /* __USART_H */

(2)usart.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
******************************************************************************
* @file uasrt.c
* @author Soso
* @date 2019-12-18
* @brief Redirect c library printf function to usart port, interrupt receiving mode.
******************************************************************************
*/

#include "usart.h"


/* Configuring nested vectored interrupt controller NVIC */
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

/* Nested vector interrupt controller group selection */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

/* Preemptio Priority is 1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* Sub Priority is 1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* Enable interrupt */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

/* Configure USART as the interrupt source */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* Initialize configuration NVIC */
NVIC_Init(&NVIC_InitStructure);
}

void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;

/* Enable port alternate function and enable USART GPIO clock */
RCC_APB2PeriphClockCmd(DEBUG_USART_AF|DEBUG_USART_GPIO_CLK,ENABLE);
/* Enable USART Clock */
RCC_APB1PeriphClockCmd(DEBUG_USART_CLK,ENABLE);

/* Configure the Tx pin for alternate function */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

/* Configure the Rx pin for the alternate function */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);

/* Configuration USART mode */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/* USART mode control: simultaneous enable send and receive */
USART_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;

USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
USART_Init(DEBUG_USART, &USART_InitStructure);

/* Configure the serial port to receive interrupts. */
NVIC_Configuration();

/* Enable serial port receive interrupt */
USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);

/* Enable serial */
USART_Cmd(DEBUG_USART, ENABLE);
}


/***************** Send a character **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* Send a byte of data to the USART */
USART_SendData(pUSARTx,ch);

/* Waiting for the transmit data register to be empty */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

/***************** Send string **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');

/* Waiting for transmission to complete */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
{}
}

/***************** Send a 16-digit number **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;

/* Take out the high eight */
temp_h = (ch&0XFF00)>>8;
/* Take the lower eight */
temp_l = ch&0XFF;

/* Send high eight */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);

/* Send the lower eight digits */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}

/* Redirect the c library function printf to the serial port,
use the printf function after redirection. */
int fputc(int ch, FILE *f)
{
/* Send a byte of data to the serial port */
USART_SendData(DEBUG_USART, (uint8_t) ch);

/* Waiting to send */
while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);

return (ch);
}

/* Redirect the c library function scanf to the serial port,
rewrite backwards can use scanf, getchar and other functions. */
int fgetc(FILE *f)
{
/* Waiting for serial input data */
while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_RXNE) == RESET);

return (int)USART_ReceiveData(DEBUG_USART);
}
/*********************************************END OF FILE*********************************************/

3,延时函数配置模块

(1)systick.h
1
2
3
4
5
6
7
8
9
10
11
#ifndef __SYSTICK_H
#define __SYSTICK_H

#include"stm32f10x.h"

void delay_us(u32 i);
void delay_ms(u32 i);


#endif /* __SYSTICK_DELAY_H */

(2)systick.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "systick.h"

void delay_us(u32 i)
{
u32 temp;
SysTick->LOAD=9*i; //Set the reload value, at 72MHZ
SysTick->CTRL=0X01; //Enable, reduce to zero is no action, use external clock source
SysTick->VAL=0; //Clear counter
do
{
temp=SysTick->CTRL; //Read current countdown value
}
while((temp&0x01)&&(!(temp&(1<<16)))); //Waiting time to arrive
SysTick->CTRL=0; //Close counter
SysTick->VAL=0; //Empty counter
}
void delay_ms(u32 i)
{
u32 temp;
SysTick->LOAD=9000*i; //Set the reload value, at 72MHZ
SysTick->CTRL=0X01; //Enable, reduce to zero is no action, use external clock source
SysTick->VAL=0; //Clear counter
do
{
temp=SysTick->CTRL; //Read current countdown value
}
while((temp&0x01)&&(!(temp&(1<<16)))); //Waiting time to arrive
SysTick->CTRL=0; //Close counter
SysTick->VAL=0; //Empty counter
}

4,主函数main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
******************************************************************************
* @file main.c
* @author Soso
* @date 2019-12-18
* @brief Matrix keyboard application.
*
******************************************************************************
*/

#include "stm32f10x.h"
#include "usart.h"
#include "keyboard.h"
#include "systick.h"

uint8_t key_flag = 0;

int main(void)
{
KeyBoard_Init();
USART_Config();

printf("Initialization successful.\r\n");

char key_value = 0;

while(1)
{
key_value = Key_scan();
if(key_flag == 1)
{
key_flag = 0;
printf("S%c push down.\r\n",key_value);
}
}
}




/*********************************************END OF FILE*********************************************/

三、硬件接线说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
【*】 引脚分配
STM32 串口模块
PB11 -> Tx
PB10 -> Rx
+3.3V -> +3.3V
GND -> GND
波特率:115200

STM32 矩阵键盘
PB12 -> R1
PB13 -> R2
PB14 -> R3
PB15 -> R4
PA8 -> C1
PA9 -> C2
PA10 -> C3
PA11 -> C4

四、最终效果

QHylq0.png


STM32F103学习笔记——薄膜矩阵键盘扫描
https://kevinloongc.github.io/posts/2ac21edf.html
作者
Kevin Loongc
发布于
2019年12月16日
许可协议