This is part 2 in a series on WiringPi 2 for Python. The basics are covered in part 1 (click here). You should read that first if you haven’t already, as we build on it here in part 2.
Today we’ll cover three things…
1. Raspberry Pi board revision checking with WiringPi2 for Python
2. Using the Raspberry Pi’s internal pull-ups and pull-downs with WiringPi2 for Python
3. Using hardware PWM with WiringPi2 for Python
1. Checking your Raspberry Pi board revision number in WiringPi2
It’s quite useful to be able to check what version of the Raspberry Pi board you are running. Some of the GPIO ports differ between revisions. So if you can check which revision of Pi your program is running on, you can make sure that the port/pin numbers it uses are correct.
If you use wiringpi’s own pin numbers, this is taken care of for you. But if you use the BCM GPIO numbers or the physical P1 header pin numbers, this feature will be useful for you.
import wiringpi2 as wiringpi
Pi_rev = wiringpi.piBoardRev()
2. Internal pull-ups and pull-downs
In the button circuit in part 1, we used resistors to “pull-down” the port. This gives it a “default” state of 0V (0, False).
Why are they necessary/useful?
If you have no pull-up or pull-down resistors attached to a port, its status is not clearly defined. It is “floating”. It is susceptible to random electromagnetic radiation from you, from any devices near or far and from the environment. Any wires attached to the GPIO ports act as antennae for this radiation (it’s mostly radio waves).
So imagine the situation where you have a motor with a propellor on it, or one which controls Granny’s stairlift, which is switched on or off by a GPIO port. If that port is susceptible to random changes of state, the propellor might spin when it shouldn’t and hurt someone. Or Granny might be sent back upstairs when she wants to be downstairs. It’s an out-of-control situation. You can easily get it under control by using pull-up or pull-down resistors, so that’s what we do.
What’s all this about internal ones then?
In our button circuit, we used resistors to pull down the voltage. This was to demonstrate the idea.
But, in fact, the Raspberry Pi has built-in pull-up and pull-down resistors which can be enabled in software. The i²c ports have permanent, hardware pull-ups), but all the rest can be set/unset in software. This means we can eliminate our pull-down resistors for the button – as long as we enable the internal ones. (The circuit will still function without either, but may be unreliable.)
Activating internal pull-ups and pull-downs with WiringPi
WiringPi enables you do that. Having initialised WiringPi and set the port(s) to input or output, as we did in part 1, you need one of the following commands…
- Activate pull-up
- Activate pull-down
- Deactivate both pull-up and pull-down
Here’s an example where we set port 25 for input with pull-down enabled…
# GPIO port numbers import wiringpi2 as wiringpi # load wiringpi2 wiringpi.wiringPiSetupGpio() # set up GPIO numbering wiringpi.pinMode(25, 0) # sets GPIO 25 to input mode wiringpi.pullUpDnControl(25, 1) # set pull-down
How does that apply to our ‘one input one output’ program?
We’ll need to change the button led circuit first, to this (you could also just remove the 10k resistor to GND from the previous circuit)…
…and then, once you’ve done that, you need to insert a new line after line 7
wiringpi.pullUpDnControl(25, 1) # set pull-down
to enable the pull-down on the button port (25).
The whole program should then look like this…
import wiringpi2 as wiringpi from time import sleep # allows us a time delay wiringpi.wiringPiSetupGpio() wiringpi.pinMode(24, 1) # sets GPIO 24 to output wiringpi.digitalWrite(24, 0) # sets port 24 to 0 (0V, off) wiringpi.pinMode(25, 0) # sets GPIO 25 to input wiringpi.pullUpDnControl(25, 1) # set pull-down try: while True: if wiringpi.digitalRead(25): # If button on GPIO25 pressed wiringpi.digitalWrite(24, 1) # switch on LED. Sets port 24 to 1 (3V3, on) else: wiringpi.digitalWrite(24, 0) # switch off LED. Sets port 24 to 0 (0V, off) sleep(0.05) # delay 0.05s finally: # when you CTRL+C exit, we clean up wiringpi.digitalWrite(24, 0) # sets port 24 to 0 (0V, off) wiringpi.pinMode(24, 0) # sets GPIO 24 back to input Mode # GPIO 25 is already an input, so no need to change anything
As you’ll see, if you try it out, it works just the same as the previous version.
3. Now Some Hardware PWM
Pulse-width modulation (PWM) is switching things on and off lots of times very quickly. It’s very useful for controlling things like motor speeds, led brightness, servo positions and a whole host of other things.
The Raspberry Pi has a hardware PWM port, which it shares with the 3.5mm audio output. If not using this audio output, you can use the hardware PWM port (GPIO18) on P1 header pin 12 or WiringPi pin 1.
To do that, you need to set up wiringpi and the set GPIO18 for alternative function (2)
import wiringpi2 as wiringpi # If using BCM GPIO numbers wiringpi.wiringPiSetupGpio() wiringpi.pinMode(18,2) # pwm only works on GPIO port 18 wiringpi.pwmWrite(18, 0) # duty cycle between 0 and 1024. 0 = off, 1024 = fully on # OR, using wiringpi numbers wiringpi.wiringPiSetup() wiringpi.pinMode(1,2) # pwm only works on wiringpi pin 1 wiringpi.pwmWrite(1, 0) # duty cycle between 0 and 1024. 0 = off, 1024 = fully on # OR, using P1 header pin numbers wiringpi.wiringPiSetupPhys() wiringpi.pinMode(12,2) # pwm only works on P1 header pin 12 wiringpi.pwmWrite(12, 0) # duty cycle between 0 and 1024. 0 = off, 1024 = fully on
Why the Darlington Array chip?
You don’t need it at all for the led! It’s for the motor. Most motors need to run at a higher voltage than the Pi’s 3.3V offers, and a higher current than the GPIO ports can cope with. So we need a way of being able to switch a higher voltage with the 3V3 from a GPIO port. The ULN2003 is seven pairs of transistors that allow this switching in a safe way. You could just use a standard transistor, but this chip only costs ~30 pence or 50 cents so why not have the capability of switching 7 things at once – you don’t have to use them all?
The other nice thing this chip does is protect your Pi’s GPIO port from the voltage spike that can occur when an inductive load (a relay, solenoid, motor etc.) is switched off. It has built-in freewheeling diodes that give the required protection – all for much less than the cost of the separate parts. So in my opinion it would be rude not to use one. :)
You can get dedicated H-bridge motor control chips that will give you bidirectional motor control. But for this experiment I wanted to keep things simple and feed the motor raw PWM.
#!/usr/bin/env python2.7 # script by Alex Eames https://raspi.tv import wiringpi2 as wiringpi from time import sleep wiringpi.wiringPiSetupGpio() wiringpi.pinMode(18,2) # hardware pwm only works on GPIO port 18 wiringpi.pwmWrite(18,0) # duty cycle between 0 and 1024 # 0 = off and 1024 = constantly on pause_time = 0.002 # you can change this to slow down/speed up try: while True: for i in range(0,1025): # 1025 because it stops at 1024 wiringpi.pwmWrite(18,i) sleep(pause_time) for i in range(1024,-1,-1): # from 1024 to zero in steps of -1 wiringpi.pwmWrite(18,i) sleep(pause_time) finally: wiringpi.pwmWrite(18,0) # switch PWM output to 0 wiringpi.pinMode(18,0) # GPIO18 to input
This program cycles the led (and motor, if you connect one) from fully off to fully on and 1023 steps in between over a period of about 2 seconds.
As I found out when I wrote the motor demo program for the Gertboard, hardware PWM is superior to software PWM. You get more precise control. For example, hardware PWM can control servos without jitter, but soft PWM (even when written well) is not as good.
That’s about it for today. You might be surprised to realise that almost everything we’ve done so far could be done in wiringpi version 1. Next time we’ll have a look at some of the new and exciting stuff Gordon’s cooked up for us in version 2. :)
What we’ve covered so far