Tutorial: Reading an analog sensor

Matt Bartos edited this page Aug 20, 2017 · 2 revisions

Reading an analog sensor

This tutorial will show you how to program the PSoC to read data from an analog sensor. We will be using a Maxbotix Ultrasonic Depth sensor. This sensor operates over the same voltage range as the board, making it easy to work with. While this tutorial is written specifically for the perfect-cell board, it will also work with a Cypress Development Kit.

Connecting the sensor

  • Connect the black GND (Pin 7) wire on the sensor to a GND wire terminal on the board.
  • Connect the green Analog (Pin 3) wire on the Sensor to the P3[2] wire terminal on the board.
  • Connect the red V+ (Pin 6) wire on the sensor to the P3[3] wire terminal on the board.

maxbotix_pins

Note: your wire colors may differ. If they do, please ignore the color directions and just use the pin connection information. Using a flat-head screwdriver, place the wires from the ultrasonic sensor in the clamps and tighten.

The red and black wires provide power to the sensor and the green wire outputs the analog signal. The sensor uses a 5V power source. Make sure the power jumper on the board is set to 5V.

Placing components

Start a project in PSoC creator called analog-sensor.

Power pin

We do not want the sensor to stay on all the time and simply consume power. We would like to turn it on before use, and turn it off after use. In the case of the board used in this tutorial, the V+, or voltage inputs, on your breakout board are equipped with PMOS switches. These switches are connected to one of the PSoC’s pins. When the pin is flipped high (logic 0), the switch will not deliver power to the sensor. Alternatively, when flipped low (logic 1), the switch will deliver power to the sensor. To use this feature, we can just simply drag and drop a digital output pin component to the schematic.

  • Place a Digital Output Pin on your schematic. Call this pin Ultrasonic_Sensor_Power, and Remove the Hardware Connection option.

To make sure the sensor starts in the OFF (which requires a digital high) condition we must set the initial state to Low (0).

  • Under the General tab, set the Drive Mode to Resistive Pull Up, and the Initial state to Low (0).

analog_power

Analog to Digital Converters

The PSoC has three analog-to-digital converters (ADCs), each of which can be used simultaneously for making analog measurements:

  • Two 12 bit Successive Approximation (SAR) ADCs: While accurate, these ADCs are specifically designed for rapid measurements.
  • One adjustable 20 bit Delta Sigma ADC: This is the work horse of the NeoMote. It is a 20 bit, ultra-low noise ADC. The accuracy is adjustable, from 8 to 20 bits, with lower resolutions corresponding to higher sampling rates.

Note: For advanced applications requiring many analog sensors, the above ADCs can be multiplexed to permit for many analog sensors to be sampled.

  • In the schematic view, drag and drop the SAR ADC component onto your schematic. The component is located in the Analog -> ADC folder in the component view.

sar_adc

  • Double click the ADC_SAR_1 component on your schematic to adjust its settings.
  • One of the fundamental settings of an ADC is its Input Mode. The input mode can either be single ended or differential.
  • The maxbotix depth sensor has only a single signal wire. So we will use we will use the Single input mode.
  • Looking at the sensor datasheet for the MaxBotix Distance sensor, we can see the output signal can vary between 0-5V. We thus need to make sure that the ADC range is set in a way to capture this range in sensor output.

We will use most of the default configuration but make sure the following settings are applied:

  • Resolution: 12 Bits
  • Input Range: 0.0 to 2.048V (Single Ended) 0 to Vref*2

sar_adc_settings

Note: This sensor can also be configured to run in digital mode using the RS232 connection. This can be easily configured on the board, but we’ll stick the analog output for this tutorial.

Note: If you do not have this sensor available, you can just measure the voltage of an AA battery as a substitute using the same settings.

Note: Single ended inputs are a voltage difference between the signal wire and the ground wire 0-X volts. A differential input has two signal wires, one connected to the positive ADC input, and the other to the negative ADC input. This gives a range that does not necessarily start at zero, and can even potentially begin negative (–X volts to Y volts). Depending on the sensor you are using, reading the datasheet will likely inform you of the correct input mode.

Hooking up pins

The SAR ADC in single-ended mode requires only one input. In your schematic, drag and drop Pins and Ports -> Analog Pin components and connect it to the SAR ADC using the Wire Tool. Name this pin Ultrasonic_Analog_Signal by double clicking it.

analog_signal

Ensure that the analog pin has the following settings:

analog_signal_settings

Assigning Pins

  • Open analog-sensor.cydwr.
  • Set Ultrasonic_Sensor_Power to P3[3].
  • Set Ultrasonic_Analog_Signal to P3[2].

Writing the sensor driver

The sensor just outputs a voltage, which we measure using the ADC. To get the actual distance, we have to convert this reading. The datasheet specifies that “the HRXL-MaxSonar-WRS sensors use a scale factor of (Vcc/5120) per 1-mm.” If we read the voltage, we can then get the distance in mm using the following formula:

distance = voltage_reading * (resolution / voltage_range);

voltage is the output of the sensor in volts. You will then be able to use your favorite PC terminal interface to display the sensor readings.

Create a file called analog.c that contains the following code:

#include <project.h>
#include <stdlib.h>
#include "analog.h"

#define MAXBOTIX_V_RANGE 4.75
#define MAXBOTIX_RESOLUTION 5120

int take_analog_depth_reading(){
    // Initialize variables
    int16 adc_result = 0;
    float volt_reading = 0;
    int distance = -9999;
    
    // Initialize and start ADC
    ADC_SAR_1_Wakeup();
    ADC_SAR_1_Start();
    ADC_SAR_1_StartConvert();
    
    // Turn on sensor and delay briefly to let it settle
    Ultrasonic_Sensor_Power_Write(1u);
    CyDelay(500u);

    // If ADC has finished converting, get the result
    adc_result = ADC_SAR_1_GetResult16();
    // Convert the raw ADC reading to volts
    volt_reading = ADC_SAR_1_CountsTo_Volts(adc_result);
    distance = volt_reading * (MAXBOTIX_RESOLUTION / MAXBOTIX_V_RANGE);
    
    // Turn off sensor
    Ultrasonic_Sensor_Power_Write(0u);
    
    // Stop ADC conversion
    ADC_SAR_1_StopConvert();
    ADC_SAR_1_Sleep();
    
    return distance;
}

/* [] END OF FILE */

Now create a file called analog.h that contains the following code:

int take_analog_depth_reading();

/* [] END OF FILE */

Finally, edit the existing main.c file:

#include <project.h>
#include "analog.h"

// Initialize variables
int depth_analog = -9999;  // Analog depth reading


int main(void)
{
    // Enable global interrupts
    CyGlobalIntEnable;
    
    for(;;)
    {
    
        // Take distance reading
        depth_analog = take_analog_depth_reading();
                
        // Delay 1 second
        CyDelay(1000u);          
    }
}

/* [] END OF FILE */

Code Explanation

The <project.h> file must be included to use function calls from Cypress' built-in-components (including the pins and the ADC). If you are familiar with C programing, you may have also noticed that we included <stdlib.h> to support string operations.

Note: Header files, those ending in ".h", allow for the use of functions already written by others. By including the header file at the of your main.c file, you are able to call functions described inside the file. For example, stdio.h allows us to use sprintf() to format our strings.

The ADC must be started and told to begin making measurements. This is done by calling the ADC_Start() and ADC_StartConvert() functions.

Note: ADC_Wakeup() is used to restore device configuration after sleep mode, while ADC_Sleep() is used to store ADC configuration settings before sleep mode. In this example, these functions are not needed.

We then enter a never ending, for loop taking an ADC sample and saving it to a variable depth_analog. We then pause for one second before repeating the same step. The measurement is actually taken by the take_analog_depth_reading() function, which we have declared for this purpose. The function returns the ADC reading value when the measurement has been completed. The first step is to provide power to the sensor, which is done by calling Ultrasonic_Sensor_Power_Write(1u). We then delay the code for 100 milliseconds to give the sensor time to settle.

To read the ADC measurement, we call the ADC_SAR_1_GetResult16() function. This function will return an integer value, ranging from 0 to 2^N, where N is the number of bits (or resolution) of the ADC. What’s actually more useful in this case is the Voltage of the ADC measurement, as opposed to the integer value. Luckily, the API provides us with a simple conversion. By calling ADC_SAR_1_CountsTo_Volts(), we can convert the integer value to a floating point voltage value.

Note: The API also supports methods to make conversions to milli-, and micro-volts. To learn more, read the datasheet for the ADC component.

We then take this reading and plug it into the sensor calibration equation mentioned earlier to obtain the distance.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.