




































Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Community
Ask the community for help and clear up your study doubts
Discover the best universities in your country according to Docsity users
Free resources
Download our free guides on studying techniques, anxiety management strategies, and thesis advice from Docsity tutors
This lecture handout contains some important points related Microcontroller. It was given by Prof. Siddanth Dheer at Tata Institute of Social Science. It includes: Microcontroller, Assembly, Language, Programming, Compiler, Output, Files, Directives, Memory, Area
Typology: Lecture notes
1 / 44
This page cannot be seen from the preview
Don't miss anything!
C51 generates a number of output files during compilation. By default, each of these output files shares the same basename , as the source file. However, each has a different file extension. The following table lists the files and gives a brief description of each.
File Extension Description
basename .LST Files with this extension are listing files that contain the formatted source text along with any errors detected by the compiler. Listing files may optionally contain the symbols used and the generated assembly code. See the PRINT directive in the following sections for more information.
Basename .OBJ Files with this extension are object modules that contain relocatable object code. The Linker/Locator may link object modules to an absolute object module.
Basename .I Files with this extension contain the source text as expanded by the preprocessor. All macros are expanded and all comments are deleted in this listing. See the PREPRINT directive in the following sections for more information.
Basename .SRC Files with this extension are assembly source files generated from your C source code. These files can be assembled with the A51 assembler. See the SRC directive in the following sections for more information.
The Compiler offers a number of control directives that you can use to control the compiler’s operation. Directives are composed of one or more letters or digits and, unless otherwise specified, can be specified compiler options of your project or within a source file using the #pragma directive. For example: pragma SYMBOLS CODE DEBUG
In the above example, SYMBOLS, CODE, and DEBUG are all control directives.
NOTES Multiple options may be specified on the #pragma line.
Typically, each control directive may be specified only once at the beginning of a source file. If a directive is specified more than once, the compiler generates a fatal error and aborts compilation.
Directives that may be specified more than once are so noted in the following sections.
space within the computer. Refer to the Intel 8 - Bit Embedded Controllers handbook or other 8051 data books for more information about the 8051 memory architecture.
Program Memory
Internal Data Memory
External Data Memory
Special Function Register Memory
Program memory can be read only. It cannot be written to. Program memory may reside within the 8051 CPU, or it may be external, or it may be both, depending upon the 8051 derivative and the hardware design. There may be up to 64 KBytes of program memory. Program code including all functions and library routines are stored in program memory. Constant variables may be stored in program memory, as well. The 8051 executes programs stored in program memory only.
Program memory can be accessed by using the code memory type specifier in C51.
Internal Data Memory
Internal data memory resides within the 8051 CPU and can be read and written. Up to 256 bytes of internal data memory are available depending on the 8051 derivative. The first 128 bytes of internal data memory are both directly addressable and indirectly addressable. The upper 128 bytes of data memory (from 0x80 to 0xFF) can be addressed only indirectly. There is also a 16 byte area starting at 20h that is bit-addressable.
Access to internal data memory is very fast because it can be accessed using an 8-bit address. However, internal data memory is limited to a maximum of 256 bytes.
Internal data can be broken down into three distinct data types when using C51: data , idata , and bdata.
The data memory specifier always refers to the first 128 bytes of internal data memory. Variables stored here are accessed using direct addressing.
The idata memory specifier refers to all 256 bytes of internal data memory; however, this memory type specifier code is generated by indirect addressing which is slower than direct addressing.
The bdata memory specifier refers to the 16 bytes of bit-addressable memory in the internal data area (20h to 2Fh). This memory type specifier allows you to declare data types that can also be accessed at the bit-level.
External Data Memory
External data memory can be read and written and is physically located external to the 8051 CPU. Access to external data is very slow when compared to access to internal data. This is because external data memory is accessed indirectly through the data pointer ( DPTR ) register which must be loaded with a 16-bit address before accessing the external memory.
There may be up to 64 KBytes of external data memory; though, this address space does not necessarily have to be used as memory. Your hardware design may map peripheral devices into the memory space. If this is the case, your program would access external data memory to program and control the peripheral. This technique is referred to as memory-mapped I/O.
There are two different data types in C51 with which you may access external data: xdata and pdata.
The xdata memory specifier refers to any location in the 64 KByte address space of external data memory.
The pdata memory type specifier refers to only 1 page or 256 bytes of external data memory. See the “Compact Model” section under “Memory Models” later in this chapter for more information on pdata.
Special Function Register Memory
The 8051 also provides 128 bytes of memory for Special Function Registers (SFRs). SFRs are bit, byte, or word sized registers that are used to control timers, counters, serial I/O, port I/O, and peripherals. Refer to the “Special Function Registers” section for more information on SFRs.
The memory model determines the default memory type to be used for function arguments, automatic variables, and declarations with no explicit memory type specifier. You specify the memory model in the C51 options window in the project window using the SMALL , COMPACT , and LARGE control directives. Refer to the “Control Directives” section in the “Compiling with C51” chapter for more information about these directives.
NOTE Except in very special selected applications, you should always use the default SMALL memory model. It will generate the fastest most efficient code.
This type of data access mechanism generates more code than the small or compact models.
The C51 compiler explicitly supports the architecture of the 8051 and its derivatives and provides access to all memory areas of the 8051. Each variable may be explicitly assigned to a specific memory space.
Accessing the internal data memory is considerably faster than accessing the external data memory. For this reason, place frequently used variables in internal data memory. Place larger, less frequently used variables in external data memory.
Explicitly Declared Memory Types
Implicit Memory Types
Explicitly Declared Memory Types
By including a memory type specifier in the variable declaration, you may specify where variables are stored. The following table summarizes the available memory type specifiers.
Memory Type
Description
code program memory (64 KBytes); accessed by opcode MOVC @A+DPTR
data directly addressable internal data memory; fastest access to variables ( bytes)
idata indirectly addressable internal data memory; accessed across the full internal address space (256 bytes)
bdata bit-addressable internal data memory; allows mixed bit and byte access ( bytes)
xdata external data memory (64 KBytes); accessed by opcode MOVX @DPTR
pdata paged (256 bytes) external data memory; accessed by opcode MOVX @R n
As with the signed and unsigned attributes, you may include memory type specifiers in the variable declaration. For example: char data var1;
char code text[] = "ENTER PARAMETER:";
unsigned long xdata array[100];
float idata x,y,z;
unsigned int pdata dimension;
unsigned char xdata vector[10][4][4];
char bdata flags;
NOTE C51 allows you to specify the memory type even before the type declarator. For this reason, the declaration data char x; is equivalent to the declaration char data x.
Implicit Memory Types
If the memory type specifier is omitted in a variable declaration, the default or implicit memory type is automatically selected. Function arguments and automatic variables which cannot be located in registers are also stored in the default memory area.
The default memory type is determined by the SMALL , COMPACT and LARGE compiler control directives. (See the “Memory Models” section above.)
C51 provides you with a number of basic data types to use in your C programs. C offers you the standard C data types and also supports several data types that are unique to the 8051 platform. The following table lists the data types available in C51.
Data Type Bits Bytes Value Range
bit † 1 0 to 1
signed char 8 1 -128 to +
unsigned char 8 1 0 to 255
enum 16 2 -32768 to +
signed short 16 2 -32768 to +
unsigned short 16 2 0 to 65535
signed int 16 2 -32768 to +
unsigned int 16 2 0 to 65535
signed long 32 4 -2147483648 to 2147483647
unsigned long 32 4 0 to 4294967295
float 32 4 ±1.175494E-38 to ±3.402823E+
sbit † 1 0 to 1
sfr † 8 1 0 to 255
sfr16 † 16 2 0 to 65535
Bit-addressable objects are objects which can be addressed as bytes or as bits. Only data objects that occupy the bit-addressable area of the 8051 internal memory fall into this category. The C51 compiler places variables declared with the bdata memory type into this bit-addressable area. You may declare these variables as shown below: int bdata ibase; /* Bit-addressable int */
char bdata bary [4]; /* Bit-addressable array / The variables ibase and bary are bit-addressable. Therefore, the individual bits of these variables may be directly accessed and modified. To do this, use the sbit keyword to declare new variables that access the bits of variables declared using bdata. For example: sbit mybit0 = ibase ^ 0; / bit 0 of ibase / sbit mybit15 = ibase ^ 15; / bit 15 of ibase */
sbit Ary07 = bary[0] ^ 7; /* bit 7 of bary[0] / sbit Ary37 = bary[3] ^ 7; / bit 7 of bary[3] */
The above example represents declarations, not assignments to the bits of the ibase and bary variables declared above. The expression following the carat symbol ( ^ ) in the example, specifies the position of the bit to access with this declaration. This expression must be a constant value. The range depends on the type of the base variable included in the declaration. The range is 0 to 7 for char and unsigned char , 0 to 15 for int , unsigned int , short , and unsigned short , and 0 to 31 for long and unsigned long.
You may provide external variable declarations for the sbit type to access these types in other modules. For example: extern bit mybit0; /* bit 0 of ibase / extern bit mybit15 / bit 15 of ibase */
extern bit Ary07; /* bit 7 of bary[0] / extern bit Ary37; / bit 7 of bary[3] */
Declarations involving the sbit type require that the base object be declared with the memory type bdata. The only exception to this are the variants for special function bits as discussed in the section entitled “Special Function Registers” later in this chapter.
The following example shows how to change the bits of ibase and bary using the above declarations. Ary37 = 0; /* clear bit 7 in bary[3] / bary[3] = 'a'; / Byte addressing / ibase = -1; / Word addressing / mybit15 = 1; / set bit 15 ibase */
The bdata memory type is handled like the data memory type except that variables declared with bdata reside in the bit-addressable portion of the internal data memory. Note that the total size of this area of memory may not exceed 16 bytes.
In addition to declaring sbit variables for scalar types, you may also declare sbit variables for structures and unions. For example: union lft { float mf; long ml; };
bdata struct bad { char m1; union lft u; } tcp;
sbit tcpf31 = tcp.u.ml ^ 31; /* bit 31 of float */ sbit tcpm10 = tcp.m1 ^ 0; sbit tcpm17 = tcp.m1 ^ 7;
NOTES You may not specify bit variables for the bit positions of a float. However, you may include the float and a long in a union. Then, you may declare bit variables to access the bits in the long type.
The sbit data type uses the specified variable as a base address and adds the bit position to obtain a physical bit address. Physical bit addresses are not equivalent to logical bit positions for certain data types. Physical bit position 0 refers to bit position 0 of the first byte. Physical bit position 8 refers to bit position 0 of the second byte. Since int variables are stored high-byte first, bit 0 of the integer is located in bit position 0 of the second byte. This is physical bit position 8 when accessed using an sbit data type.
The 8051 family of microprocessors provides a distinct memory area for accessing Special Function Registers (SFRs). SFRs are used in your program to control timers, counters, serial I/Os, port I/Os, and peripherals. SFRs reside from address 0x80 to 0xFF and can be accessed as bits, bytes, and words. For more information about special function registers, refer to the Intel 8 - Bit Embedded Controllers handbook or other 8051 data books.
Within the 8051 family, the number and type of SFRs vary. Note that no SFR names are predefined by the C51 compiler. However, declarations for SFRs are provided in include files.
C51 provides a number of include files for various 8051 derivatives. Each file contains declarations for the SFRs available on that derivative. See the section entitled, “
With typical 8051 applications, it is often necessary to access individual bits within an SFR. The C51 compiler makes this possible with the sbit data type. The sbit data type allows you to access bit-addressable SFRs. For example: sbit EA = 0xAF;
This declaration defines EA to be the SFR bit at address 0xAF. On the 8051, this is the enable all bit in the interrupt enable register.
NOTE Not all SFRs are bit-addressable. Only those SFRs whose address is evenly divisible by 8 are bit-addressable. These SFR’s lower nibble will be either 0 or 8; for example, SFRs at 0xA8 and 0xD0 are bit-addressable, whereas SFRs at 0xC7 and 0xEB are not. SFR bit addresses are easy to calculate. Add the bit position to the SFR byte address to get the SFR bit address. So, to access bit 6 in the SFR at 0xC8, the SFR bit address would be 0xCE (0xC8 + 6).
Any symbolic name can be used in an sbit declaration. The expression to the right of the equal sign ( = ) specifies an absolute bit address for the symbolic name. There are three variants for specifying the address.
Variant 1 : sfr_name ^ int_constant
This variant uses a previously-declared sfr ( sfr_name ) as the base address for the sbit. The address of the existing SFR must be evenly divisible by 8. The expression following the carat symbol ( ^ ) specifies the position of the bit to access with this declaration. The bit position must be a number in the range 0 to 7. For example: sfr PSW = 0xD0; sfr IE = 0xA8;
sbit OV = PSW ^ 2; sbit CY = PSW ^ 7;
sbit EA = IE ^ 7;
Variant 2 : int_constant ^ int_constant
This variant uses an integer constant as the base address for the sbit. The base address value must be evenly divisible by 8. The expression following the carat symbol ( ^ ) specifies the position of the bit to access with this declaration. The bit position must be a number in the range 0 to 7. For example: sbit OV = 0xD0 ^ 2; sbit CY = 0xD0 ^ 7;
sbit EA = 0xA8 ^ 7;
Variant 3 : int_constant
This variant uses an absolute bit address for the sbit. For example: sbit OV = 0xD2; sbit CY = 0xD7;
sbit EA = 0xAF;
NOTES Special function bits represent an independent declaration class that may not be interchanged with other bit declarations or bit fields.
The sbit data type declaration may be used to access individual bits of variables declared with the bdata memory type specifier. See the section entitled “Bit-Addressable Objects” in this chapter.
Absolute Variable Location
Variables may be located at absolute memory locations in your C program source modules using the at keyword. The usage for this feature is:
type ¤ memory_space ¥ variable_name at constant ; where:
type is the type of the variable.
memory_space is the memory space for the variable.
variable_name is the name of the variable.
constant is the address at which to locate the variable.
If memory_space is missing from the declaration, the default memory space is used.
The absolute address following at must conform to the physical boundaries of the memory space for the variable. C51 checks for invalid address specifications.
The following restrictions apply to absolute variable location:
The following example demonstrates how to locate several different variable types using the at keyword.
struct link { struct link idata *next;
Untyped pointers may be used to access any variable regardless of its location in 8051 memory space. Many of the C51 library routines use these pointer types for this reason. By using these generic untyped pointers, a function can access data regardless of the memory in which it is stored.
NOTE The code generated for an untyped pointer will execute more slowly than the equivalent code generated for a typed pointer. This is because the memory area is not known until run-time. The compiler cannot optimize memory accesses and must generate generic code that can access any memory area. If execution speed is a priority, you should use typed pointers instead of untyped pointers wherever possible.
The following code and assembly listing shows the values assigned to untyped pointers for variables in different memory areas. Note that the first value is the memory space followed by the high-order byte and low-order byte of the address.
. . . stmt level source 1 char c_ptr; / char ptr */ 2 int i_ptr; / int ptr */ 3 long l_ptr; / long ptr / 4 5 void main (void) 6 { 7 1 char data dj; / data vars / 8 1 int data dk; 9 1 long data dl; 10 1 11 1 char xdata xj; / xdata vars / 12 1 int xdata xk; 13 1 long xdata xl; 14 1 15 1 char code cj = 9; / code vars / 16 1 int code ck = 357; 17 1 long code cl = 123456789; 18 1 19 1 20 1 c_ptr = &dj; / data ptrs / 21 1 i_ptr = &dk; 22 1 l_ptr = &dl; 23 1 24 1 c_ptr = &xj; / xdata ptrs */ 25 1 i_ptr = &xk; 26 1 l_ptr = &xl;
28 1 c_ptr = &cj; /* code ptrs */ 29 1 i_ptr = &ck; 30 1 l_ptr = &cl; 31 1 } . . . ASSEMBLY LISTING OF GENERATED OBJECT CODE
; FUNCTION main (BEGIN) ; SOURCE LINE # 5 ; SOURCE LINE # 6 ; SOURCE LINE # 20 0000 750004 R MOV c_ptr,#04H 0003 750000 R MOV c_ptr+01H,#HIGH dj 0006 750000 R MOV c_ptr+02H,#LOW dj ; SOURCE LINE # 21 0009 750004 R MOV i_ptr,#04H 000C 750000 R MOV i_ptr+01H,#HIGH dk 000F 750000 R MOV i_ptr+02H,#LOW dk ; SOURCE LINE # 22 0012 750004 R MOV l_ptr,#04H 0015 750000 R MOV l_ptr+01H,#HIGH dl 0018 750000 R MOV l_ptr+02H,#LOW dl ; SOURCE LINE # 24 001B 750002 R MOV c_ptr,#02H 001E 750000 R MOV c_ptr+01H,#HIGH xj 0021 750000 R MOV c_ptr+02H,#LOW xj ; SOURCE LINE # 25 0024 750002 R MOV i_ptr,#02H 0027 750000 R MOV i_ptr+01H,#HIGH xk 002A 750000 R MOV i_ptr+02H,#LOW xk ; SOURCE LINE # 26 002D 750002 R MOV l_ptr,#02H 0030 750000 R MOV l_ptr+01H,#HIGH xl 0033 750000 R MOV l_ptr+02H,#LOW xl ; SOURCE LINE # 28 0036 750005 R MOV c_ptr,#05H 0039 750000 R MOV c_ptr+01H,#HIGH cj 003C 750000 R MOV c_ptr+02H,#LOW cj ; SOURCE LINE # 29 003F 750005 R MOV i_ptr,#05H 0042 750000 R MOV i_ptr+01H,#HIGH ck 0045 750000 R MOV i_ptr+02H,#LOW ck
Typed pointers may be used to access variables in the declared 8051 memory area only. Typed pointers provide the most efficient method of accessing data objects, but at the cost of reduced flexibility.
The following code and assembly listing shows how pointer values are assigned to typed pointers. Note that the code generated for these pointers is much less involved than the code generated in the untyped pointers example listing in the previous section.
. . . stmt level source 1 char data c_ptr; / typed char ptr */ 2 int xdata i_ptr; / typed int ptr */ 3 long code l_ptr; / typed long ptr */ 4 5 long code powers_of_ten [] = 6 { 7 1L, 8 10L, 9 100L, 10 1000L, 11 10000L, 12 100000L, 13 1000000L, 14 10000000L, 15 100000000L 16 }; 17 18 void main (void) 19 { 20 1 char data strbuf [10]; 21 1 int xdata ringbuf [1000]; 22 1 23 1 c_ptr = &strbuf [0]; 24 1 i_ptr = &ringbuf [0]; 25 1 l_ptr = &powers_of_ten [0]; 26 1 } . . . ASSEMBLY LISTING OF GENERATED OBJECT CODE
; FUNCTION main (BEGIN) ; SOURCE LINE # 18
0000 750000 R MOV c_ptr,#LOW strbuf ; SOURCE LINE # 24 0003 750000 R MOV i_ptr,#HIGH ringbuf 0006 750000 R MOV i_ptr+01H,#LOW ringbuf ; SOURCE LINE # 25 0009 750000 R MOV l_ptr,#HIGH powers_of_ten 000C 750000 R MOV l_ptr+01H,#LOW powers_of_ten ; SOURCE LINE # 26 000F 22 RET ; FUNCTION main (END) . . .
Pointer Conversions
C51 can convert between typed pointers and untyped pointers. Pointer conversions can be forced by explicit program code using type casts or can be coerced by the compiler.
The C51 compiler coerces a typed pointer into an untyped pointer when the typed pointer is passed as an argument to a function which requires an untyped pointer. This is the case for functions such as printf , sprintf , and gets which use untyped pointers as arguments. For example: extern int printf ( void *format, ...);
extern int myfunc ( void code *p, int xdata *pq);
int xdata *px; char code *fmt = "value = %d | %04XH\n";
void debug_print (void) { printf (fmt, *px, px); / fmt is converted / myfunc (fmt, px); / no conversions */ }
In the call to printf , the argument fmt which represents a 2-byte code pointer is automatically converted or coerced into a 3-byte untyped pointer. This is done because the prototype for printf requires an untyped pointer as the first argument.