• 【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);
    	}
    }
    
  • 相关阅读:
    基于遗传算法的水力发电厂的优化(Matlab代码实现)
    jsp儿童网站系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
    Win11勒索软件防护怎么打开?Win11安全中心勒索软件防护如何设置
    WindowsServer下配置Mysql主从同步---Mysql主从复制同步001
    从0到1构建react完整项目2022最新无坑版
    Windows10下Tomcat8.5安装教程
    Python入门都实践需要多长时间?|猿代码科技
    Qt5开发从入门到精通——第五篇一节( 文本编辑器 Easy Word 开发 V1.0 详解 )
    【365天深度学习训练营】第三周 天气识别
    你有了解过这些架构设计,架构知识体系吗?(架构书籍推荐)
  • 原文地址:https://blog.csdn.net/WandZ123/article/details/127112395