Добавить в корзинуПозвонить
Найти в Дзене
Будни инженера

Разные версии языка Си для микроконтроллеров

Ранее я показал простую программу для микроконтроллера на Си. Однако при компиляции программ на Си вы можете столкнуться с неожиданностями… Все мы привыкли думать, что язык Си — это как математика: дважды два везде четыре. Написал код на компьютере, перекинул на микроконтроллер, и всё работает. Теоретически — да. Практически — вас ждёт сюрприз. Язык Си для маленьких чипов — это совсем не тот язык, который учили в институте. Вернее, похож, но с большими «но». Давайте разбираться, почему так вышло и как не попасть в ловушку. Производители микроконтроллеров (например, STMicroelectronics, Microchip, Espressif) не пишут свой компилятор с нуля. Обычно они берут готовый движок (чаще всего от LLVM или GCC) и дорабатывают его под свою железку. Представьте, что у вас есть рецепт супа. Один повар варит его в кастрюле на плите, а второй — в мультиварке. Рецепт один, но вкус и время готовки будут разными. Так и здесь: база общая, а настройки свои. Вот основные три отличия, с которыми сталкивается к
Оглавление

Ранее я показал простую программу для микроконтроллера на Си. Однако при компиляции программ на Си вы можете столкнуться с неожиданностями…

Все мы привыкли думать, что язык Си — это как математика: дважды два везде четыре. Написал код на компьютере, перекинул на микроконтроллер, и всё работает. Теоретически — да. Практически — вас ждёт сюрприз.

Язык Си для маленьких чипов — это совсем не тот язык, который учили в институте. Вернее, похож, но с большими «но». Давайте разбираться, почему так вышло и как не попасть в ловушку.

Единого «чистого Си» не существует

Производители микроконтроллеров (например, STMicroelectronics, Microchip, Espressif) не пишут свой компилятор с нуля. Обычно они берут готовый движок (чаще всего от LLVM или GCC) и дорабатывают его под свою железку.

Представьте, что у вас есть рецепт супа. Один повар варит его в кастрюле на плите, а второй — в мультиварке. Рецепт один, но вкус и время готовки будут разными. Так и здесь: база общая, а настройки свои.

Чем же они отличаются на деле?

Вот основные три отличия, с которыми сталкивается каждый, кто пробует перекинуть код с одного “камня” на другой.

1. Размер «обычных» чисел (это главная засада)

В учебниках по Си обычно пишут, что переменная int — это целое число. И всё. А сколько места она занимает в памяти — решает компилятор.

  • Для старого доброго контроллера 8051: int = 2 байта (может посчитать примерно до 32 тысяч).
  • Для мощного STM32: int = 4 байта (считает до 2 миллиардов).

Казалось бы, какая разница? А она есть. Если вы написали код для STM32, где переменная переполняется только на 2 миллиардах, и перенесли его на 8051, то переполнение наступит в 65 тысяч раз быстрее! Контроллер будет выдавать математическую «кашу» или просто зависнет.

2. Где живут переменные (ручное управление)

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

Производители добавляют в язык специальные слова-подсказки. Например:

  • __flash — значит «сохрани данные в энергонезависимой памяти, она медленная, зато данные не исчезнут при отключении питания».
  • __ram — значит «клади в быструю память, где значения перемещаются моментально».

В одной среде разработки (например, для AVR у Arduino) такое слово есть. А в другой среде (для ARM-чипов) его нет, потому что там всё иначе устроено. И ваш код, где было __flash, в другой среде просто выдаст ошибку.

3. Библиотеки — это не часть языка

Когда новичок пишет delay(1000), он думает, что это команда самого Си. Нет, это чья-то добрая библиотека.

Стандартные библиотеки (где лежат привычные printf, scanf, malloc) в мире микроконтроллеров — редкость. Зачем они, если в контроллере нет экрана и клавиатуры?

Поэтому в каждой среде разработки свой набор готовых кирпичиков (функций):

  • В Arduino – digitalWrite, analogRead.
  • В STM32CubeIDE – HAL_GPIO_WritePin.
  • В ESP-IDF (для ESP32) – gpio_set_level.

Они делают одно и то же (зажигают светодиод), но называются по-разному. И код с этими названиями несовместим.

Так что же делать простому радиолюбителю?

Не пугайтесь. Хорошая новость в том, что 95% логики (циклы, условия, математика) работают везде одинаково. Проблемы возникают только в двух случаях:

  1. Когда вы работаете напрямую с памятью.
  2. Когда вы работаете с входами/выходами или таймерами.

Золотое правило: Если у вас получилась программа для Arduino Uno, то вложить её в проект для ESP32 и нажать «скомпилировать» — плохая затея. Переписывать придётся только ту часть, которая касается конкретных железок (выводов, портов). Остальное, скорее всего, заработает само.

Итог

Версии Си для микроконтроллеров отличаются не «буквами» языка, а местными особенностями:

  • Размером чисел.
  • Своими служебными словами (про память).
  • Набором волшебных библиотек.

Но база — переменные, if, for, while, функции — едина на все 100%. Поэтому, научившись программировать в одной среде, вы без труда разберетесь и в другой. Главное — помнить, что «чистый Си» живёт только в книгах, а в реальных чипах у него всегда есть местный диалект.

На этом всё. Подписывайтесь на канал, чтобы ничего не пропустить…