MODULE 3_programming in C_lecture Notes (2)
MODULE 3_programming in C_lecture Notes (2)
MODULE 3
Programming In C
Why program the 8051 in C?
Compilers produce hex files that we download into the ROM of the microcontroller. The size of
the hex file produced by the compiler is one of the main concerns of microcontroller
programmers, for two reasons:
How does the choice of programming language affect the compiled program size? While
Assembly language produces a hex file that is much smaller than C, programming in Assembly
language is tedious and time consuming. C programming, on the other hand, is less time
consuming and much easier to write, but the hex file size produced is much larger than if we used
Assembly language. The following are some of the major reasons for writing programs in C
instead of Assembly:
The study of C programming for the 8051 is the main topic of this chapter. In Section 7.1,
we discuss data types and time delays. I/O programming is shown in Section 7.2. The
logic operations AND, OR, XOR, inverter, and shift are discussed in Section 7.3. Section
7.4 describes ASCII and BCD conversions and checksums. In Section 7.5 we show how
8051 C compilers use the program (code) ROM space for data. Finally, in Section 7.6
data serialization for 8051 is shown.
In this section we first discuss C data types for the 8051 and then provide code for time
delay functions.
Since one of the goals of 8051 C programmers is to create smaller hex files, it is
worthwhile to re-examine C data types for 8051 C. In other words, a good understanding
of C data types for the 8051 can help programmers to create smaller hex files. In this
section we focus on the specific C data types that are most useful and widely used for the
8051 microcontroller.
Unsigned char
Since the 8051 is an 8-bit microcontroller, the character data type is the most natural
choice for many applications. The unsigned char is an 8-bit data type that takes a value in
the range of 0 – 255 (00 – FFH). It is one of the most widely used data types for the 8051.
In many situations, such as setting a counter value.
where there is no need for signed data we should use the unsigned char instead of the signed char.
Remember that C compilers use the signed char as the default if we do not put the keyword
unsigned in front of the char (see Example 7-1). We can also use the unsigned char data type for a
string of ASCII characters, including extended ASCII characters.
In declaring variables, we must pay careful attention to the size of the data and try to use
unsigned char instead of int if possible. Because the 8051 has a limited number of registers and
data RAM locations, using the int in place of the char data type can lead to a larger size hex file.
Such a misuse of the data types in compilers such as Microsoft Visual C++ for x86 IBM PCs is
not a significant issue.
Example
Example
Run the above program on your simulator to see how PI displays values 30H, 31H, 32H. 33H.
34H. 35H. 41H. 42H, 43H, and 44H, the hex values for ASCII 0, 1, 2, and so on.
Example
Run the above program on your simulator to see how PI toggles continuously. Examine the asm
code generated by the C compiler.
Signed char
The signed char is an 8-bit data type that uses the most significant bit (D7 of D7 – DO) to
represent the – or + value. As a result, we have only 7 bits for the magnitude of the signed
number, giving us values from -128 to +127. In situations where + and – are needed to represent a
given quantity such as temperature, the use of the signed char data type is a must.
Again notice that if we do not use the keyword unsigned, the default is the signed value. For that
reason we should stick with the unsigned char unless the data needs to be represented as signed
numbers.
Example
Run the above program on your simulator to see how PI displays values of 1, FFH, 2, FEH, 3,
FDH, 4, and FCH, the hex values for +!,-!, +2, -2, and so on.
Unsigned int
The unsigned int is a 16-bit data type that takes a value in the range of 0 to 65535 (0000 –
FFFFH). In the 8051, unsigned int is used to define 16-bit variables such as memory addresses. It
is also used to set counter values of more than 256. Since the 8051 is an 8-bit microcontroller and
the int data type takes two bytes of RAM, we must not use the int data type unless we have to.
Since registers and memory accesses are in 8-bit chunks, the misuse of int variables will result in
a larger hex file. Such misuse is not a big deal in PCs with 256 megabytes of memory, 32-bit
Pentium registers and memory accesses, and a bus speed of 133 MHz. However, for 8051
programming do not use unsigned int in places where unsigned char will do the job. Of course the
compiler will not generate an error for this misuse, but the overhead in hex file size is noticeable.
Also in situations where there is no need for signed data (such as setting counter values), we
should use unsigned int instead of signed int. This gives a much wider range for data declaration.
Again, remember that the C compiler uses signed int as the default if we do not use the keyword
unsigned.
Signed int
Signed int is a 16-bit data type that uses the most significant bit (015 of D15 – DO) to represent
the – or + value. As a result, we have only 15 bits for the magnitude of the number, or values
from -32,768 to +32,767.
The sbit keyword is a widely used 8051 C data type designed specifically to access single-bit
addressable registers. It allows access to the single bits of the SFR registers. As we saw in
Chapter 5, some of the SFRs are bit^addressable. Among the SFRs that are widely used and are
also bit-addressable are ports PO -P3.
Example
Write an 8051 C program to toggle bit DO of the port PI (Pl.O) 50,000 times.
The bit data type allows access to single bits of bit-addressable memory spaces 20 – 2FH. Notice
that while the sbit data type is used for bit-addressable SFRs, the bit data type is used for the bit-
addressable section of RAM space 20 -2FH. To access the byte-size SFR registers, we use the sfr
data type. We will see the use of sbit, bit, and sfr data types in the next section.
Time Delay
In either case, when we write a time delay we must use the oscilloscope to measure the duration
of our time delay. Next, we use the for loop to create time delays. Discussion of the use of the
8051 timer to create time delays is postponed until Chapter 9.
In creating a time delay using a for loop, we must be mindful of three factors that can affect the
accuracy of the delay.
1. The 8051 design. Since the original 8051 was designed in 1980, both the fields of 1C
technology and microprocessor architectural design have seen great advancements. As
we saw in Chapter 3, the number of machine cycles and the number of clock periods per
machine cycle vary among different versions ofthe 8051/52 microcontroller. While the
original 8051/52 design used 12 clock
periods per machine cycle, many of the newer generations of the 8051 use fewer clocks
per machine cycle. For example, the DS5000 uses 4 clock peri ods per machine cycle,
while the DS89C420 uses only one clock per machine cycle.
2. The crystal frequency connected to the XI – X2 input pins. The duration of the clock
period for the machine cycle is a function of this crystal frequency.
3. Compiler choice. The third factor that affects the time delay is the compiler
used to compile the C program. When we program in Assembly language, we can control
the exact instructions and their sequences used in the delay sub routine. In the case of C
programs, it is the C compiler that converts the C statements and functions to Assembly
language instructions. As a result, different compilers produce different code. In other
words, if we compile a given 8051 C programs with different compilers, each compiler
produces different
hex code.
For the above reasons, when we write time delays for C, we must use the oscilloscope to measure
the exact duration.
Example Write an 8051 C program to toggle bits of PI continuously forever with some delay.
Solution:
// Toggle PI forever with some delay in between “on” and “off”, ^include <reg51.h>
Example
Write an 8051 C program to toggle the bits of PI ports continuously with a 250 ms
delay.
Solution:
The program below is tested for the DS89C420 with XTAL = 11.0592 MHz.
Example
In this section we look at C programming of the I/O ports for the 8051. We look at both byte and
bit I/O programming.
Example LEDs are connected to bits PI and P2. Write an 8051 C program that shows the count
from 0 to FFH (0000 0000 to 1111 1111 in binary) on the LEDs.
Solution:
Example
Write an 8051 C program to get a byte of data from PI, wait 1/2 second, and then send it to P2.
Solution:
Example
Write an 8051 C program to get a byte of data from PO. If it is less than 100, send it to
Solution:
The I/O ports of PO – P3 are bit-addressable. We can access a single bit without disturbing the
rest of the port. We use the sbit data type to access a single bit of PO – P3′. One way to do that is
to use the PxAy format where x is the port 0, 1, 2, or 3, and y is the bit 0 – 7 of that port. For
example, P1A7 indicates PI.7. When using this method, you need to include the reg51 .h file.
Study the next few examples to become familiar with the syntax.
Example
Write an 8051 C program to toggle only bit P2.4 continuously without disturbing the rest of the
bits of P2.
Solution:
Example Write an 8051 C program to monitor bit PI.5. If it is high, send 55H to PO; otherwise,
sendAAHtoP2.
Solution:
Example A door sensor is connected to the P 1.1 pin, and a buzzer is connected to PI.7. Write an
8051 C program to monitor the door sensor, and when it opens, sound the buzzer. You can sound
the buzzer by sending a square wave of a few hundred Hz.
Solution:
Example The data pins of an LCD are connected to PI. The information is latched into the LCD
whenever its Enable pin goes from high to low. Write an 8051 C program to send “The Earth is
but One Country” to this LCD.
Solution:
Run the above program on your simulator to see how PI displays each character of the message.
Meanwhile, monitor bit P2.0 after each character is issued.
Another way to access the SFR RAM space 80 – FFH is to use the sfr data type. This is
shown in Example 7-16. We can also access a single bit of any SFR if we specify the bit address
as shown in Example 7-17. Both the bit and byte addresses for the PO – P3 ports are given in
Table 7-2. Notice in Examples 7-16 and 7-17, that there is no ^include <reg51.h> statement. This
allows us to access any byte of the SFR RAM space 80 – FFH. This is a method widely used for
the new generation of 8051 microcontrollers, and we will use it in future chapters.
Example
Write an 8051 C program to toggle all the bits of PO, PI, and P2 continuously with a
250 ms delay.’ Use the sfr keyword to declare the port addresses.
Example
Solution:
The sbit data type is used for bit-addressable SFR registers only. Sometimes we need to store
some data in a bit-addressable section of the data RAM space 20 – 2FH.
Example Write an 8051 C program to get the status of bit Pl.O, save it, and send it to P2.7
continuously.
Solution:
In Chapter 7, we showed how to place fixed data into the code space using 8051 C. In that
chapter we also showed how to access fixed data stored in the code space of the 8051 family. In
this section we show how to access the external data space of the 8051 family using C language.
To access the external data space (RAM or ROM) of the 8051 using C, we use XBYTE[loc]
where loc is an address in the range of 0000 – FFFFH. Example 14-18 shows how to write some
data to external RAM addresses starting at 0. Notice that the XBYTE function is part of the
absacc.h header file. Examine Examples 14-19 and 14-20 to gain some mastery of accessing
external data memory using C.
In Section 14.4 we discussed how to access the 1KB SRAM of the DS89C4xO chip using
Assembly language. Examples 14-21 and 14-22 will show the 8051 C version of some of
the Assembly programs.
Example
Write a C program (a) to store ASCII letters ‘A’ to ‘E’ in external RAM addresses starting at 0,
then (b) get the same data from the external RAM and send it to PI one byte at a time.
Solution:
Run the above program on your 8051 simulator and examine the contents of xdata to verify the
result.
Example
An external ROM uses the 8051 data space to store the look-up table (starting at 100H) for DAC
data. Write a C program to read 30 bytes of table data and send it to PI.
Solution:
Example
Assume that we have an external RAM with addresses 0000 – 2FFFH for a given 8051-based
system, (a) Write a C program to move the message “Hello” into external RAM, and (b) read the
same data in external RAM, and send it to the serial port.
Solution:
Example
Write a C program (a) to enable the access to the 1KB SRAM of the DS89C4xO, (b) put the
ASCII letters ‘A’, ‘B’ and ‘C’ in SRAM, and (c) read the same data from SRAM and send each
one to ports PO, PI, and P2. This is the C version of an earlier example.
Solution:
Example
Write a C program to (a) enable access to the 1KB SRAM of the DS89C4xO, (b) move a block of
data from the code space of the DS89C420 chip into 1KB SRAM, then (c) read the same data
from SRAM and send it to the serial port of the 8051 one byte at a time.
Solution:
SUMMARY
This chapter described memory interfacing with 8031/51-based systems. We began with an
overview of semiconductor memories. Types of memories were compared in terms of their
capacity, organization, and access time.
ROM (read-only memory) is nonvolatile memory typically used to store programs. The relative
advantages of various types of ROM were described in this chapter, including PROM, EPROM,
UV-EPROM, EEPROM, flash memory EPROM, and mask ROM.
RAM (random-access memory) is typically used to store data or programs. The relative
advantages of its various types, including SRAM, NV-RAM, checksum byte RAM, and DRAM,
were discussed.
Address decoding techniques using simple logic gates, decoders, and programmable logic were
covered. RAM and ROM memories were interfaced with 8031 systems, and programs were
written to access code and data stored on these external memories. The 64KB of external data
space of the 8051 was discussed, and programs were written in both Assembly and C to access
them. Finally, the 1 KB SRAM memory of the DS89C4xO chip was explored and we showed
how to access it in both Assembly and C.