Учимся программировать под микроконтроллеры STM32

31 июля 2017

Тема программирования микроконтроллеров ранее многократно поднималась в этом блоге, но исключительно в контексте микроконтроллеров AVR и, соответственно, Arduino. Сегодня же речь пойдет о микроконтроллере STM32F103C8T6 на базе ядра ARM 32 Cortex-M3. Вы наверняка слышали об архитектуре ARM — она используется в большинстве современных телефонов и планшетов, а также Raspberry Pi, полетных контроллерах для квадрокоптеров, некоторых осциллографах, и много где еще.

Список покупок

Для повторения шагов из сей заметки вам понадобится следующие железки:

К моменту, когда вы будете читать эти строки, ссылки могут устареть. Однако необходимые товары легко находятся по запросам «STM32F103C8T6 Development Board» и «ST-Link v2 Programmer» как на AliExpress, так и на eBay. Плата также известна под названием «STM32 Blue Pill».

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

О плате Blue Pill

Ниже приведены некоторые характеристики платы и используемой в ней микроконтроллера:

  • Микроконтроллер 32-х битный;
  • Рабочая частота 72 МГц;
  • 64 Кб flash-памяти;
  • 20 Кб оперативной памяти;
  • Мне удалось насчитать 32 GPIO;
  • 12-и битный АЦП, 10 аналоговых пинов;
  • 16-и битный ШИМ, 15 ШИМ-пинов;
  • 3 UART канала, 2 I2C шины, 2 SPI шины;
  • Возможность отладки по JTAG;
  • Плата питается от 3.3 В;

Расположение пинов (кликабельно — GIF, 1082x759, 143 Кб, источник):

Расположение пинов на плате Blue Pill

Для сравнения, Arduino Nano стоит столько же и имеет похожий форм-фактор, но работает на 8-и битном микроконтроллере, имеет частоту 16 МГц, меньше пинов, лишь 32 КБ flash-памяти, 2 Кб оперативной памяти, 10-битный АЦП, 8-и битный ШИМ, по одному каналу UART, I2C и SPI, а про JTAG он и вовсе слыхом не слыхивал. То есть, за те же деньги мы получаем куда более мощную железку.

Настройка Arduino IDE

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

Для программирования под данную плату нам понадобится кросс-компилятор для ARM, отладчик, стандартная библиотека C и клиент к программатору. В Arch Linux соответствующие пакеты ставятся так:

sudo pacman -S arm-none-eabi-gcc arm-none-eabi-gdb \
  arm-none-eabi-newlib stlink

Далее учим Arduino IDE работать с нашей платой:

cd ~/opt/arduino/hardware
git clone https://github.com/rogerclarkmelbourne/Arduino_STM32.git

Мне дополнительно пришлось поправить Arduino_STM32/STM32F1/platform.txt:

# compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/
compiler.path=/usr/bin/

… ибо сыпались ошибки про то, что Arduino IDE не может найти исполняемый файл arm-none-eabi-g++.

После этого если открыть Arduino IDE, то в меню Tools → Board вы обнаружите большой выбор плат на базе микроконтроллеров STM32. Выбираем Generic STM32F103C. В Tools → Upload Method выбираем STLink. Четыре пина на плате с подписями 3.3V, IO, CLK и GND подключаем к пинам 3.3V, SWDIO, SWCLK и GND программатора соответственно. Проверяем джамперы на плате. Оба джампера (так называемые boot0 и boot1) должны стоять в положении 0.

Пробуем скомпилировать и залить такой скетч:

void setup() {
  pinMode(PC13, OUTPUT);
}

void loop() {
  digitalWrite(PC13, HIGH);
  delay(100);
  digitalWrite(PC13, LOW);
  delay(100);
}

Fun fact! В плате Blue Pill светодиод стоит между ногой PC13 и VCC (схема [PDF]), а не между ногой и землей, как можно было бы ожидать. Поэтому, подавая HIGH на PC13, мы гасим светодиод, а подавая LOW — зажигаем.

Если при загрузке получаем ошибку:

st-flash 1.3.1
INFO src/common.c: Loading device parameters....
WARN src/common.c: unknown chip id! 0xe0042000

