Read Port Number via Serial / Analog Pins

Hey,
i am Building myself a little “Debug” Software (Read and Write IO Pins via Serial Interface).

So i want to say:

Read - Digital - PIN#

and it should give Back: "Pin PIN# is HIGH

or

Write - Analog - PIN# - Value - Time

And it should put Pin PIN# to Value for Time.

For Digital Pins this is Done so far.

int PortEinlesen()
{
	/*	Valid Ports: digi_0 - digi_max
	 *	sowie A_0 - A_max
	 *	AnalogPorts -> 10xx
	 *	zB 	A10 = 1010
	 *		A8  = 1008
	 */
	const int digi_0 = 0;
	const int digi_max = 53;
	const int A_0 = 1000;
	const int A_max = 1015;
	char incoming[5];
	for(int i=0; i<4;i++)
	{
		incoming[i] = -1;
	}
	read:
	Serial.println("PinNR pls(00-53, A0-A15");
	einlesen:
	while(incoming[1] == -1)
	{
		delay(1000);
		if (Serial.available() > 0)
		{
			// read the incoming byte:
			Serial.readBytesUntil('\n',incoming,4);
			/*for(int i=0; i<4;i++)    //DEBUGGING
			{
				Serial.print("Angekommen: ");
				Serial.print(i);
				Serial.print(". ");
				Serial.print(incoming[i],DEC);
				Serial.print(". ");
				Serial.println(incoming[i]);
			}*/
		}
	}
	int Port = 0;
	int faktor = 1;
	for(int i =3; i>=0; i--)
	{
		if(incoming[i] == -1) continue;
		if(incoming[i] == 'A') {Port += 1000; continue;)
		/*Serial.print("incoming["); //DEBUGGING
		Serial.print(i);
		Serial.print("] = ");
		Serial.print(incoming[i],DEC);
		Serial.print(", Faktor = ");
		Serial.print(faktor);
		Serial.print(", Port vor Summe = ");
		Serial.print(Port);
		Serial.print(".\nPort nach Summe = ");*/
		Port += faktor * (incoming[i] - 48);
		faktor = faktor * 10;
		//Serial.println(Port);
	}
	if(!((Port >= digi_0 && <= digi_max) || (Port >= A_0 && Port <= A_max)))
	{
		Serial.print("Port nicht gültig!"); 
		return -1;
	}
	return Port;
}

Works good so far, no Problems for Digital IO.

But now i get an AnalogPin, so it Returns me 10xx.

How do i Change 10 to A?

AFAIK the Compiler turns all Ax to specific INT Values (eg A0 <-> 14 on Arduino Uno).
But the Values are Different for each Arduino Version, so i cant do

if (Port = 1000) Port = 14;

and i would have to do it for 16 Analog out on a Arduino MEGA → wasted Runtime.

Any “Clean” Ideas?

For analogRead you normally just pass the analog port number, not the Axx compiler macro.

int xxx = analogRead(3); // Read from analog pin 3

Just treat it in the exact same way as your digital code, but use analogRead instead of digitalRead.

Okay THX works for AnalogRead on AnalogPins.
But how About DigitalRead on Analog Pins?

I dont really need it but i want to make the software as universal as possible.

Ah, right, digital read on analog pins. I see where you're going now.

Yes, they will be different on the different boards.

But, you'll be compiling the code each time for each board, won't you?

You can use compiler directives to change the offset you add to the pin number (Pin - 1000 + offset) depending on which board you're compiling on. You could do it by the chip on the board (#ifdef AVR_ATmega328P).

There is a complete list here: Using the GNU tools

For analogRead you normally just pass the analog port number, not the Axx compiler macro.

For analogRead, you can use either.

ATM i'm Thinkin 'bout using the IF terms.

Seems a lot easier and its only a Debug Software so its not time critical.

i was hoping that A in general was defined as 14 (depending on Board) so i could just say

if > 1000 than -1000 + A.

Are the A pins "in line" on all boards? so 14 to xx without interrupts?

Than we could use

Port - 1000 + A0, so 1000 would be A0, 1001 would be A1 and so on.
seems workin on arduino uno, anyone could Say for other?

AWOL:

For analogRead you normally just pass the analog port number, not the Axx compiler macro.

For analogRead, you can use either.

Hypothetical question...

Suppose you craft a board with 8 digital and 16 analog pins.

Digital read can go from 0-23 (0-7 being digital, 8-23 being analog). Analog read can go from 0 to 15.
A0 equates to 8, A1 to 9, etc through to A15 being 23.

Which analog pin would you expect to read when doing analogRead(A3) ?

That is why you don't use Axx for analogRead.

Admittedly it's not a problem on the "common" boards, but there's nothing to stop a board like that being made by someone, so it's a good idea to not get into the habit of using Axx for analog reads.

pilzkopf:
ATM i'm Thinkin 'bout using the IF terms.

Seems a lot easier and its only a Debug Software so its not time critical.

i was hoping that A in general was defined as 14 (depending on Board) so i could just say

if > 1000 than -1000 + A.

Are the A pins "in line" on all boards? so 14 to xx without interrupts?

Than we could use

Port - 1000 + A0, so 1000 would be A0, 1001 would be A1 and so on.
seems workin on arduino uno, anyone could Say for other?

That should work, yes.

More specifically:

if (port >= 1000) {
  port = port - 1000 + A0;
}

So, if A0 is 14, you enter 1000 you end up with 14. You enter 1001 you end up with 15, etc.

You could have some upper bounds checking with

if (port > A0 + NUM_ANALOG_PINS - 1) {
  Serial.println("Unknown analog pin");
  return;
}

NUM_ANALOG_PINS is defined in pins_arduino.h in the board variant. On the Uno it is defined as 6. So entering 1006 would give you 1006 - 1000 + 14 = 20. A0+NUM_ANALOG_PINS-1 = 14 + 6 - 1 = 19. 20 > 19, so fail.

Thinking about best type of return in my EnterPort function:

If i return 10xx for analog i couldn't use it directly.
If i return the Value of "xx + A0" i could use it directly in digitalRead, but not analogRead.

Your Choice? :wink:

EDIT:
Is there a list of Consts like NUM_ANALOG_PINS? Could be very helpful (defined my own ATM).

If you represent the pin internally purely as the digital pin number, you can calculate everything else from that.

If the pin number >= A0 then you are in the realms of the analog pins.

If the pin number >= A0 + NUM_ANALOG_PINS then you don't have a valid pin.

You can print the analog pin name with "A" + (digitalPinNumber - A0)

if (digitalPinNumber >= A0) {
  Serial.print("A");
  Serial.print(digitalPinNumber - A0);
} else {
  Serial.print(digitalPinNumber);
}

To do an analogRead, first ensure you have an analog pin, then read from it:

if (digitalPinNumber >= A0) {
  return analogRead(digitalPinNumber - A0);
} else {
  return -1;
}

The "digital" pin number is the only really unique pin identifier.

Drop the whole 1000+ thing, and if the user enters Axx then just add A0 to the xx part of the input value. That way it's always internally represented directly as the digital pin number.

But than i have to substract A0 for analogRead()

Yes, as in the little code snippet above.