Code Check for ROV

I've made post in different sections before concerning this project. As a Capstone Senior Design project my team is building an ROV......we are all Mechanical Engineers with no robotic experience making the programming difficult. My part of the project is to control this thing. We need to control 4 horizontal thrusters, two vertical thrusters, and a servo. I initially developed code that would take voltage analog inputs from the surface using joysticks and transmit this voltage to an arduino onboard the ROV via 50' of ethernet line. Noise may be a concern here so I am now working on serial communication using RS232. I was able to find several examples of serial communication on this website and I think I may now have functioning code, at least according to my testing with LEDs.

The code receives inputs from an Arduino on surface in a form like this: and then executes the commands. The commands are not developed yet, I am just turning on LEDs right now and I have commented out some things for testing purposes.

My question is this: What if anything could go wrong with this? How reliably will this behave?

I think I have provided everything yall need to help me, if not let me know. Thankyou!

const char SOP = '<';
const char EOP = '>';

enum { Case, Speed };

int whichNumber = Case;

int  Casev, Speedv;


//-------------------------------------------------------------------


void setup ()
  { 
  Serial.begin (9600);
  pinMode (3, OUTPUT);
  pinMode (4, OUTPUT);
  pinMode (5, OUTPUT);
  pinMode (6, OUTPUT);
  pinMode (7, OUTPUT);
  pinMode (8, OUTPUT);
  pinMode (9, OUTPUT);
  pinMode (10, OUTPUT);
  pinMode (11, OUTPUT);
  pinMode (12, OUTPUT);
  pinMode (13, OUTPUT);
  
  } 

//------------------------------------------------------------------- 

  
void processNumber (int n)
  {
  int x = n;  
  
  switch (whichNumber)
    {
      
    case Case: 
      Casev = x;
      whichNumber = Speed;
      //Serial.print ("  Case = ");
      break;
      
    case Speed: 
      Speedv = x;
      whichNumber = Case;
      //Serial.print (" Speed = ");
      break;
    
  
    }
    //Serial.print(x);
  }  
  
  
 //------------------------------------------------------------------- 
  
void processInput ()
  {
  static float receivedNumber = 0;
  static boolean False = false;
  
  byte c = Serial.read ();
  
  switch (c)
    {
      
    case EOP:  
      if (False) 
        processNumber (- receivedNumber); 
      else
        processNumber (receivedNumber); 

    // fall through to start a new number
    case SOP: 
      receivedNumber = 0; 
      False = false;
      break;
      
    case '0' ... '9': 
      receivedNumber *= 10;             // receivedNumber = recievedNumber*10
      receivedNumber += c - '0';       //receivedNumber = recievedNumber + (c - '0')
      break;
      
    case '-':
      False = true;
      break;
      
    } 
  }  


//-------------------------------------------------------------------
  
