Iar и stm32 cortex m0. часть 0x05, gpio — входит и выходит…

STM32F091 — микроконтроллер начального уровня на базе ядра ARM Cortex-M0

ПодробностиКатегория: STM

STM32F091 — микроконтроллер начального уровня на базе ядра ARM Cortex-M0 с тактовой частотой 48 МГц, объёмом FLASH-памяти 256 кбайт, CAN интерфейсом и функцией управления пользовательскими устройствами (CEC).

Микроконтроллеры STM32F091xB/xC интегрируют высокопроизводительное 32-битное ядро ARM Cortex-M0 RISC-архитектуры с тактовой частотой 48 МГц.

В дополнение к перечисленному новые устройства содержат высокоскоростную встроенную память (до 256 КБ FLASH и 32 КБ SRAM) и расширенный набор периферийных устройств и линий ввода/вывода.

Микроконтроллеры оснащены стандартными коммуникационными интерфейсами (два I2C, два SPI/один I2S, один HDMI CEC, один CAN и до восьми USART), а также такими периферийными модулями, включая один 12-битный АЦП, один 12-битный ЦАП с двумя каналами, семь 16-битных таймеров общего назначения, 32-битный таймер и таймер ШИМ-модулятора с расширенными функциями управления.

Диапазон рабочих температур STM32F091xB/xC составляет от -40 °C до +85 °C и от -40 °C до +105 °C, а напряжение питания – от 2.0 В до 3.6 В. Различные режимы пониженного энергопотребления помогут разработчикам создавать на базе микроконтроллеров энергоэффективные решения.

STM32F091xB/xC поставляются в корпусах семи различных типов с количеством выводов от 48 до 100 и формой кристалла, которая может быть изготовлена по проекту заказчика. В зависимости от выбранной модели устройства пользователю доступен различный набор периферийных модулей.

Благодаря своим возможностям, STM32F091xB/xC отлично подходят для широкого круга применений, таких как: управление приложениями и пользовательские интерфейсы, портативное оборудование, A/V ресиверы и цифровые телевизоры, периферийные устройства ПК, игровые и навигационные платформы, промышленные приложения, программируемые логические контроллеры, инверторы, принтеры, сканеры, сигнализации, видеоконференции и системы климат-контроля.

Внутренняя архитектура микроконтроллеров STM32F091x

Периферия STM32F091Cx STM32F091Rx STM32F091Vx
FLASH (кбайт) 128 256 128 256 128 256
SRAM (кбайт) 32
Таймеры 8 (16-бит)1 (32-бит)
SPI [I2S] 2 [2]
I2C 2
USART 6 8
CAN 1
CEC 1
12-бит АЦП (каналов) 1 (10 внешних + 3 внутренних) 1 (16 внешних + 3 внутренних)
12-бит ЦАП (каналов) 1 (2)
Аналоговый компаратор 2
GPIO 38 52 88
Емкостной сенсорный интерфейс (каналов) 17 18 24
Частота ЦПУ 48 МГц
Напряжение питания 2.0…3.6 В
Диапазон рабочих температур Окружающей среды: -40…+85°C / -40…+105°CПерехода: -40…+105°C / -40…+125°C
Корпуса LQFP-48UFQFPN-48 LQFP-64UFBGA-64WLCSP-64 LQFP-100UFQFPN-100

Отличительные особенности:

  • 32-битное ядро ARM® Cortex®-M0 с тактовой частотой до 48 МГц
  • Внутренняя память:
    • FLASH: от 128 кбайт до 256 кбайт
    • SRAM: 32 кбайт с аппаратным блоком контроля по четности
  • Блок вычисления кода коррекции ошибок (CRC)
  • Система питания и схема сброса:
    • Диапазон напряжения питания цифровой части и линий ввода/вывода: от 2.0 В до 3.6 В
    • Диапазон напряжения питания аналоговой части: от 2.0 В до 3.6 В
    • Схема сброса при включении и выключении питания (POR/PDR)
    • Программируемый детектор напряжения (PVD)
    • Режимы энергосбережения: спящий, останова и ждущий
    • Схема питания от резервного источника (VBAT) для часов реального времени и регистров резервного хранения данных
  • Система синхронизации и тактирования:
    • Кварцевый генератор с тактовой частотой от 4 МГц до 32 МГц
    • Отдельный генератор с тактовой частотой 32 кГц для часов реального времени с калибровкой
    • Внутренний RC-генератор с тактовой частотой 8 МГц и шестью узлами фазовой автоподстройки частоты
    • Внутренний RC-генератор с тактовой частотой 40 кГц
    • Внутренний генератор с частотой 48 МГц с автоматической синхронизацией с внешним тактовым сигналом
  • До 88 высокоскоростных линий ввода/вывода
    • Карта векторов внешних прерываний
    • До 69 линий ввода/вывода с напряжением питания 5 В и 19 линий с независимым источником питания VDDIO2
  • 12-канальный контроллер прямого доступа к памяти (DMA)
  • Один 12-битный АЦП с частотой дискретизации 1 MSPS (млн. выборок в сек.), до 16 каналов:
    • Диапазон напряжения входного аналогового сигнала: от 0 В до 3.6 В
    • Независимый источник питания: от 2.4 В до 3.6 В
  • Один 2-канальный 12-битный ЦАП
  • Два быстродействующих аналоговых компаратора с настраиваемыми входами и выходами
  • До 24 каналов сенсорного емкостного интерфейса с функциями кнопок, клайдера и дискового элемента ввода
  • Часы реального времени (RTC) с календарем, будильником и периодическим выходом из режима останова/ожидания
  • 12 таймеров:
    • Один 16-битный таймер с расширенными функциями управления для формирования 6 каналов ШИМ
    • Один 32-битный и семь 16-битных таймеров с четырьмя каналами захвата/сравнения/OCN, необходимых для декодирования команд управления инфракрасного порта или управления ЦАП
    • Независимый и системный сторожевой таймеры
    • Системный таймер SysTick
  • Коммуникационные интерфейсы:
    • Два интерфейса I2C с поддержкой режима Fast Mode Plus (скорость передачи данных 1 Мбит/с) и током нагрузки 20 мА, один из которых поддерживает режим шины SMBus/PMBus и выход из режима сна по сигналу пробуждения
    • До 8 портов USART с поддержкой синхронного режима ведущего SPI и управление модемом. Три из них поддерживают интерфейс ISO7816, LIN и IrDA с автоматическим определением скорости передачи данных и функцией выхода из режима сна по сигналу пробуждения
    • Два интерфейса SPI со скоростью передачи данных 18 Мбит/с и программируемой длиной фрейма от 4 до 16 бит, а также мультиплексированный интерфейс I2S
    • Интерфейс сети CAN
  • Функция пробуждения при вставке разъёма в гнездо HDMI
  • Последовательный проводной интерфейс отладки (SWD)
  • Уникальный 96-битный идентификатор устройства

