2.STM32 GPIO


如果想单独一对一辅导学习嵌入式、C++、Java、Python编程语言的可以加微信咨询

使用寄存器点亮 LED 灯

1. GPIO 简介

GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。

STM32 芯片的 GPIO被分成很多组,每组有 16 个引脚,如型号为 STM32F103ZET6 型号的芯片有 GPIOA、GPIOB、GPIOC 至 GPIOG 共 7 组 GPIO,芯片一共 144 个引脚,其中 GPIO 就占了一大部分,所有的 GPIO引脚都有基本的输入输出功能。

最基本的输出功能是由 STM32 控制引脚输出高、低电平,实现开关控制,如把 GPIO 引脚接入到 LED 灯,那就可以控制 LED 灯的亮灭,引脚接入到继电器或三极管,那就可以通过继电器或三极管控制外部大功率电路的通断。

最基本的输入功能是检测外部输入电平,如把 GPIO 引脚连接到按键,通过电平高低区分按键是否被按下。

GPIO 工作模式

typedef enum
{
 GPIO_Mode_AIN = 0x0, // 模拟输入
 GPIO_Mode_IN_FLOATING = 0x04, // 浮空输入
 GPIO_Mode_IPD = 0x28, // 下拉输入
 GPIO_Mode_IPU = 0x48, // 上拉输入
 GPIO_Mode_Out_OD = 0x14, // 开漏输出
 GPIO_Mode_Out_PP = 0x10, // 推挽输出
 GPIO_Mode_AF_OD = 0x1C, // 复用开漏输出
 GPIO_Mode_AF_PP = 0x18 // 复用推挽输出
} GPIOMode_TypeDef;

1.2 GPIO工作模式

在固件库中,GPIO 总共有 8 种细分的工作模式,稍加整理可以大致归类为以下三类:
1.输入模式 (模拟/浮空/上拉/下拉)
在输入模式时,施密特触发器打开,输出被禁止,可通过输入数据寄存器 GPIOx_IDR 读取 I/O 状态。其中输入模式,可设置为上拉、下拉、浮空和模拟输入四种。上拉和下拉输入很好理解,默认的电平由上拉或者下拉决定。浮空输入的电平是不确定的,完全由外部的输入决定,一般接按键的时候用的是这个模式。模拟输入则用于 ADC 采集。

2.输出模式 (推挽/开漏)
在输出模式中,推挽模式时双 MOS 管以轮流方式工作,输出数据寄存器 GPIOx_ODR 可控制 I/O输出高低电平。开漏模式时,只有 N-MOS 管工作,输出数据寄存器可控制 I/O 输出高阻态或低电平。输出速度可配置,有 2MHz10MHz50MHz 的选项。此处的输出速度即 I/O 支持的高低电平状态最高切换频率,支持的频率越高,功耗越大,如果功耗要求不严格,把速度设置成最大即可。在输出模式时施密特触发器是打开的,即输入可用,通过输入数据寄存器 GPIOx_IDR 可读取 I/O
的实际状态。

3.复用功能 (推挽/开漏)
复用功能模式中,输出使能,输出速度可配置,可工作在开漏及推挽模式,但是输出信号源于其它外设,输出数据寄存器 GPIOx_ODR 无效;输入可用,通过输入数据寄存器可获取 I/O 实际状态,但一般直接用外设的寄存器来获取该数据信号。通过对 GPIO 寄存器写入不同的参数,就可以改变 GPIO 的工作模式,再强调一下,要了解具体寄存器时一定要查阅《STM32F10X-中文参考手册》中对应外设的寄存器说明。在 GPIO 外设中,控制端口高低控制寄存器 CRH 和 CRL 可以配置每个 GPIO 的工作模式和工作的速度,每 4 个位控制一个 IO,CRH 控制端口的高八位,CRL 控制端口的低 8 位,具体的看 CRH 和 CRL 的寄存器描述。

1.3 创建工程添加代码

在这里插入图片描述

/*
  *工程模板(寄存器版本)
  */
#include "stm32f10x.h"


/**
  *   主函数
  */
int main(void)
{    
    // 开启GPIOB 端口时钟
    RCC_APB2ENR |= (1<<3);


    //清空控制PB0的端口位
    GPIOB_CRL &= ~( 0x0F<< (4*0));    
    // 配置PB0为通用推挽输出,速度为10M
    GPIOB_CRL |= (1<<4*0);


    // PB0 输出 低电平
    GPIOB_ODR &= ~(1<<0);
    
    while(1);
}

// 函数为空,目的是为了骗过编译器不报错
void SystemInit(void)
{    
}

/*********************************************END OF FILE**********************/

1.4 其他说明

