Первые шаги с STM32 и компилятором mikroC для ARM архитектуры — Часть 1

в 10:25, , рубрики: Maple-mini, microC, stm32, Микроконтроллеры для начинающих, программирование микроконтроллеров

Еще в студенческие годы мне пришлось весьма тесно обобщатся с микроконтроллерами, тогда это были 8-битные 8051 и AVR. Сейчас, захотев вернутся этому занятию, перевел свой взгляд на весьма широкое семейство контроллеров STM32. О них немало написано на просторах Сети, тем не менее я изъявил желание написать небольшой цикл статей о работе с STMками. Знакомство с ними я хотел бы начать, как говорят, с полного 0. Для экспериментов мною была приобретена простая и дешевая (3$) отладочная плата Maple Mini. Используемый в ней контроллер STM32F103CB обладает весьма внушительным букетом возможностей. (особенно в сравнении с решениями в своей ценовой категории). Подробно можно почитать в сети, и конечно же, в даташите.. Родная Ардуиноподобная среда разработки мне сразу не пришлаcь по вкусу (на вкус и цвет, как говорят...). Из всего изобилия разнообразных сред разработки я остановил свой взгляд на mikroC for ARM компании mikroelektronika. Когда-то я сталкивался с их компиляторами(для 8081), мне весьма понравилось. Хоть и не без косяков, но решил попробовать.

Плата имеет такой вид, все очень просто и лаконично:

image

Принципиальная схема платы тоже проста, но все самое необходимое здесь есть:

image

Программатором выбран китайский клон ST-LINK2 (3$), тем не менее он отлично работает с mikroС

image

Ссылка на демо-версию mikroC. Ограничение демо-версии: максимум 4KB бинарного кода. Не много, но для ознакомления вполне достаточно. С установкой приложения проблем возникнуть не должно, единственное нужно драйвера на ST-LINK2 поставить перед запуском инсталлятора mikroC.

После запуска и создания проекта нас приветствует окно приложения:

image

Первым делом после выбора типа используемого микроконтроллера необходимо настроить свойства нашего проекта. Конфигурация проекта mikroC вызывается сочетанием клавиш Shift-Ctrl-E (Project — Edit Project). Именно в этом окне настраиваются все прелести, связанные с непростой внутренней организацией системы тактирования STM32 микроконтроллеров. Вообще я советую хотя бы вкратце ознакомится с Reference manual на данное семейство микроконтроллеров. К нему мы будем неоднократно возвращаться.

image

Блок-схема системы тактирования из даташита 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 (HCLK not divided)
  • 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)

image

Теперь можем сохранить настройки для нашего МК. Все готово для написания 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 имеем такой сигнал:

image

Если нам необходимо считать состояние порта, то используем регистр 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 часть подошла к концу. Во второй части я постараюсь Вас познакомить с реализацией ШИМ модуляции, работой с таймерами и функцией подавления дребезга контактов на кнопке.

Автор: kselltrum

Источник


  1. николай:

    PLL multiplication factor — коэффициент умножения PLL. На входе у нас частота кварца 8 МГц, при коэффициенте 11 имеем частоту 72 МГц для SYSCLOCK (PLL input clock х 11) ??

    Может коэффициент должен быть 9? 9×8=72….
    или я ошибаюсь????

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js