Говоря о прерываниях, невозможно не рассказать о так называемых внешних прерываниях. За страшным названием стоит просто прерывание от переключения входной ножки. Да, в PIC была одна или две специальных ножки, умеющих генерировать прерывания — тут же таких ножек вагон. Работает всё точно так же, как и во втором проекте — разве что нужно настроить ножку на вход.

17. Прерывания EXTI

При задании прерывания EXTI нужно задать порт–источник и пин–источник прерывания. Также нужно указать реакцию (прерывание или событие — разница пока не важна, выбираем прерывание), тип перепада (только фронт, только спад или и то и другое) и линию EXTI — просто номер EXTI–прерывания, одного из 5.

void init_EXTI()
{  
  EXTI_InitTypeDef EXTI_InitStructure;

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}

Обработчик прерывания будет тот же, что и во втором проекте. Отличие только в названии обработчика (векторе прерывания) и проверяемых флагах.

int state=0;

void EXTI0_IRQHandler(void)
{ 
  if (EXTI_GetITStatus(EXTI_Line0))
  { 
    EXTI_ClearITPendingBit(EXTI_Line0);
    if(state)
      GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_SET);
    else
      GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_RESET);
    state = 1 - state; 
  }
}

18. NVIC — приоритетный контроллер прерываний

Однако так ничего работать не будет. Прерывания EXTI обслуживаются через контроллер прерываний, который называется NVIC — значит, нам нужно его настроить. Здесь тоже всё довольно просто: назначаем источник (прерывание EXTI0), приоритет и состояние (включен/выключен). Инициализируем.

void init_NVIC()
{  
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);   
}

Весь код 4 проекта полностью

#include "stm32f10x_conf.h"

void init_GPIO()
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
}

int state=0;

void EXTI0_IRQHandler(void)
{ 
  if (EXTI_GetITStatus(EXTI_Line0))
  { 
    EXTI_ClearITPendingBit(EXTI_Line0);
    if(state)
      GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_SET);
    else
      GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_RESET);
    state = 1 - state; 
  }
}

void init_EXTI()
{  
  EXTI_InitTypeDef EXTI_InitStructure;

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}

void init_NVIC()
{  
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);   
}

void main()
{
  init_GPIO();
  init_EXTI();
  init_NVIC();
  while(1) ;
}

Скачать архив 4 проекта.

Весь цикл:

1. Порты ввода–вывода

2. Таймер и прерывания

3. Выходы таймера

4. Внешние прерывания и NVIC

5. Ставим FreeRTOS