一、前言
單片機(jī)型號(hào):STM32F103C8T6
開發(fā)環(huán)境:Keil5
二、GPIO的8種工作模式
4種輸入模式
- 上拉輸入模式:在默認(rèn)狀態(tài)下(GPIO引腳無輸入),讀取得的GPIO引腳數(shù)據(jù)為1,高電平(與Vdd相連的為上拉電阻);
- 下拉輸入模式:在默認(rèn)狀態(tài)下(GPIO引腳無輸入),讀取得的GPIO引腳數(shù)據(jù)為0,低電平(與Vss相連的為下拉電阻);
- 浮空輸入模式:在芯片內(nèi)部既沒有上拉電阻,也沒有下拉電阻,經(jīng)由觸發(fā)器輸入。配置成這個(gè)模式直接用電壓表測(cè)量其引腳為1點(diǎn)幾伏,這是個(gè)不確定值。由于其輸入阻抗較大,一般把這種模式用于標(biāo)準(zhǔn)的通信協(xié)議I2C、USART的接收端;
- 模擬輸入模式:關(guān)閉了斯密特觸發(fā)器,不接上、下拉電阻,經(jīng)由另一線路吧電壓信號(hào)傳送到片上外設(shè)模塊。如傳送至ADC模塊,由ADC采集電壓信號(hào),所以使用ADC外設(shè)的時(shí)候,必須設(shè)置為模擬輸入模式;
4中輸出模式
- 推挽輸出模式:線路經(jīng)過一個(gè)由P-MOS管和N-MOS管組成的單元電路。在輸出高電平時(shí),P-MOS管導(dǎo)通;低電平時(shí),N-MOS管導(dǎo)通。兩個(gè)管子輪流導(dǎo)通,一個(gè)負(fù)責(zé)灌電流,一個(gè)負(fù)責(zé)拉電流,使其負(fù)載能力和開關(guān)速度都比普通的方式有很大的提高。普通推挽輸出模式一般應(yīng)用在輸出電平為0和3.3伏的場(chǎng)合;
- 開漏輸出模式:如果我們控制輸出為0,低電平,則使N-MOS管導(dǎo)通,使輸出接地;如果我們控制輸出為1(無法直接輸出高電平),則既不輸出高電平,也不輸出低電平,為高阻態(tài);為正常使用時(shí)必須在外部接上一個(gè)上拉電阻。它具有“線與”特效,即很多個(gè)開漏模式引腳連接到一起時(shí),只有當(dāng)所有引腳都輸出高阻態(tài),才由上拉電阻提供高電平,此高電平的電壓為外部上拉電阻所接電源的電壓。若其中一個(gè)引腳為低電平,那線路就相當(dāng)于短路解讀,使得整條線路都為低電平,0伏;普通開漏輸出模式一般應(yīng)用在電平不匹配的場(chǎng)合,如需要輸出5伏的高電平,就需要在外部接一個(gè)上拉電阻,電源為5伏,把GPIO設(shè)置為開漏模式,當(dāng)輸出高阻態(tài)時(shí),由上拉電阻和電源向外輸出5伏的電平;
- 復(fù)用推挽輸出模式:
- 復(fù)用開漏輸出模式:
對(duì)相應(yīng)的復(fù)用模式,則是根據(jù)GPIO的復(fù)用功能來選擇的,例如GPIO的引腳用作串口的輸出,則使用復(fù)用推挽輸出模式;如果用在IC、SMBUS這些需要線與功能的復(fù)合場(chǎng)所,就使用復(fù)用開漏輸出模式;
注意:在使用任何一種開漏模式時(shí),都需要接上拉電阻;
三、按鍵原理
如上圖,按鈕一端接地,一端接GPIO引腳,這條路其實(shí)是一個(gè)斷路;控制按鈕時(shí)我們通常會(huì)將GPIO引腳設(shè)置為上拉輸入模式,上拉輸入模式默認(rèn)為高電平,當(dāng)按鈕沒有按下的時(shí)候,這個(gè)引腳讀到的一直是高電平;當(dāng)按鈕被按下的時(shí)候,引腳會(huì)被強(qiáng)行拉低,此時(shí)引腳讀到的為低電平,那說明按鍵已經(jīng)被按下;
四、單個(gè)按鈕
我們已經(jīng)知道了按鈕的工作原理,按照下圖連接好元器件
按鈕左側(cè)始終是高電位(PC0與之相連也是高電位),按鈕右側(cè)始終是低電位,當(dāng)按鈕按下時(shí),PC0引腳會(huì)被強(qiáng)行拉低,此時(shí)引腳讀到的為低電平;
檢測(cè)到低電平時(shí),翻轉(zhuǎn)引腳PC10的電平為低電位,從而實(shí)現(xiàn)按下按鈕,小燈亮;松開按鈕,小燈滅;
效果展示
詳細(xì)代碼
led.h
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
void LED_GPIO_Config(void);
#endif
led.c
#include "led.h"
void LED_GPIO_Config(void)
{
//定義一個(gè)GPIO_InitTypeDef類型的結(jié)構(gòu)體
GPIO_InitTypeDef GPIO_InitStructure;
//開啟GPIOC的外設(shè)時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
//選擇要控制的GPIO引腳
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
//設(shè)置引腳模式為上拉輸入模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
//設(shè)置引腳速率為50MHz
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//調(diào)用庫(kù)函數(shù),初始化GPIOC
GPIO_Init(GPIOC,&GPIO_InitStructure);
//選擇要控制的GPIO引腳
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
//設(shè)置引腳模式為推挽輸出模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//設(shè)置引腳速率為50MHz
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//調(diào)用庫(kù)函數(shù),初始化GPIOC
GPIO_Init(GPIOC,&GPIO_InitStructure);
}
main.c
#include "stm32f10x.h"
#include "led.h"
GPIO_InitTypeDef GPIO_InitStructure;
void Delay(int m,int n) //延時(shí)函數(shù)
{
int i,j;
for(i=0;i<m;i++) {
for(j=0;j<n;j++);
}
}
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
LED_GPIO_Config(); //初始化GPIO
while (1)
{
uint8_t flag = GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_0);
if(flag == 0) {
//按鈕按下,置低電位,小燈亮
GPIO_ResetBits(GPIOC,GPIO_Pin_10);
}else {
//按鈕松開,置高電位,小燈滅
GPIO_SetBits(GPIOC,GPIO_Pin_10);
}
Delay(100,100); //延時(shí)消抖
}//while(1)
}
五、按鈕鍵盤
鍵盤由多行多列按鈕組成,程序設(shè)計(jì)通常采用逐行逐列進(jìn)行掃描,4*4的矩陣鍵盤一共需要8個(gè)GPIO引腳,將控制行的引腳設(shè)置成輸出模式,控制列的引腳設(shè)置成上拉輸入模式;
先掃描第一行,那么就將PD0~PD2輸出高電平,PD3輸出低電平,記為0xF7;控制列的引腳為輸入引腳,將其和0xF7相與,如果哪一位為0,那么就證明哪一個(gè)被按下;
2、代碼
接線:4*4矩陣鍵盤,行從上至下依此接B5、B6、B7、B8;列從左至右依此接A1、A2、A3、A4;
按鍵從左至右,從上至下,依此編號(hào)為1、2、3、… 、16
Key.h
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
void delay_us(uint32_t delay_us);
void delay_ms(uint16_t delay_ms);
void KEY_GPIO_Config(void);
int scan(void);
#endif
Key.c文章來源:http://www.zghlxwxcb.cn/news/detail-498514.html
#include "Key.h"
void KEY_GPIO_Config(void)
{
//定義一個(gè)GPIO_InitTypeDef類型的結(jié)構(gòu)體
GPIO_InitTypeDef GPIO_InitStructure;
//開啟GPIOA、GPIOB的外設(shè)時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB,ENABLE);
///控制行
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
///讀取列
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
int scan(void)
{
uint8_t flag = 1;
//掃描第一行
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_SetBits(GPIOB,GPIO_Pin_7);
GPIO_SetBits(GPIOB,GPIO_Pin_8);
//掃描第一列
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
if(flag == 0) {
flag = 1;
return 1;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
if(flag == 0) {
flag = 1;
return 2;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
if(flag == 0) {
flag = 1;
return 3;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);
if(flag == 0) {
flag = 1;
return 4;
}
}
//掃描第二行
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOB,GPIO_Pin_6);
GPIO_SetBits(GPIOB,GPIO_Pin_7);
GPIO_SetBits(GPIOB,GPIO_Pin_8);
//掃描第二列
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
if(flag == 0) {
flag = 1;
return 5;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
if(flag == 0) {
flag = 1;
return 6;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
if(flag == 0) {
flag = 1;
return 7;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);
if(flag == 0) {
flag = 1;
return 8;
}
}
//掃描第三行
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
GPIO_SetBits(GPIOB,GPIO_Pin_8);
//掃描第三列
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
if(flag == 0) {
flag = 1;
return 9;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
if(flag == 0) {
flag = 1;
return 10;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
if(flag == 0) {
flag = 1;
return 11;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);
if(flag == 0) {
flag = 1;
return 12;
}
}
//掃描第四行
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOB,GPIO_Pin_6);
GPIO_ResetBits(GPIOB,GPIO_Pin_7);
GPIO_SetBits(GPIOB,GPIO_Pin_8);
//掃描第四列
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
if(flag == 0) {
flag = 1;
return 13;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
if(flag == 0) {
flag = 1;
return 14;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
if(flag == 0) {
flag = 1;
return 15;
}
}
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);
if(flag == 0) {
delay_ms(200);
flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4);
if(flag == 0) {
flag = 1;
return 16;
}
}
return -1;
}
- STM32用
GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
讀取GPIO引腳的電平(配置為輸入模式); - 一般檢測(cè)到低電平后延時(shí)一會(huì)再次檢測(cè),是常見的消抖手段,防止誤觸;
main.c文章來源地址http://www.zghlxwxcb.cn/news/detail-498514.html
#include "stm32f10x.h"
#include "Key.h"
int main(void)
{
KEY_GPIO_Config();
while(1)
{
switch(scan())
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
break;
case 10:
break;
case 11:
break;
case 12:
break;
case 13:
break;
case 14:
break;
case 15:
break;
case 16:
break;
}
}
}
到了這里,關(guān)于STM32單片機(jī)學(xué)習(xí)3--STM32控制鍵盤的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!