STM32F10x GPIO配置 之 位繫結
阿新 • • 發佈:2019-01-03
對GPIO進行未繫結,好處:加快對位操作的速度。
1、位繫結公式(操作不同地址區域的位,用下面不同的公式)
2、下面以GPIOA埠的配置進行講解:
3、對少量位進行繫結的程式例舉:
/************************************************************************************************** * 硬體平臺:STM32F103VC * 學習重點:GPIOx的位繫結 * 實現功能:對於GPIOA埠的第八位輸出 跟隨 高八位的輸入 **************************************************************************************************/ /*============================================================================= * 位繫結公式: * 1、SRAM區域 :0X2200 0000 ----0X200F FFFF * Aliasaddr = 0X22000000 + ( A -0X20000000 )*32 + n*4 * 2、片上外設區域 :0X4200 0000 ----0X400F FFFF * Aliasaddr = 0X42000000 + ( A -0X40000000 )*32 + n*4 * 引數解釋: * Aliasaddr : 設定“埠GPIOx的第n位”的暫存器_相應位的實際地址 * A : 埠GPIOx的基地址(GPIOx_BASE) + 相應暫存器的偏移地址 * n : 配置的是相應暫存器的第n位 * 暫存器的偏移地址 :CRL CRH IDR ODR BSRR BRR LCKR * 00H 04H 08H 0CH 10H 14H 18H =============================================================================*/ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_lib.h" //包含了所有的標頭檔案 它是唯一一個使用者需要包括在自己應用中的檔案,起到應用和庫之間介面的作用。 #include "stm32f10x_map.h" /*----------------------------------------------------------------------------------------------------------- *將GPIOA的第3位作為輸出引腳,暫存器ODR的偏移地址為0X0C * A = GPIOA_BASE + 0X0C = (APB2PERIPH_BASE + 0X0800) + 0X0C = ((PERIPR_BASE + 0X1000) + 0X0800) + 0X0C * = ((0X40000000 + 0X1000) + 0X0800) + 0X0C = 0X4001080C * n = 3 (設定暫存器ODR的第3位) * 將GPIOA的第11位作為輸入引腳,暫存器IDR的偏移地址為0X08 * A = GPIOA_BASE + 0X08 = (APB2PERIPH_BASE + 0X0800) + 0X08 = ((PERIPR_BASE + 0X1000) + 0X0800) + 0X08 * = ((0X40000000 + 0X1000) + 0X0800) + 0X08 = 0X40010808 * n = 11 (設定暫存器IDR的第11位) ------------------------------------------------------------------------------------------------------------*/ u32 *PAO0 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 0*4) ; u32 *PAO1 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 1*4) ; u32 *PAO2 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 2*4) ; u32 *PAO3 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 3*4) ; u32 *PAO4 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 4*4) ; u32 *PAO5 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 5*4) ; u32 *PAO6 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 6*4) ; u32 *PAO7 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 7*4) ; u32 *PAI8 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 8*4) ; u32 *PAI9 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 9*4) ; u32 *PAI10 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 10*4) ; u32 *PAI11 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 11*4) ; u32 *PAI12 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 12*4) ; u32 *PAI13 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 13*4) ; u32 *PAI14 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 14*4) ; u32 *PAI15 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 15*4) ; /* Private functions -----------------------------------------------------------------------------*/ /************************************************************************************************** * Function Name : main * Description : 從GPIOA.8-.16輸入一個電平訊號,GPIOA.0-.7口分別將對應引腳輸入的電平訊號輸出 * Input : None * Output : None * Return : None ****************************************************************************************************/ int main(void) { /*--------控制STM32引腳GPIOA.0 GPIOA.1推輓輸出高電平--------*/ //1、設定GPIOA的引腳的工作模式,即配置暫存器GPIOA_CRL 、 GPIOA_CRH //GPIOA.0-.7推輓輸出,速度50MHZ , GPIOA.8-.16浮空輸入 GPIOA->CRL = 0x33333333 ; // CNF0 = 00 MODE0 = 11 GPIOA->CRH = 0x44444444 ; // CNF0 = 01 MODE0 = 00 //2、配置暫存器GPIOA_ODR、GPIOA_IDR ,實現GPIOA.0輸出 跟隨 GPIOA.8的輸入 while(1) { /*----------------------第0位----------------------*/ if( *PAI8 == 1) //暫存器GPIOA->IDR的第8位為1,表示從在GPIOA.8口輸入了高電平 { *PAO0 = 1 ; //對暫存器GPIOA->ODR的第0位置一 } else { *PAO0 = 0 ; //對暫存器GPIOA->ODR的第0位清零 } /*----------------------第1位----------------------*/ if( *PAI9 == 1) //暫存器GPIOA->IDR的第9位為1,表示從在GPIOA.9口輸入了高電平 { *PAO1 = 1 ; //對暫存器GPIOA->ODR的第1位置一 } else { *PAO1 = 0 ; //對暫存器GPIOA->ODR的第1位清零 } /*----------------------第2位----------------------*/ if( *PAI10 == 1) //暫存器GPIOA->IDR的第10位為1,表示從在GPIOA.10口輸入了高電平 { *PAO2 = 1 ; //對暫存器GPIOA->ODR的第2位置一 } else { *PAO2 = 0 ; //對暫存器GPIOA->ODR的第2位清零 } /*----------------------第3位----------------------*/ if( *PAI11 == 1) //暫存器GPIOA->IDR的第11位為1,表示從在GPIOA.11口輸入了高電平 { *PAO3 = 1 ; //對暫存器GPIOA->ODR的第3位置一 } else { *PAO3 = 0 ; //對暫存器GPIOA->ODR的第3位清零 } /*----------------------第4位----------------------*/ if( *PAI12 == 1) //暫存器GPIOA->IDR的第12位為1,表示從在GPIOA.12口輸入了高電平 { *PAO4 = 1 ; //對暫存器GPIOA->ODR的第4位置一 } else { *PAO4 = 0 ; //對暫存器GPIOA->ODR的第4位清零 } /*----------------------第5位----------------------*/ if( *PAI13 == 1) //暫存器GPIOA->IDR的第13位為1,表示從在GPIOA.13口輸入了高電平 { *PAO5 = 1 ; //對暫存器GPIOA->ODR的第5位置一 } else { *PAO5 = 0 ; //對暫存器GPIOA->ODR的第5位清零 } /*----------------------第6位----------------------*/ if( *PAI14 == 1) //暫存器GPIOA->IDR的第14位為1,表示從在GPIOA.14口輸入了高電平 { *PAO6 = 1 ; //對暫存器GPIOA->ODR的第6位置一 } else { *PAO6 = 0 ; //對暫存器GPIOA->ODR的第6位清零 } /*----------------------第7位----------------------*/ if( *PAI15 == 1) //暫存器GPIOA->IDR的第15位為1,表示從在GPIOA.15口輸入了高電平 { *PAO7 = 1 ; //對暫存器GPIOA->ODR的第7位置一 } else { *PAO7 = 0 ; //對暫存器GPIOA->ODR的第7位清零 } } return 1 ; }
4、利用巨集定義函式對大量的位進行位繫結的步驟:
5、對大量的位進行位繫結的程式例舉:
/************************************************************************************************** * 硬體平臺:STM32F103VC * 學習重點:GPIOx的位繫結 * 實現功能:對於GPIOA埠的第八位輸出 跟隨 高八位的輸入 **************************************************************************************************/ /*============================================================================= * 位繫結公式: * 1、SRAM區域 :0X2200 0000 ----0X200F FFFF * Aliasaddr = 0X22000000 + ( A -0X20000000 )*32 + n*4 * 2、片上外設區域 :0X4200 0000 ----0X400F FFFF * Aliasaddr = 0X42000000 + ( A -0X40000000 )*32 + n*4 * 引數解釋: * Aliasaddr : 設定“埠GPIOx的第n位”的暫存器_相應位的實際地址 * A : 埠GPIOx的基地址(GPIOx_BASE) + 相應暫存器的偏移地址 * n : 配置的是相應暫存器的第n位 * 暫存器的偏移地址 :CRL CRH IDR ODR BSRR BRR LCKR * 00H 04H 08H 0CH 10H 14H 18H =============================================================================*/ /* Includes ------------------------------------------------------------------*/ #include "stm32f10x_lib.h" //包含了所有的標頭檔案 它是唯一一個使用者需要包括在自己應用中的檔案,起到應用和庫之間介面的作用。 #include "stm32f10x_map.h" ///*----------------------------------------------------------------------------------------------------------- // *將GPIOA的第3位作為輸出引腳,暫存器ODR的偏移地址為0X0C // * A = GPIOA_BASE + 0X0C = (APB2PERIPH_BASE + 0X0800) + 0X0C = ((PERIPR_BASE + 0X1000) + 0X0800) + 0X0C // * = ((0X40000000 + 0X1000) + 0X0800) + 0X0C = 0X4001080C // * n = 3 (設定暫存器ODR的第3位) // * 將GPIOA的第11位作為輸入引腳,暫存器IDR的偏移地址為0X08 // * A = GPIOA_BASE + 0X08 = (APB2PERIPH_BASE + 0X0800) + 0X08 = ((PERIPR_BASE + 0X1000) + 0X0800) + 0X08 // * = ((0X40000000 + 0X1000) + 0X0800) + 0X08 = 0X40010808 // * n = 11 (設定暫存器IDR的第11位) // ------------------------------------------------------------------------------------------------------------*/ // //u32 *PAO0 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 0*4) ; //u32 *PAO1 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 1*4) ; //u32 *PAO2 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 2*4) ; //u32 *PAO3 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 3*4) ; //u32 *PAO4 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 4*4) ; //u32 *PAO5 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 5*4) ; //u32 *PAO6 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 6*4) ; //u32 *PAO7 = (u32 *)(0X42000000 + (0X4001080C - 0X40000000)*32 + 7*4) ; // //u32 *PAI8 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 8*4) ; //u32 *PAI9 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 9*4) ; //u32 *PAI10 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 10*4) ; //u32 *PAI11 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 11*4) ; //u32 *PAI12 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 12*4) ; //u32 *PAI13 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 13*4) ; //u32 *PAI14 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 14*4) ; //u32 *PAI15 = (u32 *)(0X42000000 + (0X40010808 - 0X40000000)*32 + 15*4) ; /******************************快速位繫結**********************************************************/ /*----------------1、巨集定義要操作的暫存器地址---------------------------------------------*/ #define GPIOA_ODR (GPIOA_BASE + 0X0C) #define GPIOA_IDR (GPIOA_BASE + 0X08) #define GPIOB_ODR (GPIOB_BASE + 0X0C) #define GPIOB_IDR (GPIOB_BASE + 0X08) #define GPIOC_ODR (GPIOC_BASE + 0X0C) #define GPIOC_IDR (GPIOC_BASE + 0X08) #define GPIOD_ODR (GPIOD_BASE + 0X0C) #define GPIOD_IDR (GPIOD_BASE + 0X08) #define GPIOE_ODR (GPIOE_BASE + 0X0C) #define GPIOE_IDR (GPIOE_BASE + 0X08) /*----------------2、獲取埠GPIOx(A-E)的對應暫存器的某一操作位的位地址-------------------*/ // #define BitBand(Addr , BitNum) *( (volatile unsigned long *)(Addr & 0xf0000000) + 0x2000000 + ((Addr&0xfffff)*32) + (BitNum*4) ) // 因為 左移、右移 語句的執行速度比乘除法語句的運動速度快,所以將上述語句改成如下方式 #define BitBand(Addr , BitNum) *( (volatile unsigned long *)( (Addr & 0xf0000000) + 0x2000000 + ((Addr&0xfffff)<<5) + (BitNum<<2) ) ) /*----------------3、巨集定義函式,對固定的位繫結 進行功能封裝------------------------------*/ #define PAout(n) BitBand(GPIOA_ODR , n) #define PAin(n) BitBand(GPIOA_IDR , n) #define PBout(n) BitBand(GPIOB_ODR , n) #define PBin(n) BitBand(GPIOB_IDR , n) #define PCout(n) BitBand(GPIOC_ODR , n) #define PCin(n) BitBand(GPIOC_IDR , n) #define PDout(n) BitBand(GPIOD_ODR , n) #define PDin(n) BitBand(GPIOD_IDR , n) #define PEout(n) BitBand(GPIOE_ODR , n) #define PEin(n) BitBand(GPIOE_IDR , n) /* Private functions -----------------------------------------------------------------------------*/ /************************************************************************************************** * Function Name : main * Description : 從GPIOA.8-.16輸入一個電平訊號,GPIOA.0-.7口分別將對應引腳輸入的電平訊號輸出 * Input : None * Output : None * Return : None ****************************************************************************************************/ int main(void) { /*--------控制STM32引腳GPIOA.0 GPIOA.1推輓輸出高電平--------*/ //1、設定GPIOA的引腳的工作模式,即配置暫存器GPIOA_CRL 、 GPIOA_CRH //GPIOA.0-.7推輓輸出,速度50MHZ , GPIOA.8-.16浮空輸入 GPIOA->CRL = 0x33333333 ; // CNF0 = 00 MODE0 = 11 GPIOA->CRH = 0x44444444 ; // CNF0 = 01 MODE0 = 00 //2、配置暫存器GPIOA_ODR、GPIOA_IDR ,實現GPIOA.0輸出 跟隨 GPIOA.8的輸入 while(1) { /*----------------------第0位----------------------*/ if( PAin(8) == 1) //暫存器GPIOA->IDR的第8位為1,表示從在GPIOA.8口輸入了高電平 { PAout(0) = 1 ; //對暫存器GPIOA->ODR的第0位置一 } else { PAout(0) = 0 ; //對暫存器GPIOA->ODR的第0位清零 } /*----------------------第1位----------------------*/ if( PAin(9) == 1) //暫存器GPIOA->IDR的第9位為1,表示從在GPIOA.9口輸入了高電平 { PAout(1) = 1 ; //對暫存器GPIOA->ODR的第1位置一 } else { PAout(1) = 0 ; //對暫存器GPIOA->ODR的第1位清零 } /*----------------------第2位----------------------*/ if( PAin(10) == 1) //暫存器GPIOA->IDR的第10位為1,表示從在GPIOA.10口輸入了高電平 { PAout(2) = 1 ; //對暫存器GPIOA->ODR的第2位置一 } else { PAout(2) = 0 ; //對暫存器GPIOA->ODR的第2位清零 } /*----------------------第3位----------------------*/ if( PAin(11) == 1) //暫存器GPIOA->IDR的第11位為1,表示從在GPIOA.11口輸入了高電平 { PAout(3) = 1 ; //對暫存器GPIOA->ODR的第3位置一 } else { PAout(3) = 0 ; //對暫存器GPIOA->ODR的第3位清零 } /*----------------------第4位----------------------*/ if( PAin(12) == 1) //暫存器GPIOA->IDR的第12位為1,表示從在GPIOA.12口輸入了高電平 { PAout(4) = 1 ; //對暫存器GPIOA->ODR的第4位置一 } else { PAout(4) = 0 ; //對暫存器GPIOA->ODR的第4位清零 } /*----------------------第5位----------------------*/ if( PAin(13) == 1) //暫存器GPIOA->IDR的第13位為1,表示從在GPIOA.13口輸入了高電平 { PAout(5) = 1 ; //對暫存器GPIOA->ODR的第5位置一 } else { PAout(5) = 0 ; //對暫存器GPIOA->ODR的第5位清零 } /*----------------------第6位----------------------*/ if( PAin(14) == 1) //暫存器GPIOA->IDR的第14位為1,表示從在GPIOA.14口輸入了高電平 { PAout(6) = 1 ; //對暫存器GPIOA->ODR的第6位置一 } else { PAout(6) = 0 ; //對暫存器GPIOA->ODR的第6位清零 } /*----------------------第7位----------------------*/ if( PAin(15) == 1) //暫存器GPIOA->IDR的第15位為1,表示從在GPIOA.15口輸入了高電平 { PAout(7) = 1 ; //對暫存器GPIOA->ODR的第7位置一 } else { PAout(7) = 0 ; //對暫存器GPIOA->ODR的第7位清零 } } return 1 ; }