Microprocessors and Microcontrollers: Unit III: (c) 8051 I/O Ports, Timer, Serial Port & Interrupts

I/O Bit Manipulation Programming

Let us see important points for programming I/O ports :

I/O Bit Manipulation Programming

AU : May-13

Let us see important points for programming I/O ports :

Port 0 has open drain outputs and hence to use this port as an input or an output it is necessary to connect external pull-up resistors (value 10 K) as shown in the Fig. 16.2.1.


Port 1, port 2 and port 3 do not require any pull-up resistors since they have internal pull-up resistors.

On reset, all ports are configured as an input ports.

If the ports are configured as an output ports, to make them input ports again, we have to write FFH (1 to all 8-bits) on these ports.

Now we will see simple programming examples to clearly understand the I/O concepts discussed above.

 

Example 16.2.1 Write a program to toggle all bits of PO continuously.

Solution :

BACK : MOV A, #0AAH ; Load AAH in the (A) accumulator

MOV P0, A          ; Send contents of A to port 0

A CALL Delay ; Wait for some time

MOV A, #55H ; Load 55H in the accumulator

MOV P0, A  ; Send contents of A to port 0

A CALL Delay ; Wait for some time

SJMP BACK ; Repeat

The same action can be implemented using following program code.

BACK : MOV PO, A ; Send contents of A on port 0

CPL A ; Complement contents         of port 0

A CALL Delay ; Wait for some time

SJMP Back ; Repeat

Note : I Like port 0, we can toggle all bits of P1, P2 or P3 by replacing the corresponding port instead of P0 in the above programs.

Example 16.2.2 Write a program to read the content of Pl and save it in R6 and also send it to P2.

Solution :  

MOV A, # 0FFH ;         A ← FFH

MOV Pl, A ; Make P1 as an input port by writing all 1's to it

MOV A, P1          ; Read data from P1

MOV R6, A         ; Save          it in R6

MOV P2, A          ; Send         it to P2

 

Example 16.2.3 Write an ALP to receive input from port P1.5 and if it is high then an output 35H is sent to port 0.

Solution :  

SETB P1.5 ;         Configure P1.5 as an input

JNB P1.5, LAST ; Skip next instruction if P1.5 is low

MOV P0, #35H ; Send 35H on P0

LAST : …

Programming I/O Ports using 8051C

Before going to see programming I/O ports using 8051C let us brief some important points about 8051C.

For 8051 microcontroller we need to include the file reg51.h. This file contains all the definitions of 8051 registers. With this information C compiler produces hex file that can be downloaded into the ROM of the microcontroller. It is important to note that the size of the hex file produced by the assembly language is much smaller than the hex file produced by the C compiler. Apart from this fact, there are many reasons for writing programs in C instead of assembly :

1. It is much easier and less time consuming to write programs in C than assembly.

2. C is more flexible; it is easier to modify and update.

3. Programming in C allows to use code available in function libraries.

4. Program written in C for one microcontroller is portable to other microcontrollers with little or no modifications.

Data Types in 8051C

The Table 16.2.1 lists the data types that are available in typical C × 51 compiler. The Table 16.2.1 gives the information about the size of the data variable and its value range.


Using the Appropriate Data Type

It is necessary to keep in mind that the code space for the 8051 is limited to 64 kbytes and it has limited on-chip ROM. Thus, it is necessary to look at the size of the created hex file. One way to keep the size of data file optimum is to use appropriate data type. The following points must be considered while selecting the data type.

• The unsigned char is an 8-bit data type. Thus, it must be used to store the value in the range of 0-255 (00-FFH). Since the 8051 is an 8-bit microcontroller, it is one of the most widely used data type.

• Use unsigned data type when there is no need for signed data.

• C compiler uses the signed data type as the default. Thus when we want to use unsigned data type, we must use unsigned keyword.

• S bit data type should be used to access bit addressable registers. It allows use to access single bits of the SFR registers.

• SFR data type should be used to access the byte size SFR registers.

Logical Operations in 8051C

