- •Оглавление
- •Предисловие
- •Почему я написал книгу?
- •Для кого эта книга?
- •Как использовать эту книгу?
- •Как организована книга?
- •Об авторе
- •Ошибки и предложения
- •Поддержка книги
- •Как помочь автору
- •Отказ от авторского права
- •Благодарность за участие
- •Перевод
- •Благодарности
- •I Введение
- •1. Введение в ассортимент микроконтроллеров STM32
- •1.1. Введение в процессоры на базе ARM
- •1.1.1. Cortex и процессоры на базе Cortex-M
- •1.1.1.10. Внедренные функции Cortex-M в ассортименте STM32
- •1.2. Введение в микроконтроллеры STM32
- •1.2.1. Преимущества ассортимента STM32….
- •1.2.2. ….И его недостатки
- •1.3. Краткий обзор подсемейств STM32
- •1.3.1. Серия F0
- •1.3.2. Серия F1
- •1.3.3. Серия F2
- •1.3.4. Серия F3
- •1.3.5. Серия F4
- •1.3.6. Серия F7
- •1.3.7. Серия H7
- •1.3.8. Серия L0
- •1.3.9. Серия L1
- •1.3.10. Серия L4
- •1.3.11. Серия L4+
- •1.3.12. Серия STM32WB
- •1.3.13. Как правильно выбрать для себя микроконтроллер?
- •1.4. Отладочная плата Nucleo
- •2. Установка инструментария
- •2.1. Почему выбирают Eclipse/GCC в качестве инструментария для STM32
- •2.1.1. Два слова о Eclipse…
- •2.2. Windows – Установка инструментария
- •2.2.1. Windows – Установка Eclipse
- •2.2.2. Windows – Установка плагинов Eclipse
- •2.2.3. Windows – Установка GCC ARM Embedded
- •2.2.4. Windows – Установка инструментов сборки
- •2.2.5. Windows – Установка OpenOCD
- •2.2.6. Windows – Установка инструментов ST и драйверов
- •2.3. Linux – Установка инструментария
- •2.3.2. Linux – Установка Java
- •2.3.3. Linux – Установка Eclipse
- •2.3.4. Linux – Установка плагинов Eclipse
- •2.3.5. Linux – Установка GCC ARM Embedded
- •2.3.6. Linux – Установка драйверов Nucleo
- •2.3.7. Linux – Установка OpenOCD
- •2.3.8. Linux – Установка инструментов ST
- •2.4. Mac – Установка инструментария
- •2.4.1. Mac – Установка Eclipse
- •2.4.2. Mac – Установка плагинов Eclipse
- •2.4.3. Mac – Установка GCC ARM Embedded
- •2.4.4. Mac – Установка драйверов Nucleo
- •2.4.5. Mac – Установка OpenOCD
- •2.4.6. Mac – Установка инструментов ST
- •3. Hello, Nucleo!
- •3.1. Прикоснитесь к Eclipse IDE
- •3.2. Создание проекта
- •3.3. Подключение Nucleo к ПК
- •3.5. Изучение сгенерированного кода
- •4. Инструмент STM32CubeMX
- •4.1. Введение в инструмент CubeMX
- •4.1.1. Представление Pinout
- •4.1.2. Представление Clock Configuration
- •4.1.3. Представление Configuration
- •4.1.4. Представление Power Consumption Calculator
- •4.2. Генерация проекта
- •4.2.1. Генерация проекта Си при помощи CubeMX
- •4.2.2. Создание проекта Eclipse
- •4.2.3. Ручное импортирование сгенерированных файлов в проект Eclipse
- •4.3. Изучение сгенерированного кода приложения
- •4.3.1. Добавим что-нибудь полезное в микропрограмму
- •4.4. Загрузка исходного кода примеров книги
- •5. Введение в отладку
- •5.1. Начало работы с OpenOCD
- •5.1.1. Запуск OpenOCD
- •5.1.2. Подключение к OpenOCD Telnet Console
- •5.1.3. Настройка Eclipse
- •5.1.4. Отладка в Eclipse
- •5.2. Полухостинг ARM
- •5.2.1. Включение полухостинга в новом проекте
- •5.2.2. Включение полуохостинга в существующем проекте
- •5.2.3. Недостатки полухостинга
- •5.2.4. Как работает полухостинг
- •II Погружение в HAL
- •6. Управление GPIO
- •6.2. Конфигурация GPIO
- •6.2.1. Режимы работы GPIO
- •6.2.2. Режим альтернативной функции GPIO
- •6.2.3. Понятие скорости GPIO
- •6.3. Управление GPIO
- •6.4. Деинициализация GPIO
- •7. Обработка прерываний
- •7.1. Контроллер NVIC
- •7.1.1. Таблица векторов в STM32
- •7.2. Разрешение прерываний
- •7.2.1. Линии запроса внешних прерываний и контроллер NVIC
- •7.2.2. Разрешение прерываний в CubeMX
- •7.3. Жизненный цикл прерываний
- •7.4. Уровни приоритета прерываний
- •7.4.1. Cortex-M0/0+
- •7.4.2. Cortex-M3/4/7
- •7.4.3. Установка уровня прерываний в CubeMX
- •7.5. Реентерабельность прерываний
- •8. Универсальные асинхронные последовательные средства связи
- •8.1. Введение в UART и USART
- •8.2. Инициализация UART
- •8.3. UART-связь в режиме опроса
- •8.3.1. Установка консоли последовательного порта в Windows
- •8.3.2. Установка консоли последовательного порта в Linux и MacOS X
- •8.4. UART-связь в режиме прерываний
- •8.5. Обработка ошибок
- •8.6. Перенаправление ввода-вывода
- •9. Управление DMA
- •9.1. Введение в DMA
- •9.1.1. Необходимость DMA и роль внутренних шин
- •9.1.2. Контроллер DMA
- •9.2. Модуль HAL_DMA
- •9.2.1. DMA_HandleTypeDef в HAL для F0/F1/F3/L0/L1/L4
- •9.2.2. DMA_HandleTypeDef в HAL для F2/F4/F7
- •9.2.3. DMA_HandleTypeDef в HAL для L0/L4
- •9.2.4. Как выполнять передачи в режиме опроса
- •9.2.5. Как выполнять передачи в режиме прерываний
- •9.2.8. Разнообразные функции модулей HAL_DMA и HAL_DMA_Ex
- •9.3. Использование CubeMX для конфигурации запросов к DMA
- •10. Схема тактирования
- •10.1. Распределение тактового сигнала
- •10.1.1. Обзор схемы тактирования STM32
- •10.1.1.1. Многочастотный внутренний RC-генератор в семействах STM32L
- •10.1.3.1. Подача тактового сигнала от высокочастотного генератора
- •10.1.3.2. Подача тактового сигнала от 32кГц генератора
- •10.2. Обзор модуля HAL_RCC
- •10.2.1. Вычисление тактовой частоты во время выполнения
- •10.2.2. Разрешение Выхода синхронизации
- •10.2.3. Разрешение Системы защиты тактирования
- •10.3. Калибровка HSI-генератора
- •11. Таймеры
- •11.1. Введение в таймеры
- •11.1.1. Категории таймеров в микроконтроллере STM32
- •11.1.2. Доступность таймеров в ассортименте STM32
- •11.2. Базовые таймеры
- •11.2.1. Использование таймеров в режиме прерываний
- •11.2.2. Использование таймеров в режиме опроса
- •11.2.3. Использование таймеров в режиме DMA
- •11.2.4. Остановка таймера
- •11.3. Таймеры общего назначения
- •11.3.1.1. Режим внешнего тактирования 2
- •11.3.1.2. Режим внешнего тактирования 1
- •11.3.2. Режимы синхронизации ведущего/ведомого таймеров
- •11.3.2.1. Разрешение прерываний, относящихся к триггерной цепи
- •11.3.2.2. Использование CubeMX для конфигурации синхронизации ведущего/ведомого устройств
- •11.3.3. Программная генерация связанных с таймером событий
- •11.3.4. Режимы отсчета
- •11.3.5. Режим захвата входного сигнала
- •11.3.5.1. Использование CubeMX для конфигурации режима захвата входного сигнала
- •11.3.6. Режим сравнения выходного сигнала
- •11.3.6.1. Использование CubeMX для конфигурации режима сравнения выходного сигнала
- •11.3.7. Генерация широтно-импульсного сигнала
- •11.3.7.1. Генерация синусоидального сигнала при помощи ШИМ
- •11.3.7.2. Использование CubeMX для конфигурации режима ШИМ
- •11.3.8. Одноимпульсный режим
- •11.3.8.1. Использование CubeMX для конфигурации одноимпульсного режима
- •11.3.9. Режим энкодера
- •11.3.9.1. Использование CubeMX для конфигурации режима энкодера
- •11.3.10.1. Режим датчика Холла
- •11.3.10.2. Комбинированный режим трехфазной ШИМ и другие функции управления двигателем
- •11.3.10.3. Вход сброса таймера и блокировка регистров таймера
- •11.3.10.4. Предварительная загрузка регистра автоперезагрузки
- •11.3.11. Отладка и таймеры
- •11.4. Системный таймер SysTick
- •12. Аналого-цифровое преобразование
- •12.1. Введение в АЦП последовательного приближения
- •12.2. Модуль HAL_ADC
- •12.2.1. Режимы преобразования
- •12.2.1.1. Режим однократного преобразования одного канала
- •12.2.1.2. Режим сканирования с однократным преобразованием
- •12.2.1.3. Режим непрерывного преобразования одного канала
- •12.2.1.4. Режим сканирования с непрерывным преобразованием
- •12.2.1.5. Режим преобразования инжектированных каналов
- •12.2.1.6. Парный режим
- •12.2.2. Выбор канала
- •12.2.3. Разрядность АЦП и скорость преобразования
- •12.2.4. Аналого-цифровые преобразования в режиме опроса
- •12.2.6. Аналого-цифровые преобразования в режиме DMA
- •12.2.6.1. Многократное преобразование одного канала в режиме DMA
- •12.2.6.3. Непрерывные преобразования в режиме DMA
- •12.2.7. Обработка ошибок
- •12.2.8. Преобразования, управляемые таймером
- •12.2.9. Преобразования, управляемые внешними событиями
- •12.2.10. Калибровка АЦП
- •12.3. Использование CubeMX для конфигурации АЦП
- •13.1. Введение в периферийное устройство ЦАП
- •13.2. Модуль HAL_DAC
- •13.2.1. Управление ЦАП вручную
- •13.2.2. Управление ЦАП в режиме DMA с использованием таймера
- •13.2.3. Генерация треугольного сигнала
- •13.2.4. Генерация шумового сигнала
- •14.1. Введение в спецификацию I²C
- •14.1.1. Протокол I²C
- •14.1.1.1. START- и STOP-условия
- •14.1.1.2. Формат байта
- •14.1.1.3. Кадр адреса
- •14.1.1.4. Биты «Подтверждено» (ACK) и «Не подтверждено» (NACK)
- •14.1.1.5. Кадры данных
- •14.1.1.6. Комбинированные транзакции
- •14.1.1.7. Удержание синхросигнала
- •14.1.2. Наличие периферийных устройств I²C в микроконтроллерах STM32
- •14.2. Модуль HAL_I2C
- •14.2.1.1. Операции I/O MEM
- •14.2.1.2. Комбинированные транзакции
- •14.3. Использование CubeMX для конфигурации периферийного устройства I²C
- •15.1. Введение в спецификацию SPI
- •15.1.1. Полярность и фаза тактового сигнала
- •15.1.2. Управление сигналом Slave Select
- •15.1.3. Режим TI периферийного устройства SPI
- •15.1.4. Наличие периферийных устройств SPI в микроконтроллерах STM32
- •15.2. Модуль HAL_SPI
- •15.2.1. Обмен сообщениями с использованием периферийного устройства SPI
- •15.2.2. Максимальная частота передачи, достижимая при использовании CubeHAL
- •15.3. Использование CubeMX для конфигурации периферийного устройства SPI
- •16. Циклический контроль избыточности
- •16.1. Введение в расчет CRC
- •16.1.1. Расчет CRC в микроконтроллерах STM32F1/F2/F4/L1
- •16.2. Модуль HAL_CRC
- •17. Независимый и оконный сторожевые таймеры
- •17.1. Независимый сторожевой таймер
- •17.1.1. Использование CubeHAL для программирования таймера IWDG
- •17.2. Системный оконный сторожевой таймер
- •17.2.1. Использование CubeHAL для программирования таймера WWDG
- •17.3. Отслеживание системного сброса, вызванного сторожевым таймером
- •17.4. Заморозка сторожевых таймеров во время сеанса отладки
- •17.5. Выбор сторожевого таймера, подходящего для вашего приложения
- •18. Часы реального времени
- •18.1. Введение в периферийное устройство RTC
- •18.2. Модуль HAL_RTC
- •18.2.1. Установка и получение текущей даты/времени
- •18.2.1.1. Правильный способ чтения значений даты/времени
- •18.2.2. Конфигурирование будильников
- •18.2.3. Блок периодического пробуждения
- •18.2.5. Калибровка RTC
- •18.2.5.1. Грубая калибровка RTC
- •18.2.5.2. Тонкая калибровка RTC
- •18.2.5.3. Обнаружение опорного тактового сигнала
- •18.3. Использование резервной SRAM
- •III Дополнительные темы
- •19. Управление питанием
- •19.1. Управление питанием в микроконтроллерах на базе Cortex-M
- •19.2. Как микроконтроллеры Cortex-M управляют рабочим и спящим режимами
- •19.2.1. Переход в/выход из спящих режимов
- •19.2.1.1. «Спящий режим по выходу»
- •19.3. Управление питанием в микроконтроллерах STM32F
- •19.3.1. Источники питания
- •19.3.2. Режимы питания
- •19.3.2.1. Рабочий режим
- •19.3.2.2. Спящий режим
- •19.3.2.3. Режим останова
- •19.3.2.4. Режим ожидания
- •19.3.2.5. Пример работы в режимах пониженного энергопотребления
- •19.4. Управление питанием в микроконтроллерах STM32L
- •19.4.1. Источники питания
- •19.4.2. Режимы питания
- •19.4.2.1. Рабочие режимы
- •19.4.2.2. Спящие режимы
- •19.4.2.2.1. Режим пакетного сбора данных
- •19.4.2.3. Режимы останова
- •19.4.2.4. Режимы ожидания
- •19.4.2.5. Режим выключенного состояния
- •19.4.3. Переходы между режимами питания
- •19.4.4. Периферийные устройства с пониженным энергопотреблением
- •19.4.4.1. LPUART
- •19.4.4.2. LPTIM
- •19.5. Инспекторы источников питания
- •19.6. Отладка в режимах пониженного энергопотребления
- •19.7. Использование калькулятора энергопотребления CubeMX
- •20. Организация памяти
- •20.1. Модель организации памяти в STM32
- •20.1.1. Основы процессов компиляции и компоновки
- •20.2.1. Исследование бинарного ELF-файла
- •20.2.2. Инициализация секций .data и .bss
- •20.2.2.1. Пара слов о секции COMMON
- •20.2.3. Секция .rodata
- •20.2.4. Области Стека и Кучи
- •20.2.5. Проверка размера Кучи и Стека на этапе компиляции
- •20.2.6. Различия с файлами скриптов инструментария
- •20.3. Как использовать CCM-память
- •20.3.1. Перемещение таблицы векторов в CCM-память
- •20.4.1. Программирование MPU с использованием CubeHAL
- •21. Управление Flash-памятью
- •21.1. Введение во Flash-память STM32
- •21.2. Модуль HAL_FLASH
- •21.2.1. Разблокировка Flash-памяти
- •21.2.2. Стирание Flash-памяти
- •21.2.3. Программирование Flash-памяти
- •21.3. Байты конфигурации
- •21.3.1. Защита от чтения Flash-памяти
- •21.4. Дополнительные памяти OTP и EEPROM
- •21.5. Задержка чтения Flash-памяти и ускоритель ART™ Accelerator
- •21.5.1. Роль TCM-памятей в микроконтроллерах STM32F7
- •22. Процесс начальной загрузки
- •22.1.1. Программное физическое перераспределение памяти
- •22.1.2. Перемещение таблицы векторов
- •22.1.3. Запуск микропрограммы из SRAM с помощью инструментария GNU MCU Eclipse
- •22.2. Встроенный загрузчик
- •22.2.1. Запуск загрузчика из встроенного программного обеспечения
- •22.2.2. Последовательность начальной загрузки в инструментарии GNU MCU Eclipse
- •22.3. Разработка пользовательского загрузчика
- •22.3.2. Как использовать инструмент flasher.py
- •23. Запуск FreeRTOS
- •23.1. Введение в концепции, лежащие в основе ОСРВ
- •23.2.1. Структура файлов с исходным кодом FreeRTOS
- •23.2.1.2. Как импортировать FreeRTOS с использованием CubeMX и CubeMXImporter
- •23.3. Управление потоками
- •23.3.1. Состояния потоков
- •23.3.2. Приоритеты потоков и алгоритмы планирования
- •23.3.3. Добровольное освобождение от управления
- •23.3.4. Холостой поток idle
- •23.4. Выделение памяти и управление ею
- •23.4.1. Модель динамического выделения памяти
- •23.4.1.1. heap_1.c
- •23.4.1.2. heap_2.c
- •23.4.1.3. heap_3.c
- •23.4.1.4. heap_4.c
- •23.4.1.5. heap_5.c
- •23.4.2. Модель статического выделения памяти
- •23.4.3. Пулы памяти
- •23.4.4. Обнаружение переполнения стека
- •23.5. Примитивы синхронизации
- •23.5.1. Очереди сообщений
- •23.5.2. Cемафоры
- •23.5.3. Сигналы потоков
- •23.6. Управление ресурсами и взаимное исключение
- •23.6.1. Мьютексы
- •23.6.2. Критические секции
- •23.6.3. Обработка прерываний совместно с ОСРВ
- •23.7. Программные таймеры
- •23.7.1. Как FreeRTOS управляет таймерами
- •23.8. Пример из практики: Управление энергосбережением с ОСРВ
- •23.8.1. Перехват холостого потока idle
- •23.8.2. Бестиковый режим во FreeRTOS
- •23.9. Возможности отладки
- •23.9.1. Макрос configASSERT()
- •23.9.2. Статистика среды выполнения и информация о состоянии потоков
- •23.10. Альтернативы FreeRTOS
- •23.10.1. ChibiOS
- •23.10.2. ОС Contiki
- •23.10.3. OpenRTOS
- •24. Продвинутые методы отладки
- •24.1. Введение в исключения отказов Cortex-M
- •24.1.1.1. Как инструментарий GNU MCU Eclipse обрабатывает исключения отказов
- •24.1.1.2. Как интерпретировать содержимое регистра LR при переходе в исключение
- •24.1.2. Исключения отказов и их анализ
- •24.2.1. Представление Expressions
- •24.2.1.1. Мониторы памяти
- •24.2.2. Точки наблюдения
- •24.2.3. Режим Instruction Stepping Mode
- •24.2.4. Keil Packs и представление Peripheral Registers
- •24.2.5. Представление Core Registers
- •24.3. Средства отладки от CubeHAL
- •24.4. Внешние отладчики
- •24.4.1. Использование SEGGER J-Link для отладчика ST-LINK
- •24.4.2. Использование интерфейса ITM и трассировка SWV
- •24.5. STM Studio
- •24.6. Одновременная отладка двух плат Nucleo
- •25. Файловая система FAT
- •25.1. Введение в библиотеку FatFs
- •25.1.1. Использование CubeMX для включения в ваши проекты библиотеки FatFs
- •25.1.2. Наиболее важные структуры и функции FatFs
- •25.1.2.1. Монтирование файловой системы
- •25.1.2.2. Открытие файлов
- •25.1.2.3. Чтение и запись файла
- •25.1.2.4. Создание и открытие каталога
- •25.1.3. Как сконфигурировать библиотеку FatFs
- •26. Разработка IoT-приложений
- •26.2. Ethernet контроллер W5500
- •26.2.1. Как использовать шилд W5500 и модуль ioLibrary_Driver
- •26.2.1.1. Конфигурирование интерфейса SPI
- •26.2.1.2. Настройка буферов сокетов и сетевого интерфейса
- •26.2.2. API-интерфейсы сокетов
- •26.2.2.1. Управление сокетами в режиме TCP
- •26.2.2.2. Управление сокетами в режиме UDP
- •26.2.3. Перенаправление ввода-вывода на сокет TCP/IP
- •26.2.4. Настройка HTTP-сервера
- •26.2.4.1. Веб-осциллограф
- •27. Начало работы над новым проектом
- •27.1. Проектирование оборудования
- •27.1.1. Послойная разводка печатной платы
- •27.1.2. Корпус микроконтроллера
- •27.1.3. Развязка выводов питания
- •27.1.4. Тактирование
- •27.1.5. Фильтрация вывода сброса RESET
- •27.1.6. Отладочный порт
- •27.1.7. Режим начальной загрузки
- •27.1.8. Обратите внимание на совместимость с выводами…
- •27.1.9. …и на выбор подходящей периферии
- •27.1.10. Роль CubeMX на этапе проектирования платы
- •27.1.11. Стратегии разводки платы
- •27.2. Разработка программного обеспечения
- •27.2.1. Генерация бинарного образа для производства
- •Приложение
- •Принудительный сброс микроконтроллера из микропрограммы
- •B. Руководство по поиску и устранению неисправностей
- •Проблемы с установкой GNU MCU Eclipse
- •Проблемы, связанные с Eclipse
- •Eclipse не может найти компилятор
- •Eclipse постоянно прерывается при выполнении каждой инструкции во время сеанса отладки
- •Пошаговая отладка очень медленная
- •Микропрограмма работает только в режиме отладки
- •Проблемы, связанные с STM32
- •Микроконтроллер не загружается корректно
- •Невозможно загрузить микропрограмму или отладить микроконтроллер
- •C. Схема выводов Nucleo
- •Nucleo-F446RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F411RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F410RB
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F401RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F334R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F303RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F302R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F103RB
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F091RC
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F072RB
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F070RB
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F030R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-L476RG
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-L152RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-L073R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-L053R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •D. Корпусы STM32
- •LFBGA
- •LQFP
- •TFBGA
- •TSSOP
- •UFQFPN
- •UFBGA
- •VFQFP
- •WLCSP
- •E. Изменения книги
- •Выпуск 0.1 – Октябрь 2015
- •Выпуск 0.2 – 28 октября 2015
- •Выпуск 0.2.1 – 31 октября 2015
- •Выпуск 0.2.2 – 1 ноября 2015
- •Выпуск 0.3 – 12 ноября 2015
- •Выпуск 0.4 – 4 декабря 2015
- •Выпуск 0.5 – 19 декабря 2015
- •Выпуск 0.6 – 18 января 2016
- •Выпуск 0.6.1 – 20 января 2016
- •Выпуск 0.6.2 – 30 января 2016
- •Выпуск 0.7 – 8 февраля 2016
- •Выпуск 0.8 – 18 февраля 2016
- •Выпуск 0.8.1 – 23 февраля 2016
- •Выпуск 0.9 – 27 марта 2016
- •Выпуск 0.9.1 – 28 марта 2016
- •Выпуск 0.10 – 26 апреля 2016
- •Выпуск 0.11 – 27 мая 2016
- •Выпуск 0.11.1 – 3 июня 2016
- •Выпуск 0.11.2 – 24 июня 2016
- •Выпуск 0.12 – 4 июля 2016
- •Выпуск 0.13 – 18 июля 2016
- •Выпуск 0.14 – 12 августа 2016
- •Выпуск 0.15 – 13 сентября 2016
- •Выпуск 0.16 – 3 октября 2016
- •Выпуск 0.17 – 24 октября 2016
- •Выпуск 0.18 – 15 ноября 2016
- •Выпуск 0.19 – 29 ноября 2016
- •Выпуск 0.20 – 28 декабря 2016
- •Выпуск 0.21 – 29 января 2017
- •Выпуск 0.22 – 2 мая 2017
- •Выпуск 0.23 – 20 июля 2017
- •Выпуск 0.24 – 11 декабря 2017
- •Выпуск 0.25 – 3 января 2018
- •Выпуск 0.26 – 7 мая 2018
Таймеры |
340 |
Period (которое соответствует регистру автоперезагрузки (ARR)) каждые 1 мс. Это означает, что менее чем за 1 с светодиод становится полностью ярким. Второй цикл аналогичным образом уменьшает поле Pulse, пока оно не достигнет нуля.
Частота обновления таймера установлена на 84МГц34/(499+1)(999+1)=168Гц. Такую же частоту можно получить, установив Prescaler в 249, а Period в 1999. Однако эффект плавного мерцания меняется. Почему так происходит? Если вы не можете объяснить различие, я настоятельно рекомендую сделать перерыв перед тем, как продолжать, и провести эксперименты самостоятельно.
11.3.7.1. Генерация синусоидального сигнала при помощи ШИМ
Выходной прямоугольный сигнал, сгенерированный с помощью метода ШИМ, может быть отфильтрован для генерации сглаженного сигнала, который является аналоговым сигналом, имеющим пониженную двойную амплитуду напряжения или, как говорят,
размах напряжения (peak-to-peak voltage, Vpp). RC-фильтр нижних частот (см. рисунок
24) способен срезать все эти переменные сигналы, имеющие частоту выше заданного порогового значения. Общее правило низкочастотных RC-фильтров заключается в том, что чем ниже частота среза (cut-off frequency), тем ниже Vpp35. В низкочастотном RCфильтре используется важная характеристика конденсаторов: способность блокировать постоянные токи при одновременном пропускании переменных: учитывая постоянную времени R/C, образованную цепочкой резистор-конденсатор, фильтр закорачивает на землю переменные сигналы с частотой выше, чем постоянная RC-цепочки, позволяющая пропускать постоянную составляющую сигнала и более низкую частоту переменного напряжения.
Рисунок 24: Типовой фильтр нижних частот, реализованный с резистором и конденсатором
Хотя эта схема очень проста, выбор подходящих значений для R (сопротивления) и C (емкости) включает в себя некоторые конструктивные решения: какую пульсацию мы можем допустить и как быстро должен реагировать фильтр. Эти два параметра являются взаимоисключающими. В большинстве фильтров мы хотели бы иметь идеальный фильтр, который пропускал бы все частоты ниже частоты среза, без пульсации напряжения. К сожалению, такого идеального фильтра не существует: чтобы уменьшить пульсацию до нуля, мы должны выбрать очень большой фильтр, что приведет к тому, что будет затрачиваться много времени, прежде чем выходной сигнал станет стабильным. Хотя это может быть приемлемым для постоянного и фиксированного напряжения, это
34Максимальная частота таймеров в микроконтроллере STM32F401RE при тактировании от шины APB1 составляет 84 МГц.
35При работе с фильтрами для сглаживания выходного сигнала удобнее учитывать влияние на выходное напряжение, чем отклик по частоте фильтра. Однако математический аппарат расчета передаточной функции фильтра выходит за рамки данной книги. Если интересно, этот онлайн-калькулятор (http://sim.okawa-
denshi.jp/en/PWMtool.php) позволяет оценить выходной сигнал Vpp с учетом VIN, частоты ШИМ и значений
R и C.
Таймеры |
341 |
оказывает серьезное влияние на качество выходного сигнала, если мы пытаемся генерировать сложную форму сигнала из ШИМ-сигнала.
Частота среза fc RC-фильтра нижних частот первого порядка выражается формулой:
f |
= |
1 |
|
||
c |
|
2 RC |
|
|
[9]
На рисунке 25 показано влияние фильтра нижних частот на ШИМ-сигнал с частотой 100 Гц. Здесь мы выбрали резистор 1 кОм и конденсатор 10 мкФ. Это означает, что частота среза равна:
f |
= |
|
1 |
|
15.9 |
Гц |
|
|
3 |
|
−5 |
||||
c |
|
2 10 |
10 |
|
|
||
|
|
|
|
|
|
Рисунок 25: Влияние фильтра нижних частот с частотой среза, равной 15,9 Гц
На рисунке 26 показано влияние фильтра нижних частот с резистором 4300 кОм и конденсатором 10 мкФ. Это означает, что частота среза равна:
f |
= |
1 |
|
|
|
3.7 Гц |
|
|
|
|
|||
c |
|
2 (4.3 10 |
3 |
) 10 |
−5 |
|
|
|
|
|
|
Рисунок 26: Влияние фильтра нижних частот с частотой среза, равной 3,7 Гц
Как видите, второй фильтр позволяет получить значение Vpp, равное примерно 160 мВ, которое является колебанием напряжения, применимым для многих приложений.
Изменяя выходное напряжение (которое подразумевает, что мы меняем коэффициент заполнения), мы можем генерировать произвольный выходной сигнал, частоту которого составляет часть периода ШИМ. Основная идея здесь состоит в том, чтобы разделить желаемую форму сигнала, например, синусоидальную, на количество «x» делений. На каждое деление у нас имеется один цикл ШИМ. Время (то есть коэффициент
заполнения) напрямую соответствует амплитуде сигнала на этом делении, которая рассчитывается с использованием функции sin().
Таймеры |
342 |
Рисунок 27: Как синусоида может быть аппроксимирована несколькими сигналами ШИМ
Рассмотрим диаграмму, показанную на рисунке 27. Здесь синусоида была разделена на 10 делений. Поэтому здесь нам потребуется 10 различных импульсов ШИМ, увеличивающихся/уменьшающихся синусоидальным образом. Импульс ШИМ с коэффициентом заполнения 0% будет представлять минимальную амплитуду (0 В), импульс с коэффициентом заполнения 100% будет представлять максимальную амплитуду (3,3 В). Поскольку выходной импульс ШИМ имеет перепад напряжения от 0 до 3,3 В, наша синусоида также будет колебаться от 0 до 3,3 В.
Для завершения одного цикла синусоиды требуется 360 градусов. Следовательно, для 10 делений нам нужно будет увеличивать угол с шагом 36 градусов. Это называется угловой скоростью шага (Angle Step Rate, ASR) или угловым разрешением (Angle Resolution). Мы мо-
жем увеличить количество делений, чтобы получить более точную форму сигнала. Но по мере увеличения деления нам также необходимо увеличивать разрешение, что означает, что мы должны увеличить частоту таймера, используемого для генерации сигнала ШИМ (чем быстрее работает таймер, тем меньше период).
Обычно 200 делений являются хорошим приближением для выходного сигнала. Это означает, что, если мы хотим генерировать синусоидальный сигнал 50 Гц, нам нужно запустить таймер на частоте 50 Гц * 200 = 10 кГц. Период импульса будет равен 200 (шагов
– это означает, что мы изменяем выходное напряжение на 3,3 В / 200 = 0,016 В), и поэтому значение Prescaler будет (при условии, что микроконтроллер STM32F030 работает на частоте 48 МГц) :
Prescaler = |
48 МГц |
|
= 24 |
|
50 Гц 200 |
|
200 |
||
|
делений |
Pulse |
||
|
|
|
В следующем примере показано, как генерировать чистый синусоидальный сигнал 50 Гц в микроконтроллере STM32F030, работающем на частоте 48 МГц.
|
Имя файла: src/main-ex9.c |
|
|
|
|
14 |
#define PI |
3.14159 |
15 |
#define ASR |
1.8 //360 / 200 = 1.8 |
16 |
|
|
17int main(void) {
18uint16_t IV[200];
19float angle;
20
21 HAL_Init();
22
Таймеры |
343 |
23Nucleo_BSP_Init();
24MX_TIM3_Init();
26for (uint8_t i = 0; i < 200; i++) {
27angle = ASR*(float)i;
28IV[i] = (uint16_t) rint(100 + 99*sinf(angle*(PI/180)));
29 |
} |
30 |
|
31 |
HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1, (uint32_t *)IV, 200); |
32 |
|
33while (1);
34}
35
36/* Функция инициализации TIM3 */
37void MX_TIM3_Init(void) {
38TIM_OC_InitTypeDef sConfigOC;
40htim3.Instance = TIM3;
41htim3.Init.Prescaler = 23;
42htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
43htim3.Init.Period = 199;
44htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;
45 |
HAL_TIM_PWM_Init(&htim3); |
46 |
|
47sConfigOC.OCMode = TIM_OCMODE_PWM1;
48sConfigOC.Pulse = 0;
49sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
50sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
51HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
53hdma_tim3_ch1_trig.Instance = DMA1_Channel4;
54hdma_tim3_ch1_trig.Init.Direction = DMA_MEMORY_TO_PERIPH;
55hdma_tim3_ch1_trig.Init.PeriphInc = DMA_PINC_DISABLE;
56hdma_tim3_ch1_trig.Init.MemInc = DMA_MINC_ENABLE;
57hdma_tim3_ch1_trig.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
58hdma_tim3_ch1_trig.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
59hdma_tim3_ch1_trig.Init.Mode = DMA_CIRCULAR;
60hdma_tim3_ch1_trig.Init.Priority = DMA_PRIORITY_LOW;
61 HAL_DMA_Init(&hdma_tim3_ch1_trig); 62
63/* Несколько указателей дескриптора DMA периферии указывают на один
64и тот же дескриптор DMA.
65Имейте в виду, что существует только один канал для выполнения всех запросов к DMA. */
66__HAL_LINKDMA(&htim3, hdma[TIM_DMA_ID_CC1], hdma_tim3_ch1_trig);
67__HAL_LINKDMA(&htim3, hdma[TIM_DMA_ID_TRIGGER], hdma_tim3_ch1_trig);
68}
Наиболее значимая часть представлена в строках [26:29]. Эти строки кода используются для генерации вектора инициализации (Initialization Vector, IV), то есть вектора, содержащего значения Pulse, используемые для генерации синусоидального сигнала (который
Таймеры |
344 |
соответствует уровням выходного напряжения). Функция Си sinf() возвращает синус заданного угла, выраженный в радианах. Поэтому нам нужно преобразовать угловые выражения в градусах в радианы по формуле:
Радианы = 180 Градусы
Однако в нашем случае мы разделили цикл синусоидального сигнала на 200 шагов (то есть мы разделили окружность на 200 шагов), поэтому нам нужно вычислить значение в радианах для каждого шага. Но так как синус дает отрицательные значения для угла между 180° и 360° (см. рисунок 28), мы должны масштабировать его, так как выходные значения ШИМ не могут быть отрицательными.
Рисунок 28: Значения, принятые синусоидальной функцией между 180° и 360°
Как только сгенерирован вектор IV, мы можем запустить ШИМ в режиме DMA. DMA1_Channel4 сконфигурирован для работы в циклическом режиме, поэтому он автоматически устанавливает значение регистра TIMx_CCRx в соответствии со значениями Pulse, содержащимися в IV. Использование таймера в режиме DMA – лучший способ для генерации произвольной функции без задержки и влияния на ядро Cortex-M. Тем не менее, часто векторы IV внутри программы жестко закодированы с использованием массивов с модификатором const, автоматически сохраняемых во Flash-памяти. Вы можете найти несколько онлайн-инструментов для этого, например, представленный здесь36.
Рисунок 29: Как таймеры позволяют аппроксимировать синусоидальный сигнал частотой 50 Гц с использованием ШИМ
36 https://daycounter.com/Calculators/Sine-Generator-Calculator.phtml