/* 單片機: STM32F107VCT6 ** 系統時鐘: 72MHz ** 外部晶振: 25MHz **/ #include <stm32f10x.h>
#define KEY_SYNC 0 // 若id!=0, 則認為是可能按下了按鍵id; 否則沒有按鍵按下 #define KEY_DOWN 1 // 經過SysTick採樣後才認為按鍵真的按下了 #define KEY_PROCESSING 2 // 開始處理按鍵 #define KEY_PROCESSED 3 // 按鍵處理完畢 #define KEY_UP 4 // 按鍵已鬆開 (沒有新按鍵按下時將保持這個狀態, key.id的值不會丟失)
// 0->1為不定長延時 // 1->2為15ms延時 // 3->4為n個15ms的延時, 直到按鍵鬆開
EXTI_InitTypeDef exti;
struct key_state { uint8_t id; uint8_t step; } key;
int main(void) { GPIO_InitTypeDef gpio; NVIC_InitTypeDef nvic; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOE, ENABLE); /* PE13~15為低電平點亮的LED燈 */ gpio.GPIO_Mode = GPIO_Mode_Out_PP; gpio.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_SetBits(GPIOE, gpio.GPIO_Pin); // 熄滅LED GPIO_Init(GPIOE, &gpio); /* PE10~12為低電平有效的按鍵 */ gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; gpio.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; GPIO_Init(GPIOE, &gpio); GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource10); GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource11); GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource12); SysTick_Config(0x107ac0); // 採樣用的定時器, 數值=72000000Hz*0.015s=1080000ticks=0x107ac0 // 允許執行外中斷處理函數 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); nvic.NVIC_IRQChannel = EXTI15_10_IRQn; nvic.NVIC_IRQChannelCmd = ENABLE; nvic.NVIC_IRQChannelPreemptionPriority = 0; // SysTick中斷不可搶占按鍵中斷 nvic.NVIC_IRQChannelSubPriority = 1; // 先處理SysTick後處理按鍵中斷 NVIC_Init(&nvic); // 開外中斷 exti.EXTI_Line = EXTI_Line10 | EXTI_Line11 | EXTI_Line12; exti.EXTI_LineCmd = ENABLE; exti.EXTI_Mode = EXTI_Mode_Interrupt; exti.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_Init(&exti); while (1) { // 按鍵處理 if (key.step == KEY_PROCESSING) { GPIOE->ODR ^= GPIO_Pin_12 << key.id; // 根據按鍵號切換指定LED燈的狀態 key.step = KEY_PROCESSED; } } }
void EXTI15_10_IRQHandler(void) { key.id = 0; key.step = KEY_SYNC; if (EXTI_GetFlagStatus(EXTI_Line10) == SET) { EXTI_ClearFlag(EXTI_Line10); key.id = 1; } if (EXTI_GetFlagStatus(EXTI_Line11) == SET) { EXTI_ClearFlag(EXTI_Line11); key.id = 2; } if (EXTI_GetFlagStatus(EXTI_Line12) == SET) { EXTI_ClearFlag(EXTI_Line12); key.id = 3; } // 關外中斷 exti.EXTI_LineCmd = DISABLE; EXTI_Init(&exti); }
void SysTick_Handler(void) { if (key.id == 0) return; if (key.step < KEY_PROCESSING) { if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_9 << key.id) == 0) key.step++; else { key.step = KEY_SYNC; // 按鍵提前鬆開, 無效 key.id = 0; exti.EXTI_LineCmd = ENABLE; EXTI_Init(&exti); } } else if (key.step == KEY_PROCESSED) { // 等待按鍵釋放 if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_9 << key.id) != 0) { key.step = KEY_UP; exti.EXTI_LineCmd = ENABLE; EXTI_Init(&exti); } } }
|