Buderus-trade.ru

Теплотехника Будерус
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Русские Блоги

Русские Блоги

Способ задержки во встраиваемой системе, его преимущества и недостатки

Реализация задержки во встроенной системе

1. Полная аппаратная реализация

использовать Емкость и сопротивление Для завершения конкретного Задержка колебаний эффект

Время задержки изменить нельзя.

2. Чистый программный метод (неточный, загружает процессор)


3. Программируемый таймер / счетчик в микроконтроллере.

Разница между основным таймером, общим таймером и расширенным таймером в STM32 F103 (включая разницу между шиной и функцией)

Функция: Подсчет = основной таймер + вход и выход, захват = общий таймер + вход тормозного сигнала, 7-канальный дополнительный выход сигнала = расширенный таймер

Каковы источники таймера?

  • Внутренние часы (системные часы) от умножителя частоты, вход которого APB1 или APB2
  • Режим внешних часов 1: Внешний входной контакт; 2: Внешний триггерный вход ETR
  • Внутренний штифт
  • Другие таймеры

Режим работы таймера

Режим счета (на примере обычного таймера)

Режим сравнения выходов

Входной режим захвата

Сначала установите захват входа как обнаружение нарастающего фронта и запишите значение TIMx_CNT при возникновении нарастающего фронта. Затем настройте сигнал захвата для захвата по заднему фронту и захвата по заднему фронту и запишите значение TIMx_CNT в это время. Таким образом, разница между значениями двух TIMx_CNT до и после составляет ширину импульса высокого уровня. В то же время, в соответствии с частотой счета TIM, мы можем знать точное время ширины импульса высокого уровня.

Одноимпульсный режим

Режим ШИМ

Роль ШИМ и его реализация

PWM( Широтно-импульсная модуляция ), упомянутый Импульсная модуляция , Как следует из названия, относится к Для управления шириной импульса это способ использования цифрового выхода микроконтроллера для управления аналоговой схемой. Очень эффективная технология


Метод реализации

(1) Традиционный метод цифровой схемы . Используя традиционную цифровую схему для реализации ШИМ, конструкция схемы более сложная, объем большой, способность к помехам слабая, а цикл управления системой длиннее.

(2) Режим моделирования общего ввода / вывода микроконтроллера . В ситуации, когда в микроконтроллере нет функции вывода ШИМ, вывод ШИМ может быть реализован путем управления обычным портом ввода-вывода с помощью ЦП. Однако реализация ШИМ таким образом потребует много времени, что значительно снизит эффективность ЦП, а точность полученного сигнала ШИМ не очень высока.

(3) Режим прямого вывода ШИМ микроконтроллера . Для микроконтроллеров с функцией вывода ШИМ после простой настройки импульсы ШИМ могут выводиться на указанные выводы микроконтроллера. Это также наиболее часто используемая реализация ШИМ в настоящее время.

Разница между ШИМ и режимом сравнения выходов

Режим PWM — это особая форма режима сравнения выходов , режим pwm Генерируется по четырем каналам на соответствующем таймере Частота синхронизирована (т.е. одинакова) ,а также Режим сравнения выходов Может генерироваться по четырем каналам Разная частота , Но все они выводят сигналы с разной скважностью. 。

Установка начального значения предделителя, автоперезагрузки, регистра захвата / сравнения в таймере

CCR: регистр захвата / сравнения, включая вход захвата (измерение частоты импульсов) и выход сравнения (сравнение двух импульсов)

Инициализируйте входной канал захвата. Вызов функции: TIM_ICInit ();

ARR: автоматическая перезагрузка регистра

PSC: Функция регистра предделителя:

Перед событием обновления (UEV) коэффициент предварительного делителя равен 1, один отсчет за такт; после UEV коэффициент предварительного делителя равен 2, два всегда считаются за цикл

Расчет времени задержки таймера

Время задержки = (Timx_ARR + 1) * (TIMx_PSC + 1) / TIMxCLK

пример:

Если взять, например, тактовую частоту 72 МГц, если вы хотите посчитать 500 мкс, каково значение предварительного делителя и значение счета?

Решение: тактовая частота составляет 72 МГц, а тактовый период — 1/72000000.
s, 500us требует 500 * 72 тактовых циклов. Если значение предварительного делителя равно 71, тактовая частота счетчика составляет 1 МГц, период тактовой частоты составляет 1/1000000 с,
Для 500us требуется 500 тактов, значение счетчика — 499.

