How to measure an Analog Distance Sensor
This video shows how to use the PDQ Board to measure an analog voltage, and output the data on multiple digital displays. Topics covered include: ADC (analog to digital converter), controlling LED's, digital inputs, digital outputs, analog inputs.
Video
Click here to view the video in a new window.
Introduction
This video is a demonstration of reading an analog voltage, computing data, and controlling LEDs. I am using a Sharp GP2D12 Infrared (IR) sensor. More information about sharp distance sensors. The PDQ board connects to your host PC via a serial cable, running at a baud rate of 115200.
Software
The following software is involved in this demonstration:
- Mosaic IDE Plus - Compiles the C source code below, resulting in a .DLF, or "download file."
- Mosaic Terminal - Communicates with the PDQ Board over a serial comm port.
- QED-Forth Real Time Operating System (RTOS) - Operating system controlling the PDQ Board
The Mosiac IDE Plus compiles your C source code into a binary file. The Mosaic Terminal sends this file to the PDQ Board Users Guide. The QED-Forth RTOS on the PDQ Board Users Guide receives this file into ram, and then saves to flash memory after the download is complete. If you type "main" into the terminal followed by the 'enter' key, the RTOS will execute main()
from the loaded source code. You also have the option to "Autostart" your program; this instructs the PDQ Board to execute main()
at device power-on.
Hardware
This project is constructed from boards manufactured by Mosaic Industries as well as materials sold by other vendors.
Mosaic Hardware
- Docking Panel, sold together with the PDQ Board as a Starter Kit
Other
- Switches, 10 LED Bar Graph, 7-Segment LED Display - Generic products, check http://www.digikey.com/.
Schematic
The following schematic describes how all the components in this circuit are connected. Please download the pdf for a high resolution view of this document.
how-to-measure-an-analog-distance-sensor.pdf (right-click save as)
Source Code
#include <MOSAIC\ALLQED.h> // include the standard library functions // This sample program accompanies the youtube video located here: // // - http://www.youtube.com/watch?v=8ABlonlmBwk // // This program reads an IR distance sensor and visually outputs the distance on // a seven segment LED display. A 10 LED bar graph also fills up as the distance // decreases. 4 switches are connected to digital inputs which allow the user // to change the display. This program is meant to be a simple demonstration of // the onboard I/O available on the PDQ board. This program is a modified // version of the demo project entitled "Analog I/O Demo" which is provided with the // Mosaic IDE Plus. // Copyright 2010 Mosaic Industries, Inc. All Rights Reserved. // Disclaimer: THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT ANY // WARRANTIES OR REPRESENTATIONS EXPRESS OR IMPLIED, INCLUDING, BUT NOT // LIMITED TO, ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS // FOR A PARTICULAR PURPOSE. // ************* Switch Definitions ***************** // This #define masks one bit from Port M // if SWITCH1 is non-zero, then it is ON #define SWITCH1 ( PORTM & 0x04 ) // ON = enable bar graph #define SWITCH2 ( PORTM & 0x08 ) // ON = enable seven-segment display #define SWITCH3 ( PORTM & 0x10 ) // ON = freeze output on all displays #define SWITCH4 ( PORTM & 0x20 ) // ON = exit to forth prompt // ************* Forward Declaration **************** _Q void DoBarGraph( int val ); _Q void LEDOutput( float cm ); _Q void BlankDigit( void ); _Q void DisplayBarGraph( int bar ); // ******* Multiple 10 Bit A/D Conversions with Results in a C Array ********* #define DEFAULT_NUMSAMPLES 16 _qv uint c_results_10[DEFAULT_NUMSAMPLES]; // declare c buffer for 10 bit A/D results _Q void SampleToArray(int channel) // converts using 10bit A/D on specified channel (0-7), puts results in // the 1-dimensional C array c_results_10[] // We use the EXTENDED_ADDR union defined in TYPES.H to convert // the simple 16bit array address into the 32bit xaddr required by ATDMultiple() { xaddr xcbuffer = TO_XADDR(c_results_10,0); //USAGE: ATDMultiple ( xaddr buffer, uint utime, int one_byte, // int numsequences, int starting_channel_id, int numchannels ); ATDMultiple(xcbuffer, 0xfff, 0, DEFAULT_NUMSAMPLES, channel, 1); } // ********************* Initializations **************** _Q void InitAnalogPins(void) // zeros the standard C array to hold 10bit results; // turns on the analog converters { int i; ATDOn(0); // turn on converter for AN0-AN7 for(i=0;i<DEFAULT_NUMSAMPLES;i++) c_results_10[i]=0; // zero the C array } // DigitArray holds 8 bit patterns which are used to light up the seven segment // display. The pattern is written to each segment (denoted with letters) // in the following order, with an X for the decimal place: // XGFEDCBA // In this configuration, A is the least significant bit, and the decimal place // is the most significant bit. Remember that these LEDs are active low, so // 0 means lit, 1 means dark. // // 0 1 2 3 4 5 6 7 8 9 A Blank const char DigitArray[12] = { 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0xff }; // This function sets up the digital I/O pins // Each pin is connected to an LED in the active low configuration _Q void InitDigitalPins(void) { // we set the value of the port before we change the port to output PORTT = 0xff; // turn off the LED's PORTP = 0xff; // turn off LED's PORTM = 0xff; // turn off LED's DDRT = 0xff; // make Port T all outputs DDRP = 0xff; // make Port P all outputs DDRM = 0x03; // make just the lower 2 pins outputs } // display a digit on the 7 segment LED _Q void DisplayDigit( int digit ) { // bind the range of 'digit' between 10 and 0 if( digit > 10 ) { digit = 10; } if( digit < 0 ) { digit = 0; } // Note: if 'digit' is 10, an A is displayed on the seven segment display //PortP bits 2-7 ChangeBits( (DigitArray[digit] << 2), 0xfc, (int) &PORTP ); //PortM bits 0-1 ChangeBits( (DigitArray[digit] >> 6), 0x03, (int) &PORTM ); } // Completely turns off the 7-segment display _Q void BlankDigit( void ) { //PortP bits 2-7 ChangeBits( (DigitArray[11] << 2), 0xfc, (int) &PORTP ); //PortM bits 0-1 ChangeBits( (DigitArray[11] >> 6), 0x03, (int) &PORTM ); } // Allows the 7 segment display to be lit in any configuration // NOTE: This and other functions defined with _Q are interactively // callable from the forth prompt. This function is not called from within main _Q int test( int bits ) { //Make sure digital pins are setup correctly InitDigitalPins(); //PortP bits 2-7 ChangeBits( (bits << 2), 0xfc, (int) &PORTP ); //PortM bits 0-1 ChangeBits( (bits >> 6), 0x03, (int) &PORTM ); return 0; } // This function takes a 10 bit input (named 'bar') and displays it on the bar graph // The 10 bits are split across PortT and PortP. // The 8 least significant bits of 'bar' are output on PortT, while the remaining // 2 bits are output on PortP _Q void DisplayBarGraph( int bar ) { // output 8 bits to PortT ChangeBits( 0xff & bar, 0xff, (int) &PORTT ); bar >>= 8; // output 2 bits to PortP ChangeBits( bar, 0x3, (int) &PORTP ); } // converts A/D counts to centimeters _Q float CountsToCm( int counts ) { float cm; // The following conversion equation was obtained by plugging 18 sample // points into Microsoft Excel. A second order polynomial equation fit // the data best. // // x = 1000/counts // y = .00003*x^2 + 0.0678*x + 4.2692 cm = 0.0003*counts*counts + .0678*counts + 4.2692; cm = 1000/cm; cm += 1; return cm; } // This function processes the data we just read into the C array // It also calls LEDOutput() which handles lighting up LED's _Q void ProcessArray( void ) { int i, shifted; float cm; for( i = 0; i < DEFAULT_NUMSAMPLES; i++ ) { shifted = c_results_10[i] >> 6; // shift the data so it is right justified shifted = shifted & 0x3ff; // the shift may have carried in 1's, // so we need to zero out the upper bits // convert A/D counts to centimeters cm = CountsToCm( shifted ); // output data to the bar graph and seven segment LEDs LEDOutput( cm ); } } // The bar graph is empty at this distance (cm) #define MAX_DIST (45) // the bar graph is full at this distance (cm) #define MIN_DIST (15) // This function takes in centimeters and outputs to the bar graph and // seven segment LED display. The range for the bar graph is #defined above _Q void LEDOutput( float cm ) { float conversion; int filled; int bits; // calculate how full the bar graph should be conversion = cm - MIN_DIST; // subtract minimum conversion = conversion / MAX_DIST; // divide by maximum conversion = conversion * 10; // conversion has a range from 0.0 to 1.0 // now multiply by how many LEDs we have // bind conversion at the top limit // we need this because it is easy for cm to go above MAX_DIST if( conversion > 10 ) conversion = 10; // filled is the number of lights displayed on the bar graph // it is also the number visible on the seven segment display filled = 10 - (int) conversion; // 'bits' holds the bit pattern for the bar graph // we start bits with ten 1's bits = 0x3ff; // we then shift it to the right 'filled' bits. bits >>= filled; // if switch1 is on, display the bar graph. if not display all 1's or not lit if( SWITCH1 ) DisplayBarGraph( bits ); else DisplayBarGraph( 0x3ff ); // if switch2 is on, light up the seven segment display if( SWITCH2 ) DisplayDigit( filled ); else BlankDigit(); } // ************************** main ***************************** int main (void) { // init digital and analog i/o pins InitAnalogPins(); InitDigitalPins(); // loop forever while(1) { if( ! SWITCH4 ) // only loop if switch4 is OFF { SampleToArray(0); // sample 8 bit A/D channel 0 ProcessArray(); // converts input to centimeters, also calls display routines } if( SWITCH3 ) // exit loop if switch3 is ON break; } return 0; }
See also → Microcontroller Projects