Sending negative numbers to shiftOut()

Hi all,
I'm trying to get my Arduino talking to a 16 relay board I picked up using a shift register - at this point in time I'm only working with 8 but once it's all working will move to use all 16.
I am using MQTT to receive a number relating to which relay to turn on or off. My code checks this number against a current status array and turns it on or off accordingly. I decided to have (to start with) an integer with zero value. I also have an array with my relay values as follows:

const int relayValues[]={1,2,4,8,16,32,64,128};

This way I can get the number of the relay that is being flipped, subtract 1 from it and get it's index value from this array. I then check if it's currently on or off - if it's on I XOR it with the current status, if it's off I OR it.
For example, if I received a value of 3, it would return 4 from this array. If no other relays are on, it would OR with the current value (which is an int that begins as 0) and output the new number (in this case 4).
I then send this number to my shift register after NOT-ing it, as my relay board uses a 1 to turn the relay off and 0 to turn it on. This then makes the value (in the example) -5.
My problem is this: my shiftOut command then looks like this:

shiftOut(datapin,clockpin,MSBFIRST,-5)

but nothing gets received at the other side of the shift register.
I'm confused why I'm getting -5 instead of 251 and if this would be causing my shift register to sit there with a dumb look on its face.
(the number in binary after NOTing is 11111011)

Full code below, criticism welcomed as I'm flying by the seat of my pants here.
Thanks :smiley:

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>

#define datapin 2
#define clockpin 3
#define latchpin 4
int current = 0;		// 00000000

const int relayValues[]={1,2,4,8,16,32,64,128};
int relayCheck[] = {0,0,0,0,0,0,0,0};
int changeVal = 0;
int chkOnOff[]={0,1};
String OnOrOff;

byte mac[] = {  
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
byte mqttserver[] = { 192, 168, 2, 7 };

EthernetClient ethClient;
PubSubClient clientr(mqttserver, 1883, callback);


int calculateRelayVal(int newVal) {
  
    Serial.print("Starting calculateRelayVal with val of ");
    Serial.println(newVal);
    Serial.print("Current value is ");
    Serial.println(current);
  
	// newVal has relay we need to toggle
	// referenced in relayCheck as newVal-1
	
	int intRelayToWorkWith = relayValues[(newVal-1)];
	
	if(relayCheck[(newVal-1)]==0) {
		// relay is currently off, turn on
		changeVal = current | intRelayToWorkWith;
		relayCheck[(newVal-1)]=1;
	} else {
		// relay is currently on, turn off
		changeVal = current ^ intRelayToWorkWith;
		relayCheck[(newVal-1)]=0;
	}

Serial.print("Finished checking values, changeVal currently ");
Serial.println(changeVal);

	current = changeVal;
	return current;
Serial.println("completing calculateRelayVal");
Serial.println("");
}
void doWork(int val) {
  
    Serial.println("");
    Serial.print("doWork starting with val of ");
    Serial.println(val);
  
	// as relays need a '0' to turn on and a '1' to turn off, need to NOT this value
        
	int realVal = ~val;

  Serial.print("Doing NOT conversion gives result of ");
  Serial.println(realVal);

	digitalWrite(latchpin,LOW);
	shiftOut(datapin,clockpin,MSBFIRST,realVal);
	digitalWrite(latchpin,HIGH);

Serial.println("sent value, closing doWork");
Serial.println("");
}



static void callback(char* topic, byte* payload, unsigned int length) {
  
  Serial.print("callback with payload ");
  length=length/2;
  Serial.write(payload,length);
  
  int readVar = (unsigned int)atoi((char *) payload);
  
  Serial.println(readVar);
  String debugcalReV = "Calling calculateRelayVal with the payload of ";
  String debugcalReVGO = debugcalReV + readVar;
  Serial.print(debugcalReVGO);
  Serial.println(" ... ");
  
  int registerValue = calculateRelayVal(readVar);  
  
  String debugregVal = "registerValue is set to ";
  String debugregValGO = debugregVal + registerValue;
  Serial.println(debugregValGO);
  Serial.println("doing work now for above value ... ");
  
  doWork(registerValue);
  
  String debugdoWork = "doWork complete for ";
  String debugdoWorkGO = debugdoWork + registerValue;
  Serial.println(debugdoWorkGO);
  
  if(relayCheck[(readVar-1)]==1) {
    OnOrOff = " turned on.";
  } else {
    OnOrOff = " turned off.";
  }
  String DataMash = "Publishing data - relay ";
  String DataResult = DataMash + readVar + OnOrOff;
  Serial.println(DataResult);
  char PublishData[100];
  DataResult.toCharArray(PublishData,100);

  clientr.publish("RelayControlReport", PublishData);
  
}




void setup()
{
  Serial.begin(9600);
  
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  if(clientr.connect("arduinoClient")) {
     clientr.publish("checkInTopic","Relay Controller Online");
     clientr.publish("RelayControlReport","Relay Controller Online");
    clientr.subscribe("RelayControl"); 
  }
  
delay(500);
Serial.println("Scouris - MQTT Control, booting up.");
Serial.println("Resetting relays to OFF ...");
doWork(0);
Serial.println("Continuing.");
  delay(1000);
}


void loop()
{
  clientr.loop();
}

(the number in binary after NOTing is 11111011)

Thanks for the well-presented question. In return, may I ask one? Isn't that the bit pattern you expected? If not, what was?

The 16-bit numbers -5 and 251 have the same bit pattern in the lower 8 bits. Which is all that goes to the shift register right now, right?

-br

// as relays need a '0' to turn on and a '1' to turn off, need to NOT this value

int realVal = ~val;

Taking the negative of a number is not the same as applying a logical NOT operation. Negative is a two's complement operation.
It makes no difference to the shift out what you send it will just take the bit pattern.

but nothing gets received at the other side of the shift register.

That shouldn't have happened. Something else is wrong.

I'm confused why I'm getting -5 instead of 251

-5 IS 251. They are one and the same and does not matter here.

If you really don't want -5, assign that value to an unsigned char type, or cast it, like:

shiftOut(datapin,clockpin,MSBFIRST,(unsigned char) -5)

But it actually does nothing because there is nothing that needs to be done.

Thanks for the responses, greatly appreciated.
In all the examples I've seen with using shiftOut it uses numbers between 0-255 so I was concerned when I saw my debug messages dumping negative numbers.
I'll re-do my physical circuit and see if I haven't managed to hook the wrong pins up somewhere :slight_smile:

Many thanks :slight_smile:

Edit: found out what my problem was. Total noobish mistake - in one of my editing frenzies, I removed the declarations for latchpin, clockpin and datapin as OUTPUTs. Put those in and it's all good now. Thanks again!