Область применения:

  • Управление приложениями
  • Пользовательские интерфейсы
  • Портативное оборудование
  • Аудиовидеоресиверы и цифровые телевизоры
  • Периферийные компоненты ПК
  • Игровые и навигационные платформы
  • Промышленные приложения
  • Программируемые логические контроллеры
  • Инверторы
  • Принтеры
  • Сканеры
  • Системы тревоги
  • Видеоконференции
  • Системы климат-контроля

Инструментальные средства:

NUCLEO-F091RC — отладочная плата STM32 Nucleo на базе микроконтроллера STM32F091RCT6 с поддержкой платформы Arduino.

  • Плата STM32 Nucleo предлагает пользователю гибкий и доступный способ опробовать новые идеи и построить прототип на основе любого микроконтроллера серии STM32, производя выбор из различных комбинаций производительности, потребляемой мощности и набора периферии
  • Поддержка плат расширения Arduino™ и ST Morpho позволяет расширить функциональные возможности открытой платформы разработки STM32 Nucleo благодаря широкому выбору специализированных модулей. Плата STM32 Nucleo не требует никаких дополнительных инструментальных средств, поскольку имеет в своем составе программатор/отладчик ST-LINK/V2-1
  • Помимо этого, разработчикам доступна полнофункциональная библиотека (аппаратно абстрактного уровня) драйверов и примеров прикладного кода, а также доступ к онлайн среде проектирования embed

Источник: http://gamma.spb.ru/novosti-proizvoditelej/stm/190-stm32f091-mikrokontroller-nachalnogo-urovnya-na-baze-yadra-arm-cortex-m0

STM32 для начинающих. Урок 1. GPIO

GPIO (general-purpose input/output,Интерфейс ввода/ вывода общего назначения)— Интерфейс связывающий микроконтроллер с внешними устройствами (Кнопками, светодиодами, датчиками и так далее).

Как и любой другой микроконтроллер, микроконтроллер STM32, имеет в своем составе интерфейс ввода/вывода.

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

Контакты GPIO, группируются в порты(GPIOA,GPIOB,GPIOC…). Каждый контакт может работать на прием или передачу данных.

Рассмотрим режимы работы контакта GPIO:

  • HiZ вход — В таком состоянии сопротивление входа стремится к бесконечности, и он ведет себя как отключенный от схемы.
  • Вход с подтяжкой к питанию — Контакт работает на прием данных. Когда данных нет, контакт подтягивается к логической “1” (напряжению питания). Это делается, что бы избежать помех и искажения данных.
  • Вход с подтяжкой к земле — Контакт работает на прием данных. Когда данных нет, контакт подтягивается к логическому “0” (земле). Это делается, что бы избежать помех и искажения данных.
  • Аналоговый вход — Контакт работает в аналоговом режиме, что позволяет выводить на него сигнал ЦАП или считывать сигнал для АЦП.
  • Выход с открытым коллектором.
  • Двухтактный выход — Контакт работает на передачу данных. Контакт может быть установлен в логическую “1” либо в логический “”, соответствующим регистром.
  • Альтернативный режим с подтяжкой.
  • Альтернативный режим с открытым коллектором.

Альтернативные режимы пока рассматривать не будем, равно как выход с открытым коллектором и аналоговый вход. Рассмотрим подробнее режимы работы “Вход с подтяжкой к питанию/земле” и “Двухтактный выход”.

Как и любую другую периферию, перед использованием GPIO необходимо настроить.

Так как периферия микроконтроллеров STM32 очень богата и разнообразна, разработчики потрудились облегчить жизнь пользователям и избавить их от ручной правки регистров, путем создания библиотек HALи SPL.

Разумеется, никто не запрещает вам вручную править регистры. Хоть ручная правка регистров и сложна, однако позволяет лучше понять работу микроконтроллера и оптимизировать прошивку.

Читайте также  GPS маячок. STM32

Но мы не будет сильно углубляться в дебри даташитов и регистров. Возьмем библиотеку SPLи с её помощью инициализируем порты ввода/вывода нашей платы STM32 F3 DISCOVERY.

Работать будем в среде Keil uVision 5.

Как создать свой первый проект в данной среде смотрите здесь :

STM32 для начинающих. Урок 0. Создание проекта в Keil uVision.

Добавим следующий код:

#include “stm32f30x_gpio.h”#include “stm32f30x_rcc.h”RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE,ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);GPIO_StructInit (&PORTE);PORTE.GPIO_Mode = GPIO_Mode_OUT;PORTE.GPIO_OType = GPIO_OType_PP;PORTE.GPIO_Pin = GPIO_Pin_10;PORTE.GPIO_PuPd = GPIO_PuPd_DOWN;PORTE.GPIO_Speed = GPIO_Speed_50MHz;GPIO_StructInit (&PORTA);PORTA.GPIO_Mode = GPIO_Mode_IN;PORTA.GPIO_Pin = GPIO_Pin_0;PORTA.GPIO_PuPd = GPIO_PuPd_DOWN;PORTA.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init (GPIOE,&PORTE);GPIO_Init (GPIOA,&PORTA);if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)GPIO_SetBits(GPIOE,GPIO_Pin_10);GPIO_ResetBits(GPIOE,GPIO_Pin_10);

Итак, разберем подробнее, что же происходит в данном коде.

Точка входа — функция main, именно с неё начинается работа нашей прошивки. Сначала вызывается функция InitGPIO,в которой мы настраиваем работу наших портов. Остановимся на ней подобробнее.

Вначале создаются две структуры GPIO_InitTypeDef инициализации портов GPIOE,GPIOA, названные мною как PORTA,PORTE. Данные структуры являются частью библиотеки SPL, и содержат в себе параметры работы соответствующих портов.

Читайте также  STM32.Bluetooth и Android.

Затем, происходит включение тактирование портов GPIOA,GPIOE командами RCC_AHBPeriphClockCmd. Следует помнить что, изначально тактирование периферии контроллера отключено, в целях снижения энергопотребления. Данной командой мы включаем или выключаем тактирование периферии шины AHB. Подробнее о тактировании поговорим в следующих уроках.

После этого мы заполняем поля структуры GPIO_InitTypeDef , для портов GPIOE,GPIOA. Предварительно структуру можно проинициализировать (записать в неё стандартные значения) командой GPIO_StructInit. Рассмотрим поля структуры GPIO_InitTypeDef:

  • GPIO_Mode — Режим работы порта.
  • GPIO_OType — При настройке порта на выход, данным полем задается его тип (С открытым стоком или двухтактный).
  • GPIO_Pin — Данным полем мы выбираем, какие ножки порта настраивать.
  • GPIO_PuPd — Выбираем режим подтяжки к напряжению питания или к земле.
  • GPIO_Speed — Скорость работы порта.

