购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

任务3.1 使用GPIO接口实现流水灯

GPIO结构

3.1.1 GPIO接口的工作模式

GPIO接口是通用型输入/输出(General-Purpose Input/Output)接口的简称,其功能类似于8051单片机的P0~P3接口。GPIO接口可以由开发者通过软件控制,GPIO接口对应的引脚可以作为通用输入(GPI)、通用输出(GPO)或通用输入输出(GPIO)等接口。对于通用输入接口,可以通过读取某个寄存器来确定引脚电平的高低;对于通用输出接口,可通过写入某个寄存器来让这个引脚输出高电平或者低电平;对于其他特殊功能,则由另外的寄存器来控制GPIO接口。

每个GPIO接口都有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)。

GPIO接口的主要特性如下:

➲ 受控的GPIO接口多达16个。

➲ 输出状态包括推挽输出或开漏输出+上拉或下拉。

➲ 从输出数据寄存器(GPIOx_ODR)或外设(复用功能输出)输出数据。

➲ 可为每个GPIO接口设置不同的速度(或频率)。

➲ 输入状态包括悬空、上拉或下拉、模拟。

➲ 可将数据输入到输入数据寄存器(GPIOx_IDR)或外设(复用功能输入)。

➲ 置位/复位寄存器(GPIOx_BSRR)具有对GPIOx_ODR进行按位写的权限。

➲ 锁定寄存器(GPIOx_LCKR)可以冻结GPIO接口的配置。

➲ 具有模拟功能。

➲ 通过复用功能寄存器,每个GPIO接口最多可具有16个复用功能。

➲ GPIO接口可快速翻转,每次翻转最快只需要2个时钟周期。

➲ 引脚的复用非常灵活,允许引脚当成GPIO接口或多种外设功能中的一种。

GPIO接口的工作模式如图3-1所示。

图3-1 GPIO接口的工作模式(引自ST公司的官方参考手册)

通过软件可以将微控制器STM32F407的GPIO接口设置为以下模式:

➲ 输入悬空。

➲ 输入上拉。

➲ 输入下拉。

➲ 模拟功能。

➲ 具有上拉或下拉功能的开漏输出。

➲ 具有上拉或下拉功能的推挽输出。

➲ 具有上拉或下拉功能的复用功能(推挽输出)。

➲ 具有上拉或下拉功能的复用功能(开漏输出)。

每个GPIO接口位(Port Bit)均可自由编程设置,但GPIO接口的寄存器必须按32位字、半字或字节进行访问。GPIOx_BSRR旨在对GPIO_ODR进行原子读取/修改访问,这样可确保在读取和修改之间发生中断请求也不会有问题。

推挽输出(Push-Pull Output):是指两个参数相同的功率晶体管或金属氧化物半导体场效应晶体管(Metal-Oxide-Semiconductor Field Effect Transistor,MOSFET),以推挽的方式存在于电路中。因为元件受到两个互补信号的制约,总会保持一个导通状态、另一个截止的状态。推拉输出既可以提高电路的负载能力,又可以提高开关速度。

开漏输出:输出端相当于晶体管的集电极,要得到高电平状态需要上拉电阻才行,适合作为电流型的驱动,其吸收电流的能力相对强(一般为20 mA内)。开漏输出可以利用外部电路的驱动能力来减少IC内部的驱动。一般来说,开漏是用来连接不同电平元件、匹配电平用的,因为在开漏引脚没有连接外部的上拉电阻时,只能输出低电平。如果需要引脚同时具备输出高电平的功能,则需要连接上拉电阻。开漏输出的一个优点是可以通过改变上拉电阻的电压来改变传输电平。例如,在连接上拉电阻时,可以提供TTL/CMOS电平输出。上拉电阻的阻值决定了逻辑电平转换时沿的速度。阻值越大,速度越低、功耗越小,所以上拉电阻的选择要兼顾功耗和速度。

