目录
一、写在前面:
二、GPIO基本情况
1.概述
2.引脚说明
3.GPIO工作方式
(1)4种输入模式
(2)4种输出模式
(3)4种最大输出速度
(4)主要特性
4.GPIO相关配置寄存器
三、GPIO的那一堆寄存器
1.端口模式寄存器 (GPIOx_MODER)
GPIO port mode register
2.端口输出类型寄存器(GPIOx_OTYPER)
GPIO port output type register
3.端口输出速度寄存器(GPIOx_OSPEEDR)
GPIO port output speed register
4.端口上拉/下拉寄存器(GPIOx_PUPDR)
GPIO port pull-up/pull-down register
5.端口输入数据寄存器(GPIOx_IDR)
GPIO port input data register
6.端口输出数据寄存器(GPIOx_ODR)
GPIO port output data register
7.端口置位/复位寄存器(GPIOx_BSRR)
GPIO port bit set/reset register
8.GPIO端口配置锁定寄存器 (GPIOx_LCKR) (x = A..I)
GPIO port configuration lock register
9.GPIO 复用功能低位寄存器 (GPIOx_AFRL) (x = A..I)
GPIO alternate function low register
10.GPIO 复用功能高位寄存器 (GPIOx_AFRH) (x = A..I)
GPIO alternate function high register
四、GPIO小实验:跑马灯
1.硬件
2.库函数版(library function):
(1)重要函数
(2)led.c
3.寄存器版(register):
(1)RCC AHB1 外设时钟使能寄存器 (RCC_AHB1ENR)
(2)led.c
4.位操作版(Bit-band operations):
(1)位带操作
(2)步骤
(3)led.c
之前上过嵌入式的课程,也曾用rt1052/64把别人的程序编编改改,但对于单片机的理解仅停留在胎教的阶段。此次利用老师给的stm32f4(探索者)开发板,对单片机进行一个全面的学习。
该文章为学习笔记,内容主要来自《Cortex M3与M4权威指南》、《STM32F4xx中文参考手册》、《STM32F4开发指南-寄存器版本_V1.2》、《STM32F4开发指南-库函数版本_V1.2》、正点原子的教学视频及网络。环境选择Keil uVision5。
由于我编程和模电水平确实较差,望大家多批评指正了
GPIO(General-purpose input/output),通用型输入输出的简称。既然一个引脚可以用于输入、输出或其他特殊功能,那么一定有寄存器用来选择这些功能。对于输入,一定可以通过读取某个寄存器来确定引脚电位的高低;对于输出,一定可以通过写入某个寄存器来让这个引脚输出高电位或者低电位;而对于其他特殊功能,则有另外的寄存器来控制它们。
①一共有7组IO口:GPIOA—GPIOG
②每组IO口有16个IO:GPIOA_0—GPIOA_15
③一共7*16=112个IO
④所有IO口都可以作为中断输入
图1、2 5V容忍I/O端口位的基本结构
①输入浮空(input floating)
逻辑器件与引脚即不接高电平,也不接低电平,电压不确定
②输入上拉(input pull-up)
将不确定的信号通过一个电阻嵌位在高电平,上拉电阻同时可起到限流作用,IO口的常态为高电平
③输入下拉(input pull-down)
把电压拉低到GND,IO口的常态为低电平
④模拟功能(analog)
关闭施密特触发器,将电压信号传送到片上外设模块,不接上下拉电阻
①带上拉或下拉的开漏输出(output open-drain)
相当于三极管的集电极
开漏输出只可以输出强低电平 ,高电平靠外部电阻拉高
利用外部电路的驱动能力,减少IC(integrated circuit)内部的驱动。驱动电流从外部的VCC流出,IC内部仅需很小的栅极驱动电流
②带上拉或下拉的开漏复用功能(alternate function open-drain)
可同时当作普通GPIO及内部外设(片上外设)控制器的引脚来使用
I/O引脚通过一个复用器连接到板载外设,该复用器一次仅允许一个外设的复用功能(AF)连接到I/O引脚,确保共用同一个I/O引脚的外设之间不会发生冲突
③带上拉或下拉的推挽输出(output push-pull)
推挽输出可输出强高低电平,连接数字器件。
推挽结构一般指两个三极管分别受两互补信号的控制,总是一个导通一个截止
推挽电路是两个参数一样的三极管以推挽形式置于电路中,每次只有一个导通,导通功耗小、效率高。输出即可向负载灌电流,也可从负载抽取电流。因此可提高电路的负载能力以及开关速度。
④带上拉或下拉的推挽复用功能(alternate function push-pull)
同②
关于推挽输出和开漏输出可用图3来概括:
图3 左为推挽、右为开漏
2MHz / 25MHz / 50MHz / 100MHz
受控 I/O 多达 16 个
输出状态:推挽或开漏 + 上拉/下拉
从输出数据寄存器 (GPIOx_ODR) 或外设(复用功能输出)输出数据
可为每个 I/O 选择不同的速度
输入状态:浮空、上拉/下拉、模拟
将数据输入到输入数据寄存器 (GPIOx_IDR) 或外设(复用功能输入)
置位和复位寄存器 (GPIOx_BSRR),对 GPIOx_ODR 具有按位写权限
锁定机制 (GPIOx_LCKR),可冻结 I/O 配置
模拟功能
复用功能输入/输出选择寄存器(一个 I/O 最多可具有 16 个复用功能)
快速翻转(toggle),每次翻转最快只需要两个时钟周期
引脚复用非常灵活,允许将 I/O 引脚用作 GPIO 或多种外设功能中的一种
每组IO口含下面10个寄存器,即10个寄存器可以控制一组GPIO的16个IO口。
均为32位
每个通用 I/O 端口包括:
4 个 32 位配置寄存器(GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR 和GPIOx_PUPDR)
2 个 32 位数据寄存器(GPIOx_IDR 和GPIOx_ODR)
1 个 32 位置位/复位寄存器 (GPIOx_BSRR)
1 个 32 位锁定寄存器 (GPIOx_LCKR)
2 个 32 位复用功能选择寄存器(GPIOx_AFRH 和 GPIOx_AFRL)
MODER寄存器每2位控制一个IO。32个位控制一组IO的16个IO
00:输入(复位状态)
01:通用输出状态
10:复用功能模式
11:模拟模式
位31-16保留,必须保持复位值。
位15-0 端口x配置位,每位控制一个IO 0:输出推挽(复位状态)1:输出开漏
每2位控制一个IO口。32位控制一组IO口的16个IO
00:2MHz(低速)
01:25MHz(中速)
10:50MHz(快速)
11:30pF时为100MHz(高速)【15pF时为80MHz(高速)】 皮法 (pF)
00:无上拉或下拉
01:上拉
10:下拉
11:保留
31:16保留,必须保持复位值
15:0这些位为只读形式,只能在字模式下访问。它们包含相应I/O端口的输入值
31:16保留,必须保持复位值
15:0 通过写入该寄存器,可分别对ODR位进行置位(1)和复位(0)
31:16BRy:用于端口复位
这些位为只写形式,只能在字、半字或字节模式下访问。读取这些位可返回值0x0000
0:不会对相应的ODRx位执行任何操作
1:对相应ODRx位进行复位
15:0 BSy:用于端口置位
这些位为只写形式,只能在字、半字或字节模式下访问。读取这些位可返回值0x0000
0:不会对相应的ODRx位执行任何操作
1:对相应ODRx位进行置位
如果同时对BSx和BRx置位,则BSx的优先级更高
图4 引脚0到7所用复用器
31:0ADRLy:端口x位y的复用功能选择(Alternate function selection for port x bit y) (y = 0..7) 这些位通过软件写入,用于配置复用功能 I/O。AFRLy 选择:
图5 引脚8到15所用复用器
功能同复用功能低位寄存器。
注:任何方式操作IO口,都必须先使能相应的IO口时钟
go to defination的快捷键为F12
GPIO:推挽输出(上拉)
1个初始化函数:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
作用:初始化一个或者多个IO口(同一组)的工作模式,输出类型,速度以及上下拉方式。也就是一组IO口的4个配置寄存器。
(GPIOx->MODER, GPIOx->OSPEEDR,GPIOx->OTYPER,GPIOx->PUPDR)
2个读取输入电平函数:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:读取某个GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
作用:读取某组GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。
2个读取输出电平函数:
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:读取某个GPIO的输出电平。实际操作的是GPIO_ODR寄存器。
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
作用:读取某组GPIO的输出电平。实际操作的是GPIO_ODR寄存器。
4个设置输出电平函数:
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:设置某个IO口输出为高电平(1)。实际操作BSRRL寄存器
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
作用:设置某个IO口输出为低电平(0)。实际操作的BSRRH寄存器。
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
这两个函数不常用,也是用来设置IO口输出电平。
使能IO口时钟
RCC_AHB1PeriphClockCmd();
#include "led.h"
#include "stm32f4xx.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); //IO口时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10; //对结构体进行赋值
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
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); //置位
}
RCC(Reset Clock Controller)
RCC AHB1 peripheral clock enable register
#include "stm32f4xx.h"
void LED_Init(void)
{
RCC->AHB1ENR|= 1<<5; //IO口时钟使能
//PF9
GPIOF->MODER &= ~(3<<2*9); //通用输出
GPIOF->MODER |= 1<<(2*9);
GPIOF->OSPEEDR &= ~(3<<2*9); //50MHz
GPIOF->OSPEEDR |= 2<<(2*9);
GPIOF->OTYPER &= ~(1<<9); //推挽
GPIOF->OTYPER |= (0<<9);
GPIOF->PUPDR &= ~(3<<2*9); //上拉
GPIOF->PUPDR |= 1<<(2*9);
GPIOF->ODR |= 1<<9; //高电平
//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;
}
位带别名区(Bit Band alias address)把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。
使能IO口时钟,调用RCC_AHB1PeriphClockCmd();
初始化IO口模式
位带操作
#include "stm32f4xx.h"
#include "led.h"
#include "delay.h"
int main(void)
{
delay_init(168); //初始化延时函数
LED_Init();
while(1)
{
PFout(9) = 1; //PFout()为IO口操作宏定义
PFout(10) = 1;
delay_ms(500);
PFout(9) = 0;
PFout(10) = 0;
delay_ms(500);
}
}
本文结束
STM32F4学习笔记(二):时钟树及SysTick定时器