【STM32】:GPIO工作原理

前言

时不可以苟遇,道不可以虚行。


一、GPIO 基本结构和工作方式

  • IO口引脚
  • stm32的大部分引脚除了当GPIO使用外,还可以复用为外设功能引脚(比如串口)

1、GPIO 的工作方式

  • 四种输入模式:
  1. 输入浮空 (_IN_FLOATING_)
  2. 输入上拉 (In Pull Up:IPU)
  3. 输入下拉 (In Pull Down:IPD)
  4. 模拟输入 (AIN:Analog In)
  • 四种输出模式:
  1. 开漏输出(带上拉或者下拉):_Out_OD_(Out Open Drain)
  2. 开漏复用功能(带上拉或者下拉):AF_OD
  3. 推挽式输出(带上拉或者下拉):Out_PP(Out Push Pull),点灯
  4. 推挽式复用功能(带上拉或者下拉):AF_PP
  • 四种最大速度:
  1. 2 MHz
  2. 25 MHz
  3. 50 MHz
  4. 100 MHz
  • 推挽输出:可以输出强高低电平,连接数字器件
  • 开漏输出:只可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻,适合做电流型的驱动,其吸收电流的能力相对强(一般在 20 MA 以内)

二、GPIO寄存器说明

在这里插入图片描述
在这里插入图片描述

GPIO 相关配置寄存器:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


3、STM32F4xx GPIO 引脚说明

- 端口复用

  • STM32F4 的大部分端口都具有复用功能。

    所谓复用,就是一些端口不仅仅可以做为通用的 IO 口,还可以复用为一些外设引脚,比如:PA9、PA10 可以复用为 STM32F4 的串口 1 引脚。

  • 作用:最大限度的利用端口资源。

- 所有 IO 口都可以作为中断输入


四、GPIO 库函数介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

库函数代码:

  • main.c
#include "stm32f4xx.h"
#include "LED.h"
#include "delay.h"

/** 库函数版本 **/
int main(void)
{
    
    
	delay_init(168);
	
	LED_Init();
	
	while(1)
	{
    
    
		GPIO_SetBits(GPIOF,GPIO_Pin_9);
		GPIO_ResetBits(GPIOF,GPIO_Pin_10);
		delay_ms(500);
		
		GPIO_SetBits(GPIOF,GPIO_Pin_10);
		GPIO_ResetBits(GPIOF,GPIO_Pin_9);
		delay_ms(500);
	}
}
  • LED.c
#include "LED.h"

/** 库函数版本 **/
void LED_Init(void)
{
    
    
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOF, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOF, GPIO_Pin_9 | GPIO_Pin_10);
}
  • LED.h
#ifndef _LED_H_
#define _LED_H_

#include "stm32f4xx.h"

void LED_Init(void);

#endif

五、寄存器配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

寄存器代码:

  • main.c
#include "stm32f4xx.h"
#include "LED.h"
#include "delay.h"

/** 寄存器版本 **/
int main(void)
{
    
    
	delay_init(168);
	LED_Init();
	
	while(1)
	{
    
    
		GPIOF->ODR &= 1 << 9;	//PF9:0
		GPIOF->ODR &= 1 << 10;	//PF10:0
		delay_ms(500);
		
		GPIOF->ODR |= 1 << 9;	//PF9:1
		GPIOF->ODR |= 1 << 10;	//PF10:1
		delay_ms(500);
	}
}
  • LED.c
#include "LED.h"

/** 寄存器版本 **/
void LED_Init(void)
{
    
    
	RCC->AHB1ENR |= 1 << 5;		// 1 左移 5 位,将寄存器的第五位设置为1,其他位不变
	
	//PF9
	// 11 = 3,左移18(2*9)位,然后再取反,将MODER寄存器的18、19位清零,其他位不变
	GPIOF->MODER &= ~(3 << 2*9);
	// 01(通用输出功能) = 1,左移18(2*9)位,将MODER寄存器的19、18位置为01,其他位不变
	GPIOF->MODER |= 1 << (2*9);
	
	// 11 = 3,左移18(2*9)位,然后再取反,将OSPEEDR寄存器的18、19位清零,其他位不变
	GPIOF->OSPEEDR &= ~(3 << 2*9);
	// 10(50MHz:快速) = 2,左移18(2*9)位,将OSPEEDR寄存器的19、18位置为10,其他位不变
	GPIOF->OSPEEDR |= 2 << (2*9);
	
	
	GPIOF->OTYPER &= ~(1 << 9);
	GPIOF->OTYPER |= 0 << 9;
	
	// 11 = 3,左移18(2*9)位,然后再取反,将PUPDR寄存器的18、19位清零,其他位不变
	GPIOF->PUPDR &= ~(3 << 2*9);
	// 01(上拉) = 1,左移18(2*9)位,将PUPDR寄存器的19、18位置为01,其他位不变
	GPIOF->PUPDR |= 1 << (2*9);
	
	//输出高低电平:使用ODR寄存器
	GPIOF->ODR |= 1 << 9;	//1
	//GPIOF->ODR &= 1 << 9;	//0
	
	//PF10
	GPIOF->MODER &= ~(3 << 2*10);
	GPIOF->MODER |= 1 << (2*10);
	
	GPIOF->OSPEEDR &= ~(3 << 2*10);
	GPIOF->OSPEEDR |= 2 << (2*10);
	
	GPIOF->OTYPER &= ~(1 << 10);
	GPIOF->OTYPER |= 0 << 10;
	
	GPIOF->PUPDR &= ~(3 << 2*10);
	GPIOF->PUPDR |= 1 << (2*10);
	
	GPIOF->ODR |= 1 << 10;	//1
}
  • LED.h
#ifndef _LED_H_
#define _LED_H_

#include "stm32f4xx.h"

void LED_Init(void);

#endif

六、位操作

1、位操作基本原理

位带操作简单的说,就是 把每个比特膨胀为一个 32 位的字,当访问这些字的时候就达到了访问比特的目的,比如说 GPIO 的 ODR 寄存器有 32 个位,那么可以映射到 32 个地址上,我们去访问这 32 个地址就达到访问 32 个比特的目的。这样我们往某个地址写 1 就达到往对应比特位写 1 的目的,同样往某个地址写 0 就达到往对应的比特位写 0 的目的。

在这里插入图片描述

映射关系

  • 位带区:支持位带操作的地址区
  • 位带别名:对别名地址的访问最终作用到位带区的访问上

支持位带操作的两个内存区的范围是:

  • 0x2000_0000 ~ 0x200F_FFFF (SRAM 区中的最低 1 MB)
  • 0x4000_0000 ~ 0x400F_FFFF (片上外设区中最低 1 MB)

对于 SRAM 位带区的某个比特,记它所在字节地址为 A,位序号为 n(0 <= n <= 7),则该比特在别名区的地址为:
在这里插入图片描述
对于 片上外设 位带区的某个比特,记它所在字节地址为 A,位序号为 n(0 <= n <= 7),则该比特在别名区的地址为:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

位带操作代码:

  • main.c
#include "stm32f4xx.h"
#include "LED.h"
#include "delay.h"
#include "sys.h"

/** 位带操作版本 **/
int main(void)
{
    
    
	delay_init(168);
	LED_Init();
	
	while(1)
	{
    
    
		PFout(9) = 1;
		PFout(10) = 1;
		delay_ms(500);
		
		PFout(9) = 0;
		PFout(10) = 0;
		delay_ms(500);
	}
}

猜你喜欢

转载自blog.csdn.net/WandZ123/article/details/127112395