在微控制器STM32F407复位期间及复位刚刚完成时,复用功能尚未激活,GPIO接口被配置为输入悬空模式。复位后,调试引脚处于复用功能上拉/下拉模式。

➲ PA15:JTDI处于上拉模式。

➲ PA14:JTCK、SWCLK处于下拉模式。

➲ PA13:JTMS、SWDAT处于下拉模式。

➲ PB4:NJTRST处于上拉模式。

➲ PB3:JTDO处于悬空模式。

当引脚配置为输出时,写入到输出数据寄存器(GPIOx_ODR)的值将由GPIO接口输出。用户可以在推挽输出模式或开漏输出模式下使用输出驱动器(输出0时仅激活N-MOS)。

输入数据寄存器(GPIOx_IDR)每隔1个AHB1时钟周期捕获一次GPIO接口上的数据。

所有的GPIO接口都具有内部弱上拉及下拉电阻,可根据GPIOx_PUPDR的值来打开/关闭GPIO接口。

微控制器STM32F407的GPIO接口通过一个复用器连接到板载外设/模块,该复用器一次仅允许一个外设的复用功能(AF)连接到GPIO接口。这可以确保使用同一个GPIO接口的外设之间不会发生冲突。

每个GPIO接口都有一个复用器,该复用器采用16路复用功能输入(AF0~AF15),可通过GPIOx_AFRL(针对引脚0到7)和GPIOx_AFRH(针对引脚8到15)寄存器对这些输入进行配置。微控制器STM32F407复用功能的选择如图3-2所示。

➲ 微控制器STM32F407完成复位后,所有GPIO接口都会连接到系统的复用功能0(AF0)。

➲ 外设的复用功能会映射到AF1~AF13。

➲ Cortex-M4F内核的FEVENTOUT会映射到AF15。

图3-2 微控制器STM32F407复用功能的选择(引自ST公司的官方参考手册)

1.GPIO接口的输入模式

GPIO接口的输入模式如图3-3所示。通过编程将GPIO接口作为输入时,输出缓冲器被关闭、TTL施密特触发器的输入被打开。根据GPIOx_PUPDR中的值决定是否打开上拉模式和下拉模式,输入数据寄存器每隔1个AHB1时钟周期对GPIO接口上的数据进行一次采集,对输入数据寄存器的读访问可获取GPIO接口的状态。

在悬空模式下,GPIO接口的电平状态是不确定的,完全由外部输入决定。如果GPIO接口是悬空的,则读取该接口的电平是不确定的。

上拉模式就是将不确定的信号通过一个电阻钳位在高电平,电阻同时起限流作用。弱上拉和强上拉只是上拉电阻的阻值不同,没有特别严格的区分。

下拉模式就是将不确定的信号通过一个电阻钳位在低电平,电阻同时起限流作用。弱下拉和强下拉只是下拉电阻的阻值不同,没有特别严格的区分。

图3-3 GPIO接口的输入模式(引自ST公司的官方参考手册)

2.GPIO接口的模拟模式

GPIO接口的模拟模式如图3-4所示。通过编程将GPIO接口作为模拟输入时,输出缓冲器被禁止,TTL施密特触发器的输入被关闭,GPIO接口的模拟输入的功耗变为零,TTL施密特触发器的输出被强制设置为恒定值(0),上拉和下拉电阻被关闭,读取输入数据寄存器的结果为0。

图3-4 GPIO接口的模拟模式(引自ST公司的官方参考手册)

3.GPIO接口的输出模式

GPIO接口的输出模式如图3-5所示。通过编程将GPIO接口作为模拟输出时,输出缓冲器被打开,TTL施密特触发器的输入被打开。若在开漏输出模式下,则输出寄存器中的0可激活N-MOS,输出寄存器中的1会使GPIO接口保持高组态(HiZ,即P-MOS始终不激活)。若在推挽输出模式下,则输出寄存器中的0可激活N-MOS,而输出寄存器中的1可激活P-MOS。根据GPIOx_PUPDR中的值决定是否打开上拉电阻和下拉电阻,输入数据寄存器每隔1个AHB1时钟周期对GPIO接口上的数据进行一次采集,对输入数据寄存器的读访问可获取GPIO接口的状态,对输出数据寄存器的读访问可获取最后写入的值。

