Для мучений и изучений данного девайса. Сказано, сделано. Была собрана платка и пошло поехало. Ах да! Тема нашего разговора зашла о сравнении двух МК. Один выше сказанный против ATmega328. Почему именно они. Оба МК в корпусе TQFP-32. (Правда ATmega328 бывает и в DIP корпусе)
Теперь давайте рассмотрим по ближе их внутренности. Для большего понимания я собрал все необходимые данные в одну табличку.

Параметры ATmega328 STM32F030K6T6
Разрядность 8 бит 32 бита
FLASH 32кб 32кб
SRAM 1кб 4кб
EEPROM 512б -
Таймер 8 бит 2 шт -
Таймер 16 бит 1 шт 16 шт
ШИМ 3 канала 6 каналов
USART 1 шт 1 шт
SPI 1 шт 1 шт
I2C 1 шт (TWI) 1 шт
АЦП 8 каналов 10 бит 16 каналов 12 бит
Питание 2,7 - 5,5 2,4 - 3,6
Скорость 0 - 16МГц 48МГц при внешних 4 - 32МГц
Стоимость 160 - 170 руб. 80 - 140 руб.
Как видно из таблицы, STM32 довольно интереснее и богаче чем AVR. Есть правда одна мелочь. У STM32 нет EEPROM, но зато есть DMA которое просто убивает AVR напрочь. Правда AVR может похвастаться Ардуиной и простатой программирования. Да не спорю, но у STM32 есть STM32Cube, который генерит код для IAR и берет на себя всю рутину настройки периферии. И последний гвоздь в "гроб" AVR это RTOS. Да, на AVR тоже можно установить, но с ней надо разбираться, а в STM32 ставим галочку "FREERTOS" и все. Система сама сделает все что нужно, а нам останется только создавать потоки и писать код в них. Ну это так для затравки. На самом деле там все немного сложнее. Короче STM32 мне нравится и для того чтобы окончательно склонить вас на эту платформу, бросив в ящик стола Ардуину, я создам от начала до конца плату и покажу как с ней работать. О, забыл. У всех STM32 есть отладчик SWD. Это три провода SWDIO, SWCLK, GND и можно скакать по строкам кода прямо в железе, а не как у ATmega328 виртуально в Протеусе. Для этого нужен всего лишь универсальный программатор ST-LINK. Его можно использовать если приобрести плату Discovery или отдельно программатор . А теперь от слов к делу.
Схема. Покрупнее
Данную плату я делал как модуль для своей отладочной платы под AVR. Но ее можно повторить разведя плату по своему усмотрению (Проект под DipTrace я выложу в конце статьи). Что на схеме. А на схеме простая обвязка как и для AVR. Кварц на 8МГц с двумя конденсаторами по 20p. Так же как и в AVR собрана схема питания для опорки АЦП. Цепь сброса как у AVR. Единственное отличие это цепь BOOT. В отличии от AVR у всех STM32 на борту есть железный загрузчик. По умолчанию он выведен на USART. То есть если прижать к питанию ножку BOOT0 и рестартануть МК, то при помощи программы Flash Loader Demonstrator можно прошить МК без программатора. Данная фишка полезна если у вас уже есть готовое и работающее устройство и необходимо обновить прошивку, то нужно лишь переходник USB USART. Многие не хотят связываться с STM32 из-за питания не более 3,6 вольт. Ерунда. Если посмотреть в таблицу пинов, то можно заметить что все ножки могут принимать на себя 5 вольт без последствий. Поехали дальше.

А так она выглядит установленная на плату.

Теперь подключаем программатор ST-LINK-GA к SWD разъему.

Теперь когда все готово, качаем свежую версию с сайта ST (ссылка в самом низу страницы). Устанавливаем и запускаем.

Жмем New Project. И в появившемся окне находим наш контроллер. Жмем Ок.

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

Расписывать что и зачем я не буду, так как это тема отдельной статьи. Сейчас для примера просто сделайте то что я покажу. Что мы будем делать. Мы запустим операционную систему и в единственном потоке будем моргать светодиодом. Этакий "Хелой Ворд" из пушки.))) Для этого в левом окошке нажмите на плюс у надписи "FREERTOS" и в выпавшем списке поставте галочку.

Причем как только будет выбран внешний кварц, справа на контроллере подсветятся зеленым ножки на которые нужно его повесить. Следующим делом надо выбрать ножку на которой будет висеть светодиод. Я выбрал порт В и пин 0. И нашел граблю.Я с перепугу что ли, не знаю зачем, перевернул выводную гребенку первых четырех пинов к верху ногами. Отсюда неразбериха на порте В. Этот косяк касается только моей платы. Но ничего, от этого МК работать не перестал. И так как настроить пин. Дело в том что у STM все пины могут принимать кучу значений, но если касаться дискретного ввода/вывода, то на выход может быть три варианта. Выход в воздухе, выход с подтяжкой к плюсу питания, выход с подтяжкой к общей шине. По умолчанию STM32CubeMX вешает ножку в воздухе. Ну и пусть, нам же нужно просто проверить работу и продемонстрировать силу STM32. Для того чтобы настроить ножку, нужно щелкнуть по ней левой кнопкой мышки и в появившемся окне выбрать GPIO_Output. Если МК мелковат, то можно покрутить колесиком и увеличить его.)))

Следующим этапом нужно настроить тактование МК. Дело в том что у STM32 с этим делом очень мутно. В отличии от AVR у STM32 на входе стоит кварц с частотой от 4 до 32 МГц, а на шинах его можно разогнать до 48 МГц. Внутри МК очень сложная система тактования, но на помощь нам идет опять STM32CubeMX. Переходим во вкладку Clock Configuration и настраиваем как на картинке ниже.

Вот и все. Жмем на иконку с шестеренкой на верху.

Появится вот такое окно.

А вот тут я забыл сказать. Скачайте и установите себе IAR. Его можно скачать у официалов но урезанный по количеству кода, либо можно найти в торрентах. Либо если много лишних денег, то можно и прикупить лицензию. Ну я думаю многие пойдут по тропе с CodeVisionAVR. В общем это оставляю на ваше усмотрение. У меня версия 7.40. Возвращаемся к Кубу. В окошке назовите проект, но только латинскими, IAR не любит русские буквы в путях. И задайте где будет хрониться проект. В окне IDE нужно выбрать (а он по умолчанию) EWARM. Жмем Ок. Программа думает, а потом выдает вот такое окно. Бла-бла-бла. В общем жмем открыть проект (для тех кто в танке средняя кнопка).

Окно исчезнет, а вместо него запустится IAR и наш проект. Слева заходим в Aplication->User и запускаем main.c. Вот эта куча кода и есть то что нагенерил за нас STM32CubeMX.

И что теперь с этим ужасом делать? А вот для этого нужно целую серию статей))) А сейчас просто находим вот такой кусок кода.

Это и есть наш единственный поток. В теле цикла for(;;) удаляем единственную функция osDelay(1);, а вместо нее запишем вот такой код. HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
osDelay(500);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
osDelay(500);

Чудненько. Теперь просто жмем на кнопочку с зеленой стрелочкой справа на верху и ждем компиляцию и загрузку.

Если все правильно и без ошибок, то программа соберет весь проект, создаст все что нужно и загрузит прошивку в МК. После этого перейдет в режим отладки. Вот он родной. Мечта AVR-щика. Если есть не преодолимое желание поюзать, то можно прям на железе походить по шагам, строка за строкой. А если охота посмотреть как работает программа, то жмен на крестик сверху слева и наслаждаемся микание светодиода.

Вот и все. Микроконтроллеры можно купить по самой низкой цене аж по 78 рублей за штуку в магазине ЧипРезистор . Ну а если хочется по дешевле то есть и мелкий опт. От 35 штук уже по 50 руб.
Проект для DipTrace.
И конечно же видео.


гость 31.12.15 10:35

Недавно хотел сделать частотомер на АТМЕГА16 плюс внешний 8 бит счетчик на 74логике, -не хватило быстродействия.На ассемблере писать-голова не выдержит,городить внешний счетчик на 16 бит-геморойно.АВР - это прошлый век, недешевый контроллер.Поддержу автора, АВР это пройденый этап,я тоже купил чип stm32f100 плюс чип адаптера ЮСБ CP2103, скоро от АВР все откажутся.

Алексей 31.12.15 12:26

Я не согласен. Все таки еще развивается Arduino и многие на нее подсели, а последняя в свою очередь работает на AVR. Переход на STM это что-то вроде перехода на следующий уровень. Так сказать из Детсада в школу.

АНОНИМ 12.02.16 10:44

AVR и STM32 это процессоры не конкурирующие друг с другом. В вашей табличке нет самого главного параметра - это ток потребления!! А посмотрев на них - можно прослезится. Atmega 328 - – Active Mode: 0.2 mA – Power-down Mode: 0.1 µA – Power-save Mode: 0.75 µA (Including 32 kHz RTC) STM32F030K6T6 48 MHz - Active Mode: периферия включена 23.3 mA периферия выключена 11.5 mA - Stop Mode: 0.048 mA STM32 жрёт электричество нещадно - грубо говоря в 100 раз больше чем AVR. От батарейки девайс на STM32 не запитаешь. А вот AVR будут работать месяцами. Так что отказаться от AVR трудно. Удачи всем.

Алексей 12.02.16 10:54

