Использовать объединения для приведения типов это уже само по себе грязный хак.
Код
union MyUnion{
Type1 a;
Type2 b;
};
...
union MyUnion var;
var.a = something;
do_something_with(var.b);
По стандарту объединение - это лишь указание компилятору, что его поля
могут разделять общую память, и обещание (с стороны программиста) не использовать эти поля одновременно. Гарантируется, что записывая "а", мы его сможем прочитать, записывая "b" мы сможем прочитать его. А записывая "а", а после читая "b" мы нагло обманываем компилятор и можем за это получить по ушам. Шибко умный оптимизатор может заметить, что выражение var.a инициализируется, но нигде не используется и выкинет его инициализацию, после чего значение var.b будет не определено. Хотя часто такой код работает до поры до времени, пока не изменился уровень/флаги оптимизации, не обновился компилятор и т.д.
Единственно надежный способ (уже указан выше) это преобразовывать указатель на структуру в указатель на char:
Цитата
union SPI_union TXdata;
uint8_t* pData = (uint8_t*)&TXdata;
После этого можешь передавать данные в SPI:
SPDR = *pData++;