#学习笔记二:GPIO的探索与矩阵按键
##1.在配置cubemx时,对gpio的配置有开漏输出和推挽输出两种方式,
###这里有一篇文章(别人的文章)讲的很详细link戳这里跳转
通俗来讲,推挽输出,可以输出高电平,也可以输出低电平。
而开漏输出,输出低电平,在有上拉电阻时,可以正常工作,他可以有多个上拉电阻,并且是与关系。
开漏输出
所谓的推挽输出模式,是根据这两个 MOS 管的工作方式来命名的。在该结构中输入高电平时,经过反向后,上方的 P-MOS 导通,下方的 N-MOS 关闭,对外输出高电平;而在该结构中输入低电平时,经过反向后,N-MOS 管导通,P-MOS 关闭,对外输出低电平。当引脚高低电平切换时,两个管子轮流导通,P 管负责灌电流,N 管负责拉电流,使其负载能力和开关速度都比普通的方式有很大的提高。推挽输出的低电平为 0 伏,高电平为 3.3 伏,具体参考图 7_2,它是推挽输出模式时的等效电路。
开漏输出
开漏输出模式时,上方的 P-MOS 管完全不工作。如果我们控制输出为 0,低电平,则 P-MOS管关闭,N-MOS 管导通,使输出接地,若控制输出为 1 (它无法直接输出高电平) 时,则 P-MOS管和 N-MOS 管都关闭,所以引脚既不输出高电平,也不输出低电平,为高阻态。为正常使用时必须外部接上拉电阻,参考图 7_3 中等效电路。它具有“线与”特性,也就是说,若有很多个开漏模式引脚连接到一起时,只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,此高电平的电压为外部上拉电阻所接的电源的电压。若其中一个引脚为低电平,那线路就相当于短路接地,使得整条线路都为低电平,0 伏。
##2.还有就是对IO口拉高还是拉低的问题。
这里有三种情况,pull down(拉低),pull up(拉高),no pull down no pull up(什么也不干),这是对IO口初始状态的设定。后面结合实例进行讲解。
##3.GPIO的函数
1.void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
功能: GPIO初始化
实例:HAL_GPIO_Init(GPIOC,&GPIO_InitStruct);
2.void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
功能:在函数初始化之后的引脚恢复成默认的状态,即各个寄存器复位时的值
实例:HAL_GPIO_Init(GPIOC, GPIO_PIN_4);
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
功能:读取引脚的电平状态、函数返回值为0或1
实例:HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4);
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
功能:引脚输入高低电平
实例:HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4,0);
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
翻转引脚的电平状态
实例:HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_4); 常用在LED上
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
功能:锁住引脚电平,比如说一个管脚的当前状态是1,当这个管脚电平变化时保持锁定时的值。
实例:HAL_GPIO_LockPin(GPIOC, GPIO_PIN_4);
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);
功能: 外部中断服务函数,清除中断标志位
实例:HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
功能: 中断回调函数,可以理解为中断函数具体要响应的动作。
实例:HAL_GPIO_EXTI_Callback(GPIO_PIN_4);
这些函数可以在下图这个.h文件找到。
下面贴上一段矩阵按键的扫描,帮助理解。
HAL_GPIO_WritePin (R1_PORT, R1_PIN, GPIO_PIN_RESET);//在MX中设为output,只有这个函数能改变引脚电平状态,拉低一个,剩下的拉高
HAL_GPIO_WritePin (R2_PORT, R2_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R3_PORT, R3_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R4_PORT, R4_PIN, GPIO_PIN_SET);
if (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN))) //在MX中设置为input型,pull up拉高电平,这个函数读取io口电平,不是高即为按下,就锁定了一行中所在的一列
{
while (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN)));
return 13; //S13 1
}
if (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN)))
{
while (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN)));
return 9; //S9 2
}
if (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN)))
{
while (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN)));
return 5; //S5 3
}
if (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN)))
{
while (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN)));
return 1; //S1 4
}
以这段代码为例(4*4矩阵按键),在cubemx中设置引脚状态为output,用HAL_GPIO_WritePin这个函数改变引脚电平,将第一行四列的引脚电平分别写为低,高高高,接下来扫描行,
if (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN)))
{
while (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN)));
return 9; //S9 2
}
我们知道按键按下,电路接通,即低电平按键生效,当读到的电平不是高电平,就锁定了行和列。
下面给出完整代码
uint8_t read_key(void) //矩阵键盘扫描作用函数
{
HAL_GPIO_WritePin (R1_PORT, R1_PIN, GPIO_PIN_RESET);//在MX中设为output,只有这个函数能改变引脚电平状态,拉低一个,剩下的拉高
HAL_GPIO_WritePin (R2_PORT, R2_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R3_PORT, R3_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R4_PORT, R4_PIN, GPIO_PIN_SET);
if (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN))) //在MX中设置为input型,pull up拉高电平,这个函数读取io口电平,不是高即为按下,就锁定了一行中所在的一列
{
while (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN)));
return 13; //S13 1
}
if (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN)))
{
while (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN)));
return 9; //S9 2
}
if (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN)))
{
while (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN)));
return 5; //S5 3
}
if (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN)))
{
while (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN)));
return 1; //S1 4
}
HAL_GPIO_WritePin (R1_PORT, R1_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R2_PORT, R2_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin (R3_PORT, R3_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R4_PORT, R4_PIN, GPIO_PIN_SET);
if (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN)))
{
while (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN))); //S14 5
return 14;
}
if (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN)))
{
while (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN))); //S10 6
return 10;
}
if (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN)))
{
while (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN))); //S6 7
return 6;
}
if (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN)))
{
while (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN))); //S2 8
return 2;
}
HAL_GPIO_WritePin (R1_PORT, R1_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R2_PORT, R2_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R3_PORT, R3_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin (R4_PORT, R4_PIN, GPIO_PIN_SET);
if (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN)))
{
while (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN))); //S15 9
return 15;
}
if (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN)))
{
while (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN))); //S11 0
return 11;
}
if (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN)))
{
while (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN))); //S7 K1
return 7;
}
if (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN))) //S3 K2
{
while (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN)));
return 3;
}
HAL_GPIO_WritePin (R1_PORT, R1_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R2_PORT, R2_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R3_PORT, R3_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin (R4_PORT, R4_PIN, GPIO_PIN_RESET);
if (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN)))
{
while (!(HAL_GPIO_ReadPin (C1_PORT, C1_PIN))); //S16 K3
return 16;
}
if (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN)))
{
while (!(HAL_GPIO_ReadPin (C2_PORT, C2_PIN))); //S12 K4
return 12;
}
if (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN)))
{
while (!(HAL_GPIO_ReadPin (C3_PORT, C3_PIN))); //S8 K5
return 8;
}
if (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN)))
{
while (!(HAL_GPIO_ReadPin (C4_PORT, C4_PIN))); //S4 K6
return 4;
}
return 0;
}
下面是.h文件
#ifndef _key_H_
#define _key_H_
#include "main.h"
#define R3_PORT GPIOC
#define R3_PIN GPIO_PIN_10
#define R2_PORT GPIOC
#define R2_PIN GPIO_PIN_9
#define R1_PORT GPIOC
#define R1_PIN GPIO_PIN_8
#define C2_PORT GPIOC
#define C2_PIN GPIO_PIN_12
#define C4_PORT GPIOC
#define C4_PIN GPIO_PIN_7
#define C3_PORT GPIOC
#define C3_PIN GPIO_PIN_6
#define C1_PORT GPIOD
#define C1_PIN GPIO_PIN_2
#define R4_PORT GPIOC
#define R4_PIN GPIO_PIN_11
uint8_t OLED_change(uint8_t SS);
uint8_t read_key(void);
unsigned int call(unsigned int high_time);
#endif
欢迎指正