<>前言

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

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

* IO口引脚
* stm32的大部分引脚除了当GPIO使用外,还可以复用为外设功能引脚(比如串口)
1、GPIO 的工作方式

* 四种输入模式:
* 输入浮空 (_IN_FLOATING_)
* 输入上拉 (In Pull Up:IPU)
* 输入下拉 (In Pull Down:IPD)
* 模拟输入 (AIN:Analog In)
* 四种输出模式:
* 开漏输出(带上拉或者下拉):_Out_OD_(Out Open Drain)
* 开漏复用功能(带上拉或者下拉):AF_OD
* 推挽式输出(带上拉或者下拉):Out_PP(Out Push Pull),点灯
* 推挽式复用功能(带上拉或者下拉):AF_PP
* 四种最大速度:
* 2 MHz
* 25 MHz
* 50 MHz
* 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); } }

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信