Unie i struktury. Problem.

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
Scrobik
-
Posty: 12
Rejestracja: 03 sie 2007, 11:06
Lokalizacja: Stalowa Wola
Kontakt:

Unie i struktury. Problem.

Post autor: Scrobik » 09 sie 2007, 9:56

Przeczytalem ciekawa wskazowkeo o adresowaniu bitowym.
Nie rozumiem tego zapisu uchar Flag1:1; Czy to oznacza ze zmiennej Flag1 jest nadana wartosc 1? Nie rozumiem tez po co sie stosuje unie? Dlaczego w unii Flags sa zadeklarowane dwie zmienne: FlagBits Bits; uchar Byte; Po co deklarowac: uchar Byte. Dziekuje za podpowiedz

Kod: Zaznacz cały

Mikrokontrolery AVR nie posiadają znanego z rodziny '51 obszaru pamięci adresowanego bitowo i związanego z tym naturalnego wsparcia dla jednobitowych, oszczędzających pamięć zmiennych logicznych. Możemy jednak uzyskać ten sam efekt wykorzystując standardowe mechanizmy C i deklarując unię, która zawiera albo bajt albo strukturę ośmiu pól jednobitowych :

typedef struct
{
 uchar Flag1:1;
 uchar Flag2:1;
 uchar Flag3:1;
 uchar Flag4:1;
 uchar Flag5:1;
 uchar Flag6:1;
 uchar Flag7:1;
 uchar Flag8:1;
} FlagBits;

typedef union
{
 FlagBits Bits;
 uchar   Byte;
} Flags;


Do zmiennych typu Flags mamy wtedy dostęp albo poprzez cały bajt albo poprzez poszczególne bity. Wygodnie jest też zdefiniować bity jako flagi nazwane zgodnie z pełnioną funkcją - ułatwia to ich używanie w kodzie :

volatile Flags SysFlags;
volatile Flags SerialFlags;
#define MS100FLAG SysFlags.Bits.Flag1
#define T1_DELAY_DONE SysFlags.Bits.Flag2


tasza
Użytkownik
Posty: 1391
Rejestracja: 21 lut 2005, 15:02

Post autor: tasza » 09 sie 2007, 10:41

Może na przykładzie:
:arrow: https://elportal.pl/tasza/lxt/led_tree_avr.zip ( https://elportal.pl/index.php?module=Co ... y&ceid=145 )
led_tree.h pisze:

Kod: Zaznacz cały

typedef struct {
	unsigned char b0: 1;
	unsigned char b1: 1;
	unsigned char b2: 1;
	unsigned char b3: 1;
	unsigned char b4: 1;
	unsigned char b5: 1;
	unsigned char b6: 1;
	unsigned char b7: 1;
} TBits;


typedef union {
	TBits			bits;
	unsigned char	uchar;
} TByte;

Zdefiniowałam dwa typy danych:
TBits - pole bitowe (8 sztuk po 1 bit)
TByte - unia, która zapewnia dostęp do bajtu jako takiego (składnik uchar), lub
do jego poszczególnych bitów (składnik bits)

z tej unii (typ TByte) korzysta taka zabawna funkcja CorrctPcb(),
która służy do "prostowania ścieżek" na płytce - po prostu ścieżki poprowadziłam
jak leci, aby odpowiednie dane trafiały tam gdzie trzeba - należy je przepuścić właśnie
przez wspomnianą funkcyjkę....
led_tree.c pisze:

Kod: Zaznacz cały

unsigned char CorrectPcb ( unsigned char b ) {

	TByte o,i;

	i.uchar = b;
	// rewrite as is
	o.bits.b7 = i.bits.b7;
	o.bits.b6 = i.bits.b6;
	o.bits.b5 = i.bits.b5;
	o.bits.b4 = i.bits.b4;
	// fix tracks ( see PCB layout )
	o.bits.b3 = i.bits.b0;
	o.bits.b2 = i.bits.b1;
	o.bits.b1 = i.bits.b2;
	o.bits.b0 = i.bits.b3;

	return ( o.uchar );
}
Jak działa powyższa?
Dostaje na wejście jako parametr jeden bajcik (unsigned char)
Zapisuje go na chwilkę w zmiennej lokalnej i ( od input ), ale ponieważ
to unia i dostaje unsigned char - wpisujemy daną do pola 'uchar'
Potem wykonujemy przemieszanie bitów (najmłodszych) i przepisanie na wprost najstarszych
(to operacje na polach bits.b0....bits.b7 )
potem zwracamy wynik wyciągając do z drugiej zmiennej lokalnej o (od out).
To taki przykład....inne zastosowanie pól bitowych i unii...
wyobraź sobie, że chcesz w np. EEPROM zachowywać takie rekordy danych:
numer kanału (zakres 0..3), wartość z jakiegoś przetwornika A/C (0...63).
Pierwsze zajmie 2 bity, drugie - 6 bitów - razem 8 czyli bajcik
robimy tak:

Kod: Zaznacz cały

typedef struct {
	unsigned char channelNum: 2;
	unsigned char adcData : 6;
} TBits;


typedef union {
	TBits			bits;
	unsigned char	uchar;
} TByte;

możesz wtenczas zadeklarować sobie zmienną:

Kod: Zaznacz cały

TByte dataRecord;
wypełnić jej pola przykładowo tak:

Kod: Zaznacz cały

dataRecord.bits.channelNum = 3;
dataRecord.bits.adcData = 29;
Zakładając, że masz funkcję do zapisu do EEPROM (czy gdziekolwiek) o takiej sygnaturze:

Kod: Zaznacz cały

void writeToEEprom (unsigned char address, unsigned char data);
wywołujesz ją np. tak:

Kod: Zaznacz cały

writeToEEprom ( 0xAA,  dataRecord.uchar );
Pytanka?

N.

Scrobik
-
Posty: 12
Rejestracja: 03 sie 2007, 11:06
Lokalizacja: Stalowa Wola
Kontakt:

Post autor: Scrobik » 10 sie 2007, 10:55

Dziekuje za wystarczajace wyjasnienie. Rozjasnilo mi sie w glowie. Powodzenia.

ODPOWIEDZ