图3-5 GPIO接口的输出模式(引自ST公司的官方参考手册)

GPIO接口的输出经过两个保护二极管后,向上流向“输入模式”结构,向下流向“输出模式”结构。先看“输出模式”结构,GPIO接口的输出经过一个由P-MOS和N-MOS场效应管组成的单元电路,这个单元电路使GPIO接口具有推挽输出和开漏输出两种模式。

(1)推挽输出模式。推挽是指两个参数相同的晶体管或MOS场效应管以推挽的方式存在于电路中,各负责正负半周的波形放大任务。当电路工作时,两只对称的晶体管或MOS场效应管每次只有一个导通,所以导通损耗小、效率高。推挽输出既可以向负载灌电流,也可以从负载抽电流。推拉输出既可以提高电路的负载能力,也可以提高开关速度。推挽输出模式如图3-6所示。

图3-6 推挽输出模式(引自ST公司的官方参考手册)

所谓的推挽输出模式,是根据两个MOS场效应管的工作方式来命名的。在两个MOS场效应管组成的单元电路中输入高电平时,经过反向后,上方的P-MOS导通,下方的N-MOS截止,对外输出高电平;而在该单元电路中输入低电平时,经过反向后,N-MOS导通,P-MOS截止,对外输出低电平。当GPIO接口切换高低电平时,P-MOS和N-MOS轮流导通,P-MOS负责灌电流,N-MOS负责抽电流,使其负载能力和开关速度都有了很大的提高。推挽输出的低电平为0 V,高电平为3.3 V。

(2)开漏输出。开漏输出模式如图3-7所示。在开漏输出模式下,P-MOS完全不工作。如果要使输出为0(低电平),则P-MOS截止、N-MOS导通,使输出接地;若使输出为1(它无法直接输出高电平)时,则P-MOS和N-MOS都关闭,所以GPIO接口既不输出高电平,也不输出低电平,为高阻态。为了正常使用,必须外接上拉电阻。上拉电阻具有“线与”功能,也就是说,若有很多开漏输出模式的引脚连接到一起,则只有当所有引脚都输出高阻态时,才由上拉电阻提供高电平,此高电平的电压值为外部上拉电阻所接的电源电压;若其中一个引脚为低电平,就相当于短路接地,使得所有引脚的输出都是低电平,即0V。

推挽输出模式通常用在输出电平为0 V和3.3 V,且需要进行高速切换开关状态的场合。在STM32系列微控制器中,除了必须用开漏输出模式的场合,均建议使用推挽输出模式。开漏输出模式一般应用在I2C总线、SMBus(系统管理总线)等需要“线与”功能场合,以及电平不匹配的场合。例如,若需要输出5V的高电平,就可以外接一个上拉电阻,令电源电压为5 V,并且把GPIO接口设置为开漏输出模式,当输出为高阻态时,由上拉电阻和电源向外输出5V的高电平。

图3-7 开漏输出模式(引自ST公司的官方参考手册)

4.GPIO接口的复用模式

GPIO接口的复用模式如图3-8所示。通过编程使GPIO接口实现复用功能时,可将输出缓冲器配置为开漏输出模式或推挽模式,输出缓冲器由来自外设的信号驱动(发送器使能和数据),TTL施密特触发器的输入被打开。根据GPIOx_PUPDR中的值决定是否打开上拉和下拉,输入数据寄存器每隔1个AHB1时钟周期对GPIO接口上的数据进行一次采样,对输入数据寄存器的读访问可获取GPIO接口的状态。

