本次实验使用的是淘宝上常见的矩阵键盘,如下图,最左边和最右边的引脚为空,所以这里说的1引脚对应单片机从左往右数的第二个,第八个引脚对应倒数第二个引脚。
原理图如下(从淘宝找的,有点模糊):
从原理图看:
引脚1关联的键位有:1 ,4,7,*。 引脚2关联的键位有:2,5,8,0。引脚3关联的引脚:3,6,9,#。引脚4关联的引脚:A,B,C,D。引脚5关联引脚:1,2,3,A。 引脚6关联引脚:4,5,6,B。
引脚7关联引脚:7,8,9,C。 引脚8关联引脚:*,0,#,D。
通过使用万用表测量电流,按下对应按键,万用表显示对应电流。
下面进行代码的编写:
1.1按键初始化(void keyboard_init(void))
1.初始化GPIO,GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_10 配置为下降沿中断触发,上拉。
2.GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 ,输入模式,下拉。
3.还有设置中断优先级分组以及使能中断
void keyboard_init(void)
{
GPIO_InitTypeDef gpio_initstruct;
__HAL_RCC_GPIOB_CLK_ENABLE();
//调用GPIO初始化函数
gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_10;
gpio_initstruct.Mode = GPIO_MODE_IT_FALLING;
gpio_initstruct.Pull = GPIO_PULLUP;
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &gpio_initstruct);
gpio_initstruct.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
gpio_initstruct.Mode = GPIO_MODE_INPUT;
gpio_initstruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOB, &gpio_initstruct);
HAL_NVIC_SetPriority(EXTI0_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
HAL_NVIC_SetPriority(EXTI1_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
HAL_NVIC_SetPriority(EXTI2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}
1.2中断函数
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void EXTI1_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
}
void EXTI2_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
}
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);
}
1.3在回调函数中,确定按下按键的行和列
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
uint8_t row = 0, column = 0;
if(key_value != 0) return; //判断键值是否为空,不为空直接返回
//确认行
if(GPIO_Pin == GPIO_PIN_0)
row = 0x10;
else if(GPIO_Pin == GPIO_PIN_1)
row = 0x20;
else if(GPIO_Pin == GPIO_PIN_2)
row = 0x30;
else if(GPIO_Pin == GPIO_PIN_10)
row = 0x40;
//确定列
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11) == GPIO_PIN_SET)
{
delay_ms(10); //消抖
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11))
column = 0x01;
}
else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_SET)
{
delay_ms(10);
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12))
column = 0x02;
}
else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) == GPIO_PIN_SET)
{
delay_ms(10);
while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13))
column = 0x03;
}
if(row != 0 && column != 0)
key_value = row | column; //取得键值
}
1.4将键值转换成对应的字符
uint8_t keyboard_get_value(void)
{
uint8_t ch = 0;
if(key_value != 0)
{
if(key_value == 0x11) ch = '1';
else if(key_value == 0x12) ch = '2';
else if(key_value == 0x13) ch = '3';
else if(key_value == 0x21) ch = '4';
else if(key_value == 0x22) ch = '5';
else if(key_value == 0x23) ch = '6';
else if(key_value == 0x31) ch = '7';
else if(key_value == 0x32) ch = '8';
else if(key_value == 0x33) ch = '9';
else if(key_value == 0x41) ch = '*';
else if(key_value == 0x42) ch = '0';
else if(key_value == 0x43) ch = '#';
delay_ms(400);
key_value = 0x00;
}
return ch;
}
main 函数
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "keyboard.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* 初始化LED灯 */
uart1_init(115200);
keyboard_init();
printf("hello world!\r\n");
uint8_t key_value = 0;
while(1)
{
key_value = keyboard_get_value();
if(key_value != 0)
{
printf("按下了:%c\r\n", key_value);
key_value = 0;
}
}
}
更新:查找stm32f103 c8t6产品手册发现 pb3 pb4用作jtag引脚,故而将jtag引脚重定义为普通IO口输入输出
//keyboard.h 头文件
#ifndef __KEYBOARD_H__
#define __KEYBOARD_H__
#include "sys.h"
#define P1 GPIO_PIN_1 //从左往右,第二个引脚,下面依次往右数
#define P2 GPIO_PIN_2
#define P3 GPIO_PIN_3
#define P4 GPIO_PIN_4
#define P5 GPIO_PIN_6
#define P6 GPIO_PIN_7
#define P7 GPIO_PIN_12
#define P8 GPIO_PIN_13
#define PIN_SOURCE GPIOB
void keyboard_init(void);
uint8_t get_keyboard_ch(void);
#endif
//keyboard.c 文件
#include "keyboard.h"
uint8_t key_val=0;
void keyboard_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStructure.Pin= P1 | P2 | P3 | P4;
GPIO_InitStructure.Mode=GPIO_MODE_IT_FALLING; //下降沿触发中断
GPIO_InitStructure.Pull=GPIO_PULLUP; //上拉
GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(PIN_SOURCE,&GPIO_InitStructure);
GPIO_InitStructure.Pin= P5 | P6 | P7 | P8;
GPIO_InitStructure.Mode=GPIO_MODE_INPUT; //输入模式
GPIO_InitStructure.Pull=GPIO_PULLDOWN; //下拉
GPIO_InitStructure.Speed=GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(PIN_SOURCE,&GPIO_InitStructure);
__HAL_AFIO_REMAP_SWJ_NOJTAG(); // 禁用 JTAG,但保留 SWD
HAL_NVIC_SetPriority(EXTI1_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
HAL_NVIC_SetPriority(EXTI2_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
HAL_NVIC_SetPriority(EXTI3_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
HAL_NVIC_SetPriority(EXTI4_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI4_IRQn);
}
void EXTI1_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(P1);
}
void EXTI2_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(P2);
}
void EXTI3_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(P3);
}
void EXTI4_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(P4);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
uint8_t row=0,col=0;
if(key_val !=0) return;
//读取中断的Pin引脚
if(GPIO_Pin==P1){
row=0x10;
}
else if(GPIO_Pin==P2){
row=0x20;
}
else if(GPIO_Pin==P3){
row=0x30;
}
else if(GPIO_Pin==P4){
row=0x40;
}
if(HAL_GPIO_ReadPin(PIN_SOURCE,P5)==GPIO_PIN_SET){
delay_ms(10);
while(HAL_GPIO_ReadPin(PIN_SOURCE,P5));
col=0x01;
}
else if(HAL_GPIO_ReadPin(PIN_SOURCE,P6)==GPIO_PIN_SET){
delay_ms(10);
while(HAL_GPIO_ReadPin(PIN_SOURCE,P6));
col=0x02;
}
else if(HAL_GPIO_ReadPin(PIN_SOURCE,P7)==GPIO_PIN_SET){
delay_ms(10);
while( HAL_GPIO_ReadPin(PIN_SOURCE,P7));
col=0x03;
}
else if(HAL_GPIO_ReadPin(PIN_SOURCE,P8)==GPIO_PIN_SET){
delay_ms(10);
while(HAL_GPIO_ReadPin(PIN_SOURCE,P8) );
col=0x04;
}
if( (row!=0) &&(col!=0)){
key_val= row | col;
}
}
uint8_t get_keyboard_ch(void)
{
uint8_t ch=0;
if(key_val!=0){
if(key_val==0x11) ch='1';
else if(key_val==0x12) ch='4';
else if(key_val==0x13) ch='7';
else if(key_val==0x14) ch='*';
else if(key_val==0x21) ch='2';
else if(key_val==0x22) ch='5';
else if(key_val==0x23) ch='8';
else if(key_val==0x24) ch='0';
else if(key_val==0x31) ch='3';
else if(key_val==0x32) ch='6';
else if(key_val==0x33) ch='9';
else if(key_val==0x34) ch='#';
else if(key_val==0x41) ch='A';
else if(key_val==0x42) ch='B';
else if(key_val==0x43) ch='C';
else if(key_val==0x44) ch='D';
delay_ms(400);
key_val=0;
}
return ch;
}
就是加了一行 __HAL_AFIO_REMAP_SWJ_NOJTAG(); // 禁用 JTAG,但保留 SWD
其他没啥多大变化
按键测试能正常输出。