One of the most frequent operations required in embedded applications is monitoring a single or a group of bits of a port, checking the status of a bit and controlling an external device connected to a bit of an output port. C allows logical operations such as AND, OR, Exclusive-OR as well as shifting a byte to the left and right. The Table 16.2.2 shown below provides the syntax for such operations.


 

Programming Examples

Example 16.2.4 Write an 8051 C program to send binary counter values from 00-FFH to port P1.

Solution :

#include <reg51.h>

void main(void)

{

unsigned char c;

for(c=0; c<=255; c++)

P1=c;

}

 

Example 16.2.5 Write an 8051 C program to send hex values for ASCII characters of 0, 1, 2, 3, A, B, C, X, Y and Z.

Solution :

#include <reg51.h>

void main (void)

{

unsigned char mychar[]="0123ABCXYZ";

unsigned char c;

for(c=0; c< = 10; c++)

P1=mychar [c];

}

Comment : Program displays values 30H, 31H, 32H, 33H, 41H, 42H, 43H, 58H, 59H and 5AH on port P1.

 

Example 16.2.6 Write an 8051 C program to toggle all the bits of port P0 and P1 continuously such that when P0 = FFH, P0 = 00 and vice-versa.

Solution :

#include <reg51.h>

void main(void)

{

for(;;)       /* repeat continuously */{

P0=0x00  ; /* [0X indicates data in */

P1=0xFF ; /* hex] */

NOP  ; /* [wait for some */

NOP  ; /* time] */

P0=0xFF ;

P1=0x00

NOP  ; /* [wait for some */

NOP ; /* time] */

}

}       

 

Example 16.2.7 Write an 8051 C program to send the sum of values – 12 and 15 to port P1.

Solution :

#include <reg51.h>

void main(void)

{

signed char i, j;

i = -12;

j = 15;

P1 = i + j;

}

 

Example 16.2.8 Write an 8051 C program to toggle bit 0 of the port P1 (P1.0) 20,000 times.

Solution :

#include <reg51.h>

shit PORTBIT = P1 ^ 0;          /* sbit is declared outside of main function */

void main(void)

{

unsigned int i;

for(i = 0; i< =20000; i++)

{

PORTBIT = 0;

PORTBIT = 1;

}

}

Comment: P1 ^0 represents bit 0 of port 1.

 

Example 16.2.9 Write an 8051 C program to flash LEDs 10 times.

Solution :

#include < reg51 .h >

void DELAY(void);

void main(void)

{

unsigned char N;

N=0;

do

{

P1=0xFF; /* Turn all LEDs ON */

DELAY(); /* Wait for some time */

P1=0x00;    /* Turn all LEDs OFF */

DELAY(); /* Wait for some time */

N=N+1;

} while(N<10);

}

void DELAY(void)

{

unsigned char i, j;

for(i=0; i< = 255; i=i+1)

 

{

for(j=0; j< =255; j=j +1)

{

;

}

}

}

Comment : Program illustrates the use of do-while loop.

Equivalent assembly language program

ORG 0

SJMP START

ORG 30H

START: MOV A,#00

MAIN: MOV P1, #0FFH

CALL DELAY

MOV P1, #00H

CALL DELAY

INC A

CJNE A, #10, MAIN

END

DELAY:     MOV R0,    #00H

LOOP1:      MOV R1,    #00H

LOOP2:      INC R1

CJNE R1,   #255, LOOP2

INC R0

CJNE R0, #255, LOOP1

RET


 

Example 16.2.10 Eight LEDs are connected to port 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 :

#include <reg51.h>

#define LED P2 /* define P2 as LED */

Void main(void)

{

LED=0; /*clear port P2 */

for(;;) /*repeat continuously */

{

LED++; /*increment P2 */

}

}

 

Example 16.2.11 Write an 8051 C program to get a byte of data from P1 and then send it to P2.

Solution :

#include <reg51.h>

#define INP P1

#define OUTP P2

void main(void)

{

unsigned char mybyte;

INP=0xFF; /*Configure port P1 as an input port */

while(l) {

{

mybyte = INP; /*read a byte from P1 */

OUTP = mybyte; } /*send it to P2 */

}

 

Example 16.2.12 Write an 8051 C program to read a byte of data from P0. If it is less than 50, send it to P1; otherwise, send it to P2.

Solution :

#include <reg51.h>

void main(void)

{

unsigned char mybyte ;

P0=0xFF; /* Configure port P0 as an input port */

mybyte=P0;  /* read a byte from P0 */

if(mybyte<50)

P1=mybyte; /* send it to Pl if less than 50*/

else

P2=mybyte; * send it to P2 if more than 50*/

}

 

Example 16.2.13 Write an 8051 C program to read the content of port P1. If it is greater than 200, wait for 250 msec and send the data to port P2. otherwise wait for 150 msec and send the data to port P0.

Solution :

#include <reg51.h>

void Delay (unsigned int);

void main (void)

{

unsigned char mybyte ;

P1=0XFF;   /* Configure port Pl as an input port */

mybyte=P1;          /* read a byte from P1 */

if(mybyte>200)

{

Delay (250); /* wait for 250 msec*/

P2=mybyte; /* send byte to port P2*/

}

else

{

Delay (150); /* wait for 150 msec*/

P0=mybyte; /* send byte to port P0*/

}

void Delay (unsigned int count)

{

unsigned int i, j;

for (i=0; iccount; i++)

for (j=0; j< 1200; j++)

}

}

 

Example 16.2.14 Write an 8051 C program to toggle only bit P0.5 continuously.

Solution :

/* toggling an individual bit */

#include <reg51.h>

sbit portbit = P0 ^ 5; /*declaration of single bit is using sbit/

void main(void)

{

while(l)

{

poitbit=l; /* turn on P0.5 */

poitbit=0; /* turn off P0.5 */

}

}

 

Example 16.2.15

Write an 8051 C program to monitor bit Pl.5. If it is high, send 00H to P0; otherwise, send 00H to P2.

Solution :

#include <reg51.h>

sbit portbit = P0 ^ 5; /* declaration of single bit using sbit */

void main(void)

{

portbit=l; /* configure mybit an input */

if(portbit= = l)

Pl =0x00;

else

P2=0xFF;

}

 

Example 16.2.16 Write an 8051 C program to send a given message, "My program" on the LCD connected to PO. Every time to latch the data into the LCD, it is necessary to make its enable (En) pin from high to low.

Solution :

#include <reg51.h>

#define LCD Data P0 s

bit En=P1^y0;

void main(void)

{

unsigned char message[] ="My program";

unsigned char C;

for(C=0; C<10; C++)     /* send 10 characters */

{

LCD Data = message [c];

En=l; /* Make En high */

En=0; /* Make En Low */

}

}

 

Example 16.2.17 Write an 8051 C program to toggle all the bits of P0 and P2 continuously with a some delay. Use the sfr keyword to declare the port addresses.

Solution : #include <reg51.h>

/* Accessing ports as SFRs using the sfr data type */

sfr P0 = 0x80;      /* declaration of P0 using sfr data type */

sfr P2 = 0xA0;     /*declaration of P2 using sfr data type */

void Delay (unsigned int);

void main(void)

{

while(1) /* read it continuously */

{

P0=0x55;

P2=0x55;

Delay(250); /* delay */

P0=0xAA;

P2=0xAA;

Delay(250);

}

}

void Delay (unsigned int count)

{

unsigned int i, j;

for (i=0; i<count; i++)

for (j=0; j < 1200; j++)

}

 

Example 16.2.18 Write an 8051 C program to turn bit P0.5 on and off 10,000 times.

Solution:

sbit PORTBIT = 0x85; /* another way to declare bit P0^5 */

void main(void)

{

unsigned int i;

for(i=0; i<10000; i++)

{

PORTBIT=1;

PORTBIT=0;

}

}

 

Example 16.2.19 Write an 8051 C program to get the status of bit P0.0, complement it and send it to P1.5 continuously.

Solution :

#include <reg51.h>

sbit inbit = P0^0;

sbit outbit = P1^5;

bit tempbit;

void main(void)

{

while(1)

{

tempbit = inbit; /* read a bit from P0.0 */

if(tempbit==1) /* complement the bit */

tempbit=0;

else

tempbit=1;

outbit tempbit; /*send it to P1.5 */

}

}

 

