Go Down

Topic: Interrupts are interrupting serial communication (Read 307 times) previous topic - next topic

pejuangsst14

Hello everyone!

I'm now working on VFD Inverter, and i intend to use VB.Net to control voltage and frequency. But I have a problem with arduino interrupts in my code. It seems the interrupt pause my serial communication line in void loop {}. I don't know what to do, and i can't erase interrupts line since i got this code from another site and the author said that the interrupt play important role in his code. So, is there another method/solution to keep interrupts in the code like make a new void in the code? Could you help me, please? Btw, i am using cli{} and sli{} functions in my code.

Here is my code:
Code: [Select]


int i=0;
int j=0;
int k=0;

int x=0;
int y=0;
int z=0;

int OK=0;
int OK1=0;
int OK2=0;
int OK3=0;
int OK4=0;
 
int sinPWM[]={0,1,2,3,4,6,7,8,9,11,12,13,14,16,17,18,19,21,22,23,24,26,27,28,29,31,32,33,34,36,37,38,39,40,42,43,44,45,47,48,49,50,52,53,54,55,56,
              58,59,60,61,62,64,65,66,67,68,70,71,72,73,74,76,77,78,79,80,82,83,84,85,86,87,89,90,91,92,93,94,96,97,98,99,100,101,102,104,105,106,
              107,108,109,110,111,112,114,115,116,117,118,119,120,121,122,123,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
              142,143,144,145,147,148,149,150,151,152,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,171,172,173,
              174,175,176,177,178,179,179,180,181,182,183,184,185,185,186,187,188,189,189,190,191,192,193,193,194,195,196,197,197,198,199,200,200,
              201,202,203,203,204,205,205,206,207,208,208,209,210,210,211,212,212,213,214,214,215,215,216,217,217,218,219,219,220,220,221,221,222,
              223,223,224,224,225,225,226,226,227,227,228,228,229,229,230,230,231,231,232,232,233,233,234,234,234,235,235,236,236,237,237,237,238,
              238,238,239,239,240,240,240,241,241,241,241,242,242,242,243,243,243,244,244,244,244,245,245,245,245,246,246,246,246,246,247,247,247,
              247,247,247,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,
              249,249,249,249,249,249,249,249,249,249,249,249,249,248,248,248,248,248,248,248,247,247,247,247,247,247,246,246,246,246,246,245,245,
              245,245,244,244,244,244,243,243,243,242,242,242,241,241,241,241,240,240,240,239,239,238,238,238,237,237,237,236,236,235,235,234,234,
              234,233,233,232,232,231,231,230,230,229,229,228,228,227,227,226,226,225,225,224,224,223,223,222,221,221,220,220,219,219,218,217,217,
              216,215,215,214,214,213,212,212,211,210,210,209,208,208,207,206,205,205,204,203,203,202,201,200,200,199,198,197,197,196,195,194,193,
              193,192,191,190,189,189,188,187,186,185,185,184,183,182,181,180,179,179,178,177,176,175,174,173,172,171,171,170,169,168,167,166,165,
              164,163,162,161,160,159,158,157,156,155,154,153,152,152,151,150,149,148,147,145,144,143,142,141,140,139,138,137,136,135,134,133,132,
              131,130,129,128,127,126,125,123,122,121,120,119,118,117,116,115,114,112,111,110,109,108,107,106,105,104,102,101,100,99,98,97,96,94,
              93,92,91,90,89,87,86,85,84,83,82,80,79,78,77,76,74,73,72,71,70,68,67,66,65,64,62,61,60,59,58,56,55,54,53,52,50,49,48,47,45,44,43,42,
              40,39,38,37,36,34,33,32,31,29,28,27,26,24,23,22,21,19,18,17,16,14,13,12,11,9,8,7,6,4,3,2,1,0};


float A;
float F;

String inputString = "";                  
boolean stringComplete = false;  
String In_1;
String In_2;
int Val1 = 0;
int Val2 = 0;

void setup() {
Serial.begin(9600);
inputString.reserve(200);

pinMode(4, OUTPUT);
pinMode(13,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(2,OUTPUT);
pinMode(5,OUTPUT);

cli();                              // clear interrupts
TCCR0A=0;                           //reset nilai
TCCR0B=0;                           //reset nilai
TCNT0=0;                            //reset nilai                                  
TCCR0A=0b10100001;                  //phase correct pwm mode
TCCR0B=0b00000001;                  //tidak ada prescaler


TCCR2A=0;                           //reset nilai
TCCR2B=0;                           //reset nilai
TCNT2=0;                            //reset nilai
TCCR2A=0b10100001;                  //phase correct pwm mode
TCCR2B=0b00000001;                  //tidak ada prescaler


TCCR3A=0;                           //reset nilai
TCCR3B=0;                           //reset nilai
TCNT3=0;                            //reset nilai
TCCR3A=0b10100001;                  //phase correct pwm mode
TCCR3B=0b00000001;                  //tidak ada prescaler


TCCR1A=0;                           //reset nilai
TCCR1B=0;                           //reset nilai
TCNT1=0;                            //reset nilai
OCR1A=509;                          // compare match value
TCCR1B=0b00001001;                  //WGM12 bit is 1 for CTC mode and no prescaler

TIMSK1 |=(1 << OCIE1A);             // memulai interrupts

sei();                          
}
ISR(TIMER1_COMPA_vect){             // interrupt mulai ketika timer 1 cocok dengan OCR1A
  
//=====================Phase A=======================//

  if(i>629 && OK==0){               // nilai akhir dari sample untuk pin 13
    i=0;                            // mulai dari nilai awal sample
    OK=1;}                          //mengaktifkan pin 4
  
  if(i>629 && OK==1){               // nilai akhir dari sample untuk pin 4
    i=0;                            //mulai dari nilai awal sample
    OK=0;}                          //mengaktifkan pin 13

  x=round(A*sinPWM[i]);             // nilai x berasal dari sample dan i berindex 0
  i=i+F;                            
    if(OK==0){
      OCR0B=0;                      //pin 4 0
      OCR0A=x;}                     //pin 13 1

    if(OK==1){
      OCR0A=0;                      //pin 13 0
      OCR0B=x;}                     //pin 4 1

    if ((i>=418) || OK1==1){         //jika nilai i mencapai 209, maka phase kedua akan dimulai
      OK1=1;                      
      
//=====================Phase B=======================//

  if(j>629 && OK2==0){              // nilai akhir dari sample untuk pin 10
    j=0;                            // mulai dari nilai awal sample
    OK2=1;}                          //mengaktifkan pin 9
    
  if(j>629 && OK2==1){              // nilai akhir dari sample untuk pin 9
    j=0;                            //mulai dari nilai awal sample
    OK2=0;}                         //mengaktifkan pin 10

  y=round(A*sinPWM[j]);             // nilai y berasal dari sample dan i berindex 0
  j=j+F;                            
    if(OK2==0){
      OCR2B=0;                      //pin 9 0
      OCR2A=y;}                     //pin 10 1

    if(OK2==1){
      OCR2A=0;                      //pin 10 0
      OCR2B=y;}                     //pin 9 1
}

    if ((j>=418) || OK3==1){        //jika nilai j mencapai 209, maka phase ketiga akan dimulai
      OK3=1;                      

//=====================Phase C=======================//
  
  if(k>629 && OK4==0){              // nilai akhir dari sample untuk pin 5
    k=0;                            // mulai dari nilai awal sample
    OK4=1;}                         //mengaktifkan pin 2
    
  if(k>629 && OK4==1){              // nilai akhir dari sample untuk pin 2
    k=0;                            //mulai dari nilai awal sample
    OK4=0;}                         //mengaktifkan pin 5
    
  z=round(A*sinPWM[k]);             // nilai z berasal dari sample dan i berindex 0
  k=k+F;                          
    if(OK4==0){
    OCR3B=0;                        //pin 2 0
    OCR3A=z;}                        //pin 5 1
    
    if(OK4==1){
    OCR3A=0;                        //pin 5 0
    OCR3B=z;}                       //pin 2 1
  }
}
void loop() {
  
     serialEvent();
     if (stringComplete) {
      if (inputString.substring(0,4)=="VOLT"){
        In_1 = inputString.substring(4);
        Val1 = In_1.toInt();
        A= Val1/1023;
        Serial.println(Val1);
      }
      if (inputString.substring(0,4)=="FREQ"){
        In_2 = inputString.substring(4);
        Val2 = In_2.toInt();
        F= map(Val2,1023,0,0,50);
      }
    
      inputString = "";
      stringComplete = false;
      }
    }
  }

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