А никто и не предлагает отказаться от AVR. Я лишь показа разницу в периферии. Я до сих пор поддерживаю библиотеку для AVR и до сих пор мой основной МК ATMega8A.

Сергей 24.02.16 18:02

На мой взгляд как то странно сравнивать свежие STM32 с пенсионерами AVR. Если хотите сравнивать STM32 с контролерами ATMEL, то сравнивайте их с семейством ATSAM но не как ни с AVR.

Андрей 24.02.16 18:06

Это кто это пенсионер? AVR жив и будет еще жить хрен знает сколько. И глядя в таблицу, сравнение по моему идет больше по периферии, а не по архитектуре.

Алексей 24.02.16 19:04

Ну начинается. Давайте теперь обсудим АМД и Интел.

Сергей 24.02.16 22:02

На хабре один "знаток" написал, что у AVR нет параллельной шины для подключения стандартного LCD, а у STM32 есть...

Алексей 24.02.16 22:36

Что значит стандартный LCD? Это про FSMC? Так это не только для дисплея, это и для памяти. Просто параллельная шина. У AVR тоже есть, например у Mega8515. К ней через регистр-защелку можно SRAM подключить.

Сергец 25.02.16 06:24

Алексей, ну а я про что?! Такое впечатление, что вы даже не пытаетесь вникнуть в смысл моих сообщений.

Алексей 25.02.16 09:38

Ну, а какой смысл сравнивать два одинаковых микроконтроллера разных фирм. Оба на ядре ARM. Если совсем придираться, то тогда уж надо сравнивать AVR с STM8. Я то придерживался приближенностью периферии, формфактора и цены. И как раз разной архитектуры.

Адлан 03.06.16 17:40

Здравствуйте. Помогите, пожалуйста, кто может. Установил последнюю версию Куба 4.15, Библиотеки F1 1.4.0. Созданный пустой проект в EWARM не компилируется - больше сотни ошибок. ЧТо может быть? Спасибо [email protected]

Алексей 03.06.16 20:48

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

Doc 18.07.16 21:51

"Правда AVR может похвастаться Ардуиной и простатой программирования." ЧЕМ может похвастаться? ;D

Алексей 19.07.16 11:41

Это глупое сравнение. Во первых у STM есть аналог ардуины под названием нуклео. Программы пишутся в онлайн IDE прямо через браузер. А вот если плюсы лично камня, то. Частота работы ядра 72МГц, AVR и не снилась такая скорость. Конечно если маргать светодиодом, то разницы никакой, а вот если запустить ось и кучу периферии, то AVR сдуется. Разряднось, 32 далеко не 8. Попериферии на STM может находиться 3 I2C, 3 SPI, 6 UART, USB, CAN, Ethernet. Почти все имеет возможность ремапится, то есть переноситься на другие ноги мк. Есть так же DMA, это независимый сопроцессор для работы с периферией. Так что прерывания у AVR нервно курят в сторонке. Есть аппаратный SDIO для полноценной работы с CD картами, а не костыльный ISP в AVR. В общем там много чего еще есть, но самый жирный камень в огород AVR, это помехоустойчивосиь. AVR выбить пролегающим рядом кабелем от электромортора как нефиг делать, а вот STM нужно постараться. Так что язвить с ардуиной я бы не советовал.

гость 11.08.16 23:27

MICROCHIP поглотила AVR!))))))))))

Алексей 12.08.16 08:35

Опоздали с новостью, уже как лет пять назад.

Владимир 17.08.16 22:56

Алексей! В январе 2016 года фирма Microchip покупает Atmel за 3,56 млрд долларов.Каких 5лет?

Алексей 18.08.16 10:30

Это деюро, а дефакто это тянется аж с 2008 года. Так что я действительно ошибся, не 5 лет, а 8 лет назад.))))

Владимир 18.08.16 23:53

Алексей!Стал переходитьна stm32 !А насчёт потребления в авотономном режиме советует всё не тактировать, тогда и снизится ток потребления.

Олег 09.11.16 22:31

В datashet на STM не нашел графиков потребления оттактовой CLK системной как у AVR - а по тем табличкам что есть - STM32 вчистую проигрывает акак в обычном режмие, так и в Idle. Да и нет у этого STM32 тактовой в 72Мгц - только 48 макс, ивсе, так что даже при 32 разрядах 8 битник AVR - лучше получается, и кстати производитель в datasheet не написал сколько тактов в STM32 машинный цикл у него, так что если окажется 2 такта против 1 у AVR - то считай что 48/2=24 реальных Мгца - почти те же самые что и у 20 Мгц у AVR. Вот и вопрос - а чудо-то где у этого STM32 о котором Вы все талдычете?

АНОНИМ 09.11.16 23:03
Алексей 10.11.16 00:23

Я даже не хочу спорить. Что лучше Интел или АМД? Или Жигули или Волга? У СТМ есть аппаратный USB, CAN, Ethernet, SDIO и еще куча периферии которой AVRу только может присниться во сне. В конце концов есть ДМА как самостоятельный сопроцессор с прямым доступом к памяти перед которым все прерывания AVR нервно покуривают в сторонке. Например у первых сериях на борту сразу 3 UARTа, 2 SPI, 3 I2C. Ремап портов есть и не нужно ломать башку как развести плату. Если вам по нраву работать с AVR, то работайте, кто вам мешает. Я по сей день под мелкие проекты леплю меги восьмые и не жалуюсь. Ай да, воткните AVR рядом с пускателем и посмотрите как ему башку снесет наводками. У AVR нет защиты от ЭМН. Поэтому в автосигнализации всегда ставили ПИКи, так как АВР умирает в таких условиях. Да чего спорить, дохлый номер.

Корнет 27.11.16 21:22

Ну кстати уже есть ардуино и на STM32. Это и Амперка и Espruino всякие на JS) Тем более если Микрочип взял Атмел ну нафиг их

Алексей 27.11.16 21:44

Название Espruino пародирует Arduino, самую известную на тот момент хобби-платформу, но Espruino не совместима с классической Arduino Uno ни механически, ни программно.(цитата из Амперки)
Еще у меня есть плата Нуклео и она тоже никаким боком к Arduino не относится, разве что геометрией самой платы)))
Вообще по сути я использую тот МК, который подходит для текущей задачи.

Андрей 20.12.16 22:50

Кому нравится переплачивать: стоит attiny2313-20 - 2Kb-flash /128bit-ram/16bit_ timer -1/8bit_ timer -1 =2.1$ против stm32f103c8t6 64Kb-flash/20Kb-sram/16BIT timer (+контроль мертвого времени для двухканального режима ШИМ) -4/ADC-2/72MHz CPU/=2.3$.По-моему сделать измеритель импеданса цепи RLC c помощью авр практически нереально,либо городить 10 камней.А с STM и БПФ можно сделать(ДМА помогает).Попытался как-то сделать на Меге10 частотомер (точность 1 герц)- банально не хватило быстродействия (либо городить внешний 32-битный счетчик с регистром сдвига-откуда габариты).От АВР отказался год назад, AVR- выходит, для небедных людей.

Andrey 20.12.16 22:53

АНОНИМ писал-"И вот еще, цитата из описания STM32 на русском - "...С
момента
получения
прерывания
до
начала
выполнения
первой
команды
обработчика
прерывания
затрачивается
только
двенадцать
циклов
тактового
сигнала"

Это правда.Но перемножьте два 32-битных числа на avr - явно 8-10 тактов!

Алексей 20.12.16 23:31

Да, я уже сожалею что этот халивар начал.))))

Александр 21.12.16 00:27

Почитал коменты и вспомнил.
Два малыша в песочнице
Один дудука!
Второй, бибика!
Первый, ДУдука! (интонация более грозная)
Второй, БИБИКА! (С еще более выразительной интонацией)
Первый ДУДУКА! (Уже крича)
Второй БИБИКА!!! (Чуть ли не плача)
....
Закончилось эта баталия, оба стоят и плачат, один громче другова.)))

Вал 10.02.17 01:43

Какая частота будет если зациклить без задержки
while (1)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
}

Алексей 10.02.17 10:07

Та что на шине APB

Игорь 08.06.17 22:33

Так давайте сразу ноутбуки во встраиваемые системы встраивать, они же лучше чем СТМ в сотни раз, и пееферии там ну просто охрененно сколько, там уже и вай фай есть и блютузы и даже программаторы не нужны, сразу и монитор есть с клавой чтобы писать прогу и сразу запустить, и программаторы не нужны и отладчики.
Всё равно что купить себе на дачу в личное пользование экскаватор для того чтобы ИНОГДА выкапывать пару ям глубиной в пол метра.
Ставить в термостат, часы, весы СТМ ну по моему это не нормально. Кстати да, как насчёт энергонезависимой памяти, вот делаю я термостат, выставляю температуру, тут вырубается свет, и что, настройки потеряны. А ведь во встроенные системы которые должны настраиваться 1 раз для дальнейшей работы, значения должны сохраняться навсегда

Алексей 09.06.17 08:25

Ну например в чип-дип STM32F030F4P6 стоит 48р, а прямой аналог ATtiny2313 98р. Я думаю для построения термостата любого из них будет достаточно. А компенсация памяти у STM может быть в любом датчике температуры. Да хотя бы в том же DS18B20. А что касается ноутов, так в любом терминале приема оплаты как раз установлен ПК с ОС и монитором. Так что даже такие системы есть. При выборе МК в первую очередь выбирают тот что дешевле. Это если хобби, то можно купить ардуину дабы не заморачиваться с пайкой, а когда систему планируется ввести на производство и выпускать сотнями, то считается каждая копейка. И переплата за МК 50 рублей при его цене в 48 это непозволительная роскошь.

