STM32一文通(3) GPIO

作者: 熊爸天下_56c7 | 来源:发表于2020-07-26 22:55 被阅读0次

预置知识: 开时钟

STM32 每一个片上外设资源都有自己的时钟,这些时钟被一个叫做RCC的外设统一管理,
所以,每一个片上外设想要应用第一件事就是: 开时钟!!!!!
根据系统结构图,GPIO都在APB2总线上


所以,我们要用void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)函数操作开启GPIO的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能或者失能APB2外设时钟

一. GPIO基础知识、寄存器及库函数

二. (重要)GPIO位带操作

如果我们想读取某个推挽输出GPIO引脚现在的状态,怎么做呢?
我们可以读取它的ODR寄存器状态, 比如GPIOB的0脚可以这样读:

GPIOB->ODR ^= GPIO_Pin_0;

由于我们不喜欢寄存器操作的方式, 现在我们想把它封装起来, 怎么封装呢?

这里我们用到一个位带别名区(可以理解为一大片寄存器), 位带区把每个GPIO寄存器的每个位(每个引脚)的状态映射到了自己的寄存器中. 我们根据GPIO的寄存器地址+位(引脚)偏移,可以算出去这个寄存器的哪个映射地址中可以读到这个位(引脚)的状态, 我们称之为地址转换计算。计算公式推导过程忽略, 直接记住结果:

地址转换计算公式

 ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2))

在程序中, 我们定义这样一个宏:

#define BITBAND(addr, bitnum) *(unsigned int*)((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2))

当我们想获取GPIOB的ODR寄存器的某个位的状态时:

#define GPIOB_ODR_Addr      (GPIOB_BASE + 0X0C)   //找到GPIOB的基地址
#define GPIOB_ODR_bitnum    0                     //想读GPIOB的ODR寄存器的第0位
#define BITBAND(addr, bitnum) *(unsigned int*)((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2)) //位带操作地址转换公式

当函数调用时:

BITBAND(GPIOB_ODR_Addr,GPIOB_ODR_bitnum)=0; //写位

a= BITBAND(GPIOB_ODR_Addr,GPIOB_ODR_bitnum); //读位

事实上,并非只有GPIO. 位带区分为外设位带区和SRAM位带区(两者的地址计算方法还不一样). 它们为STM32提供了按位读取的基础.就像51单片机里的sbit

这里举一个位带操作的完整例子:

main.c

#include "stm32f10x.h"
#include "led.h"
#include "key.h"

#ifndef BITBAND
#define BITBAND(addr, bitnum) *(unsigned int*)((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2)) //位带操作地址转换公式
#endif  /*BITBAND*/

int a;
int main(void)
{
    LED_GPIO_Config();
    KEY1_GPIO_Config();
    KEY2_GPIO_Config();
    LED_G(OFF);//其实这里也可以改成LED_G_Out_Sbit=1
    LED_R(OFF);
    LED_B(OFF); 
    while(1)
    {
        if(KEY1_In_Sbit)
        {
            while(KEY1_In_Sbit);
            LED_G_Out_Sbit=!LED_G_Out_Sbit;
        }
            
        if(KEY2_In_Sbit)
        {
            while(KEY2_In_Sbit);
            LED_R_Out_Sbit=!LED_R_Out_Sbit;
        }
    }   
}

led.h

#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"



#define LED_G_GPIO                          GPIOB
#define LED_G_Pin                           GPIO_Pin_0
#define LED_G_GPIO_ODR_Addr         (GPIOB_BASE + 0X0C)   //绿灯位带操作:找到GPIOB的基地址
#define LED_G_ODR_bitnum                0                     //绿灯位带操作:想读GPIOB的ODR寄存器的第0位
#define LED_G_Out_Sbit                          BITBAND(LED_G_GPIO_ODR_Addr,LED_G_ODR_bitnum)   //将绿灯的位定义出来了

#define LED_R_GPIO                          GPIOB
#define LED_R_Pin                           GPIO_Pin_5
#define LED_R_GPIO_ODR_Addr         (GPIOB_BASE + 0X0C)   //红灯位带操作:找到GPIOB的基地址
#define LED_R_ODR_bitnum                5                     //红灯位带操作:想读GPIOB的ODR寄存器的第5位
#define LED_R_Out_Sbit                          BITBAND(LED_R_GPIO_ODR_Addr,LED_R_ODR_bitnum)    //将宏灯的位定义出来了

#define LED_B_GPIO                          GPIOB
#define LED_B_Pin                           GPIO_Pin_1
#define LED_B_GPIO_ODR_Addr         (GPIOB_BASE + 0X0C)   //蓝灯位带操作:找到GPIOB的基地址
#define LED_B_ODR_bitnum                1                     //蓝灯位带操作:想读GPIOB的ODR寄存器的第1位
#define LED_B_Out_Sbit                          BITBAND(LED_B_GPIO_ODR_Addr,LED_B_ODR_bitnum)  //将蓝灯的位定义出来了

#define ON   1
#define OFF  0

