Control two devices via serial port - conflict between variables

Hello,

I am a beginner with microcontroller programming and I am sorry if my problem is very trivial. But I hope that someone can help me to move my work forward, because I got stuck…

I want to control a bipolar transistor with arduino, but setting it high and low via messages received on a serial port. That is easy and works great without issues.

The problem is, that in the arduino sketch, which I must use for controlling other device, there is already one variable reading bytes from a serial port. And when both of them (variable for the transistor and for the other device) are active, then only the second one (for the other device) reads data from serial…
Do you know why it is like this and how can I “choose” which variable will be reading the data?

For controlling the transistor I just send two different letters, let’s say c and d for low and high.
For controlling the device there are byte packages send in order to control voltage/current.
And this is not good if my device receives “dumb” messages like “c” or “d”, because there could be a problem with current or voltage which are set…

Here is my code for the transistor:

void controlBipolar()
{
while (Serial.available()>0){

Serial.begin(BaudRate);
incomingSharp=Serial.read();
Serial.println(incomingSharp);

switch(incomingSharp)
{
case ‘d’:
digitalWrite(bipolar,HIGH);
break;
case ‘c’:
digitalWrite(bipolar,LOW);
break;
}
}
}

And here the other variable, which when active, disactivates the other one:

void serialMonitor()
{
if (Serial.available() > 0)
{
enableWatchdog();
unsigned long timeOut = 0;
commandByte = Serial.read();
Serial.println("Command byte: ");
Serial.println(commandByte);
for (byte i = 0; i < ((commandByte & 0b01100000) >> 5); i++)
{

I will be very thankful if someone could tell me, where the problem is.

Variables don’t read bytes, code does.

It would help if you posted your code (in code tags this time please).

It sounds like you need to define a simple serial protocol, and only read the serial line in one place.

It seems to work now.

A simple if-statement calls one of these two functions, depending on what message is being read on a serial port.

I only don't understand why I must send miminum two characters (for example "dd" or "cc") to the serial port. Sending one letter doesn't work. And if I send the message from C#, then I even need to send three same characters. It's not a problem, but I was just wondering, why it is like that..

I only don't understand why I must send miminum two characters (

No, I don't either, because I can't see your code

Sorry. This is the part of the code for reading serial:

#define BaudRate 115200

char serialRead;
char incomingSharp;
byte commandByte;
byte serialData[7];

void setup()
{...

Serial.begin(BaudRate);

...}

void loop(){
...

chooseVar();

...}

void chooseVar(){
  while(Serial.available()>0){
  serialRead=(char)Serial.read();
  Serial.println("I am in void chooseVar: ");      // Only to control if the function is called
  Serial.println(serialRead);

  if(serialRead=='d' || serialRead=='c'){
    controlBipolar();
  }
  else {
    serialMonitor();
  }
}
}

void controlBipolar()
{
  Serial.flush();
  if (Serial.available()>0){
  
  incomingSharp=Serial.read();
  Serial.println("I am in void controlBipolar: ");     // Only to control if the function is called
  Serial.println(incomingSharp);
 
   switch(incomingSharp)
  {
    case 'd':
    digitalWrite(bipolar,HIGH);
    break;
    case 'c':
    digitalWrite(bipolar,LOW);
    break;
  } 
  }
}

void serialMonitor()
{
  if (Serial.available() > 0)  
  {
    enableWatchdog();
    unsigned long timeOut = 0;

    commandByte = Serial.read();
    Serial.println("I am in void serialMonitor: ");
    Serial.println(commandByte);
    for (byte i = 0; i < ((commandByte & 0b01100000) >> 5); i++)
    {
      while(Serial.available() == 0) 
      {
        delayMicroseconds(4);
        timeOut++; // watchdog counter
        if (timeOut > SERIAL_TIMEOUT)
        {
          break;
        }
      } // waits for data
      if (timeOut > SERIAL_TIMEOUT)
      {
        break;
      }
      serialData[i] = Serial.read(); // assigns data
    }  


    Serial.flush();

    if (timeOut <= SERIAL_TIMEOUT)
    {      
      if (commandByte & 0b10000000)
      {        
        // set command (write to Arduino)
        setLoad(commandByte & 0b00011111);
        sendMessage(0);
      }
      else
      {
        sendMessage(commandByte & 0b00011111);
      }
    }   
  }

  
}

jenny_co:
Sorry. This is the part of the code for reading serial:

Post your complete program please - or at least post a complete program that illustrates the problem.

You may find some useful stuff in Serial Input Basics - simple reliable ways to receive data.

...R

  Serial.println("I am in void chooseVar: ");I think you meant  Serial.println(F("I am in function chooseVar: "));

The sketch is much too long and I exceed the maximum allowed length…
I tried to reduce it to only that part, which reads serial data.

#define AVR 

#include <Wire.h>
#ifdef AVR
  #define I2C Wire
#endif
#ifdef ARM
  #define I2C Wire1
#endif
#include <math.h>

#define BaudRate 115200

// <Pins>
const int bipolar=13;
// </Pins>

// <DAC>
//  commands
const byte DAC_ADDRESS = 0b1001100; // I2C address of DAC (A0 tied to GND)
const byte DAC_WRITE_DAC_AND_INPUT_REGISTERS = 0b00110000; // write to DAC memory 
// </DAC>

// <Serial>
byte commandByte; // first byte of TX/RX data
byte serialData[7]; // data TX/RX
const unsigned long SERIAL_TIMEOUT = 1275000; // approx. 5.1 seconds for receiving all the data
// </Serial>

// <Watchdog>
unsigned int watchdogCounter = 0;
const unsigned int WATCHDOG_TIMEOUT = 2000;
byte isWatchdogEnabled = 0;
// </Watchdog>

// <Voltmeter>
// serial communication
byte remoteStatus = 0; // 0 = local, 1 = remote
const byte REMOTE_ID = 29;
// </Voltmeter>

// <Ammeter>
unsigned int current = 0;
//  calibration constants
const unsigned int IADC_SLOPE = 4535;
const char IADC_INTERCEPT = 13;
// </Ammeter>

// <Status>
const byte READY = 0;
// others stop device automatically
const byte CURRENT_OVERLOAD = 1; // both ADC and DAC
const byte VOLTAGE_OVERLOAD = 2; // both ADC and DAC
const byte POWER_OVERLOAD = 4;
const byte OVERHEAT = 8;
// current status
byte loadStatus = READY;
// </Status>

// <Operating Mode>
const byte MODE_CC = 0;
const byte MODE_CV = 1;
const byte MODE_CP = 2;
const byte MODE_CR = 3;
const byte MODE_CVIP = 4;
byte mode = MODE_CC;
// </Operating Mode>

char serialRead;
char incomingSharp;   //Bipolar, Ola


void setup()
{      
  delay(200); // for safety
  Serial.begin(BaudRate);
  
  #ifdef AVR
    analogReference(EXTERNAL);
  #endif
  #ifdef ARM
    ADC->ADC_MR |= (0b1111 << 24); // set maximum ADC tracking time
    analogReadResolution(12);
  #endif
  pinMode(bipolar, OUTPUT);
 
  I2C.begin();
  
  // system watchdog  
  #ifdef AVR
    cli();
    asm("WDR");
    WDTCSR |= (1 << WDCE) | (1 << WDE);
    WDTCSR = (1 << WDE) | (1 << WDP3) | (1 << WDP0);
    sei();  
  #endif
}

void loop() {
  // <Watchdog>
  #ifdef AVR
    asm("WDR"); // system watchdog reset
  #endif
  watchdogCounter++;
  if ((watchdogCounter > WATCHDOG_TIMEOUT) && (isWatchdogEnabled == 1))
  {
    isWatchdogEnabled = 0;
    Serial.end();
    Serial.begin(BaudRate);
    loadStatus = READY;
  }
  // </Watchdog>
    
  chooseVar();
  }

void chooseVar(){
  while(Serial.available()>0){
  serialRead=(char)Serial.read();
  Serial.println(F("I am in chooseVar: "));  
  Serial.println(serialRead);
  if(serialRead=='d' || serialRead=='c'){
    controlBipolar();
  }
  else {
    serialMonitor();
  }
}
}

void controlBipolar()
{
  Serial.flush();
  if (Serial.available()>0){
  
  incomingSharp=Serial.read();
  Serial.println(F("I am in controlBipolar: "));
  Serial.println(incomingSharp);
 
   switch(incomingSharp)
  {
    case 'd':
    digitalWrite(bipolar,HIGH);
    break;
    case 'c':
    digitalWrite(bipolar,LOW);
    break;
  } 
  }
}

void serialMonitor()
{
  if (Serial.available() > 0)  
  {
    enableWatchdog();
    unsigned long timeOut = 0;

    commandByte = Serial.read();
    Serial.println(F("I am in serialMonitor: "));
    Serial.println(commandByte);
    for (byte i = 0; i < ((commandByte & 0b01100000) >> 5); i++)
    {
      while(Serial.available() == 0) 
      {
        delayMicroseconds(4);
        timeOut++; // watchdog counter
        if (timeOut > SERIAL_TIMEOUT)
        {
          break;
        }
      } // waits for data
      if (timeOut > SERIAL_TIMEOUT)
      {
        break;
      }
      serialData[i] = Serial.read(); // assigns data
    }  

    Serial.flush();

    if (timeOut <= SERIAL_TIMEOUT)
    {      
      if (commandByte & 0b10000000)
      {        
        // set command (write to Arduino)
//        setLoad(commandByte & 0b00011111);
//        sendMessage(0);
      }
      else
      {
//        sendMessage(commandByte & 0b00011111);
      }
    }   
  }
  
}

void enableWatchdog()
{
  // communication watchdog
  watchdogCounter = 0;
  isWatchdogEnabled = 1;  
}

unsigned int readADC12bit(int channel) // oversamples ADC to 12 bit (AVR) or averages 16 samples (ARM)
{  
  byte i;
  unsigned int analogResult = 0;
  #ifdef ARM
    delay(1);
  #endif
  for (i = 0; i < 16; i++)
  {
    analogResult += analogRead(channel);
  }
  #ifdef AVR
    return (analogResult >> 2);
  #endif
  #ifdef ARM
    return (analogResult >> 4);
  #endif
}

The problem is, that the first character sent via serial port remains in the chooseVar() function and the second character is sent to either controlBipolar() or serialMonitor(). And I should be able to control it only with minimum one character. Since if there are minimum two characters required to call serialMonitor(), then I am going to loose some data sent from C# control program to arduino…

The problem is, that the first character sent via serial port remains in the chooseVar() function and the second character is sent to either controlBipolar() or serialMonitor().

Wrong. The first character is in the global serialRead variable. The next character is READ by (not sent to) the appropriate function.

Since if there are minimum two characters required to call serialMonitor(), then I am going to loose some data sent from C# control program to arduino...

First, why are two or more characters needed to call the serialMonitor() function? Second, why are the commands not packeted? The chooseVar() method should be reading all the serial data, storing it until the end of packet marker arrives, and THEN deciding which, if any, function to call.

PaulS:
First, why are two or more characters needed to call the serialMonitor() function?

I have no idea. I don't want it and I don't understand why if I send one character, nothing happens.
I am totally lost now.

PaulS:
Second, why are the commands not packeted? The chooseVar() method should be reading all the serial data, storing it until the end of packet marker arrives, and THEN deciding which, if any, function to call.

I will try to find out, how to do that.

What I actually want to do is:
a) If I send either "c" or "d" the function controlBipolar() is called and sets LOW/HIGH respectively.
b) If there is any other message (coming from C# control program), function serialMonitor() is called.

I thought that setting if-statement will be enough to choose between these two functions. But as I see nothing happens when I send only one character. Only when sending two characters something happens.

I am not a programmist, it is my first time when I program something like that and I am really sorry if I sometimes use wrong words to describe the functionality of the sketch.

I have no idea. I don't want it and I don't understand why if I send one character, nothing happens.

Aren't you responsible for the sending application?

That application needs to read what the Arduino writes to the serial port, and show it to you, so you have a hope in hell of debugging the Arduino code.

Do you have a clue what Serial.flush() does? I seriously doubt that you need ANY calls to it.

I will explain it more in details..

I have a windows control program written in C# which comunicates with Arduino via serial port. I didn't write this program, I just bought it together with the device (my device is a programmable load). So, the C# program and Arduino communicate in both directions. One direction - Arduino sends analog data (voltage, current etc) to windows program, and in the second direction the control program sends commands to arduino in order set the load. These commands are storaged in commandByte variable.

I wanted to ADD to the Arduino sketch and to C# control program a few lines of code in order to control another device - a bipolar transistor. So I just wrote few lines in C# for sending messages via COM port and also wrote the function controlBipolar() for Arduino.
If I write a new arduino sketch for controlling the transistor ONLY, everything works fine. Sending one character sets the transistor to HIGH and sending another character sets the transistor to LOW.

But when I put these two sketches together, meaning having in one sketch the function controlBipolar() and serialMonitor(), then it didn't work at all. So I wrote the if-statement to choose between these two functions. It still didn't work. But then I noticed, that if I send more then one character (for example "dd" or "dc" etc.) then one of these two functions is called and it works.
But the problem is, that somehow I need at least these two characters, because otherwise nothing works. And of course this is a problem for the serialMonitor() function, because if the function starts reading only from the second character, it means that the beginning of the message from C# control program which sets the load, is going to be lost.

You will need to share ALL of your code if you really want help.

If your code is too long you can add it as an attachment.

It would be a big help if you can post a typical example of the messages that are sent from your C# program and a typical example of the message it expects to receive from the Arduino.

...R

So, I have already found a solution...this was very trivial.
The function chooseVar() was proving the condition if(Serial.available()>0) and then the called function (either controlBipolar() or SerialMonitor()) was proving the same condition again.
Proving it only once in the first function solved the problem. Now I am able to send one character and control my bipolar transistor :slight_smile:

Thank you very much for your help guys!