📄 chapter 7 pointers -- valvano.htm
字号:
use EEPROM for configuration constants and even nonvolatile data logging. For
more information on how to write C code that dynamically writes EEPROM see
Chapter 1 of Valvano's </FONT><U>Embedded Microcomputer Systems: Real Time
Interfacing<FONT face="Times New Roman,Times">.</FONT></U><FONT
face="Times New Roman,Times"> The one-time-programmable PROM is a simple
nonvolatile storage used in small volume products that can be programmed only
once with inexpensive equipment.<B> </B>The ROM is a low-cost nonvolatile
storage used in large volume products that can be programmed only once at the
factory.<B> </B></FONT></P>
<P> </P>
<P>
<TABLE borderColor=#808080 cellSpacing=2 width=533 border=0>
<TBODY>
<TR>
<TD vAlign=top width="23%"><FONT face="Times New Roman,Times"
size=2>Memory </FONT></TD>
<TD vAlign=top width="25%"><FONT face="Times New Roman,Times" size=2>When
power is removed</FONT></TD>
<TD vAlign=top width="33%"><FONT face="Times New Roman,Times"
size=2>Ability to Read/Write</FONT></TD>
<TD vAlign=top width="19%"><FONT face="Times New Roman,Times"
size=2>Program cycles</FONT></TD></TR>
<TR>
<TD vAlign=top width="23%"><FONT face="Times New Roman,Times"
size=2>RAM</FONT></TD>
<TD vAlign=top width="25%"><FONT face="Times New Roman,Times"
size=2>volatile</FONT></TD>
<TD vAlign=top width="33%"><FONT face="Times New Roman,Times"
size=2>random and fast access</FONT></TD>
<TD vAlign=top width="19%"><FONT face="Times New Roman,Times"
size=2>infinite</FONT></TD></TR>
<TR>
<TD vAlign=top width="23%"><FONT face="Times New Roman,Times"
size=2>battery-backed RAM</FONT></TD>
<TD vAlign=top width="25%"><FONT face="Times New Roman,Times"
size=2>nonvolatile</FONT></TD>
<TD vAlign=top width="33%"><FONT face="Times New Roman,Times"
size=2>random and fast access</FONT></TD>
<TD vAlign=top width="19%"><FONT face="Times New Roman,Times"
size=2>infinite</FONT></TD></TR>
<TR>
<TD vAlign=top width="23%"><FONT face="Times New Roman,Times"
size=2>EEPROM</FONT></TD>
<TD vAlign=top width="25%"><FONT face="Times New Roman,Times"
size=2>nonvolatile </FONT></TD>
<TD vAlign=top width="33%"><FONT face="Times New Roman,Times"
size=2>easily reprogrammed </FONT></TD>
<TD vAlign=top width="19%"><FONT face="Times New Roman,Times"
size=2>10,000 times</FONT></TD></TR>
<TR>
<TD vAlign=top width="23%"><FONT face="Times New Roman,Times" size=2>Flash
</FONT></TD>
<TD vAlign=top width="25%"><FONT face="Times New Roman,Times"
size=2>nonvolatile </FONT></TD>
<TD vAlign=top width="33%"><FONT face="Times New Roman,Times"
size=2>easily reprogrammed </FONT></TD>
<TD vAlign=top width="19%"><FONT face="Times New Roman,Times" size=2>100
times</FONT></TD></TR>
<TR>
<TD vAlign=top width="23%"><FONT face="Times New Roman,Times" size=2>OTP
PROM</FONT></TD>
<TD vAlign=top width="25%"><FONT face="Times New Roman,Times"
size=2>nonvolatile </FONT></TD>
<TD vAlign=top width="33%"><FONT face="Times New Roman,Times" size=2>can
be easily programmed </FONT></TD>
<TD vAlign=top width="19%"><FONT face="Times New Roman,Times"
size=2>once</FONT></TD></TR>
<TR>
<TD vAlign=top width="23%"><FONT face="Times New Roman,Times"
size=2>ROM</FONT></TD>
<TD vAlign=top width="25%"><FONT face="Times New Roman,Times"
size=2>nonvolatile </FONT></TD>
<TD vAlign=top width="33%"><FONT face="Times New Roman,Times"
size=2>programmed at the factory</FONT></TD>
<TD vAlign=top width="19%"><FONT face="Times New Roman,Times"
size=2>once</FONT></TD></TR></TBODY></TABLE></P>
<ADDRESS><FONT face="Times New Roman,Times">Table 7-1: Various types of memory
available for the 6811 and 6812. </FONT></ADDRESS>
<P> </P>
<P><FONT face="Times New Roman,Times">From a logical standpoint we define
implement segmentation when we group together in memory information that has
similar properties or usage. Typical software segments include global variables
(<B>data section</B>), the heap, local variables, fixed constants (<B>idata
section</B>), and machine instructions (<B>text section</B>). Global variables
are permanently allocated and usually accessible by more than one program. We
must use global variables for information that must be permanently available, or
for information that is to be shared by more than one module. We will see the
first-in-first-out (FIFO) queue is a global data structure that is shared by
more than one module. Imagecraft and Hiware both allow the use of a heap to
dynamically allocate and release memory. This information can be shared or not
shared depending on which modules have pointers to the data. The heap is
efficient in situations where storage is needed for only a limited amount of
time. Local variables are usually allocated on the stack at the beginning of the
function, used within the function, and deallocated at the end of the function.
Local variables are not shared with other modules. Fixed constants do not change
and include information such as numbers, strings, sounds and pictures. Just like
the heap the fixed constants can be shared or not shared depending on which
modules have pointers to the data. </FONT></P>
<P><FONT face="Times New Roman,Times">In an embedded application, we usually put
global variables, the heap, and local variables in RAM because these types of
information can change during execution. When software is to be executed on a
regular computer, the machine instructions are usually read from a mass storage
device (like a disk) and loaded into memory. Because the embedded system usually
has no mass storage device, the machine instructions and fixed constants must be
stored in nonvolatile memory. If there is both EEPROM and ROM on our
microcomputer, we put some fixed constants in EEPROM and some in ROM. If it is
information that we may wish to change in the future, we could put it in EEPROM.
Examples include language-specific strings, calibration constants, finite state
machines, and system ID numbers. This allows us to make minor modifications to
the system by reprogramming the EEPROM without throwing the chip away. If our
project involves producing a small number of devices then the program can be
placed in EPROM or EEPROM. For a project with a large volume it will be cost
effective to place the machine instructions in ROM. </FONT></P>
<P> </P>
<P><B><I><FONT face=Helvetica,Arial><A name=MATH></A>Pointer
Arithmetic</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">A major difference between addresses and
ordinary variables or constants has to do with the interpretation of addresses.
Since an address points to an object of some particular type, adding one (for
instance) to an address should direct it to the next object, not necessarily the
next byte. If the address points to integers, then it should end up pointing to
the next integer. But, since integers occupy two bytes, adding one to an integer
address must actually increase the address by two. Likewise, if the address
points to long integers, then adding one to an address should end up pointing to
the next long integer by increasing the address by four. A similar consideration
applies to subtraction. In other words, values added to or subtracted from an
address must be scaled according to the size of the objects being addressed.
This automatic correction saves the programmer a lot of thought and makes
programs less complex since the scaling need not be coded explicitly. The
scaling factor for long integers is four; the scaling factor for integers is
two; the scaling factor for characters is one. Therefore, character addresses do
not receive special handling. It should be obvious that when define structures
(see </FONT><A
href="http://www.ece.utexas.edu/~valvano/embed/chap9/chap9.htm">Chapter
9</A><FONT face="Times New Roman,Times">) of other sizes, the appropriate
factors would have to be used.</FONT></P>
<P><FONT face="Times New Roman,Times">A related consideration arises when we
imagine the meaning of the difference of two addresses. Such a result is
interpreted as the number of objects between the two addresses. If the objects
are integers, the result must be divided by two in order to yield a value which
is consistent with this meaning. See <A
href="http://www.ece.utexas.edu/~valvano/embed/chap8/chap8.htm">Chapter 8</A>
for more on address arithmetic.</FONT></P>
<P><FONT face="Times New Roman,Times">When an address is operated on, the result
is always another address of the same type. Thus, if <B>ptr</B> is a signed
16-bit integer pointer, then <B>ptr+1</B> is also points to a signed 16-bit
integer. </FONT></P>
<P><FONT face="Times New Roman,Times">Precedence determines the order of
evaluation. <A
href="http://www.ece.utexas.edu/~valvano/embed/chap1/chap1.htm#PRECEDENCE">See a
table of precedence.</A> One of the most common mistakes results when the
programmer meglects the fact the<B> * </B>used as a unary pointer reference has
precedence over all binary operators. This means the expression<B> *ptr+1</B> is
the same as <B>(*ptr)+1</B> and not <B>*(ptr+1)</B>. This is an important point
so I'll mention it again,<I> "When confused about precedence (and aren't we all)
add parentheses to clarify the expression."</I> </FONT></P>
<P> </P>
<P><B><I><FONT face=Helvetica,Arial><A name=COMPARE></A>Pointer
Comparisons</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">One major difference between pointers and
other variables is that pointers are always considered to be unsigned. This
should be obvious since memory addresses are not signed. This property of
pointers (actually all addresses) ensures that only unsigned operations will be
performed on them. It further means that the other operand in a binary operation
will also be regarded as unsigned (whether or not it actually is). In the
following example, <B>pt1</B> and <B>pt2</B>[5] return the current values of the
addresses. For instance, if the array <B>pt2</B>[] contains addresses, then it
would make sense to write</FONT></P>
<P> </P>
<DIR>
<P><CODE>short *pt1; /* define 16-bit integer
pointer */<BR>short *pt2[10]; /* define ten 16-bit integer pointers
*/<B><BR></B>short done(void){ /* returns true if pt1 is higher than
pt2[5] */<BR> if(pt1>pt2[5]) return(1);
<BR> return(0);<BR>}</CODE></P></DIR>
<ADDRESS><FONT face="Times New Roman,Times">Listing 7-2: Example showing a
pointer comparisons</FONT></ADDRESS>
<P> </P>
<P><FONT face="Times New Roman,Times">which performs an unsigned comparison
since pt1 and pt2 are pointers. Thus, if pt2[5] contains 0xF000 and pt1 contains
0x1000, the expression will yield true, since 0xF000 is a higher unsigned value
than 0x1000. </FONT></P>
<P><FONT face="Times New Roman,Times">It makes no sense to compare a pointer to
anything but another address or zero. C guarantees that valid addresses can
never be zero, so that particular value is useful in representing the absence of
an address in a pointer.</FONT></P>
<P><FONT face="Times New Roman,Times">Furthermore, to avoid portability
problems, only addresses within a single array should be compared for relative
value (e.g., which pointer is larger). To do otherwise would necessarily involve
assumptions about how the compiler organizes memory. Comparisons for equality,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -