4

Trying to get an active infrared sensor to trigger an event on a GPIO pin. I'm using python and the RPi.GPIO library on an RPi model B.

Some background info, not sure how relevant it is, but I'm a beginner, so not sure. I apologise in advance if my terminology is off.

  • I have two LEDs wired to GPIO pins which show various activity. They are both working fine.
  • I have another LED wired directly from GPIO 3.3v pin to GPIO ground to show when power is active, this is also working fine.
  • The sensor has a master and slave part. I power the sensor from a 12v adapter, running the 12v and ground cables to the master, and then to the slave, along with another cable between the master and slave for sensor detection. I have measured this comms line (labelled T0) to be 4.53v, and when detection event occurs, this drops slightly to 4.51v.

I've tried two different approaches to getting the sensor to trigger an GPIO event.

  1. Hooking into the T0 comms line. I did this by placing a few resistors in series to get under 3.3v as advised, and wiring the ground (from the 12v adapter) to a GPIO ground. My python code was looking for a GPIO.FALLING event.
  2. Hooking into an LED on the master board which was lighting up on detection. This rose to 4.7v when detected and stayed at 0v when not. I desoldered the LED from the PCB and replaced with wire going to GPIO, i.e. the + side of the LED went to the GPIO pin, and the - side of the led when to a GPIO ground. Again I placed some resistors to get it under 3.3v. My python code was looking for a GPIO.RISING event.

In both cases the GPIO event doesn't trigger. I've tried setting GPIO.IN with neither pull_up_down specified, and both GPIO.PUD_UP and GPIO.PUD_DOWN set.

I feel the second approach should be easier to work with, which is what I've focused on, but I just can't get the detection to register on the GPIO. I'm guessing I've gotten my resistor values wrong or perhaps wired the ground wrong?

One possible clue - if I try to use a multimeter to read the output after the resistors, an GPIO event is triggered, but it doesn't trigger if I read it before the resistors.

Any help appreciated, thanks!

Update

A friend recommended the second option was the easiest and suggested I ensure the sensor and pi have a common ground, as well as try something more simple first, specifically, write some python code to poll the GPIO pin and using a GPIO power port to trigger an event. Here's the code:

import RPi.GPIO as GPIO
import time

sensor = 7
GPIO.setmode(GPIO.BOARD)
GPIO.setup(sensor, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
current = GPIO.input(sensor)
previous = current
def printState(current):
    print 'GPIO pin %s is %s' % (sensor, 'HIGH' if current else 'LOW')
printState(current)
while True:
    current = GPIO.input(sensor)
    if current != previous:
        printState(current)
    previous = current
    time.sleep(0.1)
GPIO.cleanup()

And this works perfectly! I use a wire connected to 3.3v GPIO pin and touch the sensor pin (GPIO pin 7) and the state changes from initial value of LOW to HIGH and stays HIGH as long as I keep them connected. That confirms port setup is working and my problem something to do with either the grounding, the resistor value or (unlikely) the RISING event.

4
  • Have you connected the grounds together? Jul 31, 2013 at 7:13
  • No I haven't, but I've been chatting to a friend who has more electronics experience and suggested the same thing, as well as starting to debug more simply, which is what I'm doing now...will update question.
    – si618
    Jul 31, 2013 at 8:55
  • You should wire the 2 resistors into a voltage divider. So GND <-resistor-> GPIO-pin <-resistor-> T0. PS, could you tell what IR sensor you are using?
    – Gerben
    Jul 31, 2013 at 12:09
  • 1
    Could you attach a diagram of your circuit? It will greatly help in our troubleshooting.
    – Butters
    Jul 31, 2013 at 13:56

2 Answers 2

5

OK, thanks for the input folks, it's working beautifully now.

As gnibbler alluded to in the comments, I needed to connect the ground from the sensor and the RPi.

I also had too high a resistance value between the LED and the GPIO.IN pin, which I was able to determine by expanding on the first debug test, i.e. touching the 3.3v before the resistor didn't trigger the event, but touching it after the resistor did.

The circuit is really simple:

Sensor + LED -> 1.2K resistor -> GPIO.IN on lucky pin 7

Additionally, the sensor ground and RPi grounds are now wired together, and I didn't need to wire the - side of the LED to a GPIO ground pin.

To be honest, I just guessed the resistor value by trial and error, and hoped that I didn't blow up the RPi, as I wasn't sure how to calculate the current coming out of the sensor LED? I know it was under 5v and needed a 1.7v+ drop, but how do you determine current if you don't know what else is drawing power on the circuit?

1

I have used an MCP3002 ADC to read analogue signals on my Raspberry Pi 2. It was connected to Python through the SPI and it could get up to 1Mhz. I have used an 4067 16-to-1 multiplexer and connected the output to the analogue input pin of the ADC. So, by setting 4 GPIOs on my Raspberry Pi High or Low, I could read 16 analogue devices on my ADC and I have another channel free, just in case that I need it.

Here is the code in python to do so:

#!/usr/bin/python

import time
#import uinput
import RPi.GPIO as GPIO
import spidev # import the SPI driver
from time import sleep
from array import *
import sys

DEBUG = False
vref = 3.3 * 1000 # V-Ref in mV (Vref = VDD for the MCP3002)
resolution = 2**10 # for 10 bits of resolution
calibration = 38 # in mV, to make up for the precision of the components
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(7, GPIO.OUT)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
GPIO.setup(15, GPIO.OUT)

# MCP3002 Control bits
#
#   7   6   5   4   3   2   1   0
#   X   1   S   O   M   X   X   X
#
# bit 6 = Start Bit
# S = SGL or \DIFF SGL = 1 = Single Channel, 0 = \DIFF is pseudo differential
# O = ODD or \SIGN
# in Single Ended Mode (SGL = 1)
#   ODD 0 = CH0 = + GND = - (read CH0)
#       1 = CH1 = + GND = - (read CH1)
# in Pseudo Diff Mode (SGL = 0)
#   ODD 0 = CH0 = IN+, CH1 = IN-
#       1 = CH0 = IN-, CH1 = IN+
#
# M = MSBF
# MSBF = 1 = LSB first format
#        0 = MSB first format
# ------------------------------------------------------------------------------


# SPI setup
spi_max_speed = 1000000 # 1 MHz (1.2MHz = max for 2V7 ref/supply)
# reason is that the ADC input cap needs time to get charged to the input     level.
CE = 0 # CE0 | CE1, selection of the SPI device
spi = spidev.SpiDev()
spi.open(0,CE) # Open up the communication to the device
spi.max_speed_hz = spi_max_speed

#
# create a function that sets the configuration parameters and gets the     results
# from the MCP3002
#


def read_mcp3002(channel):
    # see datasheet for more information
    # 8 bit control :
    # X, Strt, SGL|!DIFF, ODD|!SIGN, MSBF, X, X, X
    # 0, 1,    1=SGL,     0 = CH0  , 0   , 0, 0, 0 = 96d
    # 0, 1,    1=SGL,     1 = CH1  , 0   , 0, 0, 0 = 112d
    if channel == 0:
        cmd = 0b01100000
    else:
        cmd = 0b01110000

    if DEBUG : print("cmd = ", cmd)

    spi_data = spi.xfer2([cmd,0]) # send hi_byte, low_byte; receive hi_byte, low_byte

    if DEBUG : print("Raw ADC (hi-byte, low_byte) = {}".format(spi_data))

    # receive data range: 000..3FF (10 bits)
    # MSB first: (set control bit in cmd for LSB first)
    # spidata[0] =  X,  X,  X,  X,  X,  0, B9, B8
    # spidata[1] = B7, B6, B5, B4, B3, B2, B1, B0
    # LSB: mask all but B9 & B8, shift to left and add to the MSB
    adc_data = ((spi_data[0] & 3) << 8) + spi_data[1]
    return adc_data
def main():
        x=0
      while True:
        binary_x="{0:04b}".format(x)
        GPIO.output(15, int(binary_x[0]))
        GPIO.output(13, int(binary_x[1]))
        GPIO.output(11, int(binary_x[2]))
        GPIO.output(7, int(binary_x[3]))
        # average three readings to get a more stable one
        channeldata_1 = read_mcp3002(0) # get CH0 input
        sleep(0.001)
        channeldata_2 = read_mcp3002(0) # get CH0 input
        sleep(0.001)
        channeldata_3 = read_mcp3002(0) # get CH0 input
        channeldata = (channeldata_1+channeldata_2+channeldata_3)/3
        #
        # Voltage = (CHX data * (V-ref [= 3300 mV] * 2 [= 1:2 input divider]) / 1024 [= 10bit resolution]            #
        voltage = int(round(((channeldata * vref * 2) / resolution),0))+ calibration
        print("sensor ",x" voltage: "voltage)
      # if you would like to have some kind of delay.
        #sleep(0.5)
        x=x+1
        if x==16 :
           x=0
if __name__ == '__main__':
    main()

16 analogue sensors in on ADC input, but probably you need to play with calibration depending on the input voltage.

Not the answer you're looking for? Browse other questions tagged or ask your own question.