Phantom 'voltage' in analog I/O

My LCD recently stopped working after a short circuit so I went back to trying to figure out a switch-toggled I/O. However, I noticed that if I set a certain trigger to activate if the read voltage is above 100/255 in 8-bit mode (~2V I think), the trigger will activate even if I plug nothing into the I/O ports.

This was basically my ‘test program’:

void setup(){
    analog.setMode(MODE_8_BIT);
    analog.startConversion(1);
    delay(50);
   
    int currentV = 0;

    unsigned int r =0;
    while(r<10)
   {
        currentV = analog.readAverage(1,10);
        if(currentV > 100)
        {
             leds.green(HIGH);
             delay(500);
             r++
         }
     leds.green(LOW);
    }
}

So without anything plugged into the I/O ports, the green LED flashed ten times and then stopped. However, the red LED (which is supposed to activate when there is a positive voltage on input 1) did not flash. When I adjusted the ‘threshold voltage reading’ to 150, it did nothing (as it was supposed to do).

When I plugged in my SPDT lever switch to +, I/O port 1, and ground, the red LED would light when I clicked it, however, the program would flash the green LED even if I did not do anything, therefore implying it was reading a voltage of at least 100 on I/O port 1. I had plugged in the last output of the SPDT to ground through a 33 ohm resistor, so if I did not click the switch it would send the voltage to ground, and if I clicked the switch it would send the voltage to input 1. Before the short circuit that broke the LCD, this type of grounding had gotten rid of the ‘noise’, however now it seems like there is a noise even without anything plugged in at all. The same thing happened with using port 2 (an analog port). Is there a way to cure this, and am I right in thinking that the same short circuit that killed the lcd also messed up the voltage reading? (I had accidentally connected a + input voltage from an analog port to the ground on a digital port without a resistor)

I also have read about ‘pulling’ pins high or low but I do not understand what this means.

Also, if I ordered a replacement silver bezel LCD and 2x7 .100" male header strip, do I have to desolder the male headers from the Orangutan to attach it? I am not sure how to connect it right now.

Hello.

I need to apologize; I gave you incorrect information when I said you would need a male header to connect your LCD to the Orangutan LV-168. Unfortunately, the unit I checked as a reference before responding to you was manufactured in a non-standard way. You will need to solder a 2x7 female header to your LCD (just like I assume is on your broken LCD?), and this will plug into the male pins on your Orangutan. It would have been helpful if you had mentioned your confusion on this earlier since your order has already shipped, but we will ship you a free 2x7 female header this afternoon via the same shipping method as your original order.

As for your code problem, trying to read the voltage of a floating pin is somewhat meaningless; you cannot expect it to be at any particular value. When you are using something like a button that leaves an input floating when not pressed, you need to use a pull-up resistor to make sure it’s at a known voltage. For example, you can connect one side of the button/switch to ground and the other side to your input pin, which is also connected to 5V through a resistor. When the button is not pressed, the pin will read 5V, and when the button is pressed it will read 0V.

The mega168 digital I/O lines have internal pull-ups that you can enable by setting the appropriate bit of the PORTx register while it is configured as a digital input, which means you don’t have to use an external resistor. For example, to enable the internal pull-up on pin PC1, you would use:

DDRC &= ~(1 << PC1); // make pin PC1 an input
PORTC |= 1 << PC1; // enable internal pull-up to 5V (pin will read 5V when disconnected)

I also recommend you use digital logic to check for your switch (i.e., see if the appropriate bit of the PINx register is set or cleared). Looking at analog voltages seems like overkill for applications where there are only two possible states.

Does this make sense?

- Ben

Thank you for the clarification on pin pull-ups. I tried implementing that code for the pin, however, it seems that something weird has happened with the controller. When I turn it on it drives the motors very slowly and the blue power light near the power switch does not go on. I tried disconnecting the motors but it did not help. I am afraid I programmed something wrong and now it refuses to listen to further programming requests.

I think I first tried the code
DDRC &= ~(1 << PC1);
PORTC |= 1 << PC1;

and changed it to

DDRC &= ~(1 << PC1);
PORTC |= 0 << PC1;

in an attempt to pull the pin to 0V instead. I had put this part of the code inside a pushbutton activation i.e.

unsigned char button = buttons.waitForPress(TOP_BUTTON | BOTTOM_BUTTON);
if(button == TOP_BUTTON || button == BOTTOM_BUTTON)
{

}

however I still cannot get the board to power on normally or respond to programming requests. Is there a way to reset the board so I can program it agian?

