![]() |
![]() |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Микроконтроллеры. Начало. STM32.
Автор: Александр Скалдуцкий, scelikr@gmail.com Микроконтроллеры для котят Всем Мяу, котаны :) Как-то раз от меня ушла кошка :( Ну и чем валерьянку лопать, я решил заняться делом, так сказать «на благо Родине». Давно уж хотел цифровыми устройствами заняться, да времени не было (сами понимаете, то спать, то с кошкой по крышам гулять), а тут как раз время-то и появилось. Ну-с начнём..) Всё как обычно начинается с выбора. Ну вроде выбор-то небольшой PIC, да AVR. Последние мне как-то больше приглянулись. Нужен был ещё и USB программатор за неимением других портов на компьютере, от цены которого у меня чуть хвост не отвалился. Ещё Arduino есть - зверёк такой. Его и программировать по USB можно. Ну, думаю, "то что доктор прописал". В селе нашем его только через интернет-магазин достать можно. Нашёл, где по-выгодней, чуть не купил и... ОПА! Смотрю - STM32VL-Discovery. Что за зверь такой? Хм, STM32.. Что-то слышал краем уха.. А от характеристик усы дыбом, честно! А лап-то у неё сколько!
Итак, попорядку:
А что дальше? В STM32VL-Discovery есть встроенный программатор/отладчик, который лёгким движением лапы (снятием перемычек) может программировать и отлаживать (отладка очень уж вещь полезная, но об этом чуть позже) микроконтроллеры STM32 за пределами платы. С Arduino такое не прокатит. То есть используя STM32VL-Discovery мы и деньги экономим и получаем большую производительность и свободу творчества :) Да и сами микроконтроллеры STM32 выглядят привлекательней остальных:
А ещё STM32 32-х разрядные, а это означает возможность работы с 32-х битными данными за один такт. AVR и PIC этим не похвастаются.
Ну что, котаны, убедил? Тогда начнём курс молодого бойца цифровика!) Как оно работает? Из чего состоит? Что умеет? Как известно, все коты очень любознательные, а радиокоты особенно! Микроконтроллер - это микросхема сочетающая в себе функции процессора, периферии, имеющая ОЗУ, flash память. Как компьютер, только меньше! Проведём аналогию: компьютером управляет операционная система, а микроконтроллером «прошивка», которую пишете Вы; операционная система компьютера хранится на жёстком диске, «прошивка» микроконтроллера в его flash памяти; функции ОЗУ схожи - хранение изменяющихся данных во время выполнения программы. А ещё у МК есть различные периферийные устройства, такие как АЦП и ЦАП например. МК общается с внешним миром при помощи лап на его корпусе (не таких как у котов, конечно, а металлических). Но не все из них управляются программой, есть выводы питания, вывод сброса, выводы питания периферии, вывод резервного питания. А те, которые управляются программой делятся на группы называемые «порты». Все эти управляемые выводы называются 2-мя буквами и цифрой. Например PA1: P - порт, А - порт «А», 1 - номер вывода этого порта. В программе порты конфигурируются либо на вход, либо на выход, по вашему желанию. Выводы порта настроенного на вход могут быть в разных режимах, для каждого вывода он может быть своим:
А у порта настроенного на выход выводы могут быть в таких режимах:
Но не все выводы можно назначать «как захочется». Для того, что бы узнать, что можно, а что нельзя нужно посмотреть документацию (таблица 4) или воспользоваться программой MicroXplorer. Перед использованием порта его нужно сначала тактировать - подавать на него тактовые импульсы, т.к. изначально они не подаются для экономии энергии. Можно выбрать разную частоту тактирования - больше частота - быстрее работают входы или выходы этого порта, но и больше потребление энергии. Ещё есть выводы BOOT 0 и BOOT 1. Эти выводы не относятся к портам, они служат для управления загрузкой микроконтроллера. Если во время подачи питания на выводе BOOT 0 логический ноль (вывод соединен с общей точкой), то микроконтроллер выполняет программу загруженную во flash память, т.е. Вашу прошивку. Если во время подачи питания на выводе BOOT 0 логическая еденица (вывод соединен с питанием микроконтроллера), а на выводе BOOT 1 логический ноль, то микроконтроллер выполняет не Вашу прошивку, а записанный на заводе загрузчик. Запомните это! Вы будете часто пользоваться этим в процессе работы с микроконтроллерами STM32! Иногда загрузка записанного с завода загрузчика - единственный способ записать/изменить прошивку микроконтроллера. Это бывает например при конфигурировании в прошивке выводов, к которым подключается программатор или при прошивке микроконтроллера без использования программатора. Так что настоятельно рекомендую при проектировании печатной платы эти выводы (или хотя бы BOOT 0) распологать в удобном месте. Вот разобрались :) Теперь знаем что такое микроконтроллер, из чего он состоит. Сейчас узнаем ещё о некоторых премудростях и перейдём к самому интересному - практике! Программа в микроконтроллере выполняется пошагово. Один такт процессора - один шаг программы. Например пусть перемигивается красная и зелёная лампочки, пока НЕ нажата кнопка. Длительность каждой лампы - 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. Итак:
Если у Вас вариант без отладочной платы/программатора, то для загрузки программы в МК понадобится программка Flash Loader Demonstrator которая находится здесь Находим общий язык Перед тем, как писать свою первую программу нужно найти с МК общий язык. Вряд ли он будет учить наш язык, по этому придется выучить (а может просто вспомнить) язык на котором мы будем общаться с МК, это Си. Понадобятся нам только основы (состав программы, функции, операторы). Если язык этот знаете, то можете сразу перейти к пункту «Первая программа», ну а незнающих я введу в курс дела. Проект состоит из файлов с расширениями .c и .h. В первых находятся функции во вторых названия используемых функций и константы например. Так уж заведено. Самый главный файл, в котором находится код программы main.c. Для использования различных функций нужно подключать библиотеки с этими функциями. Подключаются они записью #include "название_библиотеки" ну библиотеки естественно должны быть в проекте. Подключают их в самом начале файла. Функции - это своеобразная часть программы. Вообще программа состоит из одной или нескольких функций. Функция имеет вид: тип_возвращаемой_переменной имя_функции (тип_переменной) В функцию можно отправить какую-нибудь переменную, фунция её обработает и вернёт какое-нибудь значение. Очень удобно использовать функцию для повторяющихся действий, чем писать постоянно один и тот же кусок кода, можно просто отправлять переменную в функцию и получать обратно обработанное значение. Перед тем, как использовать функцию, её нужно объявить в самом начале файла. Делают это в таком виде: тип_возвращаемой_переменной имя_функции (тип_переменной); Ах, да, забыл самое главное! В конце каждой строки должна быть точка с запятой! Если функция ничего не возвращает (например временная задержка, она просто тянет кота за хвост время), то тип указывают void. При запуске, первой всегда выполняется функция main(). Ну с функциями вроде разобрались, понимание придёт только с практикой. Выше я упоминал тип переменной. Все переменные могут быть разных типов, вот основные:
Строку (слово, предложение) можно представить как массив из символов типа char. Например: char stroka[5] = "Слово"; Здесь квадратных скобках - количество символов в строке, «stroka» - название массива. Перед использованием переменной её нужно обязательно объявить. (просто указать тип переменной и имя) Дальше по плану операторы. Операторы - символы при помощи которых производятся какие либо операции над переменными.
Например выражение a=b+c значит присвоить переменной a значение суммы значений переменных b и c.
Например выражение a++ значит увеличить значение переменной a на 1 (то же самое, что и a=a+1)
Например выражение a<b становится истинным, если значение переменной 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))
Чуть не забыл рассказать про циклы. Основные: while(условие) { тело цикла } Тело цикла (всё что в фигурных скобках) выполняется, когда условие истинно (пока условие не станет ложным).
Дальше идёт цикл всех циклов. Цикл со счетчиком. Он выполняется определенное количество раз, выглядит он так: for (начальное_значение; цикл_выполняется_до, шаг) { тело цикла { Начальное_значение - начальное значение счётчика Цикл_выполняется_до - до достижения какого значения выполняется цикл Шаг - с каким шагом счетчик считает Например for (i=0; i<10, i++) { тело цикла } Здесь начальное значение переменной i равно 0, цикл выполняется, пока значение переменной i меньше 10, при каждом выполнении цикла к переменной i прибавляется 1. Так же можно изменять значение переменной прямо в цикле. Дальше по плану «условный переход»: if (условие){ тело 1 } else { тело 2 } В усовном переходе «тело 1» выполняется, если условие истинно и выполняется «тело 2», если условие ложно. Ещё есть такой вариант: if (условие 1){ тело 1 } else if (условие 2) { тело 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" Вот так: Далее нужно сделать функцию задержки (не хотим же мы мигать светодиодом с частотой в несколько МГц?). void Delay(int i) { Так. Тут по порядку, функция ничего не возвращает, по этому void, название функции Delay, сразу объявляем переменную i типа int. В фигурных скобках тело функции - цикл for. Это его строчная запись. Начальное значение i мы не изменяем, цикл выполняется, пока i не равна нулю (как i становится равна нулю, цикл прекращается, функция «выключаеся»). С каждым выполнением тела цикла (тактом) переменная i уменьшается на 1. Т.е. суть цикла - просто повториться количество раз равное i. Пока выполняется цикл время идёт, происходит задержка. Далее в главной функции main нужно включить тактирование порта, как это сделать можно посмотреть в файле stm32f10x_rcc.h: Какой порт ответственный за какой вывод можно посмотреть в документации к МК: Для тактирования порта С добавляем строчку: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); Далее нужно настроить выводы. Смотрим, в файле stm32f10x_gpio.h в какой структуре настраиваются выводы: Добавляем в прогармму строчку: 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 функция Delay заканчивает свою работу, т.к. она 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, получили опыт работы с микроконтроллером (надеюсь положительный) и самое главное, теперь Вы можете воплотить свои идеи цифровых устройств в жизнь (и поведать о них, на нашем любимом РадиоКоте)! Пусть пока ещё простенькие, но всё навёрстывается с опытом. А я постараюсь в следующих статьях рассказать об АЦП, ЦАП, прерываниях, использовании отладки и других полезностях. Удачного воплощения идей! Все вопросы, не стесняемся, пишем на форум
А ещё хочу поздравить РадиоКота с его главным праздником! Пусть время и течёт, как флюс из упавшего флакона, но РадиоКот всегда останется нашим незаменимым помощником и приютом для котов (и котят) с паяльниками. Здоровья тебе (все 7 штук), нечеловечьего счастья и сбычи кошачих мечт! Соблюдай ТБ :)
Файлы: Все вопросы в Форум.
Эти статьи вам тоже могут пригодиться: |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
![]() |


![]() |
![]() |
|||
|
||||
![]() |
![]() |