CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

"Joining" ints

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
andyd



Joined: 08 Mar 2007
Posts: 30

View user's profile Send private message

"Joining" ints
PostPosted: Wed Apr 04, 2007 3:52 pm     Reply with quote

I'm sure there's some basic logical operation that could do this, but my head just won't think of it now... I need a 16 bit number, but due to the way my EEPROMs are read, I need to read it as two 8 bit numbers (the 8 MSB then the 8 LSB), how can I then "join" these to make the 16 bit number? Like strcat() but for ints basically...
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Apr 04, 2007 4:14 pm     Reply with quote

...make16()

See also the chapter 'How do I write variables to EEPROM that are not a byte?' in the 'Common Questions And Answers' section of the CCS manual for another solution.
Guest








PostPosted: Thu Apr 05, 2007 8:09 am     Reply with quote

Something like this would work. A similar, but opposite, technique can be used to break a 16-bit number into two 8-bit numbers.
(note: this has not been compiled)

int8 lsb; // low order byte
int8 msb; // high order byte
int16 result; // concatenation of the two above values

result = (int16)msb << 8; // cast msb to a 16-bit, shift it left 8 places
result += lsb // add lsb into the lower half of result
Ttelmah
Guest







PostPosted: Thu Apr 05, 2007 9:29 am     Reply with quote

There are three techniques. Which is easiest/best, depends on you.
Make8/make16. Advantage already there in the compiler. Disadvantage, is that it is 'CCS' specific.
Using shifts and masks as shown above. Pretty generic. Downside is that it is more work for the compiler (but the compiler is pretty efficient about this).
The third is the union. My favourite.
Code:

union splitter {
   int8 b[2];
   int16 w;
};

union splitter val;
val.b[0] = 0x10;
val.b[1] = 0x20;

printf("%4LX/n/r",val.w);
//prints '2010' - the bytes have been combined

val.w=0x1234;

printf("%2X/n/r",val.b[0]);
//prints '34' the low byte has been selected.

This is a standard C construct, and allows rally quick conversions both ways.
You can even declare a structure, with 'low', and 'high' bytes, and ue this instead of the array. This can be really useful when moving code between processors where the byte oder differs, making it easy to convert.

Best Wishes
bungee-



Joined: 27 Jun 2007
Posts: 206

View user's profile Send private message

PostPosted: Mon Apr 20, 2009 4:28 pm     Reply with quote

Ttelmah wrote:

The third is the union. My favourite.
Code:

union splitter {
   int8 b[2];
   int16 w;
};

union splitter val;
val.b[0] = 0x10;
val.b[1] = 0x20;

printf("%4LX/n/r",val.w);
//prints '2010' - the bytes have been combined

val.w=0x1234;

printf("%2X/n/r",val.b[0]);
//prints '34' the low byte has been selected.

Thank you for the code example above.

I have a question regarding union. Is it possible to declare it like that:


Code:

union splitter {
    int8 b1;
    int8 b2;
    int16 w;
};



And to work it the same as your code. I would put two ports instead of b1 and b2 so I could work with 16bit port :D

Thank's for the answers. Cool
Ttelmah
Guest







PostPosted: Tue Apr 21, 2009 2:21 am     Reply with quote

No.
As posted:
Code:

union splitter {
    int8 b1;
    int8 b2;
    int16 w;
};

This gives you a 16bit memory 'location', holding 'w', and then a byte 'b1', mapped to the same location (LSB), and _another_byte 'b2', mapped to the same location_. Neither talks to the 'MSB' of the 16bit value.
A union, maps each variable in it, to the same memory location. In the original, the 2byte array, is mapped to the same location as the 16bit 'w' value, allowing you to access each byte, as the entries in the array.
If you want to use 'names', rather than an array access, the way to go, is to declare a 'new' 16bit structure. So:
Code:

struct bytes {
    int8 LSB;
    int8 MSB;
};

union splitter {
    struct bytes b;
    int16 w
} val;

Then you can talk to val.w for the whole 16bit 'word', or val.b.LSB, and val.b.MSB for the two bytes.

Best Wishes
andrewg



Joined: 17 Aug 2005
Posts: 316
Location: Perth, Western Australia

View user's profile Send private message Visit poster's website

PostPosted: Tue Apr 21, 2009 8:00 am     Reply with quote

One caution for using the union technique, is if you might ever want to port to a different endian architecture (big-endian versus little-endian, which flip the order of the bytes). In that case, using explicit bit shifts is probably best, followed by the make16, since you can easily implement your own make16 on other platforms.
_________________
Andrew
Ttelmah
Guest







PostPosted: Tue Apr 21, 2009 8:43 am     Reply with quote

Actually, I'd say the union/structure technique is better in this case.
All you do is something like:
Code:

#ifdef LSBfirst
struct bytes {
    int8 LSB;
    int8 MSB;
};
#else
struct bytes {
    int8 MSB;
    int8 LSB;
};
#endif

and you gain a version that is portable onto any compiler offering a define int8 type, just defining 'LSBfirst', for chips where thsi is true.
Rotations can give unexpected results sometimes, when dealing with signed values in particular, on older compilers, and are sometimes coded quite inefficiently, hence my preference for the structure/union approach.
Macros ae probably the 'best' overall solution, since you can then just code to match the vagaries of your particular compliler/CPU.... Smile

Best Wishes
John P



Joined: 17 Sep 2003
Posts: 331

View user's profile Send private message

PostPosted: Tue Apr 21, 2009 10:07 am     Reply with quote

A very smart friend suggested this method to me a few years ago, and since then it's the way I've always done it:

Code:

   int16 the_word;
   #byte word_low = the_word
   #byte word_high = the_word+1


If you want to see how it looks in the LST file:

MAIN.THE_WORD 00000064
MAIN.WORD_LOW 00000064
MAIN.WORD_HIGH 00000065

Yes, 8-bit variables set up using the #byte directive are usable just like any other variables. So you can read or write the full 16-bit variable, or either of its components, just as you need to.
bungee-



Joined: 27 Jun 2007
Posts: 206

View user's profile Send private message

PostPosted: Thu Apr 23, 2009 3:59 pm     Reply with quote

Thank you all for the answers. I learn a lot from them. But my problem still remains. I also try to use #byte statment.

I will describe my problem. I have two ports on PIC18f4550 and I would like to use them together as 16bit port. But the trick is that I will use port B and port D, because A and C are intended for other things.

I could use make8 instructions (probably will), but I wandered if is there another way.
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Thu Apr 23, 2009 6:40 pm     Reply with quote

Code:
int8 var1;// LSB
int8 var2;// MSB
int16 var3;
var1 = input_b();
var2 = input_d();
var3 = make16(var2, var1);


This will read portb and portd, place them into a 16-bit variable. Not much simpler, I think.

Ronald
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group