Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial Internet of Things >> Встроенный

Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Научитесь инициализировать массивы C с помощью внешних текстовых файлов

Это руководство объясняет, как заполнять массивы в программе на C данными, хранящимися в отдельных текстовых файлах. Значения не встраиваются в исходный код, а загружаются на этапе компиляции. Охватываются одномерные и многомерные массивы, показано, как управлять размещением массива в ОЗУ или энергонезависимой памяти, и как выбирать между несколькими файлами данных для инициализации.

Примеры ориентированы на 32-битный микроконтроллер ARM и компилятор GCC. Все фрагменты используют стандартный C и работают с этим компилятором.

Основы инициализации массива

При объявлении массива в C можно указать список значений — инициализаторов — в фигурных скобках. Например:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

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

Пробелы

Инициализаторы разделяются запятыми; между ними можно свободно добавлять пробелы, табуляции, переводы строк и другие пробельные символы. В C операторы могут занимать несколько строк, что особенно удобно для больших массивов.


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Инициализация массива из файла

Препроцессор C может включать произвольные текстовые файлы директивой #include. Эта возможность не ограничена заголовочными или исходными файлами — подходит любой простой текстовый файл. Файл с числами, запятыми и пробелами может использоваться для инициализации массива:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Включаемый файл должен быть чистым текстом — без форматирования, заголовков или других артефактов. Пример, созданный в Блокноте Windows:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

После компиляции массив в памяти выглядит так, как показано на скриншоте отладчика. В данном случае массив находится в ОЗУ, что видно по высоким адресам в столбце «Location».


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Размещение массива в энергонезависимой памяти и выбор файла данных

В примере выше массив — глобальная переменная без явного размещения. Компилятор предполагает, что она может меняться во время выполнения, и помещает в ОЗУ. Начальные значения хранятся во флеш-памяти, а процедура запуска копирует их в ОЗУ. Если массив действительно константен, квалификатор const говорит компилятору оставить его только во флеше, экономя драгоценное ОЗУ. На скриншоте ниже «Location» указывает на низкие адреса флеша.


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Директивы #define и #if позволяют переключать размещение в ОЗУ/флеш или выбирать разные файлы данных. Например, следующий код выбирает место хранения на этапе компиляции:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Конструкция #if — классический пример условного включения. Она определяет, применяется ли квалификатор const на основе флага компиляции.

Аналогично можно условно выбирать файл с исходными данными:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Тестирование на большом массиве

Для проверки техники использовался 10 000-элементный шумовой сигнал в CSV-файле. На графике ниже показана волна, а в объявлении — как данные включаются в программу:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн
 

Исходный CSV не содержал запятых после каждого значения. Операция поиска/замены по регулярному выражению (найти \R, заменить на ,\R) добавила запятые ко всем 10 000 записям за один раз.

Результирующий массив виден в отладчике, аккуратно сгруппированный по 100 элементов в строке.


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Многомерные массивы

При работе с двух- или трехмерными данными помните: C хранит массивы в порядке «строка за строкой» (row-major). Например, массив uint16_t test[2][3] в памяти выстроен как:

[0,0] [0,1] [0,2] [1,0] [1,1] [1,2]

Доступ к последовательным элементам по последнему индексу быстрее, так как данные смежны. Если нужны два вектора по 1000 отсчетов, объявляйте test[2][1000] для лучшей работы с кэшем.

Инициализатор двумерного массива обычно группируется вложенными скобками:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Однако внешние скобки можно опустить; компилятор заполнит массив слева направо. Выдается предупреждение missing braces around initializer. Если общее число значений совпадает с размером массива, код компилируется.


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Чтобы распределить данные по нескольким файлам, просто включайте каждый файл по очереди, оборачивая весь список в пару скобок:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Инициализация массивов в объединениях

union позволяет разным типам разделять одну память. Например, объединение, содержащее одномерный вектор и двумерную матрицу, занимает одно адресное пространство:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

При инициализации компилятор заполняет первый член первым. Если порядок обратный, может появиться предупреждение, так как список инициализации не полностью заключен в скобки. Двойные скобки вокруг #include обеспечивают правильную группировку:

Файл данных для объединения выглядит так:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

В памяти оба vector и matrix начинаются по одному адресу, как показывает отладчик:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Знаете ли вы другой способ инициализировать многомерный массив из одного числового файла? Делитесь идеями в комментариях.

Бонус: строки

Инициализация строки из внешнего файла требует, чтобы кавычки были внутри самого файла. Прямой #include внутри строкового литерала сломает компилятор. Вместо этого поместите кавычки в файл и включайте его так:


Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн

Результирующая строка находится в ОЗУ, как иллюстрирует скриншот.

 

Прошивка встроенных систем: лучшие практики инициализации массивов C из внешних файлов данных и сигнальных волн


 

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

 

Источник предоставлен.

Встроенный

  1. Облачная революция: как облачные вычисления трансформируют IT, безопасность и карьеры
  2. STMicroelectronics запускает STM32Cube.AI — внедрение нейросетей в пограничные устройства на STM32
  3. DATA MODUL запускает ультра-яркие 21.5" и 31.5" open-frame мониторы с EasyTouch для наружного и внутреннего использования
  4. Microchip представляет 24-бит и 16-бит Delta-Sigma ADC с 153.6 кSPS data rates
  5. Contrinex 2020: облачные сенсоры и Bluetooth light curtains для безопасности
  6. Массивы в C++: объявление, инициализация и работа с указателями
  7. Динамическое выделение массивов в C++: практическое руководство с примерами кода
  8. Чтение файлов в Java с BufferedReader — Практическое руководство с примерами
  9. Оживление IoT с IBM и Tech Data — Часть 2
  10. Превращение IoT в реальность: инсайты Tech Data и IBM — Часть 1