1.在嵌入式中,为了避免影响到其他的寄存器位,常用 &=~ 对寄存器进行清零,用| = 对寄存器进行置位。
2.GPIO 引脚速度: GPIO_Speed_2MHz (10MHz, 50MHz) ;
又称输出驱动电路的响应速度:(芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路,通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。)
可理解为: 输出驱动电路的带宽:即一个驱动电路可以不失真地通过 信号的最大频率。如果一个信号的频率超过了驱动电路的响应速度,就有可能信号失真。如果信号频率为10MHz,而你配置了2MHz的带宽,则10MHz的方波很可能就变成了正弦波。就好比是公路的设计时速,汽车速度低于设计时速时,可以平稳地运行,如果超过设计时速就会颠簸,甚至翻车。

关键是GPIO的引脚速度跟应用匹配(推荐10倍以上)。
比如:
① USART串口,若最大波特率只需115.2k,那用2M的速度就够了,既省电也噪声小。
② I2C接口,若使用400k波特率,若想把余量留大些,可以选用10M的GPIO引脚速度。
③ SPI接口,若使用18M或9M波特率,需要选用50M的GPIO的引脚速度。

3.stm32f10x.h寄存器地址设置,这里没有用任何固件库,属于最原始的根据硬件手册编写

/*本文件用于添加寄存器地址及结构体定义*/

/*片上外设基地址  */
#define PERIPH_BASE           ((unsigned int)0x40000000)

/*APB2 总线基地址 */
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
/* AHB总线基地址 */
#define AHBPERIPH_BASE        (PERIPH_BASE + 0x20000)


/*GPIOB外设基地址*/
#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)


/* GPIOB寄存器地址,强制转换成指针 */
#define GPIOB_CRL            *(unsigned int*)(GPIOB_BASE+0x00)
#define GPIOB_CRH            *(unsigned int*)(GPIOB_BASE+0x04)
#define GPIOB_IDR            *(unsigned int*)(GPIOB_BASE+0x08)
#define GPIOB_ODR            *(unsigned int*)(GPIOB_BASE+0x0C)
#define GPIOB_BSRR      *(unsigned int*)(GPIOB_BASE+0x10)
#define GPIOB_BRR            *(unsigned int*)(GPIOB_BASE+0x14)
#define GPIOB_LCKR        *(unsigned int*)(GPIOB_BASE+0x18)

/*RCC外设基地址*/
#define RCC_BASE      (AHBPERIPH_BASE + 0x1000)
/*RCC的AHB1时钟使能寄存器地址,强制转换成指针*/
#define RCC_APB2ENR         *(unsigned int*)(RCC_BASE+0x18)

4.startup_stm32f10x_hd.s”的文件,
它里边使用汇编语言写好了基本程序,当 STM32 芯片上电启动的时候,首先会执行这里的汇编程序,从而建立起 C 语言的运行环境,所以我们把这个文件称为启动文件。
startup_stm32f10x_hd.s 文件由官方提供,一般有需要也是在官方的基础上修改,不会自己完全重写。该文件从 ST 固件库里面找到,找到该文件后把启动文件添加到工程里面即可。不同型号的芯片以及不同编译环境下使用的汇编文件是不一样的,但功能相同。对于启动文件这部分我们主要总结它的功能,不详解讲解里面的代码,其功能如下:
• 初始化堆栈指针 SP;
• 初始化程序计数器指针 PC;
• 设置堆、栈的大小;
• 初始化中断向量表;
• 配置外部 SRAM 作为数据存储器(这个由用户配置,一般的开发板可没有外部 SRAM);
• 调用 SystemIni() 函数配置 STM32 的系统时钟。
• 设置 C 库的分支入口“__main”(最终用来调用 main 函数);

1.5 三个灯的循环点亮

 
#include "stm32f10x.h"

/**
  *   主函数
  */
int main(void)
{    
    // 开启GPIOB 端口时钟
    RCC_APB2ENR |= (1<<3);


    //清空控制PB0的端口位
    GPIOB_CRL &= ~( 0x0F<< (4*0));    
    // 配置PB0为通用推挽输出,速度为10M
    GPIOB_CRL |= (1<<4*0);


    // PB0 输出 低电平
    GPIOB_ODR &= ~(1<<0);
    
    //清空控制PB1的端口位
    GPIOB_CRL &= ~( 0x0F<< (4*1));    
    // 配置PB1为通用推挽输出,速度为10M
    GPIOB_CRL |= (1<<4*1);


    // PB1 输出 低电平
    GPIOB_ODR &= ~(1<<1);
    
    //清空控制PB5的端口位
    GPIOB_CRL &= ~( 0x0F<< (4*5));    
    // 配置PB5为通用推挽输出,速度为10M
    GPIOB_CRL |= (1<<4*5);


    // PB5 输出 低电平
    GPIOB_ODR &= ~(1<<5);
    while(1);
}

// 函数为空,目的是为了骗过编译器不报错
void SystemInit(void) 
{    
}

/*********************************************END OF FILE**********************/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值