Problem receiving bytes from VB.NET

Hi everyone!

I’m designing a particular project in which serial communication in very important.

I try to explain what the system does in a few words: the VB.NET program sends to Arduino a letter just to be recognized, then Arduino sends some data from sensors, the VB.NET program elaborates these data and sends Arduino two bytes. These two bytes represent the logic states that have to be written to 16 digital pins (one bit for each pin).

Now, Arduino recognizes the letter sent from the computer, the program receives data from Arduino correctly and creates the final two bytes perfectly, but here comes the problem!

Arduino receives the two bytes (I think), uses some bit masks and tries to write the obtained values to the digital pins, but these digital pins behave in a wrong way and I don’t understand how they work!

Here is the VB.NET code for the specific part:

Dev16To9 = Dev16To9Array(7) * 128 + Dev16To9Array(6) * 64 + Dev16To9Array(5) * 32 + Dev16To9Array(4) * 16 + Dev16To9Array(3) * 8 + Dev16To9Array(2) * 4 + Dev16To9Array(1) * 2 + Dev16To9Array(0)
        Dev8To1 = Dev8To1Array(7) * 128 + Dev8To1Array(6) * 64 + Dev8To1Array(5) * 32 + Dev8To1Array(4) * 16 + Dev8To1Array(3) * 8 + Dev8To1Array(2) * 4 + Dev8To1Array(1) * 2 + Dev8To1Array(0)
        SerialPort1.Open()
        SerialPort1.Write(Dev16To9)
        SerialPort1.Write(Dev8To1)
        Label4.Text = Dev8To1
        SerialPort1.Close()

And this is the code for Arduino:

#include <Wire.h>

// PINS
// Current Sensors
const unsigned int PanelCS = 0;
const unsigned int ToEnelCS = 1;
const unsigned int RequiredCS = 2;
const unsigned int FromEnelToDevCS = 3;
const unsigned int FromEnelToBatteryCS = 4;

// Voltage dividers
const unsigned int PanelVD = 5;
const unsigned int BatteryVD = 6;

// Smart devices
const unsigned int Dev1 = 22;
const unsigned int Dev2 = 23;
const unsigned int Dev3 = 24;
const unsigned int Dev4 = 25;
const unsigned int Dev5 = 26;
const unsigned int Dev6 = 27;
const unsigned int Dev7 = 28;
const unsigned int Dev8 = 29;
const unsigned int Dev9 = 30;
const unsigned int Dev10 = 31;
const unsigned int Dev11 = 32;
const unsigned int Dev12 = 33;
const unsigned int Dev13 = 34;
const unsigned int Dev14 = 35;
const unsigned int Dev15 = 36;
const unsigned int Dev16 = 37;

// Variables
// Currents
int PanelCurrent;
int ToEnelCurrent;
int RequiredCurrent;
int FromEnelToDevCurrent;
int FromEnelToBatteryCurrent;
// Voltages
int PanelVoltage;
int BatteryVoltage;
// Powers
byte ProducedPower;
byte ConsumedPower;
int BoughtPower;
int SoldPower;
// Panel angle
byte PanelAngle;
// Communication Start Byte
byte CodeA;
// Bytes from PC
byte BytesFromPc[2];


void setup(){
  pinMode(Dev1,OUTPUT);
  pinMode(Dev2,OUTPUT);
  pinMode(Dev3,OUTPUT);
  pinMode(Dev4,OUTPUT);
  pinMode(Dev5,OUTPUT);
  pinMode(Dev6,OUTPUT);
  pinMode(Dev7,OUTPUT);
  pinMode(Dev8,OUTPUT);
  pinMode(Dev9,OUTPUT);
  pinMode(Dev10,OUTPUT);
  pinMode(Dev11,OUTPUT);
  pinMode(Dev12,OUTPUT);
  pinMode(Dev13,OUTPUT);
  pinMode(Dev14,OUTPUT);
  pinMode(Dev15,OUTPUT);
  pinMode(Dev16,OUTPUT);
  
  Serial.begin(9600);
  Wire.begin();
}

void loop(){

  ProducedPower = 1;
  ConsumedPower = 2;
  BatteryVoltage = 3;
  
  //------------------------------------------------------------- 
  
  Wire.requestFrom(2, 1);    
  while(Wire.available()){
   PanelAngle = Wire.read();
  }
  
  if(Serial.available())   CodeA = Serial.read();
    
    if(CodeA==0x41){
      delay(50);
      Serial.write(ProducedPower);
      Serial.write(ConsumedPower);
      Serial.write(BatteryVoltage);
      Serial.write(PanelAngle);
      
      if(Serial.available()){
        for(int i=0; i<2; i++){
          BytesFromPc[i] = Serial.read();
        }   
      }
      
      
      digitalWrite(Dev1, BytesFromPc[1] & 1);
      digitalWrite(Dev2, (BytesFromPc[1] >> 1)& 1);
      digitalWrite(Dev3, (BytesFromPc[1] >> 2)& 1);
      digitalWrite(Dev4, (BytesFromPc[1] >> 3)& 1);
      digitalWrite(Dev5, (BytesFromPc[1] >> 4)& 1);
      digitalWrite(Dev6, (BytesFromPc[1] >> 5)& 1);
      digitalWrite(Dev7, (BytesFromPc[1] >> 6)& 1);
      digitalWrite(Dev8, (BytesFromPc[1] >> 7)& 1);
      digitalWrite(Dev9, BytesFromPc[0] & 1);
      digitalWrite(Dev10, (BytesFromPc[0] >> 1)& 1);
      digitalWrite(Dev11, (BytesFromPc[0] >> 2)& 1);
      digitalWrite(Dev12, (BytesFromPc[0] >> 3)& 1);
      digitalWrite(Dev13, (BytesFromPc[0] >> 4)& 1);
      digitalWrite(Dev14, (BytesFromPc[0] >> 5)& 1);
      digitalWrite(Dev15, (BytesFromPc[0] >> 6)& 1);
      digitalWrite(Dev16, (BytesFromPc[0] >> 7)& 1);
    }
    
}

This evening I’ll try to understand what Arduino exactly receives, but in the meantime I’d like to get some advice.

Thanks a lot!

First problem, I suspect, is that your VB code opens and closes the serial port. When it opens the port the Arduino will reset and your VB code needs to wait for that to complete before sending anything. Then it should keep the port open until you are completely finished with the Arduino.

Your receiving code is not at all robust. If it works it is just by good luck.

The examples in serial input basics show a few simple ways to reliably recieve data.

It may be wise to require the VB code to wait for a request from the Arduino before it sends data.

This Python demo may give you some ideas. The concepts can apply in any language.

Thanks for the advice! I'll try to make the code more robust.

I tried to make the codes more robust, but I had problems. I made Arduino send some characters to confirm that it has received the required data, but the computer program stopped working and Arduino stopped both sending and receiving data.

