【秋招】嵌入式面試八股文 - GPIO 詳解
【秋招】嵌入式面試八股文 - 最全專欄(這專欄就夠 )
1. GPIO基本概念
Q: 什么是GPIO?它的基本功能是什么?
GPIO(通用輸入輸出端口)是微控制器上可以由用戶程序控制的引腳,可以配置為輸入或輸出模式。
基本功能:
- 數(shù)字輸入:讀取外部設(shè)備的高低電平狀態(tài)
- 數(shù)字輸出:向外部設(shè)備輸出高低電平信號(hào)
- 可配置為特殊功能引腳:連接到內(nèi)部外設(shè)(UART、SPI、I2C等)
- 中斷觸發(fā):檢測電平變化并觸發(fā)中斷
Q: GPIO的常見工作模式有哪些?
常見的GPIO工作模式:
- 輸入模式:浮空輸入:不連接上拉或下拉電阻上拉輸入:內(nèi)部連接上拉電阻下拉輸入:內(nèi)部連接下拉電阻模擬輸入:用于ADC采樣
- 輸出模式:推挽輸出:可主動(dòng)輸出高低電平開漏輸出:只能主動(dòng)下拉,需外接上拉電阻開源輸出:只能主動(dòng)上拉,需外接下拉電阻
- 特殊模式:復(fù)用功能:連接到內(nèi)部外設(shè)中斷模式:配置為輸入并啟用中斷功能
2. GPIO配置與使用
Q: 如何配置GPIO的輸入輸出模式?
以STM32為例的GPIO配置:
// 配置GPIO為輸出模式 void GPIO_OutputConfig(void) { // 使能GPIO時(shí)鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 定義GPIO初始化結(jié)構(gòu)體 GPIO_InitTypeDef GPIO_InitStructure; // 配置PA5為推挽輸出,50MHz GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } // 配置GPIO為輸入模式 void GPIO_InputConfig(void) { // 使能GPIO時(shí)鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 定義GPIO初始化結(jié)構(gòu)體 GPIO_InitTypeDef GPIO_InitStructure; // 配置PB1為上拉輸入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB, &GPIO_InitStructure); }
Q: 什么是GPIO的上拉和下拉電阻?它們的作用是什么?
上拉電阻:
- 將引腳默認(rèn)拉至高電平
- 防止引腳懸空,提高抗干擾能力
- 適用于連接常開開關(guān)、按鍵等
下拉電阻:
- 將引腳默認(rèn)拉至低電平
- 防止引腳懸空,提高抗干擾能力
- 適用于連接常閉開關(guān)等
作用:
- 定義引腳的默認(rèn)電平狀態(tài)
- 防止輸入引腳處于高阻態(tài)時(shí)受干擾
- 限制電流,保護(hù)GPIO和外部設(shè)備
Q: 推挽輸出和開漏輸出有什么區(qū)別?各自適用于什么場景?
推挽輸出:
- 由一對(duì)互補(bǔ)的MOS管組成(一個(gè)P-MOS和一個(gè)N-MOS)
- 可主動(dòng)輸出高電平和低電平
- 驅(qū)動(dòng)能力強(qiáng),上升沿和下降沿速度快
- 適用場景:LED驅(qū)動(dòng)、數(shù)字信號(hào)輸出、需要快速切換的場合
開漏輸出:
- 只有一個(gè)N-MOS管,只能主動(dòng)下拉
- 輸出高電平時(shí)需要外部上拉電阻
- 可實(shí)現(xiàn)線與功能(多個(gè)輸出連接到同一條線)
- 適用場景:I2C總線、多設(shè)備共享總線、電平轉(zhuǎn)換
3. GPIO中斷與防抖
Q: 如何配置GPIO中斷?常見的中斷觸發(fā)方式有哪些?
GPIO中斷配置步驟(以STM32為例):
void GPIO_InterruptConfig(void) { // 1. 配置GPIO為輸入模式 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); // 2. 配置EXTI線 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿觸發(fā) EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); // 3. 配置NVIC NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
常見的中斷觸發(fā)方式:
- 上升沿觸發(fā):信號(hào)從低電平變?yōu)楦唠娖綍r(shí)觸發(fā)
- 下降沿觸發(fā):信號(hào)從高電平變?yōu)榈碗娖綍r(shí)觸發(fā)
- 雙邊沿觸發(fā):信號(hào)發(fā)生任何電平變化時(shí)觸發(fā)
- 高電平觸發(fā):信號(hào)保持高電平時(shí)觸發(fā)
- 低電平觸發(fā):信號(hào)保持低電平時(shí)觸發(fā)
Q: 什么是按鍵抖動(dòng)?如何實(shí)現(xiàn)按鍵消抖?
按鍵抖動(dòng):機(jī)械按鍵按下或釋放時(shí),由于機(jī)械彈片的彈性作用,會(huì)在短時(shí)間內(nèi)產(chǎn)生多次接通和斷開,導(dǎo)致一次按鍵操作被誤判為多次。
軟件消抖方法:
- 延時(shí)消抖:
// 延時(shí)消抖 bool Button_Read(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { if(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == 0) { delay_ms(20); // 延時(shí)20ms if(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == 0) { return true; // 按鍵按下 } } return false; }
- 定時(shí)器采樣消抖:
// 定時(shí)器采樣消抖 #define DEBOUNCE_COUNT 5 uint8_t button_samples[DEBOUNCE_COUNT] = {0}; uint8_t sample_index = 0; // 在定時(shí)器中斷中調(diào)用(如10ms周期) void Button_SampleInTimer(void) { // 讀取當(dāng)前按鍵狀態(tài) button_samples[sample_index] = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0); sample_index = (sample_index + 1) % DEBOUNCE_COUNT; // 檢查是否所有樣本一致 bool all_same = true; for(int i = 1; i < DEBOUNCE_COUNT; i++) { if(button_samples[i] != button_samples[0]) { all_same = false; break; } } if(all_same) { // 按鍵狀態(tài)穩(wěn)定,可以處理 button_state = button_samples[0]; } }
- 狀態(tài)機(jī)消抖:
// 狀態(tài)機(jī)消抖 typedef enum { BUTTON_STATE_RELEASED, BUTTON_STATE_PRESSED, BUTTON_STATE_DEBOUNCING_PRESS, BUTTON_STATE_DEBOUNCING_RELEASE } ButtonState; ButtonState button_state = BUTTON_STATE_RELEASED; uint32_t debounce_time = 0; #define DEBOUNCE_DELAY 20 // 20ms消抖時(shí)間 // 在主循環(huán)或定時(shí)器中調(diào)用 void Button_StateMachine(void) { uint32_t current_time = GetTickCount(); bool button_raw = (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0); switch(button_state) { case BUTTON_STATE_RELEASED: if(button_raw) {
剩余60%內(nèi)容,訂閱專欄后可繼續(xù)查看/也可單篇購買
【秋招】嵌入式八股文最全總結(jié) 文章被收錄于專欄
雙非本,211碩。本碩均為機(jī)械工程,自學(xué)嵌入式,在校招過程中拿到小米、格力、美的、比亞迪、海信、???、大華、江波龍等offer。八股文本質(zhì)是需要大家理解,因此里面的內(nèi)容一定要詳細(xì)、深刻!這個(gè)專欄是我個(gè)人的學(xué)習(xí)筆記總結(jié),是對(duì)很多面試問題進(jìn)行的知識(shí)點(diǎn)分析,專欄保證高質(zhì)量,讓大家可以高效率理解與吸收里面的知識(shí)點(diǎn)!掌握這里面的知識(shí),面試絕對(duì)無障礙!