I am writing data to eeprom AT24C16 using PIC microcontroller pic18f4520. Every address of this eeprom can hold 8-bits while I am using long int's to store data that are 16-bit in size. How to break long int into 2 8-bit parts to write them and how to get them back together after reading from eeprom??
3 Answers
In C, you can use bit-shift and masking to extract each byte of a longer number:
lower_8bits = value & 0xff;
upper_8bits = (value >> 8) & 0xff;
And you can 'reassemble' the number from bytes by doing the reverse:
value = (upper_8bits << 8) | lower_8bits;
-
\$\begingroup\$ I was tempted to start gibbering about unions, but this isn't the moment, is it? ;-) \$\endgroup\$– AsmyldofJun 30, 2015 at 13:37
-
1\$\begingroup\$ @Asmyldof It's tempting, but a good compiler will optimise bit shifting snippets to just a read of the relevant byte, without requiring you to worry about endianness. \$\endgroup\$ Jun 30, 2015 at 13:38
-
\$\begingroup\$ I know, but unions are awesomesauce :-D \$\endgroup\$– AsmyldofJun 30, 2015 at 13:42
-
\$\begingroup\$ Some compilers are stupid enough to actually shift-by-8 and [OR/AND], exactly as stated in the source code, even on an 8-bit chip with all optimizations turned on. I've used unions and pointer notation to get around this, depending on how often I need to access each variable that way. \$\endgroup\$– AaronDJun 30, 2015 at 19:03
long int my16bitdata = 0xEA51;
int MSB, LSB;
MSB = (my16bitdata>>8) & 0xFF;
LSB = my16bitdata & 0xFF;
In this case the outcome would be:
MSB = 0xEA
and
LSB = 0x51
Explaination:
By perfoming a bit shift(>>) operation on the 16 bit value, we can slide the upper bits down to the lower section. All 8 of them. We then do a bitwise AND (&) with a 0xFF to apply that value to the 8 bits available in the 'int'.
For the lower 8 bits (LSB), no bit shift is required so we can just do the bitwise AND to get the data we need.
A higher level approach that lets the compiler do the shifting would look like this:
typedef union Int16
{
int data;
struct
{
unsigned char lsb;
unsigned char msb;
}bytes __attribute__ ((packed));
}Int16 __attribute__ ((packed));
#define MSB bytes.msb
#define LSB bytes.lsb
Int16 myInt;
unsigned char msb, lsb;
myInt.data = 0x1234;
msb = myInt.MSB;
lsb = myInt.LSB;
long int
is only 16 bits? \$\endgroup\$