
В интернете есть много разных статей по решению задач с IT-собеседований, но на русском языке по программированию микроконтроллеров я видел только одну статью на Хабре. Недавно я менял работу: посещал много компаний и отвечал на вопросы по поводу различных аспектов моей профессии. По итогам этих и более ранних встреч решил написать о том, чем на собеседованиях могут озадачить программиста микроконтроллеров. Дисклеймер: хоть эта статья и размещена в блоге YADRO, в ней собраны вопросы от разных компаний.
Все вопросы из статьи мне задавали, и когда я был «зеленым» студентом, и когда я стал уже специалистом с опытом. Я решил разделить их по темам и не привязываться к своему стажу на тот момент: бывало, я получал довольно сложные и интересные вопр��сы сразу после окончания института и, наоборот, сталкивался с совсем простыми, будучи опытным специалистом.
В первую очередь эта статья для молодых специалистов, которым интересно, что вообще спрашивают при устройстве на программиста микроконтроллеров. Во вторую — для тех, кто давно не ходил на собеседования и хочет вспомнить, что там могут спросить.
Правила такие: я пишу вопрос и короткий ответ, исходя из моих нынешних познаний (без претензии на абсолютную истину). Некоторые вопросы общего характера я оставлю без ответа и вынесу в конец раздела — например, об опыте использования технологии в целом. Вопросы последовательно разложены до минимальных составляющих, в реальности общение выглядит чаще не как последовательный опрос по этим пунктам, а как естественная беседа.
Для упрощения все ответы приведены для 32-битных микроконтроллеров STM32 и операционной системы FreeRTOS. Последний нюанс: я пока не работал с Ethernet, поэтому вопросов про его устройство в статье нет, хотя про него спрашивают практически на каждом собеседовании.
Вопросы про программирование
Что такое volatile? — Ключевое слово, которое сообщает компилятору, что значение переменной может изменяться вне текущего потока, например, в прерывание.
Что такое extern? — Ключевое слово для объявления переменных, которые фактически определены в другом месте, например в соседней библиотеке.
Что такое static? — Если объявить функцию со словом «static», то она будет видна только в этом файле. Если объявить с такой припиской локальную переменную, то она сохраняет свое значение между вызовами функции.
Необходимо повернуть двумерный квадратный массив на 90˚, как это сделать? — Вначале меняем строки со столбцами, а затем зеркально отображаем.
Как определить количество элементов массива? — С помощью sizeof(array) / sizeof(array[0]).
Для чего нужен *void? — Это универсальный указатель на любой тип данных. Используется, например, в функциях работы с памятью (memcpy), где не важен тип данных.
Что такое константный указатель и указатель на константу? — Указатель на константу (const int p) сообщает, что нельзя менять значение, на которое он указывает, но можно менять адрес. Константный указатель (int const p) — что можно менять значение по адресу, но нельзя менять сам адрес.
Напишите функцию, которая подсчитывает количество единиц в бинарном числе.
int counter (unsigned int var){ int count=0; while(var) { if(var%2 ==1) count++; var /=2; } return count; }
Ниже представлен код. Что он должен делать по первоначальной задумке? Делает ли он это или его надо исправить? Как его исправить?
unsigned int count = 100; while (count >= 0){ printf("%u\n", count); count--; }
— Этот код должен выводить числа от 100 до 0, но когда count дойдет до 0 и из него еще раз вычтут единицу, он станет 0xFFFFFFFF. Для unsigned условие >= 0 истинно всегда. Самое простое решение — убрать unsigned.
Как происходит компиляция переменных с припиской extern? — Компилятор создает ссылки на внешнюю переменную.
Чем отличается union от struct? — В union элементы взаимоисключающие, делят одни ячейки памяти, а в struct выделяется место для каждого поля.
Что будет, если объявить переменную volatile const? — Из основного кода нельзя будет изменить значение переменной, но извне значение может измениться.
На два входа логической ячейки приходит 1, а выходит 0. Что это за ячейка? — Исключающее ИЛИ.
Какая первая программа была написана на языке С? — Этот язык был разработан для создания Unix.
Как выглядит число –2 в памяти контроллера? — 0xFE, если переменная однобайтовая (дополнительный код).
Чем динамическая переменная отличается от статической? — Статическая переменная создается один раз и хранится в памяти все время работы устройства, под динамическую же на стеке выделяется память, которая потом освобождается вручную.
Какой алгоритм невозможно реализовать программно? — Алгоритм, решающий проблему остановки.
Насколько хорошо знаете ассемблер? Используете ли вы ассемблерные вставки?
Знаете Python? Можете ли вы написать ПО верхнего уровня? Хотя обычно его пишут отдельные люди, порой бывает полезно уметь написать что-то самому для отладки.
Вы работали в Keil / Eclipse / IAR / VScode? Использовали Git / Github / Gitlab? Приходилось использовать LVGL? Знакомы с FreeRTOS или другими RTOS?
Вопросы про микроконтроллеры
Как написать код и прошить им микроконтроллер без использования IDE? — Скачать toolchain, написать main.c и makefile в блокноте, добавить файлы от производителя контроллера (startup, линковщик, CMSIS) и собрать все это через консоль. Для прошивки воспользоваться утилитами типа CubeProgrammer или сделать также через консоль.
Как работает startup-файл для микроконтроллера? — Настраивает стек и таблицу векторов прерываний, инициализирует память, вызывает main.
Расскажите поэтапно, как происходит компиляция проекта? — Препроцессинг (обработка include, define), компиляция (преобразование в ассемблер), ассемблирование (в машинный код), компоновка.
Что такое регистр? — Это ячейка памяти микроконтроллера (процессора или периферийного устройства), которая хранит данные и управляет работой оборудования.
Как писать во внутреннюю флеш-память контроллера? — Вначале необходимо выбрать сектор памяти, в который будет идти запись, после разблокировать работу с флеш-памятью, стереть сектор и тогда можно будет писать в память. После записи необходимо снова заблокировать флеш-память.
Какие особенности есть у флеш-памяти контроллера? — У нее ограниченный срок службы (~10 000 стираний), стирать необходимо постранично, но при этом запись возможна только после стирания. На чистой странице все значения равны 1.
Как после чтения данных с флеш-памяти убедиться, что они были записаны без ошибки? — Добавить к ним CRC и проверять при чтении.
Что такое bootloader? — Это, по сути, отдельная прошивка, задача которой — обновление и загрузка основной прошивки. Например, при включении микроконтроллера вначале запускается bootloader, который находит новую прошивку на подключенной флешке и устанавливает ее.
Что является точкой входа в программу? Какой именно код выполняется первым? — Функция Reset_Handler.
Опишите порядок инициализации ШИМ на выводе микроконтроллера. — Задаю тактирование микроконтроллера, порта вывода и таймера, настраиваю вывод как альтернативную функцию, затем настраиваю и запускаю таймер и канал с ШИМ.
Расскажите про режим энергосбережения. — Режим энергосбережения позволяет уменьшить ток потребления контроллера за счет уменьшения частоты тактирования и отключения периферии или перевода ядра в режимы sleep/stop. Часто используется в устройствах, которые питаются от аккумулятора. Самый простой пример — девайс включается несколько раз в день, чтобы снять и сохранить показания с датчиков, а затем уходит в энергосберегающий режим.
Как устроена RAM контроллера? Какие отделы памяти есть? — RAM используется для хранения данных программы, в ней есть секция data (содержит инициализированные глобальные переменные), bss (неинициализированные переменные), heap (куча) и stack (стек вызовов функций).
В каких режимах может работать вывод микроконтроллера, настроенный как выход? — Push-pull и open-drain.
Вопросы про RTOS
Чем отличаются жесткий и мягкий real time? — Жесткий real time подразумевает строгое соблюдение временных рамок, мягкий же предполагает некоторые упущения.
Что такое критическая секция? — Это участок кода, доступ к которому должен выполняться без прерывания другими задачами или обработчиками прерываний, дабы избежать повреждения данных.
Что такое атомарная операция? — Операция, которая выполняется как неделимое действие, целиком.
Что будет, если задач окажется очень много? — Будут выполняться только задачи с высоким приоритетом, если они готовы к выполнению. Задачи с низким приоритетом будут выполняться редко или не выполняться вообще.
Что будет, если в задаче будет бесконечный цикл? — При вытесняющей многозадачности эта задача будет занимать все рабочее время, за исключением выполнения задач с более высоким приоритетом. При невытесняющей — управление не будет передано другим задачам вовсе.
Какие существуют виды замещения задач? — Вытесняющая, когда задача с высоким приоритетом останавливает работу текущей задачи, и невытесняющая (кооперативная), когда задача сама передает управление.
Вы работали с семафорами, очередями?
Вопросы про электронику
Чем отличается биполярный транзистор от MOSFET? — Это был мой самый частый вопрос в студенчестве. Обычно хватает такого ответа: отличается структурой и тем, что MOSFET открывается напряжением, а биполярный транзистор — током.
Как нумеруются выводы микросхем? — Против часовой стрелки начиная от метки на корпусе.
Какие типы памяти микросхем знаете? — Энергозависимые (оперативная память, SRAM, DRAM) и энергонезависимые (ROM, EPROM, EEPROM, флеш, FRAM). Энергозависимые виды памяти теряют данные при отсутствии питания.
Как устроены ячейки памяти различных типов? — EEPROM и флеш строятся на базе транзисторов с переменным затвором. Ячейка SRAM — на базе нескольких транзисторов (триггер). DRAM — на базе транзистора и конденсатора маленькой емкости.
Чем линейный регулятор отличается от импульсного? — Линейный регулятор преобразует напряжение за счет рассеивания части мощности на регулирующем транзисторе, работающем в линейном режиме. Главным его достоинством является простота и выходное линейное напряжение. Импульсный же преобразователь регулирует напряжение за счет переключения ключа и фильтрации выходного сигнала, требует для себя некоторое количество обвязки, но при этом обладает более высоким КПД.
Как считается КПД линейного регулятора? — Выходное напряжение нужно разделить на входное.
Как отличить диодную сборку от биполярного транзистора одним мультиметром? — Использовать функцию hFE на мультиметре.
За счет чего электросчетчик измеряет затраченную мощность? — Электросчетчик измеряет напряжение и ток, протекающий в цепи, с помощью трансформаторов / шунтов / датчиков. Зная это, можно вычислить потребляемую мощность.
Можно ли из двух диодов сделать биполярный транзистор? — Нет, таким образом не получится сформировать работающий средний слой (базу).
Виды АЦП и их отличия? — Параллельные АЦП — это быстродействующее АЦП, где входное напряжение подается на массив компараторов. АЦП последовательного приближения — в них измеряемый сигнал сравнивается с эталонным напряжением, которое постепенно приближается по значению к измеряемому. Их комбинация (последовательно-параллельное АЦП), сигма-дельта АЦП — работает на базе интегратора и сумматора.
Что такое коэффициент мощности? — Отношение активной мощности к полной, коэффициент, показывающий эффективность использования электроэнергии.
Что изображено на схеме? Какую роль выполняет каждый из элементов? Как сконфигурированы подключенные выводы микроконтроллера?

