日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx_LCKR作用和配置

發(fā)布時(shí)間:2023/12/10 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx_LCKR作用和配置 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

摘自:STM32F103五分鐘入門系列(二)GPIO的七大寄存器+GPIOx_LCKR作用和配置
作者:自信且愛笑‘
發(fā)布時(shí)間: 2021-05-01 12:08:32
網(wǎng)址:https://blog.csdn.net/Curnane0_0/article/details/116276876?spm=1001.2014.3001.5501

學(xué)習(xí)板:STM32F103ZET6

GPIO的七大寄存器+GPIOx_LCKR作用和配置+編程小總結(jié)

  • 一、GPIO的寄存器
    • 1、端口配置低寄存器(GPIOx_CRL) (x=A..E)
      • 1、詳述
      • 2、舉例
    • 2、端口配置高寄存器(GPIOx_CRH) (x=A..E)
    • 3、端口輸入數(shù)據(jù)寄存器(GPIOx_IDR)(x=A...E)
      • 1、詳述
      • 2、舉例
    • 4、端口輸出數(shù)據(jù)寄存器(GPIOx_ODR)(x=A...E)
      • 1、詳述
      • 2、舉例
    • 5、端口位設(shè)置/清除寄存器(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、舉例
  • 二、總結(jié)
    • 1、幾種IO口輸出類型(以PB5和PB10為例)
      • 1、使用GPIOB_ODR寄存器
      • 2、使用GPIOB_BSRR寄存器
      • 3、使用GPIOB_BRR寄存器
      • 4、小總結(jié)(比較重要)

一、GPIO的寄存器

參考文件:《STM32中文參考手冊》

每個(gè)GPIO端口有兩個(gè)32位配置寄存器(GPIOx_CRL, GPIOx_CRH),兩個(gè)32位數(shù)據(jù)寄存器
(GPIOx_IDR和GPIOx_ODR),一個(gè)32位置位/復(fù)位寄存器(GPIOx_BSRR),一個(gè)16位復(fù)位寄存
器(GPIOx_BRR)和一個(gè)32位鎖定寄存器(GPIOx_LCKR)

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

1、詳述

該寄存器是用來配置低位寄存器(PX0~PX7),為32位寄存器。對于GPIOX,從PX0 ~PX7共8 個(gè)IO口,32位寄存器的每四位配置一個(gè)IO口。用來配置GPIO的輸入輸出模式和輸出時(shí)的speed。

對于每個(gè)IO口配置的四位,由兩位的MODE和兩位的CNF,其中MODE配置Speed,CNF配置是哪種輸出模式


所以配置GPIO的步驟:
①判斷是低8位IO還是高8位IO
②判斷該IO對應(yīng)的CNF和MODE值為多少
③編寫配置函數(shù):

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

2、舉例

以按鍵為例

由原理圖可知,KEY_UP按下后,PA0變?yōu)楦唠娖?#xff0c;沒有按下時(shí),PA0處于懸空狀態(tài);KEY0、KEY1、KEY2按下后PE4、PE3、PE2分別變?yōu)榈碗娖?#xff0c;未按下時(shí),對應(yīng)IO口處于懸空狀態(tài)。所以按鍵的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位變?yōu)?000,其它位不變。

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)類似,唯一不同的是對應(yīng)PX8~PX15 IO口。

3、端口輸入數(shù)據(jù)寄存器(GPIOx_IDR)(x=A…E)

1、詳述

該寄存器為32位寄存器, 其中高16位保持不變,低16位依次對應(yīng)PX0~PX15,該寄存器只能以16位的形式讀出

那怎么獲取某一位的值呢?可以用與運(yùn)算,如想要知道第6位是不是輸入了高電平,即檢測第6位是否為1,只需與1111111110111111與運(yùn)算,即與0xffbf進(jìn)行與運(yùn)算
代碼:

uint16_t x;//定義一個(gè)16位的數(shù) 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

總之,端口輸入數(shù)據(jù)寄存器(GPIOx_IDR) 就是來判讀各位的IO口是什么狀態(tài)。

2、舉例

例:按下開關(guān)KEY0后LED1亮,取消按下后LED1滅

為了方便代碼粘貼,全部程序在主函數(shù)中編寫
代碼:

#include "sys.h" #include"stm32f10x.h"int main(void){ uint16_t x;//定義一個(gè)16位的數(shù)//KEY0 PE4 CFN+MODE 1000//LED0 PE5 CFN+MODE 0011RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE , ENABLE);//時(shí)鐘使能// 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,點(diǎn)亮LED0}GPIOE->ODR|=0xFFFF;//恢復(fù)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);//時(shí)鐘使能
  • 1

上述代碼是配置時(shí)鐘,GPIO時(shí)鐘配置都用RCC_APB2PeriphClockCmd()


GPIOE->CRL&=0xff00ffff;GPIOE->CRL|=0x00380000;//PE5與PE4一起配置
  • 1
  • 2

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

PE4是KEY0,按下后PE4引腳變?yōu)榈碗娖?#xff0c;未按下時(shí)PE4引腳為懸空,采用下拉輸入,所以CFN+MODE為1000;PE5為LED0,低電平時(shí)點(diǎn)亮,高電平時(shí)熄滅,所以采用推挽輸出,速度為50M,CFN+MODE為0011,兩者都為低位IO,采用GPIOE_CRL寄存器配置。


第一行代碼先將16~23位置0,其它位不變,第二行代碼將16 ~23位置00111000,其它位不變,完成PE4和PE5的配置。

x=GPIOE->IDR&0x0010;
  • 1

上述代碼是為了檢測KEY0是否按下,如果按下,則GPIOE_IDR的第4位變?yōu)?,此時(shí)與0x0010與運(yùn)算后,值為0

檢測到按下后,執(zhí)行:

GPIOE->ODR&=0xffdf;//PE5置0,點(diǎn)亮LED0
  • 1

上述代碼的寄存器是接下來要總結(jié)的寄存器,就是將IO的某位軟件置0或1輸出,而GPIOx_IDR是外界原因置0或1來輸入到芯片。
現(xiàn)在要點(diǎn)亮LED0,則GPIOE的第5位變?yōu)?,所以和0xffdf進(jìn)行與運(yùn)算就行了


需要注意的是,進(jìn)行與運(yùn)算和或運(yùn)算時(shí),改變的只能是相關(guān)的IO引腳,其它無關(guān)的IO引腳的電平值一定要保持不變

GPIOE->ODR|=0xFFFF;//恢復(fù)PE都為高電平
  • 1

上述代碼是為了將GPIOE全部引腳恢復(fù)原狀,因?yàn)樗姥h(huán)中執(zhí)行一次后,PE4和PE5都變?yōu)榈碗娖?#xff0c;若不恢復(fù)原狀,LED的引腳PE5一直處于低電平狀態(tài),燈會(huì)常亮,不再受KEY控制。

其實(shí)恢復(fù)PE5為高電平就行了,這行代碼可改為:

GPIOE->ODR&=0xfef;
  • 1

或者利用移位運(yùn)算:

GPIOE->ODR=1<<5; //GPIOE->ODR|=1<<5;//都可以
  • 1
  • 2

4、端口輸出數(shù)據(jù)寄存器(GPIOx_ODR)(x=A…E)

1、詳述

該寄存器與GPIOx_IDR類似,高16位也是保留位,就當(dāng)做啥也沒有,進(jìn)行與運(yùn)算和或運(yùn)算時(shí),只需和16位的數(shù)進(jìn)行運(yùn)算就行,從某種意義上講,該寄存器與前面的GPIOx_IOR就是16位寄存器。

只要設(shè)置了某IO口的為輸出模式(GPIOx_CRL、GPIOx_CRL)就可以利用該寄存器對該位進(jìn)行置0或1。

前面第三部分的例子中也用到了該寄存器,現(xiàn)再舉例說明

2、舉例

例:控制蜂鳴器發(fā)聲

打開原理圖,找到蜂鳴器和芯片的連接圖


由原理圖可得:
①芯片PB8接蜂鳴器,所以配置GPIO時(shí)用到端口配置高位寄存器(GPIOB_CRH)
②當(dāng)引腳輸出高電平時(shí),三極管基極電流變大,集電極電流也變大,蜂鳴器發(fā)聲。

代碼:(為了代碼說明方便,將代碼都寫入到主函數(shù))

#include "sys.h" #include "stm32f10x.h" #include "delay.h"int main(void){ uint16_t x;//定義一個(gè)16位的數(shù)//BEEP PB8 CFN+MODE 0011RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);//時(shí)鐘使能// 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位通過與運(yùn)算置0,再通過或運(yùn)算置0011。