图3-8 GPIO接口的复用模式(引自ST公司的官方参考手册)

3.1.2 STM32F407ZGT6的时钟系统

时钟树

STM32F407ZGT6的时钟树如图3-9所示。

图3-9 时钟树(引自ST公司的官方参考手册)

STM32F407ZGT6可以使用三种不同的时钟作为系统时钟(SYSCLK):

➲ HSI时钟。

➲ HSE时钟。

➲ 主PLL时钟。

STM32F407ZGT6还具有以下两个次级时钟源:

➲ 32 kHz的低速内部RC振荡器(LSIRC),用于驱动独立的看门狗电路,也可以作为实时时钟(Real Time Clock,RTC)将微控制器从停机/待机模式中自动唤醒。

➲ 32.768 kHz的低速外部晶振(LSE晶振),作为RTC。

对于每个时钟源来说,在未使用时都可单独打开或者关闭,以降低功耗。复位与时钟控制器(Reset Clock Controller,RCC)为应用带来了高度的灵活性,读者在运行内核和外设时可选择使用外部晶振或者使用RC振荡器,既可采用最高的频率,也可为以太网、USB OTG FS、USB OTG HS、I2S和SDIO等需要特定时钟的外设提供合适的频率。

STM32F407ZGT6通过多个预分频器可配置AHB、高速APB(APB2)和低速APB(APB1)的频率。AHB的最大频率为168 MHz,APB2的最大频率为84 MHz,APB1的最大频率为42 MHz。

除了以下时钟,所有的外设时钟均由系统时钟(SYSCLK)提供:

➲ 来自特定PLL输出(PLL48CLK)的USB OTG FS时钟(48 MHz)、基于模拟技术的随机数发生器(RNG)时钟(48 MHz)和SDIO时钟(48 MHz)。

➲ I2S时钟。要实现高品质的音频性能,可通过特定的PLL(PLLI2S)或映射到I2S_CKIN引脚的外部时钟提供I2S时钟。

➲ 由外部PHY提供的USB OTG HS(60 MHz)时钟

➲ 由外部PHY提供的以太网MAC时钟(TX、RX和RMII)。当使用以太网时,AHB时钟频率至少为25 MHz。RCC可以向Cortex内核的系统定时器(SysTick)馈送8分频的AHB时钟(HCLK)。SysTick既可以使用此时钟作为时钟源,也可使用HCLK作为时钟源,具体可在SysTick控制和状态寄存器中配置。

STM32F405xx/07xx微控制器和STM32F415xx/17xx微控制器的定时器时钟频率由硬件自动设置,分为两种情况:如果APB预分频器为1,则定时器时钟频率等于APB的频率;否则等于APB的频率的2倍。

1.HSE时钟

高速外部(HSE)时钟有2个时钟源:晶振/陶瓷谐振器和外部时钟。谐振器和负载电容必须尽可能靠近振荡器的引脚,以尽量减小输出失真和起振稳定时间。负载电容必须根据所选振荡器的不同进行适当的调整。HSE时钟的硬件配置如图3-10所示。

图3-10 HSE时钟的硬件配置(引自ST公司的官方参考手册)

外部时钟(HSE旁路):在此模式下,必须提供外部时钟源。外部时钟源必须使用占空比约为50%的外部时钟信号(方波、正弦波或三角波信号)来驱动OSC_IN引脚,同时OSC_OUT引脚应保持为高阻态(HiZ)。

晶振/陶瓷谐振器(HSE晶振):HSE的特点是精度非常高,RCC的时钟控制寄存器(RCC_CR)中的HSERDY位用于表示高速外部振荡器是否稳定。在启动HSE晶振时,硬件将此位置1后,才可以使用HSE晶振。通过RCC_CR中的HSEON位可以打开或关闭HSE晶振。

2.HSI时钟

