Curious about smart parking systems engineering? Click here to learn more !

Analog Inputs/Output In Raspberry Pi

Posted by Momen 16/03/2017 0 Comment(s)

Welcome to Zeroohm Raspberry Pi Training series. In this series of Raspberry Pi Training, Zeroohm will focus its efforts on helping the community learn more about Raspberry Pi fundamentals and basics starting with basic control of LED's, motors, sensors and utilizing of wirless communication. We hope that you find this useful, Please, leave a comment for any questions or comments or reviews!

We provide all our trainings for groups from schools, universities, public sector and private sector in Abu Dhabi, Dubai, Sharjah, Fujirah, RAK or anywhere in UAE. Please,click here to contact us directly for any training inquires.

Our Raspberry Pi training series:

1. Introduction to Raspberry Pi

2. Analog Inputs/Output In Raspberry Pi

3. Wireless Communication in Raspberry Pi

4. How to connect a new Raspberry Pi to your Laptop without a screen

5. Communication between Raspberry Pi and Arduino

 

 

  • Analog to Digital Converter connection:

Raspberry pi’s GPIO pins is all digital ports, meaning that they only can input and output digital values (HIGH or LOW) without any help of an external device. In order to read analog values we must first connect an analog to digital converter that will read analog values and converted into digital values (i.e a very fast HIGH and LOW pulses). The ADC output a sequence of pulses that changes with the change of analog inputs. For example, taking the representation of HIGH is ‘1’ and LOW is ‘0’, a zero analog voltage will produce LOW sequence of pulses (0000000000), a 3.3 analog volt will produce a HIGH sequence of pulses (1111111111), and 1.8 volt will produce a (1000101110) and so on.

 

By reading the sequences of HIGH and LOW pulses the raspberry by reads the analog value on the input. But first we must connect the ADC properly with the raspberry pi. In this series you’ll be using MCP3008 ADC IC. The connection of that IC is as shown bellow:

 

 

  • Experiment 1: Light Detector.

Light-Dependant Resistor (LDR) is a two-lead semiconductor electrical component that varies its resistance with respect to the amount of light applied on it.

In this task you will control the switching of an LED by reading the output of LDR (photo cell).

1. Connect the following Circuit using the shown components:

2. From raspberry pi start menu go to ‘Programming’ then open ‘Python 3 (IDLE)’.

import RPi.GPIO as GPIO  
from gpiozero import MCP3008
import time

GPIO.setmode(GPIO.BOARD)
GPIO.setup(8,GPIO.OUT)

LDR=MCP3008(0) #define the MCP30088 channel
# Read value and 0.3 dead band
ldr_dark_voltage = (LDR.value*3.3)+0.3
GPIO.output(8,GPIO.LOW)
while True:
    ldr_value = LDR.value*3.3
    if ldr_value >= ldr_dark_voltage:
        GPIO.output(8,GPIO.HIGH)a
    else:
        GPIO.output(8,GPIO.LOW)
        time.sleep(1)

3. Write the following code:

4. Run the code by pressing “F5”.
 

Discussion:

  • We first import MCP3008 library to the code so that we can read the analog value easily.
  • The as costumed, we define the numbering mode that we are going to use and then define the pins that we are going to use as inputs and outputs.
  • Then we give the MCP3008 channel 0 the name ‘LDR’.
  • After that we read the value by calling ‘channelName.value’. The result will be a number between 0 and 1. We multiply the value with our logic level voltage 3.3v to get the exact voltage on the LDR.
  • Then we open an indefinite loop and inside the loop we read the value and make a decision to turn the LED on and OFF based on the LDR sensor value. 

Brainstorming:

In our code the procedure is simple, you can just read any analog sensor by one command and multiplying the result we supplied voltage. But how does the MCP3008 Analog to Digital Converter knows which channel to read?

It’s really simple, when the MCP3008 library uses SPI communication protocol (a set of rules to guide the exchange of data between two devices). The protocol define the raspberry pi as “master” and MCP3008 as “slave”, meaning that the raspberry pi is the BOSS!!

The raspberry pi uses GPIO.10, GPIO.9 and GPIO.11 (pins 19, 21 and 23) for SPI serial communication as MOSI (master out salve in), MISO (master in slave out) and SCLK (slave clock) respectively to send, (using MOSI) pin, and to receive data, using (MISO). The SCLK is for synchronization.

When the command ‘channelName.value’ runs, the channel that you named is identified and then the raspberry pi sends 3 bytes (24 bits) of data, the MCP3008 takes the first 10 bits which identify which channel to read. For example channel 0 is identified by ‘10000000’, so the MCP3008 will send back the result of channel 0 (also 3 bytes).

 

  • Experiment 2: Temperature Sensor.

