|
|
|||||||||||||||||||||||||||
StructuresStructures are perhaps what makes C such a powerful language for creating very complex programs with huge amounts of data. They are basically a way of grouping together related data items under a single symbolic name. Why Use Structures?Here is an example: A piece of C51 software had to perform a linearization process on the raw signal from a variety of pressure sensors manufactured by the same company. For each sensor to be catered for there is an input signal with a span and offset, a temperature coefficient, the signal conditioning amplifier, a gain and offset. The information for each sensor type could be held in "normal" constants thus:
As can be seen, the names conform to an easily identifiable pattern of:
Where 'N' is the number of the sensor type. A structure is a neat way of condensing this type of related and repeating data. In fact the information needed to describe a sensor can be reduced to a generalized:
The concept of a structure is based on this idea of generalized "template" for related data. In this case, a structure template (or "component list") describing any of the manufacturer's sensors would be declared:
This does not physically do anything to memory. At this stage it merely creates a template which can now be used to put real data into memory. This is achieved by:
This reads as "use the template SENSOR_DESC to layout an area of memory named sensor_database, reflecting the mix of data types stated in the template". Thus a group of 5 unsigned chars will be created in the form of a structure. The individual elements of the structure can now be accessed as:
Arrays Of StructuresIn the example though, information on many sensors is required and, as with individual chars and ints, it is possible to declare an array of structures. This allows many similar groups of data to have different sets of values.
This creates four identical structures in memory, each with an internal layout determined by the structure template. Accessing this array is performed simply by appending an array index to the structure name:
and so on... Initialized StructuresAs with arrays, a structure can be initialized at declaration time
so that here the structure is created in memory and pre-loaded with
values.
Placing Structures At Absolute AddressesIt is sometimes necessary to place a structure at an absolute address. A typical example are CAN interfaces or other peripheral chips that offer arrays of data groups. For example, the registers of a memory-mapped real time clock chip are to be grouped together as a structure. The template in this instance might be
A trick using the linker is required here so the structure creation must be placed in a dedicated module. This module's XDATA segment, containing the RTC structure, is then fixed at the required address at link time. Using the absolute structure could be:
Linker Input File To Locate RTC_chip structure over real RTC Registers is: l51 main.obj,rtcbytes.obj XDATA(?XD?RTCBYTES(0h)) Pointers To StructuresPointers can be used to access structures, just as with simple data items. Here is an example:
Note that the '*' which normally indicates a pointer has been replaced by appending '->' to the pointer name. Thus '*name' and 'name->' are equivalent. Passing Structure Pointers To FunctionsA common use for structure pointers is to allow them to be passed to functions without huge amounts of parameter passing; a typical structure might contain 20 data bytes and to pass this to a function would require 20 parameters to either be pushed onto the stack or an abnormally large parameter passing area. By using a pointer to the structure, only the two or three bytes that constitute the pointer need be passed. This approach is recommended for C51 as the overhead of passing whole structures can tie the poor old 8051 CPU in knots! This would be achieved by:
Advanced Note: Using a structure pointer will cause the called function to operate directly on the structure rather than on a copy made during the parameter passing process. Structure Pointers To Absolute AddressesIt is sometimes necessary to place a structure at an absolute address. This might occur if, for example, a memory-mapped real time clock chip is to be handled as a structure. An alternative approach to that given earlier is to address the clock chip via a structure pointer. The important difference is that in this case no memory is reserved for the structure - only an "image" of it appears to be at the address. The template in this instance might be:
/* Define Real Time Clock Structure */
struct RTC
{
char seconds ;
char mins ;
char hours ;
char days ;
} ;
/* Create A Pointer To Structure */
struct RTC xdata *rtc_ptr ; // 'xdata' tells C51 that this
//is a memory-mapped device.
void main(void)
{
rtc_ptr = (void xdata *) 0x8000 ; // Move structure
// pointer to address of real-time
// clock at 0x8000 in xdata
rtc_ptr->seconds = 0 ; // Operate on elements
rtc_ptr->mins = 0x01 ;
}
This general technique can be used in any situation where a pointer-addressed structure needs to be placed over a specific IO device. However it is the user's responsibility to make sure that the address given is not likely to be allocated by the linker as general variable RAM! To summarize, the procedure is:
UnionsUnions allow you to define different datatype references for the same physical address. This way you can address a 32-bit word as a "long" OR as 2 different "ints" OR as an array of 4 bytes. A union is similar in concept to a structure except that rather than creating sequential locations to represent each of the items in the template, it places each item at the same address. A union specifying 4 bytes may still only occupy a single byte. A union may consist of a combination of longs, char and ints all based at the same physical address. The the number of bytes of RAM used by a union is simply determined by the size of the largest element, so:
requires 4 bytes, this being the size of a long. The physical location of each element is the base address plus the following offsets:
In embedded C the commonest use of a union is to allow fast access to individual bytes of longs or ints. These might be 16 or 32 bit real time counters, as in this example:
/* Declare Union */
union clock
{
long real_time_count ; // Reserve four byte
int real_time_words[2] ; // Reserve four bytes as
// int array
char real_time_bytes[4] ; // Reserve four bytes as
// char array
} ;
/* Real Time Interrupt */
void timer0_int(void) interrupt 1 using 1
{
clock.real_time_count++ ; // Increment clock
if(clock.real_time_words[1] == 0x8000)
{ // Check/compare lower word only
/* Do something! */
}
if(clock.real_time_bytes[3] == 0x80)
{ // Check/compare most significant byte only
/* Do something! */
}
}
[ Pointers and Arrays | Structures and Unions | Generic and Spaced Pointers ] |
ESAcademy, 2000 All materials |