Руслан 17.06.17 21:46
Я ее переделал под хол!
Но при подключении вилазят еррори!
Нужна информация как работать с не родними библиотеками!
В интернете ничего не нашел там только расказивают как подключать родние библиотеки.
Если "плохо искал" то дайте ссилку где можно посмотреть или почитать как ето делать!
А еще лучше сделайте видео, думаю многим начинающим (и не только) оно будет интересно посмотреть!
Заранее благодарен!
Алексей 05.08.17 10:19
Руслан 22.11.17 12:17

Я имел ввиду ето https://www.youtube.com/watch?v=wOIlhRd-vN8
5 - 7 минута!!!

Руслан 22.11.17 12:18

Алексей подскажите пожалуйста как работать с перечислениями "enum" а то нигде нету такой информации и в ваших видео "Си для самих маленьких" тоже нету а мне как раз очень надо!
Когда баловался AVR-ками то такоє чудо как перечисления не встречал а сейчас заинтересовался STM-ками а там их очень много! И нету информации как с ними работать!
Есть такой пример из реального кода:


StatusCode MIFARE_Read(byte blockAddr, byte * buffer, byte * bufferSize);

Где StatusCode ето перечисление:


enum StatusCode: byte {
STATUS_OK , // Success
STATUS_ERROR , // Error in communication
STATUS_COLLISION , // Collission detected
STATUS_TIMEOUT , // Timeout in communication.
STATUS_NO_ROOM , // A buffer is not big enough.
STATUS_INTERNAL_ERROR , // Internal error in the code. Should not happen ;-)
STATUS_INVALID , // Invalid argument.
STATUS_CRC_WRONG , // The CRC_A do es not match
STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK.
};

Ето из ардуиновской библиотеки(С++), но Keil ругается на ето!
Как правильно записать возврат функцией перечисления?

Руслан 22.11.17 12:29

И еще как обьявить в функции одним из аргументов которой есть перечисление:


void PCD_WriteRegister(PCD_Register reg, byte value);

Где PCD_Register перечислениє:


enum PCD_Register: byte {
// Page 0: Command and status
// 0x00 // reserved for future use
CommandReg = 0x01 << 1, // starts and stops command execution
ComIEnReg = 0x02 << 1, // enable and disable interrupt request control bits
DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits
ComIrqReg = 0x04 << 1, // interrupt request bits
...
};

А reg ето как я понял име перечисления но его нигде нету обьявленним в коде и откуда оно взялось мне не понятно!
Много страний перечитал в интернете и нашел информацию что ети перечисления можно заменить дефайнами но все же хотелось би узнать как с ними работать!!!

Руслан 22.11.17 12:35

С нетерпением жду ответа!
Может снимите видосик как с ними работать,чтоб и для других било, думаю видео будет очень полезним потому что таких видео нету(по крайней мере я не нашел)!

Дмитрий 28.11.17 22:02

"простатой программирования"

Интересный орган для программирования контроллеров. Вообще как можно было сравнивать 32-битные с 8-битными непонятно. Как Порш Каен с Зарпорожцем.

Алексей 29.11.17 10:24

Можно сравнивать, можно. Просто нужно учесть что в данном сравнении Порш стоит дешевле Запорожца. По поводу урологии, так пикантнее. Так что исправлять не буду.

Константин 23.12.17 00:06

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

АНОНИМ 11.02.18 16:27

Почему вы сравниваете 32разрядный МК ST с 8разрядным Atmel. Глупое сравнение. Равносильно сравнивать 32разрядный Atmel AT91SAM с 8разрядными STM8 учитывая даже что у Atmel есть 32 разрядники еще мощнее

Алексей 13.02.18 12:18

Потому что на момент написания статьи, 8-ми бинтных ST не было в продаже, а по цене мега и СТМ32 стоят одинаково.

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

Мое обучение началось, когда я два года назад заинтересовался темой микроконтроллеров и инженер, у которого поинтересовался насчет них, выдал мне плату 300х200мм и сказал, что в ней стоит контроллер STM32F217ZGT6 и на этой плате есть все необходимое для обучения. «В общем, освоишь ее - все остальное покажется фигней» (он, правда, не сказал, что для моргания светодиодом надо настроить SPI, о котором на тот момент я даже не слышал). Спустя три не очень напряженных месяца бесплотных попыток, осознания слабости навыков программирования и огромного количества прочитанных статей пришлось все же раскошелится на STM32VLDISCOVERY и способом копирования программ и экспериментов с ними дело наконец-то пошло, но все равно медленно.

За полтора года успел поработать разработчиком, искал вакансии, где работают с STM32 (так как считаю, что сейчас это наиболее перспективные микроконтроллеры своего класса), нахватался опыта и когда дело дошло до диплома, вспомнил о своих наболевших мозолях. Идея с темой пришла мгновенно: «Отладочная плата на STM32 и (полноценный) обучающий курс (для самых маленьких) к ней».

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

Жизнь показала, что времени у меня было отнюдь не полгода, но все же все время, отведенное на диплом, почти закончилось, совсем скоро защита, но как не удивительно все не только готово, но и почти на 100% протестировано (на живых людях в том числе).

На выходе получилось следующее:

1. Сам курс (методическое пособие по-научному)

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

2. Отладочная плата на контроллере STM32F103RET6

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

Придя на первую работу в качестве разработчика электроники, я столкнулся с одним интересным мнением и, как оказалось, оно весьма распространено. Это мнение звучало примерно так: «Вот я программист и программирую микроконтроллеры, схемотехнику не знаю и знать не хочу, паять, кстати, тоже не умею». Пообщавшись с группой программистов вне фирмы, понял, что человек с моей работы далеко не одинок в своем мнении и хоть я его и не поддерживаю, понять и уважать мнение окружающих стоит, тем более это отлично вписывалось в тогдашнюю концепцию отладочной платы «все на борту». В связи с этим плата получилось достаточно «жирненькая», получила название STM32SB (SB-StudyBoard) V1.0b. Ниже разберем, что в нее вошло.

1. Микроконтроллер
Исходя из того, что я работал с микроконтроллером STM32F103RET6, он и был выбран для проекта.

2. Схема питания и аппаратный USB контроллера
В этом микроконтроллере есть встроенный USB, который было решено вывести на отдельный разъем.

3. Спикер
Было решено ввести для освоения ШИМ модуляции и обучению написанию мелодий.

4. Цифровой индикатор и сдвиговый резистор
Для одновременного освоения динамической индикацией и сдвиговым регистром было решено их совместить.

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

6. ЖК-дисплей
Стандартный ЖК-дисплей на 2 строки по 16 символов для освоения параллельного интерфейса.

7. Клавиатура
Матричная клавиатура, это нужно знать и уметь.

8. Расширитель портов ввода-вывода
Много портов ввода-вывода не бывает, а тут еще и I2C освоить можно.

9. Электронный термометр
Датчик температуры по 1-Wire, полезная вещь и ценный опыт работы с ним может пригодиться.

10. Электронный потенциометр
На этой вещице можно освоить полноценный SPI и попробовать сделать замеры изменения напряжения через АЦП.

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

12. Ключевые транзисторы
Так же на уровне моргания светодиодом, но вдруг кому принцип не понятен.

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

14. Преобразователь WIFI-UART(esp8266)
В схеме преобразователь участвует как разъем, также он указан и здесь. Используется уже довольно нашумевший модуль esp8266.

15. Преобразователь USB-UART
USB это всегда круто, сдесь используется чип CP2102.

16. JTAG и SWD
Ну куда же без этих вещей.

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

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

Вот список моих «косяков», того, чего я не заметил, забыл или даже не знал при разработке этой платы:

1. Понял, что пины SWD расположены с странном порядке и хоть работе платы это не мешает. Услышал, на мой взгляд, правильное мнение, что их стоит располагать так, как они расположены на STM32VLDISCOVERY, чтобы избежать недоразумений у нового пользователя.

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

3. Я разработал свой логотип для этой платы, который хотел перевести в PCB и разместить на плате, но забыл.

4. Для экономии места во второй ревизии платы я бы разместил некоторые не используемые пользователем SMD компоненты на нижней стороне платы.

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

6. Забыл подписать, где JTAG и SWD, так же у них не показано, как их подключать и если для JTAG и его разъемом BH-20 все не так сложно, то с SWD ситуация несколько опасней.

7. При разработке футпринта ЖК-дисплея вышел казус и отверстия оказались слишком малы для болтов М3.

8. У преобразователя CP2102 перепутаны выводы RX и TX. Так как я привык, что в документации приводится пример подключения относительно микроконтроллера, а не внешнего устройства, пришлось перерезать таки 2 дорожки.

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

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

11. Ну и, как водится, «хорошая мысля приходит опосля». Так, уже после получения платы я понял, что стоило сделать размер ее подходящий хоть под какой-нибудь корпус - видимо придется доработать во второй ревизии.

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

Напоследок покажу вам 3D модель этой платы:

И для сравнения фотографии ее же, как она получилась «в живую», вид с верху:

И вид с боку, чтоб было видно побольше «костылей»:

Извините, но весь проект до сдачи диплома выкладывать мне бы не хотелось, но после этой работы у меня встал вопрос, а стоит ли данный проект развивать? Меня посетила идея написать цикл статей, посвященных обучению, где был бы представлен такой вот полноценный курс по этой отладочной плате, где все написано простыми словами и объяснено на пальцах. Хотелось бы услышать от вас в комментариях насколько это было бы полезно и необходимо на настоящее время.

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

Микроконтроллеры для котят

Всем Мяу, котаны:)

Как-то раз от меня ушла кошка:(Ну и чем валерьянку лопать, я решил заняться делом, так сказать «на благо Родине». Давно уж хотел цифровыми устройствами заняться, да времени не было (сами понимаете, то спать, то с кошкой по крышам гулять), а тут как раз время-то и появилось. Ну-с начнём..)

Всё как обычно начинается с выбора. Ну вроде выбор-то небольшой PIC, да AVR. Последние мне как-то больше приглянулись. Нужен был ещё и USB программатор за неимением других портов на компьютере, от цены которого у меня чуть хвост не отвалился. Ещё Arduino есть - зверёк такой. Его и программировать по USB можно. Ну, думаю, "то что доктор прописал". В селе нашем его только через интернет-магазин достать можно. Нашёл, где по-выгодней, чуть не купил и... ОПА! Смотрю - STM32VL-Discovery. Что за зверь такой? Хм, STM32.. Что-то слышал краем уха.. А от характеристик усы дыбом, честно!

А лап-то у неё сколько!

Итак, попорядку:

  • У Arduino 14 цифровых портов ввода/вывода и 6 аналоговых входов. У STM32VL-Discovery 45 цифровых входа/выхода 10 из которых по желанию превращаются в аналоговые входы.
  • У Arduino 32 Кб для хранения программы и 2 Кб ОЗУ. У STM32VL-Discovery 64 Кб для хранения программ и 8 Кб ОЗУ.
  • У Arduino тактовая частота 16 МГц у STM32VL-Discovery же 24 МГц.
  • Любой микроконтроллер STM32 можно заменить другим STM32, но с лучшими характеристиками, без изменения схемы
  • STM32 можно программировать без программатора по COM порту (об этом чуть позже)
  • Цена Arduino на момент написания статьи ~1300 рублей, STM32VL-Discovery ~600 рублей. Это ж дешевле более чем в 2 раза!

А что дальше? В STM32VL-Discovery есть встроенный программатор/отладчик, который лёгким движением лапы (снятием перемычек) может программировать и отлаживать (отладка очень уж вещь полезная, но об этом чуть позже) микроконтроллеры STM32 за пределами платы. С Arduino такое не прокатит. То есть используя STM32VL-Discovery мы и деньги экономим и получаем большую производительность и свободу творчества:)

Да и сами микроконтроллеры STM32 выглядят привлекательней остальных:

STM32F100C4T6B ATtiny24A-SSU PIC16F688-I/SL STM32F103RET6 ATmega1284P-PU PIC18F4550-I/PT
Средняя цена, руб 60 65 60 240 330 220
Тактовая частота, МГц 24 20 20 72 20 48
Flash память, Кбайт 16 2 4 512 128 16
RAM, Байт 4096 128 256 65536 16384 2048
USART, шт 2 0 0 5 2 0
SPI, шт 1 1 0 3 1 1
АЦП, шт 16x12Bit 8x10Bit 8x10Bit 16х12Bit 8x10Bit 13x10Bit
ЦАП, шт 1x12Bit 0 0 2х12Bit 0 0
Количество линий ввода/вывода, шт 37 12 12 51 32 35

А ещё STM32 32-х разрядные, а это означает возможность работы с 32-х битными данными за один такт. AVR и PIC этим не похвастаются.

Ну что, котаны, убедил? Тогда начнём курс молодого бойца цифровика!)

Как оно работает? Из чего состоит? Что умеет?

Как известно, все коты очень любознательные, а радиокоты особенно!

Микроконтроллер - это микросхема сочетающая в себе функции процессора, периферии, имеющая ОЗУ, flash память. Как компьютер, только меньше!

Проведём аналогию: компьютером управляет операционная система, а микроконтроллером «прошивка», которую пишете Вы; операционная система компьютера хранится на жёстком диске, «прошивка» микроконтроллера в его flash памяти; функции ОЗУ схожи - хранение изменяющихся данных во время выполнения программы. А ещё у МК есть различные периферийные устройства, такие как АЦП и ЦАП например.

МК общается с внешним миром при помощи лап на его корпусе (не таких как у котов, конечно, а металлических). Но не все из них управляются программой, есть выводы питания, вывод сброса, выводы питания периферии, вывод резервного питания. А те, которые управляются программой делятся на группы называемые «порты». Все эти управляемые выводы называются 2-мя буквами и цифрой. Например PA1: P - порт, А - порт «А», 1 - номер вывода этого порта.

В программе порты конфигурируются либо на вход, либо на выход, по вашему желанию.

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

  • Цифровой вход - вход, значение которого (логическая 1 или 0) можно считывать программой. Если напяжение на входе 0, то значение равно 0, если на входе напяжение равное напрядению питания, то значение входа 1. Третьего не дано. Можно сделать с подтягивающим резистором либо к питанию, либо к массе
  • Аналоговый вход - вход значение которого можно считывать программой, но значений может быть много - целых 4096. А точнее от 0 если на входе напяжение 0 относительно минуса питания микроконтроллера до 4095, если на входе напряжение равное напряжению питания. Все эти преобразования делает АЦП - аналогово-цифровой преобразователь, при помощи его можно например измерять напряжение на терморезисторе и узнавать температуру или измерять напяжение на фоторезисторе и узнавать яркость попадающего на него света... Ну много чего можно придумать, если фантазия есть:) Если питать микроконтроллер от 3В, то 0В = 0, а 3В = 4096, значит 3/4096=0.000732421, т.е. при изменении напяжения на входе на 0.000732421В значение входа в программе меняется на 1. Не так-то всё и сложно, да? Идём дальше
  • Цифровой вход в режиме альтернативной функции - вход для работы с периферией. Например вход для таймера или вход для какого-нибудь интерфейса. Из программы значение этого входа считать нельзя. В программе можно например считать данные полученные по этому выводу каким-нибудь интерфейсом.

А у порта настроенного на выход выводы могут быть в таких режимах:

  • Выход. Просто выход. Обычный цифровой выход. На выводе либо напрядение питания (логическая 1) либо на выводе нет напряжения (логическая 0). Всё просто.
  • Выход в режиме альтернативной функции - выход управляемый периферией. Этим выходом нельзя управлять из программы, но программой можно заставить управлять этим выводом например интерфейс.

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

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

Ещё есть выводы BOOT 0 и BOOT 1 . Эти выводы не относятся к портам, они служат для управления загрузкой микроконтроллера. Если во время подачи питания на выводе BOOT 0 логический ноль (вывод соединен с общей точкой), то микроконтроллер выполняет программу загруженную во flash память, т.е. Вашу прошивку. Если во время подачи питания на выводе BOOT 0 логическая еденица (вывод соединен с питанием микроконтроллера), а на выводе BOOT 1 логический ноль, то микроконтроллер выполняет не Вашу прошивку, а записанный на заводе загрузчик. Запомните это! Вы будете часто пользоваться этим в процессе работы с микроконтроллерами STM32! Иногда загрузка записанного с завода загрузчика - единственный способ записать/изменить прошивку микроконтроллера. Это бывает например при конфигурировании в прошивке выводов, к которым подключается программатор или при прошивке микроконтроллера без использования программатора. Так что настоятельно рекомендую при проектировании печатной платы эти выводы (или хотя бы BOOT 0) распологать в удобном месте.

Вот разобрались:) Теперь знаем что такое микроконтроллер, из чего он состоит. Сейчас узнаем ещё о некоторых премудростях и перейдём к самому интересному - практике!

Программа в микроконтроллере выполняется пошагово. Один такт процессора - один шаг программы.

Например пусть перемигивается красная и зелёная лампочки, пока НЕ нажата кнопка. Длительность каждой лампы - 5 секунд. Вот алгоритм:

  1. Проверяем, на входе с кнопкой есть напряжение? (кнопка замыкает вывод микроконтроллера на + питания)
  2. Если нет напряжения, то загорается красная лампочка на 5 секунд, зелёная тухнет, если есть напряжение, то начинаем всё сначала
  3. Снова проверяем
  4. Если нет напряжение, то загорается зелёная лампочка на 5 секунд, красная тухнет, если есть напряжение, то начинаем всё сначала
  5. Начинаем сначала

СТОП! А если я нажму кнопку, пока горит лампочка? То ничего не произойдёт! Потому что программа выполняется пошагово, а шаг с проверкой нажатия кнопки находится в момент переключения лампочек.
Вот именно для таких случаев есть такая вещь, как прерывания

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

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

Встаём на лапы!

Ну, котята, пора вставать на лапы! Надеюсь у Вас уже есть отладочная плата? Или хотя бы микроконтроллер? Надеюсь есть:) А если нет, то бежим в магазин! (и желательно не за колбасой. хотя...) Какое же это учение без практики?

Отлично на первых порах иметь отладочную плату, например STM32VL-Discovery, но если жаба душит или всё-таки нехватает на колбасу, то можно обойтись и одним микроконтроллером и преобразователем интерфейсов RS-232 ->UART (напр. MAX3232) или USB ->UART (напр. FT232RL). В этом случае в 100 рублей можно вполне уложиться, но придётся делать печатную плату и паять минимум 48 выводов шириной 0,3 мм с зазором 0,2 мм. Я предупреждал.

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

