Society of Robots - Robot Forum

Software => Software => Topic started by: jonagik on August 19, 2011, 06:44:03 PM

Title: How to tell if an input port is high
Post by: jonagik on August 19, 2011, 06:44:03 PM
Do these lines in the Photovore_v1 code return true if the port is high/low (i.e. input) or do they return true if we've set them high/low (i.e. output)?

#define PORT_IS_ON( port_letter, number )      ( port_letter & (1<<number) )
#define PORT_IS_OFF( port_letter, number )      !( port_letter & (1<<number) )

Thanks
Title: Re: How to tell if an input port is high
Post by: adanvasco on August 19, 2011, 08:05:42 PM
In order to read a port digital input (high or low) you should use the PINx register, where x is the port letter.
Title: Re: How to tell if an input port is high
Post by: rbtying on August 19, 2011, 09:31:55 PM
If you pass in the PINx register for the port_letter parameter, it will tell you the value it reads from the pin - that is to say, input; however, the pin may not be in high-impedance mode.
Title: Re: How to tell if an input port is high
Post by: jonagik on August 19, 2011, 09:33:28 PM
Thanks for that :)
Title: Re: How to tell if an input port is high
Post by: jonagik on August 19, 2011, 10:19:09 PM
Is this valid?

if( (PIND) & (1 << 2) ) {
    //Do something when port D2 input is high.
}
Title: Re: How to tell if an input port is high
Post by: Metal Slug 2 on August 19, 2011, 10:44:40 PM
Is this valid?

if( (PIND) & (1 << 2) ) {
    //Do something when port D2 input is high.
}
Yep. :)
When you read PIND, an 8-bit binary number will result, with a 0 representing LOW and 1 representing HIGH.  Then, when you AND (&) the reading with (1<<2), you are checking to see if port D2 is HIGH.

So for example, lets assume in whatever circuit you have setup only the portD2 pin is attached to some sensor, and that sensor is outputting a HIGH signal.  When the microcontroller reads PORTD, the resulting binary number is: 00000100
When you then AND that number with (1<<2), which is 100 in binary, the result is TRUE, and therefore the microcontroller knows that pinD2 is HIGH.


Title: Re: How to tell if an input port is high
Post by: jonagik on August 19, 2011, 10:57:52 PM
I've got a switch attached from VCC to PD2 and an LED from VCC to PD4.

My code is:
DDRD = 0x10;
while(1) {
     if ((PIND) & (0x03)) {
          PORTD = 0x00;
     }
     else {
          PORTD = 0x10;
     }
}

However, when I execute this on my ATMEGA8515, the LED remains lit regardless of the switch position (which implies that D2 is HIGH regardless of the switch position). What's going wrong?

Thanks in advance.
Title: Re: How to tell if an input port is high
Post by: rbtying on August 19, 2011, 11:05:00 PM
If the switch is attached from VCC to PD2, you'll need a pulldown resistor to pull it down to ground when the switch is not depressed.

What you could do instead, however, is to enable the internal pullup on PD2 (PORTD |= 1 << 2) and set it as an input, and then connect the switch between PD2 and ground. It'll read an inverted signal (true when switch is not pressed, false when switch is pressed), but it's simpler to set up, and easy to account for in the code.
Title: Re: How to tell if an input port is high
Post by: jonagik on August 19, 2011, 11:35:21 PM
I've attached the switch from PD2 to GND and used the following code but it still doesn't work (LED remains on):

   DDRD = 0x10;
   while (1) {
      PORTD |= (1 << 2);
      if ((PIND) & (0x03))  {
         PORTD = 0x00;
      }
      else {
         PORTD = 0x10;
      }
   }   
Title: Re: How to tell if an input port is high
Post by: rbtying on August 19, 2011, 11:37:42 PM
You need to use Read-Modify-Write on the PORTD operations - you're removing the pullup on the switch when you set PORTD to 0x00 and 0x10.
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 12:08:51 AM
Shouldn't this work?

              DDRD = 0x14;
   while (1) {
      if (PIND2)  {
         PORTD = 0x04;
      }
      else {
         PORTD = 0x14;      
      }
   }

