STM32 每个 IO 口可以自由编程,但 IO 口寄存器必须要按 32 位字被访问。 本文主要是库函数实现的笔记。相关图片来自正点原子教程。
输入浮空 输入上拉 输入下拉 模拟输入
a.输入浮空
CPU可以通过输入数据寄存器读出I/O口的高低电平,工作电路如图。
b.上拉下拉输入:添加了上拉、下拉电阻后,CPU再读电平
c.模拟输入
输入量为模拟量,不再是电平,输入的电压范围:0—3.3V
开漏输出 开漏复用功能 推挽式输出 推挽式复用功能
a. 开漏输出
开漏输出:输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般 20ma 以内)。
开漏是用来连接不同电平的器件,匹配电平用的,因为开漏引脚不连接外部的上拉电阻时,只能输出低电平,如果需要同时具备输出高电平的功能,则需要接上拉电阻,很好的一个优点是通过改变上拉电源的电压,便可以改变传输电平。
b. 推挽输出
推挽输出:可以输出高,低电平,连接数字器件; 推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由 IC 的电源决定。
推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。
(2) 8 个模式定义
GPIO_Mode_AIN = 0x0, //模拟输入
GPIO_Mode_IN_FLOATING = 0x04, //浮空输入
GPIO_Mode_IPD = 0x28, //下拉输入
GPIO_Mode_IPU = 0x48, //上拉输入
GPIO_Mode_Out_OD = 0x14, //开漏输出
GPIO_Mode_Out_PP = 0x10, //通用推挽输出
GPIO_Mode_AF_OD = 0x1C, //复用开漏输出
GPIO_Mode_AF_PP = 0x18 //复用推挽
STM32 的 IO 口位配置表如下
(3)IO口速度定义
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
STM32 输出模式配置:
I/O口输出速度是指I/O口驱动电路的响应速度而不是输出信号的速度,输出信号的速度与程序有关(芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路)。通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,这样非常有利于提高系统的EMI性能。当然如果要输出较高频率的信号,但却选用了较低频率的驱动模块,很可能会得到失真的输出信号。关键是GPIO的引脚速度跟应用匹配。
(4)IO配置
① 作为普通GPIO输入:
根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时不要使能该引脚对应的所有复用功能模块。
② 作为普通GPIO输出:
根据需要配置该引脚为推挽输出或开漏输出,同时不要使能该引脚对应的所有复用功能模块。
③ 作为普通模拟输入:
配置该引脚为模拟输入模式,同时不要使能该引脚对应的所有复用功能模块。
④ 作为内置外设的输入:
根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时使能该引脚对应的某个复用功能模块。
⑤ 作为内置外设的输出:
根据需要配置该引脚为复用推挽输出或复用开漏输出,同时使能该引脚对应的所有复用功能模块。
(5)GPIO口初始化
①使能GPIO口的时钟
②配置模式设置(8种模式)
注:STM32的GPIO的时钟统一挂接在APB2上,具体的使能寄存器为RCC_APB2ENR。该寄存器的第2位到第8位分别控制GPIOx(x=A,B,C,D,E,F,G)端口的时钟使能。
Eg:RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE); //使能PA,PD端口时钟
注:STM32 的很多 IO 口都是 5V 兼容的,可以从该芯片的数据手册管脚描述章节查到( I/O Level 标 FT 的就是 5V 电平兼容的)。
(6)GPIO配置寄存器
a.STM32 的 CRL 控制着每组 IO 端口( A~G)的低 8 位的模式。每个 IO 端口的位占用 CRL 的 4 个位,高两位为 CNF,低两位为 MODE。GPIO口配置是通过配置寄存器来进行的,每个GPIO 端口有:
两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH)分别控制每个端口的高八位和低八位。如果IO口是0-7号的话,则写CRL寄存器;如果IO口是8-15号的话,则写CRH寄存器。CRL 和 CRH 控制着每个 IO 口的模式及输出速率。
配置表如下:
输出模式配置:
端口低配置寄存器 CRL 的描述:
该寄存器的复位值为 0X4444 4444,复位值其实就是配置端口为浮空
输入模式。从上图还可以得出: STM32 的 CRL 控制着每组 IO 端口( A~G)的低 8 位的模式。每个 IO 端口的位占用 CRL 的 4 个位,高两位为 CNF,低两位为 MODE。
几个常用的配置,比如 0X0 表示模拟输入模式( ADC 用)、 0X3 表示推挽输出模式(做输出口用,50M 速率)、 0X8 表示上/下拉输入模式(做输入口用)、 0XB 表示复用输出(使用 IO 口的第二功能, 50M 速率)。
CRH 的作用和 CRL 完全一样,只是 CRL 控制的是低 8 位输出口,而 CRH 控制的是高 8位输出口。
b.两个32位数据寄存器(GPIOx_IDR,GPIOx_ODR)一个是只读作输入数据寄存器,一个是只写作输出寄存器。
端口输入数据寄存器 IDR 各位描述:
要想知道某个 IO 口的状态, 你只要读这个寄存器,再看某个位的状态就可以了。
ODR 是一个端口输出数据寄存器,也只用了低 16 位。该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前 IO 口的输出状态。而向该寄存器写数据,则可以控制某个 IO 口的输出电平。
一个32位置位/复位寄存器(GPIOx_BSRR)。
一个16位复位寄存器(GPIOx_BRR)。
一个32位锁定寄存器(GPIOx_LCKR)。
常用的IO端口寄存器只有四个:CRH,CRL,IDR,ODR。
数据手册中列出的每个I/O端口的特定硬件特征。 GPIO端口的每个位可以由软件分别配置成多种模式。每个I/O端口位可以自由编程,然而I/O端口寄存器必须按32位字被访问(不允许半字或字节访问)。 另外,STM32的每个端口使用前都要将其时钟使能,STM32的GPIO的时钟统一挂接在APB2上,具体的使能寄存器为RCC_APB2ENR,该寄存器的第2位到第8位分别控制GPIOx(x=A,B,C,D,E,F,G)端口的时钟使能,当外设时钟没有启用时,程序不能读出外设寄存器的数值。
(7)GPIO库函数简要解释:
函数名 | 具体功能 |
---|---|
GPIO_DeInit | 重新初始化外围设备GPIOx相关寄存器到它的默认复位值 |
GPIO_AFIODeInit | 初始化交错功能(remap, event control和 EXTI 配置) 寄存器 |
GPIO_Init | 根据GPIO_初始化结构指定的元素初始化外围设备GPIOx |
GPIO_StructInit | 填充GPIO_初始化结构(GPIO_InitStruct)内的元素为复位值 |
GPIO_ReadInputDataBit | 读指定端口引脚输入数据 |
GPIO_ReadInputData | 读指定端口输入数据 |
GPIO_ReadOtputDataBit 读 | 指定端口引脚输出数据 |
GPIO_ReadOtputData | 读指定端口输出数据 |
GPIO_SetBits | 置1指定的端口引脚 |
GPIO_ResetBits | 清0指定的端口引脚 |
GPIO_WriteBit | 设置或清除选择的数据端口引脚 |
GPIO_Write | 写指定数据到GPIOx端口寄存器 |
GPIO_ANAPinConfig | 允许或禁止 GPIO 4 模拟输入模式 |
GPIO_PinLockConfig | 锁定GPIO引脚寄存器 |
GPIO_EventOutputConfig | 选择GPIO引脚作为事件输出 |
GPIO_EventOutputCmd | 允许或禁止事件输出 |
GPIO_PinRemapConfig | 改变指定引脚的映射 |
GPIO_EXTILineConfig | 设置外部中断 |
GPIO_ETH_MediaInterfaceConfig | 配置以太网接口 |
(8)实例学习
①GPIO输出——LED实现:关键部分是实现GPIO的初始化工作,具体实现如下:
#define LED PAout(12) //输出,使用的是位带操作来实现操作某个 IO 口的 1 个位
void led_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PA端口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;//PA.8端口设置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO口的速度为50MHZ
GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化PA
GPIO_SetBits(GPIOA,GPIO_Pin_12);//PA.8输出高
}
在使用PA15引脚的时候,按照正常的 IO 初始化,并且停止使用JTAG,依然不能点亮LED,因为PA15默认JTAG的一个脚,现在要变成普通IO就要使能复用时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);//使能PA端口
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //关闭JTAG口,使PB3,PB4,PA15这几个IO作为普通IO使用
位操作就是可以单独的对一个比特位读和写,这个在51单片机中非常常见。51单片机中通过关键字sbit来实现位定义,STM32F103中没有这样的关键字,而是通过访问位带别名区来实现。
a.通过位带操作 PA12 输出高低电平从而控制 LED 的方法如下:
#define LED PAout(15) //输出
LED=1; //通过位带操作控制 LED 的引脚 PA12 输出高电平
LED=0; //通过位带操作控制 LED 的引脚 PA12 输出低电平
b.使用固件库操作和寄存器操作:
来实现 IO 口操作。 库函数操作方法如下:
GPIO_SetBits(GPIOA, GPIO_Pin_12); //设置 GPIOA12 输出 1,等同 LED=1;
GPIO_ResetBits (GPIOA, GPIO_Pin_12); //设置 GPIOA12 输出 0,等同 LED=0;
库函数操作就直接调用两个函数即可控制 IO 输出高低电平。
c.通过直接操作寄存器:
BRR 和 BSRR 的方式来操作 IO 口输出高低电平,方法如下:
GPIOA->BRR=GPIO_Pin_12; //设置 GPIOA.12 输出 1,等同 LED=1;
GPIOA->BSRR=GPIO_Pin_12; //设置 GPIOA.12 输出 0,等同 LED=0;
② 仿真测试
IO 口复用的,信号在逻辑分析窗口是不能显示出来的(看不到波形),比如串口的输出, SPI, USB, CAN 等。
相关设置如下:
Use Simulator,即使用软件仿真。选择: Run to main(),即跳过汇
编代码,直接跳转到 main 函数开始仿真。
设置下方的: Dialog DLL 分别为: DARMSTM.DLL
和 TARMSTM.DLL,
Parameter 均为: -pSTM32F103RC,用于设置支持 STM32F103RC 的软硬件仿真。如下图:
仿真结果如下:
下载到开发板上,运行结果与仿真的一致。
③ GPIO输入——按键输入
STM32 的 IO 口做输入使用的时候,是通过调用函数
GPIO_ReadInputDataBit() 来读取 IO 口的状态的。
主要实现部分:
void Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能 PORTA 时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;//PA12
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉
GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化PA12
}
void Key_Scan(void)
{
if(KEY == 0)
{
delay_ms(10);
if(KEY == 0)
LED = !LED;
}
}
逻辑分析仪仿真如下:
效果:按下按键实现 LED 亮灭。
欢迎访问:http://wentao1213.com/2017/05/20/STM32-GPIO-LIB/
参考:
1.STM32使用之GPIO
2.STM32学习笔记之GPIO口的使用
3.STM32的GPIO输入输出模式配置
4.原子STM32开发手册—库函数版