Example 17.2.20 To illustrate some of the above operations, let us write a program that monitors switch S0 and when pressed, it flashes the single LED0 ten times.

Solution :

#include <reg51.h>

void DELAY (unsigned int);

sbit S0 = P0^0; /* switch is connected to port 0.0 */

sbit LED = P1^0; /* LED is connected to port P1.0 */

unsigned char c; 

void main(void)

{

S0 = 1; /* Configure P0.0 an input */

do /* Check whether S0 is pressed or not */

{

}

while (S0 = = 0);

for (c=0; c<20; c++) /* flash LED ten times */

{

LED = ~LED;/* invert the status of LED */

DELAY(1500);

}

}

void DELAY (unsigned int count)

{

unsigned int i, j;

for (i=0; i< count; i++)

for (j=0; j < 1200; j++)

:

}

 

Example 16.2.21 In a home guard system, a door sensor is connected to the P1.0 pin, window sensor is connected to the P1.1 pin, and the a siren is connected to P2.0. Write an 8051 C program to monitor the door and window sensor. When any one gets open, sound the siren. We can sound the siren by sending a square wave of a few hundred Hz.

Solution :

#include <reg51.h>

void DELAY (unsigned int);

shit Dsensor = Pl ^ 0;

shit Wsensor = Pl ^1;

shit Siren = P2 ^ 0;

void main (void)

{

Dsensor =1 /* Configure P1.0 and P1.1 an input */

Wsensor = 1

while(Dsensor= = l Wsensor= = l)

{

siren = ~ siren ;    /* invert the status of siren*/

DELAY(150);

}

}

void DELAY (unsigned int count)

{

unsigned int i,j;

for (i=0; i<count; i++)

for (j=0; j< 1200; j++)

;

}

 

 Example 16.2.22 Write an 8051 C program to toggle all the bits of P0 and P2 continuously with a some delay. Use the Ex-OR operator.

Solution :

#include <reg51.h>

void Delay (unsigned int);

void main (void)

{

P0=0x55;

P2=0x55;

while(l)

{

P0=P0^0xFF;

P2=P2^0xFF;

Delay(250);

}

}

void Delay(unsigned int count)

{

unsigned int i,j;

for (i=0; iccount; i++)

for (j=0; j < 1200; j++)

;

}

 

Example 16.2.23 Write an 8051 C program to get bit P1.0 and send it to P2.7 after inverting it.

Solution :

#include <reg51.h>

sbit inbit = P0^ 0;

sbit outbit = P1 ^ 5; /*sbit is used to declare port (SFR) bits*/

bit tempbit; /*It is bit-addressable memory*/

void main(void)

{

while(1)

{

tempbit=inbit; /*read a bit from P0.0 */

outbit=~tempbit; /*invert it and send it to Pl.5 */

}

}

 

Example 16.2.24 Write an 8051 C program to read the P1.0 and P1.1 bits and issue an ASCII character to P0 according to the status of bits given in the following Table 16.2.3.


Solution :

#include <reg51.h>

void main(void)

{

unsigned char c

c=P1; /* read P1 */

c = c & 0x3; /* mask the unused bits, i.e. ADD C with 00000011 */

switch(c) /* make decision */

{

case (0):

{

P0='A'; /* issue ASCII A */

break;

}

case (1) :

{

P0='B’; /* issue ASCII B */

break;

}

case (2):

{

P0='C’; /* issue ASCII C */

break;

}

case (3):

{

P0='D'; /* issue ASCII B */

break;

}

}

}

 

Example 16.2.25 Write an 8051 C program to convert ASCII digits of two keys '5' and '6' to packed BCD and display them on P1.

Solution :

Procedure

To convert ASCII to packed BCD, it is first converted to unpacked BCD, and then combined to make packed BCD. For example, on pressing keys 5 and 6 keyboard gives 35H and 36H, respectively. Let see the conversion process :


Program

#include <reg51.h>

void main(void)