14.7. Канал захвата

Для обнаружения внешних событий и фиксации момента их возникновения любой их каналов захвата-сравнения может использоваться в роли канала захвата. Для выполнения захвата счетчик необходимо перевести в нормальный режим работы.

Захват могут инициировать любые события системы событий, в т.ч. изменение состояния на любом из выводов. От заданных для таймера-счетчика действий события будет зависеть тип выполняемого захвата.

Перед выполнением захвата необходимо разрешить работу требуемого канала захвата-сравнения. При возникновении условия захвата, таймер-счетчик зафиксирует момент возникновения события путем копирования текущего значения регистра счетчика в регистр разрешенного канала захвата-сравнения.

Если в качестве источника события для захвата используются линии ввода-вывода, их необходимо настроить на обнаружение фронтов. Более детально о такой настройке линий ввода-вывода см. в 13.6 «Настройка параметров контроля входа». После захвата, если значение в регистре периода будет меньше 0x8000, в старшем бите регистра захвата будет запомнена полярность фронта на линии ввода-вывода. Равенство старшего бита регистра захвата нулю означает, что захват инициирован падающим фронтом. Если же старший бит окажется равным единице, то захват вызвал нарастающий фронт.

Поддерживается три различных типа захвата.

14.7.1. Входной захват

Читайте так же:
Счетчик беременности от дня зачатия

Если в качестве действия события выбрать «входной захват», то при возникновении любого события в разрешенном канале захвата будет выполнен входной захват. О доступности действительных данных в соответствующем регистре захвата-сравнения сигнализируют флаги прерываний. Точно также о доступности действительных данных в регистрах буферов сигнализируют флаги действительности буферов. Подробности о двойной буферизации захвата см. в 14.5 «Двойная буферизация».

Счетчик выполняет непрерывный счет от BOTTOM к TOP, а затем заново начинает счет с BOTTOM и т.д. (см. рисунок 14.9). На рисунке также показаны четыре события захвата в одном канале захвата.

Рисунок 14.9. Временная диаграмма захвата входа

14.7.2. Захват частоты

Если в качестве действия события выбрать «захват частоты», то при возникновении любого события в разрешенном канале захвата будет выполняться входной захват и рестарт. Данный тип захвата позволяет измерять частоту или период сигнала. Результатом захвата является интервал времени T от предыдущего рестарта таймера-счетчика до возникновения события. Зная его, можно легко вычислить частоту f сигнала: f = 1/T.

На рисунке 14.10 показан пример, где дважды измеряется период внешнего сигнала.

Рисунок 14.10. Захват частоты внешнего сигнала

Поскольку все каналы захвата используют один и тот же счетчик (CNT), активным в текущий момент времени может быть только один из каналов захвата. Если же все-таки использовать два канала захвата с различными источниками, то рестарт счетчика будет выполняться по положительным фронтам событий обоих входных источников и, поэтому, входной захват будет бесполезным.

14.7.3. Захват длительности импульса

Если в качестве действия события выбрать «измерение длительности импульса», то разрешенный канал событий будет выполнять входной захват по падающему фронту события и перезапускать таймер по нарастающему фронту. В результате, счетчик будет обнуляться в начале каждого импульса, а в конце импульса будет выполнен входной захват. Источником событий должна быть линия ввода-вывода с настроенной генерацией событий по обоим фронтам. На рисунке 14.11 показан пример, где дважды выполняется измерение длительности импульсов внешнего сигнала.

Рисунок 14.11. Захват длительности импульса внешнего сигнала

14.7.4. 32-битный входной захват

Совместное использование двух таймеров-счетчиков позволяет добиться 32-битного входного захвата. Типичная настройка 32-битного входного захвата подразумевает подключение события переполнения младшего таймера к входу старшего таймера через систему событий. С учетом конвейеризации всех событий обновление старшего таймера произойдет с задержкой в один период синхронизации УВВ после возникновения переполнения в младшем таймере. Для компенсации этой задержки у старшего таймера необходимо установить бит задержки события.

14.7.5. Переполнение захвата

Таймер-счетчик способен обнаружить переполнение буфера в любом из каналов входного захвата. В ситуации, когда установлены оба флага действительности буфера и прерывания по захвату и, при этом, обнаруживается новое событие захвата, просто не куда записать новую отметку времени. При обнаружении переполнения буфера новое значение теряется, устанавливается флаг прерывания по ошибке и (опционально) генерируется прерывание.

Урок 16. Таймеры STM32 в режиме счетчиков. Генерация циклических прерываний от таймеров.

Уроки STM32

В уроке познакомимся с таймерами микроконтроллера, научимся конфигурировать их в режиме счетчика и организовывать циклические прерывания.

В предыдущем уроке я рассказывал о выполнении задач параллельными процессами. Для реализации такого способа необходимо формировать циклические прерывания с заданным периодом. Опять же в предыдущем уроке было сказано, что логичнее и проще это делать с помощью аппаратных таймеров.

В этом уроке мы будем рассматривать таймеры в качестве именно такого функционального применения. Т.е. будем использовать их для генерации циклических прерываний.

Таймеры STM32.

У нашего микроконтроллера STM32F103C8T6 есть 4 таймера:

  • TIM1 – расширенный таймер, ориентированный на управление электродвигателем.
  • TIM2 … TIM4 – таймеры общего назначения.

Все таймеры имеют одинаковую архитектуру. Расширенный таймер отличается наличием дополнительных аппаратных узлов для формирования противофазных сигналов ШИМ. В результате его можно конфигурировать на работу в режиме 6-канального ШИМ и управлять им тремя полумостовыми усилителями мощности.

Но сейчас нас это не интересует. Для нашей задачи — формирования циклических прерываний, все таймеры имеют одинаковую архитектуру.

