124
Interfacing 7-segment Display .................................................................................... ............................................... #include <at89x52.h> void display_digit(unsigned char); void delay(); #define dis_a P0_1 /*a segment*/ #define dis_b P0_0 /*b segment*/ #define dis_c P0_6 /*c segment*/ #define dis_d P0_5 /*d segment*/ #define dis_e P0_4 /*e segment*/ #define dis_f P0_2 /*f segment*/ #define dis_g P0_3 /*g segment*/ void main(void) { unsigned char i; while(1){ /*Repeat fowever*/ for(i=0;i<10;i++) { display_digit(i); /*Display 0-9*/ delay(); /*delay*/ } }

Interfacing 7

Embed Size (px)

Citation preview

Page 1: Interfacing 7

Interfacing 7-segment Display...................................................................................................................................

#include <at89x52.h>void display_digit(unsigned char);void delay();

#define dis_a P0_1        /*a segment*/#define dis_b P0_0        /*b segment*/#define dis_c P0_6        /*c segment*/#define dis_d P0_5        /*d segment*/#define dis_e P0_4        /*e segment*/#define dis_f P0_2        /*f segment*/#define dis_g P0_3        /*g segment*/

void main(void){unsigned char i;while(1){                   /*Repeat fowever*/for(i=0;i<10;i++){display_digit(i);        /*Display 0-9*/delay();                        /*delay*/}}}

/*---------------------------------------------------Display the data passed to this function----------------------------------------------------*/void display_digit(unsigned char digg)

Page 2: Interfacing 7

{if (digg==0x00)                /*Display 0*/{dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=0;dis_f=0;dis_g=1;}else if (digg==1){dis_a=1;dis_b=0;dis_c=0;dis_d=1;dis_e=1;dis_f=1;dis_g=1;}else if (digg==2){dis_a=0;dis_b=0;dis_c=1;dis_d=0;dis_e=0;dis_f=1;dis_g=0;}else if (digg==3){dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=1;dis_f=1;dis_g=0;}else if (digg==4){dis_a=1;dis_b=0;dis_c=0;dis_d=1;dis_e=1;dis_f=0;dis_g=0;}else if (digg==5){dis_a=0;dis_b=1;dis_c=0;dis_d=0;

Page 3: Interfacing 7

dis_e=1;dis_f=0;dis_g=0;}else if (digg==6){dis_a=0;dis_b=1;dis_c=0;dis_d=0;dis_e=0;dis_f=0;dis_g=0;}else if (digg==7){dis_a=0;dis_b=0;dis_c=0;dis_d=1;dis_e=1;dis_f=1;dis_g=1;}else if (digg==8){dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=0;dis_f=0;dis_g=0;}else if (digg==9){dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=1;dis_f=0;dis_g=0;}}/*---------------------------------------------------Delay Program----------------------------------------------------*/void delay(){TMOD=0x01;                /*Timer 0, mode 1*/TL0=0xFE;TH0=0xFE;TR0=1;while(TF0==0);TR0=0;TF0=0;

Page 4: Interfacing 7

}

Analog to Digital Conversion...................................................................................................................................

#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;

void main( void ) {

       unsigned char adVal;       unsigned long volts;       InitIO();

       READ = 1;       WRITE = 1;       INTR = 1;       ClearScreen();

        while(1) {

               /* Make a low-to-high transition on the WR input */

               while( INTR == 1 );    /* wait until the INTR signal makes  */                                      /* high-to-low transition indicating */                                      /* completion of conversion          */

                                        /* Read the voltage value from the port */                             READ = 0;                adVal = P1;                READ = 1;

                /* Compute the digital value of the volatge read */

                /* Print the value of the voltage in decimal form */       }}

Page 5: Interfacing 7

Interfacing Temperature Sensor (DS1620) with AT89C51...................................................................................................................................

IntroductionThe DS1620 Digital Thermometer and Thermostat provides 9-bit temperature readings. It has three alarm outputs, so the device can also act as a thermostat. The DS1620, which incorporates a 3-wire interface can be controlled using an AT89C51 Microcontroller. The DS1620 is connected directly to the I/O port on the AT89C51 microcontroller, and the 3-wire handshaking and temperature readings are handled by low-level software drivers as shown in this document.

Temperature Control of the DS1620The thermostat ouputs of the DS1620 allow it to directly control heating and cooling devices. THIGH is driven high if the device exceeds a predefined limit set within the TH Register. The output THIGH can be used to indicate that a high temperature tolerance boundary has been met or exceeded, or it can be used as part of a closed loop system to activate a cooling system and deactivate it when the system temperature returns to tolerance. TLOW is driven high when the temperature of the device falls below the limit set in the TL Register. TLOW remains active until the DS1620's temperature becomes greater than the value stored in the low temperature register, TL. TCOM is driven high when the temperature exceeds the limit set in the TH Register and remains high until the device temperature falls below that set in the TL Register. In this way, any amount of user-defined temperature hysteresis can be obtained. For typical thermostat operation, the DS1620 will operate in continuous mode. However, for applications  here only one reading is needed at certain times or to conserve power, the one-shot mode may be used. Note that the thermostat outputs (THIGH , TLOW , TCOM) will remain in the state they were in after the last valid temperature conversion cycle when operating in one-shot mode.Hardware ConfigurationThe 3-wire bus is comprised of three signals. These are the RST-bar (reset) signal, the CLK (clock) signal, and the DQ (data) signal. All data transfers are initiated by driving the RST-bar input high. Driving the RST-bar input low terminates the communication. A clock cycle is a sequence of a falling edge followed by a rising edge. For data inputs, the data must be valid during the rising edge of the clock cycle. Data bits are output on the falling edge of the clock and remain valid through the rising edge. When reading data from the DS1620, the DQ pin goes to a high-impedance state while the clock is high. Taking RST-bar low during a communication cycle will cause DQ to go to a high-impedance state, thus ending the communication. Data

Page 6: Interfacing 7

over the 3-wire interface is sent LSB first. Figure 1 illustrates the device connection to the microcontroller programmable input/output port.

Real Time Clock Interfacing (DS1307) with AT89C51...................................................................................................................................

/********************************************************************//* DEMO1307.c                                                       *//********************************************************************/#include <at89x52.h>                /* Prototypes for I/O functions       */#include <stdio.h>/***************************** Defines *****************************/#define        ACK        0#define        NACK        1#define        ADDRTC        0xd0        /* I2C slave address */#define        DS1307        /* compile directive, modify as required */

/************************* bit definitions *************************/sbit scl = P2^0;               /* I2C pin definitions */sbit sda = P2^1;sbit sqw = P3^2;                /* pin function depends upon device */

void        I2C_start();void        I2C_stop();void        I2C_write(unsigned char d);uchar        I2C_read(uchar);

Page 7: Interfacing 7

void        readbyte();void        writebyte();void        initialize();void        disp_clk_regs(uchar);void        burstramwrite(uchar);void        burstramread();void        alrm_int();void        alrm_read();void        tc_setup();

/* global variables */uchar        sec, min, hr, dy, dt, mn, yr;void I2C_start()        /* ----------------------------------------------- */{       sda = 1;  scl = 1;        /* Initiate start condition */       sda = 0;}void I2C_stop()                /* ----------------------------------------------- */{       sda = 0; sda = 0; sda = 0; sda = 0;        /* Initiate stop condition */       scl = 1; scl = 1; sda = 1;}void I2C_write(uchar d)                /* ----------------------------- */{uchar i;

       scl = 0;       for (i = 1; i <= 8; i++)       {               sda = (d >> 7);               scl = 1;               d = d << 1;        /* increase scl high time */               scl = 0;       }       sda = 1;        /* Release the sda line */       scl = 0;       scl = 1;       if(sda) printf("Ack bit missing  %02X",(unsigned int)d);       scl = 0;}uchar I2C_read(uchar b)        /* ----------------------------------- */{uchar d, i;

       sda = 1;             /* Let go of sda line */       scl = 0;       for (i = 1; i <= 8; i++)        /* read the msb first */       {               scl = 1;               d = d << 1;               d = d | (unsigned char)sda;               scl = 0;       }

Page 8: Interfacing 7

       sda = b;          /* Hold sda low for acknowledge */

       scl = 0;       scl = 1;       if(b == NACK)        sda = 1;        /* sda = 1 if next cycle is reset */       scl = 0;

       sda = 1;          /* Release the sda line */       return d;}void readbyte()        /* -- read one byte of data from the specified address -- */{uchar Add;       printf("ADDRESS: ");        /* Get Address */       scanf("%bx", &Add);       I2C_start();       I2C_write(ADDRTC);       I2C_write(Add);       I2C_start();       I2C_write(ADDRTC | 1);       printf("%2bx", I2C_read(NACK) );       I2C_stop();}void writebyte()        /* -- write one byte of data to the specified address -- */{uchar Add;uchar Data;       printf("Address: ");        /* Get Address */       scanf("%bx", &Add);       printf("DATA: ");       scanf("%bx", &Data);        /* and data */       I2C_start();       I2C_write(ADDRTC);       I2C_write(Add);       I2C_write(Data);       I2C_stop();}void initialize()        /* -- initialize the time and date using entries from stdin -- *//* Note: NO error checking is done on the user entries! */{uchar        yr, mn, dt, dy, hr, min, sec, day;

       I2C_start();                /* The following Enables the Oscillator */       I2C_write(ADDRTC);        /* address the part to write */       I2C_write(0x00);        /* position the address pointer to 0 */       I2C_write(0x00);        /* write 0 to the seconds register, clear the CH bit */       I2C_stop();

       printf("Enter the year (0-99): ");       scanf("%bx", &yr);       printf("Enter the month (1-12): ");

Page 9: Interfacing 7

       scanf("%bx", &mn);       printf("Enter the date (1-31): ");       scanf("%bx", &dt);       printf("Enter the day (1-7): ");       scanf("%bx", &dy);       printf("Enter the hour (1-23): ");       scanf("%bx", &hr);       hr = hr & 0x3f;        /* force clock to 24 hour mode */       printf("Enter the minute (0-59): ");       scanf("%bx", &min);       printf("Enter the second (0-59): ");       scanf("%bx", &sec);

       I2C_start();       I2C_write(ADDRTC);        /* write slave address + write */       I2C_write(0x00);        /* write register address, 1st clock register */       I2C_write(sec);       I2C_write(min);       I2C_write(hr);       I2C_write(dy);       I2C_write(dt);       I2C_write(mn);       I2C_write(yr);

#if defined DS1307 || defined DS1338{       I2C_write(0x10);        /* enable sqwe, 1Hz output */}#elif defined DS1337 || defined DS1339{       I2C_start();       I2C_write(ADDRTC);        /* write slave address + write */       I2C_write(0x0e);        /* write register address, control register */       I2C_write(0x20);        /* enable osc, bbsqi */       I2C_write(0);                /* clear OSF, alarm flags */                               /* could enable trickle charger here */}#elif defined DS1340{       I2C_write(0x10);        /* enable sqwe, 1Hz output */       I2C_start();                /* address pointer wraps at 7, so point to flag register */       I2C_write(ADDRTC);        /* write slave address + write */       I2C_write(0x09);        /* write register address, control register */       I2C_write(0);                /* clear OSF */}#endif

       I2C_stop();

}void        disp_clk_regs(uchar prv_sec)        /* ----------------------------------------- */{

Page 10: Interfacing 7

uchar Sec, Min, Hrs, Dte, Mon, Day, Yr, mil, pm;

       printf("Yr Mn Dt Dy Hr:Mn:Sc");

       while(!RI)        /* Read & Display Clock Registers */       {               I2C_start();               I2C_write(ADDRTC);        /* write slave address + write */               I2C_write(0x00);        /* write register address, 1st clock register */               I2C_start();               I2C_write(ADDRTC | 1);        /* write slave address + read */               Sec = I2C_read(ACK);        /* starts w/last address stored in register pointer */               Min = I2C_read(ACK);               Hrs = I2C_read(ACK);               Day = I2C_read(ACK);               Dte = I2C_read(ACK);               Mon = I2C_read(ACK);               Yr  = I2C_read(NACK);               I2C_stop();               if(Hrs & 0x40)                       mil = 0;               else                       mil = 1;

               if(Sec != prv_sec)        /* display every time seconds change */               {                       if(mil)                       {                               printf("%02bX/%02bX/%02bX %2bX", Yr, Mon, Dte, Day);                               printf(" %02bX:%02bX:%02bX", Hrs, Min, Sec);                       }                       else                       {                               if(Hrs & 0x20)                                       pm = 'A';                               else                                       pm = 'P';                               Hrs &= 0x1f;        /* strip mode and am/pm bits */                               printf("%02bx/%02bx/%02bx %02bx", Yr, (Mon & 0x1f), Dte, Day);                               printf(" %02bx:%02bx:%02bx %cM", Hrs, Min, Sec, pm);                       }               }               if(prv_sec == 0xfe)        return;               prv_sec = Sec;       }       RI = 0;  /* Swallow keypress before exiting */}

Page 11: Interfacing 7

void burstramwrite(uchar Data)        /* -------- fill RAM with data -------- */{uchar j;

   I2C_start();       I2C_write(ADDRTC);        /* write slave address + write */       I2C_write(0x08);        /* write register address, 1st RAM location */       for (j = 0; j < 56; j++)        /* write until the pointer wraps around */       {               I2C_write(Data);       }       I2C_stop();}void burstramread()                /* ----------------------------------------- */{uchar j;

       I2C_start();       I2C_write(ADDRTC);        /* write slave address + write */       I2C_write(8);        /* write register address, 1st RAM location -1*/       I2C_start();       I2C_write(ADDRTC | 1);        /* write slave address + read */

       for (j = 0; j < 56; j++)       {               if(!(j % 16)) printf("%02bX ", j);               printf("%02bX ", I2C_read(ACK) );       }       I2C_read(NACK);       I2C_stop();}void        alrm_int()        /* ----- initialize alarm registers ------ */{uchar        M, Sec, Min, Hr, DyDt;

       printf("1-Alarm each second        2-Alarm match=sec 3-Alarm match=sec+min");       printf("4-Alarm match=sec+min+hr 5-Alarm match=sec+min+hr+date");       printf("6-Alarm match=sec+min+hr+day        Enter selection: ");

       M = _getkey();        /* Note-No error checking is done on entries! */

       switch(M)       {               case '1':        M = 0xf;        break;               case '2':        M = 0xe;        break;               case '3':        M = 0xc;        break;               case '4':        M = 8;                break;               case '5':        M = 0;                break;               case '6':        M = 0x40;        break;

Page 12: Interfacing 7

       }       if(M & 0x40)       {               printf("Enter the day (1-7): ");               scanf("%bx", &DyDt);       }       else       {               printf("Enter the date (1-31): ");               scanf("%bx", &DyDt);       }       printf("Enter the hour (1-23): ");       scanf("%bx", &Hr);       printf("Enter the minute (0-59): ");       scanf("%bx", &Min);       printf("Enter the second (0-59): ");       scanf("%bx", &Sec);

       if( (M & 1) )        Sec |= 0x80;       if( ((M >> 1) & 1) )        Min |= 0x80;       if( ((M >> 2) & 1) )        Hr |= 0x80;       if( ((M >> 3) & 1) )        DyDt |= 0x80;       if(M & 0x40)        DyDt |= 0x40;

       I2C_start();       I2C_write(ADDRTC);        /* write slave address + write */       I2C_write(7);                /* write register address */       I2C_write(Sec);       I2C_write(Min);       I2C_write(Hr);       I2C_write(DyDt);       I2C_start();       I2C_write(ADDRTC);        /* write slave address + write */       I2C_write(0x0e);        /* write register address */       I2C_write(5);                /* enable interrupts, alarm 1 */       I2C_stop();}void        alrm_read()        /* ----- read alarm registers ------ */{uchar        Sec, Min, Hr, DyDt;

       I2C_start();       I2C_write(ADDRTC);        /* write slave address + write */       I2C_write(7);                /* write register address */       I2C_start();       I2C_write(ADDRTC | 1);        /* write slave address + read */       Sec = I2C_read(ACK);       Min = I2C_read(ACK);       Hr = I2C_read(ACK);       DyDt = I2C_read(NACK);

       printf("Alarm 1: %02bx %02bx %02bx %02bx", Sec, Min, Hr, DyDt);}void        tc_setup()        /* ---- trickle charger set up routine ---- */{uchar        M, val;

Page 13: Interfacing 7

#if defined DS1339       #define        TC 0x10        /* address for DS1339 trickle charge register */#else       #define        TC 0x08        /* address for DS1340 trickle charge register */#endif

       printf("Enable Trickle Charger (Y/N)? ");       M = _getkey();

       if(M == 'Y' || M == 'y')       {               printf("1-250 ohm res2-2K res=sec3-4K res");

               M = _getkey();        /* Note-No error checking is done on entries! */

               switch(M)               {                       case '1':        val = 1;        break;                       case '2':        val = 2;        break;                       case '3':        val = 3;        break;               }               printf("1-no diode2-1 diode");

               M = _getkey();        /* Note-No error checking is done on entries! */

               switch(M)               {                       case '1':        val += 4;        break;                       case '2':        val += 8;        break;               }               I2C_start();               I2C_write(ADDRTC);                /* write slave address + write */               I2C_write(TC);                /* write register address */               I2C_write(val | 0xa0);        /* enable trickle charger per user input */               I2C_stop();       }       else       {               I2C_start();               I2C_write(ADDRTC);                /* write slave address + write */               I2C_write(TC);                /* write register address */               I2C_write(0);                        /* disable trickle charger */               I2C_stop();       }       I2C_start();

Page 14: Interfacing 7

       I2C_write(ADDRTC);                /* write slave address + write */       I2C_write(TC);                /* write register address */       I2C_start();       I2C_write(ADDRTC | 1);        /* write slave address + read */       printf("Trickle Charger: %02bx", I2C_read(NACK) );}main        (void)        /* ----------------------------------------------------- */{uchar        M, M1;

       sqw = 1;        /* set up for read, weak pull-up */

       while (1)       {#if defined DS1307               printf("DEMO1307 build %s", __DATE__);#elif defined DS1337               printf("DEMO1337 build %s", __DATE__);#elif defined DS1338               printf("DEMO1338 build %s", __DATE__);#elif defined DS1339               printf("DEMO1339 build %s", __DATE__);#elif defined DS1340               printf("DEMO1340 build %s", __DATE__);#endif

               printf("CI Init RTC    CR Read Clock");               printf("BR Byte Read   BW Write Byte");

#if defined DS1337 || defined DS1339        /* only print if part has alarms */               printf("AI Alarm 1 Int AR Alarm Read");#endif#if defined DS1340 || defined DS1339        /* parts that have trickle charger */               printf("Tc Trickle charger");#endif

#if defined DS1307 || defined DS1338        /* only print if part has RAM */               printf("RR RAM Read    RW RAM Write");#endif

               printf("Enter Menu Selection:");

               M = _getkey();

               switch(M)               {                       case 'A':                       case 'a':                       printf("Init or Read: ");                       M1 = _getkey();

Page 15: Interfacing 7

                       switch(M1)                       {                               case 'I':                               case 'i':        alrm_int();       break;

                               case 'R':                               case 'r':        alrm_read();       break;                       }                       break;

                       case 'B':                       case 'b':                       printf("Read or Write: ");                       M1 = _getkey();

                       switch(M1)                       {                               case 'R':                               case 'r':        readbyte();       break;

                               case 'W':                               case 'w':        writebyte();       break;                       }                       break;

                       case 'C':                       case 'c':                       printf("\rEnter Clock Routine to run:C");                       M1 = _getkey();

                       switch(M1)                       {                               case 'I':                               case 'i':        initialize();       break;

                               case 'R':                               case 'r':        disp_clk_regs(0x99);     break;                       }                       break;

                       case 'R':                       case 'r':                       printf("\rEnter Ram Routine to run:R");                       M1 = _getkey();

                       switch(M1)                       {                               case 'R':                               case 'r':        burstramread();       break;

Page 16: Interfacing 7

                               case 'W':                               case 'w':        printf("Enter the data to write: ");                                               scanf("%bx", &M1);                                               burstramwrite(M1);       break;                       }                       break;

                       case 'T':                       case 't':        tc_setup();        break;               }       }}

Serial Communication...................................................................................................................................

#pragma SMALL DB OE#include <reg51.h>

unsigned char ReceiveSerial() {

       unsigned char c;

       TMOD = 0x20;        /* configure timer for the correct baud rate */        TH1 = 0xe6;     /* 1200 bps for 12 MHz clock */        TCON = 0x00;    /* Set timer to not running */

       SCON = 0x50;    /* Set Serial IO to receive and normal mode */       TR1 = 1;        /* start timer to Receive */               while( (SCON & 0x01) == 0 ) /* wait for receive data */;       c = SBUF;       return c;}

void SendSerial(unsigned char c) {

        /* initialize..set values for TMOD, TH1 and TCON */        /* set the Tx interrupt in SCON to indicate sending data */        /* start timer */        /* write character to SBUF */        /* wait for completion of sent data */}

void main(void) {

       unsigned char c;

       while( 1 ) {

Page 17: Interfacing 7

           /* Use ReceiveSerial to read in a character 'c' */           /* Do some computation on 'c' */           /* Send the result using SendSerial() */        }}

Implementing a Calculator Using Peripherals Like a Keypad and LCD...................................................................................................................................

/* To implement a integer calculator using a keypad and LCD */

#pragma SMALL DB OE#include <reg51.h>#include "io.h"

/* The functions to initialize and control the LCD are assumed to be in the file io.c */

/* Function to output the decimal value of the result on the LCD */void PrintInt(int i) {     .     .     .}

/* Routine to scan the key pressed */unsigned char key_scan(){       unsigned char i, j, temp1, temp2;

        while( 1 ) /* keep waiting for a key to be pressed */

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

                        /* Set each row to 0 */                        P1 = 0xff & ~(1<<i);

                        /* Scan each column to see which key was pressed */                        for (j=4; j<8; j++) {

                              /* Code to determine the position of the                                 key which was pressed */                              /* return(position) */                        }                }}

void main() {

        /* You can have a conversion table to convert the key position into a           valid number which indicates the operator or operand value. For eg:           the numbers 0 to 9 are valid operands and 100 to 103 denote

Page 18: Interfacing 7

           addition, subtraction, multiplication and division respectively */

        char conv_table[] = {

                 1, 2,  3, 100 /* add */,                 4, 5,  6, 101 /* sub */,                 7, 8,  9, 102 /* mul */,                -1, 0, -1, 103 /* div */        };        char num1, num2, op;        int result;

        InitIO();

        while(1) {

                ClearScreen();

                /* read num1 */                GotoXY(0, 0);                PrintString("num1 : ");                do {

                    num1 = conv_table[key_scan()];                }                while( num1 < 0 || num1 > 9 );

                /* read a valid operation */                GotoXY(0, 0);                PrintString("op :   ");                do {

                    op = conv_table[key_scan()];                }                while( op < 100 );

                /* read num2 */                GotoXY(0, 0);                PrintString("num2 : ");                do {

                    num2 = conv_table[key_scan()];                }                while( num2 < 0 || num2 > 9 );

                /* compute result */                if( op == 100 ) {

                     /* Add numbers and display result on the LCD */                }                else if( op == 101 ) {                      .                      .                      .                      .

Page 19: Interfacing 7

                /* Continue similarly for other operations */

                }        }}

Implementing a 4 bit Counter using an 8051 and Interfacing it to an LCD...................................................................................................................................

#pragma SMALL DB OE#include#include "io.h"

/* P0, P1, P2 and P3 are predefined port names and are bit addressable */

sbit reset = P0^4; /* bit 4 of Port 0 */sbit up_down = P0^5;sbit load = P0^6;sbit Start_LCD = P0^7; /* bit 7 of Port 3 */

/* Delay function */void delay() {

        int i, j;

        for(i=0; i<1000; i++)                for(j=0; j<100; j++)                        i = i + 0;}

/* Function to output the decimal value of the count on the LCD */void PrintInt(unsigned char i) {       char ch[4];

       /* Write code to convert the count to a string value and use the           PrintString function provided in io.c */

        PrintString(ch);}

void main(void) {

        unsigned char count = 0;

        InitIO();  /* Initialize the LCD */        while (1) {                if (Start_LCD == 1) {                        ClearScreen();                        PrintString("Ready...");                        delay();

Page 20: Interfacing 7

                }                else if (reset == 1) {

                        /* Output 0 on the LCD */

                }                else if (load == 1) {

                       /* Output the current value of Datain on the LCD */

                }                else {                        /* Check the Up/Down pin for 1 or 0 count up or down                           accordingly. Display each value on the LCD */               }      }}

Interfacing LCD to PC Parallel Port...................................................................................................................................

General:Character (alphanumeric) type LCD modules are most commonly driven froman embedded microcontroller. It is sometimes desirable to be able to drive this type of module directly from a PC. This would allow the module to be tested or a demonstration or simulation to be set up quickly and with a minimum of engineering. This application note describes a method of driving an LCD character module fromthe printer port of a PC with minimal external hardware.

The printer port of a PC:There are at least three versions of printer ports available now on PCs.SPP (Standard Parallel Port)EPP (Enhanced Parallel Port)ECP (Extended Capability Port)To make this design as universal as possible it will be based on the least capable and oldest specification, SPP.Click here to Download the Program...main.c

/* Sample Software to display a message on a 16 x2 character LCD module/* from a parallel port of a PC#include <time.h>#include <conio.h>#include <string.h>#define PORTADDRESS 0x378 /*Enter port address here */#define DATA PORTADDRESS+0 /*LCD data port */#define CONTROL PORTADDRESS+2 /*LCD control port */void main (void){

Page 21: Interfacing 7

/* Total of 40 characters including spaces in each line of string */char string[] = {”>>8051projects<< ““ABC abc 123,!@$? “};char init[10];int count;int len;init[0] = 0x0F; /* Initialize display */init[1] = 0x01; /* Clear display */init[2] = 0x38; /* Dual line 8 bits */_out(CONTROL, _inp(CONTROL) & 0xDF); /* Reset control port */_out(CONTROL, _inp(CONTROL) | 0x08); /*Set RS *//* Initialization routine */for (count = 0; count <= 2; count++){_out(DATA, init[count]);_out(CONTROL,_inp(CONTROL) | 0x01; /*Set Enable */delay(20);_out(CONTROL,_inp(CONTROL) & 0xFE; /*Reset Enable */delay(20);}_out(CONTROL, _inp(CONTROL) & 0xF7);/*Reset RS *//* Output the message */len = strlen(string);for (count = 0; count < len; count++){_out(DATA, string[count]);_out(CONTROL,_inp(CONTROL) | 0x01; /*Set Enable */delay(2);_out(CONTROL,_inp(CONTROL) & 0xFE); /*Reset Enable */delay(2);}}

Interfacing LCD (4 bit Mode)...................................................................................................................................

This is an example how to interface to the standard Hitachi-44780 LCD using an AT89C51 microcontroller and Keil as C Compiler. I use a standard 16-character by 2-line LCD module, see schematic below. Here, I use 4-bit interfacing.Click here to Download the Program...

Page 22: Interfacing 7

main.c

#include <at89x52.h>#include "lcd.h"

main( ){    LCD_init();    LCD_row1(); LCD_puts("Hello World");    LCD_row2(); LCD_puts("Good Morning");    while (1);}

seven.c

#define LCD_en P3_1#define LCD_rs P3_0#define LCD_DELAY 2000 /* Delay for 1 ms */#define LCD_clear() LCD_command(0x1)        /* Clear display LCD */#define LCD_origin() LCD_command(0x2)        /* Set to origin LCD */#define LCD_row1() LCD_command(0x80)        /* Begin at Line 1 */#define LCD_row2() LCD_command(0xC0)   /* Begin at Line 2 *//**************************************************** Prototype(s)                                    ****************************************************/void LCD_delay(unsigned char ms);void LCD_enable();void LCD_command(unsigned char command);void LCD_putc(unsigned char ascii);void LCD_puts(unsigned char *lcd_string);void LCD_init();

/**************************************************** Sources                                         *

Page 23: Interfacing 7

***************************************************/void LCD_delay(unsigned char ms){       unsigned char n;       unsigned int i;       for (n=0; n<ms; n++)       {               for (i=0; i<LCD_DELAY; i++); /* For 1 ms */       }   }

void LCD_enable(){    LCD_en = 0; /* Clear bit P2.4 */    LCD_delay(1);    LCD_en = 1; /* Set bit P2.4 */}

void LCD_command(unsigned char command){    LCD_rs = 0; /* Clear bit P2.5 */    P2 = (P2 & 0xF0)|((command>>4) & 0x0F);    LCD_enable();    P2 = (P2 & 0xF0)|(command & 0x0F);    LCD_enable();    LCD_delay(1);}

void LCD_putc(unsigned char ascii){    LCD_rs = 1; /* Set bit P2.5 */    P2 = (P2 & 0xF0)|((ascii>>4) & 0x0F);    LCD_enable();    P2 = (P2 & 0xF0)|(ascii & 0x0F);    LCD_enable();    LCD_delay(1);}

void LCD_puts(unsigned char *lcd_string){       while (*lcd_string)       {               LCD_putc(*lcd_string++);       }}

void LCD_init(){    LCD_en = 1; /* Set bit P2.4 */    LCD_rs = 0; /* Clear bit P2.5 */      LCD_command(0x33);    LCD_command(0x32);    LCD_command(0x28);    LCD_command(0x0C);    LCD_command(0x06);    LCD_command(0x01); /* Clear */

Page 24: Interfacing 7

    LCD_delay(256);}

Multiplexed seven-segment display (4 digits)...................................................................................................................................

main.c

#include <at89x52.h>

extern unsigned char digit1;extern unsigned char digit2;extern unsigned char digit3;extern unsigned char digit4;extern void timer_enable(void);void main(void){

timer_enable();while(1){digit1=0x00;digit2=0x01;digit3=0x06;digit4=0x03;}}

seven.c

#include <at89x52.h>void display_digit(unsigned char);#define dis_a P0_2#define dis_b P0_3#define dis_c P0_4#define dis_d P0_6#define dis_e P0_5#define dis_f P0_1#define dis_g P0_0

#define disp1 P2_7#define disp2 P2_6#define disp3 P2_5#define disp4 P2_4

unsigned char count_val;unsigned char digit1;unsigned char digit2;unsigned char digit3;unsigned char digit4;

void timer_enable(void){/*------------------------------------

Page 25: Interfacing 7

Timer 0 routine for Display.--------------------------------------*/count_val=0x00;                                /*Clear Count value*/TMOD = (TMOD & 0x0F) | 0x20;  /* Set Mode (8-bit timer with reload) */TH1 = 0x00;              /* Reload TL1 to count 100 clocks */TL1 = 0xff;ET1 = 1;                      /* Enable Timer 1 Interrupts */TR1 = 1;                      /* Start Timer 1 Running */EA = 1;                       /* Global Interrupt Enable *//*--------------------------------------*/}

void timer1_ISR (void) interrupt 3{disp1=0;disp2=0;disp3=0;disp4=0;if (count_val==1){disp1=1;disp2=0;disp3=0;disp4=0;display_digit(digit1);}else if (count_val==2){disp1=0;disp2=1;disp3=0;disp4=0;display_digit(digit2);}else if (count_val==0x03){disp1=0;disp2=0;disp3=1;disp4=0;display_digit(digit3);}else if (count_val==0x04){disp1=0;disp2=0;disp3=0;disp4=1;display_digit(digit4);count_val=0x00;}count_val++;}/*---------------------------------------------------Display the data passed to this function----------------------------------------------------*/void display_digit(unsigned char digg){if (digg==0x00){

Page 26: Interfacing 7

dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=0;dis_f=0;dis_g=1;}else if (digg==1){dis_a=1;dis_b=0;dis_c=0;dis_d=1;dis_e=1;dis_f=1;dis_g=1;}else if (digg==2){dis_a=0;dis_b=0;dis_c=1;dis_d=0;dis_e=0;dis_f=1;dis_g=0;}else if (digg==3){dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=1;dis_f=1;dis_g=0;}else if (digg==4){dis_a=1;dis_b=0;dis_c=0;dis_d=1;dis_e=1;dis_f=0;dis_g=0;}else if (digg==5){dis_a=0;dis_b=1;dis_c=0;dis_d=0;dis_e=1;dis_f=0;dis_g=0;

Page 27: Interfacing 7

}else if (digg==6){dis_a=0;dis_b=1;dis_c=0;dis_d=0;dis_e=0;dis_f=0;dis_g=0;}else if (digg==7){dis_a=0;dis_b=0;dis_c=0;dis_d=1;dis_e=1;dis_f=1;dis_g=1;}else if (digg==8){dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=0;dis_f=0;dis_g=0;}else if (digg==9){dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=1;dis_f=0;dis_g=0;}else if (digg==0x0A)        /*For symbol -*/{dis_a=1;dis_b=1;dis_c=1;dis_d=1;dis_e=1;dis_f=1;dis_g=0;}}

Page 28: Interfacing 7

Interfacing 7-segment Display...................................................................................................................................

#include <at89x52.h>void display_digit(unsigned char);void delay();

#define dis_a P0_1        /*a segment*/#define dis_b P0_0        /*b segment*/#define dis_c P0_6        /*c segment*/#define dis_d P0_5        /*d segment*/#define dis_e P0_4        /*e segment*/#define dis_f P0_2        /*f segment*/#define dis_g P0_3        /*g segment*/

void main(void){unsigned char i;while(1){                   /*Repeat fowever*/for(i=0;i<10;i++){display_digit(i);        /*Display 0-9*/delay();                        /*delay*/}}}

/*---------------------------------------------------Display the data passed to this function----------------------------------------------------*/void display_digit(unsigned char digg){if (digg==0x00)                /*Display 0*/{dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=0;dis_f=0;dis_g=1;}else if (digg==1){dis_a=1;dis_b=0;dis_c=0;dis_d=1;dis_e=1;dis_f=1;dis_g=1;}else if (digg==2){dis_a=0;dis_b=0;

Page 29: Interfacing 7

dis_c=1;dis_d=0;dis_e=0;dis_f=1;dis_g=0;}else if (digg==3){dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=1;dis_f=1;dis_g=0;}else if (digg==4){dis_a=1;dis_b=0;dis_c=0;dis_d=1;dis_e=1;dis_f=0;dis_g=0;}else if (digg==5){dis_a=0;dis_b=1;dis_c=0;dis_d=0;dis_e=1;dis_f=0;dis_g=0;}else if (digg==6){dis_a=0;dis_b=1;dis_c=0;dis_d=0;dis_e=0;dis_f=0;dis_g=0;}else if (digg==7){dis_a=0;dis_b=0;dis_c=0;dis_d=1;dis_e=1;dis_f=1;dis_g=1;}else if (digg==8)

Page 30: Interfacing 7

{dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=0;dis_f=0;dis_g=0;}else if (digg==9){dis_a=0;dis_b=0;dis_c=0;dis_d=0;dis_e=1;dis_f=0;dis_g=0;}}/*---------------------------------------------------Delay Program----------------------------------------------------*/void delay(){TMOD=0x01;                /*Timer 0, mode 1*/TL0=0xFE;TH0=0xFE;TR0=1;while(TF0==0);TR0=0;TF0=0;}

Example of how to read and write data on the 8051 serial port using polling...................................................................................................................................

/************************************************************************** serial.c - A demonstration of how to access the serial port on an*  8051 using C code.  To avoid using interrupts, this example polls*  the interrupt flags in the serial port to know when the serial port*  is ready.*/

/* included headers */

#include        /* register names */

/** function declarations - Here the functions in our code are declared.*  In C, this is only necessary if the actual implementation of the*  function is performed in a separate file or after any function that

Page 31: Interfacing 7

*  calls it in its own file.  In this program, these functions will*  all be implemented within this file.  However, for asthetics,*  functions will be implemented in order of highest-level to lowest.*  By nature, this creates a scenario where the functions will be*  called by code placed above the actual implementation, so the*  functions must first be declared here.*/

char getCharacter (void);        /* read a character from the serial port */void sendCharacter (char);        /* write a character to the serial port */

/* functions */

/************************************************************************** main - Program entry point.  This program will simply receive characters*  from the serial port, then send them back.** INPUT: N/A* RETURNS: N/A*/

main(){       char        chr;        /* variable to hold characters in */

       /* Before the serial port may be used, it must be configured. */

       /*        * The serial controll register configures the method of operation        * for the serial port.  The value used below is 0x50 (or 50h in        * 8051 lingo), referring to the bits within the SCON register,        * this does the following:        *  MODE = 010 (8-bit UART serial buffer, no stop bit - this is typical)        *  REN = 1 (enabled receiving)        *  TB8, RB8 = 00 (unused in this mode)        *  RI,TI = 00 (start the interupt flags as ready to receive and send)        */

       SCON = 0x50;                /* mode 1, 8-bit uart, enable receiver */

       /*        * Because a standard serial port transmits no clocking signal, both        * ends of the serial connection must agree on a clock frequency,        * which is then generated internally at each end.  For this example,

Page 32: Interfacing 7

        * a baud rate of 2400 bits per second will be used.  The timer must be        * configured accordingly.        * The formula for determining the reload value based on desired baud        * rate and clock frequency is:        *  TH1 = 256 - clock frequency (in Hz) / (384 * baud rate)        * For 2400bps and a 11.02Mhz clock:        *  TH1 = 256 - 11,020,000 / (384 * 2400) = 255 = 0xFE        */

       TMOD = 0x20;                /* timer 1, mode 2, 8-bit reload */       TH1  = 0xFE;                /* reload value for 2400 baud */

       /* Setting TR1 will start the timer, and serial communications */

       TR1  = 1;

       /*        * Set the Transmit Interrupt flag to send the the character in           * the serial buffer, clearing it for use by the program.        */

       TI   = 1;

       /*        * Now the program isr eady to send and receive data on the serial        * port. Because it is going to do this indefinitely (until the        * device is effectively turned off), the rest of the program will        * be in an infinite while() loop.        */

        while (1==1)        {                              /* read the next character from the serial port */

               chr = getCharacter ();

               /* send it back to the original sender */

               sendCharacter (chr);        }}

/************************************************************************** getCharacter - Waits for a new character to arrive in the serial port,*  then reads it.** INPUT: N/A* RETURNS: newly received character*/

Page 33: Interfacing 7

char getCharacter (void){       char chr;        /* variable to hold the new character */

       /*        * Wait until the serial port signals a new character has arrived.        * It does so by setting the Received interrupt flag, RI, which        * this routine loops on until it is set to 1.  This is known        * as polling.     */

       while (RI != 1) {;}

       /* now read the value in the serial buffer into the local variable */

       chr = SBUF;

       /*        * 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.        */

       RI = 0;

       /* the character is then returned to the calling function. */

       return(chr);}

/************************************************************************** sendCharacter - Waits until the serial port is ready to send a new*  character, then sends it.** INPUT:*        chr - The character to send** RETURNS: N/A*/

void sendCharacter(    char        chr        /* character to send */){       /*        * Because of the way terminal programs for serial ports work, we want        * to replace carriage returns with line feeds.        */

Page 34: Interfacing 7

       if (chr == '\r') chr = '\n';

       /*        * Wait until the serial port signals the previous character has        * been sent. It does so by setting the Transmit interrupt flag, TI,        * which this routine loops on until it is set to 1.      */

       while (TI != 1) {;}

       /*        * Clear the Transmit Interrupt flag to prepare the serial port        * to send a new character.        */

       TI = 0;

       /* Write the character into the serial port buffer register, SBUF */

       SBUF = chr;

       /*        * The serial port hardware takes over from here, and the program        * may continue with other operations.        */

       return;}

A rewrite of the serial example to use interrupts in C...................................................................................................................................

/************************************************************************** int.c - A demonstration of how to write interrupt-driven code for an*  8051 using the Keil C compiler.  The same techniques may work in other*  8051 C compilers with little or no modifcation.  This program will*  combine the functionality of both basic.c and serial.c to allow serial*  communications to be entirely in the background, driven by the serial*  interrupt.  This allows the main() function to count on Port 0 without*  being aware of any ongoing serial communication.*/

/* included headers */

#include

Page 35: Interfacing 7

/* function declarations */

char getCharacter (void);        /* read a character from the serial port */void sendCharacter (char);        /* write a character to the serial port */

/** Interrupt handlers:*  Here the code for the interrupt handler will be placed.  In this*  example, a handler for the serial interrupt will be written. *  Examination of the 8051 specs will show that the serial interrupt is*  interrupt 4.  A single interrupt is generated for both transmit and*  receive interrupts, so determination of the exact cause (and proper*  response) must be made within the handler itself.*  To write an interrupt handler in Keil, the function must be declared*  void, with no parameters.  In addition, the function specification*  must be followed by a specification of the interrupt source it is*  attached to.  The "using" attribute specifies which register bank*  to use for the interrupt handler.*/

void serial_int (void) interrupt 4{       static char        chr = '\0';        /* character buffer */

       /*        * 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.        */

       if (RI == 1)        /* it was a receive interrupt */       {               chr = SBUF;        /* read the character into our local buffer */               RI = 0;        /* clear the received interrupt flag */               TI = 1;        /* signal that there's a new character to send */       }       else if (TI == 1)        /* otherwise, assume it was a transmit interrupt */       {               TI = 0;        /* clear the transmit interrupt flag */               if (chr != '\0')        /* if there's something in the local buffer... */               {                       if (chr == '\r') chr = '\n';        /* convert  to  */                       SBUF = chr;        /* put the character into the transmit buffer */                       chr = '\0';               }       }}

Page 36: Interfacing 7

/* functions */

/************************************************************************** main - Program entry point.  This program sets up the timers and*  interrupts, then simply receives characters from the serial port and*  sends them back.  Notice that nowhere in the main function is Port 0*  incremented, nor does it call any other function that may do so. *  main() is free to do solely serial communications.  Port 0 is handled*  entirely by the interrupt handler (aside from initialization).** INPUT: N/A* RETURNS: N/A*/

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  = 0xFE;        /* reload value for 2400 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.        */              ES   = 1;                /* allow serial interrupts */       EA   = 1;                /* enable interrupts */

       /* initialize Port 0 to 0, as in basic.c */

    P0 = 0;

       /*        * 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==1)    {               unsigned int        i;

Page 37: Interfacing 7

               for (i = 0; i < 60000; i++) {;}        /* delay */               P0 = P0 + 1;        /* increment Port 0 */       }}

A very basic example of writing C code for the 8051...................................................................................................................................

/************************************************************************** basic.c - The basics of writing C code for the 8051 using the Keil*  development environment.  In this case, a simple program will be*  constructed to make a binary counter on Port 0.*/

/** As always with C, the included header files should come first.  Most* every project for the 8051 will want to include the file reg51.h.  This* header file contains the mapping of registers to names, such as setting* P0 (port 0) to address 0x80.  This allows the coder to use the keyword* "P0" in their code whenever they wish to access Port 0.  For the complete* list of registers named, view the file.*/

#include

/** Other header files may be included after reg51.h, including any headers* created by the user.*/

/** The C program starts with function main().  In the case of a program* written using multiple .c files, main can only occur in one of them.* Unlike in programming user applications for a standard computer, the* main() function in a Keil program for the 8051 takes no inputs and* returns no output, thus the declaration has implied void types.*/

/************************************************************************** main - Program entry point** INPUT: N/A* RETURNS: N/A*/

main()

Page 38: Interfacing 7

{     unsigned int i;        /* will be used for a delay loop */

     /* First, Port 0 will be initialized to zero */

     P0 = 0;

     /*      * Now the counter loop begins.  Because this program is intended      * to run in an embedded system with no user interaction, and will      * run forever, the rest of the program is placed in a non-exiting      * while() loop.      */

     while (1==1)     {          /*                  * This is a very unpredictable method of implementing a delay                  * loop, but remains the simplest.  More reliable techniques                  * can be done using the using the built-in timers.  In this                  * example, though, the for() loop below will run through 60000                  * iterations before continuing on to the next instruction.                  * The amount of time required for this loop varies with the                  * clock frequency and compiler used.                  */

          for (i = 0; i < 60000; i++) {;}

         /* Increment Port 0 */

         P0 = P0 + 1;     }

}

Global Positioning System

Global Positioning System (GPS) is a network of satellites that continuously transmit coded information, which makes it possible to precisely identify locations on earth by measuring distance from the satellites.

GPS stands for Global Positioning System, and refers to a group of U.S.Department of Defense satellites constantly circling the earth. The satellites transmit very low power radio signals allowing anyone with a GPS receiver to determine their location on Earth. This remarkable system was

Page 39: Interfacing 7

not cheap to build, costing the U.S. billions of dollars. Ongoing maintenance, including the launch of replacement satellites, adds to the cost of the system.

It would not only tell us where we are in position coordinates (latitude/longitude), but would even display our location on an electronic map along with cities, streets and more. These designers originally had a military application in mind. GPS receivers would aid navigation, troop deployment and artillery fire (among other applications). Fortunately, an executive decree in the 1980s made GPS available for civilian use also. Now everyone gets to enjoy the benefits of GPS! The capability is almost unlimited.

APPLICATIONS OF GPS

GPS has a variety of applications on land, at sea and in the air. Basically, GPS allows you to record or create locations from places on the earth and help you navigate to and from those spots. GPS can be used everywhere except where it's impossible to receive the signal such as inside buildings; in caves, parking garages, and other subterranean locations; and underwater. The most common airborne applications include navigation by general aviation and commercial aircraft. At sea, GPS is typically used for navigation by recreational boaters and fishing enthusiasts. Land-based applications are more diverse. The scientific community uses GPS for its precision timing capability and a myriad of other applications. Surveyors use GPS for an increasing portion of their work. GPS offers an incredible cost savings by drastically reducing setup time at the survey site. It also provides amazing accuracy. Basic survey units can offer accuracies down to one meter. More expensive systems can provide accuracies

Recreational uses of GPS are almost as varied as the number of recreational sports available. GPS is becoming increasingly popular among hikers, hunters, snowmobilers, mountain bikers, and cross- country skiers, just to name a few. If you are involved in an activity or sport where you need to keep track of where you are, find your way to a specified location, or know what direction and how fast you're going, you can benefit from the Global Positioning System.

GPS is rapidly becoming commonplace in automobiles as well. Some basic systems are already in place, providing emergency roadside assistance at the push of a button (by transmitting your current position to a dispatch center). More sophisticated systems can show the vehicle's position on an electronic map display, allowing drivers to keep track of where they are and look up street addresses, restaurants, hotels and other destinations. Some systems can even automatically create a route and give turn-by-turn directions to a designated location.

You don't have to be a rocket scientist to learn how GPS works. All you need is a little background knowledge plus the desire to explore and understand the world of GPS. Don't let terms like "pseudo-random", "anti-spoofing" and "P Code" frighten you. Let's dig right in and start to become familiar with the best navigation tool to come along since the invention of the compass.

Page 40: Interfacing 7

The Space Segment

The space segment, which consists of at least 24 satellites (21 active plus 3 operating spares) is the heart of the system. The satellites are in what's called a "high orbit" about 12,000 miles above the Earth's surface. Operating at such a high altitude allows the signals to cover a greater area.

The satellites are arranged in their orbits so a GPS receiver on earth can always receive from at least four of them at any given time. The satellites are traveling at speeds of 7,000 miles an hour, which allows them to circle the earth once every 12 hours. They are powered by solar energy and are built to last about 10 years. If the solar energy fails (eclipses, etc.), they have backup batteries on board to keep them running. They also have small rocket boosters to keep them  flying in the correct path.

Each satellite transmits low power radio signals on several frequencies (designated L1, L2, etc.). Civilian GPS receivers "listen" on the L1 frequency of 1575.42 MHz in the UHF band. The signal travels "line of sight", meaning it will pass through clouds, glass and plastic, but will not go through most solid objects such as buildings and mountains.

To give you some idea of where the L1 signal is on the radio dial, your favorite FM radio station broadcasts on a frequency somewhere between 88 and 108 MHz (and sounds much better!). The satellite signals are also very low power signals, on the order of 20-50 watts. Your local FM radio station is around 100,000 watts. Imagine trying to listen to a 50-watt radio station transmitting from 12,000 miles away! That's why it's important to have a clear view of the sky when using your GPS.

L1 contains two "pseudorandom" (a complex pattern of digital code) signals, the Protected (P) code and the Coarse/Acquisition (C/A) code. Each satellite transmits a unique code, allowing the GPS receiver to identify the

Page 41: Interfacing 7

signals. "Anti-spoofing" refers to the scrambling of the P code in order to prevent its unauthorized access. The P code is also called the "P (Y)" or"Y" code.

The main purpose of these coded signals is to allow for calculating the travel time from the satellite to the GPS receiver on the Earth. This traveltime is also called the Time of Arrival. The travel time multiplied by the speed of light equals the satellite range (distance from the satellite to the GPS receiver). The Navigation Message (the information the satellites transmit to a receiver) contains the satellite orbital and clock information and general system status messages and an ionospheric delay model. The satellite signals are timed using highly accurate atomic clocks.The Control Segment

The "control" segment does what its name implies - it "controls" the GPS satellites by tracking them and then providing them with corrected orbital and clock (time) information. There are five control stations located around the world - four unmanned monitoring stations and one "master control station". The four unmanned receiving stations constantly receive data from the satellites and then send that information to the master control station. The master control station "corrects" the satellite data and, together with two other antenna sites, sends ("uplinks") the information to the GPS satellites.

The User Segment

The user segment simply consists of you and your GPS receiver. As mentioned previously, the user segment consists of boaters, pilots, hikers, hunters, the military and anyone else who wants to know where they are, where they have been or where they are going.

How does it Work?

The GPS receiver has to know two things if it's going to do its job. It has to know WHERE the satellites are (location) and how FAR AWAY they are (distance). Let's first look at how the GPS receiver knows where the satellites are located in space. The GPS receiver picks up two kinds of coded information from the satellites. One type of information, called "almanac" data, contains the approximate positions (locations) of the satellites. This data is continuously transmitted and stored in the memory of the GPS receiver so it knows the orbits of the satellites and where each satellite is supposed to be. The almanac data is periodically updated with new information as the satellites move around.

Any satellite can travel slightly out of orbit, so the ground monitor stations keep track of the satellite orbits, altitude, location, and speed. The ground stations send the orbital data to the master control station, which inturn sends corrected data up to the satellites. This corrected and exact position data is called the "ephemeris" (pronounced: i-'fe-me-res) data, which is valid for about four to six hours, and is transmitted in the coded information to the GPS receiver. So, having received the almanac and ephemeris data, the GPS receiver knows the position (location) of the satellites at all times.

Time is of the Essence

Page 42: Interfacing 7

Even though the GPS receiver knows the precise location of the satellites in space, it still needs to know how far away the satellites are (the distance) so it can determine its position on Earth. There is a simple formula that tells the receiver how far it is from each satellite.

Calculating position

Your distance from a given satellite object equals the velocity of the transmitted signal multiplied by the time it takes the signal to reach you (Velocity x Travel Time = Distance).

GPS works on the principle, called "Time of Arrival". the same basic formula to determine distance, the receiver already knows the velocity. It's the speed of a radio wave - 186,000 miles per second (the speed of light), less any delay as the signal travels through the Earth's atmosphere. Now the GPS receiver needs to determine the time part of the formula. The answer lies in the coded signals the satellites transmit. The transmitted code is called "pseudo-random code" because it looks like a noise signal. When a satellite is generating the pseudo-random code, the GPS receiver is generating the same code and tries to match it up to the satellite's code. The receiver then compares the two codes to determine how much it needs to delay (or shift) its code to match the satellite code. This delay time (shift) is multiplied by the speed of light to get the distance.

Your GPS receiver clock does not keep the time as precisely as the satellite clocks. Putting an atomic clock in your GPS receiver would make it much larger and far too expensive! So each distance measurement needs to be corrected to account for the GPS receiver's internal clock error. For this reason, the range measurement is referred to as a "pseudo-range". To determine position using pseudo-range data, a minimum of four satellites must be tracked and the four fixes must be recomputed until the clock error disappears.

Now that we have both satellite location and distance, the receiver can determine a position. Let's say we are 11,000 miles from one satellite. Our location would be somewhere on an imaginary sphere that has the satellite in the center with a radius of 11,000 miles. Then let's say we are 12,000 miles from another satellite. The second sphere would intersect the first sphere to create a common circle. If we add a third satellite, at a distance of 13,000 miles, we now have two common points where the three spheres intersect. Even though there are two possible positions, they differ greatly in latitude/longitude position AND altitude. To determine which of the two common points your actual position is, you'll need to enter your approximate altitude into the GPS receiver. This will allow the receiver to calculate a two-dimensional position (latitude, longitude). However, by adding a fourth satellite, the receiver can deter-mine your three-dimensional position (latitude, longitude, altitude). Let's say our distance from a fourth satellite is 10,000 miles. We now have a fourth sphere intersecting the first three spheres at one common point.

The unit stores data about where the satellites are located at any given time. This data is called the almanac. Sometimes when the GPS unit is not turned on for a length of time, the almanac can get outdated or "cold". When the GPS receiver is "cold", it could take longer to acquire satellites. A

Page 43: Interfacing 7

receiver is considered "warm" when the data has been collected from the satellites within the last four to six hours. When you're looking for a GPS unit to buy, you may see "cold" and "warm" acquisition time specifications. If the time it takes the GPS unit to lock on to the signals and calculate a position is important to you, be sure to check the acquisition times. Once the GPS has locked onto enough satellites to calculate a position, you are ready to begin navigating! Most units will display a position page or a page showing your position on a map (map screen) that will assist you in your navigation.

GPS Receiver Technology

Most modern GPS receivers are a parallel multi-channel design. Older single-channel designs were once popular, but were limited in their ability to continuously receive signals in the toughest environments - such as under heavy tree cover. Parallel receivers typically have from between five and 12 receiver circuits, each devoted to one particular satellite signal, so strong locks can be maintained on all the satellites at all times. Parallel-channel receivers are quick to lock onto satellites when first turned on and they are unequaled in their ability to receive the satellite signals even in difficult conditions such as dense foliage or urban settings with tall buildings.

About Trimble's Lassen IQ GPS Reciever

About Trimble's Lassen IQ GPS Reciever...................................................................................................................................

The Lassen iQ GPS receiver is a full featured, ultra low power receiver on a miniature form factor, suitable for a variety of mobile, embedded applications. The Lassen iQ GPS receiver incorporates Trimble’s FirstGPSTM architecture in the form of two ASICS: Colossus RF down converter and IO-C33 baseband chip.

The IO-C33 integrates Trimble’s IO digital signal processor with the Epson C33 RISC processor, real-time clock, UART, and 1Mbit memory. Together with the colossus RF, this implementation of FirstGPS technology makes

Page 44: Interfacing 7

possible one of the smallest (26 mm x 26 mm x 6mm) and lowest power (less than 89 mW) GPS modules available.

The Lassen iQ GPS receiver outputs a complete position, velocity, and time (PVT) solution in the NMEA Version 3.0 ASCII protocol, the Trimble ASCII Interface Protocol (TAIP), and the Trimble TSIP binary protocol. A Pulse-Per-Second signal is available for very accurate timing applications.

Receiver PerformanceThe Lassen iQ GPS receiver is a complete 12-channel parallel tracking GPS receiver designed to operate with the L1 frequency, Standard Position Service, Coarse Acquisition code. Using two highly integrated Trimble custom integrated circuits, the receiver is designed in a modular format especially suited for embedded applications where small size and extremely low power consumption are required. The receiver features Trimble's latest signal processing code, a highgain RF section for compatibility with standard 27 dB active gain GPS antennas, and a CMOS TTL level pulse-per-second (PPS) output for timing applications or for use as a general purpose synchronization signal.

The Lassen iQ GPS receiver acquires a position fix with minimal delay after power cycling. The battery back-up RAM is used to keep the Real Time clock (RTC) alive, and to store the following:• Almanac• Ephemeris• Last positionUser settings such as port parameters, NMEA, and TAIP configurations can be stored in the receiver’s non-volatile (Flash) memory. These settings are retained without application of main power or battery back-up power.

The Lassen iQ GPS receiver has two configurable serial I/O communication ports

Hardware Details of Trimble's Lassen IQ GPS Reciever

Page 45: Interfacing 7

in NumberFunction

Description1TXD ASerial Port A transmit, 3.3 V TTLCMOS2GndGround, Power and Signal3RXD ASerial Port A receive, 3.3 V TTL CMOS4PPSPulse-Per-Second, 3.3 V TTL CMOS5TXD BSerial port B transmit, 3.3V TTL CMOS6RXD BSerial port B receive, 3.3V TTL CMOS7Prime Power (VCC)+3.3 VDC to ± 0.3 VDC8Battery BackupPower+2.5 VDC to + 3.6 VDC

Power Supply for Trimble's Lassen IQ GPS RecieverPower RequirementsThe Lassen iQ GPS module requires +3.3 VDC ±0.3 VDC at 33 mA, typical excluding the antenna. The on-board capacitance is 10 ìF. An important design consideration for power is the module's internal clock frequency at 12.504 MHz ± 3 KHz. Interference spurs on prime power in this narrow frequency band should be kept to less than 1mV. The receiver does not require any special power up or down sequencing. The receiver power is supplied through pin 7 of the I/O connector.

The Power supply can be derived from +5V to +3.3V by using the Regulator IC LM317. The circuit diagram is gven below.

Page 46: Interfacing 7

Serial Port Interface for GPS Receiver

As an embedded design, the Lassen iQ GPS module provides direct CMOS compatible TTL level serial I/O. The RX and TX signals on the J2 I/O connector are driven directly by the DUART on the Lassen iQ GPS receiver. Interfacing these signals directly to a UART in your application circuitry provides direct serial communication without the complication of RS-232 or RS-422 line drivers.

If we want to connect the GPS receiver to any RS232 serial port you need a converter. MAX3232 is an serial driver IC which can operate from 3v to 5v.

Page 47: Interfacing 7

Output Protocols from a GPS Receiver

The Lassen iQ GPS receiver operates using one of three protocols Trimble Standard Interface Protocol (TSIP), Trimble ASCII Interface Protocol (TAIP), or NMEA 0183. Protocol selection and port characteristics are user configurables. The factory default settings are:• Port 1, TSIP bi-directional• Port 2, NMEA 0183 OUT/RTCM SC-104 V2.1 IN

TSIPTSIP is a powerful binary packet protocol that allows the system designer maximum configuration control over the GPS receiver for optimum performance in any number of applications. TSIP supports over 20 commands and their associated response packets for use in configuring the Lassen iQ GPS receiver to meet user requirements.

TAIPTAIP is the Trimble ASCII interface protocol designed specifically for vehicle tracking applications. It is a bi-directional protocol using simple ASCII commands with the associated ASCII responses.

NMEANMEA 0183 is an industry standard protocol common to marine applications. NMEA provides direct compatibility with other NMEAcapable devices such as chart plotters, radars, etc. The Lassen iQ GPS receiver supports most NMEA messages for GPS navigation. NMEA messages and output rates can be user selected as required.

DGPS

Page 48: Interfacing 7

The Lassen iQ GPS receiver can be configured for RTCM SC-104 input which is the GPS industry standard for differential correction data. The receive side of Port 2 is factory configured to accept RTCM data.

Above all protocols the NMEA protocol is the standard protocol for all GPS. More about NMEA protocol is given below

NMEA SENTENCE TYPESThe following information describes the most common NMEA-0183 sentences transmitted by GPS receivers. The NMEA standard provides quite a range of sentences, but many relate to non-GPS devices and some others are GPS related but rarely used. We normally recommend the use of NMEA mode for new GPS applications to give maximum compatibility with all GPS receivers. Most GPS receivers also have a binary mode but it is normally best to reserve the use of binary GPS protocols for applications that really require their use, such as those requiring position updates of greater than once per second. This protocol works on the baud rate of 4800.

Sentence        Description$GPGGA        Global positioning system fixed data$GPGLL        Geographic position - latitude / longitude$GPGSA        GNSS DOP and active satellites$GPGSV        GNSS satellites in view$GPRMC        Recommended minimum specific GNSS data$GPVTG        Course over ground and ground speed

$GPGGA Sentence (Fix data)Example$GPGGA,235947.000,0000.0000,N,00000.0000,E,0,00,0.0,0.0,M,,,,0000*00 Example (signal acquired):GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,19.7,M,,,,0000*1FField        Example        CommentsSentence ID        $GPGGA        UTC Time        092204.999        hhmmss.sssLatitude        4250.5589        ddmm.mmmmN/S Indicator        S        N = North, S = SouthLongitude        14718.5084        dddmm.mmmmE/W Indicator        E        E = East, W = WestPosition Fix        1        0 = Invalid, 1 = Valid SPS, 2 = Valid DGPS, 3 = Valid PPSSatellites Used        04        Satellites being used (0-12)HDOP        24.4        Horizontal dilution of precisionAltitude        19.7        Altitude in meters according to WGS-84 ellipsoidAltitude Units        M        M = MetersGeoid Seperation                Geoid seperation in meters according to WGS-84 ellipsoidSeperation Units                M = MetersDGPS Age                Age of DGPS data in secondsDGPS Station ID        0000        Checksum        *1F        Terminator        CR/LF 

Circuit Diagram & Program to Interface a GPS Receiver with AT89S51

Page 49: Interfacing 7

$baud = 9600      $crystal = 11059200      Config Lcd = 16 * 2

      Config Lcdpin = Pin , Db4 = P0.2 , Db5 = P0.3 , Db6 = P0.4 , Db7 = P0.5 , E = P0.1 , Rs = P0.0      Rem with the config lcdpin statement you can override the compiler settings

'$GPGGA,012211.83,4119.6171,N,07730.0636,W,1,03,3.6,00522,M,,,,*36

'GPS Time, Latitude, Longitude Display

'set up variables

Dim Gps As Byte , X As Byte , Lont(6) As Byte , Latt(6) As Byte

Page 50: Interfacing 7

Dim Lat As Byte , Latmin As Byte , Latfrac As Byte , Latns As ByteDim Lon As Byte , Lonmin As Byte , Lonfrac As Byte , Lonew As ByteDim Timt(6) As ByteDim Hours As Byte , Mins As Byte , Secs As Byte

HomeClsCursor Off

Looploop:HomeUpperlineStartloop:

Gps = Waitkey()If Gps <> "$" Then Goto Startloop

Gps = Waitkey()If Gps <> "G" Then Goto Startloop

Gps = Waitkey()If Gps <> "P" Then Goto Startloop

Gps = Waitkey()If Gps <> "G" Then Goto Startloop

Gps = Waitkey()If Gps <> "G" Then Goto Startloop

Gps = Waitkey()If Gps <> "A" Then Goto Startloop

Gps = Waitkey()If Gps <> "," Then Goto Startloop

For X = 1 To 6   Gps = Waitkey()   Lcd Chr(gps) ;   Timt(x) = Gps   If X = 2 Then Lcd ":";   If X = 4 Then Lcd ":";Next X

Timlop:Gps = Waitkey()If Gps = "," Then Goto GetlatGoto Timlop

Getlat:LowerlineFor X = 1 To 6Getlat1:

Page 51: Interfacing 7

   Gps = Waitkey()   If Gps = "." Then Goto Getlat1   Latt(x) = Gps   Lcd Chr(gps);Next X

Getlat2:Gps = Waitkey()If Gps <> "," Then Goto Getlat2Gps = Waitkey()Lcd Chr(gps) ; " ";Latns = GpsGps = Waitkey()Gps = Waitkey()

For X = 1 To 6Getlon:   Gps = Waitkey()   If Gps = "." Then Goto Getlon   Lont(x) = Gps   Lcd Chr(gps);Next XGetlon1:Gps = Waitkey()If Gps <> "," Then Goto Getlon1Gps = Waitkey()Lcd Chr(gps);Gps = Waitkey()Gps = Waitkey()Gps = Waitkey()Locate 1 , 11Lcd "Sat:"Gps = Waitkey()Lcd Chr(gps);Gps = Waitkey()Lcd Chr(gps);

Goto Looploop

DTMF Decoder Interfacing to Microcontroller

About DTMF...................................................................................................................................

Dual-tone multi-frequency (DTMF) signaling is used for telephone signaling over the line in the voice-frequency band to the call switching center. The version of DTMF used for telephone tone dialing is known by the trademarked term Touch-Tone, and is standardised by ITU-T

Page 52: Interfacing 7

Recommendation Q.23. Other multi-frequency systems are used for signaling internal to the telephone network

HistoryIn the time preceding the development of DTMF, telephone systems employed a system commonly referred to as pulse (Dial Pulse or DP in the USA) or loop disconnect (LD) signalling to dial numbers, which functions by rapidly disconnecting and connecting the calling party's telephone line, similar to flicking a light switch on and off. The repeated connection and disconnection, as the dial spins, sounds like a series of clicks. The exchange equipment counts those clicks or dial pulses to determine the called number. Loop disconnect range was restricted by telegraphic distortion and other technical problems, and placing calls over longer distances required either operator assistance (operators used an earlier kind of multi-frequency dial) or the provision of subscriber trunk dialling equipment.

DTMF was developed at Bell Labs in order to allow dialing signals to dial long-distance numbers, potentially over nonwire links such as microwave radio relay links or satellites. For a few non crossbar offices, encoder/decoders were added that would convert the older pulse signals into DTMF tones and play them down the line to the remote end office. At the remote site another encoder/decoder could decode the tones and perform pulse dialing, for example for Strowger switches. It was as if you were connected directly to that end office, yet the signaling would work over any sort of link. This idea of using the existing network for signaling as well as the message is known as in-band signaling.

It was clear even in the late 1950s when DTMF was being developed that the future of switching lay in electronic switches, as opposed to the electromechanical crossbar systems then in use. Either switching system could use either dial system, but DTMF promised shorter holding times, which was more important in the larger and more complex registers used in crossbar systems. In this case pulse dialing made no sense at any point in the circuit, and plans were made to roll DTMF out to end users as soon as possible. Tests of the system occurred in the early 1960s, where DTMF became known as Touch Tone. Though Touch Tone phones were already in use in a few places, they were vigorously promoted at the 1964 New York World's Fair.

The Touch Tone system also introduced a standardized keypad layout. After testing 18 different layouts, they eventually chose the one familiar to us today, with 1 in the upper-left and 0 at the bottom. The adding-machine layout, with 1 in the lower-left was also tried, but at that time few people used adding machines, and having the 1 at the "start" (in European language reading order) led to fewer typing errors. In retrospect, many people consider that this was a mistake. With the widespread introduction of computers and bank machines, the phone keyboard has become "oddball", causing mistakes.

In another sense, DTMF was obsolete a decade after it was instituted, as FSK methods with fewer frequencies became cheaper, faster and more reliable. However, the technical complexities of digital filtering were more expensive to deal with than junking an adequate system.

Page 53: Interfacing 7

#, *, A, B, C, and DThe engineers had envisioned phones being used to access computers, and surveyed a number of companies to see what they would need for this role. This led to the addition of the number sign (#) and star (*) keys (also known as humphries),[citation needed] as well as a group of keys for menu selection: A, B, C and D. In the end, the lettered keys were dropped from most phones, and it was many years before the humphries became widely used for vertical service codes such as *67 in the United States and Canada to suppress caller ID.

Public payphones that accept credit cards use these additional codes to send the information from the magnetic strip.

The U.S. military also used the letters, relabeled, in their now defunct Autovon phone system. Here they were used before dialing the phone in order to give some calls priority, cutting in over existing calls if need be. The idea was to allow important traffic to get through every time. The levels of priority available were Flash Override (A), Flash (B), Immediate (C), and Priority (D), with Flash Override being the highest priority. Pressing one of these keys gave your call priority, overriding other conversations on the network. Pressing C, Immediate, before dialing would make the switch first look for any free lines, and if all lines were in use, it would disconnect any non-priority calls, and then any priority calls. Flash Override will kick every other call off the trunks between the origin and destination. Consequently, it is limited to the White House Communications Agency. Precedence dialing is still done on the military phone networks, but using number combinations (Example:Entering 93 before a number is a priority call) rather than the separate tones.

Present-day uses of the A, B, C and D keys on telephone networks are few, and exclusive to network control. For example, the A key is used on some networks to cycle through different carriers at will (thereby listening in on calls). Their use is probably prohibited by most carriers. The A, B, C and D tones are used in amateur radio phone patch and repeater operations to allow, among other uses, control of the repeater while connected to an active phone line.

DTMF tones are also used by some cable television networks and radio networks to signal the local cable company/network station to insert a local advertisement or station identification. These tones were often heard during a station ID preceding a local ad insert. Previously, terrestrial television stations also used DTMF tones to shut off and turn on remote transmitters.

DTMF tones are also sometimes used in caller ID systems to transfer the caller ID information, however in the USA only Bell 202 modulated FSK signalling is used to transfer the data.

Keypad

The DTMF keypad is laid out in a 4×4 matrix, with each row representing a low frequency, and each column representing a high frequency. Pressing a single key such as '1' will send a sinusoidal tone of the two frequencies 697 and 1209 hertz (Hz). The original keypads had levers inside, so each button activated two contacts. The multiple tones are the reason for calling the

Page 54: Interfacing 7

system multifrequency. These tones are then decoded by the switching center to determine which key was pressed.

DTMF keypad frequencies

1209 Hz  1336 Hz 1477 Hz 1633 Hz

697 Hz 1 2 3 A

770 Hz 4 5 6 B

852 Hz 7 8 9 C

941 Hz * 0 # D

About MT8870

About MT8870...................................................................................................................................

The M-8870 is a full DTMF Receiver that integrates both bandsplit filter and decoder functions into a single 18-pin DIP or SOIC package. Manufactured using CMOS process technology, the M-8870 offers low power consumption (35 mW max) and precise data handling. Its filter section uses switched capacitor technology for both the high and low group filters and for dial tone rejection. Its decoder uses digital counting techniques to  detect and decode all 16 DTMF tone pairs into a 4-bit code. External component count is minimized by provision of an on-chip differential input amplifier, clock generator, and latched tri-state interface bus. Minimal external components required include a low-cost 3.579545 MHz color burst crystal, a timing resistor, and a timing capacitor.

The M-8870-02 provides a “power-down” option which, when enabled, drops consumption to less than 0.5 mW. The M-8870-02 can also inhibit the decoding of fourth column digits

Pin Diagram of MT8870

Page 55: Interfacing 7

Pin Functions of MT8870

Page 56: Interfacing 7

Tone Decoding of MT8870

Circuit Diagram

Page 57: Interfacing 7

This section describes how to interface an DTMF decoder to the microcontroller AT89C51/52and to display the digits over the seven segment display.

he circuit also has an Ring sensor which is not used in the program

INCLUDE reg_52.pdf

       STD   EQU   P3.0    ;DTMF OUTPUT       Q3                EQU        P3.1       Q2                EQU        P3.2       Q1                EQU        P3.3       Q0                EQU        P3.4              RING        EQU        P3.5

       DIS_A        EQU        P0.0               DIS_B        EQU        P0.1       DIS_C        EQU        P0.2       DIS_D        EQU        P0.3       DIS_E        EQU        P0.4       DIS_F        EQU        P0.5       DIS_G        EQU        P0.6                                   DSEG            ; This is internal data memoryORG     20H     ; Bit adressable memory

Page 58: Interfacing 7

       DTMF:  DS  1       D0 BIT   DTMF.0       D1        BIT        DTMF.1       D2        BIT        DTMF.2       D3        BIT        DTMF.3        CSEG            ; Code begins here;---------==========----------==========---------=========---------;              PROCESSOR INTERRUPT AND RESET VECTORS ;---------==========----------==========---------=========---------                ORG     00H    ; Reset          MOV SP,#60H          MOV R2,#15H       CALL DISP        ;Display - symbol on display          SETB STD        ;Make STD pin as input                 TOP:        JNB STD,$        ;wait for new data       CALL READ        ;Read Data       MOV R2,DTMF                                       CALL DISP        ;Display Dialled Data       JB STD,$                ;Wait until the key is released       AJMP TOP        ;Repeat the function                             ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%;                READ DTMF TONES;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                READ:       MOV DTMF,#00H       SETB Q0       SETB Q1       SETB Q2       SETB Q3       JNB Q0,VB1       SETB D0VB1:        JNB Q1,VB2       SETB D1                VB2:        JNB Q2,VB3       SETB D2VB3:        JNB Q3,VB4       SETB D3VB4:        RET                ;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&;        7 SEGMENT DISPLAY ROUTINE;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&DISP:       CJNE R2,#00H,AAS1       CLR DIS_A       CLR DIS_B       CLR DIS_C       CLR DIS_D       CLR DIS_E       CLR DIS_F       SETB DIS_G       RETAAS1:        CJNE R2,#01H,AS2       CLR DIS_B       CLR DIS_C       SETB DIS_A       SETB DIS_D

Page 59: Interfacing 7

       SETB DIS_E       SETB DIS_F       SETB DIS_G       RETAS2:        CJNE R2,#02H,AS3       CLR DIS_A       CLR DIS_B       CLR DIS_D       CLR DIS_E       CLR DIS_G       SETB DIS_C       SETB DIS_F       RETAS3:        CJNE R2,#03H,AS4       CLR DIS_A          CLR DIS_B       CLR DIS_C       CLR DIS_D       CLR DIS_G       SETB DIS_E       SETB DIS_F       RETAS4:        CJNE R2,#04H,AS5       CLR DIS_B       CLR DIS_C       CLR DIS_F       CLR DIS_G       SETB DIS_A       SETB DIS_D       SETB DIS_E       RETAS5:        CJNE R2,#05H,AS6       CLR DIS_A       CLR DIS_C       CLR DIS_D       CLR DIS_F       CLR DIS_G       SETB  DIS_B       SETB DIS_E       RETAS6:        CJNE R2,#06H,AS7       CLR DIS_A       CLR DIS_C       CLR DIS_D       CLR DIS_E       CLR DIS_F       CLR DIS_G       SETB DIS_B       RETAS7:        CJNE R2,#07H,AS8       CLR DIS_A       CLR DIS_B       CLR DIS_C       SETB DIS_D       SETB DIS_E       SETB DIS_F       SETB DIS_G

Page 60: Interfacing 7

       RETAS8:        CJNE R2,#08H,AS9       CLR DIS_A       CLR DIS_B       CLR DIS_C       CLR DIS_D       CLR DIS_E       CLR DIS_F       CLR DIS_G       RETAS9:        CJNE R2,#09H,AS10       CLR DIS_A       CLR DIS_B       CLR DIS_C       CLR DIS_D       CLR DIS_F       CLR DIS_G       SETB DIS_E       RETAS10:        CJNE R2,#15H,AS11                ;symbol for -       SETB DIS_A       SETB DIS_B       SETB DIS_C       SETB DIS_D       SETB DIS_E       SETB DIS_F       CLR DIS_G       RETAS11:               CJNE R2,#16H,AS12                ;switch off all disp       SETB DIS_A       SETB DIS_B       SETB DIS_C       SETB DIS_D       SETB DIS_E       SETB DIS_F       SETB DIS_G       RETAS12:               RET;**********************************************************               END

Infrared Receiver Interfacing (TSOP 1738)

Page 61: Interfacing 7

This section describes how to interface an Infrared Receiver (TSOP 1738) to the microcontroller AT89C51/52and to control 8 LED's through a RC5 Remote control.

The circuit explains how to connect an Infrared Sensor to the Microcontroller, the program to control 8 devices through a standard RC5 Remote control.

INCLUDE reg_51.pdf

INPUT   EQU     P3.2    ; Port3,Bit2 is used as input. The demodulated signal                                         ; with active low level is connected to this pin                               RB0     EQU     000H    ; Select Register Bank 0RB1     EQU     008H    ; Select Register Bank 1  ...poke to PSW to use                                                                    DSEG            ; This is internal data memoryORG     20H     ; Bit adressable memory

FLAGS:  DS      1CONTROL BIT     FLAGS.0  ; toggles with every new keystrokeNEW     BIT     FLAGS.1  ; Bit set when a new command has been received

COMMAND: DS     1       ; Received command byteSUBAD:  DS      1       ; Device subaddressTOGGLE: DS     1        ;Toggle every bitANS: DS        1        ;ADDR:        DS        1STACK:  DS      1       ; Stack begins hereCSEG            ; Code begins here

Page 62: Interfacing 7

;---------==========----------==========---------=========---------;              PROCESSOR INTERRUPT AND RESET VECTORS;---------==========----------==========---------=========---------         ORG     00H    ; Reset         JMP     MAIN         ORG     0003H  ; External Interrupt0         JMP     RECEIVE              ;---------==========----------==========---------=========---------;  ---------==========----------==========---------=========---------;  Interrupt 0  routine;  ---------==========----------==========---------=========---------RECEIVE:                       CPL P2.2               MOV  2,#235               ; Time Loop (3/4 bit time)             DJNZ 2,$                  ; Waste Time to sync second bit                MOV  2,#235               ; Time Loop (3/4 bit time)             Djnz 2,$                  ; Waste Time to sync second bit       Mov  2,#134               ; Time Loop (3/4 bit time)             Djnz 2,$                  ; Waste Time to sync second bit                     clr        a       mov        r6,#07h

pol1:        mov        c,Input       rlc        a       Mov  2,#235               ; Waste time for next BIT             Djnz 2,$            Mov  2,#235               ; Time Loop (3/4 bit time)             Djnz 2,$                  ; Waste Time to sync second bit       Mov  2,#235               ; Time Loop (3/4 bit time)             Djnz 2,$                  ; Waste Time to sync second bit       Mov  2,#105               ; Time Loop (3/4 bit time)             Djnz 2,$                  ; Waste Time to sync second bit       djnz        r6,pol1       MOV SUBAD,A              mov        r6,#06hpol2:               mov        c,Input       rlc        a

       Mov  2,#235               ; Waste time for next BIT             Djnz 2,$            Mov  2,#235               ; Time Loop (3/4 bit time)             Djnz 2,$                  ; Waste Time to sync second bit       Mov  2,#235               ; Time Loop (3/4 bit time)             Djnz 2,$                  ; Waste Time to sync second bit       Mov  2,#105               ; Time Loop (3/4 bit time)             Djnz 2,$                  ; Waste Time to sync second bit       djnz        r6,pol2       Mov  COMMAND,A             ; Save Command at IRData memory       

       MOV A,SUBAD       MOV ADDR,A       ANL A,#0FH

Page 63: Interfacing 7

       MOV SUBAD,A       CJNE A,#03H,ZXC1       MOV A,COMMAND       CPL A       MOV COMMAND,A       AJMP ASZZXC1:        MOV A,SUBAD       CJNE A,#00H,ANSS       AJMP ASZ

ASZ:        MOV A,ADDR       ANL A,#20H       MOV TOGGLE,A       CJNE A,ANS,ANSS       AJMP WARANSS:        JMP ANS1        WAR:                              MOV A,COMMAND               CJNE A,#01H,DSP1               CPL P0.0DSP1:        CJNE A,#02H,DSP2               CPL P0.1DSP2:        CJNE A,#03H,DSP3               CPL P0.2DSP3:        CJNE A,#04H,DSP4               CPL P0.3DSP4:        CJNE A,#05H,DSP5               CPL P0.4DSP5:        CJNE A,#06H,DSP6               CPL P0.5DSP6:        CJNE A,#07H,DSP7               CPL P0.6DSP7:        CJNE A,#08H,DSP8               CPL P0.7DSP8:        CJNE A,#0CH,DSP9               MOV P0,#0FFHDSP9:                                              MOV ANS,TOGGLE               MOV A,ANS               CPL ACC.5               MOV ANS,A               SETB   NEW           ; Set flag to indicate the new command

;################################################################       ANS1:           RETI       ;  ---------==========----------==========---------=========---------;  Main routine. Program execution starts here.;  ---------==========----------==========---------=========---------MAIN:          MOV SP,#60H

       SETB   EX0                          ; Enable external Interrupt0

Page 64: Interfacing 7

   CLR    IT0                          ; triggered by a high to low transition              SETB EA; /* Enable global interrupt */  MOV ANS,#00H                ;clear temp toggle bit                  CLR   NEW                      LOO:               JNB NEW,LOO       CLR NEW       AJMP LOO                             END

AT-PC Keyboard Interfacing with AT89C52...................................................................................................................................

Introduction:

The IBM keyboard you most probably have sitting in front of you, sends scan codes to your computer. The scan codes tell your Keyboard Bios, what keys you have pressed or released. Take for example the 'A' Key. The 'A' key has a scan code of 1C (hex). When you press the 'A' key, your keyboard will send 1C down it's serial line. If you are still holding it down, for longer than it's typematic delay, another 1C will be sent. This keeps occurring until another key has been pressed, or if the 'A' key has been released.

However your keyboard will also send another code when the key has been released. Take the example of the 'A' key again, when released, the keyboard will send F0 (hex) to tell you that the key with the proceeding scan code has been released. It will then send 1C, so you know which key has been released.

Your keyboard only has one code for each key. It doesn't care it the shift key has been pressed. It will still send you the same code. It's up to your keyboard BIOS to determine this and take the appropriate action. Your keyboard doesn't even process the Num Lock, Caps Lock and Scroll Lock. When you press the Caps Lock for example, the keyboard will send the scan code for the cap locks. It is then up to your keyboard BIOS to send a code to the keyboard to turn on the Caps lock LED.

Now there's 101 keys and 8 bits make 256 different combinations, thus you only need to send one byte per key, right?

Nop. Unfortunately a handful of the keys found on your keyboard are extended keys, and thus require two scan code. These keys are preceded

Page 65: Interfacing 7

by a E0 (hex). But it doesn't stop at two scan codes either. How about E1,14,77,E1,F0,14,F0,77! Now that can't be a valid scan code? Wrong again. It's happens to be sent when you press the Pause/break key. Don't ask me why they have to make it so long! Maybe they were having a bad day or something?

When an extended key has been released, it would be expect that F0 would be sent to tell you that a key has been released. Then you would expect E0, telling you it was an extended key followed by the scan code for the key pressed. However this is not the case. E0 is sent first, followed by F0, when an extended key has been released.Keyboard Commands:

Besides Scan codes, commands can also be sent to and from the keyboard. The following section details the function of these commands. By no means is this a complete list. These are only some of the more common commands.

Host Commands:

These commands are sent by the Host to the Keyboard. The most common command would be the setting/resetting of the Status Indicators (i.e. the Num lock, Caps Lock & Scroll Lock LEDs). The more common and useful commands are shown below.

ED Set Status LED's - This command can be used to turn on and off the Num Lock, Caps Lock & Scroll Lock LED's. After Sending ED, keyboard will reply with ACK (FA) and wait for another byte which determines their Status. Bit 0 controls the Scroll Lock, Bit 1 the Num Lock and Bit 2 the Caps lock. Bits 3 to 7 are ignored.  EE Echo - Upon sending a Echo command to the Keyboard, the keyboard should reply with a Echo (EE) F0 Set Scan Code Set. Upon Sending F0, keyboard will reply with ACK (FA) and wait for another byte, 01-03 which determines the Scan Code Used. Sending 00 as the second byte will return the Scan Code Set currently in Use  F3 Set Typematic Repeat Rate. Keyboard will Acknowledge command with FA and wait for second byte, which determines the Typematic Repeat Rate. F4 Keyboard Enable - Clears the keyboards output buffer, enables Keyboard Scanning and returns an Acknowledgment. F5 Keyboard Disable - Resets the keyboard, disables Keyboard Scanning and returns an Acknowledgment. FE Resend - Upon receipt of the resend command the keyboard will re- transmit the last byte sent. FF Reset - Resets the Keyboard.

Commands

Page 66: Interfacing 7

Now if the Host Commands are send from the host to the keyboard, then the keyboard commands must be sent from the keyboard to host. If you think this way, you must be correct. Below details some of the commands which the keyboard can send.

FA Acknowledge AA Power On Self Test Passed (BAT Completed) EE See Echo Command (Host Commands) FE Resend - Upon receipt of the resend command the Host should re-transmit the last byte sent.  00 Error or Buffer Overflow FF Error or Buffer OverflowScan Codes

The diagram below shows the Scan Code assigned to the individual keys. The Scan code is shown on the bottom of the key. E.g. The Scan Code for ESC is 76. All the scan codes are shown in Hex.

As you can see, the scan code assignments are quite random. In many cases the easiest way to convert the scan code to ASCII would be to use a look up table. Below is the scan codes for the extended keyboard & Numeric keypad.

Page 67: Interfacing 7

The Keyboard's Connector

The PC's AT Keyboard is connected to external equipment using four wires. These wires are shown below for the 5 Pin DIN Male Plug & PS/2 Plug.

1. KBD Clock2. KBD Data3. N/C4. GND5. +5V (VCC)

1. KBD Clock2. GND3. KBD Data4. N/C5. +5V (VCC)6. N/CThe Keyboard's ProtocolKeyboard to Host

As mentioned before, the PC's keyboard implements a bi-directional protocol. The keyboard can send data to the Host and the Host can send data to the Keyboard. The Host has the ultimate priority over direction. It can at anytime (although the not recommended) send a command to the keyboard.

The keyboard is free to send data to the host when both the KBD Data and KBD Clock lines are high (Idle). The KBD Clock line can be used as a Clear to

Page 68: Interfacing 7

Send line. If the host takes the KBD Clock line low, the keyboard will buffer any data until the KBD Clock is released, ie goes high. Should the Host take the KBD Data line low, then the keyboard will prepare to accept a command from the host.

The transmission of data in the forward direction, ie Keyboard to Host is done with a frame of 11 bits. The first bit is a Start Bit (Logic 0) followed by 8 data bits (LSB First), one Parity Bit (Odd Parity) and a Stop Bit (Logic 1). Each bit should be read on the falling edge of the clock.Interfacing Example - Keyboard to AT89C52 MicrocontrollerNormally in this series of web pages, we connect something to the PC, to demonstrate the protocols at work. However this poses a problem with the keyboard. What could be possibly want to send to the computer via the keyboard interface?

Straight away any devious minds would be going, why not a little box, which generates passwords!. It could keep sending characters to the computer until it finds the right sequence. Well I'm not going to encourage what could possibly be illegal practices.

In fact a reasonably useful example will be given using a AT89C52 single chip microcontroller. We will get it to read the data from the keyboard, convert the scan codes into ASCII and send it out in RS-232 format at 9600 BPS. However we won't stop here, you will want to see the bi-directional use of the KBD Clock & Data lines, thus we will use the keyboards status LEDS, Num Lock, Caps Lock and Scroll Lock.

The keyboard doesn't need to be expensive either. Most people have many old keyboards floating around the place. If it's an AT Keyboard, then use it (XT keyboards will not work with this program.) If we ever see the introduction of USB keyboards, then there could be many redundant AT keyboards just waiting for you to hook them up.AT-PC Keyboard Interfacing with AT89C52...................................................................................................................................

Interfacing Example - Keyboard to AT89C52 MicrocontrollerNormally in this series of web pages, we connect something to the PC, to demonstrate the protocols at work. However this poses a problem with the keyboard. What could be possibly want to send to the computer via the keyboard interface?

Straight away any devious minds would be going, why not a little box, which generates passwords!. It could keep sending characters to the computer until it finds the right sequence. Well I'm not going to encourage what could possibly be illegal practices.

In fact a reasonably useful example will be given using a AT89C52 single chip microcontroller. We will get it to read the data from the keyboard, convert the scan codes into ASCII and send it out in RS-232 format at 9600 BPS. However we won't stop here, you will want to see the bi-directional use of the KBD Clock & Data lines, thus we will use the keyboards status LEDS, Num Lock, Caps Lock and Scroll Lock.

The keyboard doesn't need to be expensive either. Most people have many old keyboards floating around the place. If it's an AT Keyboard, then use it

Page 69: Interfacing 7

(XT keyboards will not work with this program.) If we ever see the introduction of USB keyboards, then there could be many redundant AT keyboards just waiting for you to hook them up.

Circuit Diagram

$mod52;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%;                PORT DECLERATION;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%KEYB_CLOCK        EQU        P2.7KEYB_DATA        EQU        P2.6

KB_LSHIFT        EQU      12H

Page 70: Interfacing 7

    KB_RSHIFT        EQU      59H    KB_CTRL                EQU      14H    KB_ALT                EQU      11H    KB_CAPS                EQU      58H    KB_SCROLL        EQU      7EH    KB_NUML                EQU      77H    KB_TAB                EQU      0DH    KB_REL                EQU      0F0H    KB_EXT                EQU      0E0H    KB_PAUSE        EQU      0E1H       CAPS                EQU          01H    NUML                EQU          02H    SCROLL        EQU          04H    SHIFT        EQU          08H    ACK                EQU          10H    CTRL                EQU          20H    ALT                EQU          40H       RELEASE        EQU                80H    PAUSED        EQU         40H    EXTENDED EQU       80H   DSEG            ; This is internal data memoryORG     20H     ; Bit adressable memoryFLAGS1:        DS                1RECEIVED        BIT FLAGS1.0AM                        BIT        FLAGS1.1MAS                BIT        FLAGS1.2KEYBRD        BIT        FLAGS1.3AMS                BIT        FLAGS1.4

CAPPS_ON:        DS                1CAAPS                BIT        CAPPS_ON

KB_OK:                DS                1KB_DATA:                DS                1KB_STATS:                DS                1KB_SCAN:                DS                1KB_TEMP:                DS                1  ; For the da*n pause keyKB_COUNT:                DS                1NAMES:                DS                16COUNTT:                DS                1STACK:                DS           1CSEG            ; Code begins here        ;  ---------==========----------==========---------=========---------;  Main routine. Program execution starts here.;  ---------==========----------==========---------=========---------               ORG     00H    ; Reset               AJMP MAIN                          ORG 23H               JMP SERIAL;  ---------==========----------==========---------=========---------   MAIN:                

Page 71: Interfacing 7

            MOV    SP,#STACK                       MOV TMOD,#20H                ;Enable Timer 1 from Baud rate Generation               MOV TH1,#0FDH               MOV SCON,#50H                ;Enable serial port for 9600Baud rate               SETB ES               SETB EA                        ;Enable serial port interrupt               SETB TR1               CALL InitKeyb                ;Inizialize Keyboard             MOV a, KB_OK             JZ KBNotOK               LOOPS:         CALL Check_Keyb                ;Check for any keypress               JNC LOOPS               MOV A,KB_DATA                ;get data               MOV SBUF,A               AJMP LOOPS

;---------==========----------==========---------=========---------;                SERIAL INTERRUPT ROUTINE;---------==========----------==========---------=========---------SERIAL:                               JB TI,TRANS               CLR RI               RETITRANS:        CLR TI               RETI;**********************************************************

KBNotOK:               AJMP $                ;Keyboard Error;---------------------; Keyboard Routines:;---------------------;*************************************; WaitKB: Wait for keypress;*************************************WaitKB:        call   Check_Keyb        jnc     WaitKB        ret;*************************************; InitKeyb: c=1 if ACK OK;*************************************CheckACK:        mov     a, KB_STATS        mov     c, acc.4        clr     acc.4        mov     KB_STATS, a        ret

;*************************************; InitKeyb:

Page 72: Interfacing 7

;*************************************InitKeyb:        mov     KB_TEMP, #0        mov     KB_OK, #0        mov     r1, #0FFH        call   Write_Keyb        call   Check_Keyb        call   CheckACK        jnc     InitKeyb

        mov     r1, #0F4H       ; Enable       call   Write_Keyb        call   Check_Keyb        call   CheckACK        jnc     KeybErr

        mov     r1, #0F3H       ; Set Typematic        call   Write_Keyb        call   Check_Keyb        call   CheckACK        jnc     KeybErr        mov     r1, #00H      ; Typematic = 250 ms / 30 cps        call   Write_Keyb        call   Check_Keyb        call   CheckACK        jnc     KeybErr

        mov     KB_OK, #1        mov     KB_STATS, #2    ; Num Lock ON

;*************************************; Keyb_Leds: Set KB_STATS as leds;*************************************Keyb_Leds:        mov     r1, #0EDH       ; Set Leds        call   Write_Keyb        call   Check_Keyb        call   CheckACK        jnc     KeybErr        mov     r1, KB_STATS        call   Write_Keyb        call   Check_Keyb        call   CheckACKKeybErr:        ret;*************************************; Zero2One: Wait for 0 to 1 on kb; clock line, read the kb data line; and shift right the bit to acc.7;*************************************Zero2One:        jnb     KEYB_CLOCK, $        jb      KEYB_CLOCK, $        mov     c, KEYB_DATA        rrc     a        ret

Page 73: Interfacing 7

;*************************************; Check_Keyb: Check to see if any key; are pressed or release, returns; ASCII codes on KB_DATA, or 1 for; special keys, 2 for same special; with shift. Return also the scan; code on KB_SCAN.; Special Keys are basicaly all non; printable keys. See the table below; all 1 and 2 returned are special keys;*************************************Check_Keyb:        setb    KEYB_DATA        setb    KEYB_CLOCK              ; CLOCK &amp; DATA high = Idle Pos        mov     r0, #50                CheckAgain:        jnb     KEYB_CLOCK, KeyHit        djnz    r0, CheckAgain          ; check r0 times        sjmp    KeyEndKeyHit:        jnb     KEYB_DATA, KeyHit2      ; Start bit must be 0KeyEnd:        clr     KEYB_CLOCK              ; disable keyb        clr     c                       ; c=0 = no keypress        retKeyHit2:        mov     r0, #8          ; 8 bits        clr     aKeyHit3:        call   Zero2One        djnz    r0, KeyHit3        mov     r1, a

        clr     a        call   Zero2One        ; Parity bit        call   Zero2One        ; Stop bit        ; acc.7 = stop, acc.6 = parity        clr     KEYB_CLOCK

        mov     a, KB_TEMP        jz      NoIgnore               dec     KB_TEMP         ; Igonre pause scans        sjmp    ChkKbEndNC

NoIgnore:        mov     KB_SCAN, r1

        cjne    r1, #0FAH, NoKbACK        orl     KB_STATS, #ACK        sjmp    ChkKbEndNC

NoKbACK:        cjne    r1, #KB_PAUSE, NoKbPause        mov     KB_TEMP, #7             ; Ignore next 7 scans        mov     a, KB_OK        cpl     acc.6

Page 74: Interfacing 7

        mov     KB_OK, a        sjmp    ChkKbEndNC

NoKbPause:        cjne    r1, #KB_EXT, NoKbExt        orl     KB_OK, #EXTENDED        sjmp    ChkKbEndNC

NoKbExt:        cjne    r1, #KB_REL, NoRelease        orl     KB_STATS, #RELEASE        sjmp    ChkKbEndNC

NoRelease:; Test Num lock, if pressed toggle led        cjne    r1, #KB_NUML, NoNumLock        mov     a, KB_STATS        jnb     acc.7, ChkKbEndNC        cpl     acc.1        clr     acc.7        mov     KB_STATS, a        call   Keyb_Leds        sjmp    ChkKbEndNC

NoNumLock:; Test Caps lock, if pressed toggle led        cjne    r1, #KB_CAPS, NoCapsLock        mov     a, KB_STATS        jnb     acc.7, ChkKbEndNC        cpl     acc.2        clr     acc.7        mov     KB_STATS, a        call   Keyb_Leds        sjmp    ChkKbEndNC

NoCapsLock:; Test Scroll lock, if pressed toggle led        cjne    r1, #KB_SCROLL, NoScrollLock        mov     a, KB_STATS        jnb     acc.7, ChkKbEndNC        cpl     acc.0        clr     acc.7        mov     KB_STATS, a        call   Keyb_LedsChkKbEndNC:        clr     c        ret

NoScrollLock:; Test L &amp; R shifts, set bit if pressed, clear on release        cjne    r1, #KB_LSHIFT, NoShift1ShiftOK:        mov     a, KB_STATS        jbc     acc.7, ShiftRel        setb    acc.3           ; not releasing, so Set SHIFT bit        sjmp    ShiftEndShiftRel:

Page 75: Interfacing 7

        clr     acc.3           ; releasing, so Clear SHIFT bitShiftEnd:        mov     KB_STATS, a        sjmp    ChkKbEndNC     NoShift1:        cjne    r1, #KB_RSHIFT, NoShift        sjmp    ShiftOK

NoShift:        cjne    r1, #KB_CTRL, NoCtrl        mov     a, KB_STATS        jbc     acc.7, CtrlRel        setb    acc.5           ; not releasing, so Set CTRL bit        sjmp    CtrlEndCtrlRel:        clr     acc.5           ; releasing, so Clear SHIFT bitCtrlEnd:        mov     KB_STATS, a        sjmp    ChkKbEndNC     

NoCtrl:        cjne    r1, #KB_ALT, NoAlt        mov     a, KB_STATS        jbc     acc.7, AltRel        setb    acc.6           ; not releasing, so Set ALT bit        sjmp    AltEndAltRel:        clr     acc.6           ; releasing, so Clear ALT bitAltEnd:        mov     KB_STATS, a        sjmp    ChkKbEndNC     

NoAlt:        mov     a, KB_STATS             ; Releasing key test        jnb     acc.7, NoRel2                  clr     acc.7                   ; if releasing &gt; clear        mov     KB_STATS, a             ; rel bit on KB_STATS        clr     c                       ; and do nothing        retNoRel2:        mov     a, KB_OK                ; Extended key test        jnb     acc.7, KbChars                  clr     acc.7                   ; if Extended &gt; clear        mov     KB_OK, a                ; EXT bit on KB_OK        clr     c                       ; and do nothing        retKbChars:mov     dptr, #KbScanCodes        mov     a, KB_STATS        jnb     acc.2, TestShift        jb      acc.3, KbChkOK        mov     a, r1        movc    a, @a+dptr        mov     r0, a        subb    a, #97        jc      KbChkOK        mov     a, r0        subb    a, #123

Page 76: Interfacing 7

        jnc     KbChkOK        mov     dptr, #KbScanCodes2     ; if (a to z) &amp; Caps &gt; table 2        sjmp    KbChkOKTestShift:        jnb     acc.3, KbChkOK        mov     dptr, #KbScanCodes2     ; with shift table 2KbChkOK:        mov     a, r1        movc    a, @a+dptr        mov     KB_DATA, a        setb    c               ret

;*************************************; Zero2One2: Wait for high to low in; kb clock line;*************************************Zero2One2:        jnb     KEYB_CLOCK, $        jb      KEYB_CLOCK, $        ret;*************************************; Write_Keyb: Send r1 to the kb;*************************************Write_Keyb:        mov     r0, #8          ; 8 bits to receive        clr     KEYB_CLOCK      ; break the Keyboard        mov        r7, #00H       ; some delay (safety reasons)_WKwait:djnz        r7, _WKwait        clr     KEYB_DATA       ; request to send        setb    KEYB_CLOCK      ; enable the Keyboard        acall   Zero2One2       ; Start Bit        mov     a, r1           ; Data BitsTxData:        rrc     a        mov     KEYB_DATA, c        call   Zero2One2        djnz    r0, TxData

        mov     a, r1           ; calculate parity bit        mov     c, psw.0        ; this is Even parity        cpl     c               ; and Keyboard needs Odd parity        mov     KEYB_DATA, c    ; send parity bit        call   Zero2One2

        setb    KEYB_DATA       ; send stop bit        call   Zero2One2

        call   Zero2One2        mov     c, KEYB_DATA    ; get ACK bit        clr     KEYB_CLOCK      ; stop the keyboard            ret;*************************************; last 262 addr of code mem with scan codes tables

Page 77: Interfacing 7

;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$               ; last 262 addr of code mem with scan codes tablesKbScanCodes:; Keyboard Scancodes;       ?,  F9, ?,  F5,  F4,  F1,  F2, F12, ?, F10,  F8,  F6,  F4, TAB,  ~db     0,  1 , 0,  1 ,  1 ,  1 ,  1 ,  1 , 0,  1 ,  1 ,  1 ,  1 ,  1 , '~';       ?, ?,Lalt,Lshf, ?,Lctr,  Q ,  ! , ?, ?, ?,  Z ,  S ,  A ,  W ,  @db     0, 0,  0 ,  0 , 0,  0 , 'q', '1', 0, 0, 0, 'z', 's', 'a', 'w', '2';       ?, ?,  C ,  X ,  D ,  E ,  $ ,  # , ?, ?, " ",  V ,  F ,  T ,  Rdb     0, 0, 'c', 'x', 'd', 'e', '4', '3', 0, 0, ' ', 'v', 'f', 't', 'r';       % , ?, ?,  N ,  B ,  H ,  G ,  Y ,  ^ , ?, ?, ?,  M ,  J ,  U ,  &db    '5', 0, 0, 'n', 'b', 'h', 'g', 'y', '6', 0, 0, 0, 'm', 'j', 'u', '7';       * , ?, ?,  < ,  K ,  I ,  O ,  ) ,  ( , ?, ?,  > ,  ? ,  L ,  : ,  Pdb    '8', 0, 0, ',', 'k', 'i', 'o', '0', '9', 0, 0, '.', '/', 'l', ';', 'p';       _ , ?, ?, ?,  " , ?,  { ,  + , ?, ?,Caps,Rshf,Entr,  } , ?,  |db    '-', 0, 0, 0, 39 ,  0,  '[',  '=', 0, 0,  0 ,  0 ,  1 , ']', 0,  92;       ?, ?, ?, ?, ?, ?, ?, ?,BkSp, ?, ?,  1 , ?,  4 ,  7 , ?, ?, ?,  0db     0, 0, 0, 0, 0, 0, 0, 0,  1 , 0, 0, '1', 0, '4', '7', 0, 0, 0, '0';       . ,  2 ,  5 ,  6 ,  8 , ESC,Numl, F11,  + ,  3 ,  - ,  * ,  9 ,Scrldb    '.', '2', '5', '6', '8',  1 ,  0 ,  1 , '+', '3', '-', '*', '9',  0;       ?, ?, ?, ?,  F7db     0, 0, 0, 0,  1

KbScanCodes2:; Keyboard Scancodes with shift;       ?,  F9, ?,  F5,  F4,  F1,  F2, F12, ?, F10,  F8,  F6,  F4, TAB,  ~db     0,  2 , 0,  2 ,  2 ,  2 ,  2 ,  2 , 0,  2 ,  2 ,  2 ,  2 ,  2 , '`';       ?, ?,Lalt,Lshf, ?,Lctr,  Q ,  ! , ?, ?, ?,  Z ,  S ,  A ,  W ,  @db     0, 0,  0 ,  0 , 0,  0 , 'Q', '!', 0, 0, 0, 'Z', 'S', 'A', 'W', '@';       ?, ?,  C ,  X ,  D ,  E ,  $ ,  # , ?, ?, " ",  V ,  F ,  T ,  Rdb     0, 0, 'C', 'X', 'D', 'E', '$', '#', 0, 0, ' ', 'V', 'F', 'T', 'R';       % , ?, ?,  N ,  B ,  H ,  G ,  Y ,  ^ , ?, ?, ?,  M ,  J ,  U ,  &db    '%', 0, 0, 'N', 'B', 'H', 'G', 'Y', '^', 0, 0, 0, 'M', 'J', 'U', '&';       * , ?, ?,  < ,  K ,  I ,  O ,  ) ,  ( , ?, ?,  > ,  ? ,  L ,  : ,  Pdb    '*', 0, 0, '<', 'K', 'I', 'O', ')', '(', 0, 0, '>', '?', 'L', ':', 'P';       _ , ?, ?, ?,  " , ?,  { ,  + , ?, ?,Caps,Rshf,Entr,  } , ?,  |db    '_', 0, 0, 0, '"', 0, '{', '+', 0, 0,  0 ,  0 ,  2 , '}', 0, '|'

Page 78: Interfacing 7

;       ?, ?, ?, ?, ?, ?, ?, ?,BkSp, ?, ?,  1 , ?,  4 ,  7 , ?, ?, ?,  0db     0, 0, 0, 0, 0, 0, 0, 0,  2 , 0, 0, '1', 0, '4', '7', 0, 0, 0, '0';       . ,  2 ,  5 ,  6 ,  8 , ESC,Numl, F11,  + ,  3 ,  - ,  * ,  9 ,Scrldb    '.', '2', '5', '6', '8',  2 ,  0 ,  2 , '+', '3', '-', '*', '9',  0;       ?, ?, ?, ?,  F7db     0, 0, 0, 0,  2                                                    END

RTC (DS1307)  Interfacing with AT89C2051...................................................................................................................................

Circuit Diagram;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%;                PORT DECLERATION;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%SDA        EQU        P3.5  ;SDA=PIN5SCL        EQU        P3.4        ;SCL=PIN6

DS1307W   EQU    0D0H     ; SLAVE ADDRESS 1101 000 + 0 TO WRITEDS1307R   EQU    0D1H     ; SLAVE ADDRESS 1101 000 + 1 TO READ

; **********************************************************; Main Program; **********************************************************               CALL OSC_CONTROL                ;Initilize the RTCREPEAT:        CALL READ_CLOCK                ;Read Clock               AJMP REPEAT

; **********************************************************; SUB SETS THE DS1307 OSCILLATOR; **********************************************************

OSC_CONTROL:         ACALL       SEND_START ; GENERATE START CONDITION         MOV         A,#DS1307W ; 1101 0000 ADDRESS + WRITE-BIT         ACALL       SEND_BYTE  ; SEND BYTE TO 1307         MOV         A,#00H     ; ADDRESS BYTE TO REGISTER 00H         ACALL       SEND_BYTE  ; SECONDS REGISTER, ALWAYS LEAVE         SETB        LASTREAD   ; REG 00H-BIT #7 = 0 (LOW)         ACALL       SEND_STOP  ; IF REG 00H-BIT #7 = 1 CLOCK         ACALL       SEND_START ; OSCILLATOR IS OFF.         MOV         A,#DS1307R ; 1101 0001 ADDRESS + READ-BIT         ACALL       SEND_BYTE  ;         ACALL       READ_BYTE  ; READ A BYTE FROM THE 1307         CLR         ACC.7      ; CLEAR REG 00H-BIT #7 TO ENABLE

Page 79: Interfacing 7

OSC_SET:                        ; OSCILLATOR.         PUSH        ACC        ; SAVE ON STACK         ACALL       SEND_STOP  ;         ACALL       SEND_START ;         MOV         A,#DS1307W ; SETUP TO WRITE         ACALL       SEND_BYTE  ;         MOV         A,#00H     ; REGISTER 00H ADDRESS         ACALL       SEND_BYTE  ;         POP         ACC        ; GET DATA TO START OSCILLATOR         ACALL       SEND_BYTE  ; SEND IT         ACALL       SEND_STOP        RET; **********************************************************        ; THIS SUB CONTROLS THE SQW OUTPUT 1HZ; **********************************************************        SQW_CONTROL_1HZ:       LCALL SEND_START        ; SEND START CONDITION       MOV A,#DS1307W                ; SET POINTER TO REG 07H ON                               ; DS1307       LCALL SEND_BYTE       MOV A,#07H       LCALL SEND_BYTE       MOV A,#90H                ; SQW/OUT ON AT 1HZ       JNB SQW,SQW_SET                 ; JUMP IF SQW BIT IS ACTIVE       MOV A,#80H                ; TURN SQW/OUT OFF – OFF HIGHSQW_SET:       LCALL SEND_BYTE       LCALL SEND_STOP       RET; **********************************************************        ; THIS SUB READS ONE BYTE OF DATA FROM THE DS1307; **********************************************************

READ_BYTE:         MOV         BITCNT,#08H; SET COUNTER FOR 8-BITS DATA         MOV         A,#00H         SETB        SDA        ; SET SDA HIGH TO ENSURE LINE                                ; FREEREAD_BITS:         SCL_HIGH               ; TRANSITION SCL LOW-TO-HIGH         MOV         C,SDA      ; MOVE DATA BIT INTO CARRY         RLC         A          ; ROTATE CARRY-BIT INTO ACC.0         CLR         SCL        ; TRANSITION SCL HIGH-TO-LOW         DJNZ        BITCNT,READ_BITS                                ; LOOP FOR 8-BITS         JB          LASTREAD,ACKN                                ; CHECK TO SEE IF THIS IS                                ; THE LAST READ         CLR         SDA        ; IF NOT LAST READ SEND ACK-BIT

ACKN:         SCL_HIGH               ; PULSE SCL TO TRANSMIT ACKNOWLEDGE         CLR         SCL        ; OR NOT ACKNOWLEDGE BIT         RET

; **********************************************************; SUB SENDS START CONDITION

Page 80: Interfacing 7

; **********************************************************

SEND_START:         SETB        _2W_BUSY   ; INDICATE THAT 2-WIRE         CLR         ACKS        ; OPERATION IS IN PROGRESS         CLR         BUS_FLT    ; CLEAR STATUS FLAGS         JNB         SCL,FAULT         JNB         SDA,FAULT         SETB        SDA        ; BEGIN START CODITION         SCL_HIGH         CLR         SDA         ACALL       DEELAY         CLR         SCL         RETFAULT:         SETB        BUS_FLT         RET

; **********************************************************; SUB SENDS STOP CONDITION; **********************************************************SEND_STOP:         CLR         SDA         SCL_HIGH         SETB        SDA         CLR         _2W_BUSY         RET; **********************************************************; SUB DELAYS THE BUS; **********************************************************DEELAY:         NOP                    ; DELAY FOR BUS TIMING         RET; **********************************************************; THIS SUB SENDS 1 BYTE OF DATA TO THE DS1307; CALL THIS FOR EACH REGISTER SECONDS TO YEAR; ACC MUST CONTAIN DATA TO BE SENT TO CLOCK; **********************************************************SEND_BYTE:         MOV         BITCNT,#08H; SET COUNTER FOR 8-BITSSB_LOOP:         JNB         ACC.7,NOTONE; CHECK TO SEE IF BIT-7 OF         SETB        SDA        ; ACC IS A 1, AND SET SDA HIGH         JMP         ONENOTONE:         CLR         SDA        ; CLR SDA LOWONE:         SCL_HIGH               ; TRANSITION SCL LOW-TO-HIGH         RL          A          ; ROTATE ACC LEFT 1-BIT         CLR         SCL        ; TRANSITION SCL LOW-TO-HIGH         DJNZ        BITCNT,SB_LOOP; LOOP FOR 8-BITS         SETB        SDA        ; SET SDA HIGH TO LOOK FOR         SCL_HIGH               ; ACKNOWLEDGE PULSE         CLR         ACKS         JNB         SDA,SB_EX  ; CHECK FOR ACK OR NOT ACK         SETB        ACKS        ; SET ACKNOWLEDGE FLAG FOR                                ; NOT ACK

Page 81: Interfacing 7

SB_EX:         CALL       DEELAY      ; DELAY FOR AN OPERATION         CLR         SCL        ; TRANSITION SCL HIGH-TO-LOW         CALL       DEELAY      ; DELAY FOR AN OPERATION         RET; **********************************************************; SUB READS THE CLOCK AND WRITES IT TO THE SCRATCHPAD MEMORY; ON RETURN FROM HERE DATE & TIME DATA WILL BE STORED IN THE; DATE & TIME REGISTERS FROM 24H (SECS) TO 2AH (YEAR); ALARM SETTINGS IN REGISTERS 2CH(HRS) AND 2DH(MINUTES).; **********************************************************READ_CLOCK:         MOV         R1,#SECS   ; SECONDS STORAGE LOCATION         MOV         BYTECNT,#00H         CLR         LASTREAD         CALL       SEND_START         MOV         A,#DS1307W         CALL       SEND_BYTE         MOV         A,#00H         CALL       SEND_BYTE         CALL       SEND_STOP         CALL       SEND_START         MOV         A,#DS1307R         CALL       SEND_BYTE

READ_LOOP:         MOV         A,BYTECNT         CJNE        A,#09H,NOT_LAST         SETB        LASTREAD

NOT_LAST:         CALL       READ_BYTE         MOV         @R1,A         MOV         A,BYTECNT         CJNE        A,#00H,NOT_FIRST         MOV         A,@R1         CLR         ACC.7      ; ENSURE OSC BIT=0 (ENABLED)         MOV         @R1,ANOT_FIRST:         INC         R1         INC         BYTECNT         MOV         A,BYTECNT         CJNE        A,#0AH,READ_LOOP         CALL       SEND_STOP         RET;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&  ;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((;                STORE THE TIME TO RTC CHIP;(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((       STORE_RTC:       LCALL SEND_START                ; SEND 2WIRE START CONDITION       MOV A,#DS1307W                        ; LOAD DS1307 WRITE COMMAND

Page 82: Interfacing 7

       LCALL SEND_BYTE                ; SEND WRITE COMMAND       MOV A,#01H                        ; SET DS1307 DATA POINTER TO BEGINNING       LCALL SEND_BYTE                ; OF 00H       MOV A,MINS                        ; Send min       LCALL SEND_BYTE                       MOV A,HRS                        ;send hr       SETB ACC.6        ;12 HR MODE       JNB AMS,YUH       CLR ACC.5                        ;AM/PM                1=PM,0=AM       AJMP YUH1YUH: SETB ACC.5        YUH1:        LCALL SEND_BYTE       MOV A,DAY                        ; Send Day       LCALL SEND_BYTE                       MOV A,DATE1                        ; Send date       LCALL SEND_BYTE                               MOV A,MONTH                        ; Send month       LCALL SEND_BYTE       MOV A,YEAR                        ; Send yr       LCALL SEND_BYTE       LCALL SEND_STOP                ; SEND 2WIRE STOP CONTION       RET;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

Serial EEPROM Interfacing (AT24C08 with AT89C2051)...................................................................................................................................

Introduction:

Many designers today are implementing embedded systems that require low cost non-volatile memory. Microchip has addressed this need with a full line of serial EEPROMs, in a variety of memory configurations, using the industry-standard 2- or 3-wire communication protocols.Circuit Diagram

Page 83: Interfacing 7

SDA1        EQU        P1.1         ;SDA=PIN5SCL1        EQU        P1.0                ;SCL=PIN6

WTCMD EQU   10100000B       ;WRITE DATA COMMANDRDCMD EQU   10100001B       ;READ DATA COMMAND

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%;                STORE A BYTE IN EEPROM  (Data 8F in address location 2AH);%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                                MOV A,#WTCMD ;LOAD WRITE COMMAND               CALL OUTS ;SEND IT               MOV A,#2AH ;GET BYTE ADDRESS               CALL OUT ;SEND IT               MOV A,#8FH ;GET DATA               CALL OUT ;SEND IT               CALL STOP ;SEND STOP CONDITION

Page 84: Interfacing 7

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%;                        READ A BYTE FROM EEPROM FROM ADDRESS LOCATION 4DH;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                                MOV     A,#WTCMD        ;LOAD WRITE COMMAND TO SEND ADDRESS               CALL    OUTS            ;SEND IT              MOV     A,#4DH            ;GET LOW BYTE ADDRESS              CALL    OUT             ;SEND IT              CALL    CREAD           ;GET DATA BYTE              MOV A,R1               CALL MDELAY                                RET;***********************************************************************;                EEPROM ROUTINES;***********************************************************************

;***********************************************************************; THIS ROUTINE SENDS OUT CONTENTS OF THE ACCUMULATOR; to the EEPROM and includes START condition.  Refer to the data sheets; for discussion of START and STOP conditions.;***********************************************************************

OUTS:   MOV     R2,#8           ;LOOP COUNT -- EQUAL TO BIT COUNT        SETB   SDA1            ;INSURE DATA IS HI                      SETB    SCL1            ;INSURE CLOCK IS HI        NOP                     ;NOTE 1        NOP                            NOP        CLR     SDA1            ;START CONDITION -- DATA = 0        NOP                     ;NOTE 1        NOP             NOP        CLR     SCL1            ;CLOCK = 0OTSLP:  RLC     A               ;SHIFT BIT        JNC     BITLS        SETB    SDA1            ;DATA = 1        JMP     OTSL1           ;CONTINUEBITLS:  CLR     SDA1            ;DATA = 0OTSL1:  SETB    SCL1            ;CLOCK HI        NOP                     ;NOTE 1        NOP        NOP               CLR     SCL1            ;CLOCK LOW        DJNZ    R2,OTSLP        ;DECREMENT COUNTER        SETB    SDA1            ;TURN PIN INTO INPUT        NOP                     ;NOTE 1                                    SETB    SCL1            ;CLOCK ACK        NOP                     ;NOTE 1        NOP        NOP     

Page 85: Interfacing 7

        CLR     SCL1        RET

;**********************************************************************; THIS ROUTINE SENDS OUT CONTENTS OF ACCUMLATOR TO EEPROM; without sending a START condition.;**********************************************************************

OUT:    MOV     R2,#8           ;LOOP COUNT -- EQUAL TO BIT COUNTOTLP:   RLC     A               ;SHIFT BIT        JNC     BITL                   SETB    SDA1            ;DATA = 1        JMP     OTL1            ;CONTINUEBITL:   CLR     SDA1            ;DATA = 0OTL1:   SETB    SCL1            ;CLOCK HI        NOP                     ;NOTE 1        NOP        NOP            CLR     SCL1            ;CLOCK LOW        DJNZ    R2,OTLP         ;DECREMENT COUNTER        SETB    SDA1            ;TURN PIN INTO INPUT        NOP                     ;NOTE 1            SETB    SCL1            ;CLOCK ACK        NOP                     ;NOTE 1        NOP        NOP             CLR     SCL1        RET

STOP:   CLR     SDA1            ;STOP CONDITION SET DATA LOW        NOP                     ;NOTE 1        NOP        NOP             SETB    SCL1            ;SET CLOCK HI        NOP                     ;NOTE 1        NOP        NOP             SETB    SDA1            ;SET DATA HIGH        RET;*******************************************************************; THIS ROUTINE READS A BYTE OF DATA FROM EEPROM; From EEPROM current address pointer.; Returns the data byte in R1;*******************************************************************CREAD:  MOV     A,#RDCMD        ;LOAD READ COMMAND        CALL    OUTS            ;SEND IT        CALL    IN              ;READ DATA        MOV     R1,A            ;STORE DATA        CALL    STOP            ;SEND STOP CONDITION        RET

Page 86: Interfacing 7

;**********************************************************************; THIS ROUTINE READS IN A BYTE FROM THE EEPROM; and stores it in the accumulator;**********************************************************************

IN:     MOV     R2,#8           ;LOOP COUNT        SETB    SDA1            ;SET DATA BIT HIGH FOR INPUTINLP:   CLR     SCL1            ;CLOCK LOW        NOP                     ;NOTE 1        NOP        NOP        NOP            SETB    SCL1            ;CLOCK HIGH        CLR     C               ;CLEAR CARRY        JNB     SDA1,INL1       ;JUMP IF DATA = 0        CPL     C               ;SET CARRY IF DATA = 1INL1:   RLC     A               ;ROTATE DATA INTO ACCUMULATOR        DJNZ    R2,INLP         ;DECREMENT COUNTER        CLR     SCL1            ;CLOCK LOW        RET

;*********************************************************************; This routine test for WRITE DONE condition; by testing for an ACK.; This routine can be run as soon as a STOP condition; has been generated after the last data byte has been sent; to the EEPROM. The routine loops until an ACK is received from; the EEPROM. No ACK will be received until the EEPROM is done with; the write operation.;*********************************************************************ACKTST: MOV     A,#WTCMD        ;LOAD WRITE COMMAND TO SEND ADDRESS        MOV     R2,#8           ;LOOP COUNT -- EQUAL TO BIT COUNT        CLR     SDA1            ;START CONDITION -- DATA = 0        NOP                     ;NOTE 1        NOP        NOP                  CLR     SCL1            ;CLOCK = 0AKTLP:  RLC     A               ;SHIFT BIT        JNC     AKTLS        SETB    SDA1            ;DATA = 1        JMP     AKTL1           ;CONTINUEAKTLS:  CLR     SDA1            ;DATA = 0AKTL1:  SETB    SCL1            ;CLOCK HI        NOP                     ;NOTE 1        NOP        NOP             CLR     SCL1            ;CLOCK LOW        DJNZ    R2,AKTLP        ;DECREMENT COUNTER        SETB    SDA1            ;TURN PIN INTO INPUT        NOP                     ;NOTE 1             SETB    SCL1            ;CLOCK ACK        NOP                     ;NOTE 1        NOP

Page 87: Interfacing 7

        NOP              JNB     SDA1,EXIT       ;EXIT IF ACK (WRITE DONE)        JMP     ACKTST          ;START OVEREXIT:   CLR     SCL1            ;CLOCK LOW        CLR     SDA1            ;DATA LOW        NOP                     ;NOTE 1        NOP        NOP             SETB    SCL1            ;CLOCK HIGH        NOP        NOP        SETB    SDA1            ;STOP CONDITION        RET;*********************************************************************

Keypad Interfacing......................................................................................................................................

Keyboards and LCDs are the most widely used input/output devices of the 8051, and a basic understanding of them is essential. In this section, we first discuss keyboard fundamentals, along with key press and key detection mechanisms, Then we show how a keyboard is interfaced to an 8051.

Interfacing the Keyboard to the 8051

At the lowest level, keyboards are organized in a matrix of rows and columns. The CPU accesses both rows and column through ports; therefore, with two 8-bit ports, an 8*8 matrix of keys can be connected to a microprocessor. When a key pressed, a row and column make a connect; otherwise, there is no connection between row and column. In IBM PC keyboards, a single microcontroller (consisting of microprocessor, RAM and EPROM, and several ports all on a single chip) takes care of software and hardware interfacing of keyboard. In such systems it is the function of programs stored in the EPROM of microcontroller to scan the keys continuously, identify which one has been activated, and present it to the motherboard. In this section we look at the mechanism by which the 8051 scans and identifies the key.

Scanning and identifying the key               Figure13.5 shows a 4*4 matrix connected to two ports. The rows are connected to an output port and the columns are connected to an input port. If no key has been pressed, reading the input port will yield 1s for all columns since they are all connected to high (Vcc) If all the rows are grounded and a key is pressed, one of the columns will have 0 since the key pressed provides the path to ground. It is the function of the microcontroller to scan the keyboard continuously to detect and identify the key pressed. How it is done is explained next.

Page 88: Interfacing 7

Grounding rows and reading columns               To detect a pressed key, the microcontroller grounds all rows by providing 0 to the output latch, and then it reads the columns. If the data read from the columns is D3-D0=1111, no key has been pressed and the process continues until a key press is detected. However, if one of the column bits has a zero, this means that a key press has occurred. For example, if D3-D0=1101, this means that a key in the D1 column has been pressed. After a key press is detected, the microcontroller will go through the process of identifying the key. Starting with the top row, the microcontroller grounds it by providing a low to row D0 only; then it reads the columns. If the data read is all1s, no key in that row is activated and the process is moved to the next row. It grounds the next row, reads the columns, and checks for any zero. This process continues until the row is identified. After identification of the row in which the key has been pressed, the next task is to find out which column the pressed key belongs to. This should be easy since the microcontroller knows at any time which row and column are being accessed.

Assembly language program for detection and identification of key activation is given below. In this program, it is assumed that P1 and P2 are initialized as output and input, respectively. Program13.1 goes through the following four major stages:

1.        To make sure that the preceding key has been released, 0s are output to all rows at once, and the columns are read and checked repeatedly until all the columns are high. When all columns are found to be

Page 89: Interfacing 7

high, the program waits for a short amount of time before it goes to the next stage of waiting for a key to be pressed.       2)        To see if any key is pressed, the columns are scanned over and over in an infinite loop until one of them has a 0 on it. Remember that the output latches connected to rows still have their initial zeros (provided in stage 1), making them grounded. After the key press detection, it waits 20ms for the bounce and then scans the columns again. This serves two functions: (a) it ensures that the first key press detection was not an erroneous one due to spike noise, and(b) the 20ms delay prevents the same key press from being interpreted as a multiple key press. If after the 20-ms delay the key is still pressed, it goes to the next stage to detect which row it belongs to; otherwise, it goes back into the loop to detect a real key press        

3)        To detect which row the key press belongs to, it grounds one row at a time, reading the columns each time. If it finds that all columns are high, this means that the key press cannot belong to that row; therefore, it grounds the next row and continues until it finds the row the key press belongs to. Upon finding the row that the key press belongs to, it sets up the starting address for the look-up table holding the scan codes (or the ASCII value) for that row and goes to the next stage to identify the key.4)        To identify the key press, it rotates the column bits, one bit at a time, into the carry flag and checks to see if it is low. Upon finding the zero, it pulls out the ASCII code for that key from the look-up table; Otherwise, it increments the pointer to point to the next element of the look-up table.

While the key press detection is standard for all keyboards, the process for determining which key is pressed varies. The look-up table method shown in program can be modified to work with any matrix up to 8*8.

There are IC chips such as National Semiconductors MM74C923 that incorporate keyboard scanning and decoding all in one chip. Such chips use combinations of counters and logic gates (No microcontroller).

Keypad Interfacing...................................................................................................................................

;Keyboard subroutine. This program sends the ASCII code;for pressed key to P0.1 ;P1.0-P1.3 connected to rows P2.0-P2.3 connected to columns

       MOV P2,#0FFH             ;make P2 an input portK1:    MOV P1,#0                ;ground all rows at once       MOV A,P2                 ;read all col. (ensure all keys open)       ANL A,00001111B          ;masked unused bits       CJNE A,#00001111B,K1   ;check til all keys releasedK2:    ACALL DELAY            ;call 20 msec delay       MOV A,P2               ;see if any key is pressed       ANL A,#00001111B       ;mask unused bits       CJNE A,#00001111B,OVER ;key pressed, await closure

Page 90: Interfacing 7

       SJMP K2                ;check il key pressedOVER:  ACALL DELAY            ;wait 20 msec debounce time       MOV A,P2               ;check key closure       ANL A,#00001111B       ;mask unused bits       CJNE A,#00001111B,OVER1;key pressed, find row       SJMP K2                ;if none, keep pollingOVER1: MOV P1,#11111110B      ;ground row 0       MOV A,P2               ;read all columns       ANL A,#00001111B       ;mask unused bits       CJNE A,#00001111B,ROW_0;key row 0, find the col.       MOV P1,#11111101B      ;ground row 1       MOV A,P2               ;read all columns       ANL A,#00001111B       ;mask unused bits       CJNE A,#00001111B,ROW_1;keyrow 1, find the col.       MOV P1,#11111011B      ;ground row 2       MOV A,P2               ;read all columns       ANL A,#00001111B       ;mask unused bits       CJNE A,#00001111B,ROW_2;key row 2, find the col.       MOV P1,#11110111B      ;ground row 3       MOV A,P2               ;read all columns       ANL A,#00001111B       ;mask unused bits       CJNE A,#00001111B,ROW_3;keyrow 3, find the col.       LJMP K2                ;if none, false input, repeatROW_0: MOV DPTR,#KCODE0       ;set DPTR=start of row 0              SJMP FIND              ;find col. key belongs toROW_1: MOV DPTR,#KCODE1       ;set DPTR=start of row 1       SJMP FIND              ;find col. key belongs toROW_2: MOV DPTR,#KCODE2       ;set DPTR=start of row 2       SJMP FIND              ;find col. key belongs toROW_3: MOV DPTR,#KCODE3       ;set DPTR=start of row 3FIND:  RRC A                  ;see if any CY bit low       JNC MATCH              ;if zero, get the ASCII code             INC DPTR               ;point to next col. address       SJMP FIND              ;keep searchingMATCH: CLR A                  ;set A=0 (match is found)       MOVC A,@A+DPTR         ;get ASCII code from table       MOV  P0,A              ;display pressed key       LJMP  K1

;ASCII LOOK-UP TABLE FOR EACH ROW

      ORG     300HKCODE0: DB     '0','1','2','3'          ;ROW 0KCODE1: DB     '4','5','6','7'          ;ROW 1KCODE2: DB     '8','9','A','B'          ;ROW 2KCODE3: DB     'C','D','E','F'          ;ROW 3

      END

LCD Interfacing...................................................................................................................................

Frequently, an 8051 program must interact with the outside world using input and output devices that communicate directly with a human being. One of the most common devices attached to an 8051 is an LCD display. Some of the most common LCDs connected to the 8051 are 16x2 and 20x2

Page 91: Interfacing 7

displays. This means 16 characters per line by 2 lines and 20 characters per line by 2 lines, respectively.

Fortunately, a very popular standard exists which allows us to communicate with the vast majority of LCDs regardless of their manufacturer. The standard is referred to as HD44780U, which refers to the controller chip which receives data from an external source (in this case, the 8051) and communicates directly with the LCD.

AN EXAMPLE HARDWARE CONFIGURATIONLCD Pin descriptions

The LCD discussed in this section has 16 pins. The function of each pin is given in Table.

Pin Symbol I/O            Description1        Vss        -        Ground2        Vcc        -        +5V Power supply3        VEE        -        Power supply to control Contrast4        RS        I        RS = 0 to select command register RS = 1 to select data register5        R/W        I        R/W = 0 for write, R/W = 1 for read6        E        I/O        Enable7        DB0        I/O        The 8-bit data bus8        DB1        I/O        The 8-bit data bus9        DB2        I/O        The 8-bit data bus10        DB3        I/O        The 8-bit data bus11        DB4        I/O        The 8-bit data bus12        DB5        I/O        The 8-bit data bus13        DB6        I/O        The 8-bit data bus14        DB7        I/O        The 8-bit data bus15        LED-        I        Ground for LED backlight16        LED+        I        +5v for LED backlight

44780 BACKGROUND

The 44780 standard requires 3 control lines as well as either 4 or 8 I/O lines for the data bus. The user may select whether the LCD is to operate with a 4-bit data bus or an 8-bit data bus. If a 4-bit data bus is used, the LCD will require a total of 7 data lines (3 control lines plus the 4 lines for the data bus). If an 8-bit data bus is used, the LCD will require a total of 11 data lines (3 control lines plus the 8 lines for the data bus).

The three control lines are referred to as EN, RS, and RW.

The EN line is called "Enable." This control line is used to tell the LCD that you are sending it data. To send data to the LCD, your program should first set this line high (1) and then set the other two control lines and/or put data on the data bus. When the other lines are completely ready, bring EN low (0) again. The 1-0 transition tells the 44780 to take the data currently found on the other control lines and on the data bus and to treat it as a command.

The RS line is the "Register Select" line. When RS is low (0), the data is to be treated as a command or special instruction (such as clear screen,

Page 92: Interfacing 7

position cursor, etc.). When RS is high (1), the data being sent is text data which sould be displayed on the screen. For example, to display the letter "T" on the screen you would set RS high.

The RW line is the "Read/Write" control line. When RW is low (0), the information on the data bus is being written to the LCD. When RW is high (1), the program is effectively querying (or reading) the LCD. Only one instruction ("Get LCD status") is a read command. All others are write commands--so RW will almost always be low.

Finally, the data bus consists of 4 or 8 lines (depending on the mode of operation selected by the user). In the case of an 8-bit data bus, the lines are referred to as DB0, DB1, DB2, DB3, DB4, DB5, DB6, and DB7. 

LCD Interfacing (8bit Mode)...................................................................................................................................

Introduction:

This application note describes a simple technique to display characters from both the internal character generator and user designed characters on an LCD character module.The controlling microcontroller is a Atmel 89C52, a derivitive of the popular Intel 8051. The LCD module is connected to the microcontroller through its I/O ports. It could also be connected directly to the data bus with the addition of address decoding logic.The process of displaying character to this module is divided into three steps. First the module must be initialized. This sets up the built-in LCD controller chip. Second, some user designed characters are uploaded to the CGRAM. This allows the displaying of up to 8 custom characters in addition to the 192 character permanently stored in the module. Lastly, a message consisting of a mix of standard ASCII characters and custom designed characters is displayed on the module.LCD Pin descriptions

The LCD discussed in this section has 16 pins. The function of each pin is given in Table.

Pin Symbol I/O            Description1        Vss        -        Ground2        Vcc        -        +5V Power supply3        VEE        -        Power supply to control Contrast4        RS        I        RS = 0 to select command register RS = 1 to select data register5        R/W        I        R/W = 0 for write, R/W = 1 for read6        E        I/O        Enable7        DB0        I/O        The 8-bit data bus8        DB1        I/O        The 8-bit data bus9        DB2        I/O        The 8-bit data bus10        DB3        I/O        The 8-bit data bus11        DB4        I/O        The 8-bit data bus12        DB5        I/O        The 8-bit data bus13        DB6        I/O        The 8-bit data bus14        DB7        I/O        The 8-bit data bus15        LED-        I        Ground for LED backlight16        LED+        I        +5v for LED backlight

Page 93: Interfacing 7

Circuit Diagram

Page 94: Interfacing 7
Page 95: Interfacing 7
Page 96: Interfacing 7

LCD Interfacing (8bit Mode)...................................................................................................................................

Program:;**********************************************************;; Application Note:; =================; Displaying Characters on an LCD Character Module;; Description: Demo software to display “canned”;message and custom characters.; Controller: Phillips 87C751; LCD controller: HD44780, KS0066, SED1278;;*************************************************************; Constant Definition;*************************************************************INCLUDE REG_52.PDF;*****************************************; Port Connections; =================; P1.0 -> D0; P1.1 -> D1; P1.2 -> D2; . . .; P1.7 -> D7; P3.0 -> Enable; P3.1 -> RS; P3.2 -> RW

Page 97: Interfacing 7

;*******************************************************; Interrupt Vectors; ------------------org 000hjmp PowerUp ; Power up reset vector

PowerUp:;**************************************; LCD Initialization Routine;**************************************cinit: clr P3.1 ;RS lowclr P3.2 ;RW lowsetb P3.0 ;Enablemov p1,#38hacall command_byteacall ddelay ;initial delay 4.1mSecmov p1,#38h ;function setacall command_byteacall ddelay ;busy flag not avail. yetmov p1,#38h ;function setacall command_bytemov p1,#0ch ;display onacall command_bytemov p1,#01h ;clear displayacall command_byteacall cgram ;define custom fontsacall first_line ;display first lineacall second_line ;display second linesdone:jmp sdone;********************************************************;Subroutine: WRITE;=================;Purpose: To feed in data/command bytes to the LCD module;Parameters:dptr = should be set to the beginning of; the data byte address; Data bytes should be finished with 99H;Alg: get a new data/command byte; while (new data != 99h) {; set port1 with new data; call data_byte; increment data pointer; }; return;********************************************************write:write_loop:mov a,#0movc a,@a+dptrcjne a,#99h,write_contretwrite_cont:mov p1,aacall data_byteinc dptr

Page 98: Interfacing 7

jmp write_loop;************************************************; Delay Routine:; Delay periond = Ims;************************************************ddelay:         PUSH        ACC         MOV         A,#0A6HMD_OLP:         INC         A         NOP         NOP         NOP         NOP         NOP         NOP         NOP         NOP         JNZ         MD_OLP         NOP         POP         ACC         RETMADELAY:         PUSH        ACC         MOV         A,#036HMAD_OLP:         INC         A         NOP         NOP         NOP         NOP         NOP         NOP         NOP         NOP         JNZ         MAD_OLP         NOP         POP         ACCret;********************************; set address to beginning; of CG RAM;********************************cgram:mov p1,#40hacall command_bytemov dptr,#cgram_dataacall writeret;********************************; Set DDRAM to the beginnig of; the first line - 00;********************************first_line:mov p1,#080h ;set DDRAM

Page 99: Interfacing 7

acall command_bytemov dptr,#fline_dataacall writeret;********************************; Set DDRAM to the beginning of; the second line - 40;********************************second_line:mov p1,#0c0h ;set DDRAMacall command_bytemov dptr,#sline_dataacall writeret;**********************************************************; Feed Command/Data to the LCD module;***********************************************************command_byte:clr p3.1 ; RS low for a command byte.jmp bdelaydata_byte:setb p3.1 ; RS high for a data byte.nopbdelay:clr p3.2 ; R/w low for a write modeclr p3.0nopsetb p3.0 ;enable pulsenop;******************* Check Busy Flagmov p1,#0ffh ;configure port1 to input modesetb p3.2 ;set RW to readclr p3.1 ;set RS to commandclr p3.0 ;generate enable pulsenopsetb p3.0bloop: nopmov a,p1anl a,#80h ;check bit#7 busy flagcjne a,#00h,bloop;keep waiting until busy flag clears;*****************************************; check busy flag twice;*****************************************bwait:mov a,p1anl a,#80hcjne a,#00h,bloopclr p3.2 ;return to write moderet;********************************************; Data Bytes;*******************************************FLINE_DATA:db '>>8051projects<<'db 099h

Page 100: Interfacing 7

SLINE_DATA:db 00h,01h,02h,03h,04h,05h,06h,07hdb 099hCGRAM_DATA:font1: db 0ah,15h,11h,11h,0ah,04h,00h,00hfont2: db 04h,0ah,11h,11h,15h,0ah,00h,00hfont3: db 04h,0eh,15h,04h,04h,04h,04h,00hfont4: db 04h,04h,04h,04h,15h,0eh,04h,00hfont5: db 18h,18h,1fh,1fh,1fh,18h,18h,00hfont6: db 1fh,1fh,03h,03h,03h,1fh,1fh,00hfont7: db 0ah,15h,0ah,15h,0ah,15h,0ah,00hfont8: db 15h,0ah,15h,0ah,15h,0ah,15h,00hdb 99hendClick here to Download the Program...

Polling a Button...................................................................................................................................

This chapter gives an idea of how flexible the I/O pins are, despite their simple design. The Program given below polls a button connected to one of the I/O pins (which pull the line to ground from its normal pulled-up state) and passes the state of the pin to another one and lights an LED when the button is being pressed.

Connect the following circuit in the bread boardProgram to poll a button and turns on an LED

ORG 0000H                ; Execution starts here

LOOP:SETB P0.3                ; Make port P0.3 as input port       MOV C,P0.3        ; Get the button state to carry bit       MOV P1.6,C        ; Display button state on LED       SJMP LOOP                ; do it continuously       END

Program to turn on the LED when the button is pressed once and to turn off the LED when it is pressed again

       ORG 0000H                ; Execution starts hereLOOP:SETB P0.3                ; Make port P0.3 as input port       MOV C,P0.3        ; Get the button state to carry bit       JC LOOP                ; check if button is pressed       CPL P1.6                ; if pressed compliment the port       JNB P0.3,$        ; Wait until the button is released       SJMP LOOP                ; do it continuously

Page 101: Interfacing 7

       END

Seven Segment Display Interfacing

The 7 segment display is found in many displays such as microwaves or fancy toaster ovens and occasionally in non cooking devices.  It is just 7 LEDs that have been combined into one  case to make a convenient device for displaying numbers and some letters.  The display is shown on the left. The pin out of the display is on the right.

This version is a common anode version.  That means that the positive leg of each LED is connected to a common point which is pin 3 in this case.  Each LED has a negative leg that is connected to one of the pins of the device.  To make it work you need to connect pin 3 to 5 volts.  Then to make each segment light up, connect the ground pin for that led to ground.  A resistor is required to limit the current.  Rather than using a resistor from each LED to ground, you can just use one resistor from Vcc to pin 3 to limit the current. The following table shows how to form the numbers 0 to 9 and the letters A, b, C, d, E, and F.  '0' means that pin is connected to ground. '1' means that pin is connected to Vcc. 

To Display a (Pin 1) b (Pin 10) c (Pin 8) d (Pin 6) e (Pin 5) f (Pin 2) g (Pin 9)

0 0 0 0 0 0 0 1

1 1 0 0 1 1 1 1

2 0 0 1 0 0 1 0

Page 102: Interfacing 7

3 0 0 0 0 1 1 0

4 1 0 0 1 1 0 0

5 0 1 0 0 1 0 0

6 0 1 0 0 0 0 0

7 0 0 0 1 1 1 1

8 0 0 0 0 0 0 0

9 0 0 0 1 1 0 0

A 0 0 0 1 0 0 0

b 1 1 0 0 0 0 0

C 0 1 1 0 0 0 1

d 1 0 0 0 0 1 0

E 0 1 1 0 0 0 0

F 0 1 1 1 0 0 0

Now, we want to run the display with the AT89C51 microcontroller.  We will use Port 0 to run the display.  Connect the AT89C51 to the 7 segment display as follows. 

Program to display "0" on the seven segment display

; PROG2 - Second Program, Display 0 on seven segment display;

Page 103: Interfacing 7

ORG 0000H        ; Execution starts here

SETB P0.3        ; Turn off the g segmentCLR    P0.1        ; Turn on the a segmentCLR    P0.0        ; Turn on the b segmentCLR    P0.6        ; Turn on the c segmentCLR    P0.5        ; Turn on the d segmentCLR    P0.4        ; Turn on the e segmentCLR    P0.2        ; Turn on the f segment

HERE:    AJMP HERE        ; Loop here forever        END

Flashing an LED

This section describes how to interface an LED to the microcontroller AT89C51/52 to flash.

The circuit explains how to connect an LED to the Microcontroller, the program to flash an LED connected to port 1.4 using the CPL instruction

; First Program, Flash an LED at P1.4; EXCEL Technologies;; Hardware Notes:

Page 104: Interfacing 7

; AT89C51 Running at 12 MHz; P1.4 is the LED (to light, it is pulled down)

        ORG 00H        ; Execution Starts HereFLASH:    CPL P1.4        ; Turn on/off the LED        ACALL DELAY    ; call one second delay        AJMP FLASH    ; repeat forever

DELAY:    MOV R1,#0FFHREPEAT:    MOV R2,#0FFH        DJNZ R2,$        DJNZ R1,REPEAT        RET        END

Power Supply for 8051 Microcontroller

This section describes how to generate +5V and +12V DC power supply

The power supply section is the important one. It should deliver constant output regulated power supply for successful working of the project. A 0-12V/500 mA transformer is used for this purpose. The primary of this transformer is connected in to main supply through on/off switch& fuse for protecting from overload and short circuit protection. The secondary is connected to the diodes to convert 12V AC to 12V DC voltage. And filtered by the capacitors ,Which is further regulated to +5v, by using IC 7805