2010-01-14 2 views
1

На моем AVR у меня есть массив символов, которые содержат информацию интенсивности цвета в виде {R, G, B, x, R, G, B, x, .. .} (x - неиспользуемый байт). Есть ли простой способ написать длинный int (32-разрядный) до char myArray[4*LIGHTS], чтобы я мог легко написать номер 0x00BBGGRR?Использование массива символов в виде массива длинных ints

Мое типирование грубое, и я не уверен, как его написать. Я предполагаю, что просто сделайте указатель на длинный тип int и установите значение, равное myArray, но тогда я не знаю, как произвольно сказать ему, чтобы установить группу x в myColor.

uint8_t myLights[4*LIGHTS]; 
uint32_t *myRGBGroups = myLights; // ? 

*myRGBGroups = WHITE; // sets the first 4 bytes to WHITE 
         // ...but how to set the 10th group? 

Edit: Я не уверен, если типажи даже правильный термин, как я думаю, что если бы он просто усечен в 32-разрядное число до 8-бита?

+0

Правильно, это не связано с типизацией, а скорее с типедией и строками. – lImbus

ответ

5
typedef union { 
    struct { 
     uint8_t red; 
     uint8_t green; 
     uint8_t blue; 
     uint8_t alpha; 
    }   rgba; 
    uint32_t single; 
} Color; 

Color colors[LIGHTS]; 

colors[0].single = WHITE; 
colors[0].rgba.red -= 5; 

ПРИМЕЧАНИЕ. В системе с маленькими байтами младший байт 4-байтового значения будет альфа-значением; тогда как это будет красное значение в системе большого числа.

+4

Не должен ли внутренний союз быть структурой? –

+0

уверен, союз внутри союза не имеет смысла. внутренняя структура должна быть структурой. Я думаю, вы даже можете удалить имя внутренней структуры (здесь rgba), это дает вам прямой доступ к внутренним, например colors.red. – lImbus

+0

Struct кажется мне более подходящим (хотя союзы новы для меня), но когда я скомпилирую его в любом случае, я получаю тот же самый hex-файл. Это кажется подходящим способом узнать о них. - Одна из последних придирчивых вещей для меня - всякий раз, когда я пытаюсь захватить массив символов чем-то вроде 'uint8_t * pwmVals = colors;' Я получаю предупреждение: инициализация из несовместимого типа указателя. '= colors [0] .red' работает, но выглядит плохо: P –

1

Подумайте, используя C-соединение, где первое поле объединения является int32, а второе - символом 4 *. Но, не уверен, что это лучший способ для вас.

+0

Разве это не удвоило бы мои требования к памяти? У меня довольно ограниченное пространство и скорость на моем 8-битном AVR, и компилятор, похоже, хочет, чтобы мои значения интенсивности последовательны, чтобы он мог генерировать меньший/более быстрый код, когда он передает данные 4-канальным контроллерам света. –

+1

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

1

Вы должны объяснить endianness из uint32_t на AVR, чтобы убедиться, что компоненты хранятся в правильном порядке (для последующего разыменования через myLights массив), если вы собираетесь это сделать. Быстрый Google, похоже, указывает, что AVR хранят данные в памяти little-endian, но другие регистры различаются по контенту.

В любом случае, если вы это сделали, вы можете разыменовать myRGBGroups с использованием индексации массива (где каждый индекс будет ссылаться на блок из 4 байтов). Итак, чтобы установить 10-ю группу, вы можете просто сделать myRGBGroups[ 9 ] = COLOR.

0

если можно использовать арифметику myRGBgroup, например myRGBgroups ++ даст следующую группу, так же вы можете использовать плюс, минус и т.д. operators.those операторы работают с использованием размеров типа, а не один байт

myRGBgroups[10] // access group as int 
((uint8_t*)(myRGBgroups + 10)) // access group as uint8 array 
2

Ваш код действителен. Вы можете использовать myRGBGroups как обычный массив, так чтобы получить доступ к 10-й пиксель вы можете использовать

myRGBGroups[9] 
+0

увы, десятый элемент будет [9] – lImbus

+0

Я думаю, вам нужно явно нарисовать. 'uint32_t * myRGBGroups = (uint32_t *) myLights;' По крайней мере, вы делаете в C++; возможно, не в C. – Grumdrig

+0

Конечно, индекс 10-го элемента равен 9, моя ошибка;) Явное литье в C не обязательно, но необходимо в C++. C++ является более строгим в этом вопросе, чем C. –

0

Союз из структуры и uint32_t гораздо лучше, чем идея сделать uint8_t размером 4 * ОГНИ. Еще один довольно распространенный способ сделать это состоит в использовании макросов или встроенных функций, которые делают побитовое арифметика, необходимые для создания правильного uint32_t:

#define MAKE_RGBA32(r,g,b,a) (uint32_t)(((r)<<24)|((g)<<16)|((b)<<8)|(a)) 
uint32_t colors[NUM_COLORS]; 
colors[i] = MAKE_RGBA32(255,255,255,255); 

В зависимости от вашего байтов значения, возможно, должны быть помещены в междунар в другой заказ. Этот метод распространен, потому что для более старых 16-битных цветных форматов, таких как RGBA5551 или RGB565, имеет смысл думать о цветах с точки зрения поразрядной арифметики, чем в единицах байтов.

0

Вы можете выполнить что-то подобное, используя назначение структуры - это позволяет обойти проблему Endian:

typedef struct Color { 
    unsigned char r, g, b, a; 
} Color; 

const Color WHITE = {0xff, 0xff, 0xff, 0}; 
const Color RED  = {0xff, 0, 0, 0}; 
const Color GREEN = {0, 0xff, 0, 0}; 

Color colors[] = {WHITE, RED}; 
Color c; 

colors[1] = GREEN; 
c = colors[1]; 

Однако сравнение не определено в стандарте вы не можете использовать c == GREEN и вы не можете использовать {} ярлык в назначении (только инициализация), поэтому c = {0, 0, 0, 0} потерпит неудачу.

Также имейте в виду, что если это 8-битный AVR (в отличие от AVR32), то, скорее всего, вы не увидите каких-либо преимуществ в производительности от любой техники.