STM32之GPIO

1. 什么是GPIO

• GPIO是通用输入输出端口,是(General-purpose input output)的英文简写。是所有微控制器必不可少的外设之一,其作用是可以由STM32直接驱动从而和外界进行交互,从而实现和外界设备进行通信,控制,采集以及捕获的功能。

• GPIO口可以配置成多种工作模式,比如:浮空输入(GPIO_MODE_INPUT),推挽输出(GPIO_MODE_OUTPUT_PP),开漏输出(GPIO_MODE_OUTPUT_OD),复用推挽输出(GPIO_MODE_AF_PP),复用开漏输出(GPIO_MODE_AF_OD),复用输入(GPIO_MODE_AF_INPUT),模拟输入(GPIO_MODE_ANALOG)。

• STM32单片机中有多组GPIO口,例如:GPIOA,GPIOB等等,每组最多有16 个引脚,不同型号的单片机所拥有的GPIO口数量不同。

• STM32单片机引脚的电压为0-3.3v,部分引脚为5v。

2. GPIO内部结构

• 如图:

• 这个图来自芯片手册,这是GPIO的基本结构,这里面是分为输入和输出两种:

2.1 输入分为上拉输入,下拉输入,浮空输入,模拟输入

• 上拉输入:默认接了一个上拉电阻(VDD),如果此时GPIO口就算没有外界的输入,该引脚默认保持高电平,只有外界来了一个低电平信号,引脚才表示低电平。

• 下拉输入:默认接了一个下拉电阻(VSS),如果此时GPIO口就算没有外界的输入,该引脚默认保持低电平。只有外界来了一个高电平信号,引脚才表示高电平。

• 浮空输入:既没接上拉电阻,也没有接下拉电阻。此时浮空状态下,电平信号是不确定的,完全是由外界输入决定的,如果在浮空状态读取,电平是不确定的。

• 模拟输入:输入信号是不用经过TTL肖特基触发器,是直接接入进入的,输入信号为模拟量 ,然后经过ADC变为数字量

• TTL肖特基触发器:让读取进来的信号进行修剪,变成方波形状。

2.2 输出分为推挽输出,开漏输出,复用推挽输出,复用开漏输出

• 推挽输出:既能输出低电平也能输出高电平。在推挽输出工作模式下,P-MOS和N-MOS都工作,当输出高电平的时候,N-MOS不导通,P-MOS导通输出高电平。当输出低电平的时候,P-MOS不导通,N-MOS导通输出低电平。

• 开漏输出:只能输出低电平。在开漏输出工作模式下,只有N-MOS工作,只有N-MOS导通输出低电平。就算我们要求输出高电平它也是无效的,P-MOS不会工作。

• 复用推挽输出和复用开漏输出:都由内部外设决定使用那一种工作模式。比如i2c的时钟线和数据线使用的是复用开漏输出,还有can的tx线使用的是复用推挽输出。

3. 实操

3.1 点亮一个LED灯

cpp 复制代码
#include "sys.h"
#include "uart1.h"
#include "delay.h"
#include "led.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
//    led_on();//开灯
//    delay_ms(500);
//    led_off();//关灯
    while(1)//流水灯实验
    { 
        led1_on();
        led2_off();
        delay_ms(500);//没隔500ms闪烁
        
        led2_on();
        led1_off();
        delay_ms(500);//没隔500ms闪烁
    }
}
cpp 复制代码
#include "led.h"

void led_init(){
    GPIO_InitTypeDef gpio_init = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();//使能GPIO时钟
    gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init.Pin = GPIO_PIN_8 | GPIO_PIN_9;//推挽输出
    gpio_init.Pull = GPIO_PULLUP;//默认上拉
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB,&gpio_init);//初始化gpio
    led1_off();//关灯
    led2_off();

}

void led1_on(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}

void led1_off(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}


void led1_toggle(){
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
}


void led2_on(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
}

void led2_off(){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
}


void led2_toggle(){
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
}

3.2 按键控制灯

• main.c的代码

cpp 复制代码
#include "sys.h"
#include "key.h"
#include "delay.h"
#include "led.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    key_init();
    uint8_t key_num = 0;
    while(1)
    { 
        key_num = key_scan();//不断检测按键
        if(key_num == 1)
            led1_toggle();//翻转led1
        else if(key_num == 2)
            led2_toggle();//反转led2
    }
}

• key.c的代码

cpp 复制代码
#include "key.h"
#include "delay.h"

void key_init(){
    GPIO_InitTypeDef gpio_init = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIO时钟
    gpio_init.Mode = GPIO_MODE_INPUT;
    gpio_init.Pin = GPIO_PIN_0 | GPIO_PIN_1;//推挽输出
    gpio_init.Pull = GPIO_PULLUP;//默认上拉
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA,&gpio_init);//初始化gpio

}

uint8_t key_scan(){
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){//判断按键是否被按下
        //延时一段时间,在判断按键是否被按下,达到软件消抖作用
        delay_ms(10);
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){//在判断按键是否被按下
            while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);//如果被按下,等待松开按键
            return 1;//返回按键值
        }
    }
    
    
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET){//判断按键是否被按下
        //延时一段时间,在判断按键是否被按下,达到软件消抖作用
        delay_ms(10);
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET){//在判断按键是否被按下
            while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);//如果被按下,等待松开按键
            return 2;//返回按键值
        }
    }
    
    return 0;

}
相关推荐
Flamingˢ21 小时前
ZYNQ + OV5640 视频系统开发(四):HDMI 显示链路
嵌入式硬件·fpga开发·硬件架构·音视频
LCMICRO-133108477461 天前
国产长芯微LDC5141完全P2P替代DAC80501,数模转换器 (DAC)
单片机·嵌入式硬件·fpga开发·硬件工程·dsp开发·数模转换器 dac
普中科技1 天前
【普中 51-Ai8051 开发攻略】-- 第 9 章 按键控制实验
单片机·嵌入式硬件·开发板·keil·按键·普中科技·ai8051u
曼亿点1 天前
STM32HAL驱动L298N电机驱动模块(PWM调速+双电机控制)保姆级教程
stm32·单片机·嵌入式硬件
筱谙1 天前
BES 芯片跨核通讯与共享内存设计原理
嵌入式硬件·音频·蓝牙
思为无线NiceRF1 天前
高空线路安装智能安全帽全双工组网对讲系统(含优先级管控)应用方案
嵌入式硬件·物联网
独小乐1 天前
012.整体框架适配SDRAM|千篇笔记实现嵌入式全栈/裸机篇
c语言·汇编·笔记·单片机·嵌入式硬件·arm·gnu
不吃鱼的羊1 天前
ADC扫描组Scan Group
单片机
海砥装备HardAus1 天前
飞控算法中双环串级PID深度解析:角度环与角速度环的协同机制
stm32·算法·无人机·飞控·串级pid
LCMICRO-133108477461 天前
长芯微LPC556D1完全P2P替代DAC8830,是引脚兼容的16位数模转换器,该系列产品为单通道、低功耗、缓冲电压输出型DAC
stm32·单片机·嵌入式硬件·fpga开发·硬件工程·电压输出型dac