STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx_LCKR作用和配置
摘自: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、举例1
- 3、举例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;
- 1
- 2
第一行代码是为了让第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;
- 1
- 2
第一行代码是为了将第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)//低电平
....
- 1
- 2
- 3
- 4
- 5
- 6
或者:
if((GPIOE->IDR&0xffbf)==GPIOE->IDR)//低电平
....
if((GPIOE->IDR&0xffbf)!=GPIOE->IDR)//高电平
....
- 1
- 2
- 3
- 4
总之,端口输入数据寄存器(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 0011RCC_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都为高电平}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
解释一下例子:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE , ENABLE);//时钟使能
- 1
上述代码是配置时钟,GPIO时钟配置都用RCC_APB2PeriphClockCmd()
GPIOE->CRL&=0xff00ffff;GPIOE->CRL|=0x00380000;//PE5与PE4一起配置
- 1
- 2
上面代码是配置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<<5;
//GPIOE->ODR|=1<<5;//都可以
- 1
- 2
4、端口输出数据寄存器(GPIOx_ODR)(x=A…E)
1、详述
该寄存器与GPIOx_IDR类似,高16位也是保留位,就当做啥也没有,进行与运算和或运算时,只需和16位的数进行运算就行,从某种意义上讲,该寄存器与前面的GPIOx_IOR就是16位寄存器。
只要设置了某IO口的为输出模式(GPIOx_CRL、GPIOx_CRL)就可以利用该寄存器对该位进行置0或1。
前面第三部分的例子中也用到了该寄存器,现再举例说明
2、举例
例:控制蜂鸣器发声
打开原理图,找到蜂鸣器和芯片的连接图
由原理图可得:
①芯片PB8接蜂鸣器,所以配置GPIO时用到端口配置高位寄存器(GPIOB_CRH)
②当引脚输出高电平时,三极管基极电流变大,集电极电流也变大,蜂鸣器发声。
代码:(为了代码说明方便,将代码都写入到主函数)
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h"int main(void){ uint16_t x;//定义一个16位的数//BEEP PB8 CFN+MODE 0011RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);//时钟使能// RCC->APB2ENR|=0x0008;GPIOB->CRH&=0xfffffff0;GPIOB->CRH|=0x00000003;//配置PB8while(1){GPIOB->ODR|=0x0100;}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
解释一下:
GPIOB->CRH&=0xfffffff0;GPIOB->CRH|=0x00000003;//配置PB8
- 1
- 2
上述代码是配置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<<8;
- 1
移位运算在ODR中不推荐使用,虽然操作简单,但是移位运算是将16或32位的数整体左移,高位会溢出,低位会补零,若GPIOx只有一个IO被用到,可以采用移位方法,但是多个IO被使用,整体左移后会对其它IO状态产生影响。
正因为移位运算在IO口复杂情况下会对IO口造成紊乱,所以引入BSRR和BRR寄存器,可以在这两个寄存器中去移位来操作ODR寄存器,从而操作对应IO。这俩个寄存器中移位时,补0和溢出0都不会对ODR相应位产生影响,从而避免紊乱!
5、端口位设置/清除寄存器(GPIOx_BSRR)(x=A…E)
1、详述
该寄存器是对GPIOx_ODR寄存器的操作,我们之前举例时,都是用GPIOx_ODR去和一个16位数进行与运算和或运算,在进行运算时,需要求这个16位数,比较麻烦。不过可以移位法,将第一位置1,然后左移一定的位数(<<)。GPIOx_BSRR可以直接对GPIOx_ODR寄存器的某位进行设置。唯一不同的用GPIOx_BSRR操作GPIOx_ODR寄存器时,不用考虑GPIOx_ODR寄存器的不相关位。
GPIOx_BSRR也是32位寄存器,其中低16位是对GPIOx_ODR寄存器16个IO位置1,高16位是对GPIOx_ODR寄存器16个IO位置0
注意的是,如果GPIOx_BSRR的高16位和低16位都对某一IO口进行了配置,则以GPIOx_BSRR寄存器的低16位的配置为优先级。(后面例子中会说明)
2、举例1
1、以(3、GPIOxIDR寄存器的例子说明):按下开关KEY0后LED1亮,取消按下后LED1灭
因为GPIOx_BSRR寄存器高16位进行了清零操作,低16位进行了置1操作,所以不应该把它和一个32位的数进行与运算和或运算,如:
#include "sys.h"
#include"stm32f10x.h"int main(void){ uint16_t x;//定义一个16位的数//KEY0 PE4 CFN+MODE 1000//LED0 PE5 CFN+MODE 0011RCC_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,点亮LED0GPIOE->BSRR|=0x00200000;}// GPIOE->ODR|=0xFFFF;//恢复PE都为高电平GPIOE->BSRR|=0x00000030;//设置PE5(00000020)与设置PE4(00000010)合并(7、6、5、4位:0011)}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
上面程序的代码:
GPIOE->BSRR|=0x00200000;GPIOE->BSRR|=0x00000030;
- 1
- 2
是对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 0011RCC_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,点亮LED0GPIOE->BSRR=1<<21;//亮灯}//GPIOE->ODR|=0xFFFF;//恢复PE都为高电平GPIOE->BSRR|=1<<5;//灭灯GPIOE->BSRR|=1<<4;//按键恢复悬空(没办法,只能设置为高电平)/*也可以如下:(去掉或)*///GPIOE->BSRR=1<<5;// GPIOE->BSRR=1<<4;}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
还可以搭配GPIOx_BRR寄存器实现,第6部分总结。
3、举例2
再把上面的控制蜂鸣器发声的程序用GPIOB_BSRR寄存器写一下:
代码:
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h"int main(void){ //BEEP PB8 CFN+MODE 0011//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);//时钟使能RCC->APB2ENR|=0x0008;GPIOB->CRH&=0xfffffff0;GPIOB->CRH|=0x00000003;//配置PB8while(1){GPIOB->BSRR=1<<8;//或者:GPIOB->BSRR|=1<<8;//或者:GPIOB->BSRR|=0x00000100;}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
6、端口位清除寄存器(GPIOx_BRR)(x=A…E)
1、详述
GPIOx_BRR寄存器也是32位寄存器,但是高16位被保留,所以可以把它当做是16位寄存器。它的作用是将对应的0~15 IO口清零。即当对应位为1时,对应IO口置0,当对应位为0时,对应IO口保持原来的状态。
编程时,只需:GPIO(A~E)=1<<m,即可将PXm置0。
2、举例
点亮LED
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h"int main(void){ //LED0 PB5 推挽50M 0011//LED1 PE5 推挽50M 0011//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOE, ENABLE);//时钟使能GPIOA和GPIOERCC->APB2ENR|=0x0048;//RCC->APB2ENR=1<<3 ;//使能GPIOB//RCC->APB2ENR=1<<6 ;//使能GPIOEGPIOB->CRL&=0xff0fffff;GPIOB->CRL|=0x00300000;//配置PB5GPIOE->CRL&=0xff0fffff;GPIOE->CRL|=0x00300000;//配置PE5while(1){GPIOB->BRR=1<<5;//其实本来初始状态就是亮的,没必要再次点亮,,只是为了说明这个寄存器GPIOE->BRR=1<<5;}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
上述程序中,死循环中的两行代码就是通过GPIOB_BRR和GPIOE_BRR分别操作GPIOB_ODR和GPIOE_ODR来分别控制PB5和PE5输出低电平。
7、端口配置锁定寄存器(GPIOx_LCKR) (x=A…E)
1、详述
端口配置锁定寄存器是为了锁住GPIO的配置,在下次系统复位前不让其工作(只要下次复位不执行该寄存器,就不会被锁了)。
注意:锁住的是端口配置寄存器CRL或CRH
之前总结过端口配置寄存器GPIOx_CRL和GPIOx_CRH,对于每个IO,在寄存器中对应4位,即控制输入输出模式的2位CFN,控制speed的2位MODE。当端口寄存器锁住某IO口后,对应的CRL或CRH中对应的4位就被锁住,此时不能配置该位的输入、输出模式,以及不能配置speed,此时该IO口就不能使用。
具体叙述一下:
首先第16位,即高16位的第1位为LCKK,要开启锁IO模式,必须先“开锁”,开锁密码:写1——>写0——>写1——>读0——>读1。最后的读1可省略,但其它“密码”顺序、内容都不能错。
开锁程序:(GPIOB为例)
花了好长时间才调试成功(狗头)
uint32_t t;GPIOB->LCKR|=0x00010000;//LCKK写入1GPIOB->LCKR&=0x0000ffff;//LCKK写入0GPIOB->LCKR|=0x00010000;//LCKK写入1t=GPIOB->LCKR;//LCKK读0t=GPIOB->LCKR;//LCKK读出1
- 1
- 2
- 3
- 4
- 5
- 6
然后就是给某IO口上锁了,需要注意的是,只有第16位——>LCKK为0时,GPIOx_LCKR寄存器才可以被写入,某位写入1,则对应的IO口被锁住。
以PB5为例:
//开启锁定寄存器模式GPIOB->LCKR&=0x0000ffff;//LCKK写入0GPIOB->LCKR=1<<5;//锁定PB5
- 1
- 2
- 3
2、举例
例:同时配置LED0和LED1,但是LED0被GPIOB_LCKR寄存器锁住,观察两个LED能否都被点亮。
直接代码:
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h"int main(void){ uint32_t t;delay_init();//LED0 PB5 //LED1 PE5//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOE, ENABLE);//时钟使能GPIOA和GPIOERCC->APB2ENR|=0x0048;//RCC->APB2ENR=1<<3 ;//使能GPIOB//RCC->APB2ENR=1<<6 ;//使能GPIOE/* 开锁*/GPIOB->LCKR|=0x00010000;//LCKK写入1GPIOB->LCKR&=0x0000ffff;//LCKK写入0GPIOB->LCKR|=0x00010000;//LCKK写入1t=GPIOB->LCKR;//LCKK读0t=GPIOB->LCKR;//GPIOB_LCKR读出1//开启锁定寄存器模式GPIOB->LCKR&=0x0000ffff;//LCKK写入0GPIOB->LCKR=1<<5;//锁定PB5GPIOB->CRL&=0xff0fffff;GPIOB->CRL|=0x00300000;//配置PB5GPIOE->CRL&=0xff0fffff;GPIOE->CRL|=0x00300000;//配置PE5GPIOB->BSRR=1<<5;//熄灭LED0delay_ms(10);while(1){GPIOB->BRR=1<<5;//点亮LED0GPIOE->BRR=1<<5;}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
调试:
下载程序后,LED0一直熄灭,LED2一直亮。
分析:
程序开始时对GPIOB和GPIOE进行了时钟配置,接下来就是“开锁”,然后就是对PB5“上锁”,这些上面都总结了。
接下来配置PE5和PB5,然后把LED0熄灭(程序开始都清零,LED默认处于点亮状态),若LED0(PB5)的配置没有被锁住,则在死循环中LED0应该被点亮,调试时LED0应该常亮。
“开锁”时一定要注意:第0~15位的值不能被改变,所以写入0和1的时候要进行与运算和或运算。
二、总结
1、几种IO口输出类型(以PB5和PB10为例)
1、使用GPIOB_ODR寄存器
置1:
GPIOB->ODR|=0x0420;//PB10和PB5都输出高电平
- 1
GPIOB->ODR=1<<5;//只操作PB5置1//GPIOB->ODR|=1<<5;//注意同时设置PB5和PB10时不用移位
- 1
- 2
- 3
GPIOB->ODR=1<<10;//只操作PB10置1//GPIOB->ODR|=1<<510;//注意同时设置PB5和PB10时不用移位
- 1
- 2
- 3
置0:
GPIOB->ODR&=0xfbdf;//同时将PB5和PB10置0
- 1
GPIOB->ODR=0<<5;//只对PB5置0// GPIOB->ODR&=0xfffe<<5;
- 1
- 2
GPIOB->ODR&=0xff2f;//只对PB5置0
- 1
GPIOB->ODR&=0xf4ff;//只对PB10置0
- 1
GPIOB->ODR=0<<10;//只对PB10置0
- 1
GPIOB->ODR&=0xfffe<<10;//只对PB10置0
- 1
注意:GPIOB只有一个引脚使用时,才能通过移位运算操作ODR寄存器
2、使用GPIOB_BSRR寄存器
置1:
GPIOB->BSRR|=0x00000420;//同时设置PB5和PB10为1
//GPIOB->BSRR=0x00000420;
- 1
- 2
注意:此时低位设置覆盖了高位设置
GPIOB->BSRR|=1<<5;//单独设置PB5为高电平//GPIOB->BSRR=1<<5;
- 1
- 2
GPIOB->BSRR|=1<<10;//单独设置PB10为高电平//GPIOB->BSRR=1<<10;
- 1
- 2
/*同时设置PB5和PB10为高电平*/GPIOB->BSRR=1<<5;GPIOB->BSRR&=0;//清零GPIOB->BSRR=1<<10;
- 1
- 2
- 3
- 4
注意:上面代码必须清零,否则第三行代码移位时,会把原来第5位的1左移到第15位,对PB15也产生了影响!
置0:
不能和32位数进行与运算、或运算,否则低位设置会覆盖高位,导致要不PB5、PB10置1、要不保持原来的状态不变!
同时设置PB5和PB10
/*注意,一定要清零*/GPIOB->BSRR|=1<<21;//设置PB5GPIOB->BSRR&=0;//清零GPIOB->BSRR|=1<<26;//设置PB10
- 1
- 2
- 3
- 4
只设置一个IO的话,就把上述代码第一行、第三行单独拿出来就行了
3、使用GPIOB_BRR寄存器
该寄存器只能置0
GPIOB->BRR|=0x0420;//同时设置PB5、PB10为0//GPIOB->BRR=0x0420;
- 1
- 2
该寄存器是32位寄存器,但是高16位保留,所以可以当做16位寄存器来使用,和16位数与、或运算就行了。不过并不是所有单片机都可以这样,应该是这款单片机与、或运算时,是低位对齐,高位没对齐就补0。并不是所有单片机都这样,所以最好写成32位的形式。
/*同时操作PB5、PB10 为0*//*注意:一定要清零*/GPIOB->BRR|=1<<5;//操作PB5为0GPIOB->BRR&=0;//清0GPIOB->BRR|=1<<10;//操作PB10为0
- 1
- 2
- 3
- 4
- 5
4、小总结(比较重要)
使用寄存器与、或运算比较麻烦,因为要算16、32位的那个数。采用移位法可以操作ODR来输出高低电平,但是如果IO占用复杂,移位法就会造成IO口紊乱,GPIOx只有一个IO口是,才可以用移位法控制ODR寄存器。
所以使用BSRR寄存器和BRR寄存器去解决移位时IO口紊乱的问题。但是BSRR寄存器高位和低位同时配置时,低位会覆盖高位的设置,所以推荐使用以下方法:
如果要控制IO输出高低电平、采用BSRR和BRR寄存器来设置ODR寄存器,进而控制对应IO口。置1时,采用BSRR进行低位操作;置0时,采用BRR寄存器。
STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx_LCKR作用和配置相关推荐
- STM32F103五分钟入门系列(八)SysTick滴答定时器+SysTick中断实现跑马灯
学习板:STM32F103ZET6 往期博客: STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结 STM32F103五分钟入门系列(二)GPIO的七大寄存器+G ...
- STM32F103五分钟入门系列(十六)输入捕获(精雕细琢-.-)
学习板:STM32F103ZET6 往期博客: STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结 STM32F103五分钟入门系列(二)GPIO的七大寄存器+G ...
- STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结
摘自:STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结 作者:自信且爱笑' 发布时间: 2021-04-28 21:17:40 网址:https://blog. ...
- STM32F103五分钟入门系列(十三)独立看门狗IWDG
参考:STM32F103五分钟入门系列(十三)独立看门狗IWDG 作者:自信且爱笑' 发布时间:2021-07-31 19:50:28 网址:https://blog.csdn.net/Curnane ...
- Reflex WMS入门系列二十五:将叉车纳入系统进行管理
Reflex WMS入门系列二十五:将叉车纳入系统进行管理 据笔者所知,SAP WM 模块里是不对仓库里常用的叉车等仓库管理工具进行管理的.笔者发现,Reflex WMS系统则会在很多仓库部门日常操作 ...
- 机器学习入门系列二(关键词:多变量(非)线性回归,批处理,特征缩放,正规方程
机器学习入门系列二(关键词:多变量(非)线性回归,批处理,特征缩放,正规方程) 目录(?)[+] 一多变量的线性回归 二批处理 三特征缩放 四正规方程 五多变量非线性回归 一.多变量的线性回归 在#机 ...
- Quantopian 入门系列二 - 流水线 (下)
本文含 8225 字,28 图表截屏 建议阅读 42 分钟 本贴接着上贴[Quantopian 入门系列二 - 流水线 (上)]的内容,讨论下面目录的 5- 8 节: 简介 因子 筛选器 分类器 掩码 ...
- C语言速看,C语言高速入门系列(二)
C语言高速入门系列(二) -----转载请注明出处coder-pig 本节引言: 在前面一节中我们对C语言进行了初步的了解,学会了使用IDE进行代码的编写,编译执行! 在这一节中我们会对C语言的基本的 ...
- Maven五分钟入门
Maven 五分钟入门 ---本文翻译自Maven官网的Maven in 5 Minutes,稍有删改,所有版权归maven所有.本文只作学习交流之用. 安装 Maven 是一个java工具,因此,在 ...
最新文章
- 百度第七期智能对话训练营来了!
- mysql查看表格的列信息
- C++_pthread read-write lock_读写锁_visual studio 2015下配置
- Java异常以及继承的一些问题
- hdu4907 水dp 或者set
- WCF事务编程[中篇]
- QT的QStorageInfo类的使用
- 安卓APP_ Fragment(3)—— Fragment的生命周期
- DELPHI之常用函数
- 浏览器之本地缓存存储 localStorage 和 sessionStorage的区别以及用法
- amap vueamap 与_vue中使用vue-amap(高德地图)
- git中如何提交空目录
- windows自带黑体_微软黑体下载-微软黑体官方下载[字体下载]-华军软件园
- c语言使用CodeBlocks软件,使用CodeBlocks学习C语言
- Opencv4Android的OpenCL的测试,使用Opencv的ocl封装库
- doodoo.js快速入门教程
- C#实现SqlServer连接查询
- 马里兰大计算机专业学phd博士,亚利桑那州立大学计算机CS博士PHD全奖录取
- 一个屌丝程序猿的人生(一百二十六)
- 2022.3.3总结+力扣258. 各位相加
热门文章
- Java常量池理解与总结
- redux进一步优化
- Dynagen0.11+Pemuwrapper入手麻烦二三事——告诉初学者直路
- Hibernate的generator属性
- SQLite数据库常用语句及MAC上的SQLite可视化工具MeasSQLlite使用
- HBuilder:最快的Web开发IDE
- Android--UI之DatePicker、TimePicker...
- HTML5学习笔记简明版(4):新元素之video,audio,meter,datalist,keygen,output
- Ubuntu 屏幕亮度调整
- 主流开源编解码器Xvid,x264,ffmpeg 性能对比