STM32的I/O口可以由軟件配置成如下8種模式:輸入浮空、輸入上拉、輸入下拉、模擬輸入、開漏輸出、推挽輸出、推挽式復用功能及開漏復用功能。每個I/O口由7個寄存器來控制:配置模式的端口配置寄存器CRL和CRH(模式、速度);數據寄存器IDR和ODR;置位/復位寄存器BSRR;復位寄存器BRR;鎖存寄存器LCKR。
I/O口模式:
通用輸出 | 推挽輸出(Push-Pull) | 可以輸出高、低電平,連接數字器件 | |
開漏輸出(Open-Drain) | 開漏引腳不連接外部的上拉電阻時,只能輸出低電平;如果需要同時具備輸出高電平的功能,則需要接上拉電阻 | ||
復用功能輸出 | 復用功能推挽輸出 | 片內外設功能(I2C的SCL,SDA) | GPIO口被用作第二功能時的配置情況(即並非作為通用IO口使用) |
復用功能開漏輸出 | 片內外設功能(TX1,MOSI,MISO,SCK,SS) | ||
輸入 | 模擬輸入 | 應用ADC模擬輸入,或者低功耗下省電 | |
浮空輸入 | 可以做KEY識別,外部按鍵輸入 | IO的電平狀態是不確定,完全由外部輸入決定 | |
下拉輸入 | IO內部下拉電阻輸入 | 不確定信號->低電平 | |
上拉輸入 | IO內部上拉電阻輸入 | 不確定信號->高電平 |
1.GPIO口配置步驟
①使能PORTx(x=A~G)
APB2外設時鍾使能寄存器(RCC_APB2ENR)
置1開啟。清0關閉。
8-2位使能GPIO G-A
Eg:RCC->APB2ENR| = 1 << 2; //使能PORTA時鍾
②配置IO口模式 低8位(CRL) 高8位(CRH)
端口配置低寄存器(GPIOx_CRL) (x=A..E)
Eg:GPIOA->CRL |= 0x00000003; //PA0推挽輸出
③配置端口輸入和輸出電平
端口輸入數據寄存器(GPIOx_IDR) (x=A..E)
端口輸出數據寄存器(GPIOx_ODR) (x=A..E)
Eg: GPIOA->ODR |= 1 <<8; //PA8輸出高
2.GPIO配置相關寄存器
端口位設置/清除寄存器(GPIOx_BSRR) (x=A..E)
ODR寄存器只進行置1操作,不支持寫0操作。用BSRR寄存器進行清除。
端口位清除寄存器(GPIOx_BRR) (x=A..E)
端口位清除寄存器(GPIOx_BRR) (x=A..E) 具體參看數據手冊
當執行正確的寫序列設置了位16(LCKK)時,該寄存器用來鎖定端口位的配置。位[15:0]用於鎖定GPIO端口的配置。在規定的寫入操作期間,不能改變LCKP[15:0]。當對相應的端口位執行了LOCK序列后,在下次系統復位之前將不能再更改端口位的配置。 每個鎖定位鎖定控制寄存器(CRL, CRH)中相應的4個位。
3.LED
//led.c //LED IO口初始化 void LED_Init(void) { RCC->APB2ENR|=1<<2; //使能PORTA時鍾 RCC->APB2ENR|=1<<5; //使能PORTD時鍾 GPIOA->CRH&=0XFFFFFFF0; GPIOA->CRH|=0X00000003;//PA8推挽輸出 GPIOA->ODR|=1<<8; //PA8輸出高 GPIOD->CRL&=0XFFFFF0FF; GPIOD->CRL|=0X00000300;//PD2推挽輸出 GPIOD->ODR|=1<<2; //PD2輸出高 } //led.h #ifndef __LED_H #define __LED_H #include "sys.h" //LED端口定義 #define LED0 PAout(8) // PA8 #define LED1 PDout(2) // PD2 void LED_Init(void); //初始化 #endif //main.c #include "sys.h" #include "usart.h" #include "delay.h" #include "led.h" int main(void) { Stm32_Clock_Init(9); //系統時鍾設置 delay_init(72); //延時初始化 LED_Init(); //初始化與LED連接的硬件接口 while(1) { LED0=0; LED1=1; delay_ms(300); LED0=1; LED1=0; delay_ms(300); } }
4.按鍵KEY輸入
//key.c #include "key.h" #include "delay.h" //按鍵初始化函數 //PA0 PA15 PC5設置成輸入 void KEY_Init(void) { RCC->APB2ENR|=1<<2; //使能PORTA時鍾 RCC->APB2ENR|=1<<4; //使能PORTC時鍾 JTAG_Set(SWD_ENABLE); //關閉JTAG 開啟SWD PA15占用了JTAG一個口 GPIOA->CRL&=0XFFFFFFF0; //PA0設置成輸入 GPIOA->CRL|=0X00000008; GPIOA->CRH&=0X0FFFFFFF; //PA15設置成輸入 GPIOA->CRH|=0X80000000; GPIOA->ODR|=1<<15; //PA15上拉 PA0默認下拉 GPIOC->CRL&=0XFF0FFFFF; //PC5設置成輸入 GPIOC->CRL|=0X00800000; GPIOC->ODR|=1<<5; //PC5上拉 } //按鍵處理函數 //mode:0不支持連續按;1,支持連續按 //響應優先級KEY0>KEY1>WK_UP u8 KEY_Scan(u8 mode) { static u8 key_up=1;//按鍵按松開標志 if(mode)key_up=1; //支持連按 if(key_up&&(KEY0==0||KEY1==0||WK_UP==1)) { delay_ms(10);//去抖動 key_up=0; if(KEY0==0) return KEY0_PRES; else if(KEY1==0) return KEY1_PRES; else if(WK_UP==1) return WKUP_PRES; }else if(KEY0==1&&KEY1==1&&WK_UP==0) key_up=1; return 0;// 無按鍵按下 } //key.h #ifndef __KEY_H #define __KEY_H #include "sys.h" #define KEY0_PRES 1 //KEY0按下 #define KEY1_PRES 2 //KEY1按下 #define WKUP_PRES 3 //WK_UP按下 #define KEY0 PCin(5) //PC5 #define KEY1 PAin(15) //PA15 #define WK_UP PAin(0) //PA0 WK_UP void KEY_Init(void); u8 KEY_Scan(u8 mode); #endif //main.c #include "sys.h" #include "usart.h" #include "delay.h" #include "led.h" #include "key.h" int main(void) { u8 t; Stm32_Clock_Init(9); delay_init(72); LED_Init(); KEY_Init(); LED0 = 0; while(1) { t=KEY_Scan(0); switch(t) { case KEY0_PRES: LED0=!LED0; break; case KEY1_PRES: LED1=!LED1; break; case WKUP_PRES: LED0=!LED0; LED1=!LED1; break; default: delay_ms(10); } } }