STM32的GPIO的寄存器配置学习1

对着背影说爱祢 提交于 2020-03-09 16:24:06

本篇文章主要是学习以M3内核的STM32的GPIO的寄存器的配置,为什么要学习寄存器,而不利用库函数呢?我只能说为了让学的知识更加牢固吧!当然,你可以直接去利用库函数,但是如果你能认真读完本篇博客,你会对知识豁然开朗!加油吧!

STM32 的每个 IO 端口都有 7 个寄存器(如果还不懂寄存器是什么,请点击)来控制。他们分别是:配置模式的 2 个 32 位的端口配置寄存器 CRL 和 CRH2 个 32 位的数据寄存器 IDR 和 ODR1 个 32 位的置位/复位寄存器BSRR一个 16 位的复位寄存器 BRR1 个 32 位的锁存寄存器 LCKR;这里我们仅介绍常用的几个寄存器,我们常用的 IO 端口寄存器只有 4 个:CRL、CRH、IDR、ODR 。

可能罗列了这么多的寄存器,小白可能会一头蒙(心想,用的时候再找呗,我想说,那还不如直接记住,对吧,哈哈哈)接下来我会每一个介绍一下,然后会有一个程序说明,仔细看完文章吧!

一、CRL、CRH

STM32的每个 IO 口都可以自由编程,但 IO 口寄存器必须要按 32 位字被编辑被访问(因为系统本身是32位),CRL 和 CRH 控制着每个 IO 口的模式输出速率,只不过CRL控制低8位的GPIO接口(GPIO0至GPIO7);CRH控制高8位的GPIO接口(GPIO8至GPIO15)。而配置一个CRL或CRH都需要4位(MODE+CNF共4位)控制一个IO口。

下面以 CRL (CRH同样)进行描述解析:(可以跳过看图,下面可以根据所写,在回过来看图)

注意:图中共32位(是连续的呀,中间不是断的),MODE+CNF共4位用来控制一个IO口,可以配置GPIO0至GPIO7的IO口,

直接上例子,来说明问题:咱们来控制一个 PB5 为推挽输出(5是低7位中数呀,这时就需要使用CRL了),这时候需要看看上表中的信息了,从表中可以,如果想配置B系列的管脚5口为推挽输出,只需要将CNF5设置为00,将MODE5设置为11(此时设置的速率为最大,可以自己去选择)就可以了(简单吧,哈哈),那怎么写程序呢?首先明确的是要使用16进制写(不懂16进制请点击我的博客:C语言中数组的“那些事儿”),此时的情况就是:00 00 00 00 00 11 00 00 00 00 00 00 00 00 00 00(注意这个是从高位到低写的),16进制也就是:0X00300000。

PB5管脚配置程序如下:

                    GPIOB->CRL&=0XFF0FFFFF;//清掉这个位原来的设置,同时也不影响其他位的设置

                    GPIOB->CRL|=0X00300000;//清掉完原来的设置,此时就可以设置PB5为推挽输出

同样,如果想配置PB8管脚为推挽输出呢?(8是高8位中的数呀,这时就需要使用CRH了),程序如下:

                    GPIOB->CRH&=0XFFFFFFF0;//清掉这个位原来的设置,同时也不影响其他位的设置

                    GPIOB->CRH|=0X00000003;//清掉完原来的设置,此时就可以设置PB8为推挽输出

简单吧,(如果还不懂,就从头再看一遍)

二、IDR、ODR

IDR 是一个端口输入数据寄存器,只用了低 16 位。该寄存器为只读寄存器,并且只能以16 位的形式读出,你如果要想知道某个 IO 口的状态,你只要读这个寄存器,再看某个位的状态就可以了,使用起来是还是比较简单的。

需要注意的是IDR这是个只读寄存器,是不能给它赋值的。举例的程序为:

                    GPIOA->IDR & 0x0001 //即为 PA1的电平状态,IDR寄存器的16位对应了该GPIO的P0-P15

ODR 是一个端口输出数据寄存器,也只用了低 16 位。该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前 IO 口的输出状态。而向该寄存器写数据,则可以控制某个 IO 口的输出电平

举例的程序为:

                    GPIOA->ODR =1>>13 //即为 PA13的电平状态,IDR寄存器的16位对应了该GPIO的P0-P15

                    GPIOA->ODR =1>>5 //即为 PA5的电平状态,IDR寄存器的16位对应了该GPIO的P0-P15

没错,你没有看错,这句程序按照格式是可以罗列的。

如果IDR、ODR想调用,举例就是如果想读出PA1的状态,赋值给PA13,程序如下(需要借助一个变量:先定义一个变量unsigned short temp):

                   temp = GPIOA->IDR & 0x0001;

                   GPIOA->ODR = temp>>13;
如果看不懂,再看一下上面的内容(哈哈哈)         

下面我通过书上找的控制GPIO的PB5和PE5的LED灯使其交替闪烁为例,设置步骤:
               1. 使能相关时钟
               2. 设置相应的 IO 口为输入或输出
               3. 设置输入\输出的类型 设置输出的速度
               4. 设置上拉下拉寄存器
               5. 通过复位置位寄存器和输入输出数据寄存器进行操作。

程序如下: (led.c)

#include "led.h"
//初始化 PB5 和 PE5 为输出口.并使能这两个口的时钟
//LED IO 初始化
void LED_Init(void)
{
   RCC->APB2ENR|=1<<3; //使能 GPIOB 时钟  APB2ENR是APB2总线上的外设时钟使能寄存器
   RCC->APB2ENR|=1<<6; //使能 GPIOE 时钟
   GPIOB->CRL&=0XFF0FFFFF;
   GPIOB->CRL|=0X00300000;//PB.5 推挽输出
   GPIOB->ODR|=1<<5; //PB.5 输出高
   GPIOE->CRL&=0XFF0FFFFF;
   GPIOE->CRL|=0X00300000;//PE.5 推挽输出
   GPIOE->ODR|=1<<5; //PE.5 输出高
}

程序如下: (led.h)

#ifndef __LED_H
#define __LED_H
#include "sys.h"
//LED 端口定义 为了简化程序,设置宏定义
#define LED0 PBout(5) 
#define LED1 PEout(5) 
void LED_Init(void); //初始化
#endif

主程序如下(main.c

#include "sys.h"
#include "delay.h"
#include "led.h"

int main(void)
 {
    Stm32_Clock_Init(9); //系统时钟设置
    delay_init(72); //延时初始化
    LED_Init(); //初始化与 LED 连接的硬件接口
    while(1)
        {
           LED0=0;
           LED1=1;
           delay_ms(300);
           LED0=1;
           LED1=0;
           delay_ms(300);
        }
 }

附:程序中的APB2ENR 是 APB2 总线上的外设时钟使能寄存器:

使能的GPIOB 和GPIOE 的时钟使能位,分别在 bit3 和 bit6,只要将这两位置 1 就可以使能 GPIOB 和GPIOE 的时钟了(简单吧!

好了,就介绍到这,其实主要是介绍学习的方法,如何去分析,学会后,就可以很快的去接触一款新的控制器芯片。本专栏为一列,请关注。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!