GPIOB->ODR|=0x0100;
  • 1

上述代碼是使PB8輸出高電平

當(dāng)然可以將蜂鳴器關(guān)閉,只需:(還可以用GPIOB_BSRR寄存器、GPIOB_BRR寄存器)

GPIOB->ODR&=0xfeff;
  • 1

或者:

GPIOB->ODR&=0xfffe<<8;
  • 1

移位運(yùn)算在ODR中不推薦使用,雖然操作簡單,但是移位運(yùn)算是將16或32位的數(shù)整體左移,高位會(huì)溢出,低位會(huì)補(bǔ)零,若GPIOx只有一個(gè)IO被用到,可以采用移位方法,但是多個(gè)IO被使用,整體左移后會(huì)對其它IO狀態(tài)產(chǎn)生影響。

正因?yàn)橐莆贿\(yùn)算在IO口復(fù)雜情況下會(huì)對IO口造成紊亂,所以引入BSRR和BRR寄存器,可以在這兩個(gè)寄存器中去移位來操作ODR寄存器,從而操作對應(yīng)IO。這倆個(gè)寄存器中移位時(shí),補(bǔ)0和溢出0都不會(huì)對ODR相應(yīng)位產(chǎn)生影響,從而避免紊亂!

5、端口位設(shè)置/清除寄存器(GPIOx_BSRR)(x=A…E)

1、詳述

該寄存器是對GPIOx_ODR寄存器的操作,我們之前舉例時(shí),都是用GPIOx_ODR去和一個(gè)16位數(shù)進(jìn)行與運(yùn)算和或運(yùn)算,在進(jìn)行運(yùn)算時(shí),需要求這個(gè)16位數(shù),比較麻煩。不過可以移位法,將第一位置1,然后左移一定的位數(shù)(<<)。GPIOx_BSRR可以直接對GPIOx_ODR寄存器的某位進(jìn)行設(shè)置。唯一不同的用GPIOx_BSRR操作GPIOx_ODR寄存器時(shí),不用考慮GPIOx_ODR寄存器的不相關(guān)位。

GPIOx_BSRR也是32位寄存器,其中低16位是對GPIOx_ODR寄存器16個(gè)IO位置1,高16位是對GPIOx_ODR寄存器16個(gè)IO位置0
注意的是,如果GPIOx_BSRR的高16位和低16位都對某一IO口進(jìn)行了配置,則以GPIOx_BSRR寄存器的低16位的配置為優(yōu)先級(jí)。(后面例子中會(huì)說明)

2、舉例1

1、以(3、GPIOxIDR寄存器的例子說明):按下開關(guān)KEY0后LED1亮,取消按下后LED1滅
因?yàn)镚PIOx_BSRR寄存器高16位進(jìn)行了清零操作,低16位進(jìn)行了置1操作,所以不應(yīng)該把它和一個(gè)32位的數(shù)進(jìn)行與運(yùn)算和或運(yùn)算,如:

#include "sys.h" #include"stm32f10x.h"int main(void){ uint16_t x;//定義一個(gè)16位的數(shù)//KEY0 PE4 CFN+MODE 1000//LED0 PE5 CFN+MODE 0011RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE , ENABLE);//時(shí)鐘使能// 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,點(diǎn)亮LED0GPIOE->BSRR|=0x00200000;}// GPIOE->ODR|=0xFFFF;//恢復(fù)PE都為高電平GPIOE->BSRR|=0x00000030;//設(shè)置PE5(00000020)與設(shè)置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位數(shù)進(jìn)行位或運(yùn)算,所以在設(shè)置低位BS4、BS5時(shí),高位BR4、BR5也同時(shí)進(jìn)行了設(shè)置,但是以低位設(shè)置為優(yōu)先級(jí)
好好理解下圖標(biāo)注的地方!!!英文原話:Note: If both BSx and BRx are set, BSx has priority


還可以用位移方法:

完整準(zhǔn)確代碼:

#include "sys.h" #include "stm32f10x.h"int main(void){ uint16_t x;//定義一個(gè)16位的數(shù)//KEY0 PE4 CFN+MODE 1000//LED0 PE5 CFN+MODE 0011RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE , ENABLE);//時(shí)鐘使能 // 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,點(diǎn)亮LED0GPIOE->BSRR=1<<21;//亮燈}//GPIOE->ODR|=0xFFFF;//恢復(fù)PE都為高電平GPIOE->BSRR|=1<<5;//滅燈GPIOE->BSRR|=1<<4;//按鍵恢復(fù)懸空(沒辦法,只能設(shè)置為高電平)/*也可以如下:(去掉或)*///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寄存器實(shí)現(xiàn),第6部分總結(jié)。

