| 
            
            
             
              /* 单片机: 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);         }     } }
               
                       |