void loop ()
  {
  if (Serial.available ())
  processInput ();
  int  var1 = Casev;
  int  var2 = Speedv;
    
    switch (var1)
    {
    //RIGHT  
    case 1:
    analogWrite(3,var2);
    
    
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(12, LOW);
   // digitalWrite(13,LOW);
    break;
    
    //LEFT
    case 2:
    analogWrite(9,var2);
    
    
    digitalWrite(3,LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(12, LOW);
   // digitalWrite(13,LOW);
    break;
    //FWD
    case 3:
    analogWrite(10,var2);
    
    
    digitalWrite(3,LOW);
    digitalWrite(4, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(12, LOW);
   // digitalWrite(13,LOW);
    break;
    
    //REV
    case 4:
    analogWrite(6,var2);
    
    digitalWrite(3,LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(12, LOW);
    //digitalWrite(13,LOW);
    break;
    
    //CW
    case 5:
    digitalWrite(7,HIGH);
    
    digitalWrite(3,LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(12, LOW);
   // digitalWrite(13,LOW);
    
    break;
    
    //CCW
    case 6:
    digitalWrite(8,HIGH);

  //digitalWrite(3,LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(12, LOW);
  //digitalWrite(13,LOW);
    break;
    
    //SURFACE
    case 7:
    digitalWrite(4,LOW);

   // digitalWrite(3,LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(10, LOW);
    digitalWrite(12, LOW);
    //digitalWrite(13,LOW);
    break;
    
    //DIVE
    case 8:
    digitalWrite(5,var2);

    //digitalWrite(3,LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(12, LOW);
    digitalWrite(13,LOW);
    break;
    
    //PITCH 
    case 9:
    analogWrite(12,var2);
    
    //digitalWrite(3,LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
   // digitalWrite(13, LOW);
    break; 
    
    //SERVO   
    case 10:
    digitalWrite (13,HIGH);
    
    
    //digitalWrite(3,LOW);
    //...digitalWrite(4, LOW);
    // digitalWrite(5, LOW);
    //digitalWrite(6, LOW);
    //digitalWrite(7, LOW);
    //digitalWrite(8, LOW);
    //digitalWrite(9, LOW);
    //digitalWrite(10, LOW);
    //digitalWrite(12, LOW);
    break;
    
    }
    
  } 
  //-------------------------------------------------------------------

This is the code that transmits the serial data from the surface. It take analogy inputs from a joystick.

//INPUTS
int pot12 = A0; 
int pot34= A2; 
int potLR = A1;



//ADJUSTABLE PARAMETERS
int frequency=256;
float speedlimit= 1; // Value range: 0-1 (0-100%)
int DEADBAND= 20;

//OUTPUT VALUES
int val12 = 0; 
int val34= 0;
int valLR = 0;
int Fs= 0;
int Bs= 0;
int CWs=0;
int CCWs=0;
int Rs=0;
int Ls=0;
int fwd = 127-DEADBAND/2;
int rev = 127+DEADBAND/2;
int Cfwd = 255;
int Crev = -255;
int LEFT = 127-DEADBAND/2;
int RIGHT = 127+DEADBAND/2;
int Cleft= 255;
int Cright= -255;
int Case=0;







void setup() {
Serial.begin(9600);
;
  pinMode(pot12, INPUT);
  pinMode(pot34, INPUT);
  pinMode(potLR, INPUT);
 
}

//-------------------------------------------------------------------
void loop() {
// SET PWM
  
  valLR = analogRead(potLR)/4;
  
//RIGHT 
    if (valLR >= RIGHT  ) 
    {
     //Case 1    
     bumpright();
     
    }
    
//LEFT
    else if (valLR <= LEFT) 
    {  
      //Case 2
      bumpleft();
    }
    
//FWD,REV OR CW,CCW SEE LOOP1234    
    else  
    {
       //Case 3,4,5,6      
       loop1234();
    }
   Serial.print('<');
   Serial.print(10);
   Serial.print('>');
   Serial.print('<');
   Serial.print(255);
   Serial.print('>');

delay(100);



}    
 
 
//-------------------------------------------------------------------
 

void bumpleft() {
  
  Ls= (Cleft-(valLR))*speedlimit;  //left speed
  
   Case=1;
   Serial.print('<');
   Serial.print(Case);
   Serial.print('>');
   Serial.print('<');
   Serial.print(Ls);
   Serial.print('>');
}
    
//------------------------------------------------------------------- 
 
 void bumpright() {
   
   Rs=(Cright+2*(valLR))*speedlimit; //right speed
   
   Case=2;
   Serial.print('<');
   Serial.print(Case);
   Serial.print('>');
   Serial.print('<');
   Serial.print(Rs);
   Serial.print('>');
}
  
//-------------------------------------------------------------------  

void loop1234(){
  
  val12 = analogRead(pot12)/4;
  val34 = analogRead(pot34)/4;

  
 Fs=(Cfwd-2*val12)*speedlimit; //forward speed
 Bs=(Crev+2*val12)*speedlimit;
 CWs=(Cfwd-2*(val34))*speedlimit;   //clockwise speed
 CCWs=(Crev+2*(val34))*speedlimit;


//forward
  if (val12 <= fwd) {
   Case=3;
   Serial.print('<');
   Serial.print(Case);
   Serial.print('>');
   Serial.print('<');
   Serial.print(Fs);
   Serial.print('>');
  }
 
//backwards
  else if (val12 >= rev) {
   Case=4;
   Serial.print('<');
   Serial.print(Case);
   Serial.print('>');
   Serial.print('<');
   Serial.print(Bs);
   Serial.print('>');
  }
  
  
 //loop to rotate CW/CCW
  else {
  
     if (val34 <= fwd) {
     Case = 5;
     Serial.print('<');
     Serial.print(Case);
     Serial.print('>');
     Serial.print('<');
     Serial.print(CWs);
     Serial.print('>');
      }
     else if (val34 >= rev) {
     Case=6;
     Serial.print('<');
     Serial.print(Case);
     Serial.print('>');
     Serial.print('<');
     Serial.print(CCWs);
     Serial.print('>');
      }
      
      
    else {
     off();
      }
    
  }
}


//-------------------------------------------------------------------  

 void off() {
   Case=7;
   Serial.print('<');
   Serial.print(Case);
   Serial.print('>');
   Serial.print('<');
   Serial.print(0);
   Serial.print('>');
 }
    
  
//-------------------------------------------------------------------  
  
  void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x7; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}
  
//-------------------------------------------------------------------

What if anything could go wrong with this?

You could forget what pin 9 is connected to.
Or pin 7...or just about any of those anonymous pins.

The commands are for testing right now, just turning LEDs on and off. The final code will have named pins. Are there any other concerns with the code?

As a Capstone Senior Design project my team is building an ROV......we are all Mechanical Engineers with no robotic experience making the programming difficult.

I find it hard to believe that your doing your culminating project with no experience in programming any kind of computer.

The final code will have named pins.

Why doesn't THIS code? Correcting bad habits later is much harder than learning good habits to start with. You've been told what you should do. The correct response is "I'll fix that right away", not "but that's not my problem".

Sorry was not trying to be rude or anything. I'll name the pins then re-post the code.

Capstone Design incorporates many disciplines, unfortunately my team has only Mechanical Engineers. We do have experience using MATLAB for mathematical/engineering problems. The projects are not provided by the school but by sponsors through the school. The sponsors give you the project scope and funding then you run with it. We did not have to use a micro controller, we could have used mechanical relays but the micro-controller is obviously superior. The Arduino makes this easier with lots of books and online help.

The point of the program is to use and engineering approach to develop a solution to a given problem. Some of the solutions may require, as is the case with this project, using knowledge outside of our discipline or seeking someone knowledgeable in said discipline, which is exactly what I am doing here.

Code with named output variables:

const char SOP = '<';
const char EOP = '>';

enum { Case, Speed };

int whichNumber = Case;

int  Casev, Speedv;
int M1A = 3;
int M1B = 4;
int M2A = 5;
int M2B = 6;
int MServ =11;



//-------------------------------------------------------------------


void setup ()
  { 
  Serial.begin (9600);
  pinMode (M1A, OUTPUT);
  pinMode (M1B, OUTPUT);
  pinMode (M2A, OUTPUT);
  pinMode (M2B, OUTPUT);
  pinMode (MServ, OUTPUT);

 
  } 

//------------------------------------------------------------------- 

  
void processNumber (int n)
  {
  int x = n;  
  
  switch (whichNumber)
    {
      
    case Case: 
      Casev = x;
      whichNumber = Speed;
      //Serial.print ("  Case = ");
      break;
      
    case Speed: 
      Speedv = x;
      whichNumber = Case;
      //Serial.print (" Speed = ");
      break;
    
  
    }
    //Serial.print(x);
  }  
  
  
 //------------------------------------------------------------------- 
  
void processInput ()
  {
  static float receivedNumber = 0;
  static boolean False = false;
  
  byte c = Serial.read ();
  
  switch (c)
    {
      
    case EOP:  
      if (False) 
        processNumber (- receivedNumber); 
      else
        processNumber (receivedNumber); 

    // fall through to start a new number
    case SOP: 
      receivedNumber = 0; 
      False = false;
      break;
      
    case '0' ... '9': 
      receivedNumber *= 10;             // receivedNumber = recievedNumber*10
      receivedNumber += c - '0';       //receivedNumber = recievedNumber + (c - '0')
      break;
      
    case '-':
      False = true;
      break;
      
    } 
  }  


//-------------------------------------------------------------------
  
void loop ()
  {
  if (Serial.available ())
  processInput ();
  int  var1 = Casev;
  int  var2 = Speedv;
    
    switch (var1)
    {
    //RIGHT  
    case 1:
    analogWrite(M1A,var2);
    
    
    digitalWrite(M1B, LOW);
    digitalWrite(M2A, LOW);
    digitalWrite(M2B, LOW);
 
    break;
    
    //LEFT
    case 2:
    
    analogWrite(M1A,var2);
    
    digitalWrite(M1B, HIGH);
    digitalWrite(M2A, LOW);
    digitalWrite(M2B, LOW);
    break;
    
    //FWD
    case 3:
    analogWrite(M1A,var2);
    
    
    digitalWrite(M1B, LOW);
    digitalWrite(M2A, HIGH);
    digitalWrite(M2B, LOW);
    break;
    
    //REV
    case 4:
    analogWrite(M1A,var2);
    
    
    digitalWrite(M1B, LOW);
    digitalWrite(M2A, LOW);
    digitalWrite(M2B, HIGH);
    break;
    
    //CW
    case 5:
   analogWrite(M1A,var2);
    
    
    digitalWrite(M1B, HIGH);
    digitalWrite(M2A, LOW);
    digitalWrite(M2B, HIGH);
    
    break;
    
    //CCW
    case 6:
    analogWrite(M1A,var2);
    
    
    digitalWrite(M1B, LOW);
    digitalWrite(M2A, HIGH);
    digitalWrite(M2B, HIGH);
    break;
    
    //SURFACE
    case 7:
    analogWrite(M1A,LOW);
    
    
    digitalWrite(M1B, LOW);
    digitalWrite(M2A, LOW);
    digitalWrite(M2B, LOW);
    break;
    
    //DIVE
    case 8:
   analogWrite(M1A,var2);
    
    
    digitalWrite(M1B, HIGH);
    digitalWrite(M2A, HIGH);
    digitalWrite(M2B, HIGH);
    break;
    
    //PITCH 
    case 9:
     analogWrite(M1A,HIGH);
    
    
    digitalWrite(M1B, LOW);
    digitalWrite(M2A, LOW);
    digitalWrite(M2B, HIGH);
    break; 
    
    //SERVO   
    case 10:
    digitalWrite (MServ,HIGH);
    
    
    //digitalWrite(3,LOW);
    //...digitalWrite(4, LOW);
    // digitalWrite(5, LOW);
    //digitalWrite(6, LOW);
    //digitalWrite(7, LOW);
    //digitalWrite(8, LOW);
    //digitalWrite(9, LOW);
    //digitalWrite(10, LOW);
    //digitalWrite(12, LOW);
    break;
    
    }
    
  } 
  //-------------------------------------------------------------------
void processNumber (int n)
  {
  int x = n;

Why the reassignment?

int M1A = 3;
int M1B = 4;
int M2A = 5;
int M2B = 6;

Are you planning on changing these pin assignments whilst the program is running?
If not, consider making them constants.

Create some functions, with meaningful names, like turnRight(), turnLeft(), dive(), rise(), etc. Call them in the appropriate place(s) in loop().

Which is easier to grasp:

    case 1:
    analogWrite(M1A,var2);
    
    
    digitalWrite(M1B, LOW);
    digitalWrite(M2A, LOW);
    digitalWrite(M2B, LOW);
 
    break;

or:

    case 1:
       turnRight();
       break;

The big advantage of functions is that you can debug them once. Comment out the whole loop() function. Create a new loop() function that does nothing but call turnRught(). Does the sub do what it is supposed to? If so, great. The function is working properly. If not, you can look at the logic of the function to see if there are errors, and you can look at the hardware. Is it connected to the right pins? If is powered correctly?

Divide and conquer. Don't try to do everything at once.

Thanks for the advice, when I have developed the final code I will post it. I'll clean it up and make logical names for what I want it to do. I have finals this week so it won't be until next week. It sounds like I am on the right track though. Thank you!

I've cleaned the code up using some of the above suggestions.

Here it is:

//-------------------------------------------------------------------

#include <Servo.h> 
Servo servo; 

//PINS
const int  M1A = 20; // M1---M4 ARE HORIZONTAL THRUSTERS
const int  M1B = 21;
const int  M2A = 22;
const int  M2B = 23;
const int  M3A = 24;
const int  M3B = 25;
const int  M4A = 26;
const int  M4B = 27;
const int  M5A = 28; // M5---M6 ARE VERTICAL THRUSTERS
const int  M5B = 29;
const int  M6A = 30;
const int  M6B = 31;
const int  M12 = 44; // M1 and M2 PWM
const int  M34 = 45; // M3 and M4 PWM
const int  M56 = 46; // M5 and M6 PWM
const int  servopin = 2;

//INCOMING DATA
const char SOP = '<';
const char EOP = '>';
enum { 
  Case, Speed };


//VARIABLES
int whichNumber = Case;
int Casev, Speedv;
int pwmright;            //1
int pwmleft;             //2
int pwmfwd;              //3
int pwmrev;              //4
int pwmcw;               //5
int pwmccw;              //6
int pwmsurface;          //7
int pwmdive;             //8
int pwmpitch;            //9
int valservo;            //10


//-------------------------------------------------------------------


void setup ()
{ 
  Serial.begin (9600);
  pinMode (M1A, OUTPUT);
  pinMode (M1B, OUTPUT);
  pinMode (M2A, OUTPUT);
  pinMode (M2B, OUTPUT);
  pinMode (M3A, OUTPUT);
  pinMode (M3B, OUTPUT);
  pinMode (M4A, OUTPUT);
  pinMode (M4B, OUTPUT);
  pinMode (M5A, OUTPUT);
  pinMode (M5B, OUTPUT);
  pinMode (M6A, OUTPUT);
  pinMode (M6B, OUTPUT);
  pinMode (M12, OUTPUT);
  pinMode (M34, OUTPUT);
  pinMode (M56, OUTPUT);
  servo.attach(servopin);

} 

//------------------------------------------------------------------- 


void processNumber (int x)
{

  switch (whichNumber)
  {

  case Case: 
    Casev = x;
    whichNumber = Speed;
    break;

  case Speed: 
    Speedv = x;
    whichNumber = Case;
    break;


  }
}  


//------------------------------------------------------------------- 

void processInput ()
{
  static float receivedNumber = 0;
  static boolean False = false;
  byte c = Serial.read ();

  switch (c)
  {

  case EOP:  
    if (False) 
      processNumber (- receivedNumber); 
    else
      processNumber (receivedNumber); 

    // fall through to start a new number
  case SOP: 
    receivedNumber = 0; 
    False = false;
    break;

  case '0' ... '9': 
    receivedNumber *= 10;             // receivedNumber = recievedNumber*10
    receivedNumber += c - '0';      //receivedNumber = recievedNumber + (c - '0')
    break;

  case '-':
    False = true;
    break;

  } 
}  


//-------------------------------------------------------------------

void loop ()
{
  
  Serial.print(127);
  if (Serial.available ())
  
  processInput ();
  
  
  int  var1 = Casev;
  int  var2 = Speedv;

  switch (var1)
  {

    //RIGHT  
  case 1:
    pwmright = var2;
    moveright();
    break;

    //LEFT
  case 2:
    pwmleft = var2;
    moveleft();
    break;

    //FWD
  case 3:
    pwmfwd = var2;
    fwd();
    break;

    //REV
  case 4:
    pwmrev = var2;
    rev();
    break;

    //CW
  case 5:
    pwmcw = var2;
    cw();
    break;

    //CCW
  case 6:
    pwmccw = var2;
    ccw();
    break;

    //SURFACE
  case 7:
    pwmsurface = var2;
    surface();
    break;

    //DIVE
  case 8:
    pwmdive = var2;
    dive();
    break;

    //PITCH 
  case 9:
    pwmpitch = var2;
    pitch();
    break; 

    //SERVO   
  case 10:
    valservo = var2;            
    claw();    
    break;

  }

} 
//-------------------------------------------------------------------1 

void moveright()
{
}

//------------------------------------------------------------------- 2

void moveleft() 
{
}

//------------------------------------------------------------------- 3

void fwd()
{
}

//------------------------------------------------------------------- 4

void rev()
{
}

//------------------------------------------------------------------- 5

void cw()
{
}

//------------------------------------------------------------------- 6

void ccw()
{
}

//------------------------------------------------------------------- 7

void surface()
{
}

//------------------------------------------------------------------- 8 

void dive()
{
}

//------------------------------------------------------------------- 9

void pitch()
{
}

//------------------------------------------------------------------- 10

void claw()
{

  valservo = map(valservo, 0, 255, 0, 179);     // scale it to use it with the servo (value between 0 and 180) 
  servo.write(valservo);                  // sets the servo position according to the scaled value 
}


//-------------------------------------------------------------------

Data will be transmitted over 50' of wire using RS-232, how reliable can I expect this to be if the data transmission line is ran next to the power line of the ROV which will carry 20 amps? Also, would this code work using RS 485 communications?

Am I missing anything obvious here?

Also, would this code work using RS 485 communications?

RS-232, RS-485, makes no difference to your code if you use 485 in full duplex mode. Do you have 2 extra wires?


Rob

Should have 3 unused twisted pairs

You can run the rs232 type communication over cat3 four conductor phone wire (tx, rx, ground, and power/spare).

If I wanted to go the full duplex RS 485 route, would this require 4 MAXRS485 convertors? Basically keeping one in transmit mode and one in receive mode on both sides of the CAT5 cable at all times and leaving the code as is?

You need a receiver and transmitter at each end, but these come in a single chip so that's one chip at each end. Same as RS-232 in that regard but 2x the number of wires required.

would this require 4 MAXRS485 convertors?

Yes, but you wouldn't use that chip, there are plenty around that are for full duplex, eg LT1791, ISL31483 or my favourite the LTC490, duplex in an 8-pin pack.


Rob