Если у Вас отладочная плата:

С отладочной платой, конечно проще. Берём шнурок Mini-USB и соединяем плату с компьютером, все драйверы должны поставиться автоматически. Увидеть STMicroelectronics STLink dongle в диспетчере устройств - хороший знак! Ну а если что-то пошло не так и ничего не вышло - не надо царапать диван, нужно просто зайти сюда и установить STM32 ST-LINK utility .

Ну а если Вы счастливый обладатель компьютера под управлением Windows 8, то перед проведением вышеописанных действий нужно сделать так: Параметры -> Изменение параметров компьютера -> Общие -> Особые варианты загрузки и выбрать параметр Отключение проверки подписи драйверов .

Если у Вас микроконтроллер:

Если у Вас один микроконтроллер, то у Вас должны быть прямые лапы. Но я в Вас не сомневаюсь!

Перед подключением микроконтроллера к компьютеру его нужно припаять к печатной плате. Для этого кроме микроконтроллера и прямых лап нужна как минимум печатная плата. А тут уж Ваше творчество.

Рабочий минимум на схеме ниже:

Но это неинтересный минимум.

Добавьте светодиодов и кнопок (не забудьте про выводы BOOT), например так

А вот с пайкой этой блохи могут возникнуть проблемы. Но я надеюсь, не возникнут. Я накошачился паять её своим любимым советским 25 Вт паяльником с шириной жала в 3/4 ширины контроллера. У меня больше проблем с изготовлением печатной платы... ну тут уж у каждого своя технология.

И переходник нужно сделать на UART по документации к той микросхеме, которую купили.

Соединяем выводы TxD и RxD на печатной плате с выводами RxD и TxD соответственно переходника. Не забываем про общую точку и питание всего этого.

Выбор и установка ПО

Пользоваться мы будем средой разработки CooCox IDE , но это не просто так, а по нескольким причинам:

  • Во-первых это свободно распространяемое ПО. А это значит, что Ваша карма будет чиста
  • На мой взгляд (да и не только на мой) эта среда разработки удобнее остаальных
  • Позволяет использовать отладку
  • Много примеров, которые можно загружать в среду разработки (полезно для котят и не только)

Среда разработки - это программа для написания кода, компилятор, отладчик в одном. Удобненько:) Но если какому-то суровому Челябинскому коту удобнее писать код (в блокноте например), компилировать и прошивать разными программами - я не против, тогда Вам пригодится STM32 ST-LINK utilit для загрузки прошивки в микроконтроллер. Хозяин барин, как говорится.

Эта среда разработки основана на многим известном Eclipse.

  1. Идём сюда
  2. Тыкаем Download through CoCenter (Recommend)
  3. Вводим адрес эл.почты (можно от балды, он там «для галочки»)
  4. После загрузки устанавливаем этот самый CoCenter
  5. В первой строчке, где написано CooCox CoIDE тыкаем Download
  6. После того, как загрузка закончится, то вместо Download будет Install . Сюда и жмём
  7. Идём сюда
  8. Справа в колонке Download скачиваем файл который .exe. Устанавливаем его.
  9. Открываем сам CooCox CoIDE , вкладка Project , Select Toolchain Path .
  10. Указываем путь к файлу arm-none-eabi-gcc.exe (это мы установили в п.8, путь приблизительно такой: D:Program Files (x86)GNU Tools ARM Embedded4.7 2013q1bin)
  11. Снова открываем CoIDE , нажимаем View -> Configuration , открываем вкладку Debugger и делаем так [фото]
  12. Радуемся, потому что теперь мы можем написать программу и прошить её в микроконтроллер! Чем мы и займёмся.

Если у Вас вариант без отладочной платы/программатора, то для загрузки программы в МК понадобится программка Flash Loader Demonstrator которая находится

Находим общий язык

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

Проект состоит из файлов с расширениями .c и .h . В первых находятся функции во вторых названия используемых функций и константы например. Так уж заведено. Самый главный файл, в котором находится код программы main.c . Для использования различных функций нужно подключать библиотеки с этими функциями. Подключаются они записью #include "название_библиотеки" ну библиотеки естественно должны быть в проекте. Подключают их в самом начале файла.

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

тип_возвращаемой_переменной имя_функции (тип_переменной)
{
Тело функции
}

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

Перед тем, как использовать функцию, её нужно объявить в самом начале файла. Делают это в таком виде:

тип_возвращаемой_переменной имя_функции (тип_переменной);

Ах, да, забыл самое главное! В конце каждой строки должна быть точка с запятой!

Если функция ничего не возвращает (например временная задержка, она просто тянет кота за хвост время), то тип указывают void .

При запуске, первой всегда выполняется функция main() .

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

Выше я упоминал тип переменной . Все переменные могут быть разных типов, вот основные:

  • INT - переменная этого типа может быть только целым числом от -2147483648 до 2147483647
  • FLOAT - переменная этого типа число с точностью до 7 разрядов от ±1,5*10-45 до ±3,4*1033
  • DOUBLE - число с точностью до 16 разрядов от ±5*10-324 до ±1,7*10306
  • ULONG - тоже целое число, но от 0 до 18446744073709551615
  • LONG - целое от -9223372036854775808 до 9223372036854775807
  • CHAR - один символ
  • BOOL - логическая переменная. Она может иметь только 2 значения: истина (true) или ложь (false)

Строку (слово, предложение) можно представить как массив из символов типа char. Например:

char stroka = "Слово";

Здесь квадратных скобках - количество символов в строке, «stroka» - название массива.

Перед использованием переменной её нужно обязательно объявить. (просто указать тип переменной и имя)

  • + - сложение.
  • - - вычитание.
  • * - умножение.
  • / - деление.
  • = - присвоение переменной значения.

Например выражение a=b+c значит присвоить переменной a значение суммы значений переменных b и c .

  • ++ - инкремент. Увеличение значения переменной на 1
  • -- - декремент. Уменьшение значения переменной на 1

Например выражение a++ значит увеличить значение переменной a на 1 (то же самое, что и a=a+1 )

  • == - сравнение, знак «равно». (НЕ ПУТАТЬ С ПРИСВОЕНИЕМ)
  • != - сравнение, знак «не равно».
  • < - сравнение, знак «меньше».
  • <= - сравнение, знак «меньше или равно».
  • > - сравнение, знак «больше».
  • >= - сравнение, знак «больше или равно».

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

  • % - остаток от деления

Например если a=5 , b=3 , то значение выражения a%b будет равно 2 (т.к. 5/3=1 (ост.2))

  • << - побитовый сдвиг влево. Не вдаваясь в подробности значение выражения a< на языке Си будет равно выражению a*2 b
  • >> - побитовый сдвиг вправо. Выражение a>>b в программе равносильно выражению a/2 b
  • & - логическое И .
  • | - логическое ИЛИ .
  • ~ - инвертирование.

Чуть не забыл рассказать про циклы. Основные:

while(условие) {

тело цикла

Тело цикла (всё что в фигурных скобках) выполняется, когда условие истинно (пока условие не станет ложным).

for (начальное_значение; цикл_выполняется_до, шаг) {

тело цикла

Начальное_значение - начальное значение счётчика

Цикл_выполняется_до - до достижения какого значения выполняется цикл

Шаг - с каким шагом счетчик считает

Например

for (i=0; i<10, i++) {

тело цикла

Здесь начальное значение переменной i равно 0, цикл выполняется, пока значение переменной i меньше 10, при каждом выполнении цикла к переменной i прибавляется 1. Так же можно изменять значение переменной прямо в цикле.

if (условие){

тело 1

} else {

тело 2

В усовном переходе «тело 1» выполняется, если условие истинно и выполняется «тело 2», если условие ложно. Ещё есть такой вариант:

if (условие 1){

} else if (условие 2) {

В этом случае «тело 1» выполняется, если истинно «условие 1», «тело 2» выполняется, если истинно «условие 2». Таких условий может быть сколько угодно, так же может быть одно else.

Условия могут быть простыми и составными: простые - одно логическое выражение, а составное - несколько логических выражений соединённых знаком & (условия истинно, когда все условия соединённые этим знаком истинны) или | (условие истинно, если хотябы одно условие соединённое этим знаком истинно).

Ещё полезная вещь - комментарии. Помогут разобраться в забытом проекте:) или просто что бы что-то не забыть. Комментировать можно или после знаков // и до конца строки или начинаются знаками /* и заканчиваются */ , в таком случае комментарий может быть любое количество строк. На размер программы комментарии не влияют.

Ну вот, из основного вроде всё. На первое время хватит (до написания следующей части статьи)

Первая программа

Не будем отступать от традиций (а то мало ли) и начнём с Hello World. А по пути будем продолжать знакомиться с микроконтроллером и так сказать получать опыт.

Открываем среду разработки:

Нажимаем Browse in Repository

Выбираем ST

Потом мы увидим список подключаемых библиотек.

Для нашей простенькой программы нам понадобится: CMSIS core , CMSIS Boot , RCC , GPIO .

Библиотеки CMSIS core и CMSIS Boot - системные, их нужно подключать обязательно

Библиотека RCC для работы с системой тактирования

Библиотека GPIO для работы с портами ввода-вывода

Теперь слева в окне Project открываем файл main.c .

Сначала нужно подключить наши библиотеки (CMSIS подключать не нужно).

Идём в самое начало программы и добавляем строчки:

#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"

void Delay(int i) {
for (; i != 0; i--);
}

Так. Тут по порядку, функция ничего не возвращает, по этому void , название функции Delay , сразу объявляем переменную i типа int . В фигурных скобках тело функции - цикл for . Это его строчная запись. Начальное значение i мы не изменяем, цикл выполняется, пока i не равна нулю (как i становится равна нулю, цикл прекращается, функция «выключаеся»). С каждым выполнением тела цикла (тактом) переменная i уменьшается на 1. Т.е. суть цикла - просто повториться количество раз равное i . Пока выполняется цикл время идёт, происходит задержка.

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

Для тактирования порта С добавляем строчку:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);

Добавляем в прогармму строчку:

GPIO_InitTypeDef GPIO_Init1;

Этой строчкой мы объявили структуру GPIO_InitTypeDef - дали ей название GPIO_Init для использования в нашей программе далее.

Какие в этой структуре можно настроить параметры и какой вид они имеют, смотрим всё в том же stm32f10x_gpio.h :

Теперь чтобы настроить параметры выводов при помощи структуры нужно написать её название, поставить точку и появится окошечко в котором эти параметры указаны

Дважды щёлкаем по одному из них, и он появляется в строке, далее ставим = (присвоить) и прописываем значение из stm32f10x_gpio.h

Так же поступаем со всеми параметрами. Не забываем точку с запятой в конце каждой строки!

GPIO_Init(GPIOC , &GPIO_Init);

Теперь будем мигать! Мигать мы будем циклично, сделаем зацикливание в цикле while. Условие цикла будет 1. Еденица - всегда истина, нуль - всегда ложь.. такова се ля ви..

Чтобы подать ток на вывод нужно установить бит, чтобы выключить вывод нужно сбросить бит. Как это делать - всё в том же stm32f10x_gpio.h :

Делаем так:

while (1){

GPIO_SetBits(GPIOC, GPIO_Pin_9);

Delay (200000);

GPIO_ResetBits(GPIOC, GPIO_Pin_9);

Delay (200000);

1 всегда истина, значит цикл будет зацикливание.

GPIO_SetBits - функция установки бита

GPIO_ResetBits - функция сброса бита

Delay (200000) - на этой строчке выполнение программы переходит в функцию Delay , в ту самую, в которой цикл for . Число 200000 в скобках - передаётся в эту функцию, как переменная i . (помним строчку void Delay(int i) ?) и выполняется тот самый цикл в этой функции, все 200000 раз. Это быстро:) после окончания работы цикла for функция D elay заканчивает свою работу, т.к. она void , то она ничего не возвращает и программа продолжает выполняется дальше.

Т.к. while зациклен, то включение светодиода, задержка, выключение светодиода, задержка будут выполняться бесконечно циклично. Пока не выключится питание или не произойдёт прерывание (об этом в следующей статье).

Ну вот, первая программа готова. Теперь нажимаем F7, программа компилируется.

Теперь если у Вас отладочная плата, то подключаем её при помощи USB шнурка и нажимаем Download Code To Flash . Радуемся выполненной работе и полученным знаниям:)

А если у Вас не отладочная плата, то подключите к своей плате переходник сделаный ранее, а переходник к COM-порту компьютера. Далее соедините вывод BOOT 0 c плюсом питания микроконтроллера и включите питание микроконтроллера. Тем самым микроконтроллер войдет в режим прошивки. Вообще процедура прошивки не сложная. Нужно просто следовать указаниям приложения Flash Loader Demonstrator . Сначала указываем номер COM-порта, через который у Вас подключен микроконтроллер и скорость. Для воизбежании сбоев, скорость лучше выбрать поменьше

Если программа увидела Ваш микроконтроллер, то появится окно, в котором будет написано, сколько у него памяти

После нажатия «Next», Вы увидите страницу с адресацией памяти. Она нам не понадобится.

Следующий шаг самый ответственный. Можно выбрать очистку памяти или прошивку

Для прошивки выбираем Download to device и в поле Download from file выбираем компилированный.hex файл, который находится в папке CooCox -> CooIDE -> workspace -> имя_проекта -> имя_проекта -> Debug -> Bin . После снова нажимаем «Next».

После того, как увидим такое окно:

Отключаем питание микроконтроллера, закрываем Flash Loader Demonstrator , отключаем переходник, и включаем микроконтроллер в обычном режиме (когда при включении вывод BOOT 0 соединен с минусом питания микроконтроллера). Радуемся!

Итак, теперь мы знаем, чем микроконтроллеры STM лучше других, знаем как работает микроконтроллер, умеем прошивать микроконтроллер в отладочной плате и в своей плате, знаем основы языка Си, которые нужны для программирования STM32, получили опыт работы с микроконтроллером (надеюсь положительный) и самое главное, теперь Вы можете воплотить свои идеи цифровых устройств в жизнь (и поведать о них, на нашем любимом РадиоКоте)! Пусть пока ещё простенькие, но всё навёрстывается с опытом. А я постараюсь в следующих статьях рассказать об АЦП, ЦАП, прерываниях, использовании отладки и других полезностях.

Как вам эта статья?

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

Итак, для начала разберемся, что же нужно знать и уметь, чтобы начать изучать ARM’ы. А, в принципе, ничего супер сложного и фееричного 😉 Конечно, на контроллеры ARM люди обычно переходят, уже наигравшись с PIC’ами и AVR’ками, то есть в большинстве своем опытные разработчики. Но я постараюсь максимально подробно и понятно описывать все то, что мы будем разбирать, чтобы те, кто впервые решил попробовать себя в программировании микроконтроллеров, могли легко разобраться в материале. Кстати, если будут возникать какие-нибудь вопросы, или просто что-то будет работать не так, как задумывалось, пишите в комментарии, постараюсь разобраться и помочь.

Теперь перейдем к техническим вопросам) Несколько раз я уже упомянул название «Учебный курс ARM», но, по большому счету, это не совсем верно. Микроконтроллера ARM как такового не существует. Есть контроллер с ядром(!) ARM, а это, согласитесь, все-таки не одно и то же. Так вот, такие девайсы выпускает ряд фирм, среди которых особо выделяются, STMicroelectronics и NXP Semiconductors. Соответственно выпускают они контроллеры STM и LPC. Я остановил свой выбор на STM32, они мне просто больше понравились =) У STM очень подкупает, что разобравшись с любым МК из линейки STM32F10x, не возникнет никаких проблем и с любым другим. Одна линейка – один даташит. Кстати есть огромное количество как дорогих, так и не очень, отладочных плат с контроллерами STM32, что очень радует, хотя первое время будем отлаживать наши программы в симуляторе, чтобы оценить возможности контроллера, прежде чем покупать железо. Вот, на всякий случай, официальный сайт STMicroelectronics – .

Как то плавно выехали на тему компилятора, так что скажу пару слов об этом. Я, недолго думая, выбрал Keil, не в последнюю очередь из-за мощного встроенного симулятора. Можно и на UART там посмотреть, и на любой регистр, и даже логический анализатор имеется в наличии. Словом, у меня Keil оставил в основном только приятные впечатления, хотя есть и минусы, конечно, но не катастрофические. Так что можете смело качать Keil uvision4 с офф. сайта (). Правда есть одно НО – IDE платная, но доступен демо-режим с ограничением кода в 32кБ, которых нам пока с лихвой хватит. Кому этого мало есть огромное количество кряков для Keil’а 😉 Устанавливается все без проблем – пару раз тыкаем далее и все отлично ставится и работает без дополнительных танцев с бубном.

Собственно, вот и все, что я хотел тут рассказать, пора переходить от слов к делу, но это уже в следующей статье. Будем изучать программирование микроконтроллеров STM32 с нуля!

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

Меня это сильно удивило. Если верить данным статьям, для программирования не обязательно даже читать документацию к программируемому контроллеру. Меня же учили премудростям «железного программирования» совершенно иначе.

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

Выбор микроконтроллера

Многие могут сказать, что начинать изучение микроконтроллеров лучше с AVR, PIC, 8051 или чего-то еще. Вопрос многогранный и спорный. Я знаю достаточно примеров, когда люди изучив Cortex-M, программировали AVR, ARM7 и т.д. Сам же я начинал с Cortex-M3. Если перед вами стоит определенная задача, в интернете достаточно много информации со сравнением различных типов микроконтроллеров и решаемых с их помощью задач. На хабре этот вопрос тоже поднимался, например .

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

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

Что необходимо для изучения?

К сожалению, для начала программирования МК не достаточно одного лишь ПК. Придется где-то раздобыть демонстрационную плату и программатор. Хотя это и уменьшает конкуренцию на рынке труда.

Сам я использую демонстрационную плату STM3220G-EVAL и программатор J-Link PRO . Но для начала, будет вполне достаточно STM32F4DISCOVERY , которую можно купить без особых проблем за небольшую сумму.

Все примеры будут именно для отладочной платы STM32F4DISCOVERY . На данном этапе нам будет совершенно не важно, что этой плате стоит МК на базе ядра Cortex-M4. В ближайшее время мы не будем использовать его особенности и преимущества над Cortex-M3. А как там будет дальше - посмотрим.

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

Среда разработки