3、舉例2

再把上面的控制蜂鳴器發(fā)聲的程序用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);//時(shí)鐘使能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位被保留,所以可以把它當(dāng)做是16位寄存器。它的作用是將對應(yīng)的0~15 IO口清零。即當(dāng)對應(yīng)位為1時(shí),對應(yīng)IO口置0,當(dāng)對應(yīng)位為0時(shí),對應(yīng)IO口保持原來的狀態(tài)。

編程時(shí),只需:GPIO(A~E)=1<<m,即可將PXm置0。

2、舉例

點(diǎn)亮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);//時(shí)鐘使能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;//其實(shí)本來初始狀態(tài)就是亮的,沒必要再次點(diǎn)亮,,只是為了說明這個(gè)寄存器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

上述程序中,死循環(huán)中的兩行代碼就是通過GPIOB_BRR和GPIOE_BRR分別操作GPIOB_ODR和GPIOE_ODR來分別控制PB5和PE5輸出低電平。

7、端口配置鎖定寄存器(GPIOx_LCKR) (x=A…E)

1、詳述

端口配置鎖定寄存器是為了鎖住GPIO的配置,在下次系統(tǒng)復(fù)位前不讓其工作(只要下次復(fù)位不執(zhí)行該寄存器,就不會(huì)被鎖了)。
注意:鎖住的是端口配置寄存器CRL或CRH

之前總結(jié)過端口配置寄存器GPIOx_CRL和GPIOx_CRH,對于每個(gè)IO,在寄存器中對應(yīng)4位,即控制輸入輸出模式的2位CFN,控制speed的2位MODE。當(dāng)端口寄存器鎖住某IO口后,對應(yīng)的CRL或CRH中對應(yīng)的4位就被鎖住,此時(shí)不能配置該位的輸入、輸出模式,以及不能配置speed,此時(shí)該IO口就不能使用。

具體敘述一下:

首先第16位,即高16位的第1位為LCKK,要開啟鎖IO模式,必須先“開鎖”,開鎖密碼:寫1——>寫0——>寫1——>讀0——>讀1。最后的讀1可省略,但其它“密碼”順序、內(nèi)容都不能錯(cuò)。

開鎖程序:(GPIOB為例)

花了好長時(shí)間才調(diào)試成功(狗頭)

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時(shí),GPIOx_LCKR寄存器才可以被寫入,某位寫入1,則對應(yīng)的IO口被鎖住。

以PB5為例:

//開啟鎖定寄存器模式GPIOB->LCKR&=0x0000ffff;//LCKK寫入0GPIOB->LCKR=1<<5;//鎖定PB5
  • 1
  • 2
  • 3

2、舉例

例:同時(shí)配置LED0和LED1,但是LED0被GPIOB_LCKR寄存器鎖住,觀察兩個(gè)LED能否都被點(diǎn)亮。

直接代碼:

#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);//時(shí)鐘使能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;//點(diǎn)亮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

調(diào)試:
下載程序后,LED0一直熄滅,LED2一直亮。
分析:
程序開始時(shí)對GPIOB和GPIOE進(jìn)行了時(shí)鐘配置,接下來就是“開鎖”,然后就是對PB5“上鎖”,這些上面都總結(jié)了。

接下來配置PE5和PB5,然后把LED0熄滅(程序開始都清零,LED默認(rèn)處于點(diǎn)亮狀態(tài)),若LED0(PB5)的配置沒有被鎖住,則在死循環(huán)中LED0應(yīng)該被點(diǎn)亮,調(diào)試時(shí)LED0應(yīng)該常亮。

“開鎖”時(shí)一定要注意:第0~15位的值不能被改變,所以寫入0和1的時(shí)候要進(jìn)行與運(yùn)算和或運(yùn)算。

二、總結(jié)

1、幾種IO口輸出類型(以PB5和PB10為例)

1、使用GPIOB_ODR寄存器

置1:

GPIOB->ODR|=0x0420;//PB10和PB5都輸出高電平
  • 1