A temperature sensor is an electronic component that outputs a varying voltage that changes with the change of temperature. Temperature sensors comes in all shapes and sizes, and you can find them almost everywhere from factories to weather station, even in your car.

In this experiment you’ll be reading the temperature sensor TMP36 and you’ll convert the voltage to degrees and display them on screen:

  1. Connect the following Circuit using the shown components

     2. From raspberry pi start menu go to ‘Programming’ then open ‘Python 3 (IDLE)’.

     3. Write the following code:

import time  
from gpiozero import MCP3008

GPIO.setmode(GPIO.BOARD)

Temperature = MCP3008(0) #define the MCP30088 channel

while True:
    volt = Temperature.value*3.3
    TempC = (volt - 0.5) * 100
    TempF = (TempC * (9.0/5.0)) +32.0
    print('The Temperature in celsius is = ' + str(TempC))
    print('The Temperature in Fahrenheit is = ' + str(TempF) + "\n")
    time.sleep(1)

 

Discussion:

  • In this experiment we follow the same procedure as in experiment 1.
  • We read the MCP3008’s channels zero and multiply by 3.3.
  • Then for the temperature in Celsius we subtract 0.5 (sensor offset voltage) and then we multiply by 100 (because sensor outputs 10mV per degree Celsius).
  • Then we convert the Celsius temperature to Fahrenheit.
  • Finally we display the result using the command ‘print(statement)’ , where ‘statement’ can be anything from sentence to variables and numbers.
  • Note: in the print command we used ‘str()’, this is because the ‘print()’ command can take more than one elements by using ‘+’ in between, as long as they are of the same type, but the sentence is ‘string’ and ‘TempC’ and ‘TempF’ are floats.

 

  • Experiment 3: Humidity Sensor.

Humidity sensors are small electronic components that measures both the temperature and the humidity in the air. In this experiment you will use DHT11, a capacitive humidity sensor that measures the humidity in the air by measuring the change in capacitance between two electrodes which have a moisture holding material between them, when the humidity changes it affect the material and thus the capacitance.

In this experiment you’ll be reading the humidity and the temperature from the sensor and displaying it on an LCD.

  1. Connect the following Circuit using the shown components:

  2. Install the libraries that will make our life easy!
  • Adafruit DHT11 library:

      a. Copy the repository from adafruit by running this command in terminal:

        Git clone https://github.com/adafruit/Adafruit_Python_DHT.git

      b. Open the directory:

       cd Adafruit_Python_DHT

      c. Enter:

         sudo apt-get install build-essential python-dev

       d. Install the library:

         sudo python setup.py install

  • Adafruit DHT11 library:

      a. Copy the repository from adafruit by running this command in terminal:

        git clone https://github.com/adafruit/Adafruit_Python_CharLCD.git

      b. Open the directory:

       cd ./Adafruit_Python_CharLCD
       sudo python setup.py install

 

  3. After you’ve finished restart the raspberry pi.When the raspberry pi starts again, you can proceed with the experiment. 

  4. From raspberry pi start menu go to ‘Programming’ then open ‘Python 3 (IDLE)’.

  5. Write the following code:

import time
import sys
import Adafruit_CharLCD as LCD
import Adafruit_DHT

lcd_rs        = 26
lcd_en        = 19
lcd_d4        = 13
lcd_d5        = 6
lcd_d6        = 5
lcd_d7        = 11
lcd_backlight = 2
lcd_columns = 16
lcd_rows = 2

lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_columns, lcd_rows, lcd_backlight)

while True:
    humidity, temperature = Adafruit_DHT.read_retry(11, 4)
    lcd.set_cursor(0,0)
    lcd.message( "Temp: %d C" % temperature)
    lcd.set_cursor(0,1)
    lcd.message( "Humidity: %d %%" % humidity)

 

Discussion:

  • DHT11 is digital sensor, meaning that the output is digitalized within and the library reads that output, therefore in this experiment we do not require Analog to Digital Converter.
  •   Make note the LCD library uses BCM mode for numbering the pins.
  • After you set the number of the pins we initialize the LCD by the command ‘LCD.Adafruit_charLCD(pins)
  • Inside the infinite loop we read the temperature and humidity by ‘Adafruit_DHT.read_retry(11,4)’ where 4 is the ‘GPIO4’ the pin connected to the sensor.
  • Now we set cursor of the LCD (where our display will start) by ‘lcd.cursor_set(col,raw)
  • Then display the temperature and humidity by ‘lcd.message()’.
  • In the message we used ‘(“statement  %d statement” %variable)’ which is an alternative way instead of ‘(“statement ” +  str(variable) + “statement” )’.

 

  • Experiment 4: PWM and LED brightness control.

As mentioned in level 1 of this series, Light-Emitting Diode (LED) is a semiconductor light source that has one lead connected to an n-type semiconductor (negative) and the other lead connected to p-type semiconductor (positive). In level 1 we controlled the LED to turn ON and OFF using digital output, but what if we need to control the brightness of the light?

 