Итак, поля заполнены, теперь инициализируем порты согласно тому, что прописано в соответствующей структуре командой GPIO_Init.

На этом функция InitGPIO заканчивается.

После вызова функции InitGPIO, наступает основной цикл программы while. В нем мы считываем входящее значение 0 ножки порта GPIOA(К которой подключена кнопка USER платы STM32 F3 DISCOVERY).

Делаем мы это командой GPIO_ReadInputDataBit, которая возвращает входное значение выбранной ножки порта. В соответствии с состоянием ножки 0 порта GPIOA, выставляем значение 10 ножки порта GPIOE командами GPIO_ResetBits и GPIO_SetBits.

Команда GPIO_ResetBits устанавливает логический ноль на выбранной ножке порта, а команда GPIO_SetBits устанавливает логическую единицу на выбранной нами ножке.

Когда вы загрузите данную программу в плату STM32 F3 DISCOVERY, не забудьте нажать кнопку RESET, которая сбросит микроконтроллер. После этого нажимайте кнопку USER и смотрите за результатом.

Спасибо за внимание!

Другие уроки цикла

Любое копирование, воспроизведение, цитирование материала, или его частей разрешено только с письменного согласия администрации MKPROG.RU. Незаконное копирование, цитирование, воспроизведение преследуется по закону!

Источник: http://mkprog.ru/mikrokontrollery-stm32/stm32-dlya-nachinayushhih-urok-1-gpio.html

Изучаем STM32. Урок 2. Изучаем порты ввода-вывода GPIO (ч1) — DRIVE2

Добрый день, итак, пока есть время между редактированиями кодов и пайками)) напишу ещё одну статейку. На этот раз мы будем знакомиться с нашими ножками (нет не теми что внизу), а теми которые находятся на микроконтроллере и за счёт чего он воспринимает сигналы из внешнего мира и соответственно передаёт сигналы в него.

Итак, давайте посмотрим на блок — схему порта ввода-вывода контроллера

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

Ну кому более интересно это, тот может найти feference manual и выучить всё от корки до корки, мы же в данной части урока просто разберёмся что значат разные режимы работы наших портов

Итак, помните в прошлом уроке мы настраивали чем у нас будет ножка контроллера — Входом, Выходом. Но это не все параметры. Ещё ножка может быть сконфигурирована как аналоговый входвыход для допустим работы с АЦП, или с ЦАП, у кого он есть на “борту”))

Давайте рассмотрим все режимы работы
1)Input floating — по простому это вход безо всяких подтяжек (Hi-Z состояние, плавающий). По простому вход у нас ни к чему не подключён (привет помехи))))
2)Input pull-up — режим входа, в котором он чрез подтягивающий резистор подключён к питанию (номинал резистора несколько десятков килоОм)

3)Input-pull-down — режим входа, в котором он чрез подтягивающий резистор подключён к земле (массе) (номинал резистора несколько десятков килоОм)

4)Analog — режим работы, который включаем если желаем работать с АЦП или ЦАП

5)Output open-drain with pull-up or pull-down capability — выход с “открытым коллектором”

6)Output push-pull with pull-up or pull-down capability — самый используемый режим, в котором наш пин может выдавать как лог. ноль так и лог. единицу (это будут работать те самые полевые тарнзисторы о которых писал выше)

7)Alternate function push-pull with pull-up or pull-down capability — альтернативная функция (двухтактный вывод)

8)Alternate function open-drain with pull-up or pull-down capability — альтернативная функция (открытый
коллектор)

Теперь опишу как работаем с этими параметрами в нашей среде программирования.

Вот смотрите, кусочек кода, который отвечает за настройку параметров выхода

GPIO_InitStruct.Pin = GPIO_PIN_0; — данная строчка кода указывает что конфигурировать мы будем ножку 0
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; — Данная строчка указывает что режим работы — ВходУ данной строчки могут быть вот такие параметрыGPIO_MODE_INPUTGPIO_MODE_OUTPUT_PPGPIO_MODE_OUTPUT_ODGPIO_MODE_AF_PP

GPIO_MODE_AF_OD

Следующая строчка GPIO_InitStruct.Pull = GPIO_PULLDOWN; — Указывает что у нас подтяжка к массе. У данной строчки ещё могут быть вот такие вариантыGPIO_NOPULLGPIO_PULLUP

GPIO_PULLDOWN

Ну и последняя строчка указывает нам с каким портом нашего контроллера мы вообще только что разговаривали) — HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

Здесь мы рассмотрели настройку нашего пина к которому подключена кнопка. PA0.

А давайте теперь рассмотрим настройку нашего порта, куда подключены светодиоды/*Configure GPIO pins : PD12 PD13 */GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_LOW;HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);


GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13;
— эта строчка указывает какие пины настраиваем

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; — эта строка указыввает нам режим работы — ВЫХОД двухтактный (push-pull) . Возможные варианты конфигурации описаны чуть выше.
GPIO_InitStruct.Pull = GPIO_PULLUP; — данная штука указывает что включена подтяжка к питаниюВозможные варианты конфигурации описаны чуть выше.

GPIO_InitStruct.Speed = GPIO_SPEED_LOW; — данная строчка настраивает скорость работы выхода

Возможны вот такие вариантыGPIO_SPEED_LOW — низкая скорость 2MHzGPIO_SPEED_MEDIUM — средняя скорость 25MHzGPIO_SPEED_FAST — повышеная скорость 50MHz

GPIO_SPEED_HIGH -высокая скорость до 100MHz

Также, чтобы работал наш порт, и мы что то могли с ним делать — нам нужно включить тактирование порта.

Так как мы создаём проект в CubeMX, то он за нас это всё делает, но на будущее, мало ли, может кто то захочет использовать старые библиотеки- не забывайте подавать тактирование на нужные вам порты.

В нашем случае тактирование наших портов включается вот таким образом/* GPIO Ports Clock Enable */__GPIOA_CLK_ENABLE();

__GPIOD_CLK_ENABLE();

Если поищем дальше, что обозначают эти строки то вот что найдём. Функция включения тактирования нашего порта A.#define __HAL_RCC_GPIOA_CLK_ENABLE() do { \__IO uint32_t tmpreg; SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);/* Delay after an RCC peripheral clock enabling */ mpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);UNUSED(tmpreg);

} while(0)

Ну а теперь код, с помощью которого мы управляем нашими пинами. HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9,GPIO_PIN_RESET); — сбрасывает пин в НОЛЬHAL_GPIO_WritePin(GPIOC, GPIO_PIN_9,GPIO_PIN_SET); — устанавливает пин в ЕДИНИЦУ

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_9); — изменяет состояние пина на противоположное. Если было 0, то станет единица, и наоборот.