I've modified the starting code; it isn't robust yet (the code is practically the same that I published, but at the end of every cycle Arduino sends the computer the two received bytes. On the VB.NET program, I created four labels which show the bytes built by the computer and the bytes from Arduino, in order to see the differences.

At first the bytes are equal, but when the program changes the two bytes and sends them to Arduino, the two return bytes from Arduino remain the same.

More practically, at first the two bytes values are 255 in decimal, but when I change them to other values the two bytes from Arduino (which should be equal to the bytes sent by the computer) remain at 255. How could I solve this problem?

Thanks a lot! If you need more information tell me.

marcopolver: If you need more information tell me.

Yes. Your code.

...R

Here is the Arduino code:

#include <Wire.h>

// PINS
// Current Sensors
const unsigned int PanelCS = 0;
const unsigned int ToEnelCS = 1;
const unsigned int RequiredCS = 2;
const unsigned int FromEnelToDevCS = 3;
const unsigned int FromEnelToBatteryCS = 4;

// Voltage dividers
const unsigned int PanelVD = 5;
const unsigned int BatteryVD = 6;

// Smart devices
const unsigned int Dev1 = 22;
const unsigned int Dev2 = 23;
const unsigned int Dev3 = 24;
const unsigned int Dev4 = 25;
const unsigned int Dev5 = 26;
const unsigned int Dev6 = 27;
const unsigned int Dev7 = 28;
const unsigned int Dev8 = 29;
const unsigned int Dev9 = 30;
const unsigned int Dev10 = 31;
const unsigned int Dev11 = 32;
const unsigned int Dev12 = 33;
const unsigned int Dev13 = 34;
const unsigned int Dev14 = 35;
const unsigned int Dev15 = 36;
const unsigned int Dev16 = 37;

// Variables
// Currents
int PanelCurrent;
int ToEnelCurrent;
int RequiredCurrent;
int FromEnelToDevCurrent;
int FromEnelToBatteryCurrent;
// Voltages
int PanelVoltage;
int BatteryVoltage;
// Powers
byte ProducedPower;
byte ConsumedPower;
int BoughtPower;
int SoldPower;
// Panel angle
byte PanelAngle;
// Bytes from PC
byte BytesFromPc[2];


void setup(){
  pinMode(Dev1,OUTPUT);
  pinMode(Dev2,OUTPUT);
  pinMode(Dev3,OUTPUT);
  pinMode(Dev4,OUTPUT);
  pinMode(Dev5,OUTPUT);
  pinMode(Dev6,OUTPUT);
  pinMode(Dev7,OUTPUT);
  pinMode(Dev8,OUTPUT);
  pinMode(Dev9,OUTPUT);
  pinMode(Dev10,OUTPUT);
  pinMode(Dev11,OUTPUT);
  pinMode(Dev12,OUTPUT);
  pinMode(Dev13,OUTPUT);
  pinMode(Dev14,OUTPUT);
  pinMode(Dev15,OUTPUT);
  pinMode(Dev16,OUTPUT);
  
  Serial.begin(9600);
  Wire.begin();
}

void loop(){

  ProducedPower = 1;
  ConsumedPower = 2;
  BatteryVoltage = 3;
  
  //------------------------------------------------------------- 
  
  Wire.requestFrom(2, 1);    
  while(Wire.available()){
   PanelAngle = Wire.read();
  }
  
  if(Serial.available()){    
    if(Serial.read()==0x41){
      delay(50); //Is it useful?
      Serial.write(ProducedPower);
      Serial.write(ConsumedPower);
      Serial.write(BatteryVoltage);
      Serial.write(PanelAngle);
 
        for(int i=0; i<2; i++){
          BytesFromPc[i] = Serial.read(); 
        }
        for(int j=0; j<2; j++){
          Serial.write(BytesFromPc[j]);
        }
      }
    }
  
                                                      
      digitalWrite(Dev1, bitRead(BytesFromPc[1],0));
      digitalWrite(Dev2, bitRead(BytesFromPc[1],1));
      digitalWrite(Dev3, bitRead(BytesFromPc[1],2));
      digitalWrite(Dev4, bitRead(BytesFromPc[1],3));
      digitalWrite(Dev5, bitRead(BytesFromPc[1],4));
      digitalWrite(Dev6, bitRead(BytesFromPc[1],5));
      digitalWrite(Dev7, bitRead(BytesFromPc[1],6));
      digitalWrite(Dev8, bitRead(BytesFromPc[1],7));
      digitalWrite(Dev9, bitRead(BytesFromPc[0],0));
      digitalWrite(Dev10, bitRead(BytesFromPc[0],1));
      digitalWrite(Dev11, bitRead(BytesFromPc[0],2));
      digitalWrite(Dev12, bitRead(BytesFromPc[0],3));
      digitalWrite(Dev13, bitRead(BytesFromPc[0],4));
      digitalWrite(Dev14, bitRead(BytesFromPc[0],5));
      digitalWrite(Dev15, bitRead(BytesFromPc[0],6));
      digitalWrite(Dev16, bitRead(BytesFromPc[0],7));
    
}

And here is the VB.NET code:

        'Open serial communication and send a starting code
        SerialPort1.Open()
        SerialPort1.Write("A")

        'Read bytes form Arduino Mega
        ProducedPower = SerialPort1.ReadByte
        ConsumedPower = SerialPort1.ReadByte
        AccumulatorCharge = SerialPort1.ReadByte
        PanelAngle = SerialPort1.ReadByte

        [...]

        SerialPort1.Write(Dev16To9)
        SerialPort1.Write(Dev8To1)

        Label6.Text = SerialPort1.ReadByte()
        Label4.Text = Dev16To9
        Label8.Text = SerialPort1.ReadByte()
        Label10.Text = Dev8To1

        SerialPort1.Close()

Thanks again!

On the basis of the code in Reply #5 you seem to have taken no notice of any of my comments and examples in Reply #1.

I am not going to repeat myself.

If there is anything in my Reply that you did not understand, please tell me.

...R

I said that I took notice of your comments; I tried to make the computer and Arduino wait a confirmation code to start sending other data but, as I said, everything stopped working.

I will try and retry to make my code more robust and your examples will be really useful, but now the problem is different; I know that every byte sent form Arduino arrives perfectly to the computer and that the two bytes sent from the computer to Arduino are correct, but it's like Arduino can't update their values even if it receives everything.

marcopolver: I tried to make the computer and Arduino wait a confirmation code to start sending other data

I saw no evidence of that in the code in Reply #5. It still has all of the shortcomings that I pointed out in Reply #1 The reason I gave you links in that Reply is because the code in them works.

...R

Now I'm trying to make a good codes for both VB.NET and Arduino; once finished I'll test them and I'll post them here.

Here are the new codes, I think they are pretty better!

Now it seems like Arduino reads the two bytes in a wrong way, because it returns 53 or 50 instead of 255.

Arduino code:

#include <Wire.h>

// PINS
// Current Sensors
const unsigned int PanelCS = 0;
const unsigned int ToEnelCS = 1;
const unsigned int RequiredCS = 2;
const unsigned int FromEnelToDevCS = 3;
const unsigned int FromEnelToBatteryCS = 4;

// Voltage dividers
const unsigned int PanelVD = 5;
const unsigned int BatteryVD = 6;

// Smart devices
const unsigned int Dev1 = 22;
const unsigned int Dev2 = 23;
const unsigned int Dev3 = 24;
const unsigned int Dev4 = 25;
const unsigned int Dev5 = 26;
const unsigned int Dev6 = 27;
const unsigned int Dev7 = 28;
const unsigned int Dev8 = 29;
const unsigned int Dev9 = 30;
const unsigned int Dev10 = 31;
const unsigned int Dev11 = 32;
const unsigned int Dev12 = 33;
const unsigned int Dev13 = 34;
const unsigned int Dev14 = 35;
const unsigned int Dev15 = 36;
const unsigned int Dev16 = 37;

// Variables
// Currents
int PanelCurrent;
int ToEnelCurrent;
int RequiredCurrent;
int FromEnelToDevCurrent;
int FromEnelToBatteryCurrent;
// Voltages
int PanelVoltage;
int BatteryVoltage;
// Powers
byte ProducedPower;
byte ConsumedPower;
int BoughtPower;
int SoldPower;
// Panel angle
byte PanelAngle;
// Bytes from PC
byte BytesFromPc[2];

// Boolean variables for functions
boolean StartingCode;
boolean ComputerIsReady;


void setup(){
  pinMode(Dev1,OUTPUT);
  pinMode(Dev2,OUTPUT);
  pinMode(Dev3,OUTPUT);
  pinMode(Dev4,OUTPUT);
  pinMode(Dev5,OUTPUT);
  pinMode(Dev6,OUTPUT);
  pinMode(Dev7,OUTPUT);
  pinMode(Dev8,OUTPUT);
  pinMode(Dev9,OUTPUT);
  pinMode(Dev10,OUTPUT);
  pinMode(Dev11,OUTPUT);
  pinMode(Dev12,OUTPUT);
  pinMode(Dev13,OUTPUT);
  pinMode(Dev14,OUTPUT);
  pinMode(Dev15,OUTPUT);
  pinMode(Dev16,OUTPUT);
  
  Serial.begin(9600);
  Wire.begin();
}

void loop(){
  GetPanelAngle();
  ReadAnalogPins();
  ReadStartingCode();
  SendMeasuredValues();
  CheckComputerStatus();
  ReadyToReceive();
  ReceiveBytes();
  SetPins();
  SendEndCode();
}

// Function that reads the starting code "A"
void ReadStartingCode(){
  while(Serial.available()!=1);
    if(Serial.read()==0x41) StartingCode = true;
    else StartingCode = false;   
}


// Function that reads the PanelAngle byte from the second Arduino through I2C
void GetPanelAngle(){
  Wire.requestFrom(2, 1);    
  while(Wire.available()){
   PanelAngle = Wire.read();
  }  
}


// Function that reads currents and voltages values (NOW JUST EMULATED)
void ReadAnalogPins(){
  ProducedPower = 1;
  ConsumedPower = 2;
  BatteryVoltage = 3;
}

// Function that sends the measured values to the computer
void SendMeasuredValues(){
  if(StartingCode==true){
    Serial.write(ProducedPower);
    Serial.write(ConsumedPower);
    Serial.write(BatteryVoltage);
    Serial.write(PanelAngle);
  }
}


// Function that checks if the computer is ready to send the two bytes
void CheckComputerStatus(){
  while(Serial.available()!=1);
    if(Serial.read()==0x42) ComputerIsReady = true;
    else ComputerIsReady = false;   
}


// Function with which Arduino tells the computer it's ready to receive data
void ReadyToReceive(){
  if(ComputerIsReady==true) Serial.write("C");
}


// Function that reads the bytes from the computer
void ReceiveBytes(){
  while(Serial.available()!=2);
  for(int i=0; i<2; i++){
    BytesFromPc[i] = Serial.read(); 
  }
}


// Function that sets the digital pins according to the received bytes
void SetPins(){
  digitalWrite(Dev1, bitRead(BytesFromPc[1],0));
  digitalWrite(Dev2, bitRead(BytesFromPc[1],1));
  digitalWrite(Dev3, bitRead(BytesFromPc[1],2));
  digitalWrite(Dev4, bitRead(BytesFromPc[1],3));
  digitalWrite(Dev5, bitRead(BytesFromPc[1],4));
  digitalWrite(Dev6, bitRead(BytesFromPc[1],5));
  digitalWrite(Dev7, bitRead(BytesFromPc[1],6));
  digitalWrite(Dev8, bitRead(BytesFromPc[1],7));
  digitalWrite(Dev9, bitRead(BytesFromPc[0],0));
  digitalWrite(Dev10, bitRead(BytesFromPc[0],1));
  digitalWrite(Dev11, bitRead(BytesFromPc[0],2));
  digitalWrite(Dev12, bitRead(BytesFromPc[0],3));
  digitalWrite(Dev13, bitRead(BytesFromPc[0],4));
  digitalWrite(Dev14, bitRead(BytesFromPc[0],5));
  digitalWrite(Dev15, bitRead(BytesFromPc[0],6));
  digitalWrite(Dev16, bitRead(BytesFromPc[0],7));
}


// Function that sends the end code
void SendEndCode(){
  //Serial.write("D");
  Serial.write(BytesFromPc[1]);   // Now for debugging it sends one of the two received bytes
}

VB.NET code:

  Public Class Home  
    Public Sub SendStartingCode()
        'Open serial communication and send a starting code
        If CommunicationEnded = True Then
            SerialPort1.Open()
            SerialPort1.Write("A")
            CommunicationEnded = False
        End If
    End Sub

    Public Sub ReadValues()
        While SerialPort1.BytesToRead <> 4
        End While
        'Read bytes form Arduino Mega
        ProducedPower = SerialPort1.ReadByte
        ConsumedPower = SerialPort1.ReadByte
        AccumulatorCharge = SerialPort1.ReadByte
        PanelAngle = SerialPort1.ReadByte

        'Write new values to labels
        ProducedPowerLabel.Text = ProducedPower
        ConsumedPowerLabel.Text = ConsumedPower
        AccuChargeLabel.Text = AccumulatorCharge
        PanelAngleLabel.Text = CStr(PanelAngle) + "°"
    End Sub

    Public Sub CheckIfSmartDevNeeded()
        [...]
    End Sub

    Public Sub BuildBytes()
        [...]
    End Sub

    Public Sub ComputerIsReady()
        SerialPort1.Write("B")
    End Sub

    Public Sub ArduinoIsReady()
        While SerialPort1.BytesToRead <> 1
        End While
        If SerialPort1.ReadByte = 67 Then   '67 is the decimal value of "C"
            ArduinoReadyToReceive = True
        Else : ArduinoReadyToReceive = False
        End If
    End Sub

    Public Sub SendBytes()
        If ArduinoReadyToReceive = True Then
            SerialPort1.Write(Dev16To9)
            SerialPort1.Write(Dev8To1)
        End If
        
    End Sub

    Public Sub EndCommunication()
        While SerialPort1.BytesToRead <> 1
        End While
        'If SerialPort1.ReadByte = 68 Then
        Label4.Text = SerialPort1.ReadByte
        SerialPort1.Close()
        CommunicationEnded = True
        'End If
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        SendStartingCode()
        ReadValues()
        CheckIfSmartDevNeeded()
        BuildBytes()
        ComputerIsReady()
        ArduinoIsReady()
        SendBytes()
        EndCommunication()
    End Sub
End Class

It looks to me as if you have the logic back to front

Open serial communication and send a starting code

When the PC opens the serial port it should LISTEN, not talk. If you look at my Pyhton demo you will see how the Arduino sends "Arduino Ready" from setup().

I suggest you use the Arduino code in my Python demo and write a VB program that does the same job as my Python program. That way you are testing your VB code against Arduino code that you know works properly.

When you have that working it will be easy to alter things for your own project.


And, by the way this is silly

while(Serial.available()!=2);

It will work for any number (0,1, 45000 etc) except 2

...R

Thanks again, I'll try to do what you said.

About the instruction that you mentioned, why should it be silly? That's what I need: the system has to continue only when there are two bytes to read, not less and not more.

marcopolver: About the instruction that you mentioned, why should it be silly? That's what I need: the system has to continue only when there are two bytes to read, not less and not more.

Look at your code carefully. It does the exact opposite of what you want.

Just in case you don't know the ! operater means "NOT"

...R

I accept your advice, but don't treat me like a fool.

After that while there's a ";", so it waits until there are two bytes...

But now everything works, with Arduino that listens first and that silly "while(Serial.available()!=2);"... The problem was that the computer sent the two numbers as strings, so every cipher occuped a byte.

Looking at your examples I can say you can program, but remember that in programming every problem can be solved in different ways, so if my method is different from yours it doesn't mean that it can't work properly.

Bye

marcopolver: Looking at your examples I can say you can program, but remember that in programming every problem can be solved in different ways, so if my method is different from yours it doesn't mean that it can't work properly.

I am very much aware of the fact that there are as many solutions as there are programmers.

But I only have time to work on one solution.

I don't treat anyone on the forum as a fool. But I do expect programmers to think.

...R

Nice words, in fact I consider myself a person who thinks. I beleave you didn't want to treat me as a fool, but you did.

After this, thanks again for your examples and your advice, bye.