Your hardware problems sound quite strange. If the blue power LED isn’t turning on, something is seriously wrong beyond just having programmed the device with faulty code. This would be indicative of bad power source or damage to the board itself. I have a few questions for you:

  • Are you using an Orangutan LV-168?
  • What is your power source?
  • Can you describe everything you had connected to your Orangutan and how it was connected? If you can provide pictures, this would be helpful.
  • Can you describe what happened to your Orangutan right before and after it started acting strangely? Did you smell any smoke? Could anything have been shorted?
  • You say it slowly drives the motors; does it drive both motors? Does it start driving the motors when you push the power button and stop when you push the power button again, or does it drive the motors all the time?

Your software problems seem to be secondary to the hardware issues, but I still want to address them. It looks like you’re trying to modify code without understand how it works or what the mega168 is capable of. In general, this can be a bad idea, though I doubt it’s the cause of your current problems.

The mega168 does not have internal pull-downs, only internal pull-ups. Clearing the PORT bit of a pin while it is an input just disables the internal pull-up and sets it as a high-impedance (floating) input. If you want to pull the pin to ground, you have to do it externally with a resistor (and you should configure it to be a high-impedance input).

Also, the line:

PORTC |= 0 << PC1;

doesn’t accomplish anything. “<<” is a bitshift operator. Bitshifting 0 by anything just results in 0, so 0 << PC1 = 0. If you then bitwise OR (|) PORTC with 0, you end up with 0 as x|0 always equals x. If you want to selectively clear a bit of the PORTC register without affecting the other bits, you would use:

PORTC &= ~(1 << PC1);

Does the above bitwise operation make sense to you?

- Ben

I was using an Orangutan LV-168 with 3x AA batteries, and I tried replacing the batteries several times, but I think the source of the problems lies with some previous short circuits (which broke the LCD earlier). The only things ever connected to the board were an SPDT switch, ocassionally a resistor and LED in the circuit with the SPDT switch for debugging, and 2 motors.

Here is what the strange action is: When I power the Orangutan on, the blue light stays off, the one connected motor moved at a very slow pace then stopped, and after several seconds the area of the LV-168 board near the motor connection became very warm. When I substituted in an LED with a resistor for the motor, the LED flashed several times (in an erratic fashion) before going blank. It would flash more if I hit the reset button or the power button again.

Previously I had used the SPDT switch to connect ground and PD0 externally (without a resistor) by default and 5V and PD0 externally when the switch was closed. I did this without knowing about high/low impedance internal modes (I thought the pulling high/low was for something specialized I didn’t need to worry about). Although this was probably not a good idea, the switch was only closed for a split second at a time (it was toggled by a rotating axle) so I think it didn’t result in any short circuits (that and the lack of a direct 5V to ground connection). Also I think the inputs were in high impedance mode by default. I am using a SPDT roller microswitch which looks like this.

This worked fine for a while, but I managed to swap the wires on the SPDT switch and create a short circuit condition (5V to ground by default, 5V to PD0 when switch closed) and this resulted in some burning smells, however, the board was OK after that and ran my 2 motors fine. After trying to connect the switch in the original position, I think I ran into another short circuit and then the LCD died (presumably due to the short). I then did some more testing, the board ran the motors fine, encountered the ‘floating pin’ phenomenon, then tried to pull pin 3 high and have the button press make the pin read 0V while connected, and soon after, the board started acting up.

This experimentation and screwup on wiring the SPDT switch was probably a dumb idea on my part, which resulted in the short circuits and killed the LCD and apparently the board too. I originally thought the ground was high impedance and that I was wiring it up a different way (default being +5V to ground), when in reality it was default PD0 to ground. If I connected PD0 to ground, this should pull the pin to low, correct? I had not noticed the ATmega documentation guide and thus I did not learn about the pull up/bitwise code, though I still don’t understand how the bits work. Please tell me if there is someplace that explains what the bits associated with a pin do that I missed, or at least the relevant pin.

I read in the documentation that “By default, all ports on the Orangutan are set to inputs, and the pull-ups are turned off, so no additional configuration is needed for most applications.” By default the pull-ups are off, so does this means the LV-168 is set to floating (high impedance) input and I wouldn’t need extra code for this floating/high impedance input mode? And this means I could connect the +5V to PD0 while the switch is toggled, without fear of short circuit? So could I use that along with connecting ground to PD0 by default?

If you connected your switch the way you described, this was probably fine. Pin PD0 is a high-impedance input by default, so as long as your code doesn’t reconfigure it as an output, you can safely connect it directly to 5V or ground. Note that in this case it doesn’t hurt to put a resistor between the pin and power (or ground). Normally this resistor will have no effect, but if you connect something wrong (e.g. power to ground, or use the pin as an output that is set to a different voltage than what you have it connected to), the resistor will limit the current that flows and hopefully protect components from damage.