{

unsigned char K1 = '5';

unsigned char K2 = '6';

K1 = K1 & 0x0F; /*Apply mask pattern to get unpacked BCD*/

K2 = K2 & 0x0F; /*Apply mask pattern to get unpacked BCD*/

K1 = K1 >> 4; /* Shift 4 times so that lower nibble ^ upper nibble */

P1 = K1 K2 ; /* Make packed BCD */

 

Example 16.2.26 Write an 8051 C program to convert packed BCD 0x47 to ASCII and display the bytes on P1 and P2.

Solution :

Procedure

To convert packed BCD to ASCII conversion, it is first converted to unpacked BCD, and then ORed each BCD with 30H to get ASCII bytes. For example, 0100 0111 packed BCD can be converted to ASCII as shown in the Table 16.2.4.


Program

#include <reg51.h>

void main(void)

{

unsigned char x, y, z;

unsigned char PBCD = 0x47;

x = PBCD & 0x0F; /* mask lower 4 bits */

P1 = x | 0x30; /* make it ASCII */

y = PBCD & 0xF0; /* mask upper 4 bits */

y = y > > 4; /* shift it to lower 4 bits */

P2 = y | 0x30; /* make it ASCII */

}

 

Example 16.2.27 Write an 8051 C program to convert 1111 1011 (FBH) to decimal and then ASCII, and display the digits on P0 sequentially (MSD first).

Solution :

Procedure

One way to convert binary number to decimal is to divide it by 10 successively and keep the remainders. This is illustrated in Fig. 16.2.3. The first remainder gives the LSD and last remainder gives the MSD. These digits are then added with 30H to get the ASCII equivalent.


Algorithm

1. Divide the number by 10 and save the remainder.

2. Save the quotient as a number.

3. Repeat steps 1 and 2 until quotient is 0.

4. Retrieve each remainder and add 30H to convert it to ASCII.

Program

#include <reg51.h>

void main (void)

{

unsigned char Abyte, i,Q;


Example 16.2.28 a) Find the checksum byte for the hexadecimal data : 18H, 5AH, 46H and 69H. b) Perform the checksum to ensure data integrity, c) With an example show how checksum detects the error.

Solution : To ensure the data integrity of the ROM contents, one extra byte is stored at the end of a series of data bytes called checksum byte. This byte is calculated by performing two operations :

• Add all data bytes without considering carry.

• Take 2's complement of the resulted sum.

a) Let us find the checksum byte

18H + 5AH + 46H + 69H = 121H

Ignoring carry we have stun = 21H. Taking 2's complement we have checksum byte = DFH.

b) To ensure data integrity all the bytes including checksum byte are added. Ignoring the carry if sum is OOH then the data integrity is ensured. Let us check this

18H + 5AH + 46H + 69H + DFH = 200H

Ignoring carries we have sum equal to zero and therefore, we can say that data is valid and not corrupted.

c) Let us consider that the last of data is corrupted and it is now 68H instead of 69H. By adding all byte with checksum byte we get,

18H + 5AH + 46H + 68H + DFH = 1FFH

Ignoring carry in the sum, result is not zero and hence we can say that data is corrupted.

 

Example 16.2.29 Write an 8051 C program to find the checksum byte of data stream 30H, 4AH, 65H and 10H. Convert the binary value of checksum into decimal and display the value of the BCD digits on ports PO, P1 and P2.

Solution :

#include <reg51.h>

void main (void)

{

unsigned char data[] = {0X30,0X4A,0X65,0X10};

unsigned char sum=0;

unsigned char chksumbyte,i, d1, d2, d3;

for(i=0; i<4; i++)

{

sum=sum+data[i]; /* since sum is declared as byte data type, carries are ignored automatically */

}

chksumbyte = ~ sum+1; /*Take 2's complement*/

i = chksumbyte / 10; /‘divide by 10*/

d1 = chksumbyte % 10; /*store the remainder (LSD)*/

d2 = i % 10; /*store middle digit*/

d3 = i/10; /*store most significant digit*/

P0 = d1; /* send LSD to P0*/

P1 = d2; *send middle digit to P1*/

P2 = d3; /*send MSD to p2*/

}

 

Example 16.2.30 Write an 8051 C program to send byte 24H serially one bit at a time via P2.0. Send LSB first.

Solution :

