Embedded Systems

    It will not be wrong if i would say for a man in a day of today's life he will be coming in touch with more then 5-10 different kind of embedded systems although he is completely unaware of that. Amazed !!!!!!.... But this is really true. Embedded systems are so much penetrated in human life that no one has ever imagine. Cell phones, PDAs, IPODs, TV, music systems, car or any other automobile, toys, virtual reality based games, refrigerators, ACs, washing machines, microwaves and almost all other home appliances are now equipped with either light or heavy embedded system. For the industries embedded system is vital part. Robotics, CNC machines, motion controllers, AC/DC drives, stepper motor controller, PLC based automation, sensors, rectifiers, invertors, etc all are very good example of embedded systems.  And how can we forget military, satellite and space applications? One can not imagine these applications without embedded systems. Missile technology, high explosive bombs, fighter planes, tanks, rocket technology, different satellites all these become possible because of embedded system.
    So now when we have understood the importance of embedded systems in domestic as well as industrial applications, one will be curious to know what is this embedded system ?  In a wide sense Embedded system is a combination of software and hardware designed and programmed to perform one/more particular task(s).The hardware is designed for specific application and then software is embedded in this hardware to perform the task. Both software and hardware are dedicated to that particular application. The heart of the system is either processor or controller. Processor / controller may be general purpose or special purpose that controls whole system. There may be more then one processor/controller if system is complex. It may be possible that there is one general purpose processor / controller and one or more special purpose processors / controllers. For example in 3G (or 4G) cell phones there is one general purpose processor that handles user commands, memory and display etc. And there are special purpose processors like DSP for voice communication and network management, display controller to generate real and reach images on color LCD screen.
     
    To get better idea of these systems let us understood this by some examples.
    Example 1 - TV: - now a days TVs are coming with advance features like auto volume control, auto brightness and contras control etc. In auto volume control there is a set value of volume set by user. So the TV will always see the input audio signal strength and compare with this set value. If it doesn't match it will either increase or decrease it so volume will be automatically set. So when ever you change the channel in your TV you need not to change volume. In second feature there is a light sensor in TV that sees room light. It detects the room light and gives the signal to internal processor. Processor process the information and automatically adjust the brightness and contras to get the best viewing result.
    Example 2 - AC: - The AC with automatic temperature control is another example of embedded system. Once the temperature is set by user to some value AC will try to keep this temperature in room. If the temp goes down then for some time the compressor will be off. Again when temp increases above specified limit compressor will be on.  
    Example 3 - motion control: - if you want to see the example of any industrial application then motion control will the perfect one. The speed of AC/DC motor is kept constant using embedded system. The speed of motor is set depending upon application requirement. This set value is sensed by sensor and given to controller or processor. Now if the speed of motor changes suddenly then this value is feedback to controller/processor and it will compare the value with set one. Then it will increase or decrease the speed of motor to match it with set value.
    Example 4 - missile technology: - most of surface to surface or air to surface missile have technology to automatically lock their target. Initially the co-ordinates, digital image, digital map is fed into the missile controller. The missile will automatically create its virtual path from source to destination. After launch it will continuous track its path and it will be continuously guided by GPS. If there is any deviation in set path then controller will again divert the missile to right path by making suitable corrections and taking guidance by GPS. Before final few minutes of explosion it will take a picture of target and compare it with digital image make final few correction to hit exact target and finally BOOM BOOM !!!!!!!!........It's always Bulls Eye.
    Here I have illustrated some of the example which is purely industrial applications. In most of the manufacturing industries these kind of systems are always exists. I have used 89C51 micro-controller as main part. Embedded C is used to program micro-controller as in the industries assembly language is not so popular as embedded C. Micro vision keil(IDE) is used as cross compiler to provide integrated development environment (IDE). Keil provides the platform to to write the assembly language programs of many kind of controllers in standard C language. When you compile the program it will generate hex file that can be directly loaded into target controller. The latest version of keil supports almost all kind of controllers from Atmel, Dallas, Maxim, Phillips, Samsung, etc. If anyone is new voice and not familiar with keil then please first go through these links
    introduction to keil
    sample programs in keil
    interfacing programs in keil
    Introduction to Micro vision Keil (IDE)
    Keil is a cross compiler. So first we have to understand the concept of compilers and cross compilers. After then we shall learn how to work with keil.
    Concept of compiler: -
    Compilers are programs used to convert a High Level Language to object code. Desktop compilers produce an output object code for the underlying microprocessor, but not for other microprocessors. I.E the programs written in one of the HLL like ‘C’ will compile the code to run on the system for a particular processor like x86 (underlying microprocessor in the computer). For example compilers for Dos platform is different from the Compilers for Unix platform
    So if one wants to define a compiler then compiler is a program that translates source code into object code. The compiler derives its name from the way it works, looking at the entire piece of source code and collecting and reorganizing the instruction. See there is a bit little difference between compiler and an interpreter. Interpreter just interprets whole program at a time while compiler analyzes and execute each line of source code in succession, without looking at the entire program.
    The advantage of interpreters is that they can execute a program immediately. Secondly programs produced by compilers run much faster than the same programs executed by an interpreter. However compilers require some time before an executable program emerges. Now ascompilers translate source code into object code, which is unique for each type of computer, many compilers are available for the same language.
    Concept of cross compiler: -
    A cross compiler is similar to the compilers but we write a program for the target processor (like 8051 and its derivatives) on the host processors (like computer of x86)
    It means being in one environment you are writing a code for another environment is called cross development. And the compiler used for cross development is called cross compiler
    So the definition of cross compiler is a compiler that runs on one computer but produces object code for a different type of computer. Cross compilers are used to generate software that can run on computers with a new architecture or on special-purpose devices that cannot host their own compilers. Cross compilers are very popular for embedded development, where the target probably couldn't run a compiler. Typically an embedded platform has restricted RAM, no hard disk, and limited I/O capability. Code can be edited and compiled on a fast host machine (such as a PC or Unix workstation) and the resulting executable code can then be downloaded to the target to be tested. Cross compilers are beneficial whenever the host machine has more resources (memory, disk, I/O etc) than the target.  Keil C Compiler is one such compiler that supports a huge number of host and target combinations. It supports as a target to 8 bit microcontrollers like Atmel and Motorola etc.
    Why do we need cross compiler?
    There are several advantages of using cross compiler. Some of them are described as follows
             By using this compilers not only can development of complex embedded systems be completed in a fraction of the time, but reliability is improved, and maintenance is easy.
             Knowledge of the processor instruction set is not required.
             A rudimentary knowledge of the 8051’s memory architecture is desirable but not necessary.
             Register allocation and addressing mode details are managed by the compiler.
             The ability to combine variable selection with specific operations improves program readability.
             Keywords and operational functions that more nearly resemble the human thought process can be used.
             Program development and debugging times are dramatically reduced when compared to assembly language programming.
             The library files that are supplied provide many standard routines (such as formatted output, data conversions, and floating-point arithmetic) that may be incorporated into your application.
             Existing routine can be reused in new programs by utilizing the modular programming techniques available with C.
             The C language is very portable and very popular. C compilers are available for almost all target systems. Existing software investments can be quickly and easily converted from or adapted to other processors or environments.
    Now after going through the concept of compiler and cross compilers lets we start with Keil C cross compiler.
    Keil C cross compiler: -
    Keil is a German based Software development company. It provides several development tools like
             IDE (Integrated Development environment)
             Project Manager
             Simulator
             Debugger
             C Cross Compiler , Cross Assembler, Locator/Linker
    Keil Software provides you with software development tools for the 8051 family of microcontrollers. With these tools, you can generate embedded applications for the multitude of 8051 derivatives. Keil provides following tools for 8051 development
    1.     C51 Optimizing C Cross Compiler,
    2.     A51 Macro Assembler,
    3.     8051 Utilities (linker, object file converter, library manager),
    4.     Source-Level Debugger/Simulator,
    5.     ÂµVision for Windows Integrated Development Environment.
    The keil 8051 tool kit includes three main tools, assembler, compiler and linker.
    An assembler is used to assemble your 8051 assembly program
    A compiler is used to compile your C source code into an object file
    A linker is used to create an absolute object module suitable for your in-circuit emulator.
    8051 project development cycle: - these are the steps to develop 8051 project using keil
    1. Create source files in C or assembly.
    2. Compile or assemble source files.
    3. Correct errors in source files.
    4. Link object files from compiler and assembler.
    5. Test linked application.
    now let us start how to work with keil.
    working with keil: -
    to open keil software click on start menu then program and then select keil2 (or any other version keil3 etc. here the discussion is on keil2 only). Following window will appear on your screen
        
     you can see three different windows in this screen. 1) project work space window 2) editing window 3) output window.
    Project workspace window is for showing all the related files connected with your project.
    Editing window is the place where you will edit the code
    Output window will show the output when you compile or build or run your project.
    Now to start with new project follow the steps
    • click on project menu and select new project
    • you will be asked to create new project in specific directory
    • just move to your desired directory and there create a new folder for your project named "first". Here I am creating new project in d:\keil2\myprojects\first as shown in figure
    •  
    •  give the name of project as "test". By default it will be saved as *.v2 extension.
    • now you will be asked to chose your target device for which you want to write the program.
    • scroll down the cursor and select generic from list. expand the list and select 8051 (all variants)
    •  
    • when you click OK, you will be asked to add startup code and file to your project folder. click yes. Now on your screen expand target1 list fully. You will see following window.
    • now click on file menu and select new file. editor window will open. Now you can start writing your code.
    • as you start writing program in C, same way here also you have to first include the header file. Because our target is 8051 our header file will be "reg51.h"
    • after including this file. just right click on the file and select open document <reg51.h>. The following window will appear
    •  
    • if you scroll down cursor you will see that all the SFRs like P0-P3, TCON, TMOD, ACC, bit registers and byte registers are already defined in this header file. so one can directly use these register names in coding
    • now you can write your program same as c language starting with void main()
    • after completing the code save the file in project folder with ".c" extension.
    • now right click on "source group 1" in project workspace window. select "add files to source gorup 1"
    • select the C file you have created and click add button
    •     
    • you will see that the c file has been added in source group
    • now to compile the program from project menu select "build target". In the output window you will see the progress
    • if there is any compilation error then target will not be created. Remove all the errors and again build the target till you find "0 Error(s)"
    • now you are ready to run your program. from debug menu select "start/stop debug session"
    • you will see your project workspace window now shows most of the SFRs as well as GPRs r0-r7. also one more window is now opened named "watches". in this window you can see different variable values. 
    • to add variable in watch window goto "watch#1" tab. then type F2 to edit and type the name of your variable
    • if you want to see the output on ports go to peripheral menu and select I/O ports. select the desire port. you can give input to port pins by checking or unchecking any check box. here the check mark means digit 1 and no check mark means 0. the output on the pin will be shown in same manner
    • to run the program you can use any of the option provided "go", "step by step", "step forward", "step ove" etc.
    • now after testing your program you need to down load this program on your target board that is 8051. for this you have to create hax file
    • to create hex file first stop debug session. Again you will be diverted to project workspace window.
    • right click on "target 1" and select "option for target 1". Following window will appear.
    •  
    • select output tag and check "create hex file" box
    • now when you again build your program you will see the message in output window "hex file is created".
    • in your project folder you can see the hex file with same name of your project as "test.hex".
    • this file you can directly load in 8051 target board and run the application on actual environment.
    So here I have described the procedure to create a project in keil for 8051 micro controller. To see some sample programs for 8051 in keil just go through the link "sample programs in keil" so that you can get the idea how to write a program for 8051 in keil C.
    ~: Sample Programs in Keil for 8051 :~
    example-1: generate a square wave of 100 Hz at pin P1.0 of 8051 using timer
    #include <reg51.h>               // include 8051 register file sbit pin = P1^0;                    // decleare a variable type sbit for P1.0 main() {       P1 = 0x00;                     // clear port       TMOD = 0x09;                // initialize timer 0 as 16 bit timer loop:TL0 = 0xAF;                  // load valur 15535 = 3CAFh so after       TH0 = 0x3C;                   // 50000 counts timer 0 will be overflow        pin = 1;                        // send high logic to P1.0        TR0 = 1;                       // start timer        while(TF0 == 0)  {}       // wait for first overflow for 50 ms
           TL0 = 0xAF;                 // again reload count        TH0 = 0x3C;        pin = 0;                       // now send 0 to P1.0       while(TF0 == 0)  {}       // wait for 50 ms again    goto loop;                         // continue with the loop  }
    example-2: write a program to make 8 to 1 multiplexer with enable signal
    #include<reg51.h>
    sbit D0 = P0^0;                     // set P0.0-P0.7 (D0-D7) as input pins of mux sbit D1 = P0^1; sbit D2 = P0^2; sbit D3 = P0^3; sbit D4 = P0^4; sbit D5 = P0^5; sbit D6 = P0^6; sbit D7 = P0^7; sbit S0 = P1^0;                 // set P1.0-P1.2(S0-S2) as select pins of mux sbit S1 = P1^1; sbit S2 = P1^2; sbit EN = P1^7;                // set P1.7 as enable pin sbit pin = P3^5;               // set P3.5 as output 
    main() {          P3=0x00;P0=0xFF;      // clear op and set all ips         TMOD = 0x01;              // set timer 0 for 16 bit timer  next:TL0 = 0xAF;                 // load count         TH0 = 0x3C;         while(EN==1){}           // wait till enable pin becomes 0    if((S0==0)&&(S1==0)&&(S2==0)) pin = D0;                  // if select inputs are 000 op is first ip    else if((S0==1)&&(S1==0)&&(S2==0)) pin = D1;           // if select inputs are 001 op is second ip    else if((S0==0)&&(S1==1)&&(S2==0)) pin = D2;           // same as above    else if((S0==1)&&(S1==1)&&(S2==0)) pin = D3;    else if((S0==0)&&(S1==0)&&(S2==1)) pin = D4;    else if((S0==1)&&(S1==0)&&(S2==1)) pin = D5;    else if((S0==0)&&(S1==1)&&(S2==1)) pin = D6;    else if((S0==1)&&(S1==1)&&(S2==1)) pin = D7;      else pin = 0;                                                                 // by default op is cleared    TR0 = 1;                                                                      // start timer 0    while(TF0==0){}                                                          // wait until overflow means 50ms    TR0 = 0;                                                                      // stop timer    goto next;                                                                    // go for next input }  
    Example-3: take parallal input from port P1 convert it into serial and send it via P0.0
    #include<reg51.h> sbit sout = P0^0;                          // serial out on P0.0 sbit D0 = P1^0;                            // parallal input from P1 (D0-D7) sbit D1 = P1^1; sbit D2 = P1^2; sbit D3 = P1^3; sbit D4 = P1^4; sbit D5 = P1^5; sbit D6 = P1^6; sbit D7 = P1^7; int i; void delay(void);                         //  1 ms delay main()   {     for(i=0;i<8;i++)                   // rotate loop for 8 times       {         sout = D0;                       // first bit out         D0 = D1;                         // shift all bits in sequence         D1 = D2;         D2 = D3;         D3 = D4;         D4 = D5;         D5 = D6;         D6 = D7;         delay();                           // generate 1 ms delay after each bit shifted       }    } void delay()   {     int k     for(k=0;k<1000;k++);   } 
    Example-4: write a program to symulteneously transmit and receive data.
    #include <reg51.h> main()  {        TMOD=0x20;          // set timer1 in 16 bit timer mode        SCON=0x40;          // initialize serial communication        TL1=0xFD;             // load timer 1 to generate baud rate of 96KBps        TH1 = 0xFD;        TR1 = 1;               // start timer 1  loop:REN = 1;               // enable reception       while(RI==0){}       // wait until data is received       RI=0;                     // clear receive flag       ACC = SBUF;          // get data in to acc       REN = 0;                // now disable reception       SBUF = ACC;          // start transmission       while(TI==0){}       // wait until data transmitted       TI=0;                    // clear transmission flag         goto loop;              // continue this cycle 
    }
    example-5: detect an external interrupt on P3.2 and P3.3. indicate on LEDs connected on P0.0 & P0.1
    #include<reg51.h> sbit op1=P0^0;                             // LED1 as output on P0.0 sbit op2=P0^1;                             // LED2 as ouput on P0.1 void delay(void);                           // 10 ms delay
    void intrupt0(void) interrupt 0        // ext interrupt 0 vector {   op1=0;                                     // indication on LED1   delay();   op1=1; }
    void intrupt1(void) interrupt 2        // ext interrupt 1 vector {   op2=0;                                     // indication on LED2   delay();   op2=1; }
    void delay()                                 // delay for 10 ms {   int x;   for(x=0;x<10000;x++); }
    void main() {   P0=0xFF;                                 // send all 1's to P0   IE=0x85;                                  // enable both ext interrupts   while(1);                                 // continuous loop }
    Example-6: blink a LED on P2.0 for 5 second using timer 1
    #include<reg51.h> int c=0;                                  // initialize counter to 0 sbit LED= P2^0;                      // LED connected to P2.0 void timer1(void) interrupt 3     // timer 1 overflow vactor   {      TF1=0;                             // clear overflow flag       c++;                                 // increment counter      if(c==100)                        // if 100 counts of 50 ms(= 5 sec) are over           {            TR1=0;                      // stop timer            LED=0;                      // LED off           }      TH1=0x3C;                      // other reaload timer 1 with      TL1=0xAF;                      // 15535 to count 50 ms    }
    void main()   {          P2=0x00;                   // clear op         TMOD=0x90;               // set timer 1         TH1=0x3C;                 // load count 15535         TL1=0xAF;
            IE=0x88;                    // enable timer 1 interrupt         LED=1;                      // LED on         TR1=1;                     // timer 1 start         while(1);                   // continuous loop    }
    Example 7: send ultrasonic wave through P1.0 and receive its echo through P3.2. generate an interrupt. calculate the distance of object.
    #include <reg51.h> sbit tx = P1^0; // transmitter pin int c=0,d=0; // counter and distance void tmr0(void) interrupt 1 // timer 0 interrupt vector    {       TF0=0;                       // clear timer flag       c++;                          // increment counter       TL0 = 0xAF;               // reload values       TH0 = 0x3C;    } void int0(void) interrupt 0 // ext interrupt 0 vector    {        TR0 = 0;                  // stop timer        d = c*30;                // get distance = time*velocity    } main()     {          IE=0x83;             // enable interrupts          IP=0x01;            // high priority for ext interrupt          TMOD = 0x01;    // timer 0 as 16 bit timer          P1 = 0x00;        // clear op port          TL0 = 0xAF;       // load values for 50 ms          TH0 = 0x3C;           tx = 1;             // enable transmission           TR0 = 1;          // start timer           while(1);
    }
    Example 8: take input from P0. count no of 1 in input
    #include <reg51.h> sbit D0 = B^0; // define D0-D7 as bits of reg B sbit D1 = B^1; sbit D2 = B^2; sbit D3 = B^3; sbit D4 = B^4; sbit D5 = B^5; sbit D6 = B^6; sbit D7 = B^7; unsigned bdata reg; // define reg as bit addressable variable sbit b = reg^0; // define b as bit 0 of reg void main()      {          unsigned int i,c=0; // initialize counter          B=P0; // take input from P0 to B          b=0;          for(i=0;i<8;i++) // rotate bits of reg B               { // 8 times                    b=D7;                    D7=D6;                    D6=D5;                    D5=D4;                    D4=D3;                    D3=D2;                    D2=D1;                    D1=D0;                    if(b==1)c++; // check every bit if 1               }            while(1); // loop continue         }
    Example 9: connect key with P3.2. using interrupt count no of key press and display it on common anode seven segment display connected to P0.
    #include<reg51.h> unsigned int c=0,x=0; //initialize key counter and key flag void extint0(void) interrupt 0    {       x=1;                       // set key flag       c++;                      // increment key count       if(c==9)                 // if its 9          {            c=0;                // reset it to 0 and            P0=0xC0;         // display 0          }      } void main(void)     {            IE=0x81;         // enable ext int 0            P0=0xC0;        // display 0     loop:while(!x);      // check key flag            switch(c)       // if it is set get the count                   {                     case 1:                         P0=0xF9; // display digit from 1 to 9                         break;                     case 2:                         P0=0xA4;                         break;                    case 3:                        P0=0xB0;                        break;                    case 4:                        P0=0x99;                        break;                  case 5:                       P0=0x92;                       break;                  case 6:                       P0=0x82;                       break;                  case 7:                       P0=0xF8;                       break;                  case 8:                       P0=0x80;                       break;                  case 9:                       P0=0x90;                       break;                 }        x=0; // clear key flag        goto loop; // loop continue }
    Example 10: connect 8 keys with P1. detect keypress and display number on CA 7 segment display connected to P0.
    #include<reg51.h> void main(void)     {         loop:P1=0xFF;                 // send all 1's to P1                     while(P1==0xFF);            // remain within loop till key is not pressed          switch(P1)                    // when key pressed detect is              {                  case 0xFE:                        P0=0xF9; // and display digit from 1 to 8                        break;                   case 0xFD:                        P0=0xA4;                        break;                   case 0xFB:                        P0=0xB0;                        break;                   case 0xF7:                        P0=0x99;                         break;                   case 0xEF:                        P0=0x92;                        break;                    case 0xDF:                        P0=0x82;                         break;                   case 0xBF:                         P0=0xF8;                         break;                    case 0x7F:                         P0=0x80;                         break;                     }                goto loop;
            }
                          
                                  ~: Keil interfacing programs for 8051 :~
    After going through sample programs in keil now, you should be aware of how to write simple codes in C language for 8051. So now, let us see some more programs in C language for 8051. These programs are interfacing programs means different peripheral devices are connected with 8051 and we have to write the C program to properly interface these devices with it. different devices are push buttons, keypad, LEDs, 7-segment display, LCD, ADC, DAC etc. here I am not giving the schematic diagrams of interfacing but just a short description of hardware connection is given that tells how the device is connected with 8051.  
    LED Interfacing:
    Hardware:- total 32 LEDs are connected one with each i/o line. Anodes of all 32 LEDs are tied to Vcc and cathode is connected with port pin. Here is the program to generate different chasing effects one after another continuously.
    #include<reg51.h>
    void delay(void);
    void delay()
      {
                int a,b;
                for(a=0;a<100;a++)
                   for(b=0;b<1000;b++);
      }
    void main()
      {
                int i, j, k, l;
                for(i=0;i<50;i++)                      // ON-OFF effect
                  {
                            P0=0x00;
                            P1=0x00;
                            P2=0x00;
                            P3=0x00
                            Delay();
                            P0=0xFF;
                            P1=0xFF;
                            P2=0xFF;
                            P3=0xFF;
                            Delay();
                  }
                for(j=0;j<50;j++)                     // alternate blinking effect
                  {
                            P0=0x55;
                            P1=0x55;
                            P2=0x55;
                            P3=0x55
                            Delay();
                            P0=0xAA;
                            P1=0xAA;
                            P2=0xAA;
                            P3=0xAA;
                            Delay();
                  }
                for(k=0;k<50;k++)                  // ON-OFF effect for port lower and upper nibble
                  {
                            P0=0xF0;
                            Delay();
                            P0=0x0F;
                            Delay();
                            P0=0xFF
                            P1=0xF0;
                            Delay();
                            P1=0x0F;
                            Delay();
                            P1=0xFF
                            P2=0xF0;
                            Delay();
                            P2=0x0F;
                            Delay();
                            P2=0xFF
                            P3=0xF0;
                            Delay();
                            P3=0x0F;
                            Delay();
                            P3=0xFF;
                    }
                for(l=0;l<50;l++)                      // alternate switching of ports one by one
                  {
                            P0=0x00
                            Delay();
                            P0=0xFF;
                            P1=0x00;
                            Delay();
                            P1=0xFF;
                            P2=0x00
                            Delay();
                            P2=0xFF;
                            P3=0x00;
                            Delay();
                            P3=0xFF;
                  }
    Push button keypad and 7-segment interfacing:
    Hardware:-8 push buttons are connected with P2 with one terminal as common ground. A common anode type 7-segment display is connected to P0. the program displays number 1 to 8 on 7-segment depending upon the key is pressed
    #include<reg51.h> void main(void)     {      loop:P2=0xFF;             // send all 1's to P1                      while(P21==0xFF);     // remain within loop till key is not pressed          switch(P1)            // when key pressed detect is              {                  case 0xFE:                        P0=0xF9; // and display digit from 1 to 8                        break;                   case 0xFD:                        P0=0xA4;                        break;                   case 0xFB:                        P0=0xB0;                        break;                   case 0xF7:                        P0=0x99;                         break;                   case 0xEF:                        P0=0x92;                        break;                    case 0xDF:                        P0=0x82;                         break;                   case 0xBF:                         P0=0xF8;                         break;                    case 0x7F:                         P0=0x80;                         break;                }                goto loop;        }
    LCD interfacing:
    Hardware:- normally all types of text LCDs have 8 data pins and 3 control signals. here data pins are connected with P0 and three control pins RS, R/W and EN are connected with P2.7, P2.6 & P2.5 respectively. Its a 16X2 LCD.
    #include <reg51.h> #include <string.h>
    sbit rs = P2^7;  // declare P2.7 as rs pin sbit en = P2^5;  // declare p2.5 as enable pin sbit rw = P2^6;  // declare p2.6 as read/write pin sbit b = P0^7;   // busy flag 
    void writecmd(unsigned char a); // function to send command to LCD void writedat(unsigned char b);  // function to send data to LCD void busy();   // function to check LCD is busy or not void writestr(unsigned char *s); // function to write string on LCD
    void writecmd(unsigned char a) {  busy();   // check for LCD is busy or not  rs = 0;   // clear rs pin for command  rw = 0;   // clear rw pin to write  P0 = a;   // send command character  en = 1;   // strob LCD  en = 0; } void writedat(unsigned char b) {  busy();   // check for LCD is busy or not  rs = 1;   // set rs pin for data  rw = 0;   // clear rw pin to write  P0 = b;   // send data character  en = 1;   // strob LCD  en = 0; } void busy() {  en = 0;   // disable display  P0 = 0xFF;  // configur P0 as input  rs = 0;   // clear rs pin for command  rw = 1;   // set rw pin to read  while(b==1)  {   en=0;   // strob LCD till P0.7 is 1   en=1;  }  en=0; } void writestr(unsigned char *s) {  unsigned char l,i;  l = strlen(s);               // get the length of string  for(i=1;i<l;i++)  {   writedat(*s);              // write every char one by one   s++;   } }     main() {     P0=0x00;                      // P0 and P0 as output ports     P2=0x00;     writecmd(0x3C);               // initialize LCD     writecmd(0x0E);        writecmd(0x01);              // clear memory and home cursor     writestr("Wel-Come to LCD"); // write message in first line      writecmd(0xC4);              // move cursor to second line 4th pos        writestr("Program");  
        while(1)                     // continuous loop    } 
    ADC interfacing:
    Hardware:- here I have interfaced 8 bit ADC 0804 with 8051 and given program displays digital equivalent value (HEX) of any analog input on 2-digit multiplex seven segment. Usually ADC has four control signals. CS (chip select-active low), WR (SOC-start of conversion-active low), RD(OE-o/p enable-active low)and INT. from these four only INT is o/p form ADC all other are inputs. The CS is connected with ground. WR, RD and INT signals are connected with P3.0, P3.1 and P3.2 respectively. 8 data pins are connected with P1. Multiplex 7-segment has 8 data pins and 2 display select pins. data pins are connected with P0 and display select pins are connected to P2.7 and P2.6 respectively. 
    #include <reg51.h> #include <string.h>
    sbit wr = P3^0;  // ADC write enable sbit rd = P3^1;  // ADC read enable
    sbit d1 = P2^7   // display 1 select bit
    sbit d2 = P2^6   // display 2 select bit
    unsigned char data d;
    unsigned int a=0,b=0,c=0; void int1(void) interrupt 1           //external interrupt 1 subroutine   {     EA=0                              // first disable any other interrupt
        rd = 0;                           // send read signal      d=P1;                             // read the data from port     rd=1; 
        a = (d & 0x0F);                   // saperate upper and lower     b = d >> 4;                       // nibbles 
        EA=1;                             // again enable interrupts
      } 
    void tmr1(void) interrupt 3            // timer 1 overflow interrupt
      {
         c++;                              // count no of timer 1 interrupts 
         TH1=0xEC;                         // reload timer
         TL1=0x77;
         TF1=0;                            // clear timer 1 overflow flag
         if((c%2)==0)                      // check interrupt has arrived even
            {                              // times or odd times
               d1=1;                       // alternatively change display 
               d2=0;                       // for even times 
               P0=b;
            }
          else                             // and odd times
            {
               d1=0;
               d2=1;
               P0=a;
            }
        }        main() {     P0=0x00;                      // P0 output ports   
        P1=0xFF;                      // P1 input port
        TMOD=0x90;                    // initialize T1 as 16 bit timer
        TH1=0xEC;                     // load count 60535(=EC77h)
        TL1=0x77;                     // so it will overflow after 5 ms 
        TR1=1;                        // start timer
        d1=0;
        d2=1;                         //enable first display 
        P0=a;                         //display 0 initially
        IE=0x89;                      // enable external and timer interrupts       wr = 0;                       // send write signal       wr = 1; 
        while(1);                     // wait in continuous loop
      }
    DAC interfacing:
    Hardware:-a 8 bit DAC is connected to P2. Its two control signals WR and CS are tied to ground. Here I am writing a program to generate three different types of waveforms square, triangular and staircase type. To select desire waveform three push buttons are connected at P3.0 to P3.2.
    #include<reg51.h>
    void delay1();                                                   //key debounce delay
    void delay2();                                                   // delay for frequency
    void sqrarwave();                                             // function to generate square wave
    void triwave();                                                  // function to generate triangular wave
    void stairwave();                                               // function to generate staircase wave
    void delay1()                                                    // approx. 100 ms delay
      {
                int a,b;
                for(a=0;a<100;a++)
                            for(b=0;b<1000;b++);
      }
    void delay2()                                                    // approx 1 ms delay
      {
                int c;
                for(c=0;c<1000;c++);
      }
    void squarwave()
      {
                while(P3==0xFF)                                 // till any button is not pressed
                  {
                            P2=0xFF;                                // first send all high to P2
                            Delay2();
                            P2=0x00;                                 // then send all low to P2
                            Delay2();
                  }
      }
    void triwave()
      {
                unsigned char d;
                while(P3==0xFF)
                  {
                            for(d=0x00;d<0xFF;d++)        // send values 00 to FF
                              {
                                        P2=d;                           // one by one for positive ramp             
                              }
                            for(d=0xFF;d<0x00;d--)          // send values FF to 00
                              {
                                        P2=d;                           // one by one for negative ramp
                              }
                  }
    void stairwave()
      {
                while(P3==0xFF)
                  {
    P2=0x00;                                 // step by step increment
                            Delay2();
                            P2=0x20;                                 // values sent to P2
                            Delay2();
                            P2=0x40;
                            Delay2();
                            P2=0x80;
                            Delay2();
                  }
      }
    void main()
      {
                P2=0x00;                                 // P2 as output port
                P3=0xFF;                                // P3 as input port
                While(P3=0xFF);                     // wait till any button is pressed
                Switch(P3)
                  {
                            case 0xFE:                   // for first button
                                        delay1();           // key debounce delay
                                        P3=0xFF;        // send all 1’s again to P3
                                        squarwave();    // generate square wave
                                        break;
                            case 0xFD:
                                        delay1();
                                        P3=0xFF;
                                        triwave();
                                        break;
                            case 0xFB:
                                        delay1();
                                        P3=0xFF;
                                        stairwave();
                                        break;
                  }
      }     
    References-  multyremotes.