STM32微控制器中的GPIO通用输入输出口详解
3 GPIO通用输入输出口
3.1 GPIO简介
3.2 GPIO基本结构
3.3 GPIO位结构
3.4 GPIO模式
通过配置GPIO的端口配置寄存器,端口可以配置成以下8种模式:
模式名称 | 性质 | 特征 |
---|---|---|
浮空输入(IN_FLOATING) | 数字输入 | 可读取引脚电平,若引脚悬空,则电平不确定 |
上拉输入(IPU,In Pull Up) | 数字输入 | 可读取引脚电平,内部连接上拉电阻,悬空时默认高电平 |
下拉输入(IPD,In Pull Down) | 数字输入 | 可读取引脚电平,内部连接下拉电阻,悬空时默认低电平 |
模拟输入(AIN,Analog IN) | 模拟输入 | GPIO无效,引脚直接接入内部ADC |
开漏输出(Out_OD,Out Open Drain) | 数字输出 | 可输出引脚电平,高电平为高阻态,低电平接VSS |
推挽输出(Out_PP,Out Push Pull) | 数字输出 | 可输出引脚电平,高电平接VDD,低电平接VSS |
复用开漏输出(AF_OD,Atl Open Drain) | 数字输出 | 由片上外设控制,高电平为高阻态,低电平接VSS |
复用推挽输出(AF_PP,Atl Push Pull) | 数字输出 | 由片上外设控制,高电平接VDD,低电平接VSS |
浮空/上拉/下拉输入:
模拟输入:
开漏/推挽输出:
复用开漏/推挽输出:
3.5 LED和蜂鸣器简介


3.6 面包板
3.7 LED闪烁
Delay
函数相关代码;Delay.h
:
#ifndef __DELAY_H
#define __DELAY_H
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);
#endif
Delay.c
:
#include "stm32f10x.h"
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
mian.c
:
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
//开启使能时钟。第一个参数选择外设,第二个参数选择新的状态
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//配置端口模式
//定义一个结构体
GPIO_InitTypeDef GPIO_InitStructure;
//配置结构体的参数
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出。若改成GPIO_Mode_Out_OD,开漏输出模式,高电平无驱动能力,LED的接线方式就不可以短脚接负,长脚接引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //输出引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度
//第一个参数是选择哪一个GPIO,第二个参数是一个指向结构体的指针
GPIO_Init(GPIOA, &GPIO_InitStructure);
while(1)
{
//以下几种写法均可
//点亮LED
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
Delay_ms(500);
//熄灭LED
GPIO_SetBits(GPIOA, GPIO_Pin_0);
Delay_ms(500);
//点亮LED
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
Delay_ms(500);
//熄灭LED
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
Delay_ms(500);
//点亮LED
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
Delay_ms(500);
//熄灭LED
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);
Delay_ms(500);
}
}
3.8 LED流水灯
mian.c
:
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
//开启使能时钟。第一个参数选择外设,第二个参数选择新的状态
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//配置端口模式
//定义一个结构体
GPIO_InitTypeDef GPIO_InitStructure;
//配置结构体的参数
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //输出引脚,此处配置成所有的总共16个引脚,也可以按照GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2的方式来选择多个引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度
//第一个参数是选择哪一个GPIO,第二个参数是一个指向结构体的指针
GPIO_Init(GPIOA, &GPIO_InitStructure);
while(1)
{
//第二个参数是指定写到输出数据寄存器(GPIO里的ODR寄存器)的值
GPIO_Write(GPIOA, ~0x0001); //0000 0000 0000 0001,对应PA0~PA15共16个端口。因为是低电平点亮,所以还要加一个按位取反的符号
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0002); //0000 0000 0000 0010
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0004); //0000 0000 0000 0100
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0008); //0000 0000 0000 1000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0010); //0000 0000 0001 0000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0020); //0000 0000 0010 0000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0040); //0000 0000 0100 0000
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0080); //0000 0000 1000 0000
Delay_ms(500);
}
}
3.9 蜂鸣器
main.c
:
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
//开启使能时钟。第一个参数选择外设,第二个参数选择新的状态
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//配置端口模式
//定义一个结构体
GPIO_InitTypeDef GPIO_InitStructure;
//配置结构体的参数
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //输出引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度
//第一个参数是选择哪一个GPIO,第二个参数是一个指向结构体的指针
GPIO_Init(GPIOB, &GPIO_InitStructure);
while(1)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_12);
Delay_ms(500);
GPIO_SetBits(GPIOB, GPIO_Pin_12);
Delay_ms(500);
}
}
3.10 按键简介

3.11 传感器模块简介



3.12 按键控制LED