However, it doesn't.

If someone could post some code which works which I could reverse-engineer it would be much appreciated.

Thanks in advance.
Title: Re: How to tell if an input port is high
Post by: Metal Slug 2 on August 20, 2011, 12:52:23 AM
Shouldn't this work?

              DDRD = 0x14;
   while (1) {
      if (PIND2)  {
         PORTD = 0x04;
      }
      else {
         PORTD = 0x14;      
      }
   }

However, it doesn't.

If someone could post some code which works which I could reverse-engineer it would be much appreciated.

Thanks in advance.

I think your if statement is written incorrectly.  Just referencing PIND2 returns a 1 or a 0, so try changing
if(PIND2){...}
to
if( PIND2 == 1 ){...}
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 12:58:37 AM
Yea I wondered if that was the problem but it doesn't help.
Title: Re: How to tell if an input port is high
Post by: Metal Slug 2 on August 20, 2011, 01:15:22 AM
Try this:
if( PIND & (1<<2) ){...}
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 01:36:21 AM
Yea I tried that - same problem.
Title: Re: How to tell if an input port is high
Post by: joe61 on August 20, 2011, 06:45:01 AM
I've got a switch attached from VCC to PD2 and an LED from VCC to PD4.

My code is:
DDRD = 0x10;
while(1) {
     if ((PIND) & (0x03)) {
          PORTD = 0x00;
     }
     else {
          PORTD = 0x10;
     }
}

You need to test for a specific pin. When you say "((PIND) & (0x03))" you're testing to see if both pin 0 and pin 1 are on, which they won't be. 

This is for a tiny85 but the idea is the same.

Code: [Select]
#include <avr/io.h>
#include <util/delay.h>

#define led PB2
#define sw  PB0

int main()
{
    DDRB |= (1 << led);
    for (;;)
    {
if (PINB & (1 << sw))
    PORTB |= (1 <<led);
else
    PORTB &= ~(1 << led);
_delay_ms (100);
    }
}

Joe
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 07:06:37 PM
Isn't ((PIND) & (0x03)) the same as ((PIND) & (1 << 2))?

I've got a switch attached from VCC to PD2 and an LED from VCC to PD4.

My code is:
DDRD = 0x10;
while(1) {
     if ((PIND) & (0x03)) {
          PORTD = 0x00;
     }
     else {
          PORTD = 0x10;
     }
}

You need to test for a specific pin. When you say "((PIND) & (0x03))" you're testing to see if both pin 0 and pin 1 are on, which they won't be. 

This is for a tiny85 but the idea is the same.

Code: [Select]
#include <avr/io.h>
#include <util/delay.h>

#define led PB2
#define sw  PB0

int main()
{
    DDRB |= (1 << led);
    for (;;)
    {
if (PINB & (1 << sw))
    PORTB |= (1 <<led);
else
    PORTB &= ~(1 << led);
_delay_ms (100);
    }
}

