
Views: 2271
Какие задачи нам позволяют решать структуры и объединения?
Для разработчика встроенных систем эффективность и компактность кода всегда на первом месте. Если программировании на Ассемблере ты сам определяешь как и где располагаются данные, то при программировании на Си надо позаботиться, что бы объяснить компилятору как ты хочешь, что бы данные были расположены. Для чего это надо, в первую очередь, для удобства обработки и обращения к данным.
Например, мне необходимо, чтобы данные были расположены последовательно в памяти. Для этого я опишу структуру, например:
// struct { int16_t s_CLt; // данные в формате 16 байт со знаком int16_t s_tNd; // int16_t s_rEL; // uint8_t s_SEc; // данные в формате 8 байт без знака (только положит значение) uint8_t s_Nin; // unsigned Accident :2; // данные в формате 2 байта без знака (только положит значение) unsigned Freezing :1; // данные в формате 1 байта }EE; // данные подлежащие хранению в еепром //
Это будет гарантировано, что данные в памяти будут расположены последовательно и займут 9 байт (если система процессора микроконтроллера 8 битная) или 6 слов (если 16 битная). Один дополнительный байт будут занимать две переменные описанные как Accident и Freezing, они займут соответственно 0 – 1 байт (Accident ) и 2 байт (Freezing).
Обратиться т.е записывать данные и читать можно таким образом, например:
// // Для записи EE.s_CLt = 4562; EE.Accident = 2; // Для чтения temp = EE.s_CLt; temp1 = EE.s_Nin; //
Со структурами struct все довольно понятно, это расположение данных последовательно в памяти и удобный доступ к ним, особенно, если надо писать какие-то флаги управления и потом данные “скопом” передавать через какой либо интерфейс на другое устройство. Но часто возникает необходимость например иметь представление одних и тех же данных и в виде байта (или слова) и в виде бит. Как это сделать, для этого в Си есть гибкий механизм объединения union.
Например, для передачи данных через последовательный порт нам необходимо иметь доступ к данным ка к байту, а для эффективности управления флагами управления содержащимся в этом байте, и меть доступ как к биту. Вот такой фокус и позволяют делать объединения. Еще раз структуры последовательно располагать данные в памяти, объединения описывать одни и те же данные разными именами и при этом разными типа данными.
Например, мы имеем структуру данных:
// struct { int16_t s_CLt; // данные в формате 16 байт со знаком uint8_t s_SEc; // данные в формате 8 байт без знака (только положит значение) unsigned Accident :2; // данные в формате 2 байта без знака (только положит значение) unsigned Freezing :1; // данные в формате 1 байта }EE; // //
Визуально это выглядит так:
Вся структура занимает 4 байта. EE.s_CLt занимает 2 байта, EE.s_SEc занимает 1 байта, переменные Accident, Freezing (два и и один байт) будут размещены в 4 байте.
Теперь нам, например, необходимо работать с битами переменной s_CLt, можно конечно использовать операциями с битами, например, нам надо контролировать состояние бита 0 в этой переменной мы, можем вычислить так, выполняем побитовое “&” с переменной и в зависимости от состояния операции выполняет если true или falce:
// if(EE.s_CLt & 0b0000000000000001) ******; else *******; //
Но можно каждому биту присвоить свое имя, это улучшает понимание программы и не рисвоать, что нарисовано выше например писать просто так:
// if(EE.FLED1) ******; else *******; //
Где EE.FLED1 мы дали имя биту 0 переменной EE.s_CLt, как это сделать? В нашу структуру надо внедрить объединение. Структуры и объединения можно как угодно комбинировать для всевозможного описания данных в памяти для удобной последующей обработки. В нашем варианте это будет выглядеть так:
// struct { //- union { int16_t s_CLt; // данные в формате 16 байт со знаком struct { unsigned FLED1 :1;// название бита 0 unsigned FLED2 :1;// название бита 1 unsigned FLED3 :1;// название бита 2 //***** }; }; uint8_t s_SEc; // данные в формате 8 байт без знака (только положит значение) unsigned Accident :2; // данные в формате 2 байта без знака (только положит значение) unsigned Freezing :1; // данные в формате 1 байта }EE; // //
Переменную s_CLt мы помещаем, в обеднение в котором находиться эта переменная и новая внутренняя структура. Название ни объединению, ни структуре мы не даем. В этом варианте мы сможет обращаясь, например, к EE.FLED1 контролируя или изменяя состояние бита 0 переменной EE.s_CLt.
Как это выглядит визуально.
Еще раз к пониманию структур, это возможность “объяснения” компилятору, что данные надо расположить в памяти последовательно. А к пониманию объединений, что данные одни и те же могут иметь разное название. Надеюсь я смог “на пальцах” объяснить эти гибкие особенности Си.
И для окончания, например, мне необходимо обработать эти 4 байка как одно 32 битное слово, как это сделать? Это сделать просто если нашу структур поместить в объединение и добавит в ней нашу 32 битную переменную:
union { struct { //- union { int16_t s_CLt; // данные в формате 16 байт со знаком struct { unsigned FLED1 :1;// название бита 0 unsigned FLED2 :1;// название бита 1 unsigned FLED3 :1;// название бита 2 //***** }; }; uint8_t s_SEc; // данные в формате 8 байт без знака (только положит значение) unsigned Accident :2; // данные в формате 2 байта без знака (только положит значение) unsigned Freezing :1; // данные в формате 1 байта }; uint16_t s_32bit; // в ней все наши биты }EE; //
Теперь при необходимости можно обратиться к переменной EE.s_32bit и получить все данные или изменить одной операцией.
Визуально это можно представить так:
Файлы для загрузки

Просто о структурах и объединениях в Си 343.32 KB 165 downloads
Проект с примером организации данных ...Это может быть интересно
WiFi ESP8266 ESP-202 (ESP-12F)
Views: 7860 Первое знакомство, сначала надо его купить… http://voron.ua/catalog/024404 Схема для подключения и тестирования По схеме ставим две кнопки, сброс и кнопку BT2, для перевода в режим обновления прошивки. Если надо сделать …Проект с использованием MCC часть 11
Views: 936 Можно несколько облагородить программу вынести наши процедуры обработки нажатия кнопок в отдельные функции. Но вы должны понимать, что это хоть и не значительно, но будет тормозить общую скорость …Проект с использованием MCC часть 03
Views: 1669 Первым делом перенастроим регистры конфигурации, следующим образом: Отключим выход генератора (CLKOUT function is disabled. I/O function on the CLKOUT pin) Включим сторожевой таймер (WDT enabled) После этой настройки …Интерактивные Led
Views: 555 Тема проекта продолжение следует…. Это может быть интересноCCP – модуль в режиме Compare на примере PIC18
Views: 3155 CCP – модуль можно использовать в трех режимах: Capture – позволяет захватывать входной сигнал и определять его параметры (длительность или частоту). Дополнительно управлять внутренними модулями. Compare – позволяет …Development board based on MCU PIC18F47Q84
Views: 1729 PIC18F47Q84 Microcontroller Family with CAN Flexible Data Status: In Production.MAX7219/21 и 8х8 LED дисплеи
Views: 1030 MAX7219, MAX7221 предназначены для вывода информации на 8 разрядов семисегментного индикатора, но на нем легко организовать вывод на светодиодные индикаторы 8х8. продолжение следует…. Это может быть интересноСчетчики посетителей
Views: 1276 Вас сосчитали!? или счетчики посетителей. Для чего нужны счетчики посетителей? Какие они бывают? ТОРГОВЛЯ. Подсчитайте, сколько ваш магазин посещает человек за день. Кок много человек приходит утром, какое …Стробоскоп для автомобиля
Views: 2194 Одним из популярных решений светового тюнинга автомобиля, мотоцикла или скутера стал эффект – “полицейский стробоскоп“. На база платы ch-c0050 реализовано несколько проектов. В этой статье приводятся две версии …MCC PIC24 – модуль OUTPUT COMPARE – в режиме генератора звуковых сигналов
Views: 747 При проектировании простых устройств автоматики, часто необходимо иметь механизм звукового оповещения. Самый верхний уровень, это формирование голосовых сообщений, но об этом, как то по позже… В самом примитивном …