Beyond Logic


Interfacing Example - Analog Sampling Via the RS-232 Port

      Have you ever wanted to sample analog voltages and log it to your PC for further analysis? Maybe you have looked at circuits which did just this using the Parallel Port, but it was no use to you as you only have one Parallel Port and the Printer is connected to it. Or maybe you are using a Palmtop computer which doesn't have a Parallel Port. If so, then this is the circuit for you.

    Schematic


    Schematic

    Circuit Description

    The above circuit when in a working state, will wait for a byte to be sent to it before it starts the analog conversion and sends data back to the computer using the 8N1 serial format at 9600 BPS. The circuit is based on a CDP6402C or equivalent UART. This, if you want to call it, is the brains of the operation and performs the conversion of Parallel data to a Serial format for transmission. The Analog to Digital Conversion is done by the ADC0804, while the MAX232 is used to convert TTL/CMOS voltage levels into RS-232 Voltage Levels. The 74HC4060 is a Oscillator/Divider which is used to generate the UART's Clock.

    The Analog to Digital Converter (ADC0804) starts it's conversion when the UART's Data Received line becomes active. Many people at this stage will say that this circuit cannot work! - The Data Received (DR) output is Active High, while the nWrite (WR) input to the ADC is a Active Low. This circuit is quite correct. If we look at the ADC's operation, on a high to low transition of the nWrite input the internal Successive Approximation and Shift Registers are reset. Provided the nWrite line remains in this state the ADC will remain reset. The conversion process will start when a low to high transition is made on the nWrite input.

    Therefore getting back to this circuit, the Data Received output will remain low while there is no data to be received, thus the ADC will remain in the reset mode. When data is received by the UART, a low to high transition will result on the Data Received line and thus on the connected nWrite pin of the ADC.

    This low to high transition will cause the ADC to spring to life and make a digital conversion of the analog voltage on it's pins. Once the conversion is finished, it's nINTR (Interrupt) line will become active low. This signal is then used to tell the UART to send the data residing on it's Transmitter Buffer Register inputs (TBR8:TBR1). nINTR is also connected to the UART's Data Received Reset so that the Data Received line will be reset. The circuit is then ready to repeat the entire process upon receiving the next byte.

    Programming - Source Code

       /* Name       : Serial ADC Program                                      */
       /* Written By : Craig Peacock <Craig.Peacock@beyondlogic.org>           */
      
      #include <dos.h>
      #include <stdio.h>
      #include <conio.h>
      
      #define PORT1 0x3E8  /* Port Address Goes Here */
      #define INTVECT 0x0C /* Com Port's IRQ here (Must also change PIC setting) */
      
        /* Defines Serial Ports Base Address */
        /* COM1 0x3F8                        */
        /* COM2 0x2F8			       */
        /* COM3 0x3E8			       */
        /* COM4 0x2E8			       */
      
      int bufferin = 0;
      int bufferout = 0;
      unsigned char ch;
      char buffer[1025];
      
      void interrupt (*oldport1isr)();
      
      void interrupt PORT1INT()  /* Interrupt Service Routine (ISR) for PORT1 */
      {
       int c;
       do { c = inportb(PORT1 + 5);
            if (c & 1) {buffer[bufferin] = inportb(PORT1);
      		  bufferin++;
      		  if (bufferin == 1024) {bufferin = 0;}}
          }while (c & 1);
       outportb(0x20,0x20);
      }
      
      void main(void)
      {
       int c;
       outportb(PORT1 + 1 , 0);        /* Turn off interrupts - Port1 */
      
       oldport1isr = getvect(INTVECT); /* Save old Interrupt Vector of later
      				    recovery */
      
       setvect(INTVECT, PORT1INT);     /* Set Interrupt Vector Entry */
      				 /* COM1 - 0x0C */
      				 /* COM2 - 0x0B */
      				 /* COM3 - 0x0C */
      				 /* COM4 - 0x0B */
      
       /*         PORT 1 - Communication Settings         */
      
       outportb(PORT1 + 3 , 0x80);  /* SET DLAB ON */
       outportb(PORT1 + 0 , 0x0C);  /* Set Baud rate - Divisor Latch Low Byte */
      			      /* Default 0x03 =  38,400 BPS */
      			      /*         0x01 = 115,200 BPS */
      			      /*         0x02 =  57,600 BPS */
      			      /*         0x06 =  19,200 BPS */
      			      /*         0x0C =   9,600 BPS */
      			      /*         0x18 =   4,800 BPS */
      			      /*         0x30 =   2,400 BPS */
       outportb(PORT1 + 1 , 0x00);  /* Set Baud rate - Divisor Latch High Byte */
       outportb(PORT1 + 3 , 0x03);  /* 8 Bits, No Parity, 1 Stop Bit */
       outportb(PORT1 + 2 , 0xC7);  /* FIFO Control Register */
       outportb(PORT1 + 4 , 0x0B);  /* Turn on DTR, RTS, and OUT2 */
      
       outportb(0x21,(inportb(0x21) & 0xEF));  /* Set Programmable Interrupt Controller */
      					 /* COM1 (IRQ4) - 0xEF  */
      					 /* COM2 (IRQ3) - 0xF7  */
      					 /* COM3 (IRQ4) - 0xEF  */
      					 /* COM4 (IRQ3) - 0xF7  */
      
       outportb(PORT1 + 1 , 0x01);  /* Interrupt when data received */
      
       printf("\nSample Serial ADC Program. Press ESC to quit \n");
      
       do {
      
           if (bufferin != bufferout){ch = buffer[bufferout];
      				bufferout++;
      				if (bufferout == 1024) {bufferout = 0;}
      				printf("%u\n",ch);
                                      printf("%f volts\n",(float)ch/256 * 5);}
      
           if (kbhit()){c = getch();
      		  outportb(PORT1, c);}
      
          } while (c !=27);
      
       outportb(PORT1 + 1 , 0);       /* Turn off interrupts - Port1 */
       outportb(0x21,(inportb(0x21) | 0x10));  /* MASK IRQ using PIC */
      					 /* COM1 (IRQ4) - 0x10  */
      					 /* COM2 (IRQ3) - 0x08  */
      					 /* COM3 (IRQ4) - 0x10  */
      					 /* COM4 (IRQ3) - 0x08  */
       setvect(INTVECT, oldport1isr); /* Restore old interrupt vector */
      
      }
      

    The above source code was copied from the example given in the Interfacing the Serial / RS232 Port. The only modifications made was to change the Baud rate to 9600 BPS and include an optional line, shown below, to calculate the voltage present at the ADC's pins.

             printf("%f volts\n",(float)ch/256 * 5);}
    

    The program can be modified to start the conversion at fixed intervals and to log the received result to file. This makes the above circuit more useful, than it is currently presented.

    Data Sheets

    Data Sheets for all the I.C's used in this example can sought on-line from the Internet. This is a list of where the Author obtained his data sheets from. Some semiconductors may be available from other manufacturers. The URL for the manufacturer's homepage is given. You will need to search for the data sheet using their site's search engines.

    I.C's NamePart NumberLink to Manufacturers Homepage
    CMOS Universal Asynchronous Receiver/Transmitter (UART)CDP6402Harris Semiconductor
    RS-232 Level ConverterMAX232Maxim Integrated Products
    8 Bit Analog to Digital ConverterADC0804Harris Semiconductor
    14 Stage Binary Counter74HC4060National Semiconductor


Copyright 2002-2010 Craig Peacock - 25th October 2010.