Joe
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 07:08:25 PM
My current code (which isn't working) is as follows. My switch is connected from VCC to PD2 and my LED from VCC to PD4.

DDRD |= (1 << 4);
while (1) {
      if (PIND & (1 << 2))  {
         PORTD |= (1 << 4);
      }
      else {
         PORTD &= !(1 << 4);
      }
}

Where is the error? The LED remains lit.
Title: Re: How to tell if an input port is high
Post by: Webbot on August 20, 2011, 07:17:09 PM
This line:
Code: [Select]
PORTD &= !(1 << 4);
should be:
Code: [Select]
PORTB &= ~(1 << 4);
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 08:13:51 PM
Same problem :(
Title: Re: How to tell if an input port is high
Post by: Webbot on August 20, 2011, 08:34:08 PM
This line:
Code: [Select]
PORTD &= !(1 << 4);
should be:
Code: [Select]
PORTB &= ~(1 << 4);

Ooops - should have said:-

Code: [Select]
PORTD &= ~(1 << 4);
ie you should '~' rather than '!'
Title: Re: How to tell if an input port is high
Post by: Metal Slug 2 on August 20, 2011, 08:41:33 PM
I've got a switch attached from VCC to PD2 and an LED from VCC to PD4.
If you have the LED connected directly from Vcc to PD4, then you may have burnt out your LED.  If you have another LED, try hooking that up in series with a 220, 240, or 270 Ohm resistor.

Isn't ((PIND) & (0x03)) the same as ((PIND) & (1 << 2))?
Not quite, but your close.  As I mentioned before, (1<<2) in binary is 100.  When we convert 0x03 (a hexadecimal number) into binary we get 11.  To correct this mistake, we must find the hex equivalent of (1<<2) which is 0x04.
Therefore (PIND & 0x04) is the same as (PIND & (1<<2))
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 08:54:07 PM
@Webbot: I assumed as much - doesn't work with the tilde rather than the exclamation mark.

@MetalSlug2: I can get the LED to turn on/off by itself and flash and everything. I'm just having trouble with input.

Regarding the 0x03 it was a typo on my part. I meant 0x04.

So, why is my code not working?
Title: Re: How to tell if an input port is high
Post by: Metal Slug 2 on August 20, 2011, 09:53:27 PM
Ok, so I tried the experiment myself, and everything worked for me.  The code I used is:
Code: [Select]
DDRD |= 0x10; //or DDRD |= (1<<4) or  DDRD |= 0b00010000 --> PD4 used for LED, so make it output.
for(;;){
   if( PIND & (1<<2) ){
       PORTD |= (1<<4);
   }else{
       PORTD &= ~(1<<4);
   }
}
This will turn the LED OFF when PD2 is HIGH and ON when PD2 is LOW.

The only other thing I can think of that may be causing you problems is you have the LED mounted backwards. If this is true, and the anode of the LED is attached to PD4 and cathode to Vcc, then the LED can never be lit.  Double check that the anode of your LED (longer lead) is attached to Vcc, and the cathode to PD4.
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 10:18:37 PM
I tried using that exact code and it doesn't work.

I can light the LED by itself and make it blink. I can't seem to make the switch work though.

Any ideas?
Title: Re: How to tell if an input port is high
Post by: Metal Slug 2 on August 20, 2011, 10:26:24 PM
Can you provide a schematic of how your switch is hooked up please?  Are you sure you have your switch connected to PD2?
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 10:39:28 PM
I'll give you the whole layout (nb: using ATMEGA8515):

Power supply (+ve) to 5V regulator.
Power supply (-ve) to GND regulator.
Other leg of 5V regulator to VCC (Pin 40)
GND of 5V regulator to GND (pin 20)
[Programmer connection is working so won't bother with that]
PD4 (Pin 14) to LED.
LED to VCC (pin 40)
VCC to switch to PD2 (pin 12)
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 10:42:02 PM
Is it possible that at some stage I've damaged the uC with a short circuit or something?

However, I would have though that if I had, the whole uC would stop working.
Title: Re: How to tell if an input port is high
Post by: Metal Slug 2 on August 20, 2011, 10:59:20 PM
VCC to switch to PD2 (pin 12)
Ahh ok, this might be the problem then.  PD2 is not tied to ground, therefore when the switch is not pressed (assuming it is NO (normally open) i.e. off) the readings coming from PD2 are "floating" between 0 and 1, i.e. On and Off at random, and not necessarily off as you may may have assumed.  Given the circumstances of your problem, it may very well be that PD2 is returning a HIGH signal, for whatever reason.

To solve this problem, follow the schematic below:
(http://www.ladyada.net/images/arduino/pulldown.png)
This will ensure that if the button is not being pressed, a reading from PD2 will always be LOW.
Note: since you are not using PD2 as an output pin, you do not have to worry about the 100 Ohm resistor.
Title: Re: How to tell if an input port is high
Post by: jonagik on August 20, 2011, 11:36:46 PM
Thanks everyone - it's working now. The error was that I needed to attach the pin permanently to GND via a resistor and via a switch to VCC.