Skip to content

STM32 入门 2

GPIO 简介

GPIO(General Purpose Input Output)通用输入输出口

可配置8种输入输出模式

引脚电平 0~3.3V,部分可以容忍 5V

输出模式可以控制端口输出高低电平,用来驱动 LED、蜂鸣器和模拟通信协议输出时序等
输入模式下可读取端口的高低电平或电压,用于读取按键输入、外接模块电平信号输入、ADC电压采集、模拟通信协议接收数据等

GPIO 基本结构

STM32 所有 GPIO 都是挂载在 APB2 外设总线上的,GPIO 外设名称按照 GPIOA,GPIOB,GPIOC... 来命名

每个 GPIO 外设有16个引脚,编号0~15,GPIOA 第0号引脚称为 PA0,以此类推

每个 GPIO 外设内包括寄存器和驱动器,寄存器每一位对应一个引脚,0 低电平,1 高电平
由于 STM32 是 32 位的,寄存器只有低 16 位有端口,高 16 位没用

GPIO 模式

改变端口配置寄存器的值,可以配置8种模式
- 浮空输入 悬空不确定,因此使用时需要接上连续的驱动源
- 上拉输入 悬空默认高电平
- 下拉输入 悬空默认低电平
- 模拟输入 GPIO 无效,引脚直接接入 ADC(只有该模式会关闭数字输入功能)
- 开漏输出 高电平位高阻态,无驱动能力
- 推挽输出 高电平接 VDD,低电平接 VSS
- 复用开漏输出 由片上外设控制
- 复用推挽输出 由片上外设控制

LED 和蜂鸣器

LED:小的一瓣是正极,大的一瓣是负极

有源蜂鸣器:内部自带震荡源,正负极接上直流电压即可持续发声,频率固定

无源蜂鸣器:内部不带震荡源,需要控制器提供震荡脉冲才可发声,调整提供震荡脉冲的频率,可发出不同频率的声音

GPIO 输出

启用APB2上的GPIOA外设时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //clock

GPIO 初始化

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0);

输出函数

GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); // 指定端口设置为高电平
GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); // 指定端口设置为低电平
GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal); // 根据 BitVal 设置指定端口
// 这里 BitVal 可以是 Bit_SET 和 Bit_RESET,分别对应高低电平
GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); // 可以同时对16个端口写入操作

LED 闪烁

`

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //clock

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    //GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    //GPIO_SetBits(GPIOA,GPIO_Pin_0);
    GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
    while(1){
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
        Delay_ms(500);
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
        Delay_ms(500);
    }

}

Delay.h 手动添加,在 System 文件夹下面,需要添加组和头文件包含路径

现在 LED 是低电平点亮方式

如果是高电平点亮,推挽输出有驱动能力,开漏输出没有驱动能力

LED 流水灯

初始化多个引脚
因为每个端口相当于对应了一位,或可以拼装这些引脚
另外还有 GPIO_Pin_All 可以控制所有引脚(0~15)

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;

除了 GPIO 引脚可以用或运算,时钟控制的位置也可以用或运算选择多个外设(因为定义中每一位对应一个外设)
GPIO_SetBits() 函数设置引脚的时候同理可以用或运算拼接

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //clock

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    //GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    //GPIO_SetBits(GPIOA,GPIO_Pin_0);
    //GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
    int controller = 0x0001;
    while(1){
        for(int i=1;i<=8;i++)
        {
            GPIO_Write(GPIOA, ~controller); // 这里的 controller 每一位对应一个引脚的高低电平,从最低位(最右)到最高位依次对应0~15,取反是因为低电平驱动
            Delay_ms(500);
            controller *= 2;
        }
        controller = 0x0001;
    }

}

控制蜂鸣器

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //clock

    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);

    //GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    //GPIO_SetBits(GPIOA,GPIO_Pin_0);
    //GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
    while(1){
        GPIO_WriteBit(GPIOB, GPIO_Pin_12,Bit_RESET);
        Delay_ms(500);
        GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET);
        Delay_ms(500); 
    }
}