LED.h
:
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
void LED1_ON(void);
void LED1_OFF(void);
void LED1_Turn(void);
void LED2_ON(void);
void LED2_OFF(void);
void LED2_Turn(void);
#endif
LED.c
:
#include "stm32f10x.h" // Device header
/**
* 函 数:LED初始化
* 参 数:无
* 返 回 值:无
*/
void LED_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA1和PA2引脚初始化为推挽输出
/*设置GPIO初始化后的默认电平,使LED灯熄灭*/
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2); //设置PA1和PA2引脚为高电平
}
/**
* 函 数:LED1开启
* 参 数:无
* 返 回 值:无
*/
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //设置PA1引脚为低电平
}
/**
* 函 数:LED1关闭
* 参 数:无
* 返 回 值:无
*/
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1); //设置PA1引脚为高电平
}
/**
* 函 数:LED1状态翻转
* 参 数:无
* 返 回 值:无
*/
void LED1_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0) //获取输出寄存器的状态,如果当前引脚输出低电平
{
GPIO_SetBits(GPIOA, GPIO_Pin_1); //则设置PA1引脚为高电平
}
else //否则,即当前引脚输出高电平
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1); //则设置PA1引脚为低电平
}
}
/**
* 函 数:LED2开启
* 参 数:无
* 返 回 值:无
*/
void LED2_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2); //设置PA2引脚为低电平
}
/**
* 函 数:LED2关闭
* 参 数:无
* 返 回 值:无
*/
void LED2_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2); //设置PA2引脚为高电平
}
/**
* 函 数:LED2状态翻转
* 参 数:无
* 返 回 值:无
*/
void LED2_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0) //获取输出寄存器的状态,如果当前引脚输出低电平
{
GPIO_SetBits(GPIOA, GPIO_Pin_2); //则设置PA2引脚为高电平
}
else //否则,即当前引脚输出高电平
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2); //则设置PA2引脚为低电平
}
}
Key.h
:
#ifndef __KEY_H
#define __KEY_H
void Key_Init(void);
uint8_t Key_GetNum(void);
#endif
key.c
:
#include "stm32f10x.h" // Device header
#include "Delay.h"
/**
* 函 数:按键初始化
* 参 数:无
* 返 回 值:无
*/
void Key_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB1和PB11引脚初始化为上拉输入
}
/**
* 函 数:按键获取键码
* 参 数:无
* 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下
* 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
*/
uint8_t Key_GetNum(void)
{
uint8_t KeyNum = 0; //定义变量,默认键码值为0
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) //读PB1输入寄存器的状态,如果为0,则代表按键1按下
{
Delay_ms(20); //延时消抖
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0); //等待按键松手
Delay_ms(20); //延时消抖
KeyNum = 1; //置键码为1
}
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0) //读PB11输入寄存器的状态,如果为0,则代表按键2按下
{
Delay_ms(20); //延时消抖
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0); //等待按键松手
Delay_ms(20); //延时消抖
KeyNum = 2; //置键码为2
}
return KeyNum; //返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0
}
main.c
:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
uint8_t KeyNum; //定义用于接收按键键码的变量
int main(void)
{
/*模块初始化*/
LED_Init(); //LED初始化
Key_Init(); //按键初始化
while (1)
{
KeyNum = Key_GetNum(); //获取按键键码
if (KeyNum == 1) //按键1按下
{
LED1_Turn(); //LED1翻转
}
if (KeyNum == 2) //按键2按下
{
LED2_Turn(); //LED2翻转
}
}
}
3.13 光敏传感器控制蜂鸣器

Buzzer.h
:
#ifndef __BUZZER_H
#define __BUZZER_H
void Buzzer_Init(void);
void Buzzer_ON(void);
void Buzzer_OFF(void);
void Buzzer_Turn(void);
#endif
Buzzer.C
:
#include "stm32f10x.h" // Device header
/**
* 函 数:蜂鸣器初始化
* 参 数:无
* 返 回 值:无
*/
void Buzzer_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB12引脚初始化为推挽输出
/*设置GPIO初始化后的默认电平*/
GPIO_SetBits(GPIOB, GPIO_Pin_12); //设置PB12引脚为高电平
}
/**
* 函 数:蜂鸣器开启
* 参 数:无
* 返 回 值:无
*/
void Buzzer_ON(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_12); //设置PB12引脚为低电平
}
/**
* 函 数:蜂鸣器关闭
* 参 数:无
* 返 回 值:无
*/
void Buzzer_OFF(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_12); //设置PB12引脚为高电平
}
/**
* 函 数:蜂鸣器状态翻转
* 参 数:无
* 返 回 值:无
*/
void Buzzer_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0) //获取输出寄存器的状态,如果当前引脚输出低电平
{
GPIO_SetBits(GPIOB, GPIO_Pin_12); //则设置PB12引脚为高电平
}
else //否则,即当前引脚输出高电平
{
GPIO_ResetBits(GPIOB, GPIO_Pin_12); //则设置PB12引脚为低电平
}
}
LightSensor.h
:
#ifndef __LIGHT_SENSOR_H
#define __LIGHT_SENSOR_H
void LightSensor_Init(void);
uint8_t LightSensor_Get(void);
#endif
LightSensor.c
:
#include "stm32f10x.h" // Device header
/**
* 函 数:光敏传感器初始化
* 参 数:无
* 返 回 值:无
*/
void LightSensor_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB13引脚初始化为上拉输入
}
/**
* 函 数:获取当前光敏传感器输出的高低电平
* 参 数:无
* 返 回 值:光敏传感器输出的高低电平,范围:0/1
*/
uint8_t LightSensor_Get(void)
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13); //返回PB13输入寄存器的状态
}
main.c
:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Buzzer.h"
#include "LightSensor.h"
int main(void)
{
/*模块初始化*/
Buzzer_Init(); //蜂鸣器初始化
LightSensor_Init(); //光敏传感器初始化
while (1)
{
if (LightSensor_Get() == 1) //如果当前光敏输出1
{
Buzzer_ON(); //蜂鸣器开启
}
else //否则
{
Buzzer_OFF(); //蜂鸣器关闭
}
}
}
作者:木木慕慕