If you smelled something burning, there’s a good chance you damaged or weakened a component or trace somewhere by shorting 5V to ground (probably the voltage regulator). What did you do to short-circuit the LCD? Did you remove it and then plug it back in wrong?

The integrated circuits used in modern electronics can be extremely sensitive; you need to make sure you know what you’re doing before connecting things. Use the web to research how components should be connected and how the MCU works, use your multimeter (if you don’t have one, I strongly suggest you get one) to test for unintended shorts before you apply power, and post questions here if you have an doubts about what you’re doing. When you are wiring up electronics, you should remove your power connection so that if you accidentally plug something in incorrectly, you have time to fix it before things start going up in smoke. Basically, be paranoid; have the attitude of “if I get this wrong, things might break forever”.

Connecting PD0 to ground will drive the pin low. If you instead connect PD0 to ground through a resistor, you will “pull” the pin low, and the size of the resistor will determine the strength of the pull (low resistance = strong pull). Does this make sense?

I don’t know of a good resource for using digital I/O on the AVR (you can try to do a google search on this), but I can briefly try to explain here, and I plan on writing a tutorial on this at some point:

The mega168 has its digital I/O pins divided into three ports: B, C, and D. Each port has three digital I/O registers associated with it (replace x below with B, C, or D):

DDRx: the bits of this register determine whether the pins in the port are digital outputs or inputs. If the bit is set, the pin is an output; if the bit is clear, the pin is an input.
PORTx: the bits of this register control the output value of the pins in the port when the pins are configured as outputs; they control the internal pull-up resistors when the pins are inputs. If the bit is set, an output will drive high and an input will have its internal pull-up enabled; if the bit is clear, an output will drive low and an input will be high-impedance.
PINx: the bits of this register reflect the input values of the pins in the port. If the bit is set, the voltage on the pin is not below the low threshold; if the bit is clear, the voltage on the pin not above the high threshold.

The bits of these eight-bit registers each correspond to a pin. For example, bit 0 of DDRD corresponds to pin PD0, bit 2 of DDRC corresponds to pin PC2, etc. To control the I/O state of a pin, you need to manipulate the specific bit of the specific registers that control that pin’s port. To do this, you use several operators:

~: bitwise NOT; ~1 = 0 and ~0 = 1; ~11101000 = 00010111
|: bitwise OR; 1 | x = 1 and 0 | x = x; 00010001 | 10000001 = 10010001
&: bitwise AND; 1 & x = x and 0 & x = 0; 00010001 & 10000001 = 00000001
<<: bitshift left; 00111001 << 3 = 11001000 (x << n = x * 2^n)
>>: bitshift right; 00111001 >> 3 = 00000111 (x >> n = x / 2^n)

Note that if you want to selectively set a bit in a byte while leaving all other bits alone, you want to use the | operator with a 1 at the same location as the bit you want to set and zeroes at all other locations (since ORing 0 with a bit will not change that bit). To get a 1 at the desired bit location, you can shift it. For example, if we want to set bit 5 of PORTD, we would do the following:

PORTD = PORTD | (1 << 5)
=> PORTD = PORTD | (00000001 << 5)
=> PORTD = {PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0} | 00100000
=> PORTD = {PD7 PD6 1 PD4 PD3 PD2 PD1 PD0}

If you want to selectively clear a bit in a byte while leaving all other bits alone, you want to use the & operator with a 0 at the same location as the bit you want to set and ones at all other locations (since ANDing 1 with a bit will not change that bit). To get a 0 at the desired bit location, you first want to shift a 1 to that location, and then you want to invert the byte using the ~ operator. For example, if we want to clear bit 5 of PORTD, we would do the following:

PORTD = PORTD & ~(1 << 5)
=> PORTD = PORTD & ~(00000001 << 5)
=> PORTD = PORTD & ~00100000
=> PORTD = {PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0} & 11011111
=> PORTD = {PD7 PD6 0 PD4 PD3 PD2 PD1 PD0}

In general, if you want to set bit n in byte B, you use the line:

B |= (1 << n)

and if you want to clear bit n in byte B, you use the line:

B &= ~(1 << n)

Yes, though I recommend you instead use your switch as a SPST in conjunction with enabling the internal pull-up on PD0. Use the switch to connect PD0 to ground when pressed and leave PD0 externally floating (and internally pulled high) when open. Using the switch as a SPDT will necessarily give you brief moments when either power is shorted to ground or when the pin is floating, neither of which are good states for digital electronics. Plus, if you use it as a SPST, it’s much less likely for you to wire it in a way that will short power to ground.

Please let me know if anything I said here is unclear.

- Ben