Upload
anon720821824
View
142
Download
6
Embed Size (px)
Citation preview
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;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){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;
}
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 */ }}
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
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);
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; }
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): ");
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) /* ----------------------------------------- */{
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 */}
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;
} 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;
#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();
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();
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;
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 ) {
/* 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
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 ) { . . . .
/* 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();
} 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){
/* 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...
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 *
***************************************************/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 */
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){/*------------------------------------
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){
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;
}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;}}
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;
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)
{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
* 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,
* 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*/
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. */
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
/* 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'; } }}
/* 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;
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()
{ 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
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.
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
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
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
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
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
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.
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.
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
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
$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
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:
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
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.
#, *, 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
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
Pin Functions of MT8870
Tone Decoding of MT8870
Circuit Diagram
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
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
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
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)
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
;---------==========----------==========---------=========---------; 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
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
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
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
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.
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
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
(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
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:
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:
;*************************************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
;*************************************; 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 & 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
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 & 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:
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 > 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 > 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
jnc KbChkOK mov dptr, #KbScanCodes2 ; if (a to z) & Caps > 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
;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ ; 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, '|'
; ?, ?, ?, ?, ?, ?, ?, ?,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
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
; **********************************************************
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
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
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
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
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%; 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
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
;**********************************************************************; 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
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.
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
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
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
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,
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
Circuit Diagram
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
;*******************************************************; 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
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
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
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
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
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;
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:
; 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