Is is possible to detect pin mode in and IF

Hi,

I am trying to write a web generic interface which allows you to view the inputs and set the outputs over a network/internet. To keep it as generic and configurable as possible I want to do something like:

Pseudo code:

if (pinmode(1) == Output) //If the digital pin 1 is a output
{
    //Html for output, ie a check box which and be turned on/off by the user
}
else
{
    //Html for input, ie a check box which can't be edit by the user and shows the current state of the input.
}

Is this possible?

Interesting question. Supposedly yes, as I've read that the digitalWrite code checks the state of the pin, and if High was commanded and it was already High, then nothing is done. So it's probably a matter of reading the correct status registers.

I found that you can use DigitalRead() to get the status of a digital output pin and I am using that to ensure my check boxes match the pins status

//Check the status of pin 8, if it is low display an empty check box, otherwise show a checked one
if (digitalRead(8)==0) server.println("<input type=checkbox name=8 value=1>
");
else server.println("<input type=checkbox name=8 value=1 checked>
");

But wanted to take it a step further and check the pin’s mode. Maybe a step too far?

That's up to you. You could set up an int array pin_mode19 and set bits hi/lo as you declare them to be inputs/outputs, simple read of the array will tell you how think you left them, and if digitalRead works on pins set as input or outputs you'd be golden. Each byte could represent this data for each IO pin: bit 0 = 1, digital input enabled bit 1 = 1, digital output enabled bit 3 - commanded output level if digital bit 4 - read level of the pin if digital

bit 5. 0 = analog input enabled if Bit 0 & 1 are low. 1 = analog output enabled if Bit 0 & 1 are low

bit 6, 7 = bits 8, 9 of analog read value if analog input enabled bits 8-15 analog value commanded (0-255) if analog output enabled, bits 0-7 of analog read value if input enabled.

Now, maybe that's overkill for you!

The DDRx registers keep track of which direction a Pin is defined as. There doesn't seem to be an Arduino-function to (only) read the register. So you'll have to map the ATmega's I/O pin's location in the DDRx registers to the pins on the Arduino board.

CrossRoads:
…simple read of the array…

Isn’t that kind of risky? What if other functions/classes set other pins? I mean, some functions used by your sketch sketch might define directions of various pins on their own, and might even change directions of some pin(s) as various tasks are performed.

Anyhow…

Isn’t it better to read the DDR register bits for the pins?

//
// Test function to display  DDR register bits for Arduino pins
//
// davekw7x
//
void setup()
{
    Serial.begin(9600);

    // Set up various pins and test I/O mode of all pins
    pinMode(13, OUTPUT);
    pinMode(3, OUTPUT);

    // Put other pimMode stuff here if you want to

    //
    // Now get mode values for the pins
    // If it's for an ATmega1280 or '2560, pins go up to 69
    //
    for (int pin = 0; pin < 21; pin++) {
        int mode = getPinMode(pin);
        if (mode < 0) {
            Serial.print("Pin number ");
            Serial.print(pin); 
            Serial.println(" is invalid.");
        }
        else {
            Serial.print("Mode of Pin ");
            Serial.print(pin);
            Serial.print(" is ");
            if (mode == INPUT) {
                Serial.println("INPUT.");
            }
            else {
                Serial.println("OUTPUT.");
            }
        }
    }
}
void loop(){
}
//
// Function to read state of mode bit in DDR register.
//
//  davekw7x
//
// If the pin number is invalid, return -1
//
// For valid pins:
//   return 0 if the designated pin is an input pin and
//   return 1 if it is an output pin.
//
// This corresponds to direction bits in the DDR.
// That is, INPUT is defined as zero and OUTPUT is one.
//
//
// Note that the digitalPinToBitMask and digitalPinToPort
// do not test  for invalid pin numbers, so I compare with a
// constant defined by a conditional compile directive.
//
#include <pins_arduino.h>
int getPinMode(int p)
{

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    const int MAX_DIGITAL_PIN_NUMBER = 69;
#else
    const int MAX_DIGITAL_PIN_NUMBER = 19;
#endif

    // Check valid pin number
    if (p > MAX_DIGITAL_PIN_NUMBER) {
        return -1;
    }

    // Convert designated Arduino pin to ATMega port and pin
    uint8_t pbit  = digitalPinToBitMask(p);
    uint8_t pport = digitalPinToPort(p);

    // Read the ATmega DDR for this port
    volatile uint8_t *pmodereg = portModeRegister(pport);

    // Test the value of the bit for this pin and return 
    // 0 if it is reset and 1 if it is set
    return ((*pmodereg & pbit) != 0);
}

Output (on Duemilanove)


[color=blue]Mode of Pin 0 is INPUT.
Mode of Pin 1 is INPUT.
Mode of Pin 2 is INPUT.
Mode of Pin 3 is OUTPUT.
Mode of Pin 4 is INPUT.
Mode of Pin 5 is INPUT.
Mode of Pin 6 is INPUT.
Mode of Pin 7 is INPUT.
Mode of Pin 8 is INPUT.
Mode of Pin 9 is INPUT.
Mode of Pin 10 is INPUT.
Mode of Pin 11 is INPUT.
Mode of Pin 12 is INPUT.
Mode of Pin 13 is OUTPUT.
Mode of Pin 14 is INPUT.
Mode of Pin 15 is INPUT.
Mode of Pin 16 is INPUT.
Mode of Pin 17 is INPUT.
Mode of Pin 18 is INPUT.
Mode of Pin 19 is INPUT.
Pin number 20 is invalid.[/color]

Regards,

Dave

Well, sure, take all the fun out of it :slight_smile:
I could see that way being useful too.

Very nice work Dave,

saw one tiny bug, the function accepts negative numbers, so the validity test should be extended.

// Check valid pin number
if (p > MAX_DIGITAL_PIN_NUMBER || p < 0) {
return -1;
}

or should - p - become an unsigned int / uint8_t?

in the test_app: for (int pin = -1; pin < 21; pin++)

robtillaart: ...bug...

Oops.

should - p - become ... uint8_t?...

I'm thinking that's what I should have done.

Regards,

Dave

davekw7x:

CrossRoads:
…simple read of the array…

Isn’t that kind of risky? What if other functions/classes set other pins? I mean, some functions used by your sketch sketch might define directions of various pins on their own, and might even change directions of some pin(s) as various tasks are performed.

Anyhow…

Isn’t it better to read the DDR register bits for the pins?

//

// Test function to display  DDR register bits for Arduino pins
//
// davekw7x
//
void setup()
{
   Serial.begin(9600);

// Set up various pins and test I/O mode of all pins
   pinMode(13, OUTPUT);
   pinMode(3, OUTPUT);

// Put other pimMode stuff here if you want to

//
   // Now get mode values for the pins
   // If it’s for an ATmega1280 or '2560, pins go up to 69
   //
   for (int pin = 0; pin < 21; pin++) {
       int mode = getPinMode(pin);
       if (mode < 0) {
           Serial.print(“Pin number “);
           Serial.print(pin);
           Serial.println(” is invalid.”);
       }
       else {
           Serial.print("Mode of Pin “);
           Serial.print(pin);
           Serial.print(” is ");
           if (mode == INPUT) {
               Serial.println(“INPUT.”);
           }
           else {
               Serial.println(“OUTPUT.”);
           }
       }
   }
}
void loop(){
}
//
// Function to read state of mode bit in DDR register.
//
//  davekw7x
//
// If the pin number is invalid, return -1
//
// For valid pins:
//   return 0 if the designated pin is an input pin and
//   return 1 if it is an output pin.
//
// This corresponds to direction bits in the DDR.
// That is, INPUT is defined as zero and OUTPUT is one.
//
//
// Note that the digitalPinToBitMask and digitalPinToPort
// do not test  for invalid pin numbers, so I compare with a
// constant defined by a conditional compile directive.
//
#include <pins_arduino.h>
int getPinMode(int p)
{

#if defined(AVR_ATmega1280) || defined(AVR_ATmega2560)
   const int MAX_DIGITAL_PIN_NUMBER = 69;
#else
   const int MAX_DIGITAL_PIN_NUMBER = 19;
#endif

// Check valid pin number
   if (p > MAX_DIGITAL_PIN_NUMBER) {
       return -1;
   }

// Convert designated Arduino pin to ATMega port and pin
   uint8_t pbit  = digitalPinToBitMask(p);
   uint8_t pport = digitalPinToPort(p);

// Read the ATmega DDR for this port
   volatile uint8_t *pmodereg = portModeRegister(pport);

// Test the value of the bit for this pin and return
   // 0 if it is reset and 1 if it is set
   return ((*pmodereg & pbit) != 0);
}




Output (on Duemilanove)


---



Mode of Pin 0 is INPUT.
Mode of Pin 1 is INPUT.
Mode of Pin 2 is INPUT.
Mode of Pin 3 is OUTPUT.
Mode of Pin 4 is INPUT.
Mode of Pin 5 is INPUT.
Mode of Pin 6 is INPUT.
Mode of Pin 7 is INPUT.
Mode of Pin 8 is INPUT.
Mode of Pin 9 is INPUT.
Mode of Pin 10 is INPUT.
Mode of Pin 11 is INPUT.
Mode of Pin 12 is INPUT.
Mode of Pin 13 is OUTPUT.
Mode of Pin 14 is INPUT.
Mode of Pin 15 is INPUT.
Mode of Pin 16 is INPUT.
Mode of Pin 17 is INPUT.
Mode of Pin 18 is INPUT.
Mode of Pin 19 is INPUT.
Pin number 20 is invalid.




---



Regards,

Dave

Thanks for that, I will give it a try.