Tuesday 7 June 2016

Pull up my input

Erm, change of plans. Last time I referred to my plant watering machine but a couple of complications turned up. First, I still haven't gotten all the parts I need. Sometimes you can save a good deal of money by ordering components from China but as a downside it might take a while.

The second problem is with the power supply design. In brief, I need two different voltages: +5 volts for the controlling circuit (microcontroller and relays) and +12 volts for the solenoid valve that dispenses water from the reservoir to the plant. I have an AC adapter which produces +12 volts. At first I planned to use a couple of resistors as a voltage divider to drop it down to 5V but I soon realised it would be a stupid idea. My circuit doesn't require much energy but the voltage divider as a power supply would increase the power consumption manyfold - such a waste! For the sake of sanity (and my electricity bill), I now plan to use a voltage regulator instead. Unfortunately I don't have any which means that I'll have to visit the electronic parts store again..


It seems that my future in robotic agriculture has to wait. I did get some buttons via mail though (and a free disposable razor too!). Thus it's a good moment to go through how to use an AVR's I/O pins to read input.  

In C, the direction of the pins is once again set through the Data Direction Register DDRB. As a reminder, setting a bit to HIGH sets the corresponding pin as output and LOW as input. Say, if I want to use PB4 and PB3 as inputs and PB2..0 as outputs, I'll set DDRB to

 DDRB = 0b00111;  

..aand, that's it! To read the state of the pins into the variable x, for example, I simply read PINB register:

 x = PINB;  

Now x contains the states of all the pins as they were at the moment of reading. As PINB gives out both input and output pin states, we still need to pick out the right pin. To check the state of the pin PBn, one can do it for example followingly:

 x & (1 << n)  

1 << n shifts 1 to left n positions. For example if I want to read the state of PB3,
1 << 3 = 0b01000. Bitwise AND with x then results to 0 if the corresponding state is LOW and to a non-zero value if it is HIGH.

In principle this is sufficient to read the input but there's one more very beneficial trick, especially to be used with buttons. With PB4 and PB3 as inputs, I also set

 PORTB = 0b11000;  

This sets the output pins off and the input pins...on? In some sense, yes. Setting PORTB bits of input pins controls whether so called internal pull-up resistors are used or not.

The pull-up resistor raises the pin voltage when the switch is opened.

A pull-up resistor has a large resistance and it is connected between the input pin and the HIGH voltage. If the pin is disconnected, a tiny current goes through this resistor and sets the state of the pin HIGH. However, if pin is connected to the ground, the large resistance eats away all the voltage allowing the pin to go LOW.

Unless the pin is connected to a logic LOW or HIGH at all times, it is necessary to use pull-up resistors. Otherwise some electrons might be left to hang around on the pin when they shouldn't be. This potentially makes the state of the pin go nuts, which can mess up with the behaviour of the circuit.

AVR are quite handy that they have internal pull-ups, otherwise one would have to connect extra resistors to the pins to take care of those pesky, free-loading charge carriers. These internal pull-ups make using buttons on AVR very simple; all you have to do is to connect a button between ground and the pin. Then set the corresponding PORTB bit to one to enable the pull-up and your microcontroller is all ready to read some button states!

No comments:

Post a Comment