Хороший пример, объединяющий в себе работу с USART, таймерами и прерываниями — это сервомоторчик, управляемый компьютером.
Сервомотор имеет три контакта — земля, сигнал и питание. Обычно они окрашены в стандартные цвета, земля — чёрная или коричневая, питание красное, а сигнал — жёлтый.
Управление сервомотором очень хорошо ложится на модуль ШИМ, поскольку сервомотор принимает повторяющийся сигнал с длительностью единицы, пропорциональной углу поворота. Конкретный период следования импульсов совершенно неважен, он лишь должен быть в пределах 20-50 Гц, но многие сервы позволяют и большую частоту импульсов. Важна лишь длительность «единицы», которую мы и смоделируем с помощью ШИМ.
Управлять будем через терминал, нажатие кнопки «w» будет увеличивать угол отклонения качалки, кнопка «s» будет его уменьшать. Используем USART1, ремапленный на пины PB6/PB7.
#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.
Свежие комментарии