HSI时钟由16 MHz的内部RC振荡器生成,可直接作为系统时钟或PLL的输入。HSI时钟的优点是成本较低(无须使用外部组件)。此外,HSI时钟的启动速度要比HSE晶振快。但即使在校准HSI时钟后,其精度也不及HSE晶振。如果器件受到电压或温度变化的影响,则可能会影响到HSI时钟的速度。

3.PLL配置

STM32F4xx微控制器具有两个PLL:

主PLL:由HSE晶振或HIS时钟提供时钟信号,并具有两个不同的输出时钟:第一个输出时钟用于生成高速系统时钟(最高可达168 MHz);第二个输出时钟用于生成USB OTG FS的时钟(48 MHz)、随机数发生器的时钟(48 MHz)和SDIO时钟(48 MHz)。

专用PLL(PLLI2S):用于生成精确时钟,从而在I2S接口实现高品质音频性能。

由于在PLL使能后主PLL的配置参数便不可再更改,因此建议先对主PLL进行配置,再使能(选择HIS时钟或HSE晶振作为PLL的时钟源,并配置分频系数 M N P Q )。

PLLI2S使用与主PLL相同的输入时钟(PLLM[5:0]和PLLSRC位被两个PLL共用),但PLLI2S具有专门的使能/禁止和分频系数( N R )配置位。在使能PLLI2S后,其配置参数便不能再更改。

当进入微控制器停机和待机模式后,两个PLL将由硬件禁止。如果将HSE晶振或PLL(由HSE晶振提供时钟信号)作为系统时钟,则在HSE晶振发生故障时,两个PLL也将由硬件禁止。RCC PLL配置寄存器(RCC_PLLCFGR)和RCC时钟配置寄存器(RCC_CFGR)可分别用于配置主PLL和PLLI2S。

4.LSE时钟

LSE晶振是32.768 kHz的低速外部(LSE)晶振或陶瓷谐振器,可作为实时时钟(RTC)来提供时钟/日历或其他定时功能,具有功耗低且精度高的优点。LSE晶振通过RCC备份域控制寄存器(RCC_BDCR)中的LSEON位打开和关闭。RCC_BDCR中的LSERDY位表示LSE晶振是否稳定。在启动时,硬件将此位置1后,LSE晶振输出时钟信号才可以使用。

5.LSI时钟

LSIRC的时钟频率为32 kHz,可作为低功耗时钟源在停机和待机模式下保持运行,供独立看门狗(IWDG)和自动唤醒单元(AWU)使用。

通过RCC时钟控制和状态寄存器(RCC_CSR)中的LSION位可打开或关闭LSIRC。微控制器将LSION位置1后(该位可通过软件置1或清0),LSIRC才可以使用。RCC_CSR中的LSIRDY位表示低速内部振荡器是否稳定。

6.系统时钟(SYSCLK)选择

在微控制器复位后,默认的系统时钟为HIS时钟。在直接使用HIS时钟或通过PLL使用HIS时钟作为系统时钟时,HIS时钟无法停止。

只有在目标时钟就绪时(时钟在启动延迟或PLL锁相后稳定时),才可以从一个时钟切换到另一个时钟。如果选择尚未就绪的时钟,则只有在该时钟就绪时才能进行切换。RCC_CR中的状态位指示哪个时钟已就绪,以及当前哪个时钟正充当系统时钟。

7.时钟安全系统(CSS)

时钟安全系统(Clock Security System,CSS)可通过软件激活。当CSS被激活后,时钟监测器(Clock Detector)将在HSE时钟启动后延迟一段时间才能被使能,并在此HSE时钟停止后关闭。

如果HSE时钟发生故障,则CSS将自动禁止,一个时钟故障事件将发送到高级控制定时器TIM1和TIM8的中断输入,并同时生成一个中断来向软件系统通知该故障(时钟安全系统中断,CSSI),以便微控制器能够执行相关的操作(如抢救操作)。CSSI与Cortex-M4F的NMI(不可屏蔽中断)异常向量相链接。

