datasheet

STM32学习笔记一一GPIO

2019-01-09来源: eefocus关键字:STM32  GPIO

1. GPIO工作方式

STM32 每个 IO 口可以自由编程,但 IO 口寄存器必须要按 32 位字被访问。 本文主要是库函数实现的笔记。相关图片来自正点原子教程。


1.1 4种输入模式

输入浮空 输入上拉 输入下拉 模拟输入


a.输入浮空


这里写图片描述


CPU可以通过输入数据寄存器读出I/O口的高低电平,工作电路如图。


b.上拉下拉输入:添加了上拉、下拉电阻后,CPU再读电平


这里写图片描述


c.模拟输入


这里写图片描述


输入量为模拟量,不再是电平,输入的电压范围:0—3.3V


1.2 4种输出模式

开漏输出 开漏复用功能 推挽式输出 推挽式复用功能


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使用


注:操作 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开发手册—库函数版

关键字:STM32  GPIO

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/2019/ic-news010942863.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32学习笔记一一外部中断
下一篇:STM32学习笔记一一USART

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32堆栈设置

1.堆和栈大小 定义大小在startup_stm32f2xx.sStack_Size      EQU     0x00000400                AREA    STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem      
发表于 2019-04-16
STM32堆栈设置

STM32堆和栈(Heap & Stack)的资料理解

源起:在移植cjson的过程中,解析json包的时候发现动态内存分配不足而导致解析失败,为解决这一问题,而深入了解stm32的堆和栈。stm32的存储器结构。Flash,SRAM寄存器和输入输出端口被组织在同一个4GB的线性地址空间内。可访问的存储器空间被分成8个主要块,每个块为512MB。FLASH存储下载的程序。SRAM是存储运行程序中的数据。而SRAM一般分这几个部分:静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率
发表于 2019-04-16
STM32堆和栈(Heap & Stack)的资料理解

STM32定义堆栈地址到ram区顶部

本设置针对stm32f103rbt6的设置,该芯片RAM大小为20kB,故RAM区地址范围为0x20000000—0x20005000,芯片信息如下图所示;第一步:设置.sct文件;;*************************************************************; *** Scatter-Loading Description Filegenerated by uVision ***; *************************************************************LR_IROM1 0x08000000 0x00020000  
发表于 2019-04-16
STM32定义堆栈地址到ram区顶部

STM32之程序如何防止堆栈溢出

近日为某个项目写了个草稿程序,即非正式程序,后来发现老是进入hardfaulthandler,原来是堆栈溢出,后仔细查看发现函数调用纵深太深,最多的时候可保持7个函数在堆栈中调用。因此有心得如下:一、函数调用不要纵深太深,即以下模式:main(){   fun1();}fun1(){  fun2();}fun2(){   fun3();}fun3(){  fun4();}fun4(){  fun5();}fun5(){  fun6();}fun6(){   fun7();}这样子main函数要调用fun1函数完成某个功能,则要一直调到
发表于 2019-04-16

stm32之堆栈

stm32中的堆栈设置keil编译完成时存储情况当编译成功时,会出现: BUILD://Program Size: Code=340 RO-data=252 RW-data=0 ZI-data=1632Code:程序代码部分RO-data: 程序定义的常量const tempRW-data:已初始化的全局变量ZI-data:未初始化的全局变量片中的:flash=Code+RO-data+RW-dataRAM=RW-data+ZI-data通过上面的BUILD可以看出,这个程序已经用了1600多的RAM,为什么会出用到这么多的RAM呢?在startup_stm32f10x_md.s文件中存在:St
发表于 2019-04-16

说说STM32的堆栈与内存

1.概念这里所说的堆栈,是针对单片机所说的“堆”与“栈”,指的是内存中一片特殊用途的区域。而不是数据结构中的堆栈(虽然其实规则一样)。这里所说的内存,是指RAM,RAM包括SRAM,DRAM等。而不是什么手机内存卡之类。这里所说的flash,指的是用作为ROM的存储器,保存代码与常量数据。而不是动画制作。。。栈的生长方向:指的是入栈方向,从高地址向低地址生长叫做向下生长,或逆向生长;反过来就叫向上生长,或正向生长。STM32的栈是向下生长。2.内存中的堆栈安排确切地说,是keil mdk根据STM32的特性,对stm32的RAM甚至flash进行部署。编译工程后,在生成的.map文件里可以看到具体的安排。双击工程界面的工程根目录
发表于 2019-04-16
说说STM32的堆栈与内存

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved