|
|
View previous topic :: View next topic |
Author |
Message |
kypec
Joined: 20 Sep 2003 Posts: 54
|
Conversion and manipulation between 8 and 16 bit variables |
Posted: Tue Nov 11, 2003 4:26 am |
|
|
Hello,
I was looking for an easy way how to load int8 to either low or high
byte of int16 variable WITHOUT affecting the other byte of that int16.
The opposite conversion is quite simple:
int16 word;
int8 lowbyte, highbyte;
lowbyte=make8(word,0);
highbyte=make8(word,1);
My solution is like this (only for PIC18 family -> tested with PCH 3.180 compiler)
Code: |
////////////////////////////////////////////////////////////////////////////////
//MACRO for straight move of 8-bit variable to low byte of 16-bit variable
////////////////////////////////////////////////////////////////////////////////
#define move8to16low(SOURCE8,DESTINATION16) \
#asm \
movff SOURCE8,&DESTINATION16 \
#endasm
////////////////////////////////////////////////////////////////////////////////
//MACRO for straight move of 8-bit variable to high byte of 16-bit variable
////////////////////////////////////////////////////////////////////////////////
#define move8to16high(SOURCE8,DESTINATION16) \
#asm \
movff SOURCE8,&DESTINATION16+1 \
#endasm
|
and then whenever in your code you just use
move8to16low(lowbyte,word)
or
move8to16high(highbyte,word)
Please post your comments and suggestions if you know
about some pure C solution for this, thanks. |
|
|
Ttelmah Guest
|
Re: Conversion and manipulation between 8 and 16 bit variabl |
Posted: Tue Nov 11, 2003 5:46 am |
|
|
kypec wrote: | Hello,
I was looking for an easy way how to load int8 to either low or high
byte of int16 variable WITHOUT affecting the other byte of that int16.
The opposite conversion is quite simple:
int16 word;
int8 lowbyte, highbyte;
lowbyte=make8(word,0);
highbyte=make8(word,1);
My solution is like this (only for PIC18 family -> tested with PCH 3.180 compiler)
Code: |
////////////////////////////////////////////////////////////////////////////////
//MACRO for straight move of 8-bit variable to low byte of 16-bit variable
////////////////////////////////////////////////////////////////////////////////
#define move8to16low(SOURCE8,DESTINATION16) \
#asm \
movff SOURCE8,&DESTINATION16 \
#endasm
////////////////////////////////////////////////////////////////////////////////
//MACRO for straight move of 8-bit variable to high byte of 16-bit variable
////////////////////////////////////////////////////////////////////////////////
#define move8to16high(SOURCE8,DESTINATION16) \
#asm \
movff SOURCE8,&DESTINATION16+1 \
#endasm
|
and then whenever in your code you just use
move8to16low(lowbyte,word)
or
move8to16high(highbyte,word)
Please post your comments and suggestions if you know
about some pure C solution for this, thanks. |
Just use a union...
Universal C, and makes small code.
union CONVERT {
int8 b[2];
int16 word;
} value;
Then to write to/retrieve the bytes, just use value.b[0], and value.b[1]. To talk to the whole 'word', use value.word.
So:
int8 onebyte;
value.word=0x3FF;
onebyte=value.b[1]; //onebyte=03
value.b[1]=0x7;
printf("%lx",value.word); //will print 7FF
Works on all the PICs, and (with a caveat about the byte order), on other processors to. The code produced is single byte accesses for the byte operations, which is as good as the assembler solution.
Best Wishes |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Tue Nov 11, 2003 8:28 am |
|
|
Their are built in functions to handel this and keep your code easy to read.
Make8
Make16
Make32
Refer the the manual for their use. |
|
|
kypec
Joined: 20 Sep 2003 Posts: 54
|
Not what I was looking for |
Posted: Tue Nov 11, 2003 8:56 am |
|
|
Unfortunately,
make8 is only useful when you need to retrieve int8 alias byte
from larger variable like int16 or int32
make16 is for creating int16 alias long variable from two smaller
variables like int8
however, what I needed to do is to modify ONLY ONE byte of
int16 variable without use of any shifting, masking or whatsoever operations on that int16 variable
that hint with UNION declaration is indeed very handy, thanks
now my code looks like this:
Code: |
union word {
int8 b[2]; //low[0] and high[1] byte
int16 w; //create together one word
};
union word parameter[32]; //={0x05FF,100,100,1000,1000,500,100};
int8 mode_flags, now_flags;
int16 time_valve;
mode_flags=parameter[0].b[1]; //reading the byte from word
parameter[0].b[0]=now_flags; //writing the byte to word
time_valve=parameter[1].w //reading the word from word
|
the only disadvantage I can see now is that I lost the possibility
to declare and initialize my array of parameters in simple step
(therefore those brackets with hexa values) |
|
|
Ttelmah Guest
|
Re: Not what I was looking for |
Posted: Tue Nov 11, 2003 9:29 am |
|
|
kypec wrote: | Unfortunately,
make8 is only useful when you need to retrieve int8 alias byte
from larger variable like int16 or int32
make16 is for creating int16 alias long variable from two smaller
variables like int8
however, what I needed to do is to modify ONLY ONE byte of
int16 variable without use of any shifting, masking or whatsoever operations on that int16 variable
that hint with UNION declaration is indeed very handy, thanks
now my code looks like this:
Code: |
union word {
int8 b[2]; //low[0] and high[1] byte
int16 w; //create together one word
};
union word parameter[32]; //={0x05FF,100,100,1000,1000,500,100};
int8 mode_flags, now_flags;
int16 time_valve;
mode_flags=parameter[0].b[1]; //reading the byte from word
parameter[0].b[0]=now_flags; //writing the byte to word
time_valve=parameter[1].w //reading the word from word
|
the only disadvantage I can see now is that I lost the possibility
to declare and initialize my array of parameters in simple step
(therefore those brackets with hexa values) |
There is a way (more 'CCS specific'), to give both abilities, provided you are happy to manually 'set' the variables at a particular address. You can use the #locate ability to place two variables into the same area of memory (rather like a union). So:
struct {
int8 b[2];
} bytearray[];
int16 wordarray[32]={0x05FF,100,100,1000,1000,500,100};
#locate bytearray=0x400
#locate wordarray=0x400
Places an initialised int16 array (called 'wordarray'), at address 0x400 in RAM, and also an array of 'bytearray' structures at the same point.
Then just as with the union, you can access:
wordarray[0] - the first 16bit 'word', while:
bytearray[0].b[0] - is the low byte of the first word.
Again like the union system, it generates quite tidy code.
It is also worth realising, that you can cast between types into a function. So, if you declare the array as int16, and initialise it, and have the union type declared, you can create a function like:
put_byte(union word location, int val, int place) {
location.b[place]=val;
}
and call this with an int16 value, like:
int16 array[32]={0x05FF,100,100,1000,1000,500,100};
put_byte(array[2],5,0);
which will write the byte '5' to the low byte of 'array[2]', effectively giving the other 'half' of the make8/make16 functions. :-)
Best Wishes |
|
|
dragonpic Guest
|
how I do it |
Posted: Tue Nov 11, 2003 3:02 pm |
|
|
int highbyte, lowbyte;
long word;
#BYTE word0 = word
#BYTE word1 = word + 1
highbyte = word1
lowbyte = word0 |
|
|
Ttelmah Guest
|
Re: how I do it |
Posted: Tue Nov 11, 2003 3:33 pm |
|
|
dragonpic wrote: | int highbyte, lowbyte;
long word;
#BYTE word0 = word
#BYTE word1 = word + 1
highbyte = word1
lowbyte = word0 |
Works fine for a single value, but is not really a solution for an array of values... :-)
Best Wishes |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Nov 11, 2003 5:14 pm |
|
|
One word - Pointers |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 12, 2003 3:30 am |
|
|
Mark wrote: | One word - Pointers |
Yes, _but_...
It depends what you want to do, and how often. You can as you say, access words as bytes, or bytes as words, using pointers, and casting them between types. Unfortunately, the resulting code is _bulky_, and relatively slow. For instance, accessing the bytes in the union method, generates single instruction accesses, for fixed addresses. Doing the same using pointers, runs to about 30 instructions.
You 'pays your money'... :-)
Best Wishes |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Wed Nov 12, 2003 7:07 am |
|
|
Yep, but he is using arrays which will already generate the "bulky" code. |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 12, 2003 7:26 am |
|
|
Mark wrote: | Yep, but he is using arrays which will already generate the "bulky" code. |
Not true.
If (as he shows), you generate array accesses to fixed addresses, the code produced is a single access to the actual value. So if you use arrays purely for their 'simplicity', in terms of the code appearance, rather than for allowing a variable to act as an index, then you don't get the time overhead of a table access. There will be one 'table access' routine, written in front of the stored array data, but this won't be used for the simple accesses. Also the routine only appears once. If you write multiple routines accessing data via pointers, the table access code is repeated in each location it is used.
Best Wished |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Wed Nov 12, 2003 7:52 am |
|
|
I will bet a nickel that is uses a variable to access the data and that the fixed address is just an example. Furthermore, I would bet that a structure is really what he wants but is unsure of how to initialize one. |
|
|
neil
Joined: 08 Sep 2003 Posts: 128
|
All variations on a theme |
Posted: Wed Nov 12, 2003 12:44 pm |
|
|
I have always used the way CCS did it in their faq about writing a long to EEPROM. (Pointers in other words)
#define lo(x) *&x
#define hi(x) *(&x+1)
...
long variable;
hi(variable) = 0xE0;
lo(variable) = 0xFC;
// variable now = 0xE0FC
or:
variable = 0xAA55;
int low, high;
low = lo(variable); // low = 55
high = high(variable); // high = AA
From what I have seen, there is virtaully no extra code generated, just direct access to the bytes in either direction, as, quite logically the compiler assigns mulitbyte words sequentially. Am I right in thinking this?
Neil. |
|
|
Ttelmah Guest
|
Re: All variations on a theme |
Posted: Wed Nov 12, 2003 2:25 pm |
|
|
neil wrote: | I have always used the way CCS did it in their faq about writing a long to EEPROM. (Pointers in other words)
#define lo(x) *&x
#define hi(x) *(&x+1)
...
long variable;
hi(variable) = 0xE0;
lo(variable) = 0xFC;
// variable now = 0xE0FC
or:
variable = 0xAA55;
int low, high;
low = lo(variable); // low = 55
high = high(variable); // high = AA
From what I have seen, there is virtaully no extra code generated, just direct access to the bytes in either direction, as, quite logically the compiler assigns mulitbyte words sequentially. Am I right in thinking this?
Neil. |
No, this is fine, but the poster wants to work with arrays....
Best Wishes |
|
|
DragonPIC
Joined: 11 Nov 2003 Posts: 118
|
arrays? |
Posted: Wed Nov 12, 2003 3:16 pm |
|
|
I was responding to the original post. I seen nothing of arrays. Just a word and 2 byte variables.
Anyways
Code: | int make_8_from_16(long word, short high_low)
{
#BYTE word0 = word
#BYTE word1 = word + 1
if(high_low == 1)
return(word1);
else
return(word0);
} |
Maybe not the best way to approuch it, but it works. You just have to think about it. |
|
|
|
|
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
|