… то скорее всего вы перепутали пины CLK и IO.

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

Поздравляю, среда разработки настроена!

Более сложный пример

Ниже приведен код посложнее, демонстрирующий использование ШИМ, аналоговых пинов, а также отладочный вывод по UART:

const int LED1 = PB8;
const int LED2 = PB9;
const int PTNT = PA0;
const int BTN = PB7;

int selected_led = LED1;
bool btn_was_high = false;

void setup() {
  pinMode(LED1, PWM);
  pinMode(LED2, PWM);
  pwmWrite(LED1, 0);
  pwmWrite(LED2, 0);
  pinMode(BTN, INPUT);
  pinMode(PTNT, INPUT_ANALOG);

  Serial.begin(115200);
}

void loop() {
  delay(100);

  if(digitalRead(BTN) == HIGH) {
    btn_was_high = true;
  } else if(btn_was_high) {
    btn_was_high = false;
    if(selected_led == LED1) {
      selected_led = LED2;
      pwmWrite(LED1, 0);
    } else {
      selected_led = LED1;
      pwmWrite(LED2, 0);
    }
  }

  int ptnt = analogRead(PTNT);
  int ptnt_mapped = map(ptnt, 0, 4095, 0, 65535);

  Serial.println(String("ptnt = ") + ptnt + ", ptnt_mapped = " +
    ptnt_mapped);

  pwmWrite(selected_led, ptnt_mapped);
}

Соответствующая цепь, собранная на макетной плате:

Моя первая цепь с микроконтроллером STM32

При нажатии на кнопку один светодиод гаснет, а второй загорается. Яркость свечения светодиода регулируется потенциометром. Как видите, код очень мало отличается от обычного кода для Arduino. Отличаются только названия пинов, а также диапазоны значений, с которыми работают процедуры analogRead и pwmWrite.

Еще больше примеров можно найти в File → Examples → A_STM32_Examples.

Сторонние библиотеки

Многие библиотеки уже портированы под STM32 — Wire, Servo, LiquidCrystal, и другие. А что, если попытаться использовать стороннюю библиотеку с GitHub? Для эксперимента я решил попытаться воспользоваться библиотекой LiquidCrystal_I2C, уже знакомой нам по заметке Об использовании экранчиков 1602 с I2C-адаптером.

Добавляем библиотеку в Arduino IDE:

cd ~/Arduino/libraries
git clone \
 https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library.git\
 ./LiquidCrystal_I2C

Заливаем прошивку:

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, PB6, PB7);

void setup() {
  lcd.begin();
  lcd.setCursor(0, 0);
  lcd.print("Current time:");
}

void loop() {
  delay(100);
   
  lcd.setCursor(0, 1);
  unsigned long tstamp = millis();
  int h = tstamp / 1000 / 60 / 60;
  int m = (tstamp / 1000 / 60) % 60;
  int s = (tstamp / 1000) % 60;

  String line = String(h) + "h " +
                String(m) + "m " +
                String(s) + "s";

  int len = line.length();
  while(len < 16) {
    line += " ";
    len++;
  }

  lcd.print(line);
}

Любуемся результатом:

Использование библиотеки LiquidCrystal_I2C на STM32

Стоит помнить, что экранчику нужно 5 В, а плата питается от 3.3 В. Поэтому, чтобы все заработало, плату нужно запитать от USB, а экранчик подключить к пину 5V. Экранчик оказался совместим с 3.3-вольтовой логикой, но в более общем случае может потребоваться преобразователь логических уровней.

Само собой разумеется, не всякая библиотека, написанная под Arduino, так просто возьмет и заработает под STM32. Но, по всей видимости, для многих библиотек это действительно так.

Заключение

Итак, что же мы выяснили? Плата стоит как Arduino Nano, имеет похожий форм-фактор, но является при этом куда более мощной. Писать под нее можно точно так же, как под Arduino. При этом нам доступны если и не все те же библиотеки, что под Arduino, то по крайней мере очень многие из них.

Ссылки по теме:

А программируете ли вы под STM32 и если да, то что для этого используете?

Метки: .

Подпишись через RSS, E-Mail, Google+, Facebook, Vk или Twitter!

Понравился пост? Поделись с другими: