STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx 您所在的位置:网站首页 r13r14r15寄存器 STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx

STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx

2023-10-09 03:10| 来源: 网络整理| 查看: 265

摘自:STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx_LCKR作用和配置 作者:自信且爱笑‘ 发布时间: 2021-05-01 12:08:32 网址:https://blog.csdn.net/Curnane0_0/article/details/116276876?spm=1001.2014.3001.5501

学习板:STM32F103ZET6

GPIO的七大寄存器+GPIOx_LCKR作用和配置+编程小总结 一、GPIO的寄存器 1、端口配置低寄存器(GPIOx_CRL) (x=A..E) 1、详述2、举例 2、端口配置高寄存器(GPIOx_CRH) (x=A..E)3、端口输入数据寄存器(GPIOx_IDR)(x=A...E) 1、详述2、举例 4、端口输出数据寄存器(GPIOx_ODR)(x=A...E) 1、详述2、举例 5、端口位设置/清除寄存器(GPIOx_BSRR)(x=A...E) 1、详述2、举例13、举例2 6、端口位清除寄存器(GPIOx_BRR)(x=A...E) 1、详述2、举例 7、端口配置锁定寄存器(GPIOx_LCKR) (x=A..E) 1、详述2、举例 二、总结 1、几种IO口输出类型(以PB5和PB10为例) 1、使用GPIOB_ODR寄存器2、使用GPIOB_BSRR寄存器3、使用GPIOB_BRR寄存器4、小总结(比较重要)

一、GPIO的寄存器

参考文件:《STM32中文参考手册》

每个GPIO端口有两个32位配置寄存器(GPIOx_CRL, GPIOx_CRH),两个32位数据寄存器 (GPIOx_IDR和GPIOx_ODR),一个32位置位/复位寄存器(GPIOx_BSRR),一个16位复位寄存 器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)

1、端口配置低寄存器(GPIOx_CRL) (x=A…E) 1、详述

该寄存器是用来配置低位寄存器(PX0~PX7),为32位寄存器。对于GPIOX,从PX0 ~PX7共8 个IO口,32位寄存器的每四位配置一个IO口。用来配置GPIO的输入输出模式和输出时的speed。 在这里插入图片描述

对于每个IO口配置的四位,由两位的MODE和两位的CNF,其中MODE配置Speed,CNF配置是哪种输出模式

在这里插入图片描述 在这里插入图片描述

所以配置GPIO的步骤: ①判断是低8位IO还是高8位IO ②判断该IO对应的CNF和MODE值为多少 ③编写配置函数:

GPIOA(B、C、D、E)——>CRL(或CRH)=0x.... 1 2、举例

以按键为例

在这里插入图片描述在这里插入图片描述在这里插入图片描述

由原理图可知,KEY_UP按下后,PA0变为高电平,没有按下时,PA0处于悬空状态;KEY0、KEY1、KEY2按下后PE4、PE3、PE2分别变为低电平,未按下时,对应IO口处于悬空状态。所以按键的GPIO配置的模式可以是浮空输入。不过KEY_UP按下后为了更好的检测到高电平,可以采用上拉输入;KEY0、KEY1、KEY2按下后为了更好的检测到低电平,可以采用下拉输入。

KEY_UP的GPIO配置: ①PA0为低位,采用GPIOA_CRL ②上拉输入,所以CNF为10表示上拉/下拉输入,MODE为00,表示输入模式 在这里插入图片描述

代码:

GPIOA->CRL&=0xfffffff0; GPIOA->CRL|=0x00000008; 12

第一行代码是为了让第0、1、2、3这四位置0,其它位不变;第二行代码是为了让第0、1、2、3这4位变为1000,其它位不变。

KEY0的GPIO配置: ①PE4为低4位,所以使用GPIOE_CRL寄存器 ②采用下拉输入,所以CNF为10,输入模式,MODE为00

在这里插入图片描述

代码:

GPIOE->CRL&=0xfff0ffff; GPIOE->CRL|=0x00080000; 12

第一行代码是为了将第16、17、18、19位置0,其它位保持不变;第二行代码是为了将第16、17、18、19位置1000,其它位保持不变。

2、端口配置高寄存器(GPIOx_CRH) (x=A…E)

与端口配置低寄存器(GPIOx_CRL)(x=A…E)类似,唯一不同的是对应PX8~PX15 IO口。

3、端口输入数据寄存器(GPIOx_IDR)(x=A…E) 1、详述

在这里插入图片描述

该寄存器为32位寄存器, 其中高16位保持不变,低16位依次对应PX0~PX15,该寄存器只能以16位的形式读出

那怎么获取某一位的值呢?可以用与运算,如想要知道第6位是不是输入了高电平,即检测第6位是否为1,只需与1111111110111111与运算,即与0xffbf进行与运算 代码:

uint16_t x;//定义一个16位的数 x=GPIOE->IDR&0xffbf; if(x==0xffff)//高电平 .... if(x==0xffbf)//低电平 .... 123456

或者:

if((GPIOE->IDR&0xffbf)==GPIOE->IDR)//低电平 .... if((GPIOE->IDR&0xffbf)!=GPIOE->IDR)//高电平 .... 1234

总之,端口输入数据寄存器(GPIOx_IDR) 就是来判读各位的IO口是什么状态。

2、举例

例:按下开关KEY0后LED1亮,取消按下后LED1灭

为了方便代码粘贴,全部程序在主函数中编写 代码:

#include "sys.h" #include"stm32f10x.h" int main(void) { uint16_t x;//定义一个16位的数 //KEY0 PE4 CFN+MODE 1000 //LED0 PE5 CFN+MODE 0011 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE , ENABLE);//时钟使能 // RCC->APB2ENR|=0x0040; GPIOE->CRL&=0xff00ffff; GPIOE->CRL|=0x00380000;//PE5与PE4一起配置 while(1) { x=GPIOE->IDR&0x0010; if(x==0)//KEY0按下 { GPIOE->ODR&=0xffdf;//PE5置0,点亮LED0 } GPIOE->ODR|=0xFFFF;//恢复PE都为高电平 } } 123456789101112131415161718192021222324

解释一下例子:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE , ENABLE);//时钟使能 1

上述代码是配置时钟,GPIO时钟配置都用RCC_APB2PeriphClockCmd() 在这里插入图片描述 在这里插入图片描述在这里插入图片描述 在这里插入图片描述

GPIOE->CRL&=0xff00ffff; GPIOE->CRL|=0x00380000;//PE5与PE4一起配置 12

上面代码是配置PE5(LED0)和PE4(KEY0)

PE4是KEY0,按下后PE4引脚变为低电平,未按下时PE4引脚为悬空,采用下拉输入,所以CFN+MODE为1000;PE5为LED0,低电平时点亮,高电平时熄灭,所以采用推挽输出,速度为50M,CFN+MODE为0011,两者都为低位IO,采用GPIOE_CRL寄存器配置。

在这里插入图片描述 第一行代码先将16~23位置0,其它位不变,第二行代码将16 ~23位置00111000,其它位不变,完成PE4和PE5的配置。

x=GPIOE->IDR&0x0010; 1

上述代码是为了检测KEY0是否按下,如果按下,则GPIOE_IDR的第4位变为0,此时与0x0010与运算后,值为0 在这里插入图片描述 检测到按下后,执行:

GPIOE->ODR&=0xffdf;//PE5置0,点亮LED0 1

上述代码的寄存器是接下来要总结的寄存器,就是将IO的某位软件置0或1输出,而GPIOx_IDR是外界原因置0或1来输入到芯片。 现在要点亮LED0,则GPIOE的第5位变为0,所以和0xffdf进行与运算就行了

在这里插入图片描述 需要注意的是,进行与运算和或运算时,改变的只能是相关的IO引脚,其它无关的IO引脚的电平值一定要保持不变

GPIOE->ODR|=0xFFFF;//恢复PE都为高电平 1

上述代码是为了将GPIOE全部引脚恢复原状,因为死循环中执行一次后,PE4和PE5都变为低电平,若不恢复原状,LED的引脚PE5一直处于低电平状态,灯会常亮,不再受KEY控制。

其实恢复PE5为高电平就行了,这行代码可改为:

GPIOE->ODR&=0xfef; 1

或者利用移位运算:

GPIOE->ODR=1 GPIOB->ODR|=0x0100; } } 1234567891011121314151617

解释一下:

GPIOB->CRH&=0xfffffff0; GPIOB->CRH|=0x00000003;//配置PB8 12

上述代码是配置GPIOB的第8引脚,用的端口配置高位寄存器,为通用推挽输出,速度为50M,所以CNF+MODE为0011

在这里插入图片描述 先将0~3位通过与运算置0,再通过或运算置0011。

GPIOB->ODR|=0x0100; 1

上述代码是使PB8输出高电平 在这里插入图片描述

当然可以将蜂鸣器关闭,只需:(还可以用GPIOB_BSRR寄存器、GPIOB_BRR寄存器)

GPIOB->ODR&=0xfeff; 1

或者:

GPIOB->ODR&=0xfffe x=GPIOE->IDR&0x0010; if(x==0)//KEY0按下 { //GPIOE->ODR&=0xffdf;//PE5置0,点亮LED0 GPIOE->BSRR|=0x00200000; } // GPIOE->ODR|=0xFFFF;//恢复PE都为高电平 GPIOE->BSRR|=0x00000030;//设置PE5(00000020)与设置PE4(00000010)合并(7、6、5、4位:0011) } } 1234567891011121314151617181920212223

上面程序的代码:

GPIOE->BSRR|=0x00200000; GPIOE->BSRR|=0x00000030; 12

是对GPIOE_BSRR和32位数进行位或运算,所以在设置低位BS4、BS5时,高位BR4、BR5也同时进行了设置,但是以低位设置为优先级 好好理解下图标注的地方!!!英文原话:Note: If both BSx and BRx are set, BSx has priority

在这里插入图片描述 还可以用位移方法:

完整准确代码:

#include "sys.h" #include "stm32f10x.h" int main(void) { uint16_t x;//定义一个16位的数 //KEY0 PE4 CFN+MODE 1000 //LED0 PE5 CFN+MODE 0011 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE , ENABLE);//时钟使能 // RCC->APB2ENR|=0x0040; GPIOE->CRL&=0xff00ffff; GPIOE->CRL|=0x00380000;//PE5与PE4一起配置 while(1) { x=GPIOE->IDR&0x0010; if(x==0)//KEY0按下 { //GPIOE->ODR&=0xffdf;//PE5置0,点亮LED0 GPIOE->BSRR=1BSRR|=1 GPIOB->BSRR=1 GPIOB->BRR=1读0——>读1。最后的读1可省略,但其它“密码”顺序、内容都不能错。

开锁程序:(GPIOB为例)

花了好长时间才调试成功(狗头)

uint32_t t; GPIOB->LCKR|=0x00010000;//LCKK写入1 GPIOB->LCKR&=0x0000ffff;//LCKK写入0 GPIOB->LCKR|=0x00010000;//LCKK写入1 t=GPIOB->LCKR;//LCKK读0 t=GPIOB->LCKR;//LCKK读出1 123456

然后就是给某IO口上锁了,需要注意的是,只有第16位——>LCKK为0时,GPIOx_LCKR寄存器才可以被写入,某位写入1,则对应的IO口被锁住。

以PB5为例:

//开启锁定寄存器模式 GPIOB->LCKR&=0x0000ffff;//LCKK写入0 GPIOB->LCKR=1 GPIOB->BRR=1


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有