Unit - 3
8051 Programming in C
For this embedded microcontroller, we will be using a programming language called 'C'. C is extremely flexible and allows programmers to perform many low-level functions.
There are many syntax rules in C.
Declarations
The format for declaring a variable in a C program is as follows:
Variable name;
For example, the line int i; would declare an integer variable i.
Computers are very useful when repeating a specific task, and almost every program utilizes this capability. The repetitive structures for, while, and do-while are all offered by C.
It may be necessary to store a list or table of values of the same type that you want to associate in some way. An array can be used to do this. An array is a group of memory locations all of the same name and data type. Each memory location in the array is called an element and is numbered with the first element as number “0”.
C also includes a full range of operators. Operators usually have two arguments, and the symbol between them operates on the two arguments, replacing them with the new value.
Most mathematical and bitwise operators in the C language can be combined with an equal sign to create an assignment operator.
Key Takeaways:
Embedded C language is used commonly to program microcontrollers. Keil C51 compiler uses some keywords as given below for the ease of programming.
C language supports 2 different types of data types:
These are fundamental data types in C namely integer(int), floating-point(float), character(char) and void.
2. Derived data types:
Derived data types are nothing but primary datatypes but a little twisted or grouped like an array, structure, union, and pointer.
The data type determines the type of data a variable will hold. If a variable x is declared as int. it means x can hold only integer values. Every variable which is used in the program must be declared as what data-type it is.
Integers:
Integers are used to store whole numbers.
Size and range of Integer type on a 16-bit machine:
Type | Size(bytes) | Range |
int or signed int | 2 | -32,768 to 32767 |
unsigned int | 2 | 0 to 65535 |
short int or signed short int | 1 | -128 to 127 |
unsigned short int | 1 | 0 to 255 |
long int or signed long int | 4 | -2,147,483,648 to 2,147,483,647 |
unsigned long int | 4 | 0 to 4,294,967,295 |
Char type
Character types are used to store characters value.
Size and range of Integer type on a 16-bit machine
Type | Size(bytes) | Range |
char or signed char | 1 | -128 to 127 |
Unsigned char | 1 | 0 t0 255 |
Void type
Void type means no value. This is usually used to specify the type of functions that return nothing.
Key Takeaways:
Embedded C language is used commonly to program microcontrollers. So it is important to know everything about Embedded C. Keil C51 compiler uses some keywords for the ease of programming.
Figure 1. Port 0
Figure 2. Port 1 bit
Figure 3. Port 2 bit
Figure 4. Port 3 bit
Features of Port 0
Functions of Port 0
When we use Port 0 as an input port, the internal latch is used for input, and thus, a digital 1 (FFH) is written at the port address of 80H. This turns off the transistors causing the pin to float in a high impedance state connecting it to the input buffer. We can read data from ‘Read Pin Data’/’Read Latch Bit.’
When we use Port 0 as an output port, the latch programmed to 0 will turn on. Consequently, the FET will connect to GND. We will require an external pull up resistor(10k Ohm) here to give a logic ‘1’ for using Port 0 as an output port.
When the 8051 wants to access external memory, the address for the memory generates due to Port 0 and Port 2. We get the lower half of the address from Port 0 and the upper half from Port 2. This is done using ALE pulses, which help to latch the address to the external bus. Once done, Port 0 goes back to being an input port to read data from that memory.
Working of port 0
Port 0 is used to read data to addresses. To configure port 0 as an input port the internal bus writes 1 to the D flip flop and the control pin is set to 0(Upper FET is OFF). The mux is connected to Q'(0) of the D flip flop as the control pin is 0. Due to this, the pin is connected to the input buffer which can be read to get the input data.
To use the port as an output port 0 is written to the D flip flop with the control signal being set to 0. This enables the lower FET and disables the upper FET due to this the pin gets connected to the ground and a zero is written to the output device.
To write a 1 to the external device the microcontroller writes 1 to the D flip flop which drives the pin to a high impedance state as it is not connected to either VCC or ground. To solve this problem a pull-up resistor is connected to the output pin which pulls the value to 5v or logic 1.
For reading Addresses or data from external memory the Control bit is set to set 1 which connects the Mux to Data/address pin. The ALE pin is used to latch the address and once that is done the port is used for data transfer.
Features of Port 1:
The function of Port 1 – I/O port:
When Port 1 is functioning in the capacity of an input port, a digital ‘1’ (FFH) is written to the latch. At 90H. This turns off the transistor, and the pin floats in a high impedance state. Consequently, it connects to the input buffer.
When Port 1 is functioning in the capacity of an output port, the latch is given a ‘LOW’ signal (00H). This turns the FER (Field Effect Transistor) o. The pull-up resistor is OFF, and the port is used as an output port.
Features of Port 2
Functions of Port 2
I/O port:
Quite similar to Port 0. The only difference here is that in Port 2, we use one FET with an internal pull-up resistor instead of the two FETs we saw in Port 0.
Memory Access:
Port 2 is used in conjunction with Port 0 to generate the upper address of the external memory location that needs to be accessed. However, one key difference is that it doesn’t need to turnaround and get a 1 in the latch immediately for input as in Port 0. It can remain stable.
Features of Port 3
Functions of Port 3
I/O port
Just like Port 2, Port 3 can function as an input-output port.
Alternate SFR function
The input to SFR 1, we get the output of latch as 1, which turns on the NAND gate, and depending on the value of ‘Alternate Output Pin,’ FET will be wither ON/OFF.
P3 Bit | Function | Pin |
P3.0 | RxD | 10 |
P3.1 | TxD | 11 |
P3.2 | 12 | |
P3.3 | 13 | |
P3.4 | T0 | 14 |
P3.5 | T1 | 15 |
P3.6 | 16 | |
P3.7 | 17 |
RXD: this is used for a serial input port
TXD: this is used for serial output port
INT0: this used for an external interrupt 0
INT1: this used for external interrupt 1
T0: Timer 0 external input
T1: Timer 1 external input
WR: external data memory write strobe
RD: external data memory Read strobe
Key takeaway:
8051 microcontrollers have 4 I/O ports each of 8-bit, which can be configured as input or output. Hence, a total of 32 input/output pins allow the microcontroller to be connected with the peripheral devices.
A bit is the smallest unit of storage represented by 0 or 1. A byte is typically 8 bits. A file is a sequence of bytes. The size of the file is the number of bytes within the file. Although all files are a sequence of bytes m files can be regarded as text files or binary files.
There are two ways to create a time delay in 8051 C:
In creating a time delay using a for loop, there are three factors:
Write a program to toggle the bits of P1 ports continuously with a 250ms delay.
Solution:
# include<reg51.h>
void MSdelay(unsigned int);
void main(void)
{
while(1) // repeat forever
{
P1 = 0x55;
MSDelay(250);
P1=0XAA;
MSdelay(250);
}
}
void MSdelay(unsigned int itime)
{
unsigned int i,j;
for(i=0;i<time;i++)
for(j=0;j<1275;j++);
}
Write an 8051 C program to toggle all the bits of P0 and P2 continuously with a 250ms delay.
Solution:
#include<reg51.h>
void MSDelay(unsigned int);
void main(void)
{
while(1)
{
P0 = 0x55;
P2 = 0x55;
MSDelay(250);
P0=0xAA;
P2=0xAA;
MSDelay(250);
}
}
void MSdelay(unsigned int itime)
{
unsigned int i,j;
for(i=0;i<itime;i++)
for (j=0;j<1275;j++);
}
Key Takeaways:
8051 microcontroller has two independent 16 bit up counting timers named Timer 0 and Timer 1 and this article is about generating time delays using the 8051 timers.
Counters and Timers of 8051
The 8051 has two timers: timer0 and timer1. They can be used either as timers or as counters. Both timers are 16 bits wide. Since the 8051 has an 8-bit architecture, each 16-bit is accessed as two separate registers of low byte and a high byte.
Timer0 registers are 16 bits register and accessed as low byte and a high byte. The low byte is referred to as a TL0 and the high byte is referred to as TH0. These registers can be accessed like any other registers.
Figure 5. Timer 0
Timer1 registers is also a 16 bits register and are split into two bytes, referred to as TL1 and TH1.
Figure 6. Timer 1
TMOD (timer mode) Register:
This is an 8-bit register that is used by both timers 0 and 1 to set the various timer modes. In this TMOD register, the lower 4 bits are set aside for timer0 and the upper 4 bits are set aside for timer1. In each case, the lower 2 bits are used to set the timer mode and the upper 2 bits to specify the operation.
TMOD Register
M0 | M1 | Mode | Operating Mode |
0 | 0 | 0 | 13-bit timer mode. 8-bit timer/counter THx and TLx as –bit Prescaler |
0 | 1 | 1 | 16-bit timer mode, 16-bit timers/counters THx and TLx as 5-bit Prescaler |
1 | 0 | 2 | 8-bit auto-reload mode, 8-bit auto-reload timer/counter; THx holds a value which is to be reloaded into TLx each time it overflows |
1 | 1 | 3 | Split timer mode |
Mode 1-
Mode 0-
Mode 2-
Mode 3-
Mode 3 is also known as a split timer mode. Timer 0 and 1 may be programmed to be in modes 0, 1, and 2 independently of similar modes for other timers. This is not true for mode 3; timers do not operate independently if mode 3 is chosen for timer 0. Placing timer 1 in mode 3 causes it to stop counting; the control bit TR1 and the timer 1 flag TF1 are then used by timer0.
TCON Register
Bits and symbol and functions of every bit of TCON are as follows:
TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
TCON Register
Bit | Symbol | Functions |
7 | TF1 | Timer1 overflow flag. Set when timer rolls from all 1’s to 0 |
6 | TR1 | Timer 1 run control bit. Set to 1 by the programmer to enable a timer to count. |
5 | TF0 | Timer 0 overflow flag |
4 | TR0 | Timer 0 run control bit |
3 | IE1 | External Interrupt 1 edge flag |
2 | IT1 | External Interrupt 1 signal type control bit |
1 | IE0 | External Interrupt 0 edge flag |
0 | IT0 | External Interrupt 0 signal type control bit |
Key takeaways:
When the counter is running on the processor’s clock, it is called a “Timer”, which counts a predefined number of processor clock pulses and generates a programmable delay. When the counter is running on an external clock source (maybe a periodic or aperiodic external signal) it is called a “Counter” itself and it can be used for counting external events.
In Intel 8051, there are two 16-bit timer registers. These registers are known as Timer0 andTimer1. The timer registers can be used in two modes. These modes are the Timer mode and Counter mode. The only difference between these two modes is the source for incrementing the timer registers.
Timer Mode
In the timer mode, the internal machine cycles are counted. So this register is incremented in each machine cycle. So when the clock frequency is 12MHz, then the timer register is incremented in each millisecond. In this mode, it ignores the external timer input pin.
Counter Mode
TMOD Register
TMOD(Timer Mode) is an SFR. The address of this register is 89H. This is not bit-addressable.
The circuit that controls the running of the timers is shown in the figure.
Figure 7. Timer
Bit Details | High Value(1) | Low Value(0) |
C/T | Configure for the Counter operations | Configure for the Timer operations |
Gate (G) | Timer0 or Timer1 will be in Run Mode when the TRX bit of the TCON register is high. | Timer0 or Timer1 will be in Run Mode when the TRX bit of TCON register is high and INT0 or INT1 is high. |
Bit Details | 00 | 01 | 10 | 11 |
M1 M0 | This is for Mode 0. (8-bit timer/counter, with 5-bit pre-scaler) | This is Mode 1. (16-bit timer/counter) | This is Mode 3 (8-bit auto reload-timer/counter) | This is Mode 3 (The function depends on Timer0 or Timer1) |
The Gate bit will be high when the timer or counter is in mode 0 to 2.
Examples
To configure Timer0 as 16-bit event counter and Timer1 as 8-bit auto-reload counter, use the bit pattern as 0 0 1 0 0 1 0 1. It is equivalent to 25H. Then if we want to program the TMOD register with this bit pattern, we can use this instruction:
MOVTMOD,#25H
The above instruction is executed, then the timer/counter will be controlled by the software. To configure the system as hardware controlled mode, then the gate bits will be 1. So the bit patterns will be 1 0 1 0 1 1 0 1 = ADH
Then use this instruction:
MOVTMOD,#0ADH
Mode 0 of Timer/Counter
The Mode 0 operation is the 8-bit timer or counter with a 5-bit pre-scaler. So it is a 13-bit timer/counter. It uses 5 bits of TL0 or TL1 and all of the 8-bits of TH0 or TH1.
Figure 8. Mode 0
In this example the Timer1is selected, in this case, every 32 (25)event for counter operations or 32 machine cycles for timer operation, the TH1 register will be incremented by 1. When the TH1overflows from FFH to 00H, then the TF1 of the TCON register will be high, and it stops the timer/counter.
For example, we can say that if the TH1 is holding F0H, and it is in timer mode, then T
F1will be high after 10H * 32 = 512 machine cycles.
MOVTMOD,#00H
MOV TH1,#0F0H
MOV IE,#88H
SETB TR1
In the above program, Timer1 is configured as timer mode 0. In this case Gate = 0. Then the TH1 will be loaded with F0H, then enable the Timer1 interrupt. At last set the TR1 of the TCON register, and start the timer.
Mode 1 of Timer/Counter
The Mode 1 operation is the 16-bit timer or counter. In the following diagram, we are using Mode 1 for Timer0.
Figure 9. Mode 1
In this case every event for counter operations or machine cycles for timer operation, the TH0– TL0 register-pair will be incremented by 1. When the register pair overflows from FFFFH to 0000H, then the TF0 of the TCON register will be high, and it stops the timer/counter.
For example, we can say that if the TH0 – TL0 register pair is holding FFF0H, and it is in timer mode, then TF0 will be high after 10H = 16 machine cycles. When the clock frequency is 12MHz, then the following instructions generate an interrupt 16 µs after Timer0 starts running.
MOV TMOD,#01H
MOV TLO,#F0H
MOV TH0, #0FFH
MOV IE,#82H
SETB TR0
In the above program, the Timer0 is configured as timer mode 1. In this case Gate = 0. Then the TL0 will be loaded with F0H and TH0 is loaded with FFH, then enable the Timer0 interrupt. At last set the TR0 of the TCON register, and start the timer.
Mode 2 of Timer/Counter
The Mode 2 operation is the 8-bit auto-reload timer or counter. In the following diagram, we are using Mode 2 for Timer1.
Figure 10. Timer 1 mode 2 operation
In this case every event for counter operations or machine cycles for timer operation, the TL1register will be incremented by 1. When the register pair overflows from FFH to 00H, then the TF1 of the TCON register will be high, also theTL1 will be reloaded with the content of TH1 and starts the operation again.
For example, If the TH1 and TL1 register both are holding F0H and it is in timer mode, then TF1 will be high after 10H= 16 machine cycles. When the clock frequency is 12MHz this happens after 16 µs, then the following instructions generate an interrupt once every 16 µs after Timer1 starts running
MOV TMOD,#20H
MOV TL1,#0F0H
MOV TH1,#0F0H
MOV #88H
SETBTR1
In the above program, Timer1 is configured as timer mode 2. In this case Gate = 0. Then the TL1 and TH1 are loaded with F0H. then enable the Timer1 interrupt. At last set the TR1 of the TCON register, and start the timer.
Timer1 in mode 2 generates the desired baud rate when the serial port is working on Mode 1 or 3.
Programming of Counters and Timers:
To program 8051 timers, it is important to know the calculation of the initial count value to be stored in the timer register.
The calculations are as follows. In any mode,
Timer Clock period = 1/Timer Clock Frequency. = 1/(Master Clock Frequency/12)
Upon starting the timer this value from THx will be reloaded to the TLx register. (256D = FFH+1)
Steps for programming timers in 8051
Mode 1:
Load the TMOD value register indicating which timer (0 or 1) is to be used and which timer mode is selected. Load registers TL and TH with initial count values.
Start the timer with the instruction “SETB TR0” for timer 0 and “SETB TR1” for timer 1.
Keep monitoring the timer flag (TF) with the “JNB TFx, target” instruction to see if it is raised. Get out of the loop when TF becomes high.
Stop the timer with the instructions “CLR TR0” or “CLR TR1”, for timer 0 and timer 1, respectively.
Clear the TF flag for the next round with the instruction “CLR TF0” or “CLR TF1”, for timer 0 and timer 1, respectively.
Go back to step 2 to load TH and TL again.
Mode 0:
The programming techniques mentioned here are also applicable to counter/timer mode 0. The only difference is in the number of bits of the initialization value.
Mode 2:
Load the TMOD value register indicating which timer (0 or 1) is to be used; select timer mode
Load TH register with the initial count value. As it is an 8-bit timer, the valid range is from 00 to FFH.
Start the timer. Keep monitoring the timer flag (TFx) with the “JNB TFx, target” instruction to see if it is raised.
Get out of the loop when TFx goes high. Clear the TFx flag.
Go back to step 4, since mode 2 is auto-reload.
Write an 8051 C program to toggle only pin PI.5 continuously every 250 ms. Use Timer 0, mode 2 (8-bit auto-reload) to create the delay.
Solution:
#include<reg51.h>
void TOM2Delay(void);
sbit mybit=P1^5;
void mian(void)
{
unsigned char x,y;
while(1)
{
unsigned char x,y;
while(1)
{
mybit= ˜ mybit;
for(x=0;x<250;x++)
for(y=0;y<36;y++)
TOM2Delay();
}
}
256-23 = 233
23 x 1.085 us = 25 us
25 us x 250 x 40 = 250 ms by calculation.
However, the scope output does not give us this result. This is due to the overhead of the for loop in C. To correct this problem, we put 36 instead of 40.
Write an 8051 C program to create a frequency of 2500 on pin P2.7. Use Timer 1 mode 2 to create delay.
# include<reg51.h>
void T1M2Delay(void);
sbit mybit= P2^7;
void main(void)
{
unsigned char x;
while(1)
{
mybit= ˜ mybit;
T1M2Delay();
}
}
Void TIM2Delay(void)
TMOD = 0x20;
TH1=184;
TR1=1;
while(TF1==0);
TR1=0;
TF1=0;
}
1/2500 Hz = 400μs
400μs/2 = 200μs
200μs/1.085μs= 184
Key Takeaways:
The programming of 8051 Timers can be done by using either the polling method or by using an interrupt.
A timer can be used as a counter if we provide pulses from outside the chip instead of using the frequency of the crystal oscillator as the clock source. By feeding pulses to the TO (P3.4) and Tl (P3.5) pins, we turn Timer 0 and Timer 1 into counter 0 and counter 1, respectively.
Assume that a 1-Hz external clock is being fed into pin Tl (P3.5). Write a C program for counter 1 in mode 2 (8-bit auto-reload) to count up and display the state of the TL1 count on the PI. Start the count at OH.
#include<reg51.h>
sbit T1 = P3^5;
void main(void)
{
T1=1;
TMOD = 0x60;
TH1=0;
while(1)
{
do
{
TR1=1;
P1=Tl1;
}
while(TF1==0)
TR1=0;
TF1=0;
}
}
Assume that a 1-Hz external clock is being fed into pin T0(P3.4). Write a C program for counter 0 in mode-1 (16-bit) to count the pulses and display the TH0 and TL0 registers on P2 and P1 respectively.
#include(reg51.h>
void main(void)
{
T0=1;
TMOD=0x05;
TL0=0;
TH0=0;
while(1)
{
do
{
TR0=1;
P1=TL0;
P2=TH0;
}
while(TF0==0)
TR0=0;
TF=0;
}
}
Assume that a 2-Hz external clock is being fed into pin Tl (P3.5). Write a C program for counter 0 in mode 2 (8-bit auto-reload) to display the count in ASCII. The 8-bit binary count must be converted to ASCII. Display the ASCII digits (in binary) on PO, PI, and P2 where PO has the least significant digit. Set the initial value of THO to 0.
Solution:
To display the TL1 count we must convert 8-bit binary data to ASCII. See Chapter 7 for data conversion. The ASCII values will be shown in binary. For example, ’9′ will show as 00111001 on ports.
#include<reg51.h>
void BinToASCII(unsigned char);
void main()
{
Unsigned char value;
T1=1;
TMOD = 0x06;
TH0=0;
while(1)
{
do
{
TR0=1;
value= TL0;
BintoASCII(value);
}
while(TF==0)
TR0=0;
TF=0;
}
}
void BintoASCII(unsigned char value)
{
unsigned char x,d1,d2,d3;
x=value/10;
d1=value%10;
d2=x%10;
d3=x/10;
P0= 30|d1;
P1=30|d2;
P2=30|d3;
}
Assume that a 60-Hz external clock is being fed into pin T0(P3.4). Write a C program for counter 0 in mode2(8-bit auto-reload)
Assume that a 60-Hz external clock is being fed into pin TO (P3.4). Write a C program for counter 0 in mode 2 (8-bit auto-reload) to display the seconds and minutes on PI and P2, respectively.
Solution:
#include<reg51.h>
void ToTime(unsigned char);
void main()
{
unsigned char val;
void main()
{
unsigned char val;
T0=1;
TMOD = 0x06;
TH0=-60;
while(1)
{
do
{
TR0=1;
sec=TL0;
ToTime(val);
}
while(TF==0);
TR0=0;
TF0=0;
}
void ToTime(unsigned char val)
{
unsigned char sec,min;
min=value/60;
sec=value%60;
P1=sec;
P2=min;
}
Key Takeaway:
The programming of 8051 Timers can be done by using either the polling method or by using an interrupt.
References:
1. The 8051 Microcontroller and Embedded Systems using Assembly and C by Muhammad Ali Mazidi.
2. The 8051 Microcontroller by I. Scott Mackenzie, Raphael C.W Phan
8051 Microcontrollers: Internals, Instructions, Programming, and Interfacing Book by Subrata Ghoshal
3. 8051 Microcontroller Based Embedded Systems Textbook by MANISH K PATEL
4. 8051 Microcontrollers: An Applications Based Introduction Book by David Calcutt, Frederick Cowan, and G. Hassan
5. Advanced PIC Microcontroller Projects in C Book by Dogan Ibrahim