函數解釋
void GPIO_DeInit(GPIO_TypeDef* GPIOx);
- 作用:將指定GPIO端口的所有寄存器恢復為默認值。這會清除之前對該端口的所有配置,使其回到初始狀態。
- 使用方法:傳入要復位的GPIO端口指針,例如
GPIOA
、GPIOB
等。
void GPIO_AFIODeInit(void);
- 作用:將復用功能I/O(AFIO)的寄存器恢復為默認值。復用功能I/O用于將一些外設功能映射到特定的GPIO引腳上,該函數可清除這些映射配置。
- 使用方法:無需傳入參數,直接調用即可。
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
- 作用:根據
GPIO_InitStruct
結構體中的參數初始化指定的GPIO端口。該結構體包含了GPIO引腳的模式、速度等配置信息。 - 使用方法:傳入要初始化的GPIO端口指針和一個
GPIO_InitTypeDef
結構體指針。
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
- 作用:將
GPIO_InitTypeDef
結構體的成員初始化為默認值。通常在使用GPIO_Init
函數之前調用該函數,以確保結構體中的成員有合理的初始值。 - 使用方法:傳入一個
GPIO_InitTypeDef
結構體指針。
示例代碼
以下是一個簡單的示例,展示了如何使用這些函數來初始化GPIO端口:
#include "stm32f10x.h"int main(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 使能GPIOA時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 將GPIOA的所有寄存器恢復為默認值GPIO_DeInit(GPIOA);// 將復用功能I/O的寄存器恢復為默認值GPIO_AFIODeInit();// 將GPIO_InitStructure結構體的成員初始化為默認值GPIO_StructInit(&GPIO_InitStructure);// 配置GPIOA的引腳0為推挽輸出模式,最大速度為50MHzGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;// 根據GPIO_InitStructure結構體的參數初始化GPIOAGPIO_Init(GPIOA, &GPIO_InitStructure);while (1){// 點亮LEDGPIO_SetBits(GPIOA, GPIO_Pin_0);// 延時一段時間for (int i = 0; i < 1000000; i++);// 熄滅LEDGPIO_ResetBits(GPIOA, GPIO_Pin_0);// 延時一段時間for (int i = 0; i < 1000000; i++);}
}
代碼解釋
- 使能時鐘:在使用GPIO之前,需要先使能相應的時鐘。這里使用
RCC_APB2PeriphClockCmd
函數使能GPIOA的時鐘。 - 復位寄存器:調用
GPIO_DeInit
和GPIO_AFIODeInit
函數將GPIOA和復用功能I/O的寄存器恢復為默認值。 - 初始化結構體:調用
GPIO_StructInit
函數將GPIO_InitStructure
結構體的成員初始化為默認值。 - 配置GPIO:設置
GPIO_InitStructure
結構體的成員,指定要配置的引腳、模式和速度。 - 初始化GPIO端口:調用
GPIO_Init
函數根據GPIO_InitStructure
結構體的參數初始化GPIOA。 - 循環控制LED:在主循環中,使用
GPIO_SetBits
和GPIO_ResetBits
函數點亮和熄滅連接到GPIOA引腳0的LED。
通過以上步驟,你可以使用這些函數來配置和控制STM32的GPIO端口。
函數名 | 功能 | 參數說明 | 適用場景 |
---|---|---|---|
GPIO_SetBits | 將指定GPIO端口的指定引腳置為高電平(邏輯1) | - GPIOx :指定的GPIO端口,如GPIOA 、GPIOB 等- GPIO_Pin :指定的引腳,如GPIO_Pin_0 、GPIO_Pin_1 等 | 僅需將引腳拉高的場景,操作簡單直接 |
GPIO_ResetBits | 將指定GPIO端口的指定引腳置為低電平(邏輯0) | - GPIOx :指定的GPIO端口,如GPIOA 、GPIOB 等- GPIO_Pin :指定的引腳,如GPIO_Pin_0 、GPIO_Pin_1 等 | 僅需將引腳拉低的場景,操作簡單直接 |
GPIO_WriteBit | 將指定GPIO端口的指定引腳設置為指定的電平值 | - GPIOx :指定的GPIO端口,如GPIOA 、GPIOB 等- GPIO_Pin :指定的引腳,如GPIO_Pin_0 、GPIO_Pin_1 等- BitVal :電平值,Bit_SET 表示高電平,Bit_RESET 表示低電平 | 需要靈活設置引腳高低電平的場景 |
GPIO_Write | 將一個16位的值寫入指定的GPIO端口,一次性設置該端口所有引腳的電平狀態 | - GPIOx :指定的GPIO端口,如GPIOA 、GPIOB 等- PortVal :一個16位的值,用于設置端口所有引腳的電平 | 需要對一個端口的多個引腳進行批量操作的場景 |
這四個函數均為STM32標準庫中用于操作GPIO引腳輸出電平的函數,下面為你對比分析它們的區別,并給出使用示例。
函數區別分析
1. void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
- 功能:將指定GPIO端口的指定引腳置為高電平(邏輯1)。
- 特點:只能用于將引腳置高,操作簡單直接,適用于只需要將引腳拉高的場景。
2. void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
- 功能:將指定GPIO端口的指定引腳置為低電平(邏輯0)。
- 特點:只能用于將引腳置低,操作簡單直接,適用于只需要將引腳拉低的場景。
3. void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
- 功能:將指定GPIO端口的指定引腳設置為指定的電平值,電平值可以是高電平(
Bit_SET
)或低電平(Bit_RESET
)。 - 特點:可以靈活設置引腳的高低電平,通過傳入不同的
BitAction
參數來控制。
4. void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
- 功能:將一個16位的值寫入指定的GPIO端口,一次性設置該端口所有引腳的電平狀態。
- 特點:可以同時控制一個端口的所有16個引腳,適用于需要對多個引腳進行批量操作的場景。
示例代碼
以下是使用這四個函數的示例代碼:
#include "stm32f10x.h"int main(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 使能GPIOA時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 配置GPIOA的引腳0和引腳1為推挽輸出模式,最大速度為50MHzGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);while (1){// 使用GPIO_SetBits將引腳0置高GPIO_SetBits(GPIOA, GPIO_Pin_0);// 延時一段時間for (int i = 0; i < 1000000; i++);// 使用GPIO_ResetBits將引腳0置低GPIO_ResetBits(GPIOA, GPIO_Pin_0);// 延時一段時間for (int i = 0; i < 1000000; i++);// 使用GPIO_WriteBit將引腳1置高GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);// 延時一段時間for (int i = 0; i < 1000000; i++);// 使用GPIO_WriteBit將引腳1置低GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);// 延時一段時間for (int i = 0; i < 1000000; i++);// 使用GPIO_Write同時設置引腳0和引腳1的電平// 0x03 表示二進制 0000 0000 0000 0011,即引腳0和引腳1都置高GPIO_Write(GPIOA, 0x03);// 延時一段時間for (int i = 0; i < 1000000; i++);// 使用GPIO_Write同時設置引腳0和引腳1的電平// 0x00 表示二進制 0000 0000 0000 0000,即引腳0和引腳1都置低GPIO_Write(GPIOA, 0x00);// 延時一段時間for (int i = 0; i < 1000000; i++);}
}
代碼解釋
- 使能時鐘和配置GPIO:使能GPIOA的時鐘,并將GPIOA的引腳0和引腳1配置為推挽輸出模式。
- 使用
GPIO_SetBits
和GPIO_ResetBits
:分別將引腳0置高和置低,實現引腳0的電平翻轉。 - 使用
GPIO_WriteBit
:通過傳入Bit_SET
和Bit_RESET
參數,將引腳1置高和置低,實現引腳1的電平翻轉。 - 使用
GPIO_Write
:通過傳入不同的16位值,一次性設置引腳0和引腳1的電平狀態。
以下是三種GPIO控制方法的對比及效果分析:
1. 方法對比
方法1:GPIO_SetBits
和 GPIO_ResetBits
GPIO_SetBits(GPIOA, GPIO_Pin_0); // 置高電平
GPIO_ResetBits(GPIOA, GPIO_Pin_0); // 置低電平
- 原理:直接操作寄存器,通過宏定義實現。
- 特點:
- 代碼簡潔,無函數調用開銷,執行效率高。
- 專用于單一操作(置高或置低),功能明確。
方法2:GPIO_WriteBit
配合 Bit_RESET
和 Bit_SET
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); // 置低電平
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); // 置高電平
- 原理:通過函數調用設置電平,參數使用枚舉值(
BitAction
)。 - 特點:
- 代碼直觀,參數明確(
Bit_SET
/Bit_RESET
)。 - 靈活性高,可動態指定電平狀態(如通過變量控制)。
- 代碼直觀,參數明確(
方法3:GPIO_WriteBit
配合強制類型轉換
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0); // 置低電平
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1); // 置高電平
- 原理:強制將整數
0
和1
轉換為BitAction
類型。 - 特點:
- 功能上等同于方法2(
BitAction
內部對應0
和1
)。 - 缺點:代碼可讀性差,潛在兼容性風險(依賴枚舉底層實現)。
- 功能上等同于方法2(
2. 效果是否相同?
- 功能層面:三種方法最終均會修改GPIO輸出寄存器的對應位,實現引腳電平控制,效果完全相同。
- 性能層面:
- 方法1(宏操作)直接操作寄存器,無函數調用,效率最高。
- 方法2和方法3(函數調用)有輕微函數調用開銷,但實際應用中差異可忽略。
3. 代碼規范建議
-
推薦方法2:
使用Bit_SET
和Bit_RESET
,兼顧可讀性、規范性和靈活性。GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); // 正確寫法
-
避免方法3:
強制類型轉換會降低代碼可維護性,且不符合ST庫的設計意圖。 -
方法1的適用場景:
若需極致性能(如高頻信號控制),可優先選擇GPIO_SetBits
/GPIO_ResetBits
。
4. 補充說明
- 條件編譯
#if 0
的作用:
代碼中被#if 0
包裹的部分會被編譯器忽略,僅用于臨時禁用代碼塊。
若要啟用方法1或方法2,需將對應的#if 0
改為#if 1
。
總結
三種方法在功能上完全等效,但代碼風格和可維護性差異顯著。推薦優先使用方法2(Bit_SET
/Bit_RESET
),既能保證效率,又符合工程規范。