pejuangsst14

I believe the same problem have mentioned in https://forum.arduino.cc/index.php?topic=294464.0, but i don't see the problem have solved

Robin2

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

Don't call serialEvent() from loop(). It gets called automatically by the Arduino system.

Better still, don't use serialEvent() at all. Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. With code like in my examples you can check for serial data when it is convenient for your program to do so.

Getting data from the UART into the Serial Input Buffer requires interrupts. If your code is interrupting things very frequently it may simply be that there is not enough time for the Arduino to do other stuff. I can't understand your comments.

Timer0 is used by the Uno and Mega to update millis() and micros() - modifying its settings may interfere with that.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

sterretje

One solution might be to send only one character at a time (not a complete message) from the VB application. Once the Arduino receives it, the Arduino echoes the received character back to the VB app; that's the sign for the VB app to send the next character.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

GolamMostafa

@OP

Try re-writing your loop() function in the following way; where, the tasks of serialEvent() have been merged.
Code: [Select]
void loop()
{
  //serialEvent();
  if (stringComplete == false)
  {
    while (Serial.available())
    {
      char inChar = (char)Serial.read();
      inputString += inChar;
      if (inChar == '\n')
      {
        stringComplete = true;
      }
    }
  }
  else//if (stringComplete)
  {
    if (inputString.substring(0, 4) == "VOLT")
    {
      In_1 = inputString.substring(4);
      Val1 = In_1.toInt();
      A = Val1 / 1023;
      Serial.println(Val1);
    }
    if (inputString.substring(0, 4) == "FREQ")
    {
      In_2 = inputString.substring(4);
      Val2 = In_2.toInt();
      F = map(Val2, 1023, 0, 0, 50);
    }

    inputString = "";
    stringComplete = false;
  }
}

/*
void serialEvent()
{
  while (Serial.available())
  {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inChar == '\n')
    {
      stringComplete = true;
    }
  }
}*/

pejuangsst14

#5
Jun 24, 2019, 03:16 pm Last Edit: Jun 24, 2019, 03:17 pm by pejuangsst14

@Robin2
Thanks for your reply. I appreciated that.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).
Are you saying that i should use the string like this example?
Code: [Select]
char greeting[] = "Hello";

Don't call serialEvent() from loop(). It gets called automatically by the Arduino system.

Better still, don't use serialEvent() at all.
May i use the one that @GolamMostafa mentioned in the reply to my void loop? What do you think?

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. With code like in my examples you can check for serial data when it is convenient for your program to do so.
Okay, i will look at the examples from your post. Thank you very much for provide such an important information.

I can't understand your comments.
I am so sorry for wrote comments in my native language, i'll edit the comments soon

Timer0 is used by the Uno and Mega to update millis() and micros() - modifying its settings may interfere with that.
It seems, i can't modifiy the timer setting since i am beginner, and i get this code from this site. I am too afraid to try to modify it.

jremington

Quote
I am too afraid to try to modify it.
Then you have not yet learned enough programming and hardware to start a project like this. Expect endless frustrations with your "copy and paste" attitude.

Thoughtful, well organized and successful people start with the simple examples that come with the Arduino IDE, in order to learn the C/C++ programming language, and the special features of the Arduino.

pejuangsst14

