STM32单片机入门之GPIO

(图源均来自与B站UP江协科大)

框图架构讲解 

        GPIO通俗理解就是单片机的输入输出口,51单片机称为IO口,而STM32称为GPIO口,单片机与外部电路信息交汇就是靠这个GPIO口来实现的,可见,GPIO是STM32单片机很重要的一个组成模块,单片机可以通过寄存器来读取或者写入GPIO口的电平信息,再通过内部驱动器来给GPIO口输出高低电平。大致框图如下。79ec530df50a4e9094731e62c68cc6b3.jpg

 

在STM32中,GPIO共有(A~G)个部分,即GPIOA,GPIOB……而GPIPA又有16个引脚,分别是Pin0,Pin1………

这与51单片机是类似的,IO寄存器分为P0,P1……P0又有8个引脚,P0.0,P0.1……

 


 

        这里插入一个小知识。

        在学习过程中,我认为STM32单片机与51单片机最大的一个区别就是时钟开启部分,在使用51单片机时,如果想要使用某个IO口,就直接对相应寄存器操作就行了,但是STM32就不一样,你要想使用这个GPIO口,就得先开启对应GPIO的时钟,就像是唤醒这个模块一样。如果你不开启这个时钟,那么就算你操作了对应的寄存器,单片机也是不会让你使用这个GPIO模块的,这里后面写代码的时候我再详细介绍。


        继续介绍GPIO,GPIO可以被设置成8种模式,分别是浮空输入,上拉输入,下拉输入,模拟输入,开漏输出,推挽输出,复用开漏输出,复用推挽输出。下面我将搭配电路图详细介绍这些模式的工作原理以及应用场景。


        其中,浮空输入,上拉输入,下拉输入模式都是把GPIO口当做一个输入口来使用的,也就是说,单片机要从这个端口来接受数字信号的,这个数字信号在经过肖特基触发器整形后,得到一个模拟电压波形,再存储到输入数据寄存器中。逻辑框图走线如下图。

        注意:引脚这里的保护二极管起到一个保护的作用,如果引脚的电压值高于3.3V(单片机能容忍的最大工作电压,部分特殊引脚是5V,要另外讨论),那么上方的保护二极管就会打开,是多余的电压流入到VDD中,如果引脚的电压值小于VSS,那么下方的保护二极管就会打开,引脚就会从VSS汲取电压。

a6221029141c42e48163e4e35038e4fe.jpg

 那么这三种输入模式的具体区别在哪里呢?

        1:浮空输入,当GPIO口模式设置为浮空输入,图中框出来的电阻都是断开的,也就是说,引脚电平处于不确定的状态。

7f7a45176a3943cea98883f7bc022ae9.jpg

         2:上拉输入,当GPIO口模式设置为上拉输入,图中框出来的电阻开关闭合的,此时,GPIO口默认电平就会被VDD拉高,也就是说,引脚默认电平处高电平的状态。2ff40e9925fa483199e08e38583d8a32.jpg

         3:下拉输入,当GPIO口模式设置为下拉输入,图中框出来的电阻开关闭合的,此时,GPIO口默认电平就会被VSS拉低,也就是说,引脚默认电平处低电平的状态。

b0f12db0c6284cea909e5f63f30b5e88.jpg

 


         还有一种输入模式是模拟输入模式,这种模式主要是采集外设的电压信息的,当GPIO口设置了模拟输入的模式后,引脚的数字信号就不会经过肖特基触发器了,而是直接接到STM32的ADC外设模块部分,由ADC对采集到的数字信息进一部处理,随后得到电压值。框图走线如下图。

9227adcaf1034900919521b830b31146.jpg

 


        介绍完了四种输入模式,还有四种输出模式。也就是由单片机内部产生一个信号,输出到外部电路中。

        1:推挽输出,当模式为推挽输出时,由输出寄存器将数字信号引到GPIO口,此时P-MOS与N-MOS这两个MOS管均有效,当给寄存器写1时,上方的P-MOS打开,下方的N-MOS关闭,此时为高电平,并且驱动能力很强。当给寄存器写0时,上方的P-MOS关闭,下方的N-MOS打开,此时为低电平,驱动能力也很强。这个模式的特性就是高低电平均具有很强的驱动能力。(不过大部分的单片机都是高电平无驱动能力,低电平有很强的驱动能力,可以避免高低电平打架问题)

57f9cb5acd13407c9447d6f0e9ee07d3.jpg

 

        2:复用推挽输出,这种模式下,主要是单片机内部的其它模块(例如定时器模块)生成一个信号,引到GPIO口,其它部分与推挽输出模式是一样的。当我们要利用单片机输出一段PWM波到GPIO口时,我们就需要将此GPIO口设置为复用推挽输出模式。框图走线如下图。

d82c9b1d61d340fa9c0de38d8cbc0dda.jpg

         3:开漏输出,这种模式的P-MOS是无效的,可以理解为不可以用。而N-MOS是有效的,当我们给寄存器写1时,N-MOS关闭,此时GPIO口为高电平,但是也是一个高阻态的状态,也就是说,没有驱动能力。(可以形象地理解为不能输出电流)  我们给寄存器写0时,N-MOS打开,此时GPIO口电压被VSS拉低,为低电平,但是此时驱动能力很强,总结来说,开漏模式就是高电平无驱动能力,低电平有驱动能力。

        4:复用开漏输出模式,这种模式与开漏模式差不多,只是信号产生源变成了片上外设而已。


代码实现

点亮LED灯

        以上就是GPIO口的大致介绍,那么用代码如何实现利用GPIO来点亮一个LED灯呢?

        作为点灯大师,当然是要从点亮一个LED灯开始啦!我们就使用GPIOA的PA0引脚为例子,来实现点灯的功能吧!

        上面我也提到过,要用某个模块,我们就要先开启这个模块的时钟。我们可以使用STM公司封装好的函数来实现对寄存器的操作,进而开启时钟。这里用到的函数就是

 

RCC_APB2PeriphClockCmd(APB2PeriphClock_GPIOA,ENABLE);

 

        现在我们对这个函数来具体解释一下,首先因为GPIO模块是连接APB2这个总线的,所以这里函数是APB2而不是APB1,这个函数的形参有两个,第一个你要使能的具体模块也就是GPIOA,第二个参数是ENABLE,也就是使能(开启)的意思。

        开启了GPIOA的时钟后,我们要对这个模块进行初始化,这里STM帮我们用结构体封装了起来,结构体类型名为GPIO_InitTypeDeF,变量名为了规范我们就设置为GPIO_InitStructure吧,所以这里我们先声明一个结构体变量,然后再对这个结构体变量赋初始值。这个结构体一共有三个成员,Mode,Pin,Speed,Mode可以设置成以上我介绍过的八种模式,那么这里我们采用推挽输出高电平点亮的方案。Pin为引脚号,可以是0—15引脚,这里我们就采用PA0引脚吧,Speed为电平输出信号的翻转速度,是为了低功耗稳定性设置的,一般情况就设置为50MHz就好啦!最后利用GPIO_Init(GPIOA,&GPIO_InitStructure)就可以了。到这里呢,我们的开启时钟工作才算是结束。

 

GPIO_InitTyPeDeF GPIO_InitStructure;

GPIO_InitStructure.Mode=GPIO_Mode_Out_PP ;

GPIO_InitStructure.Pin=GPIO_Pin_0 ;

GPIO_InitStructure.Speed=GPIO_Speed_50MHz ;

GPIO_Init(GPIOA,&GPIO_InitStructure);

 

        开启完时钟后,我们就可以使用GPIOA的PA0引脚了,这里要对这个引脚置高电平(Set),有多个函数可以选择,GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_Set);GPIO_SetBits(GPIOA,GPIO_Pin_0);这里选择哪一个都可以。

那么完整的代码就是

#include "stm32f10x.h"


int main(void)
{
    RCC_APB2PeriPhClock(APB2PeriPh_GPIOA,ENABLE);//开启时钟
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//PA0引脚
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//50MHz

    GPIO_Init(GPIOA,&GPIO_InitStructure);
    while(1)
        {
               GPIO_SetBits(GPIOA,GPIO_Pin_0);//高电平点亮LED灯
        }

}

LED流水灯

        这里与流水灯要用到八个引脚,所以只需要在开启时钟时,将八个引脚的时钟都开启即可(按位与“|”即可实现,GPIO_Pin_0|GPIO_Pin_1)。那为了方便起见,我们就把16个引脚的时钟都先开启。用到时再设置为高电平即可。

        代码具体实现如下

#include "stm32f10x.h"
#include "Delay.h" //改文件已经事先写好,就是封装好的延时函数

int main(void)
{
    int i;
    RCC_APB2PeriPhClock(APB2PeriPh_GPIOA,ENABLE);//开启时钟
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All;//PA0引脚
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//50MHz

    GPIO_Init(GPIOA,&GPIO_InitStructure);
    while(1)
        {
               for(i=0;i<9;i++)
            {

               GPIO_SetBits(GPIOA,GPIO_Pin_i);//高电平点亮LED灯
               Delay_ms(500);
               
            }

        }

}

        GPIO大致就粗浅的学习到这里了,后面的学习再陆续使用,以加深对GPIO模块的认识。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值