Как уже неоднократно упоминалось, для ARM микроконтроллеров существует достаточное количество сред разработки, как платных так и не очень. И снова хочется опустить полемику по этому поводу. Я использую IAR Embedded Workbench for ARM 6.60 . Все примеры будут именно в этой среде. Если вам по душе (или в вашей организации используется) что-то другое (Keil, Eclipse, CCS, CooCoc и т.д.) то это вам тоже не очень помешает. На особенности, связанные именно со средой разработки, я буду обращать отдельное внимание.

Почему платная среда разработки?

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


Процесс установки я описывать не буду.

С чего начать?

Создание проекта
Для начала создадим пустой проект. IAR позволяет создать проекты на ASM, C и C++. Мы будем использовать C.

Перед нами появится пустой проект с main файлом.

Теперь необходимо настроить проект для начала работы с «нашим» МК и отладчиком. На плате STM32F4DISCOVERY установлен MK STM32F407VG . Его необходимо выбрать в свойствах проекта (General Options->Target->Device):

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

После этого необходимо настроить отладчик. Отладка программы происходит непосредственно «в железе». Производится это с помощью JTAG отладчика. Более подробнее ознакомиться с тем, как это происходит можно на Википедии . На плату STM32F4DISCOVERY интегрирован отладчик ST-LINK/V2. Для работы с отладчиком необходимо выбрать его драйвер в меню Debugger->Setup->Driver . Так же необходимо указать, что отладка должна производиться непосредственно в железе. Для этого необходимо поставить флаг Debugger->Download->Use flash loader(s)


Для тех, кто увидел слово Simulator

Теоретически, IAR позволяет отлаживать программы с использованием симулятора. Но я ни разу на практике не встречал его использования.

Теперь проект готов для работы (программирования, заливки и отладки).

«ТЗ» для первого проекта
Подведем промежуточный итог: МК и отладочная плата выбраны, проект подготовлен. Пора определиться с задачей.

Не будем отходить от классики. Первым проектом будет мигающий светодиод. Благо на плате их предостаточно.Что же это означает с точки зрения программирования? Первым делом необходимо изучить принципиальную схему демонстрационной платы и понять как «заводится» светодиод.
доступен на сайте производителя. В данном описании даже есть отдельный раздел про светодиоды на плате -4.4 LEDs . Для примера, будем использовать User LD3 . Найдем его на схеме:

Простейший анализ схемы говорит о том, что для того, что бы «зажечь» светодиод необходимо на пин МК подать «1» (которая для данного МК соответствует 3.3В). Выключение производится подачей на этот пин «0». На схеме этот пин обозначается PD13 (это, наверное, самая важная информация из этого документа).

В итоге, мы можем написать «ТЗ» для нашей первой программы:
Программа для МК должна переводить состояние пина МК PD13 из состояния «0» в состояние «1» и обратно с некоторой периодичностью, различимой для человеческого глаза (важное замечание, если моргать светодиодом слишком часто глаз может этого не различить).

Прежде чем приступать к программированию, или немного теории
Прежде чем приступить к реализации нашего ТЗ, необходимо понять как производится управление МК.

Начнем с того, что любой МК включает ядро, память и периферийные блоки. Думаю, что с памятью пока все понятно. Упомяну лишь, в STM32 есть флеш память в которой хранится программа МК (в общем случае это не верное утверждение, программа может храниться во внешней энергонезависимой памяти, но пока это опустим) и другие данные, в том числе и пользовательские. Так же есть SRAM - оперативная память.

Ядро - часть микроконтроллера, осуществляющая выполнение одного потока команд. В нашем МК тип ядра - Cortex-M4. Ядро МК можно сравнить с процессором в ПК. Оно умеет только выполнять команды и передавать данные другим блокам (в этом сравнении не учитываются процессоры с интегрированными графическими ускорителями).
При этом производитель МК не разрабатывает ядро. Ядро покупается у компании ARM Limited . Главное отличие между различными МК - в периферии.

Периферийные блоки - блоки осуществляющие взаимодействие с «внешним миром» или выполняющие специфические функции, недоступные ядру МК. Современные МК (в том числе и STM32) содержат огромный спектр периферийных блоков. Периферийные блоки предназначены для решения различных задач, от считывания значения напряжения с аналогового входа МК до передачи данных внешним устройствам по шине SPI.
В отличии от ядра МК периферийные блоки не выполняют инструкции. Они лишь выполняют команды ядра. При этом участие ядра при выполнении команды не требуется.

Пример

В качестве примера можно привести блок UART, который предназначен для приема и передачи данных от МК внешним устройствам. От ядра необходимо лишь сконфигурировать блок и отдать ему данные для передачи. После этого ядро может дальше выполнять инструкции. На плечи же периферийного блока ложится управление соответствующим выводом МК для передачи данных в соответствии с протоколом. Периферийный блок сам переводит выход МК в необходимое состояние «0» или «1» в нужный момент времени, осуществляя передачу.

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

ВАЖНО: После записи данных в спецрегистр и последующем чтении вы можете получить совершенно иные данные. Например, передача данных блоку UART для отправки, и считывание данных, полученных блоком от внешнего устройства, осуществляется с помощью одного и того же регистра.

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

Вспоминаем С
Если вы гуру в языке C, то можете смело пропускать данный раздел. Он предназначен в первую очередь для тех, кого учили (или ктоучился сам) программировать для ПК. Опыт показывает, что люди часто не помнят важных команд. Здесь я вкратце напомню про побитовые операции и работу напрямую с памятью по ее адресу.

Запись данных по адресу в памяти

Предположим, что читая описание периферийного блока, мы поняли, что для его корректной работы необходимо записать в него число 0x3B. Адрес спецрегистра 0x60004012. Регистр 32-битный.
Если вы сразу не знаете как это сделать, попробую описать цепочку рассуждений для получения правильной команды.

Значение 0x60004012 есть не что иное, как значение указателя на ячейку памяти. Нужно именно это и указать в нашей программе, тоесть сделать преобразование типов согласно синтаксису языка C:

(unsigned long*)(0x60004012)

Таким образом, у нас есть указатель на элемент. Теперь нужно в этот элемент записать необходимое значение. Делается это разыменовыванием указателя. Таким образом получаем правильную команду:

*(unsigned long*)(0x60004012) = 0x3B;

Установка произвольных бит в 1

Предположим, что необходимо установить «1» в 7 и 1 биты по адресу 0x60004012, при этом не изменив значение всех остальных бит в регистре. Для этого необходимо использовать бинарную операцию |. Сразу приведу правильный ответ:

*(unsigned long*)(0x60004012) |= 0x82;

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

Установка произвольных бит в 0

Предположим, что необходимо установить «0» в 7 и 1 биты по адресу 0x60004012, при этом не изменив значение всех остальных бит в регистре. Для этого необходимо использовать бинарную операцию &. Сразу приведу правильный ответ:

*(unsigned long*)(0x60004012) &= 0xFFFFFF7D;

Или его более простою запись (не переживайте за лишнюю операцию, компилятор все заранее посчитает даже при минимальной оптимизации):

*(unsigned long*)(0x60004012) &= (~0x82);

Некоторые особенности программ для МК
Здесь я постараюсь описать некоторые особенности программ для МК, которые важно помнить. Вещи достаточно очевидные, но все же.
У программы нет конца
В отличии от большинства программ для ПК, программа для МК не должна заканчиваться, НИКОГДА! А что собственно должен будет делать МК после завершения вашей программы? Вопрос, практически, риторический. Поэтому не забываем убедиться в том, что вы не забыли вечный цикл. При желании, можно перевести МК в режим сна.
Пользуйтесь целочисленными переменными
Не смотря на то, что мы используем МК с ядром Cortex-M4, который аппаратно выполняет операции над числами с плавающей точкой, советую вам отказаться от их использования. В МК без поддержки таких операций время вычислений будет просто огромным.
Откажитесь от динамического выделения памяти
Это только совет. Причина проста - памяти мало. Я не раз встречался с библиотеками, в которых были «медленные утечки» памяти. Было очень неприятно, когда после нескольких недель стабильной работы МК зависал с ошибкой. Лучше заранее продумать архитектуру своей программы так, чтобы не пришлось использовать динамическое выделение памяти.
Если же все-таки хочется использовать - внимательно изучите работу менеджера памяти или пишите свой.

Приступаем к работе!

Работа над программой для МК всегда начинается с чтения документации. Для нашего МК доступен на сайте производителя. Страниц много, но все читать пока не нужно. Как уже было сказано, большую часть документации составляет описание периферийных блоков и их регистров. Так же хочу обратить внимание на то, что этот Reference Manual написан не для одного МК, а для нескольких линеек. Это говорит о том, что код будет переносим при переходе на другие МК в этих линейках (если конечно не пытаться использовать периферийные блоки которых нет в используемом МК).

В первую очередь необходимо определиться с какими блоками предстоит работать. Для это достаточно изучит разделы Introduction и Main features .

Непосредственное управление состоянием пинов МК осуществляется с помощью блока GPIO. Как указано в документации в МК STM32 может быть до 11 независимых блоков GPIO. Различные периферийные блоки GPIO принято называть портами. Порты обозначаются буквам от A до K. Каждый порт может содержать до 16 пинов. Как мы отметили ранее, светодиод подключается к пину PD13. Это означает, что управление этим пином осуществляется периферийным блоком GPIO порт D. Номер пина 13.

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

Управление тактированием периферийных блоков
Для снижения электропотребления МК практически все периферийные блоки после включения МК отключены. Включение/выключение блока производится подачей/прекращением подачи тактового сигнала на его вход. Для корректной работы, необходимо сконфигурировать контроллер тактового сигнала МК, чтобы необходимому периферийному блоку поступал тактовый сигнал.
Важно: Периферийный блок не может начать работу сразу после включения тактового сигнала. Необходимо подождать несколько тактов пока он «запустится». Люди, использующие библиотеки для периферийных устройств, зачастую даже не знают об этой особенности.

За включение тактирования периферийных блоков отвечают регистры RCC XXX peripheral clock enable register .На месте XXX могут стоять шины AHB1, AHB2, AHB3, APB1 и APB2. После внимательного изучения описания соответствующих регистров, можно сделать вывод о том, тактирование периферийного блока GPIOD включается установкой «1» в третий бит регистра RCC AHB1 peripheral clock enable register (RCC_AHB1ENR) :

Теперь необходимо разобраться с тем, как узнать адрес самого регистра RCC_AHB1ENR .

Замечание: Описание системы тактирования МК STM32 достойно отдельной статьи. Если у читателей возникнет желание, я подробнее освещу этот раздел в одной из следующих статей.

Определение адресов спецрегистров
Определение адресов спецрегистров необходимо начинать с чтения раздела Memory map в Reference manual. Можно заметить, что каждому блоку выделен свой участок адресного пространства. Например, для блока RCC это участок 0x4002 3800 - 0x4002 3BFF:

Для получения адреса регистра, необходимо к начальному значению адресного пространства блока RCC прибавить Addr. offset нужного регистра. Addres offset указывается и в описании регистра (см. скриншот выше).

В итоге, мы определили адрес регистра RCC_AHB1ENR - 0x4002 3830.

Блок GPIO
Для общего ознакомления с блоком GPIO я настоятельно рекомендую полностью прочитать соответствующий раздел Reference Manual. Пока можно не особо обращать внимание на Alternate mode . Это оставим на потом.

Сейчас же наша задача научиться управлять состоянием пинов МК. Перейдем сразу к описанию регистров GPIO.

Режим работы
В первую очередь необходимо установить режим работы 13 пина порта D как General purpose output mode , что означает что блок GPIO будет управлять состоянием пина МК. Управление режимом работы пинов МК производитсяс помощью регистра GPIO port mode register (GPIOx_MODER) (x = A..I/J/K) :

Как видно из описания для совершения требуемой нам настройки необходимо записать значение 01b в 26-27 биты регистра GPIOx_MODER . Адрес регистра можно определить тем же методом, что описан выше.

Настройка параметров работы выходных пинов порта GPIO
Блок GPIO позволяет применить дополнительные настройки для выходных пинов порта. Данные настройки производятся в регистрах:
  • GPIO port output type register (GPIOx_OTYPER) - задается тип выхода push-pull или open-drain
  • GPIO port output speed register (GPIOx_OSPEEDR) - задается скорость работы выхода
Мы не будем менять данных параметров, поскольку нас вполне устраивают значения по умолчанию.
Установка значения на пине МК
Наконец-то мы подошли к моменту управления состоянием выхода МК. Для утановки выходного значения на определенном пине МК есть два метода.

Используем регистр GPIO port bit set/reset register (GPIOx_BSRR)

Запись «0» или «1» в биты 0-16 приводят к соответствующему изменению состояния пинов порта. Для того, чтобы установить определенное значение на выходе одного или нескольких пинов МК и не изменить состояния остальных, необходимо будет пользоваться операцией модификации отдельных бит. Такая операция выполняется не менее чем за 3 такта. Если же необходимо в часть битов записать 1, а в другие 0, то понадобится не менее 4 тактов. Данный метод предпочтительнее всего использовать для изменения состояния выхода на противоположное, если его изначальное состояние не известно.

GPIO port bit set/reset register (GPIOx_BSRR)

В отличии от предыдущего метода, запись 0 в любой из битов данного регистра не приведет ни к чему (да и вообще, все биты write-only!). Запись 1 в биты 0-15 приведет к установке «1» на соответствующем выходе МК. Запись 1 в биты 16-31 приведет к установке «0» на соответствующем выходе МК. Этот метод предпочтительнее предыдущего, если необходимо установить определенное значение на пине «МК», а не изменить его.

Зажигаем светодиод!
Найдя адреса всех необходимых регистров, можно написать программу, которая включает светодиод:
void main() { //Enable port D clocking *(unsigned long*)(0x40023830) |= 0x8; //little delay for GPIOD get ready volatile unsigned long i=0; i++; i++; i++; i=0; //Set PD13 as General purpose output *(unsigned long*)(0x40020C00) = (*(unsigned long*)(0x40020C00)& (~0x0C000000)) | (0x04000000); //Turn LED ON! *(unsigned long*)(0x40020C14) |= 0x2000; while(1); }
Можно компилировать (Project->Compile ) и заливать (Project->Download->Download active application ). Или запустить отладку (Project->Dpwnload and Debug ) и начать выполнение (F5).
Светодиод загорелся!
Мигаем светодиодом
Мигание светодиода есть ни что иное, как попеременное включение и выключение с задержкой между этими действиями. Самый простой способ - поместить включение и выключение в вечный цикл, а между ними вставить задержку.
void main() { //Enable port D clocking *(unsigned long*)(0x40023830) |= 0x8; //little delay for GPIOD get ready volatile unsigned long i=0; i++; i++; i++; i=0; //Set PD13 as General purpose output *(unsigned long*)(0x40020C00) = (*(unsigned long*)(0x40020C00)& (~0x0C000000)) | (0x04000000); while(1) { //Turn LED ON *(unsigned long*)(0x40020C14) |= 0x2000; //Delay for(i=0; i<1000000 ;++i); //Turn LED OFF *(unsigned long*)(0x40020C14) &= ~0x2000; //Delay for(i=0; i<1000000 ;++i); } }
Значение 1000000 в задержке подобрано экспериментально так, чтобы период мигания светодиода был различим глазом, но и не был слишком велик.
Оптимизируем алгоритм
Минусом выбранного подхода миганием светодиодом является то, что ядро МК большую часть времени проводит в пустых циклах, хотя мог бы заниматься чем-нибудь полезным (в нашем примере других задач нет, но в будущем они появятся).

Для того, чтобы этого избежать, обычно используется счетчик циклов, а переключение состояние пина МК происходит при прохождении программы определенного числа циклов.
void main() { //Enable port D clocking *(unsigned long*)(0x40023830) |= 0x8; //little delay for GPIOD get ready volatile unsigned long i=0; i++; i++; i++; i=0; //Set PD13 as General purpose output *(unsigned long*)(0x40020C00) = (*(unsigned long*)(0x40020C00)& (~0x0C000000)) | (0x04000000); while(1) { i++; if(!(i%2000000)) { //Turn LED ON *(unsigned long*)(0x40020С14) |= 0x2020; } else if(!(i%1000000)) { //Turn LED OFF *(unsigned long*)(0x40020С14) &= ~0x2000; } } }
Но и тут не обойдется без проблем, с изменением количества команд выполняемых внутри цикла, будет меняться период мигания светодиодом (или период выполнения других команд в цикле). Но на данном этапе мы не можем с этим бороться.

Немного об отладке
IAR позволяет осуществлять отладку приложения непосредственно в железе. Все выглядит практически так же, как и отладка приложения для ПК. Есть режим пошагового выполнения, входа в функцию, просмотр значения переменных (В режиме отладки View->Watch->Watch1/4 ).

Но помимо этого, присутствует возможность просмотра значений регистров ядра, спецрегистров периферийных блоков (View->Register) и т.п.
Я настоятельно рекомендую ознакомиться с возможностями дебаггера во время изучения программирования МК.

Несколько слов в заключение

Возможно, многие скажут, что ручное прописывание адресов в программе это не правильно, поскольку производитель предоставляет файлы с определениями регистров и битовых полей, библиотеки для работы с периферией и другие инструменты, облегчающие жизнь разработчику. Я с этим полностью согласен, но все равно считаю, что первые шаги в программировании МК необходимо делать перекапывая документацию к вручную, самостоятельно определяя необходимые регистры и битовые поля. В дальнейшем этим можно не пользоваться, но уметь нужно обязательно.
Приведу лишь несколько причин для этого утверждения:
  • В библиотеках от производителя иногда встречаются ошибки! Я один раз чуть не сорвал срок проекта из-за этого. Несколько раз перепаивал чип, думая, сто повредил кристалл при пайке (до этого такое случалось). А проблема заключалась в том, что в библиотеке был неверно прописан адрес спецрегистра. Обычно такое случается с МК или линейками МК только вышедшими на рынок.
  • Библиотеки для работы спериферией некоторых производителей не реализуют всех возможностей периферийных блоков. Особенно этим грешилb Luminary Micro , которых в последствии выкупили TI. Приходилось писать инициализацию периферии вручную.
  • Многие привыкают начинать программирование МК с изучения примеров. Я считаю, что сперва необходимо определиться с тем, что позволяет реализовать МК. Это можнопонять только прочитав документацию. Если чего-то нет в примерах, это не значит, что железоэто не поддерживает. Последний пример - аппаратная поддерка PTP STM32. В сети, конечно, можно кое-что найти, но это не входит в стандартный набор от производителя.
  • Драйверы периферийных блоков некоторых производителей настолько не оптимизированы, что на переключение состояния пина средствами библиотеки тратится до 20 тактов. Это непозволительная роскошь для некоторых задач.

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