Найти в Дзене

Использование union в C/C++ на примере АЦП MAX1241

В языке Си есть интересная структура union (объединение).

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

Это позволяет использовать отдельные "части" большей по размеру переменной (например, типа int или float) или наоборот, набирать из отдельных байт большую переменную.

Пример объединения для переменной для числа с плавающей запятой float, занимающей в памяти 32 бита (4 байта).

union my_float {

float f;

struct {

uint8_t byte0, byte1, byte2, byte3;

};

};

А теперь покажем, как это использовать на практике.

Имеется 12-битный АЦП MAX1241 с интерфейсом SPI.

Формат передачи следующий: сперва передается старший байт, потом - оставшиеся 4 байта, сдвинутые на 3 влево.

Изображение из даташита
Изображение из даташита

Можно было бы создать просто два отдельных байта, принять по очереди и объединить:

unsigned int ADC_read(void){

unsigned int byte0, byte1;

NSHDN = 1; // включить АЦП

delay_us(5); // пауза 5 мкс для инициализации

NCS = 0; // выбрать АЦП

while (!DOUT); // дождаться, пока преобразование не будет окончено

byte1 = spi(0); // считать старший байт

byte0 = spi(0); // считать младший байт

NCS = 1; // отменить выбор АЦП

NSHDN = 0; // выключить АЦП

byte0 = (byte1<<8) | byte0;

// привести данные с АЦП к напряжению: сдвинуть на 3 бита, ограничить 12 битами, умножить на разрешение (опорное напряжение/шкала = 5000 мВ/4095)

return ((byte0 >> 3)&0xfff)*VREF/SCALE;

}

Это работает, но с объединением, как по мне, код выглядит лучше.

Создадим объединение Word (слово), для объединения двух байт в 16-битную переменную (uint16_t):

/* Объединение для сохранения 2 байтового слова */

union Word {

unsigned char byte[2];

unsigned int word;

};

/* Функция считывания данных с АЦП */

unsigned int ADC_read(void){

union Word adc_data;

NSHDN = 1; // включить АЦП

delay_us(5); // пауза 5 мкс для инициализации

NCS = 0; // выбрать АЦП

while (!DOUT); // дождаться, пока преобразование не будет окончено

adc_data.byte[1] = spi(0); // считать старший байт

adc_data.byte[0] = spi(0); // считать младший байт

NCS = 1; // отменить выбор АЦП

NSHDN = 0; // выключить АЦП

// привести данные с АЦП к напряжению

return ((adc_data.word >> 3)&0xfff)*VREF/SCALE;

}

Программа стала чуть короче, мелочь, а приятно :)

Объединение байт "вручную" vs с помощью union
Объединение байт "вручную" vs с помощью union

Что-то пошло не так, и нам не удалось загрузить комментарии. Попробуйте ещё раз
Рекомендуем почитать
Циклы, языки и ассемблер
Рассмотрим довольно простую тему организации циклов. Почему я решил это сделать – потому что оказалось, что за привычными, особенно для уже замыленного глаза, вещами может скрываться неожиданное. Для начала обратимся к основам – как циклы делаются на ассемблере. Я буду использовать диалект x86, хотя это не принципиально. Итак, задача: Создать цикл, который повторяется 10 раз. Первый вариант: Этот цикл равносилен конструкции: for (i = 0; i < 10; i++) { ... } Как видим, здесь сначала i присваивается...
Что такое двоичная система счисления? Простыми словами
А знаете ли вы, что компьютер по факту работает с цифрами? Все наши данные: тексты, музыка, изображения, видео хранятся на накопителях и в оперативной памяти в виде обычных цифр. Компьютеру и для этого нужна мощность, чтобы преобразовать огромные массивы цифр в то, что мы видим на экране и слушаем в колонках. Это называется двоичной системой счисления. Давайте простыми словами разберемся, как это все работает. По факту, двоичная система счисления — это две цифры: 1 и 0. Основа любого компьютера — транзистор, который, как правило, имеет два состояния: открыт и закрыт...
Языки программирования 4: C
Язык C был создан чуть позже Паскаля Деннисом Ритчи из американской компании AT&T Bell Labs, и, выражаясь по-американски, "захватил мир как шторм". Предыдущая часть: Эффективный, компактный, очень гибкий в работе с памятью, он покорил меня с первого взгляда, и я сразу отказался от Бейсика и Паскаля, на которых писал до этого, оставив лишь ассемблер в запасе :) Но для новичков он не так уж понятен. Рассмотрим некоторые его особенности. Структура программы Первое, что видит человек при знакомстве с C, это вот такой код: Для сравнения код на Паскале: Программа на Паскале интуитивно понятна...
Следующая статья
Документы, вакансии и контакты