GPIOB->ODR=1<<5;//只操作PB5置1//GPIOB->ODR|=1<<5;//注意同時(shí)設(shè)置PB5和PB10時(shí)不用移位
  • 1
  • 2
  • 3
GPIOB->ODR=1<<10;//只操作PB10置1//GPIOB->ODR|=1<<510;//注意同時(shí)設(shè)置PB5和PB10時(shí)不用移位
  • 1
  • 2
  • 3

置0:

GPIOB->ODR&=0xfbdf;//同時(shí)將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只有一個(gè)引腳使用時(shí),才能通過移位運(yùn)算操作ODR寄存器

2、使用GPIOB_BSRR寄存器

置1:

GPIOB->BSRR|=0x00000420;//同時(shí)設(shè)置PB5和PB10為1 //GPIOB->BSRR=0x00000420;
  • 1
  • 2

注意:此時(shí)低位設(shè)置覆蓋了高位設(shè)置

GPIOB->BSRR|=1<<5;//單獨(dú)設(shè)置PB5為高電平//GPIOB->BSRR=1<<5;
  • 1
  • 2
GPIOB->BSRR|=1<<10;//單獨(dú)設(shè)置PB10為高電平//GPIOB->BSRR=1<<10;
  • 1
  • 2
/*同時(shí)設(shè)置PB5和PB10為高電平*/GPIOB->BSRR=1<<5;GPIOB->BSRR&=0;//清零GPIOB->BSRR=1<<10;
  • 1
  • 2
  • 3
  • 4

注意:上面代碼必須清零,否則第三行代碼移位時(shí),會(huì)把原來第5位的1左移到第15位,對PB15也產(chǎn)生了影響!

置0:

不能和32位數(shù)進(jìn)行與運(yùn)算、或運(yùn)算,否則低位設(shè)置會(huì)覆蓋高位,導(dǎo)致要不PB5、PB10置1、要不保持原來的狀態(tài)不變!

同時(shí)設(shè)置PB5和PB10

/*注意,一定要清零*/GPIOB->BSRR|=1<<21;//設(shè)置PB5GPIOB->BSRR&=0;//清零GPIOB->BSRR|=1<<26;//設(shè)置PB10
  • 1
  • 2
  • 3
  • 4

只設(shè)置一個(gè)IO的話,就把上述代碼第一行、第三行單獨(dú)拿出來就行了

3、使用GPIOB_BRR寄存器

該寄存器只能置0

GPIOB->BRR|=0x0420;//同時(shí)設(shè)置PB5、PB10為0//GPIOB->BRR=0x0420;
  • 1
  • 2

該寄存器是32位寄存器,但是高16位保留,所以可以當(dāng)做16位寄存器來使用,和16位數(shù)與、或運(yùn)算就行了。不過并不是所有單片機(jī)都可以這樣,應(yīng)該是這款單片機(jī)與、或運(yùn)算時(shí),是低位對齊,高位沒對齊就補(bǔ)0。并不是所有單片機(jī)都這樣,所以最好寫成32位的形式。

/*同時(shí)操作PB5、PB10 為0*//*注意:一定要清零*/GPIOB->BRR|=1<<5;//操作PB5為0GPIOB->BRR&=0;//清0GPIOB->BRR|=1<<10;//操作PB10為0
  • 1
  • 2
  • 3
  • 4
  • 5

4、小總結(jié)(比較重要)

使用寄存器與、或運(yùn)算比較麻煩,因?yàn)橐?6、32位的那個(gè)數(shù)。采用移位法可以操作ODR來輸出高低電平,但是如果IO占用復(fù)雜,移位法就會(huì)造成IO口紊亂,GPIOx只有一個(gè)IO口是,才可以用移位法控制ODR寄存器。

所以使用BSRR寄存器和BRR寄存器去解決移位時(shí)IO口紊亂的問題。但是BSRR寄存器高位和低位同時(shí)配置時(shí),低位會(huì)覆蓋高位的設(shè)置,所以推薦使用以下方法:

如果要控制IO輸出高低電平、采用BSRR和BRR寄存器來設(shè)置ODR寄存器,進(jìn)而控制對應(yīng)IO口。置1時(shí),采用BSRR進(jìn)行低位操作;置0時(shí),采用BRR寄存器。

總結(jié)

以上是生活随笔為你收集整理的STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx_LCKR作用和配置的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。