THE 8051
MICROCONTROLLER
INTERFACING
LABORATORY MANUAL
First Edition
Hardware List:
Pin Functions
18 Port 1. The bi-directional pins on this
port may be used for input and output:
each pin may be individually controlled
and for example some may be used
for input while others on the same port
are used for output.
9 The Reset pin. When this pin is held
at Logic 0, the chip will run normally.
If, while the oscillator is running, this
pin is held at Logic 1 for two (or more)
machine cycles, the microcontroller will
be reset.
1017 Port 3. Another bi-directional input port
(same operation as Port 1). Each pin on
this port also serves an additional
function. Pin 10 and Pin 11 are used to
receive and transmit (respectively)
serial data using the RS-232 protocol.
Pin 12 and Pin 13 are used to process
interrupt inputs. Pin 14 and Pin 15 have
alternative functions associated with
Timer 0 and Timer 1. Pin 16 and Pin 17
are used when working with external
memory
1819 These pins are used to connect an
external crystal, ceramic resonator or
oscillator module to the
microcontroller.
20 Vss. This is the ground pin.
2128 Port 2. Another bi-directional input port (same operation as Port 1). These pins are also used when
working with external memory
29 Program Store Enable (PSEN) is used to control access to external CODE memory (if used).
30 Address Latch Enable (ALE) is used when working with external memory. Note that some devices
allow ALE activity to be disabled (if external memory is not used): this can help reduce the level of
electromagnetic interference (EMI) generated by your product. This pin is also used (on some devices)
as the program pulse input (PROG) during Flash programming.
31 External Access (EA). To execute code from internal memory (e.g. on-chip Flash, where available)
this pin must be connected to Vcc. To execute code from external memory, this pin must be connected
to ground. Forgetting to connect this pin to Vcc is a common error when people first begin
working with the 8051.
3239 Port 0. Another bi-directional input port (same operation as Port 1). Note that unlike Port 1, Port 2
and Port 3 this port does NOT have internal pull-up resistors. These pins are also used when working
with external memory
40 Vcc. This is the 5V pin (on 5V devices; 3V on 3V devices, etc).
Implementation on Breadboard:
C Programming Code:
#include <c:\c51\inc\AT89C51.H>
void wait (void){ /* wait function */
unsigned int x;
for(x=0;x<10000;x++); /* one second delay for LEDs */
}
void main (void)
{
unsigned int i; /* Delay variable */
unsigned char j; /* LED variable */
}
}
}
----------------------------------------------------------------------------------------
Invoking DScope
----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------
Using DScope
----------------------------------------------------------------------------------------
Decrease Command Window Size Alt+D
Increase Command Window Size Alt+U
Reset Command reset
Go To Main Function g,main
Execute One Instruction Alt+t
Watch Set Instruction ws variablename
Watch Kill Instruction wk watchnumber
Serial Data In Instruction sin = hexdata
Exercise:
Change the above code So that the LEDs should blink like a progress bar e.g
Answer:
Objective:
Circuit Diagram:
Hardware List:
C Programming Code:
sfr P0 = 0x80;
sbit a=P0^0; sbit b=P0^1; sbit c=P0^2;
sbit d=P0^3; sbit e=P0^4; sbit f=P0^5;
sbit g=P0^6; sbit dot=P0^7;
void number(int n)
{
switch(n)
{
case 0:
dot=0; g=0; f=1; e=1; d=1; c=1; b=1; a=1; break;
// OR you can also use P0=0x3F;
case 1:
dot=0; g=0; f=0; e=0; d=0; c=1; b=1; a=0; break; // P0 = 0x06;
case 2:
dot=0; g=1; f=0; e=1; d=1; c=0; b=1; a=1; break; // P0 = 0x5B;
case 3:
dot=0; g=1; f=0; e=0; d=1; c=1; b=1; a=1; break; // P0 = 0x4B;
case 4:
dot=0; g=1; f=1; e=0; d=0; c=1; b=1; a=0; break; // P0 = 0x66;
case 5:
dot=0; g=1; f=1; e=0; d=1; c=1; b=0; a=1; break; // P0 = 0x6D;
case 6:
dot=0; g=1; f=1; e=1; d=1; c=1; b=0; a=1; break; // P0 = 0x7D;
case 7:
dot=0; g=0; f=0; e=0; d=0; c=1; b=1; a=1; break; // P0 = 0x07;
case 8:
dot=0; g=1; f=1; e=1; d=1; c=1; b=1; a=1; break; // P0 = 0x7F;
case 9:
dot=0; g=1; f=1; e=0; d=0; c=1; b=1; a=1; break; // P0 = 0x67;
}
}
void main()
{
int i=0;
while(1){
number(i);
delay(50);
i++;
if(i>=10)
i=0;
}
}
Exercise:
Change the above code to Show remaining hexadecimal values on Seven Segment like
Answer:
Hardware List:
Circuit Diagram:
Pin Assignment:
Instruction Set:
Interfacing:
Character Set:
One way is to check the BUSY bit found on data line D7. This
is not the best method because LCD's can get stuck, and program will then stay forever in a loop
checking the BUSY bit. The other way is to introduce a delay in the program. The delay has to be long
enough for the LCD to finish the operation in process. Instructions for writing to and reading from an
LCD memory are shown in the previous table.
At the beginning we mentioned that we needed 11 I/O lines to communicate with an LCD. However, we
can communicate with an LCD through a 4-bit data bus. Thus we can reduce the total number of
communication lines to seven. The wiring for connection via a 4-bit data bus is shown in the diagram
below. In this example we use an LCD display with 2x16 characters. The message 'Microcon' is written in
the first row: and In the second row we have produced the word 'www.iiu.edu.pk'.
C Programming Code:
#include<C:\c51\inc\REG51F.h>
sbit RS=P1^0;
sbit RW=P1^1;
sbit E=P1^2;
sbit BF=P0^7;
sfr DATA_BUS = 0x80; //Port 0
char data1;
return 1;
} //Ready Function Ends
unsigned char i;
E = 1; for(i=0; i<t; i++) i = i;
E = 0; for(i=0; i<t; i++) i = i;
}
int LCD_Run_Command(unsigned char COMMAND){
if(ready()){
DATA_BUS=COMMAND;
RS=0; delay(1);
RW=0; delay(1);
LCD_Pulse_E(255);
}
return 1;
}
int LCD_Show(unsigned char CHARACTER){
if(ready()){
DATA_BUS=CHARACTER;
RS=1; delay(1);
RW=0; delay(1);
LCD_Pulse_E(255);
delay(1);
}
return 1;
}
int LCD_Initialize(){
LCD_Run_Command(0x38); // 8 data lines, two lines, Font 5x7.
LCD_Run_Command(0x0E); // Display=ON, Curson=ON, Cursor Blonking=ON
LCD_Run_Command(0x01); // Clear display and return cursor to the home position
LCD_Run_Command(0x06); // During read/write operation only cursor (not text)
// should move right.
LCD_Run_Command(0x80); // Cursor at Line 1, Position 0
return 1;
}
void main()
{
for(;;)
{
delay(50);
LCD_Initialize();
for(data1='A' ; data1 <'T' ; data1++){
LCD_Show(data1);
}
LCD_Run_Command(0xC0); // Cursor at Line 2, Position 0
}
delay(50);
}
}
Exercise:
Objective:
Registers Functionality:
TMOD(Timer Mode, Address 89h): The TMOD SFR is used to control the mode of operation of both
timers. Each bit of the SFR gives the microcontroller specific information concerning how to run a timer. The
high four bits (bits 4 through 7) relate to Timer 1 whereas the low four bits (bits 0 through 3) perform the
exact same functions, but for timer 0. The individual bits of TMOD have the following functions:
7 GATE1 When this bit is set the timer will only run when INT1 (P3.3) is high. When this 1
bit is clear the timer will run regardless of the state
of INT1.
6 C/T1 When this bit is set the timer will count events on T1 (P3.5). When this bit is 1
clear the timer will be incremented every machine cycle.
5 T1M1 Timer mode bit (see table below) 1
4 T1M0 Timer mode bit (see table below) 1
3 GATE0 When this bit is set the timer will only run when INT0 (P3.2) is high. When this 0
bit is clear the timer will run regardless of the state of INT0.
2 C/T0 When this bit is set the timer will count events on T0 (P3.4). When this bit is 0
clear the timer will be incremented every machine cycle.
1 T0M1 Timer mode bit (see table below) 0
0 T0M0 Timer mode bit (see table below) 0
As you can see in the above chart, four bits (two for each timer) are used to specify a mode of operation. The
modes of operation are:
TxM1 TxM0 Timer Mode Description of Mode
0 0 0 13-bit Timer.
0 1 1 16-bit Timer
1 0 2 8-bit auto-reload
1 1 3 Split timer mode
The TCON SFR: The TCON is a bit addressable special function register controls the two timers and provides
valuable information about them. The TCON SFR has the following structure:
TCON (88h) SFR
Bit Name Bit Explanation of Function Timer
Address
7 TF1 8Fh Timer 1 Overflow. This bit is set by the microcontroller when 1
Timer 1 overflows (timer rolls from all ones to zero).
6 TR1 8Eh Timer 1 Run. When this bit is set to 1 by program, Timer 1 is 1
Please Note: the lower 4 bits (bit0 to bit3) of the TCON register dont have anything to do with timers. These
are related to Interrupts.
Setting Up Interrupts
By default at powerup, all interrupts are disabled. This means that even if, for example, the TF0 bit
is set, the 8051 will not execute the interrupt. Your program must specifically tell the 8051 that it
wishes to enable interrupts and specifically which interrupts it wishes to enable.
Your program may enable and disable interrupts by modifying the IE SFR (A8h):
Bit Name Bit Address Explanation of Function
7 EA AFh Global Interrupt Enable/Disable
6 - AEh Undefined
5 - ADh Undefined
4 ES ACh Enable Serial Interrupt
3 ET1 ABh Enable Timer 1 Interrupt
2 EX1 AAh Enable External 1 Interrupt
1 ET0 A9h Enable Timer 0 Interrupt
0 EX0 A8h Enable External 0 Interrupt
As you can see, each of the 8051s interrupts has its own bit in the IE SFR. You enable a given
interrupt by setting the corresponding bit.
C Programming Code:
// The following program geterates a clock of frequency about 2 KHz at its port P1^7
// Please read Ali Mazidis book for reference
#include <c:\c51\inc\reg51f.h>
void main(void)
{
TMOD.6 C/T1 = When this bit is set the timer will count events
on T1 (P3.5). When this bit is clear the timer
will be incremented every machine cycle.
*/
while(1){
TL1 = 0x1A; /* initial values */
// TL1 = 0x00; /* initial values */
TH1 = 0xFF;
TR1 = 1; // Start Timer 1
// ET1 = 1; // Enable Timer 1 overflow interrupt
while(!TF1){
;
}
C Programming Code:
// The following program counts the events at port P3^5, whenever this pin is connacted
to ground, an event occures and the total no of events are shown on port P0.
// Please read Ali Mazidis book for reference
#include <c:\c51\inc\reg51f.h>
void main(void)
{
TMOD.6 C/T1 = When this bit is set the timer will count events
on T1 (P3.5). When this bit is clear the timer
will be incremented every machine cycle.
So An Event Occures when we connect P3.5 to ground
*/
// P3^5=1;
while(1){
TR1 = 1; // Start Timer 1;
while(!TF1){
P0=TL1; // 0XDF = 1101 1111
The various functions the BIOS carries out are termed interrupt service routines (ISR). The design of the
PC BIOS allows the system to put these interrupt handlers (ISR) at any convenient address. So that a calling
program can find the proper routine.
The BIOS reserves part of your PCs memory for a map called a BIOS interrupt vector table. This map
consists of a long list of 32-bit addresses with one address corresponding to each interrupt handler. These
addresses point to the first byte of the program code for carrying out the interrupt and are called interrupt
vectors. The microprocessor reads the value of the vector, and starts executing the code located at the value
stored in the vector.
The table of interrupt vectors begins at the very start of the microprocessor's memory, address 00000(Hex).
Each vector comprises four bytes and all vectors are stored in increasing order. Table given below
summarizes list of selected BIOS interrupt vectors and the associated functions
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <conio.h>
int main(void)
{
clrscr();
movetoxy(35, 10);
printf("Hello\n");
getch();
return 0;
}
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <conio.h>
Figure 1: A serial data frame with eight data bits and one stop bit.
In most of our PCs, BIOS supports 4 UARTS as COM Ports COM1, COM2, COM3, COM4. The following
table shows the address at which we can find the Communications (COM) Ports Addresses in the BIOS
Data Area. Each address will take up 2 bytes.
The Following Table Summarizes the Standard Port Addresses and this information is correct for most of
PCs
The following debug command shows that the address of COM1 is 03F8 , the address of COM2 is 02F8 and
the address of COM3 is 03E8.
The following sample program in C, It shows how you can read these locations to obtain
the addresses of your communications ports. Save this code as port.address.cpp
Compile it using Turbo C compiler
#include <stdio.h>
#include <conio.h>
#include <dos.h>
void main(void)
{
unsigned int far *ptraddr; /* ointer to location of Port
addresses */
unsigned int address; /* ddress of Port */
int a;
clrscr();
ptraddr=(unsigned int far *)0x00000400;
for (a = 0; a < 4; a++)
{
address = *ptraddr;
if (address == 0)
printf("No port found for COM%d \n",a+1);
else
printf("Address assigned to COM%d is
%Xh\n",a+1,address);
*ptraddr++;
}
getch();
Null Modems
// To run this program place a loop back plug at first serial port of your PC
#include <stdio.h>
#include <bios.h>
#include <conio.h>
#define COM1 0
#define DATA_READY 0x100
#define TRUE 1
#define FALSE 0
int main(void)
{
clrscr();
int send, receive, status, DONE = FALSE;
while (!DONE)
{
status = bioscom(3, 0, COM1);
if (status & DATA_READY)
{
receive = bioscom(2, 0, COM1);
printf("Data Received = %c",receive);
}
if (kbhit())
{
if ((send = getch()) == '\x1B')
DONE = TRUE;
printf("\nSending Data = %c",send);
bioscom(1, send, COM1);
}
}
return 0;
}
#include <stdio.h>
#include <bios.h>
#include <process.h>
#include <conio.h>
#include <iostream.h>
int port_initialize()
{
union REGS regs;
regs.h.ah = 0; // Call Function 0 to initialize Port
regs.h.dl = COM1; // Which Port?
regs.h.al = SETTINGS; // Configuration parameters
cout<<"Initalizing serial port at\n";
cout<<"Date Size = 8-Bit \t Stop Bits = One \n";
cout<<"Parity Bits = No \t Baud Rate = 1200 \n";
cout<<"Settings = "<<hex<<SETTINGS<<endl;
int port_status()
{
union REGS regs;
regs.h.ah = 3; // Function 3h: Read Status
regs.h.dl = COM1; // first serial port
int86(0x14, ®s, ®s);
if (regs.h.ah & 1) // is DATA_READY
return TRUE;
else
return FALSE;
}
char port_receive()
{
if(port_status()){
union REGS regs;
regs.h.ah = 2; // Function 2h: Receive Character
regs.h.dl = COM1; // first serial port
int86(0x14, ®s, ®s);
return(regs.h.al); // Character Received
}
else
cout<<"\nData is Not Ready"<<endl;
return FALSE;
}
int main(void)
{
clrscr();
char option;
printf("\nPress [ESC] key to exit ...\n");
port_initialize();
while(1)
{
cout<<"\n[S]-> Send Data \t [R]->Receive Data \t [ESC]->Exit\n";
option = getch();
if(option =='s'){
cout<<"Send What? ";
port_send(getche());
}
if(option =='r')
cout<<port_receive()<<endl;
if(option =='\x1B')
exit(0);
}
}
Here is out put
Press [ESC] key to exit ...
Initalizing serial port at
Date Size = 8-Bit Stop Bits = One
Parity Bits = No Baud Rate = 1200
Settings = 83
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#define PORT1 0x3F8
/* Defines Serial Ports Base Address */
/* COM1 0x3F8 */ /* COM2 0x2F8 */ /* COM3 0x3E8 */ /* COM4 0x2E8 */
void main(void)
{ int c;
int ch;
outportb(PORT1 + 1 , 0); /* Turn off interrupts - Port1 */
/* PORT 1 - Communication Settings */
outportb(PORT1 + 3 , 0x80); /* SET DLAB ON */
outportb(PORT1 + 0 , 0x03); /* Set Baud rate - Divisor Latch Low Byte */
/* Default 0x03 = 38,400 BPS */
/* 0x01 = 115,200 BPS */ /* 0x02 = 56,700 BPS */ /* 0x06 = 19,200 BPS */
/* 0x0C = 9,600 BPS */ /* 0x18 = 4,800 BPS */ /* 0x30 = 2,400 BPS */
} Table of Registers
Send a character from Computer to Microcontroller through serial port. Microcontroller increments that
character and send it back to Computer.
The serial port of computer sends/receives data serially at logic levels between -12 to +12V. But the
microcontroller works at logic levels between 0 to 5V. So we need a RS-232 to TTL and TTL to RS-232
converter and this is done by RS-232 Level Converter called MAX-232.
// computer.cpp
#include <stdio.h>
#include <bios.h>
#include <conio.h>
#define COM1 0
#define DATA_READY 0x100
#define TRUE 1
#define FALSE 0
int main(void)
{
clrscr();
int send, receive, status, DONE = FALSE;
while (!DONE)
{
status = bioscom(3, 0, COM1);
if (status & DATA_READY)
{
receive = bioscom(2, 0, COM1);
printf("\nData Received = %c",receive);
if (kbhit())
{
if ((send = getch()) == '\x1B')
DONE = TRUE;
printf("\nSending Data = %c",send);
bioscom(1, send, COM1);
}
}
return 0;
}
There are some special registers in 8051 microcontrollers that are used for serial communication
Additionally, it is necessary to define the function of SM0 and SM1 by an additional table:
(*) Note: The baud rate indicated in this table is doubled if PCON.7 (SMOD) is set.
TMOD (Timer Mode). The TMOD SFR is used to control the mode of operation of both timers.
Each bit of the SFR gives the microcontroller specific information concerning how to run a timer.
The high four bits (bits 4 through 7) relate to Timer 1 whereas the low four bits (bits 0 through 3)
perform the exact same functions, but for timer 0.
As you can see in the above chart, four bits (two for each timer) are used to specify a mode of
operation. The modes of operation are:
TxM1 TxM0 Timer Mode Description of Mode
0 0 0 13-bit Timer
0 1 1 16-bit Timer
1 0 2 8-bit auto-reload
1 1 3 Split timer mode
Data Rate is the bit rate, the number of bits per second available on a particular line
Baud Rate is the number of signaling elements on a particular line, or it can also be said as the
modulation rate
D = R / L = R / log2M
D = Data Rate
R = Modulation Rate
L = Number of bits per signaling element
M = Number of signaling elements
Crystal
TH 1 = 256
384 BaudRate
11059200
TH 1 = 256 = 256 24 = 232 = E8 = 24
384 1200
As you may notice, weve only defined 4 of the 8 bits. Thats because the
other 4 bits of the SFR dont have anything to do with timers--they have
to do with Interrupts and they will be discussed later
Microcontroller Programming:
When writing a communications program in for Microcontroller you have two methods available to you.
1- Poll the T I flag to see if any new data is available.
2- Set up an interrupt handler to remove the data from the SBUF.
//poll.c
# include <c:\c51\inc\reg51.h>
SBUF = dataByte; /* Write the character into the serial port buffer register */
}
dataByte = SBUF; /* copy the the value in SBUF into the local variable */
RI = 0; /* Once the character is read, the serial port must be told
* that it is free to receive a new character. This is done
* by clearing the Received Interrupt flag. */
void main()
{
unsigned char dataByte;
SCON = 0x50; /* mode 1, 8-bit uart, enable receiver (RI=1) */
TMOD = 0x20; /* timer 1, mode 2, 8-bit reload */
TH1 = -24; /* Reload value of the timer for baud rate 1200 bps */
/* TH1 = 256 - clock frequency (in Hz) / (384 * baud rate)
* For 1200bps and a 11.02Mhz clock:
* TH1 = 256 - 11,020,000 / (384 * 1200) = 232 = 0xE8 = -24 */
TR1 = 1; /* Setting TR1 will start the timer, and serial communications */
TI=1; /* Set the Transmit Interrupt flag to send the the character in
* the serial buffer, clearing will be done by the program. */
while(1)
{
dataByte=recieveChar(); /* read the next character from the serial port */
dataByte= dataByte+1; /* Increment the received character */
sendChar(dataByte); /* send it back to the original sender */
}
//interr.c
# include <c:\c51\inc\reg51.h>
/* The interrupt was generated, but it is still unknown why. First, check
* the RI flag to see if it was because a new character was received. */
main()
{
/* Before the serial port may be used, it must be configured. */
/* Set up Timer 0 for the serial port */
SCON = 0x50; /* mode 1, 8-bit uart, enable receiver */
TMOD = 0x20; /* timer 1, mode 2, 8-bit reload */
TH1 = -24; /* reload value for 1200 baud */
ET0 = 0; /* we don't want this timer to make interrupts */
TR1 = 1; /* start the timer */
TI = 1; /* clear the buffer */
/* The compiler automatically installs the interrupt handler, so all that needs
* to be done to use it is enable interrupts. First, speficially enable the
* serial interrupt, then enable interrupts. */
/* Loop forever, increasing Port 0. Again, note nothing is done with the serial
* port in this loop. Yet simulations will show that the software is perfectly
* capable of maintaining serial communications while this counting proceeds. */
while (1)
{
unsigned int i;
for (i = 0; i < 60000; i++) {;} /* delay */
P0 = P0 + 1; /* increment Port 0 */
}
}
The Pins having a bar over them ,means that the signal is inverted by the parallel port's hardware.If a 1 were to appear on
the 11 pin [S7], the PC would see a 0. The Status pins are mainly used by the PC to know the status of the printer ,like if
there is paper in the printer, end of paper etc.
Sending commands involves only the data pins [D0 to D7].Though it is possible to use the some other pins as input, we'll
stick to the basics.
Please remember that the Data pins are from pin 2 to pin 9 and not from pin 1.
#include <stdio.h>
#include <dos.h>
void main(void)
{
outportb(0x378,0xFF); //da line
}
If you take an LED and put one terminal at pin2 and the other to pin 18,it would glow.[Use a 2K resistor in series with the
LED, otherwise you will end up ruining your LED, or source too much current from the port pin]
WARNING Please do not feed your port more than 5V.You'll blow it up. Check all the voltages with a Multimeter before
proceeding
outportb(0x378,0x00);
0x378 is the parallel port address . Usually this is the default address. Sometimes it is 0x278 too
0x00 is the command appearing at the output pins. The Format is in Hexadecimal
So if u want to make pin no2 high, that's the first pin you type
0x01 which would mean 0000 0001 for the data port.
ADC 0804: The easiest way to do analog to digital conversion is to use ADC0804 IC. This IC converts
analog signal to 8-bit digital format.
The analog voltage is applied to pin 6 (Vin + ) and the result is available
at pins 11 through 18 (D7 to D0).
We will connect pin 1 (Chip Select) to ground so that the chip is always
enabled.
Connect pin 7 (Vin - ) to ground.
The ADC0804 includes an internal oscillator which requires an external
capacitor and resistor to operate.
o Therefore connect the 150 pF capacitor from pin 4 to ground
o Also connect a 10k ohm resistor from pin 4 to pin 19.
Connect pin 20 to 5 volts for Vcc and pin 10 to ground.
Connect pin 10 to ground.
Connect pin 2 (Read) from the ADC0804 to pin 7 (P3.3) of the 2051.
Connect pin 3 (Write) to pin 8 (P3.4).
Connect pin 5 (Interrupt) to pin 9 (P3.5).
The 8 bit Output Data from the ADC0804 will be connected to Port 1 of the 2051.
o Connect pin 18 (D0) of the ADC0804 to pin 12 of the 2051 (P1.0).
o Connect pin 17 (D1) to pin 13 (P1.1).
o Connect pin 16 (D2) to pin 14 (P1.2).
o Connect pin 15 (D3) to pin 15 (P1.3).
o Connect pin 14 (D4) to pin 16 (P1.4).
o Connect pin 13 (D5) to pin 17 (P1.5).
o Connect pin 12 (D6) to pin 18 (P1.6).
o Connect pin 11 (D7) to pin 19 (P1.7).
The 2051 pins 12 and 13 do not have internal pull up resistors so external pull up resistors are
required.
o Connect a 2.2k ohm resistor from pin 12 of the 2051 to 5 volts.
o Connect a 2.2k ohm resistor from pin 13 of the 2051 to 5 volts.
To power the 2051, Connect pin 20 of the 2051 to 5 volts and pin 10 of the 2051 to ground.
For the 2051 oscillator, Connect the 11 MHz Crystal from pin 4 of the 2051 to pin 5 of the 2051.
o Connect one 33 pF capacitor from pin 4 of the 2051 to ground.
o Connect an other 33 pF capacitor from pin 5 of the 2051 to ground.
For the 2051 reset circuit,
o Connect the 8.2k ohm resistor from pin 1 of the 2051 to ground.
o Connect the 10 uF capacitor from pin 1 of the 2051 to 5 volts.
The 2051 controls the analog to digital conversion process. The conversion process has several stages.
o Stage 1) to trigger (start) a new conversion, we must make pin 3 (Write) low and then return it
to the high state. The A/D will remain in the reset state as long as the (CS) and (Write) inputs
remain low. The conversion process starts when Write goes high (rising edge triggered).
o Stage 2) When the conversion process is complete, pin 5 (Interrupt) will make a High-to-Low
transition.
o Stage 3) When we see pin 5 (Interrupt) go Low; we must make pin 2 (Read or output enable)
low to load the new value into the outputs D0 - D7. Pin 2 can be grounded to constantly have
the latest conversion present at the output.
o For the first capacitor, the negative leg goes to ground and the positive leg goes to pin 16.
o For the second capacitor, the negative leg goes to 5 volts and the positive leg goes to pin 2.
o For the third capacitor, the negative leg goes to pin 3 and the positive leg goes to pin 1.
o For the fourth capacitor, the negative leg goes to pin 5 and the positive leg goes to pin 4.
o For the fifth capacitor, the negative leg goes to pin 6 and the positive leg goes to ground.
The MAX232 includes 2 receivers and 2 transmitters so two serial ports can be used with a single
chip. We will only use one transmitter for lab. The only connection that must be made to the 2051 is
one jumper from pin 3 of the 2051 to pin 11 of the MAX232.
To power the MAX232, Connect pin 16 to 5 volts, Connect pin 15 to ground.
To connect to the serial port of PC use a 9 pin female connector. There should be 3 wires soldered to
the DB9 connector pins 2, 3 and 5.
o Connect the wire from pin 5 of the connector to ground on the breadboard.
o Connect the wire from pin 2 of the connector to pin 14 of the MAX232. (The other wire is for
receiving and is not used in this lab)
The Software
Use the following code to program the microcontroller.
A conversion is started by clearing and setting P1.0 (The ADC0804s WR input).
Then the program sits in a loop waiting for the ADC0804 to finish the conversion and assert INTR at
P1.1
the data is read and sent to PC using serial communication.
#include <reg51.h>
#include "io.h"
sbit READ = P3^2; /* Define these according to how you have connected the */
sbit WRITE = P3^3; /* RD, WR, and INTR pins */
sbit INTR = P3^4;
READ = 1;
WRITE = 1;
INTR = 1;
while(1) {
Make sure the power is off to the circuit you have built.
Connect the circuit to the PC's serial port, Comm1. Turn on the power to the breadboard. The circuit
should send a continuous stream of values to the PC. To see the values on the PC.
Try this sample program. This program takes the received value and divides it by 51 to find the
corresponding voltage level. (The minimum value is 0 which is 0 volts and the maximum value is 255,
which is 5 volts.)
#include <lcd4bitx51.h>
#include <stdio.h> // Required for the function sprintf
void main()
{
unsigned char buffer[17], readValue=0,i;
float voltage;
P0 = 0xff; // Initialize port 0 to read external values
P0 = 0x00;
InitLCD_rimsDEV2763();
PrintLCD("Value read :");
while(1) {
for(i=0;i<100;i++) // Read 100 values and average them
readValue += P0;
readValue = readValue / 100;
In the above example, one thing to keep in mind is that the A to D converter is running in self-clocking and
free running mode. It automatically converts any analog signal applied to its input into 8-bit digital code at the
output. So you read 100 values and took their average, and then converted it back into the voltage format and
display it on the LCD.
M1 is a stepper taken from an old disk drive. There are five pins, i.e., common, coil 1, 2, 3 and 4. Resistance
measured between common pin and each coil is about 75 Ohms. Driving current for each coil is then needed
about 60mA at +5V supply. A darlington transistor array, ULN2003 is used to increase driving capacity of the
2051 chip. Each output provides 500mA max at 50V. P1.4 to P1.7, four output pins are connected to the input
of the ULN2003 as shown in the circuit. Four 4.7k resistors help the 2051 to provide more sourcing current
from the +5V supply. The serial port is optional for your exercises.
I have changed a 10ms time base with a simple TF0 polling instead of using interrupt. The program is just to
send the stepper's energizing pattern to the P1 every 10ms. Flag1 is used for intertask communication.
/* STEPPER.C */
#define n 400
/* flag1 mask byte
0x01 run cw()
0x02 run ccw()
*/
main(){
flag1=0;
serinit(9600);
disable(); /* no need timer interrupt */
cw_n = n; /* initial step number for cw */
flag1 |=0x01; /* initial enable cw() */
while(1){
tick_wait(); /* wait for 10ms elapsed */
energize(); /* round-robin execution the following tasks every 10ms */
cw();
ccw();
}
}
cw(){
if((flag1&0x01)!=0){
cw_n--; /* decrement cw step number */
if (cw_n !=0)
j++; /* if not zero increment index j */
else {
flag1&=~0x01; /* disable cw() execution */
ccw_n = n; /* reload step number to ccw counter */
flag1 |=0x02; /* enable cww() execution */
}
}
}
ccw(){
if((flag1&0x02)!=0)
{
ccw_n--; /* decremnent ccw step number */
if (ccw_n !=0)
j--; /* if not zero decrement index j */
else
{flag1&=~0x02; /* disable ccw() execution */
cw_n = n; /* reload step number to cw counter */
flag1 |=0x01; /* enable cw() execution */
}
}
}
tick_wait(){ /* cputick was replaced by simpler ASM code 10ms wait */
asm" JNB TCON.5,*"; /* wait for TF0 set */
asm" CLR TCON.5"; /* clear TF0 for further set */
asm" ORL TH0,#$DC"; /* reload TH0 with $DC, TL0 = 0 */
}
energize(){
P1 = step[(j&0x07)]; /* only step 0-7 needed */
}
Exercises
1. change the speed showing the rotation becomes faster or slower than 10ms time delay.
2. with an additional serial port, write an initializing function that receives ascii command from terminal
to set the number of step for cw and ccw.