8.RTC/AWU时钟

一旦选定RTC的时钟源后,要想修改所选择的时钟源,就只能复位电源。

RTC的时钟源可以是1 MHz的HSE(HSE可以被一个可编程的预分频器分频)、LSE或者LSI时钟。选择时钟源的方式是通过编程设置RCC备份域控制寄存器(RCC_BDCR)中的RTCSEL[1:0]位和RCC时钟配置寄存器(RCC_CFGR)中的RTCPRE[4:0]位,所选择的时钟源只能通过复位备份域的方式来进行修改。

如果LSE时钟作为RTC,则系统掉电后RTC将正常工作。如果选择LSI时钟作为AWU时钟,则系统掉电后将无法保证AWU的状态。如果HSE时钟通过一个介于2和31之间的值进行分频,则在备用或系统电源掉电后将无法保证RTC的状态。

LSE时钟位于备份域(Backup Domain)中,而HSE时钟和LSI时钟则不是。因此:

(1)如果选择LSE时钟作为RTC,则只要V BAT 保持工作,即使V DD 关闭,RTC仍可继续工作。

(2)如果选择LSI时钟作为AWU的时钟,则在V DD 掉电时,将不能保证AWU的状态。

(3)如果使用HSE时钟作为RTC,则在V DD 掉电或者内部调压器关闭(切断1.2 V的供电),将不能保证RTC的状态。

9.独立看门狗时钟

如果独立看门狗(IWDG)已通过硬件选项字节或软件设置的方式启动,则LSI振荡器(LSIRC)将被强制打开且不可禁止。在LSIRC稳定后,将向IWDG提供LSI时钟。

10.时钟输出功能

STM32F407ZGT6共有两个微控制器时钟输出(Microcontroller Clock Output,MCO)引脚:

(1)MCO1。用户通过可配置的预分配器(从1到5)可以向MCO1引脚(PA8)输出4个不同的时钟,即HSI时钟、LSE时钟、HSE时钟、PLL时钟。

通过RCC时钟配置寄存器(RCC_CFGR)中的MCO1PRE[2:0]和MCO1[1:0]位可以选择所需的时钟。

(2)MCO2。用户通过可配置的预分配器(从1到5)可以向MCO2引脚(PC9)输出4个不同的时钟,即HSE时钟、PLL时钟、系统时钟(SYSCLK)、PLLI2S。

通过RCC时钟配置寄存器(RCC_CFGR)中的MCO2PRE[2:0]和MCO2[1:0]位可以选择所需的时钟。

对于不同的MCO引脚,必须在相应的GPIO接口处于复用功能模式下才能进行设置。MCO的输出时钟不得超过100 MHz(最大I/O速度)。

3.1.3 GPIO接口的结构体及库函数

stm32f4xx_gpio.h定义了与GPIO接口寄存器相关的结构体,stm32f4xx_gpio.c定义了相关的标准固件库函数。标准固件库函数的目的是通过操作结构体来操作GPIO接口寄存器。

在标准固件库中,通过4个配置寄存器可初始化GPIO接口,初始化工作是通过GPIO接口的初始化函数完成的。

1.void GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct)

该函数有两个输入参数:

输入参数1是GPIOx,其中的x可以是A、B、C、D或E,用来选择GPIO接口。

输入参数2是GPIO_InitStruct,该参数是指向结构体GPIO_InitTypeDef的指针,该结构体包含了GPIO接口的配置信息。

结构体GPIO_InitTypeDef定义在stm32f4xx_gpio.h中,其内容如下:

(1)GPIO_Pin:用于选择待设置的GPIO接口,如PA2或PA4。通过操作符“|”可以一次选中多个GPIO接口。GPIO_Pin的取值及含义如表3-1所示。

表3-1 GPIO_Pin的取值及含义

(2)GPIO_Mode:用于设置选中GPIO接口的工作状态。GPIO_Mode的取值及含义如表3-2所示。