— PA1 — цифровой выход, PA2 — вход АЦП. R1, R2 — токоограничительные резисторы. R3 и R4 — это делитель напряжения. Через делитель смотрим напряжение на нагрузке.
Вопросы про интерфейсы
Что такое bit stuffing? — Добавление дополнительного бита в сообщение, чтобы данные не воспринимались к��к специальная последовательность. Например, в CAN нельзя отправлять более пяти одинаковых бит подряд, поэтому после них добавляется бит противоположного значения (0b1111101).
Что такое byte stuffing? — Экранирование целого байта. Например, байт из данных может быть равен байту начала посылки, поэтому его заменяют на другой.
Как устроен арбитраж у CAN? Сообщение с каким ID при одновременной отправке уйдет первым, 0x01 или 0xAA? — У CAN доминантный бит 0, так что 0x01. Выигрывает всегда наименьший ID.
Какие типы кадров бывают у CAN? — Кадр данных, запроса данных, ошибки и перегрузки.
Какие механизмы защиты есть у CAN? — Есть CRC, ACK, проверка кадра в целом на правильную длину, bit stuffing.
Как соединить два микроконтроллера между собой по I²C? — Нужно выбрать выводы, которые поддерживают I²C, после чего соединить SDA с SDA, SCL с SCL. Линии необходимо подтянуть к плюсу питания через подтягивающие резисторы.
Как сделать SPI и I²C на простых GPIO-выводах? — Можно сделать «ногодрыг»: когда один вывод имитирует clock, а другой вывод передает данные. В случае с I²C выводы должны быть сконфигурированы как открытый коллектор и подтянуты через резистор к плюсу питания.
Вопросы на логику, математику и физику
Микроорганизмы в колбе увеличивают свою численность в два раза за день. За 50 дней они полностью заполнили колбу. За сколько дней они заполнят колбу наполовину? — За 49 дней.
Есть треугольник, на углах которого стоит по человеку. Каждый человек может пойти вдоль стороны треугольника, на которой находится. Направление движения выбирается независимо и случайно. С какой вероятностью два человека встретятся на любой из граней? — С вероятностью 75%.
8 программистов пишут 8 строк кода за 8 минут. Сколько времени понадобится одному программисту на 100 строк кода? — 800 минут + час обеда.
Продолжите ряд: 1, 3, 16, 125, … — 1296 (64).
Ни один астронавт не боится высоты. Некоторые музыканты боятся высоты. Тогда обязательно:
A. Все астронавты не музыканты.
B. Все музыканты не астронавты.
C. Некоторые музыканты не астронавты.
D. Некоторые музыканты — астронавты.
— Ответ: С.
Битовые операции и задачи с ними, например: что получится в выражении 0b0110 ^ 0b1001 ^ 0b1010? — Ответ: 0b0101.
Расскажите теорему Котельникова? — Для точного захвата сигнала частота захватывающего устройства должна быть как минимум в два раза больше максимальной частоты сигнала.
Расскажите законы Кирхгофа? — Сумма токов в узле равна 0. Сумма напряжений в цепи равна 0.
Переведите число из одной системы счисления в другую.
Практические задания
Практические задания — их я встречал всего пару раз, а делал только однажды. Меня просили сделать проект печатной платы в Altium с несколькими гальванически развязанными входами/выходами и написать простой код, где STM32 работал с микросхемой PCA9554PW — расширителем цифровых входов/выходов.
Когда был студентом, часто приносили чертежи, платы и просили рассказать, что за что на них отвечает. Когда ходил на собеседования уже с некоторым опытом, большую часть встречи общались про прошлые мои и нынешние проекты компании.
Стандартные вопросы тоже, конечно, были, в том числе:
Кем вы видите себя через пять лет в нашей конторе?
Почему уволились с прошлого места работы?
Чем бы вы хотели заниматься?
Выводы
Расскажу о своем взгляде на собеседования и на то, как к ним подготовиться. В первую очередь я бы посоветовал относиться к собеседованию не как к экзамену, а как к знакомству и последующей беседе. Вам нужно не только понравиться интервьюеру, но и самому оценить компанию, задачи и продукт, над которым предстоит работать. При подготовке я бы советовал пройтись по базовой теории, подготовить небольшой рассказ о своем прошлом опыте и проектах.
Приятнее всего мне показались собеседования, которые были выстроены скорее как диалоги. Не сухой опрос, а беседа о тонкостях работы того или иного механизма, который используется в текущих разработках компании. Очень понравилось, когда мне объясняли, где я ошибся в ответе на вопрос и почему. Один раз даже с интервьюером параллельно пересчитывали его задачу — оказалось, я потерял 0 в процессе вычислений. Если вам приходится проводить собеседования, я бы посоветовал человечнее относиться к соискателям и больше стремиться к формату диалога, нежели опроса. В конце концов, набравшись опыта спустя годы, человек может одобрительно вспоминать интересные собеседования в компаниях, где получил отказ, и захотеть реванша.
Кажется, сюда напрашивается вопрос: а какие самые запоминающиеся задачи на собеседованиях получали вы?
P. S. Кстати, вот статья на Хабре, которую я упоминал в самом начале.