一、GPIO(寄存器版)

       本节介绍一下单片机里面最基本一个模块——GPIO模块,至于GPIO模块的概念,不了解的可自行知乎、百度,当然了,在以后的学习中也会慢慢的懂得什么是GPIO模块。记得刚接触嵌入式时我对GPIO也是一脸懵逼,咦!这是个啥吗(黑人问号脸)?后来,通过自己查资料以及实践中的应用,渐渐明白了GPIO说白了就是一个能够读入或者输出高或低电平的模块。在STM32中,这种模块共有五组,每组有16个引脚 。也就是说,总共有80个引脚可以读入/输出高/低电平,当然了,除了简单的读入输出高低电平之外,这80个引脚还可以复用为其他功能,不过这是后话了,这节主要看一下通用的GPIO功能。 

        废话少说,进入正题。首先 从内部电路说起,给单片机写代码多少还是要有一点电路知识的,因为单片机编程涉及到了底层的一些操作,这些底层操作和电路的设计紧密相关。下面,祭出第一张图——I/O端口位的基本结构:                                                                                                         

图1-I/O端口位的基本结构(图不重要,看字)

        水平有限,关于该结构以及GPIO8种工作模式的介绍参考博客:.GPIO的8种工作模式。除了上述博客介绍的之外,这里再说几个需要注意的地方:

1.,如果选用了复用功能输出,则对输出数据寄存器进行操作是不能够改变引脚输出值的。原因看上图,复用功能输出和“输出数据寄存器啊”是一个“或”的关系;

2.同理,如果选择了模拟输入,则“输入数据寄存器”是读不到该引脚的电平变化的。

暂时就发现了以上两个需要注意的地方,以后发现了再做补充。

       下面进入寄存器操作部分,这一部分是本文的重点部分。之前说过了,STM32有80个引脚可以读入或者输出高低电平,这里有几个问题需要关注:

1.如何决定引脚的工作模式?

2.如果是输出的话,如何决定输出的是高电平还是低电平?

3.如果是读入的话,怎样知道读入的是高电平还是低电平?

       针对以上问题,STM32提供了以下几个寄存器来来解决:

1.两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH)来设置引脚的工作模式;

2.两个32位数据寄存器,即GPIOx_IDR、GPIOx_ODR分别用来读入引脚的电平值、输出电平值;

3.除此之外,还有一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄
存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。

        下面,对以上寄存器以及配置方法逐个介绍一下:

一、配置寄存器:

上图时间到

                       

图2-GPIO位配置表

     由上图可知,每个引脚需要由4个位(PxODR寄存器暂时不用考虑)来配置工作模式,而每个GPIO模块有16个引脚,也就是说每组GPIO模块需要(16*4=64)个位才能配置完全,而STM32作为一款32位单片机每次只能且必须处理32位数据,所以有两个位配置器(GPIOx_CRL,GPIOx_CRH)分别来配置每个模块的低8位(0~7号引脚)及高8位(8~16号引脚)。再次上图:   

          

图4-端口配置低寄存器
图5-端口配置高寄存器

ex:我们要将A端口的6号引脚设置为上拉输入,A端口的8号引脚设置为推挽式输出、速度为50MHz。

第一步,确定是用低寄存器还是高寄存器。由图4及图5可知6号引脚使用低寄存器、8号引脚使用高寄存器,即需要配置GPIOA->CRL和GPIOA->CRH两个寄存器(这一部分涉及到C语言指针以及结构体的知识,此处不做解释);

第二步,确定了寄存器之后就要为其赋值来配置对应的模式。由图2可知上拉输入CNF以及MODE的值分别为11B、00B,推挽式输出、速度50MHzCNF以及MODE的值分别为00B、11B,结合图4知低寄存器的值应为:1100 0000 0000 0000 0000 0000 0000B,结合图5知高寄存器的值应为:0011B。将二进制转化为16进制为C00 0000H以及3H;

第三步,最终代码:

GPIOA->CRL=0xc00 0000; 
GPIOA->CRH=0x3;

至此,A端口的6号引脚以及8号引脚的工作模式配置完毕,其他端口及其引脚的配置类似。

二、数据寄存器:

还是先上图:

图 6-端口输入寄存器
图7-端口输出寄存器

之前说过,每个GPIO模块有16个引脚且STM32只允许一次读取32个位,所以端口输入、输出寄存器都只使用了16个位保留了16个位。(至于为什么不把两个寄存器合在一起,这个恐怕得问设计师了)

ex:沿用上个例子,判断A端口的6号引脚的电平值,如果为高电平则A端口的8号引脚输出高电平,反之输出低电平。

第一步,确定寄存器。由图6及图7知,6号引脚使用端口输入寄存器、8号引脚使用端口输出寄存器,即使用GPIOA->IDR、GPIOA->ODR两个寄存器;

第二步,确定读值及赋值。首先,确定读入的值,由图6知6号引脚为第7位,则判断6号引脚的电平值:

(GPIOA->IDR&0x40)==0x40,若该表达式为真则6号引脚为高电平,反之为低电平(涉及位运算符知识,此处不做解释)

为8号引脚写入电平值,由图7知8号引脚为第9位,则:

8号引脚写入高电平,寄存器的值为1 0000 0000B,即:GPIOA->ODR=0x100;

8号引脚写入低电平,寄存器的值为0 0000 0000B,即:GPIOA->ODR=0x000;(也可直接写作:GPIOA->ODR=0x0;)

第三步,最终代

if((GPIOA->IDR&0x40)==0x40) GPIOA->ODR=0x100;

else GPIOA->ODR=0x0;

至此,A端口的6号引脚读入电平值以及8号引脚输出电平值的操作介绍完毕,其他端口及其引脚的配置类似。

三、端口位设置/复位寄存器、端口位复位寄存器、锁定寄存器

图8-端口位设置/复位寄存器
图9-端口位复位寄存器
图10-端口锁定寄存器

     写累了,这三个寄存器就不写了,溜了溜了~~

注:本文图片及转载博客来源于网络,如有侵权请联系删除

猜你喜欢

转载自blog.csdn.net/qq_41100617/article/details/86654646