In order to control that we must variety the supplied voltage, but as we all know GPIO pins are all digital pins and can only supply 3.3v ‘HIGH’ and to control the brightness we need a varying analog voltage. To such thing we use the concept of Pulse Width Modulation PWM

 

Pulse Width Modulation PWM is basically a method of representing analog voltage in terms on pulse width. To explain a pulse that goes ‘HIGH’ at time1 and goes ‘LOW’ at time2 has a width of (time2 – time1).

 

 

To explain the concept let’s take an example of a varying analog voltage from 0 to 5v, if a digital device needs to read the voltage value without ADC we must use a modulation technique, if we use PWM the voltage will be converted into a pulse, a ‘HIGH’ and ‘LOW’. If the period of each pules (depending on processor speed) is 1 second then for 0 volt the ‘LOW’ pulse will go on for 1 second, for 5v the ‘HIGH’ pulse will go on for 1 second and for half way 2.5v the ‘HIGH’ will be for 0.5 second and the ‘LOW’ will be for 0.5 second.

 

As an output, a digitally generated PWM signal to a DC voltage device (motor, led…etc.) will be read as the average over time. As in the previse example, a 0.5 second ‘HIGH’ and 0.5 second ‘LOW’ will be as if 2.5 volt is supplied. A 0.75 second ‘HIGH’ and 0.25 second ‘LOW’ will be as if 3.75 volt is supplied and so on. Therefor PWM is a good choice for analog output.

 

The ratio of the ‘HIGH’ pulse to the whole period is called duty cycle, it can be from 0% to 100%.

 

In this experiment you’ll produce analog voltage using PWM concept to dim and bight LED:

  1. Connect the following Circuit using the shown components:

2. From raspberry pi start menu go to ‘Programming’ then open ‘Python 3 (IDLE)’.

3. Write the following code:

import RPi.GPIO as GPIO
import time import sleep
 
GPIO.setmode(GPIO.BCM) 
# choose BCM or BOARD numbering schemes.   
GPIO.setup(14, GPIO.OUT)
 
led = GPIO.PWM(14, 100)
# create object white for PWM on port 25 at 100 Hertz    
led.start(0) # start white led on 0 percent duty cycle (off)   
 
pause_time = 0.02
try:  
    while True:  
        for i in range(0,101):     
# 101 because it stops when it finishes 100  
            led.ChangeDutyCycle(i)  
            sleep(pause_time)  
        for i in range (100,-1,-1):     
# from 100 to zero in steps of -1 and stop at 0
            led.ChangeDutyCycle(i)  
            sleep(pause_time)
 
except KeyboardInterrupt:  
      white.stop()           
# stop the white PWM output  
      GPIO.cleanup()          # clean up GPIO on CTRL+C exit

 

Discussion:

  • In this experiment we use the function ‘ PWM ’ in the ‘ GPIO ’ module. The command ‘GPIO.PWM(pin, frequency)’ will set the pin as PWM output.
  • objectName.start(duty cycle)’ will start the PWM signal on the pin that we defined with name and we set the duty cycle as zero (0 volt).
  • The ‘while’ loop is to make the code can continuously.
  • In the ‘for’ loop we use the command ‘objectName.ChangeDutyCycle(value)’ to change the duty cycle gradually each loop. The first loop is set to increase duty cycle thus increasing the brightness, and the second loop does the opposite.
  • The commands ‘try’ and ‘except’ work as there name suggest. In python the ‘try’ command will run the block code inside it as long as no errors occur. If the error specified with ‘except’ the block of code inside ‘try’ will break and the block of code in ‘except’ will run. In our code we use the except of ‘keyboardInterrupt’ which happens when you press CTRL+C on the key board, in our case the loop will be stopped and then code will resume running until the last line ‘GPIO.cleanup()’ and then end.

 

Brainstorming:

  • In the code we used ‘from time import sleep’ and then when applying a delay we used ‘sleep(time in seconds)’. In previous codes we use ‘import time’ and used ‘time.sleep(time in seconds)’. The difference is that with ‘import time’ we are importing the whole module and all the globals (functions) in it and when using any of those globals we write ‘time.globalName’. With ‘from time import sleep’ we are only importing the ‘sleep’ global, thus we only call ‘sleep’ without the the module name.
  • The function ‘sleep’ is a global, meaning that you can use anywhere in the python code. This function calls a code that delay the process by saving the states and then tracking and counting the CPU cycles, for example if a CPU have cycle period of 1 micro-second then we must wait 1 million cycles to delay for 1 second, so the ‘sleep’ code will use the internal Programmable Interval Timer, which generates a signal each cycle (counting pulses) to count till 1 million then it will return to the code and resume.

Leave a Comment