#define LED_G(a) if(a) GPIO_ResetBits(LED_G_GPIO,LED_G_Pin); else GPIO_SetBits(LED_G_GPIO,LED_G_Pin);// 这里用了一个条件定义
#define LED_R(a) if(a) GPIO_ResetBits(LED_R_GPIO,LED_R_Pin); else GPIO_SetBits(LED_R_GPIO,LED_R_Pin);// 这里用了一个条件定义
#define LED_B(a) if(a) GPIO_ResetBits(LED_B_GPIO,LED_B_Pin); else GPIO_SetBits(LED_B_GPIO,LED_B_Pin);// 这里用了一个条件定义

void LED_GPIO_Config(void);

#endif /*__LED_H*/

key.h

#ifndef __KEY_H
#define __KEY_H

#include "stm32f10x.h"

#define KEY1_GPIO                           GPIOA
#define KEY1_GPIO_Pin                       GPIO_Pin_0
#define KEY1_GPIO_IDR_Addr          (GPIOA_BASE + 0X08)   //key1位带操作:找到GPIOA的IDR基地址
#define KEY1_ODR_bitnum                 0                     //key1位带操作:想读GPIOA的IDR寄存器的第0位
#define KEY1_In_Sbit                                BITBAND(KEY1_GPIO_IDR_Addr,KEY1_ODR_bitnum)   //将蓝灯的位定义出来了

#define KEY2_GPIO                           GPIOC
#define KEY2_GPIO_Pin                       GPIO_Pin_13
#define KEY2_GPIO_IDR_Addr          (GPIOC_BASE + 0X08)   //key2位带操作:找到GPIOC的IDR基地址
#define KEY2_ODR_bitnum                 13                    //key2位带操作:想读GPIOC的IDR寄存器的第13位
#define KEY2_In_Sbit                                BITBAND(KEY2_GPIO_IDR_Addr,KEY2_ODR_bitnum)  //按位操作KEY2

#define KEY_ON                  1
#define KEY_OFF                 0

void KEY1_GPIO_Config(void);
void KEY2_GPIO_Config(void);

#endif

led.c和 key.c 都只有GPIO初始化函数, 这里省略了

三. GPIO库函数

1. GPIO初始化函数:GPIO_Init

GPIO初始化用以下函数

参数1:可以看到,初始化时,需要一个GPIO_TypeDef类型的指针GPIOx
参数2:需要一个GPIO_InitTypeDef类型的指针GPIO_InitStruct
这个GPIO_InitTypeDef如何定义呢?

定义这个结构体,需要对以下参数进行初始化

  • 参数2的参数1: GPIO_Pin: 可选值
  • 参数2的参数2: GPIO_Speed
  • 参数2的参数3:

例子:

GPIO_InitTypeDef GPIO_InitStructure;  //创建GPIO_InitTypeDef类型的结构体GPIO_InitStructure
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//最高输出速率50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化外设GPIOx寄存器

2. GPIO位输出1函数:GPIO_SetBits

3. GPIO位输出0函数:GPIO_ResetBits

4. GPIO读取位输入 GPIO_ReadInputDataBit

5. GPIO读取位输出 GPIO_ReadOutputDataBit

6. GPIO整体写端口:

7. GPIO整体读端口:

相关文章

  • STM32一文通(3) GPIO

    预置知识: 开时钟 STM32 每一个片上外设资源都有自己的时钟,这些时钟被一个叫做RCC的外设统一管理,所以,每...

  • 1. 控制 LED - GPIO OUTPUT

    资源推荐:STM32 Tutorial 01 - GPIO Operations using HAL 在 STM3...

  • STM32F10x之GPIO

    1 GPIO概述 1.1 功能描述 STM32的GPIO端口相对比较复杂,所以使用起来也困难许多,STM32的GP...

  • STM32的GPIO内部结构及相关寄存器

    1. GPIO简介 GPIO是通用输入/输出端口的简称,是STM32可控制的引脚。GPIO的引脚与外部硬件设备连接...

  • 2018-10-22 使用SN75176(RS485)通讯与S

    项目中使用STM32 UART连接SN75176与外界实现485通讯,通过一个单独GPIO管脚控制485 传输方向...

  • 12/12

    今天学习了gpio和stm32的点亮小灯程序,关于stm32的板子芯片内部,了解了一些

  • STM32外部中断

    STM32 的每个 IO 都可以作为外部中断的中断输入口,这点也是 STM32 的强大之处。GPIO 的管脚 GP...

  • STM32端口复用和重映射

    端口复用 STM32有很多的内置外设,这些外设的外部引脚都是与GPIO复用的。也就是说,一个GPIO如果可以复用为...

  • CPIO初始化

    STM32 点灯程序 初始化GPIO: 如果有#include "sys.h"头文件就 如果没有#include ...

  • STM32中外设的GPIO配置要求

    本文列举了STM32常用外设配置时的GPIO配置要求,表中配置列的名词的解释请参考《STM32中文参考手册_V10...

网友评论

    本文标题:STM32一文通(3) GPIO

    本文链接:https://www.haomeiwen.com/subject/wfewlktx.html