One solution might be to send only one character at a time (not a complete message) from the VB application. Once the Arduino receives it, the Arduino echoes the received character back to the VB app; that's the sign for the VB app to send the next character.
@sterretje
Thanks for you reply and could you tell me any further about how can i do that?

pejuangsst14

Then you have not yet learned enough programming and hardware to start a project like this. Expect endless frustrations with your "copy and paste" attitude.

Thoughtful, well organized and successful people start with the simple examples that come with the Arduino IDE, in order to learn the C/C++ programming language, and the special features of the Arduino.
@jremington
Yeah, you're right! I only know a little about programming and i intend to learn more, since i know this might be useful for future references

pejuangsst14

#9
Jun 24, 2019, 04:03 pm Last Edit: Jun 24, 2019, 04:05 pm by pejuangsst14
@OP

Try re-writing your loop() function in the following way; where, the tasks of serialEvent() have been merged.
@GolamMostafa
I tried your method, but it's still didn't work

Coding Badly


Did you intend this to be integer division?

Code: [Select]
A= Val1/1023;

Same question for the assignment to F.


pejuangsst14

Did you intend this to be integer division?

Code: [Select]
A= Val1/1023;

Same question for the assignment to F.
Ah, No.. Glad you can pointed it, i think i should change Val1 and Val2 to float, though. Thanks to you.

Coding Badly


Neither A nor F are protected by critical sections.


sterretje

#13
Jun 25, 2019, 08:40 pm Last Edit: Jun 25, 2019, 08:46 pm by sterretje
@sterretje
Thanks for you reply and could you tell me any further about how can i do that?
This is a modified version of Robin's second eample that demonstrates the echo
Code: [Select]

// Example 2 - Receive with an end-marker

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void setup()
{
  Serial.begin(57600);
}

void loop()
{
  recvWithEndMarker();
  processNewData();

  // do other stuff
  ...
  ...
}

void recvWithEndMarker()
{
  static byte ndx = 0;
  char endMarker = '\n';
  char rc;

  if (Serial.available() > 0 && newData == false)
  {
    rc = Serial.read();

    // echo the character
    Serial.write(rc);

    if (rc != endMarker)
    {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars) {
        ndx = numChars - 1;
      }
    }
    else
    {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      newData = true;
    }
  }
}

void processNewData()
{
  if (newData == true)
  {
    // do something usefull with the new data
    ...
    ...
   
    // indicate that we're ready for new data
    newData = false;
  }
}


For the VB side, the below assumes that you have
1) textbox called tbRxData to display data received from arduino
2) textbox called tbTxData to enter a message to be send
3) a button called btnTransmit; the code below is the click handler for that button.

The code is in C#, so probably will need some adjustments from your side.
Code: [Select]
private void btnTransmit_Click(object sender, EventArgs e)
{
    // clear receive textbox
    tbRxData.Clear();

    _serialPort.ReadTimeout = 500;

    // create tx data from tbTxData
    byte[] tmp = Encoding.ASCII.GetBytes(tbTxData.Text);
    byte[] transmitBuffer = new byte[tbTxData.Text.Length + 1];
    for (int cnt = 0; cnt < tmp.Length; cnt++)
    {
        transmitBuffer[cnt] = tmp[cnt];
    }
    // append newline
    transmitBuffer[transmitBuffer.Length - 1] = (byte)'\n';

    // send byte by byte, waiting for echo each time
    for (int byteCnt = 0; byteCnt < transmitBuffer.Length; byteCnt++)
    {
        _serialPort.Write(transmitBuffer, byteCnt, 1);
        try
        {
            byte echo = (byte)_serialPort.ReadByte();
            tbRxData.AppendText(String.Format("0x{0:X2} ", echo));
        }
        catch (TimeoutException toe)
        {
            tbRxData.Text = "No echo from Arduino";
            return;

        }
        catch (Exception ex)
        {
            tbRxData.Text = ex.Message;
            return;
        }
    }

}


If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Go Up