Ну и добавлю сюда ещё одну функцию — функция задержки Delay. Мы её часто использовали в CAVR, и тут она тоже есть. Задаётся она в милисекундах и выглядит вот так — HAL_Delay(100);
Это означает задержка в 100 милисекунд.

Можете теперь поиграться светодиодами на плате, выставив задержку и используя HAL_GPIO_TogglePin. Ваши светодиоды будут по очереди перемигиваться.

Жмём палец вверх, и читаем, читаем, читаем мануалы, и уже в голове придумываем что мы сделаем на STM32! STM — мечты сбываются)))

Ну и не забываем про хорошую музычку, да погромче! Пока писал — наслаждался вот этим шедевральным концертом. С ним как то и светодиоды по другому перемигиваются))

Источник: https://www.drive2.ru/b/2212642/

STM32F407: быстрый старт

Источник: http://microsin.net/programming/ARM/stm32f407-quick-start.html

Микроконтроллеры Процессоры, проекты, программирование

Настройка порта GPIO в STM32 для цифрового ввода/вывода требует выполнения двух основных действий – подключения тактового сигнала и настройки режима работы. Также, при необходимости, выполняется блокировка настроечных параметров.

Пример 1. Вариант настройки, с использованием структур языка С

RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // Подключение тактового сигнала
GPIOC->CRH |= GPIO_CRH_MODE8; // Настройка режима PORTC.

8 с частотой 50 МГц
GPIOC->CRH &=~GPIO_CRH_CNF8; // Установка простого режима цифрового выхода
 

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

Первая строчка выполняет функцию подключения PORTC к шине APB2. Запись RCC->APB2ENR представляет собой обращение к регистру APB2ENR из группы  регистров тактирования и контроля RCC. RCC_APB2ENR_IOPCEN есть определение значения управляющего бита PORTC в регистре APB2ENR.

В числовом виде данное значение выглядит как 0x00000010. Для установки используется оператор «ИЛИ», так как в данном регистре уже есть настроенные биты. Использовать чистое присваивание в данном случае нельзя.

Вторая строчка устанавливает режим работы выхода 8 в PORTC. Опять используется константа GPIO_CRH_MODE8 = 0x00000003, устанавливающая линию на выход с максимальной частотой.

Также можно использовать GPIO_CRH_MODE8_0 =0x00000001 или GPIO_CRH_MODE8_1=0x00000002, которые устанавливают порт на выход с частотой 10 и 20 МГЦ соответственно. Для других линий ввода/вывода используются точно такие же константы, имеющие номер соответствующей линии.

Следует учитывать, что настройка линий с 0 по 7 производится обращением к регистру GPIOC->CRL.

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

Делается это использованием оператора «И» и инверсией константы GPIO_CRH_CNF8. Последняя, в ее прямом значении, устанавливает режим альтернативного вывода с открыты стоком, так как ее значение равно 11.

Доступны константы GPIO_CRH_CNF8_0 = 0x00000004 (режим 01) и GPIO_CRH_CNF8_1 = 0x00000008 (режим 10).

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

Пример 2. Настройка порта «классическим» способом

RCC->APB2ENR |= 0x00000010; // Подключение тактового сигнала GPIOC->CRH = 0x00000333; // Настройка режима PORTC.

8,9,10 с частотой 50 МГц

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

Это несколько снижает объем исходного кода и больше напоминает программирование на ассемблере.

Первая строчка полностью аналогична первому примеру. Вторая выполняет настройку сразу трех линий ввода вывода. Каждый разряд используемого операнда отвечает за одну линию. В итоге одной строчкой можно настроить половину порта ввода/вывода.

Значение параметра соответствующей линии записывается в шестнадцатеричной форме, и устанавливает сразу оба поля CNF и MODE.

Так значение 3h соответствует 0011 или режиму простого вывода с максимальной скоростью, а значение Bh  то же самое, что и 1011 или высокоскоростной выход, подключенный к альтернативному модулю.

Пример 3. Настройка порта на вывод

GPIOC->CRH = 0x00008333;

Данный пример осуществляет установку линий 8,9,10 как выходов, а линию 11 как цифровой вход. Для этого в поля CNF11и MODE11 заносится значение 8h или в двоичном виде 1000b.

Вывод информации

Запись данных в регистр производится самым обычным способом, с помощью операции равно.

GPIOA->ODR=0xABCD; GPIOA->ODR=0x0000;

При использовании регистра GPIOx_BSRR возможна как запись значений, так и предопределенных констант. Для установки высокого уровня сигнала применяются константы GPIO_BSRR_BSy, а для сброса GPIO_BSRR_BRy, где y – номер соответствующей линии.

Пример 4. Использование GPIOx_BSRR

GPIOC->BSRR=0x00010010; GPIOC->BSRR=0x00100001; GPIOC->BSRR=GPIO_BSRR_BS4|GPIO_BSRR_BR0; GPIOC->BSRR=GPIO_BSRR_BS0|GPIO_BSRR_BR4;

Первая и третья строчки устанавливают линию 4 и сбрасывают 0, вторая и четвертая производят обратную операцию.

Чтение состояния бита

if (GPIOC->IDR & GPIO_IDR_IDR11) GPIOC->BSRR = GPIO_BSRR_BS8;

Данная строчка выполняет опрос бита 11 регистра GPIOC->IDR и установку бита 8 в случае положительного результата. Также при программировании STM32 возможно простое присваивание значения регистра IDR какой-либо переменной.

Все, вышеуказанные примеры были опробованы на плате STM32 Discovery и показали свою работоспособность.

You have no rights to post comments

Источник: https://mcucpu.ru/index.php/stm32/83-stm32gpioprimers

GPIO: мигаем светодиодом

Наконец-таки мы приступим к оживлению устройства и научимся мигать светодиодом. Создайте проект lesson_01_led (или добавляйте функционал в файлы leds.h и leds.c).

Итак, порты ввода-вывода общего назначения уже упоминались ранее, и настало время воспользоваться полученными знаниями, дабы зажечь светодиод (любой из трех на плате). Сразу же возникает вопрос о том, как правильно подключить светодиод к МК, но об этом в самом конце курса.

Сейчас нас должно заботить только одно – как заставить его светиться. Абстрагируемся от физики и допустим, что если на ножку подать логическую «1» (т. е. напряжение 3,3 В), то светодиод загорится. Если же мы прдадим логический «0», соответственно, светодиод гореть не будет.

Как видите, один вывод (анод, он же «плюс») светодиода подключен к микроконтроллеру, а второй вывод (катод, он же «минус») подключен к земле. Вам должно быть известно, что ток побежит через светодиод в сторону земли.

Критически важно научиться работать с документацией, и начнем мы именно с этого. Для начала откройте принципиальную схему устройства из раздела «обзор конструктора» и найдите светодиод, который хотите зажечь (LED1, LED2 или LED3).

Читайте также:  Антенна для диапазона 160м с низкой высотой подвеса

