startup.c

Как обычно определим векторы обработчиков прерываний:

    0,                  /*!%5 RCC                          */                                           
    exti0_irq_handler,  /*!%6 EXTI Line0                   */                       
    0,                  /*!%7 EXTI Line1                   */
    0,                  /*!%29 TIM3                         */                  
    tim4_irq_hanlder,   /*!%30 TIM4                         */                  
    0,                  /*!%31 I2C1 Event                   */

Теперь приступим к самим обработчикам.

Обработчик exti0 мы возмем из Мигание светодиодов со сменой режима от внешнего прерывания немного доработов его:

/* exti0 irq handler */
void exti0_irq_handler(void) {
    if (EXTI->PR | EXTI_PR_PR0) {
        /* change leds */
        LED_PORT->ODR ^= GREEN_LED | RED_LED;
        /* clear pending irq */
        EXTI->PR |= EXTI_PR_PR0;
    }
    /* disable exti0 interrupt */
    EXTI->IMR &= ~EXTI_IMR_MR0;
}

Также добавим обработчик для таймера №4:

/* timer4 irq handler */
void tim4_irq_hanlder(void) {
    if (TIM4->SR & TIM_SR_UIF) {
        /* switch leds */
        LED_PORT->ODR ^= ALL_LEDS;
        /* clear status bit */
        TIM4->SR &= ~TIM_SR_UIF;
        /* enable exti0 interrupt */
        EXTI->IMR |= EXTI_IMR_MR0;
    }
}

В это обработчике мы меняем состояние все светодиодо, а заодно активируем прерывание exti0 которое мы деактивировали в обработчике exti0(борьба с дребезгом контактов).