Таймеры STM32 — многофункциональные устройства. С помощью каждого из них можно реализовать:

  • Счетчик импульсов, а значит и времени с автоматической перезагрузкой.
  • Захват входного сигнала (4 канала).
    • Обнаружение фронта входного сигнала, запоминание времени, генерация события.
    • Измерение временных параметров входного ШИМ-сигнала: периода и длительности импульсов.
    • Интерфейс энкодера. Измерение параметров импульсов энкодера.
    • Генерация события по совпадению кода таймера с заданным значением.
    • Формирование ШИМ-сигнала.
    • Формирование одиночных импульсов, режим одновибратора.

    У таймеров большой выбор источников тактирования, есть предделители, обеспечивается цифровая фильтрация входных сигналов, возможна синхронизация между собой и много еще чего.

    Но сейчас нас интересует исключительно режим счетчика с перезагрузкой. Именно в этом режиме удобнее всего формировать циклические прерывания.

    Функциональная схема таймера достаточно сложная. Я выделил только необходимую нам часть.

    Функциональная схема TIM1

    Собственно отсчет импульсов или времени происходит на 16-ти разрядном счетчике CNT. Когда код счетчика достигает значения регистра перезагрузки, счетчик сбрасывается в 0. Таким образом, счетчик считает по циклу от 0 до значения регистра перезагрузки.

    Частота сигнала тактирования таймера может быть уменьшена с помощью 16-ти разрядного предделителя PSC.

    Перезагрузка счетчика формирует событие (прерывание). Частота его появления также может быть уменьшена счетчиком повторов (8 разрядов). Коэффициент деления задается в регистре повторов.

    Код счетчика используется другими узлами таймера, например, для формирования ШИМ. Но об этом в других уроках.

    В качестве источника тактирования могут быть выбраны:

    • Внутренние синхросигналы шин APB1 иAPB2, про которые мы говорили в уроке 5 (система тактирования микроконтроллера).
      • Для таймера TIM1 используется синхросигнал шины APB2;
      • Для таймеровTIM2- TIM4 используется синхросигнал шины APB1.

      Сейчас мы будем использовать только внутренний источник тактирования.

      Режимы счета таймера.

      При использовании таймера в качестве счетчика импульсов можно выбрать один из режимов:

      • прямой счет;
      • обратный счет;
      • двунаправленный.

      При прямом счете содержимое счетчика с каждым импульсом тактирования увеличивается на 1. Когда оно достигает значения регистра перезагрузки, то счетчик сбрасывается. Таким образом,таймер считает по циклу от 0 до значения перезагрузки. В момент перезагрузки формируется прерывание.

      В режиме обратного (реверсивного) счета с каждым входным импульсом содержимое счетчика уменьшается на 1. При достижении 0 в счетчик загружается значение регистра перезагрузки и реверсивный счет продолжается. Таймер считает по циклу от значения перезагрузки до 0. В момент перезагрузки формируется прерывание.

      Двунаправленный режим означает, что счетчик считает в прямом направлении от 0 до значения перезагрузки, а затем переходит в реверсивный режим и счет ведется до 0. При изменении направления счета и сбросе генерируется прерывание.

      Установка конфигурации таймера с помощью STM32CubeMX.

      Давайте научимся конфигурировать таймеры через STM32CubeMX. Заодно в строгой форме перечислим регистры, задающие режимы таймера и выясним, что конкретно в них загружать.

      Создадим проект Lesson16_1. Настроим конфигурацию системы тактирования. Обратим внимание на то, что частота тактирования таймеров на шинах APB1 и APB2 задана 72 мГц.

      STM32CubeMX

      • PC13 – активный выход;
      • PB13 – активный выход;
      • PB12 – вход с подтягивающим резистором.

      Установка выводов в STM32CubeMX

      Теперь будем конфигурировать таймер 1. В нашем микроконтроллере он самый многофункциональный.

      Открываем вкладку Timers ->TIM1.

      Выбираем в качестве источника тактирования внутреннее тактирование: Clock Source -> Internal Clock.

      Выбор источника тактирования

      Ниже появилось поле Parameter Settings.

      Установка параметров

      Давайте подробно разберем, что в нем.

      Prescaler (PSC).

      Это регистр предделителя. Предделитель делит частоту тактирования таймера, поступающую на основной счетчик. По сути, он, вместе с входной частотой, определяет разрешающую способность таймера.

      Счетчик предделителя считает входные импульсы от 0 до значения этого регистра. При равенстве кода счетчика и регистра счетчик сбрасывается и начинает считать заново. В момент сброса формируется импульс тактирования основного счетчика таймера. Таким образом, значение регистра предделителя определяет коэффициент деления частоты входного сигнала.

      Счетчик и регистр предделителя 16-ти разрядные. Т.е. максимальный коэффициент деления 65536.

      Надо помнить, что реальный коэффициент деления на 1 больше, чем значение регистра предделителя. Например:

      Значение регистра предделителяКоэффициент деления
      1
      9991000
      65535 (максимальное значение)65536

      Регистр предделителя имеет буферный регистр. Поэтому его значение можно устанавливать в любой момент. Реальное изменение коэффициента деления произойдет при перезагрузке буферного регистра в момент перезагрузки основного счетчика таймера.

      Counter mode.

      Режим счетчика, определяет в какую сторону считать.

      counter mode

      • Up – прямой счет.
      • Down – реверсивный счет.
      • Center Aligned mode 1 – двунаправленный счет, прерывание генерируется в момент, когда счетчик считает в обратную сторону и доходит до 0.
      • Center Aligned mode 2 – двунаправленный счет, прерывание генерируется, когда счетчик считает в прямом направлении и достигает значения перезагрузки.
      • Center Aligned mode 3 – двунаправленный счет, прерывание генерируется, в обоих случаях — при достижении 0 и значения перезагрузки.

      Counter Period (Auto Reload Register).

      Регистр перезагрузки. Его значение задает период работы таймера. Конечно, на время периода влияет еще режим счета.

      Счетчик 16-ти разрядный. Значит, для однонаправленного счета период может длиться от 1 до 65536 длительностей импульсов предделителя. Реальная длительность периода на 1 больше значения регистра перезагрузки. Все как для регистра предделителя.

      Internal Clock Division (CKD).

      Делитель входной частоты для внутренних нужд таймера.

      Internal Clock Division (CKD)

      Частота используется при фильтрации внешних сигналов, формировании “мертвого времени” ШИМ и т.п. Сейчас это нам не интересно.

      Repetition Counter (RCR).

      Регистр счетчика повторов. Присутствует не во всех таймерах. Счетчик повторов считает импульсы событий на выходе таймера и при достижении значения регистра повторов сбрасывается и формирует реальное событие. Т.е. он делит частоту генерации событий (прерываний) таймера.

      Счетчик 8-ми разрядный. Коэффициент деления на 1 больше значения регистра повторов и может быть в диапазоне 1 — 256. Регистр буферизирован, можно изменять его значения в любой момент.

      Auto-reload preload.

      Регистр перезагрузки буферизирован. Разработчики микроконтроллера предоставляют программисту выбор — при записи значения перезагрузки передавать его в регистр моментально или дождаться крайнего состояния счетчика.

      Управляет режимом перезагрузки специальный бит, а в STM32CubeMX выбор делается в выпадающем меню.

      Auto-reload preload

      Вкладка NVIC Settings позволяет выбрать нужный тип прерывания, связанного с таймером.

      Выбор прерывания

      Пример конфигурации таймера и реализации программы.

      Сделаем практическую задачу. Установим конфигурацию таймера 1, обеспечивающую циклические прерывания с периодом 0,5 секунд. В обработчике прерывания будем инвертировать состояние светодиода. В результате получим мигающий светодиод, но с использованием таймера и прерывания.

      Частота тактирования у нас 72 мГц. Превратим ее с помощью предделителя в круглое значение.

      Например, если задать 720 – 1 = 719, то частота после предделителя будет 72 000 000 / 720 = 100 000 Гц, или период 10 мкс.

      Если в регистр перезагрузки задать значение 50 000, то получим требуемый период 0,5 секунд.

      Конфигурация проекта

      Во вкладке NVIC Settings выберем прерывание по перезагрузке счетчика.

      Выбор прерывания

      Создаем проект и открываем его в Atollic TrueStudio.

      В папке Src проекта создан файл stm32f1xx_it.c. Он существовал и во всех предыдущих проектах. Просто мы на него до времени не обращали внимания.

      Это файл обработчиков прерываний. Хороший стиль размещать функции обработки прерываний в нем.

      В самом конце файла появилась функция:

      void TIM1_UP_IRQHandler(void) <

      /* USER CODE BEGIN TIM1_UP_IRQn 0 */
      /* USER CODE END TIM1_UP_IRQn 0 */

      /* USER CODE BEGIN TIM1_UP_IRQn 1 */
      /* USER CODE END TIM1_UP_IRQn 1 */
      >

      Это и есть обработчик прерывания таймера 1. Код, который мы поместим в функцию, будет вызываться с периодом 0,5 секунд.

      Вызовем в обработчике прерывания функции инверсии состояния для обоих светодиодов.

      void TIM1_UP_IRQHandler(void) <

      /* USER CODE BEGIN TIM1_UP_IRQn 0 */

      HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
      HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13);

      Мы установили конфигурацию таймера, но не запустили его. Сделаем это HAL-функцией в файле main.c.

      /* Initialize all configured peripherals */

      /* USER CODE BEGIN 2 */

      HAL_TIM_Base_Start_IT(&htim1); // запуск таймера

      Функция запускает таймер в режиме генерации прерываний.

      Все. Компилируем, загружаем, проверяем. Оба светодиода мигают раз в секунду.

      Полностью проект можно загрузить по ссылке:

      Зарегистрируйтесь и оплатите. Всего 60 руб. в месяц за доступ ко всем ресурсам сайта!

      Основной цикл у нас пустой. Программа просто крутится в нем.

      while (1) <

      /* USER CODE END WHILE */

      По отношению к нему светодиоды мигают в фоновом режиме, сами по себе. Если мы будем выполнять в цикле какие-либо действия, это никак не скажется на равномерном мигании светодиодов. Единственное условие – надолго не запрещать прерывания.

      В следующем уроке будем разрабатывать программу, обрабатывающую сигнал кнопки параллельным процессом. Научимся связывать переменные разных файлов одной программы. Разберемся в специфике использования функций обработки прерываний.

      STM32: Урок 6.2 — Таймеры общего назначения и продвинутые

      Продолжаем тему таймеров в STM32. В прошлый раз мы рассмотрели базовые таймеры, которые довольно-таки просты. Но сегодня мы поиграемся с более крутой игрушкой — таймерами общего назначения, которые на голову выше предыдущих.

      • До 4-х каналов для:
        • Захвата сигнала (input capture).
        • Сравнения вывода (output compare).
        • Генерации сигнала ШИМ (выровненного по границе или по центру).
        • Генерации одиночных импульсов.
        • Обновление: переполнение счётчика.
        • Событие-триггер: старт, остановка, инициализация счётчика или его обновление внутренним или внешним триггером.
        • Захват сигнала.
        • Сравнение (output compare).
        • Включение BRK.

        Вот как вы думаете, если у таймеров общего назначения так много функций, чем тогда продвинутые (advanced-control) таймеры отличаются от них? o_O
        Правильный ответ — почти ничем, это по факту просто таймеры общего назначения, которые не имеют никаких ограничений: в них напихано по 4 канала (с комплементарными) и есть все возможности сразу, без какого-то ни было разброса. Так что остальная часть статьи будет относиться ко всем таймерам выше базовых, а продвинутые таймеры я отдельно упоминать не буду.

        В даташите на STM32F100xx ( ещё ссылка ) есть сводная таблица возможностей таймеров, в которую тоже удобно поглядывать для справки:

        Кстати, обращайте внимание на сноски. Например, там написано, что у МК семейства Low density Value line нет таймера TIM4.

        Захват сигнала

        В этом режиме с выбранного канала захватываются импульсы, на каждый из них текущее значение счётчика таймера кладётся в регистр TIM_CCRx, где x — номер канала. Таким образом, период следования импульсов равен разнице между текущим значением TIM_CCRx и предыдущим. Ну а для того, чтобы получить период в каких-то внятных единицах измерения, нужно настроить предделитель через функции базового таймера.

        При этом можно настроить генерацию прерывания и запроса DMA на приход очередного импульса, и если в это время предыдущее значение TIM_CCRx не было считано, будет сгенерировано так называемое прерывание over-capture, т.е. сигнал о том, что предыдущее значение потерялось.

        Ловить можно фронты, спады или и то, и другое вместе. Есть настройка так называемого фильтра — числа выборок, после которого переход уровня будет считаться состоявшимся (полезно для устранения дребезга). Значение фильтра может принимать значения от 0 (фильтр выключен) до 15 (0xF). Также настраивается делитель входной частоты — 2, 4 или 8: будет ловиться каждый 2й, 4й или 8й импульс соответственно.

        Примера ради подёргаем вывод PB15 и замерим таймером TIM3 период, подключив PB15 к его каналу 1 (PA6):

        Также существует режим захвата ШИМ. На самом деле, это не отдельный режим, а просто особое сочетание настроек с таким эффектом. Таймер настраивается так, чтобы один канал ловил фронты и сбрасывал счётчик таймера, а второй ловил спады — тогда первый будет захватывать период ШИМ, а второй — заполнение. При этом оба канала подключаются к одному и тому же физическому входу. Суть работы этого «режима» показана в даташите следующим образом:

        Изменим предыдущий пример, используя захват ШИМ (прокомментированы только изменения):

        Режим чтения энкодера

        Работу с энкодером я уже как-то описывал , и тогда я считывал и декодировал данные с энкодера программно, здесь же таймер сделает работу за нас (не всю, конечно же). Боковые выводы энкодера надо подключить к двум каналам таймера, а средний вывод — к GND. Таймер в этом режиме сам обрабатывает поступающие с энкодера импульсы, а также увеличивает/уменьшает свой счётчик на 4 при каждом щелчке энкодера, и запоминает направление вращения.

        Так как мне захотелось ещё и прерывание заиметь, я сделал период равным 4 и разрешил счёт в обе стороны, так что теперь прерывание будет возникать при каждом щелчке энкодера. Использовал я каналы 1 и 2 таймера TIM3 (PA6 и PA7):

        Сравнение вывода (output compare)

        В этом режиме выбранный канал таймера будет подключен к соответствующему выводу и будет изменять его (вывода) состояние каждый раз, когда счётчик таймера досчитает до значения регистра TIM_CCRx. Состояние вывода, в зависимости от настройки, будет меняться на ноль, на единицу или на противоположное текущему. У многих таймеров у каналов есть комплементарные выводы, которые по умолчанию являются инверсными: на такой выход подаётся тот же сигнал, что и на обычный, но с противоположным уровнем.

        Смотрим в сводную таблицу по таймерам в даташите и видим, что комплементарных выводов у TIM3 нет, но вот у единственного канала таймера TIM16 есть такой вывод — этот таймер я и использую для примера. Вообще, комплементарные выводы есть и у нескольких других таймеров, но вот TIM15 — особенный: у него есть два канала, но комплементарный вывод имеет только 1й канал. Будьте бдительны!

        В таблице пинаутов находим выводы канала 1 таймера TIM16 — PB8 (основной) и PB6 (комплементарный). Для иллюстрации работы таймера подключим эти выводы к светодиодам на плате STM32VLDiscovery — PC8 и PC9, которые в коде мы отключим от греха подальше. Таким образом, выводы канала таймера будут напрямую мигать светодиодами:

        В это примере я выбрал режим переключения вывода в противоположное состояние (TIM_OCMode_Toggle), а остальные настройки оставил по умолчанию. Кстати, не забывайте вызывать функции типа TIM_OCStructInit() для инициализации соответствующих структур, даже если заполняете все поля структур вручную: copy&paste-ориентированное программирование никто не отменял, но при нём легко забыть заполнить какое-нибудь поле и ловить потом баги.

        Для обоих выводов канала можно настроить (поля TIM_OCPolarity и TIM_OCNPolarity структуры) так называемую «полярность» — состояние вывода в промежуток времени от начала отсчёта и до TIM_Pulse. По умолчанию для выводов выставляются значения TIM_OCPolarity_High и TIM_OCNPolarity_High, но комплементарный вывод является инверсным — поэтому, если на нём нужен обычный (не инверсный) сигнал, нужно ему выставить TIM_OCNPolarity_Low.

        В режиме сравнения генерируется то же самое прерывание, что и в режиме захвата сигнала — TIM_IT_CCx, но здесь оно было не нужно, поэтому я его не разрешал.

        Генерация ШИМ

        Вот это куда более интересная и практичная штука. Принципы ШИМ уже неоднократно были описаны — как на нашем сайте , так и у Di Halt’a (уж там разжёвано всё до мелочей), а я сосредоточусь на особенностях реализации в STM32.

        Настройка этого режима не слишком отличается от настройки output compare: вместо режима TIM_OCMode_Toggle нужно выбрать один из режимов ШИМ, тогда TIM_Period будет трактоваться как период ШИМ, а поле TIM_Pulse — как заполнение (duty cycle). Режимов ШИМ имеется два — выровненный по границе и по центру (edge-aligned и center-aligned). У микроконтроллеров AVR они называются Fast PWM и Phase Correct PWM, соответственно.

        Отличной иллюстрацией крутизны таймеров STM32 для генерации ШИМ будет типичная прикладная задача — управление сервомашинкой : Как известно, сервы управляются импульсами переменной ширины, которые шлются с частотой примерно 50 Гц (каждые 20 мс). У сервы, которая оказалась под рукой (Robbe 4.3 g), ширина управляющего импульса от 500 мкс (0°) до 2250 мкс (175°), судя по замерам — то есть, по 10 мкс на каждый градус поворота:

        ΔT = T₂ — T₁ = 2250 — 500 = 1750 мкс
        ∠A = 175°
        ΔT/A = 10 мкс/°

        1. Установить таймеру такой делитель частоты, чтобы отсчёт вёлся каждые 10 мкс.
        2. Задать период ШИМ в 20 мс, то есть 2000 отрезков времени по 10 мкс.
        3. Класть в регистр сравнения число, равное 50 (500 мкс / 10 мкс) + задаваемый угол.
        4. Регистр сравнения лучше обновлять строго в момент окончания периода во избежание дёргания сервы.

        Dead-time

        Если кто не знает, это задержка фронтов сигналов на основном и комплементарном выводах канала таймера. Эта функция есть у некоторых таймеров (смотрите руководство), и нужна она бывает для исключения сквозных токов при управлении силовыми ключами [полу]мостовых схем. Даже не спрашивайте меня, что это такое — это вне моей компетенции.

        Настраивается этот самый dead-time в поле TIM_DeadTime структуры TIM_BDTRInitTypeDef и имеет диапазон значений с 0 по 255 (0xFF). Но смысл этого числа не так уж прямолинеен:

        Ага, вот так оно и рассчитывается. Здесь Tdts — это длительность такта генератора dead-time (DTG), зависящая от Tdts — текущей частоты тактирования таймера. Обычно таймеры тактируются системной частотой, и TIM_Prescaler на это никак не влияет, а влияет поле TIM_ClockDivision структуры TIM_TimeBaseInitTypeDef — делитель частоты таймера.

        Для примера положим, что таймер затактирован без деления частоты (делитель равен 1, TIM_CKD_DIV1), системная частота F равна 24 МГц, а значение DTG = 150. Тогда:

        Tdts = 1/F = 1/24 мкс
        DTG = 150 = 100101102 ⇒ DTG[7:5] = 1002
        Tdtg = 2⋅Tdts = 1/12 мкс
        DT = (64 + DTG[5:0])Tdtg = (64 + 6)/12 = 5.8(3) мкс

        «Just like that» ☯ ChosunNinja

        Я тут для примера набросал код с dead-time попроще для расчёта: DTG=96 ⇒ DT=96.

        Для того, чтобы узреть этот самый dead-time на одноканальном осциллографе, нужно подключить PB8 и PB6 через резисторы 1 кОм к его щупу:

        Т.к. на эти выводы идут взаимно инверсные сигналы, на экране будут прекрасно видны места, где во время dead-time уровень на обоих входах одинаков из-за задержки фронтов:

        Ну, и напоследок — имейте ввиду, что если длительность dead-time превышает длительность импульса на выводе, то соответствующий импульс не будет сгенерирован вообще.

        Счётчик повторений

        Этот счётчик имеется у нескольких таймеров (TIM15, TIM16 и TIM17) и выполняет он очень простую функцию: генерировать событие (прерывание или запрос DMA) update не на каждое переполнение счётчика, а на каждые N переполнений. То есть, вы задаёте счётчик повторений, таймер его копирует в скрытый регистр и при каждом переполнении уменьшает значение копии на 1. Когда значение достигает нуля, генерируется событие update, таймер снова копирует счётчик повторений и т.д. На самом деле, перечисленные таймеры и так задействуют этот счётчик, просто по умолчанию его значение равно нулю, и событие генерируется на каждое переполнение.

        Счётчик может принимать значения от 0 до 255 (0xFF). Описывать тут особо нечего, потому что для использования этой функции достаточно при инициализации таймера написать что-то вроде:

        и всё. В этом случае событие update будет генерироваться каждые 8 переполнений (7 повторений).

        Вход BRK

        Если вам вдруг понадобится резко перевести выводы каналов таймера в заранее определённое состояние (например, выключить), то эта функция — то, что нужно. Включить её проще пареной репы — нужно сконфигурировать пин TIMx_BKIN на вход, и при инициализации BDTR включить вход BRK:

        По умолчанию для активации функции break нужно на вход BRK подать логический ноль, но это можно настроить в поле TIM_BreakPolarity. Как только break активирован, все выводы каналов переходят в состояние, которое задаётся при их инициализации полями TIM_OCIdleState и TIM_OCNIdleState в структуре TIM_OCInitTypeDef (по умолчанию на выводах будет низкий уровень). Dead-time при этом учитывается.

        Синхронизация таймеров

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

        Второй случай (цепочка таймеров) больше подойдёт для иллюстрации, ибо интереснее он. Сделаем-ка для примера 32-битный таймер из двух обычных 16-битных. Для примера я возьму таймеры TIM2 и TIM3. Задача состоит в том, таймер TIM3 тактировал таймер TIM2 по переполнению своего счётчика: то есть, счётчик таймера TIM2 будет увеличиваться при переполнении счётчика TIM3 — получаем 32-битный счётчик, «состоящий» из TIM2_CNT (старшие биты) и TIM3_CNT (младшие).

        Для этого нужно настроить выходной триггер таймера TIM3 на переполнение (update), а входной триггер таймера TIM2 — на вход с триггера TIM3. Смотрим в таблицу соединения триггеров для таймеров TIM2-TIM4 (таких таблиц несколько — для разных групп таймеров):

        Здесь мы видим, что TIM3 соединён с входом ITR2 таймера TIM2. И тут выясняется, что в Reference manual рассматриваемый случай описан в разделе «Using one timer as prescaler for another», но там допущена ошибка: вместо ITR2 там указан ITR1. Я джва года час искал ошибку в коде!

        голоса
        Рейтинг статьи
Ссылка на основную публикацию
Adblock
detector