#include <reg51.h>

sbit outbit = P2 ^ 0;

sbit ALSB = ACC ^ 0;

void main (void)

{

unsigned char mybyte = 0x24;

unsigned char i;

ACC = mybyte;

for (i=0; i<8; i++)

{

outbit = ALSB;

ACC = ACC > >1;

}

}


 

Example 16.2.31 Write an 8051 C program to send byte 24H serially one bit at a time via P2.0. Send MSB first.

Solution :

#include <reg51.h>

sbit outbit = P2 ^ 0;

sbit AMSB = ACC ^7;

void main (void)

{

unsigned char mybyte = 0x24;

unsigned char i;

ACC = mybyte;

for (i=0; i<8; i++)

{

outbit = AMSB;

ACC = ACC<<1;

}

}


 

Example 16.2.32 Write an 8051 C program to receive byte serially one bit at a time via P2.0. The first bit is LSB.

Solution :

#include c reg51.h>

shit inbit = P2 ^ 0;

shit AMSB = ACC ^7;

void main (void)

{

unsigned char i;

for (i=0; i<8; i++)

{

AMSB = inbit;

ACC = ACC>>1;

 }

}


 

Example 16.2.33 Write an 8051 C program to receive byte serially one bit at a time via P2.0. The first bit is MSB.

Solution :

#include <reg51.h>

shit inbit = P2 ^ 0;

shit ALSB = ACC^0;

void main (void)

{

unsigned char i;

for (i=0; ic8; i++)

{

ALSB = inbit;

ACC = ACC<<l;

}

}


 

Example 16.2.34 Write an 8051 C program to perform data integrity check for data given in example. If data is not corrupted, send ASCII character 'V (valid) on port P1; otherwise send 'C (corrupted) on port P1.

Solution :

#include <reg51.h>

void main (void)

{

unsigned char data[] = {0X18,0X5A,0X46,0X69,OXDF};

unsigned char chksum=0;

unsigned char i;

for(i=0; i<5; i++)

{

chksum=chksum+data[i];

}

if (chksum = =0)

P1='V';

else

P1='C’;

}

 

Example 16.2.35  Write an 8051 C program to toggle all the bits of P1, P2 and PO continuously with a 250 ms delay. Use SFR keyword to declare the port addresses.

Solution :

#include reg51.h>

void Delay (void);

void main (void)

{ while (1) /* Repeat continuously */

{

P0=0x 55; /* toggle all bits of P0 */

pl=0 x 55; /* toggle all bits of Pl */

P2=0x 55; /* toggle all bits of P2 */

Delay (250); /* wait for 250 ms */

P0=0x AA ; /* toggle all bits of P0 */

Pl=0x AA ; /* toggle all bits of Pl */

P2=0x AA ; /* toggle all bits of P2 */

Delay (250) }/* wait for 250 ms */

}

void Delay (unsigned int count)

{

unsigned int i,j;

for (i=0; i < count; i++)

for (j=0; j < 1275; j ++);

}

 

Example 16.2.36 Write a C-program to toggle all bits of PO and P2 continuously with 250 msec delay. Use inverting operator.

Solution :

#include < reg51 .h >

void MSDelay (unsigned int);

void main (void)

{

P0 = 0x55;

P2 = 0x55;

while (1)

{

P0 = ~P0;

P2 = ~P2;

MSDelay (250);

}

}

void MSDelay (unsigned int count)

{

unsigned int i, j;

for (i = 0; i < count; i++)

for (j = 0; j < 1275; j++)

}

 

Example 16.2.37 Write a 8051 C-program to convert a given hex-data OFF into its equivalent decimal data and display the result digits on P0, 1l and P2.

Solution :

#include < reg51 .h >

void main(void)

{

unsigned char x, binbyte, d1, d2, d3;

binbyte = 0xFF;

x=binbyte/10;

d1 =binbyte%10;

d2 = x%10;

d3 = x/10;

P0=d1;

P1=d2;

P2=d3;

}

Microprocessors and Microcontrollers: Unit III: (c) 8051 I/O Ports, Timer, Serial Port & Interrupts : Tag: : - I/O Bit Manipulation Programming