Еще в студенческие годы мне пришлось весьма тесно обобщатся с микроконтроллерами, тогда это были 8-битные 8051 и AVR. Сейчас, захотев вернутся этому занятию, перевел свой взгляд на весьма широкое семейство контроллеров STM32. О них немало написано на просторах Сети, тем не менее я изъявил желание написать небольшой цикл статей о работе с STMками. Знакомство с ними я хотел бы начать, как говорят, с полного 0. Для экспериментов мною была приобретена простая и дешевая (3$) отладочная плата Maple Mini. Используемый в ней контроллер STM32F103CB обладает весьма внушительным букетом возможностей. (особенно в сравнении с решениями в своей ценовой категории). Подробно можно почитать в сети, и конечно же, в даташите.. Родная Ардуиноподобная среда разработки мне сразу не пришлаcь по вкусу (на вкус и цвет, как говорят...). Из всего изобилия разнообразных сред разработки я остановил свой взгляд на mikroC for ARM компании mikroelektronika. Когда-то я сталкивался с их компиляторами(для 8081), мне весьма понравилось. Хоть и не без косяков, но решил попробовать.
Плата имеет такой вид, все очень просто и лаконично:
Принципиальная схема платы тоже проста, но все самое необходимое здесь есть:
Программатором выбран китайский клон ST-LINK2 (3$), тем не менее он отлично работает с mikroС
Ссылка на демо-версию mikroC. Ограничение демо-версии: максимум 4KB бинарного кода. Не много, но для ознакомления вполне достаточно. С установкой приложения проблем возникнуть не должно, единственное нужно драйвера на ST-LINK2 поставить перед запуском инсталлятора mikroC.
После запуска и создания проекта нас приветствует окно приложения:
Первым делом после выбора типа используемого микроконтроллера необходимо настроить свойства нашего проекта. Конфигурация проекта mikroC вызывается сочетанием клавиш Shift-Ctrl-E (Project — Edit Project). Именно в этом окне настраиваются все прелести, связанные с непростой внутренней организацией системы тактирования STM32 микроконтроллеров. Вообще я советую хотя бы вкратце ознакомится с Reference manual на данное семейство микроконтроллеров. К нему мы будем неоднократно возвращаться.
Блок-схема системы тактирования из даташита STM32F103
В данном окне задается конфигурация регистров RCC_CR и RCC_CGGR
- Internal high-speed clock enable — Включение или отключение встроенного генератора 8МГц(HSI) (oscillator OFF)
- External high-speed clock enable — Включение или отключение встроенного генератора 8МГц(HSE) (oscillator ON)
- External high-speed clock enable — Возможность подключения к входу OSC генератора тактовых импульсов вместо кварца. Мы настраиваем на использование кварца (HSE oscillator not bypassed)
- Clock seсurity system enable — Включение встроенной в контроллер систем защиты от пропадания синхросигнала; пока не используем (Clock detector OFF)
- PLL Enable — Включение/отключение модуля умножения частоты (PLL ON)
- System clock switch — Выбор тактового сигала SYSCLOCK: PLL, внешний или внутренний генератор. Мы используем PLL. Именно на частоте HSE умноженного на коэффициент PLL и работает ядро нашего контроллера (PLL selected as system clock)
- Set and cleared by software to control the division factor of the AHB clock — Установка предделителя SYSCLOCK для шины AHB, которая обслуживает периферийные модули МК; пока отключаем предделитель *(SYSCLOCK not divided)
- APB low-speed prescaller APB1 — делитель частоты для низкоскоростной периферии МК, например шины I2C, максимальная частота работы:36 МГц (HCLK divided by 2)
- APB high speed prescaller APB 2- делитель частоты для высокоскоростной периферии МК, например портов ввода-вывода, таймеров и т.д. (HCLK not devided)
- ADC prescaller — предделитель для модуля АЦП относительно APB 2 (PCLK2 divided by 2)
- PLL entry clock source — источник тактового сигнала на вход PLL, на выбор либо 1/2 встроенного RC генератора либо внешний генератор, прошедший через PREDIV1; именно его и используем (Clock from PREDIV1 selected as the PLL input clock)
- HSE divider for PLL entry — настройка этого самого PREDIV1; пока не используем (HSE clock not divided)
- PLL multiplication factor — коэффициент умножения PLL. На входе у нас частота кварца 8 МГц, при коэффициенте 11 имеем частоту 72 МГц для SYSCLOCK (PLL input clock х 11)
- USB prescaller — частота шины USB. USB по спецификации работает на частоте 48 МГц, выбираем предделитель 1,5 (PLL clock divided by 1.5)
MSU clock frequency выбираем частоту SYSCLOCK — 72МГц (72.000000)
Теперь можем сохранить настройки для нашего МК. Все готово для написания 1 программы. Как всегда поморгаем светодиодом (подключен к ножке PB1):
Для установки выходов GPIO порта на выход в microC есть функция
GPIO_Digital_Output(&GPIOх_BASE, _GPIO_PINMASK_ALL);// Настройка порта на выход
она включает тактирование блока GPIOх и прописывает значения в конфиграционный регистр. Данные которые записываем в порт заносим в регистр GPIOх_ODR.
GPIOх_ODR = ; // Региcтр записи в порт
Компилятор позволяет получить доступ к конкретному биту регистра или переменной. Для этого номер бита (начиная с 0) пишем после названия регистра через точку
REGx.by; // Доступ к отдельному (y) биту регистра (х)
Для формирования задержек используем встроенную функцию Delay_ms() (или Delay_us()) компилятора. Вот наша первая программа:
void main()
{
GPIO_Digital_Output(&GPIOb_BASE, _GPIO_PINMASK_1); //Делаем PB1 выходом
GPIOb_ODR.b1 = 0; //Записываем в регистр GPIOb_ODR в 15 бит = 0
while(1) // Бесконечный цикл
{
GPIOb_ODR.b1=~GPIOb_ODR.b1; //Инверсия 15 бита
Delay_ms(500); //Задержка 500 мс
}
}
Чтобы одна команда инициализации применялось сразу к нескольким ножкам порта пишем _GPIO_PINMASKn через оператор "или", например:
GPIO_Digital_Output(&GPIOb_BASE, _GPIO_PINMASK_1 | _GPIO_PINMASK_7); //PB1 и PB7 настроены на выход
GPIO_Digital_Output(&GPIOa_BASE, _GPIO_PINMASK_ALL ); //Все ноги PA настроены на выход
Теперь попробуем вывести меандр на один из выводов МК, переключая состояние вывода порта PB15 с интервалом 5 мс. :
void main()
{
GPIO_Digital_Output(&GPIOb_BASE, _GPIO_PINMASK_15);
GPIOb_ODR.b15 = 0;
while(1)
{
GPIOb_ODR.b15=~GPIOb_ODR.b15;
Delay_ms(5); // Задержка 5 мс.(Импульс 10 мс, частота 100 Гц)
}
}
На выводе PB15 имеем такой сигнал:
Если нам необходимо считать состояние порта, то используем регистр GPIOх_IDR, предварительно настроив порт на вход при помощи функции GPIO_Digital_Input (*port, pin_mask). На нашей плате есть кнопка, подключенная к выводу порта PB8. Следующая программа зажигает мигающий светодиод на выводе PB1 при нажатой кнопке.
void main()
{
GPIO_Digital_Output(&GPIOb_BASE, _GPIO_PINMASK_1);
GPIO_Digital_Input(&GPIOb_BASE, _GPIO_PINMASK_8); // Настраиваем вывод PB8 на вход
GPIOb_ODR.b1 = 0;
while(1)
{
if (GPIOb_IDR.b8) //Если кнопка нажата бит 8 регистра GPIOb_IDR равен 1
{
GPIOb_ODR.b1=~GPIOb_ODR.b1;
Delay_ms(500); //Задержка 500 мс
}
else
{
GPIOb_ODR.b1 = 0; //Если кнопку отпустили, погасить светодиод
}
}
}
На этом 1 часть подошла к концу. Во второй части я постараюсь Вас познакомить с реализацией ШИМ модуляции, работой с таймерами и функцией подавления дребезга контактов на кнопке.
Комментарии (15)
Shtucer
23.12.2016 14:32+1"мне пришлось весьма тесно обобщатся"
Вот это я понимаю… ошарашить читателя с первого предложения!
Вместо ссылки на "демо-версию" mikroC, лучше бы ссылку на её описание, раз уж неохота объяснять почему ("мне понравилась" не подходит).
Всё остальное — типичный ХеллоВорлд.
saw_tooth
23.12.2016 17:44+3Коль вы уже использовали компиляторы от микроСи, опишите пожалуйста, чем они лучше (ведь выбор чем то обусловлен) чем скажем компилятор кейла/IAR или GNU?
lzb_j77
23.12.2016 17:44Как создать проект — непонятно.
Как в нём выбрать тип отладчика — непонятно.kselltrum
23.12.2016 17:45-1Напишу отдельную статью, объясняющую эти аспекты.
lzb_j77
23.12.2016 18:31По-моему, именно с этого и надо было начинать — как поставить, как выбрать, как настроить.
Я вот как раз начинающий :) mikroC поставил, mikroProg suite поставил, стёр прошивку в stm32f4disco, а залить ничего не могу — не заливается :) Приходится самому думать и искать.kselltrum
23.12.2016 18:48драйвера на ST-LINK ставил перед mikroProg suite? Если нет, то у меня тоже бывал такой глюк. Лечился заливкой бинарника (*.hex) прошивки через утилиту ST-LINKa. потом его попускает. Еще проверь перемычки на плате, подключающие SWD к программатору. Бинарник в папке с проектом лежит после компиляции.
kselltrum
23.12.2016 18:58Мой китайский ST-LINK подхватился автоматом, главное чтобі драйвера на него стояли родные. MikroProg его сам увидел
DanilinS
24.12.2016 18:08Странно. У меня mikroProg Suite For ARM прекрасно увидел и китайский ST-Link (свисток) V2 и штатный отладчик с Дискавери. Без всяких доп. настроек и танцев с бубном. Система — W10 x64.
grossws
24.12.2016 20:51Для установки выходов GPIO порта на выход в microC есть функция
GPIO_Digital_Output(&GPIOх_BASE, _GPIO_PINMASK_ALL);// Настройка порта на выход
Это в mikroC, а не в Standard Peripheral Library от STMicroelectronics? Т. е. они держат свой нестандартный слой абстракций?
REGx.by; // Доступ к отдельному (y) биту регистра (х)
Как они это реализуют? Через стандартные bit fields из C11 или через проприетарное расширение компилятора?Конечно, 4k кода для stm32 выглядит просто издевательством. Разве что blinky написать можно.
grossws
24.12.2016 20:53Продолжу.
Для формирования задержек используем встроенную функцию Delay_ms() (или Delay_us()) компилятора.
Это таки intrinsic или всё же библиотечная функция?
kselltrum
24.12.2016 21:37Да, в mikroC свой свой приприетарный слой абстракций, отличающийся от Standard Peripheral Library.
golf2109
у автора есть лишние 300 долларов?
или ему хватит 4К места для программ?
зачем тратить свое время на изучение такой непопулярной IDE?
kselltrum
Просто раньше работал с их 8051 компилятором. Наверное дело привычки. А от жадности mikroC отлично лечится :)
ukt
launchpad.net/gcc-arm-embedded/