表3-2 GPIO_Mode的取值及含义

(3)GPIO_Speed:用于设置选中GPIO接口的频率。GPIO_Speed的取值及含义如表3-3所示。

表3-3 GPIO_Speed的取值及含义

(4)GPIO_OType:用于设置选中GPIO接口的输出类型。GPIO_OType的取值及含义如表3-4所示。

表3-4 GPIO_OType的取值及含义

(5)GPIO_PuPd:用于设置GPIO接口的上拉或下拉。GPIO_PuPd的取值及含义如表3-5所示。

表3-5 GPIO_OType的取值及含义

这里以点亮LED(见任务2.3)的代码为例介绍结构体GPIO_InitTypeDef的成员,代码如下:

从上述代码可以看出,要对GPIO接口进行设置,需要先通过①定义一个结构体,结构体的名字为GPIO_InitStruct,然后通过②开启GPIO接口的时钟,再通过③、④、⑤、⑥、⑦对结构体的成员进行设置,最后通过⑧完成GPIO接口的初始化。

其中③、④、⑤、⑥、⑦通过在结构体名称GPIO_InitStruct后面加“.”来调用其中的各个成员。例如,GPIO_InitStruct.GPIO_Pin,然后给该成员赋值GPIO_Pin_0,这表示选择了Pin_0这个接口。如果需要选择别的GPIO接口,则可以对GPIO_Pin这个值进行修改,使用“|”可以连接多个值,直接对GPIO_Pin赋值GPIO_Pin_All可以选择所有的GPIO接口。

④通过将GPIO_Mode的值设置为GPIO_Mode_OUT,表示点亮LED的任务需要将GPIO接口设置为输出模式;如果使用按键,就要将GPIO接口设置为输入模式。

⑤将GPIO_Speed的值设置为GPIO_Speed_100MHz(高速模式)。GPIO_Speed的取值有4种,用户可以根据GPIO接口驱动不同外设的速率而选择相应的GPIO_Speed。

⑥将GPIO_OType的值设置为GPIO_OType_PP。GPIO_OType的取值有两个,一个是GPIO_OType_PP,表示推挽输出,可以输出强高电平和强低电平,在点亮LED任务中选择GPIO_OType_PP;另一个是GPIO_OType_OD,表示开漏输出,如果选择这个值,则需要上拉电阻才能输出高电平。

GPIO_PuPd的取值有3个,⑦将GPIO_PuPd设置为GPIO_PuPd_NOPULL,表示悬空。

语句“GPIO_Init(GPIOA,&GPIO_InitStruct);”是必不可少的,该语句通过标准固件库的初始化函数将③、④、⑤、⑥、⑦设置的参数写入标准化固件库的结构体中。

2.void GPIO_PinLockConfig(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)

功能描述:锁定GPIO接口的设置寄存器。

输入参数1是GPIOx,其中的x可以是A、B、C、D或E…,用来选择GPIO接口。

输入参数2是GPIO_Pin,表示待锁定的接口位。该参数可以取GPIO_Pin_x(x是0~15)的任意组合。

例如,通过下面的代码可以锁定GPIOA的Pin0和Pin1。

3.uint16_t GPIO_ReadInputData(GPIO_TypeDef*GPIOx)

功能描述:读取指定GPIO接口的输入。

输入参数是GPIOx,其中的x可以是A、B、C、D或E…,用来选择GPIO接口。

返回值是GPIO接口输入的数据。

例如,通过下面的代码可以读取GPIOC的输入数据并把它存储到ReadValue变量中。

4.uint16_t GPIO_ReadOutputData(GPIO_TypeDef*GPIOx)

功能描述:读取指定的GPIO接口的输出。

输入参数是GPIOx,其中的x可以是A、B、C、D或E…,用来选择GPIO接口。

返回值是GPIO接口输出的数据。

