时不可以苟遇,道不可以虚行。
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











STM32F4 的大部分端口都具有复用功能。
所谓复用,就是一些端口不仅仅可以做为通用的 IO 口,还可以复用为一些外设引脚,比如:PA9、PA10 可以复用为 STM32F4 的串口 1 引脚。
作用:最大限度的利用端口资源。





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
位带操作简单的说,就是 把每个比特膨胀为一个 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);
}
}