Хороший пример, объединяющий в себе работу с USART, таймерами и прерываниями — это сервомоторчик, управляемый компьютером.

Сервомотор имеет три контакта — земля, сигнал и питание. Обычно они окрашены в стандартные цвета, земля — чёрная или коричневая, питание красное, а сигнал — жёлтый.

Управление сервомотором очень хорошо ложится на модуль ШИМ, поскольку сервомотор принимает повторяющийся сигнал с длительностью единицы, пропорциональной углу поворота. Конкретный период следования импульсов совершенно неважен, он лишь должен быть в пределах 20-50 Гц, но многие сервы позволяют и большую частоту импульсов. Важна лишь длительность «единицы», которую мы и смоделируем с помощью ШИМ.

Управлять будем через терминал, нажатие кнопки «w» будет увеличивать угол отклонения качалки, кнопка «s» будет его уменьшать. Используем USART1, ремапленный на пины PB6/PB7.

Управление по USART сервомотором через STM32VLDiscovery

#include "stm32f10x.h"

int main(void)
{
  RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
  AFIO->MAPR  |= AFIO_MAPR_USART1_REMAP;
  GPIOB->CRL  |= GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6_0 | GPIO_CRL_CNF7_0;
  USART1->BRR = 0x9C4/1;
  USART1->CR1 |= USART_CR1_TE | USART_CR1_RE;
  USART1->CR1 |= USART_CR1_UE;
  USART1->CR1 |= USART_CR1_RXNEIE;
  NVIC_EnableIRQ(USART1_IRQn);

  // Включаем порт ввода-вывода и настраиваем ножку PC7
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  // Включаем тактирование таймера
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  // Настраиваем таймер на использование 2 канала
  TIM3->CCER |= TIM_CCER_CC4E | TIM_CCER_CC4P;

  // Переводим 2 канал в режим ШИМ2
  TIM3->CCMR2|= TIM_CCMR2_OC4M_0 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2;

  // Настраиваем прескалер
  TIM3->PSC = 1000;

  // Настраиваем период таймера = 1000 циклов
  TIM3->ARR = 400;

  // Настраиваем скважность = 200 циклов
  TIM3->CCR4 = 20;

  // Включаем таймер
  TIM3->CR1 |= TIM_CR1_CEN;

  while(1);
}

void USART1_IRQHandler(void) {
  if (USART1->SR & USART_SR_RXNE) {    
    USART1->SR&=~USART_SR_RXNE;

    if(USART1->DR=='w') if(TIM3->CCR4<55) TIM3->CCR4+=1;
    if(USART1->DR=='s') if(TIM3->CCR4>15) TIM3->CCR4-=1;
  }
}

Ничего сложного, не правда ли?

Как всегда, вы можете скачать весь проект (для IAR): Servo_USART_Example.zip.