例如,通过下面的代码可以读取GPIOC的输出数据并把它存储到ReadValue变量中。

5.void GPIO_SetBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)

功能描述:设置指定的GPIO接口数据。

输入参数1是GPIOx,其中的x可以是A、B、C、D或E…,用来选择GPIO接口。

输入参数2是GPIO_Pin,表示待设置的接口位。该参数可以取GPIO_Pin_x(x是0~15)的任意组合。

例如,通过下面的代码可以将GPIOA的Pin10和Pin15置1。

6.void GPIO_ResetBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)

功能描述:清除指定的GPIO接口数据。

输入参数1是GPIOx,其中的x可以是A、B、C、D或E…,用来选择GPIO接口。

输入参数2是GPIO_Pin,表示待清0的接口位。该参数可以取GPIO_Pin_x(x是0~15)的任意组合。

例如,通过下面的代码可以将GPIOA的Pin10和Pin15清0。

7.void GPIO_WriteBit(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin,BitAction BitVal)

功能描述:设置或者清除指定的GPIO接口数据。

输入参数1是GPIOx,其中的x可以是A、B、C、D或E…,用来选择GPIO接口。

输入参数2是GPIO_Pin,表示待设置或清0的接口位。该参数可以取GPIO_Pin_x(x是0~15)的任意组合。

输入参数3是BitVal,用于指定待写入的值,该参数必须取枚举BitAction的一个值,其中Bit_RESET表示将接口位清0,Bit_SET表示将接口位置1。

例如,通过下面的代码可以将GPIOA的Pin15置1。

8.void GPIO_Write(GPIO_TypeDef*GPIOx,uint16_t PortVal)

功能描述:向指定GPIO接口写入数据。

输入参数1是GPIOx,其中的x可以是A、B、C、D或E…,用来选择GPIO接口。

输入参数2是PortVal,待写入接口数据寄存器的值。

例如,通过下面的代码可以向GPIOA写入数据0x1101。

3.1.4 流水灯的软硬件设计

在学习的GPIO接口的结构体和标准固件库函数的基础上,本节完成流水灯任务。很多工程师都会称流水灯为跑马灯。

1.任务描述

流水灯

通过GPIO接口实现流水灯。

2.硬件设计

本书使用的开发板有8个LED,标号为D1~D8,通过杜邦线连接8个LED的引脚和GPIO接口。流水灯的硬件设计如图3-11所示,这里把D1~D8分别连接到了微控制器的PA0~PA7引脚。

图3-11 流水灯的硬件设计

3.软件设计

流水灯实验

流水灯的软件设计步骤如下:

步骤1:开启GPIOA的时钟,代码如下:

步骤2:初始化GPIOA,代码如下:

步骤3:设置GPIOA,即设置GPIO接口的Pin0~Pin7的高/低电平。通过标准固件库里的函数:

可以直接给GPIOA的接口位赋值。

下面的代码是使用多文件编程来实现的。我们在微控制器的开发中要养成一个好习惯,即通过不同的源文件实现不同的功能。下面代码中的主函数主要调用LED的初始化函数进行各个参数的设置,通过设置GPIOA接口位的高/低电平来实现流水灯。其中的LED初始化函数led_Init()是在led.c中完成的,在main.c中通过“#include "led.h"”即可包含led.c中新建的源函数;实现流水灯的延时函数是在delay.c中完成的,在main.c中通过“#include"delay.h"”即可包含delay.c中定义的源函数。

实例代码如下:

运行上面的代码时,我们会发现延时函数就是空循环,代码如下:

编译上面的代码,当编译没有警告和错误时将编译后的程序下载到开发板。这时启动开发板可以发现其上的8个LED依次亮灭,实现了流水灯。 paEEhE44UuanZkroX/sJUTT+Nfv/dQydHOOE0kfiPoq/V+xDUGFATuz600/CrtpT

点击中间区域
呼出菜单
上一章
目录
下一章
×