新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32的GPIO使用的函數剖析

        STM32的GPIO使用的函數剖析

        作者: 時間:2016-11-10 來源:網絡 收藏
        該文是自己學習了一段STM32后所寫,是對STM32使用固件庫編程最簡單的一段程序,是對固件庫函數的一部分進行解析。如有錯誤之處請指正,不勝感激。

        一、GPIO_Init函數解析1

        本文引用地址:http://www.104case.com/article/201611/317503.htm

        1、參數GPIO_TypeDef1

        2、參數GPIO_InitStruct2

        3、函數代碼詳解4

        4、備注6

        一、GPIO_Init函數解析

        首先來看一下GPIO_Init函數的原型voidGPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct)。這個函數的實現是在Stm32f10x_gpio.c文件中,若要使用該函數在相應的應用程序的前面包含Stm32f10x_gpio.h頭文件。

        1、參數GPIO_TypeDef

        該函數的第一個參數為GPIO_TypeDef,它是一個結構體類型,該類型在Stm32f10x.h中被定義。定義的原型為:

        typedefstruct

        {

        __IOuint32_tCRL;

        __IOuint32_tCRH;

        __IOuint32_tIDR;

        __IOuint32_tODR;

        __IOuint32_tBSRR;

        __IOuint32_tBRR;

        __IOuint32_tLCKR;

        }GPIO_TypeDef;

        在這個結構體類型當中有7個32(8字節)位的變量,這些變量在存儲空間的地址是相鄰的。打開STM32數據手冊不難看出,每個端口對應有16的引腳,由7個寄存器控制GPIO行為,并且這7個寄存器的順序也是連續的。各個端口都有相同的結構。STM32的固件庫就將這種結構抽象出一個類型GPIO_TypeDef。在操作寄存器之前你一定要有一個寄存器映射的操作,否則無法訪問指定的寄存器,在這里我們只需要映射一次而不需要映射7此。這樣做是不是很方便,也提高了代碼的可讀性,使代碼規范化。

        既然GPIO_Init的第一個參數GPIO_TypeDef的指針變量,這個指針變量存放的就是某一個端口的首地址。某一個程序的調用語句是這樣的GPIO_Init(GPIOD,&GPIO_InitStructure);//初始化GPIOD

        GPID是固件庫中定義的一個宏,在編譯的時候會宏展開,先列出與GPIOD端口地址映射有關的宏定義如下:

        #defineGPIOD((GPIO_TypeDef*)GPIOD_BASE)

        #defineGPIOD_BASE(APB2PERIPH_BASE+0x1400)

        #defineAPB2PERIPH_BASE(PERIPH_BASE+0x10000)

        #definePERIPH_BASE((uint32_t)0x40000000)

        看到了0x40000000這個數字是不是非常熟悉,它是外設的首地址。在STM32芯片的內部STM32有兩個,一個叫APB1,一個叫APB2。每一個APB橋都會管理很多外設。STM32F10x把這兩個APB的外設寄存器訪問地址放在了不同的存儲空間。0x10000就是APB2外設的存儲空間首地址相對于整個外設的偏移。而0x1400是GPIOD端口外設首地址相對于APB2外設的存儲空間首地址的偏移。這樣就找到了GPIOD外設的基地址了!而((GPIO_TypeDef*)GPIOD_BASE)可以同時實現所有控制GPIOD端口的7個寄存器的映射。若訪問某一個寄存器只需要通過指向GPIO_TypeDef變量的指針。

        2、參數GPIO_InitStruct

        第二個參數的為GPIO_InitTypeDef*GPIO_InitStruct。就是一個指向GPIO_InitTypeDef的地址。第一個參數只找到配置的目標寄存器,第二個參數就是對相應端口如何配置的數據參數。這些參數存儲在指向GPIO_InitTypeDef變量的首地址處。先列處該參數由來的一斷代碼

        GPIO_InitTypeDefGPIO_InitStructure;

        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;

        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;

        GPIO_InitTypeDef是一個結構體的變量,該變量在Stm32f10x_gpio.h頭文件中被定義,定義的原型如下:

        typedefstruct

        {

        uint16_tGPIO_Pin;

        GPIOSpeed_TypeDefGPIO_Speed;

        GPIOMode_TypeDefGPIO_Mode;

        }GPIO_InitTypeDef;

        GPIO_InitTypeDef的第一個變量為GPIO_Pin是一個16為的無符號數,該數只有16位,每一位代表一個引腳,若要配置某一個端口的某一個引腳只需要把相應的位設置為1就可以了。在STM32的固件庫中有如下引腳號定義:

        #defineGPIO_Pin_0((uint16_t)0x0001)/*!

        #defineGPIO_Pin_1((uint16_t)0x0002)/*!

        #defineGPIO_Pin_2((uint16_t)0x0004)/*!

        #defineGPIO_Pin_3((uint16_t)0x0008)/*!

        #defineGPIO_Pin_4((uint16_t)0x0010)/*!

        #defineGPIO_Pin_5((uint16_t)0x0020)/*!

        #defineGPIO_Pin_6((uint16_t)0x0040)/*!

        #defineGPIO_Pin_7((uint16_t)0x0080)/*!

        #defineGPIO_Pin_8((uint16_t)0x0100)/*!

        #defineGPIO_Pin_9((uint16_t)0x0200)/*!

        #defineGPIO_Pin_10((uint16_t)0x0400)/*!

        #defineGPIO_Pin_11((uint16_t)0x0800)/*!

        #defineGPIO_Pin_12((uint16_t)0x1000)/*!

        #defineGPIO_Pin_13((uint16_t)0x2000)/*!

        #defineGPIO_Pin_14((uint16_t)0x4000)/*!

        #defineGPIO_Pin_15((uint16_t)0x8000)/*!

        #defineGPIO_Pin_All((uint16_t)0xFFFF)/*!

        使用這些定義好的宏就方便多了,要配置某幾個引腳只需要把相應的引腳相或就可以了。若你要多某一個端口的所有為進行配置,那么只需要使用一個宏GPIO_Pin_All。簡單吧!哈哈!

        GPIOSpeed_TypeDef是一個枚舉變量,它用于存儲GPIO速度的參數,它的定義如下:

        typedefenum

        {

        GPIO_Speed_10MHz=1,

        GPIO_Speed_2MHz,

        GPIO_Speed_50MHz

        }GPIOSpeed_TypeDef;

        通過定義可以知道,GPIOSpeed_TypeDef的變量有三種取值,那么GPIO的速度有三種,

        枚舉變量的值

        對應的速度

        1

        10MHZ

        2

        2MHZ

        3

        50MHZ

        GPIOMode_TypeDef也是一個枚舉變量,它用于存儲GPIO工作的模式,它的定義如下:

        typedefenum

        {GPIO_Mode_AIN=0x0,

        GPIO_Mode_IN_FLOATING=0x04,

        GPIO_Mode_IPD=0x28,

        GPIO_Mode_IPU=0x48,

        GPIO_Mode_Out_OD=0x14,

        GPIO_Mode_Out_PP=0x10,

        GPIO_Mode_AF_OD=0x1C,

        GPIO_Mode_AF_PP=0x18

        }GPIOMode_TypeDef;

        設計這個枚舉變量的可取值有一定的意義。在第四位當中只用到了其中的高兩位,這兩位數據用來存儲到某一個引腳的模式控制位MODEx[1:0],而高四位用來標志某一些標志。

        高四位的取值

        意義

        0

        輸入模式

        1

        輸出模式

        2

        下拉輸入

        4

        上拉輸入

        3、函數代碼詳解

        上面是GPIO_Init函數參數的解釋。我在我們就可以進入GPIO_Init函數的內部看看了。

        先把函數的代碼列出,對代碼的解釋都放在了注釋當中,如下:

        voidGPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct)

        {

        uint32_tcurrentmode=0x00,currentpin=0x00,pinpos=0x00,pos=0x00;

        uint32_ttmpreg=0x00,pinmask=0x00;

        /*Checktheparameters*/

        assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

        assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));

        assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));

        /*----------------------------GPIOModeConfiguration-----------------------*/

        currentmode=((uint32_t)GPIO_InitStruct->GPIO_Mode)&((uint32_t)0x0F);

        if((((uint32_t)GPIO_InitStruct->GPIO_Mode)&((uint32_t)0x10))!=0x00)//若為輸出上拉就會配置GPIO的速度

        {

        /*Checktheparameters*/

        assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));

        /*Outputmode*/

        currentmode|=(uint32_t)GPIO_InitStruct->GPIO_Speed;

        }

        /*----------------------------GPIOCRLConfiguration------------------------*/

        /*Configuretheeightlowportpins*/

        if(((uint32_t)GPIO_InitStruct->GPIO_Pin&((uint32_t)0x00FF))!=0x00)//若對第八個引腳進行配置,GPIO_Pin的值某一位為1就會對該引腳配置

        {

        tmpreg=GPIOx->CRL;//暫存GPIO控制寄存器原來的值

        for(pinpos=0x00;pinpos<0x08;pinpos++)//掃描8次決定,查看哪一引腳需要配置,若//需要配置則進行配置

        {

        pos=((uint32_t)0x01)<

        /*Gettheportpinsposition*/

        currentpin=(GPIO_InitStruct->GPIO_Pin)&pos;//currentpin的值為0或者為pos

        if(currentpin==pos)//若為pos說明該位需要配置

        {

        pos=pinpos<<2;//pinpos的值乘以4得到某一引腳配置位的最低位號:0,4,8......28

        /*Clearthecorrespondinglowcontrolregisterbits*///用于屏蔽某一個引腳的配置位,使這4位為0

        pinmask=((uint32_t)0x0F)<

        tmpreg&=~pinmask;

        /*Writethemodeconfigurationinthecorrespondingbits*/

        tmpreg|=(currentmode<

        /*ResetthecorrespondingODRbit*/

        if(GPIO_InitStruct->GPIO_Mode==GPIO_Mode_IPD)//若為輸入下拉,需要打開相應的開關

        {

        GPIOx->BRR=(((uint32_t)0x01)<

        }

        else

        {

        /*SetthecorrespondingODRbit*/

        if(GPIO_InitStruct->GPIO_Mode==GPIO_Mode_IPU)//若為輸入下拉,需要打開相應的開關

        {

        GPIOx->BSRR=(((uint32_t)0x01)<

        }

        }

        }

        }

        GPIOx->CRL=tmpreg;//對低8個引腳配置寄存器賦值

        }

        /*----------------------------GPIOCRHConfiguration------------------------*/

        /*Configuretheeighthighportpins*/

        if(GPIO_InitStruct->GPIO_Pin>0x00FF)

        {

        tmpreg=GPIOx->CRH;

        for(pinpos=0x00;pinpos<0x08;pinpos++)

        {

        pos=(((uint32_t)0x01)<<(pinpos+0x08));

        /*Gettheportpinsposition*/

        currentpin=((GPIO_InitStruct->GPIO_Pin)&pos);

        if(currentpin==pos)

        {

        pos=pinpos<<2;

        /*Clearthecorrespondinghighcontrolregisterbits*/

        pinmask=((uint32_t)0x0F)<

        tmpreg&=~pinmask;

        /*Writethemodeconfigurationinthecorrespondingbits*/

        tmpreg|=(currentmode<

        /*ResetthecorrespondingODRbit*/

        if(GPIO_InitStruct->GPIO_Mode==GPIO_Mode_IPD)

        {

        GPIOx->BRR=(((uint32_t)0x01)<<(pinpos+0x08));

        }

        /*SetthecorrespondingODRbit*/

        if(GPIO_InitStruct->GPIO_Mode==GPIO_Mode_IPU)

        {

        GPIOx->BSRR=(((uint32_t)0x01)<<(pinpos+0x08));

        }

        }

        }

        GPIOx->CRH=tmpreg;

        }

        }

        4、備注

        assert_param函數是對參數的檢測。參數要么是邏輯0或者1。IS_GPIO_ALL_PERIPH也是一個宏,宏定義為:

        #defineIS_GPIO_ALL_PERIPH(PERIPH)(((PERIPH)==GPIOA)||

        ((PERIPH)==GPIOB)||

        ((PERIPH)==GPIOC)||

        ((PERIPH)==GPIOD)||

        ((PERIPH)==GPIOE)||

        ((PERIPH)==GPIOF)||

        ((PERIPH)==GPIOG))

        其他的參數檢測函數當中使用的宏都是相似的,具體可以查看相應的宏定義,在此不一一列出。

        對低8位的配置和對高8位的配置原理是一樣的。所以在此只對低8引腳配置進行說明。



        關鍵詞: STM32GPIO使函數剖

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 合江县| 卢氏县| 长阳| 龙门县| 上高县| 平山县| 永清县| 五常市| 武定县| 财经| 吐鲁番市| 中超| 河间市| 勃利县| 淮南市| 宝清县| 方山县| 维西| 湄潭县| 慈利县| 昌邑市| 行唐县| 雅江县| 舒城县| 二连浩特市| 平阴县| 基隆市| 南川市| 库尔勒市| 兴山县| 文化| 集安市| 清新县| 庆阳市| 桦川县| 胶州市| 尼木县| 遂宁市| 澄城县| 潼南县| 平舆县|