Здесь нам нужно выяснить, к какой ножке подключен светодиод. Допустим, мы хотим использовать LED1, который подключен к PB0. Что же это такое? Портов в микроконтроллере может быть несколько, и обозначаются они буквами A, B … F. В stm32 каждый порт может иметь 16 выводов.

Значит, LED1 подключен к порту B, ножке номер 0. По умолчанию все периферийные устройства, к которым относятся и порты ввода-вывода, отключены от системы тактирования.

И правильно – зачем питать те модули, которые не используются? В разделе «Что у микроконтроллера под капотом» была представлена диаграмма с внутренним устройством МК, на которой можно заметить, что порты подключены к шине APB2.

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

  • включить тактирование порта B;
  • настроить 2-ю ножку порта B на выход;
  • управлять этой ножкой.

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

// leds.h

void init_leds(void);

// leds.c
void init_leds() { // Код по настройке ножки
}

Добавьте функцию инициализации светодиодов в оговоренную в прошлом разделе функцию init_mcu(), в которой будут вызываться все инициализирующие функции нашей программы.

// main.c
int main() { init_mcu(); while(1) { // Включаем и выключаем светодиод }
}

Пожалуй, наиболее важным документом, с которым нам придется работать, является Reference Manual.

В нём содержится описание всего адресного пространства и всех регистров микроконтроллера, а также того, за что они отвечают. Как нам известно – регистр не что иное, как ячейка памяти.

Следовательно для того что бы включить тактирование порта B нам необходимо записать единицу по определённому адресу.

Давайте откроем данный документ и найдем в оглавлении пункт, «2.2 Memory organization». Интересующей нас пункт «Reset and clock control RCC» (модуль системы тактирования), имеет адрес 0x40021000.

Сам модуль имеет много разных регистров, нам очевидно необходим тот, что отвечает за порты ввода-вывода. Обратимся снова к оглавлению и в «6 Reset and clock control (RCC)» перейдём к пункту «6.3.7 APB2 peripheral clock enable register (RCC_APB2ENR)».

Как видим, здесь указан не абсолютный адрес, а смещение относительно 0x40021000 – 0x18. Следовательно необходимый нам адрес – 0x40021018. Получается, что для включения тактирования необходимо просто в регистр APB2ENR записать на место четвёртого бита единицу. Как это сделать? Очень просто!

*((u32 *)0x40021018) = 0x00000008;

Но, конечно же, никто так код не пишет (21 век, как-никак). Для каждой периферии заведена структура, в которой хранятся переменные, связанные с соответствующими регистрами. В нашем случае это структура RCC. Так выглядит запись «1» на место третьего бита:

RCC->APB2ENR |= 1 APB2ENR |= RCC_APB2ENR_IOPBEN;

Так намного лучше. Согласно намеченному нами плану, необходимо настроить порт на выход.

Перейдем к разделу General-purpose I/Os (GPIO), подразделу GPIO registers. Первые два регистра, которые мы встречаем, называются GPIOx_CRL (L, нижний) и GPIOx_CRH (H, высокий). (Названия регистров могут отличаться от микроконтроллера к микроконтроллеру.

Так, например, в stm32f103 регистры MODE и CNF разделены на большее число (функционал логически обособлен) регистров.) Так как ножек на одном порте может быть 16, а под настройку режима и скорости каждого нужно по 4 (22) бита, то в общей сложности их требуется 64.

Поскольку мы хотим настроить нулевую ножку, нам необходимо произвести запись в MODE0 и CNF0 соответственно.

Настроим MODE0.

Ножка должна работать в режиме выхода. Раз скорость для нас не важна, то пусть это будет 2 МГц. Другими словами, в нижний регистр нужно записать «0», а в верхний – «1».

GPIOB->CRL &= ~GPIO_CRL_MODE0_0;
GPIOB->CRL |= GPIO_CRL_MODE0_1;

Теперь нужно настроить сам режим работы – двухтактный выход.

GPIOB->CRL &= ~GPIO_CRL_CNF0;

На этом настройка завершена. Теперь, если мы запишем в выходной регистр «1», то на выходе появится напряжение 3,3 В, и соответственно, если запишем «0», на выходе будет 0 В.

while(1) { GPIOB->ODR |= GPIO_ODR_ODR0; for (uint32_t i = 0; i ODR &= ~GPIO_ODR_ODR0; for (uint32_t i = 0; i

Так как мы еще не умеем делать правильные задержки, просто заполним процессорное время обработкой цикла на 1 миллион операций. Для выполнения такта процессора используется ассемблерная инструкция NOP (сокращение от английского: «No OPeration»), которая говорит процессору пропустить один такт работы (ничего не делать в течение него).

Подумайте, при помощи какой логической операции можно сократить код переключения состояния на две строчки.

Ответ:

GPIOB->ODR ^= GPIO_ODR_ODR0;
for (u32 i = 0; i

Осталось лишь запустить программу!

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

Код урока можно найти на github.

Источник: http://stm32.chrns.com/post/149088613644/gpio

STM32: Урок 4 – GPIO

GPIO (General Purpose Input-Output) — это выводы общего назначения, ноги микроконтроллера, доступные для прямого управления.

Это обычно довольно дефицитный ресурс во многих популярных МК, но с STM32 эта проблема теряет актуальность: в самом мелком корпусе (LQFP48) доступно 37 GPIO, а в самом большом (LQFP176) — 140 GPIO.

И всё это богатство ещё и настраивается вдоль и поперёк. Но, обо всём по порядку.

Для начала откроем и взглянем на схему вывода порта:

Сами МК питаются 3.3 В, но до сих пор ещё активно используются 5-вольтовые микросхемы и логика, а их нужно как-то подключать. Поэтому в STM32 большинство выводов «толерантны» к 5 В — уж не знаю, как ещё перевести термин «5 V tolerant».

То есть, они могут принимать на вход 5 В без какой-либо угрозы их здоровью. Толерантный пин отличается от обычного только тем, что у него верхний защитный диод подключён к Vdd_ft вместо Vdd.

Из этой схемы становится понятно, что хоть выводы и толерантны к 5 В на вход, но вот выдавать 5 В на выход не могут — тут уже нужен транзистор. Если нужно получить логическую единичку, то это не проблема — 3.

3 В вполне распознаются 5-вольтовой логикой как 1, но если нужно именно 5 В, то есть решение — режим Open-drain у GPIO. Всего у STM32F10x режимов GPIO имеется 8.

Выход общего назначения:

  • Push-pull, стандартный выход: выставляешь 0 в выходном регистре — получаешь низкий уровень на выходе, выставляешь 1 — получаешь высокий.
  • Open-drain (открытый сток, аналог открытого коллектора): вывод подключен к стоку N-MOS полевика в то время, как P-MOS полевик заперт, что позволяет управлять нагрузкой с большим напряжением, чем Vdd (3.3 В). Кому там нужно 5 В на выход? Ниже я расскажу, как их получить.

Выход с альтернативной функцией (для периферии типа SPI, UART):Вход:

  • Analog, аналоговый высокоимпендансный: подтягивающие резисторы и триггер Шмитта отключены. Используется при работе с АЦП.
  • Floating, обычный высокоимпендансный: подтягивающие резисторы отключены, триггер Шмитта включен.
  • Pull-up, вход с подтяжкой к питанию.
  • Pull-down, вход с прижатием у к «земле».

Как водится, линии GPIO объединены в порты, в STM32 — по 16 линий, поэтому нумеруются они с 0 по 15: PA0, PA1… PA15 — это линии порта A, например. Линии порта управляются программно с помощью нескольких регистров.

GPIOx_CRL и GPIOx_CRH — регистры конфигурации, содержат настройки режима (вход/выход) и частоты GPIO. Доступны на чтение и запись.

GPIOx_IDR и GPIOx_ODR — входной и выходной регистры: в первом хранится считанное со входов порта значение, во второй записывается новое состояние выводов. GPIOx_IDR доступен только на чтение, а GPIOx_ODR — на чтение и запись.

GPIOx_BSRR и GPIOx_BRR — регистры атомарного изменения битов в GPIOx_ODR.

Обычно, если нужно установить бит в регистре периферии, то его сначала нужно прочитать, потом применить побитовое 'ИЛИ' к считанному значению и битовой маске, после чего записать новое значение назад в регистр. То же и со сбросом битов, только маску нужно инвертировать и применить побитовое 'И'. А вот запись значений в GPIOx_BSRR и GPIOx_BRR изменяет только те биты выходного регистра, которые были установлены в единицу, притом происходит это за 1 такт, так что прерывание не сможет ворваться и всё испортить. Проиллюстрирую кодом:const uint32_t mask = 1 PB6, RX -> PB7 */ GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);Если вы два часа разводили двустороннюю плату, а потом обнаружили, что не можете развести какую-то сторону без огромной тучи переходов и перемычек, возможно, что функция переназначения выводов спасёт вашу клавиатуру от нелепой смерти под кулаком. Есть у GPIO и довольно диковинная функция — блокирование выводов. Я так и не понял, зачем она может понадобится, но суть такова: можно заблокировать изменение состояния любого GPIO до следующей перезагрузки МК. Активируется тоже несложно:/* Фиксируем состояния выводов PA6 и PA13 */ GPIO_PinLockConfig(GPIOA, GPIO_Pin_6 | GPIO_Pin_13);
Несколько слов об электрических характеристиках
В встречаются рекомендации подключать не более 20 выводов с отдачей 8 мА через каждый или не более 8 выводов с 20 мА, но практически нереально найти информацию по максимальному току на вывод. Но есть таблица, где приведена максимальная рассеиваемая мощность для МК целиком, причём для разных корпусов эта мощность разная. Например, для LQFP64, в котором идёт STM32F100RBT6B на STM32VLDiscovery, эта мощность равна 444 мВт, что при напряжении питания 3.3 В даёт силу тока ~134 мА. В другой таблице указано, что максимальный ток, потребляемый МК в режиме выполнения кода со всей включенной периферией при 100℃, составляет 15.7 мА. Итого имеем 134 — 15.7 = 118.3 мА на все выходы. Это максимальный ток, который может пропустить через себя МК, что немного расходится с рекомендациями. Впрочем, питать что-либо кроме светодиодов от MК в любом случае — плохая идея, а 118.3 мА хватит на пару-тройку десятков обычных светодиодов, которые при номинальном токе в 20 мА выжигают глаза, а при 1 мА вполне годятся в индикаторы.

Источник: http://robocraft.ru/blog/ARM/687.html

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}
");let k=document.querySelector(".flat_pm_modal[data-id-modal=\""+a.ID+"\"]");if(-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(k,d):jQuery(k).html(b+d),"px"==a.how.popup.px_s)e.bind(h,()=>{e.scrollTop()>a.how.popup.after&&(e.unbind(h),f.unbind(i),j())}),void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{e.unbind(h),f.unbind(i),j()});else{let b=setTimeout(()=>{f.unbind(i),j()},1e3*a.how.popup.after);void 0!==a.how.popup.close_window&&"true"==a.how.popup.close_window&&f.bind(i,()=>{clearTimeout(b),f.unbind(i),j()})}f.on("click",".flat_pm_modal .flat_pm_crs",()=>{jQuery.arcticmodal("close")})}if(void 0!==a.how.outgoing){let b,c="0"==a.how.outgoing.indent?"":" style=\"bottom:"+a.how.outgoing.indent+"px\"",e="true"==a.how.outgoing.cross?"":"",f=jQuery(window),g="scroll.out"+a.ID,h=void 0===flatPM_getCookie("flat_out_"+a.ID+"_mb")||"false"!=flatPM_getCookie("flat_out_"+a.ID+"_mb"),i=document.createElement("div"),j=jQuery("body"),k=()=>{void 0!==a.how.outgoing.cookie&&"false"==a.how.outgoing.cookie&&h&&(jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show"),j.on("click",".flat_pm_out[data-id-out=\""+a.ID+"\"] .flat_pm_crs",function(){flatPM_setCookie("flat_out_"+a.ID+"_mb",!1)})),(void 0===a.how.outgoing.cookie||"false"!=a.how.outgoing.cookie)&&jQuery(".flat_pm_out[data-id-out=\""+a.ID+"\"]").addClass("show")};switch(a.how.outgoing.whence){case"1":b="top";break;case"2":b="bottom";break;case"3":b="left";break;case"4":b="right";}jQuery("body > *").eq(0).before("
"+e+"
");let m=document.querySelector(".flat_pm_out[data-id-out=\""+a.ID+"\"]");-1===d.indexOf("go"+"oglesyndication")?flatPM_setHTML(m,d):jQuery(m).html(e+d),"px"==a.how.outgoing.px_s?f.bind(g,()=>{f.scrollTop()>a.how.outgoing.after&&(f.unbind(g),k())}):setTimeout(()=>{k()},1e3*a.how.outgoing.after),j.on("click",".flat_pm_out .flat_pm_crs",function(){jQuery(this).parent().removeClass("show").addClass("closed")})}countMode&&(flat_count["block_"+a.ID]={},flat_count["block_"+a.ID].count=1,flat_count["block_"+a.ID].click=0,flat_count["block_"+a.ID].id=a.ID)}catch(a){console.warn(a)}}function flatPM_start(){let a=flat_pm_arr.length;if(0==a)return flat_pm_arr=[],void jQuery(".flat_pm_start, .flat_pm_end").remove();flat_body=flat_body||jQuery("body"),!flat_counter&&countMode&&(flat_counter=!0,flat_body.on("click","[data-flat-id]",function(){let a=jQuery(this),b=a.attr("data-flat-id");flat_count["block_"+b].click++}),flat_body.on("mouseenter","[data-flat-id] iframe",function(){let a=jQuery(this),b=a.closest("[data-flat-id]").attr("data-flat-id");flat_iframe=b}).on("mouseleave","[data-flat-id] iframe",function(){flat_iframe=-1}),jQuery(window).on("beforeunload",()=>{jQuery.isEmptyObject(flat_count)||jQuery.ajax({async:!1,type:"POST",url:ajaxUrlFlatPM,dataType:"json",data:{action:"flat_pm_ajax",data_me:{method:"flat_pm_block_counter",arr:flat_count}}})}).on("blur",()=>{-1!=flat_iframe&&flat_count["block_"+flat_iframe].click++})),flat_userVars.init();for(let b=0;bflat_userVars.textlen||void 0!==a.chapter_sub&&a.chapter_subflat_userVars.titlelen||void 0!==a.title_sub&&a.title_subc&&cc&&c>d&&(b=flatPM_addDays(b,-1)),b>e||cd||c-1!=flat_userVars.referer.indexOf(a))||void 0!==a.referer.referer_disabled&&-1!=a.referer.referer_disabled.findIndex(a=>-1!=flat_userVars.referer.indexOf(a)))&&(c=!0),c||void 0===a.browser||(void 0===a.browser.browser_enabled||-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser))&&(void 0===a.browser.browser_disabled||-1==a.browser.browser_disabled.indexOf(flat_userVars.browser)))){if(c&&void 0!==a.browser&&void 0!==a.browser.browser_enabled&&-1!=a.browser.browser_enabled.indexOf(flat_userVars.browser)&&(c=!1),!c&&(void 0!==a.geo||void 0!==a.role)&&(""==flat_userVars.ccode||""==flat_userVars.country||""==flat_userVars.city||""==flat_userVars.role)){flat_pm_then.push(a),flatPM_setWrap(a),flat_body.hasClass("flat_pm_block_geo_role")||(flat_body.addClass("flat_pm_block_geo_role"),flatPM_ajax("flat_pm_block_geo_role")),c=!0}c||(flatPM_setWrap(a),flatPM_next(a))}}}let b=jQuery(".flatPM_sticky");b.each(function(){let a=jQuery(this),b=a.data("height")||350,c=a.data("top");a.wrap("
");let d=a.parent()[0];flatPM_sticky(this,d,c)}),debugMode||countMode||jQuery("[data-flat-id]:not([data-id-out]):not([data-id-modal])").contents().unwrap(),flat_pm_arr=[],jQuery(".flat_pm_start, .flat_pm_end").remove()}

[Что нужно для работы и отладки]

1. Установите IAR Embedded Workbench 6.30, это можно сделать на Windows 7 и Windows 8 (к сожалению, Windows XP не поддерживается).

2. Купите на ebay.com китайский J-LINK (строка для поиска JLINK Emulator V8 site:ebay.com).

3. Купите отладочную плату. Замечательный кандидат – STM32-P407 от Olimex (используется микроконтроллер STM32F407ZGT6).

[STM32F407ZGT6 – как сделать новый проект]

В качестве стартовой точки для нового проекта можно просто открыть пример, который предоставлен IAR или Olimex, и начать редактировать и изменять его. Так сделать проще всего, но недостаток в том, что появляются длинные пути к файлам, и название проекта не соответствует Вашему техзаданию.

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

Этот проект будет просто мигать светодиодом.

1. Создание нового проекта C. Создайте в любом удобном месте диска каталог для нового рабочего пространства (workspace). Предположим, это будет каталог MyWorkspace. Запустите IAR 6.30, выберите пункт меню Project – Create New Project…, откроется окно выбора типа нового проекта. Выберите C -> main и нажмите OK.

Далее откроется окно, где предложат выбрать папку для нового проекта и имя файла проекта (файл с расширением *.ewp). Перейдите в папку MyWorkspace, создайте в ней новую папку HelloWorld, зайдите в неё и в поле имени файла введите имя проекта HelloWorld, нажмите кнопку Сохранить.

Выберите в меню IAR пункт File -> Save all. Откроется окно, где будет предложено выбрать папку и имя файла для рабочего пространства (файл с расширением *.eww). Выберите папку MyWorkspace, зайдите в неё, и в качестве имени файла введите MyWorkspace. Затем нажмите Открыть.

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

Корневой каталог проекта будет MyWorkspaceHelloWorld, а корневой каталог Workspace MyWorkspace (в этот Workspace Вы при желании можете добавлять другие проекты).

В каталоге MyWorkspaceHelloWorldтакже будут созданы подкаталоги Debug (туда по умолчанию попадают выходные и временные файлы результата компиляции), settings (папка для дополнительных настроек проекта), а также будут созданы файлы HelloWorld.dep, HelloWorld.ewd, HelloWorld.ewp и main.c.

2. Настройка проекта. Как ни странно, новый проект будет даже успешно компилироваться (если выбрать Project -> Rebuild all), но это вовсе не означает, что в результате компиляции будет получено именно то, что нам нужно. Необходимо выбрать тип процессора,

Откройте свойства проекта (Project -> Options…), на закладке General Options выберите Processor variant -> Device, нажмите кнопочку справа и выберите процессор ST -> STM32F407 -> STM32F407ZG.

Перейдите в раздел опций Debugger, и в выпадающем списке Driver выберите J-Link/J-Trace (если у Вас подключен именно этот аппаратный отладчик). Нажмите OK.

На этом минимальная настройка проекта закончена, его можно даже запустить в отладчике (Project -> Download and Debug). Но пока проект ничего не умеет, потому что в теле функции main (модуль main.c) нет никакого кода, стоит просто заглушка возврата нулевого значения:

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

Сделайте копию файла C: Program Files (x86) IAR Systems Embedded Workbench 6.5 arm examples ST STM32F4xx STM32F4xx_DSP_StdPeriph_Lib Project STM32F4xx_StdPeriph_Examples GPIO IO_Toggle stm32f4xx_conf.h, и поместите его в корень проекта, в папку MyWorkspaceHelloWorld.

Добавите в корень проекта HelloWorld новую группу, куда мы будем подключать библиотечные модули для управления периферией. Для этого нажмите правой кнопкой на имя проекта, выберите Add -> Add Group… -> и введите имя группы STM32F4xx_StdPeriph_Driver.

В каталоге рабочего пространства (у нас это папка MyWorkspace) сделайте копию папки Libraries, которую можно найти в папке примеров IAR C: Program Files (x86) IAR Systems Embedded Workbench 6.5 arm examples ST STM32F4xx IAR-STM32F407ZG-SK.

После этого добавьте в папку проекта STM32F4xx_StdPeriph_Driver готовый модуль Libraries STM32F4xx_StdPeriph_Driver src stm32f4xx_gpio.c. Для этого нажмите правую кнопку на папке проекта STM32F4xx_StdPeriph_Driver и выберите Add -> Add Files…

, и выберите нужный файл.

Добавьте в настройки проекта пути поиска для заголовочных файлов. Для этого откройте Project -> Options -> C/C++ Compiler -> закладка Preprocessor, и добавьте в Additional include directories пути поиска:

$PROJ_DIR$ $PROJ_DIR$..LibrariesSTM32F4xx_StdPeriph_Driverinc $PROJ_DIR$..LibrariesCMSISDeviceSTSTM32F4xxInclude $TOOLKIT_DIR$CMSISInclude

Здесь $PROJ_DIR$ макрос, который раскрывает абсолютный путь до папки, в которой находится файл проекта HelloWorld.ewp. Макрос $TOOLKIT_DIR$ раскрывает полный путь до рабочего каталога текущего инструментария IAR (C: Program Files (x86) IAR Systems Embedded Workbench 6.5 arm).

Добавьте в окно Defined symbols символы (они используются в заголовочных файлах):

STM32F40XX USE_STDPERIPH_DRIVER

4. Мигание светодиодом. Давайте сделаем проект более осмысленным – научимся мигать светодиодом STAT1, который установлен на отладочной плате STM32-P407.

Добавьте в папку проекта STM32F4xx_StdPeriph_Driver модуль stm32f4xx_rcc.c (Add -> Add Files…, выберите файл MyWorkspace Libraries STM32F4xx_StdPeriph_Driver src stm32f4xx_rcc.c).

Добавьте код инициализации ядра процессора. Создайте в Workspace группу EWARM (Add -> Add Group… -> введите имя группу EWARM -> OK) и добавьте туда файл startup_stm32f40xx.s (Add -> Add Files… -> выберите файл MyWorkspace Libraries CMSIS Device ST STM32F4xx Source Templates iar startup_stm32f40xx.s).

Также добавьте группу CMSIS, и добавьте туда модуль MyWorkspace Libraries CMSIS Device ST STM32F4xx Source Templates system_stm32f4xx.c.

Откройте файл исходного кода main.c, и замените его старый код на следующий:

/* Простейший пример мигания светодиодом для платы Olimex STM32-P407. Пример мигает светодиодом STAT1. */ #include “stm32f4xx.h”
GPIO_InitTypeDef GPIO_InitStructure;
//Простейшая функция задержки void Delay(__IO uint32_t nCount) { while(nCount–) {} } void main() { /* Разрешить тактирование GPIOF */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); /* Конфигурирование ножки PF6, туда подключен светодиод STAT1      платы разработчика Olimex STM32-P407 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOF, &GPIO_InitStructure); /* Бесконечный цикл мигания */ while(1) { GPIOF->BSRRL = GPIO_Pin_6; //STAT==1, светодиод горит Delay(3000000L); GPIOF->BSRRH = GPIO_Pin_6; //STAT==0, светодиод погас Delay(3000000L); } }

Светодиод STAT1 подключен к порту PF6 микроконтроллера (см. схему в архиве [2]).

Примечание: есть на мой взгляд некая несуразица в именовании регистров BSRRL и BSRRH, предназначенных для управления состоянием портов GPIO. Ведь по идее L значит Low, т. е. лог. 0, а H означает High, т. е. логическую единицу.

Но здесь почему-то происходит все с точностью до наоборот – установка бита в регистре BSRRL почему-то приводит не к сбросу порта в 0, а в установку его в 1. Аналогично установка бита в регистре BSRRH почему-то приводит не к установке порта в 1, а к его сбросу в 0.

Запись 0 никакого влияния на состояние порта не оказывает.

[Работа с портами ввода/вывода GPIO, примеры IOToggle и JTAG_Remap]

Запустите IAR 6.30, на стартовой странице выберите EXAMPLE PROJECTS -> ST -> STM32F4xx -> CMSIS and STM32F4xx stdperiph lib 1.1.0 -> GPIO, далее выберите папку, куда будет копирован пример. Откроется окно Workspace, где будет два примера работы с портами ввода-вывода: “IOToggle – STM324x7I_EVAL” и “JTAG_Remap – STM324x7I_EVAL”.

Порты GPIO подключены к шине микроконтроллера AHB. С использованием регистров BSRRH и BSRRL требуется только один цикл, чтобы установить в лог. 1 любой вывод микроконтроллера, и еще 1 цикл чтобы сбросить в его 0. Таким образом, ножки GPIO можно переключать с частотой шины AHB, поделенной на 2.

В этих примерах показывается, как использовать BSRRH и BSRRL (аббревиатуры расшифровываются как Port Bit Set/Reset Register High and Low) для переключения выводов IO.

Порты PG6 и PG8 (сконфигурированные в режиме output pushpull) переключаются в бесконечном цикле:- PG6 и PG8 устанавливаются в лог. 1 путем установки соответствующих бит в регистре BSRRL.

– PG6 и PG8 сбрасываются в лог. 0 путем установки соответствующих бит в регистре BSRRH.

В этом примере HCLK сконфигурирована на 168 МГц, так что PG6 и PG8 переключаются с частотой 84 МГц (на плате STM324xG-EVAL/STM32437I-EVAL туда подключены светодиоды LED1 и LED2). Чтобы достичь максимально возможной частоты переключения IO, опции Вашего компилятора должны быть сконфигурированы на максимальную оптимизацию по скорости.

Таблица 1. Содержимое папок примера GPIO IO Toggle.

GPIO/IOToggle/stm32f4xx_conf.h Файл конфигурации библиотеки.
GPIO/IOToggle/stm32f4xx_it.c Обработчики прерывания.
GPIO/IOToggle/stm32f4xx_it.h Заголовочный файл для stm32f4xx_it.c.
GPIO/IOToggle/main.h Заголовочный файл для main.c.
GPIO/IOToggle/main.c Основная программа.
GPIO/IOToggle/system_stm32f4xx.c Системный файл кода STM32F4xx (настройка тактовой частоты).

Примечание: файл system_stm32f4xx.c сгенерирован автоматически инструментарием конфигурации тактовой частоты (clock configuration tool), и может быть просто откорректирован с учетом Ваших потребностей. Чтобы выбрать другие настройки тактирования, используйте файл STM32F4xx_Clock_Configuration_V1.1.0.xls, предоставленный в апноуте AN3988, доступном на сайте ST [4].

По умолчанию проект настроен на запуск в симуляторе, но его легко можно перенастроить на загрузку через JTAG, и он будет работать на реальном железе (Options -> Debugger -> в выпадающем списке выберите J-Link/J-Trace). Проект GPIO IO Toggle можно с успехом использовать как стартовую точку для своих собственных проектов, особенно если Вы только начинаете разбираться с платформой STM32.