Serial.print for RS232 communication

I'm attempting to send a signal via RS232 to trigger a laser firing. The only info I get is RS232 (9600-8-N-1), and the command syntax is "$FIRE 01CR". Only Tx and Rx are used, no other handshaking, CR is carriage return, 0Dh. Do I need to convert this into binary first? Or will the Mega2560 internally handle the signal and send as binary?

Below is my code, I'm using a button to induce a pin change from LOW->HIGH and detect the rising edge with attachInterrupt (I need the command sent only once, not repeatedly as long as the pin is HIGH).

const int buttonPin = 2;
int buttonState = digitalRead(buttonPin);

void setup() {
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(buttonPin), INT0_ISR, RISING);
}

void loop() {
}

void INT0_ISR() {
  Serial.write("$FIRE 01\r");
}

The output on the Serial Monitor is "$FIRE 01" when I use Serial.println in place of Serial.write (as I understand it, Serial.write actually sends the signal to the serial pin).

I'm using an RS232 to TTL converter between the laser and the arduino, with pin 0 (RX) connected to TX, and pin 1 (TX) connected to RX on the converter. When the button is pressed, I see both TX and RX flash, so I assume that means there was some kind of serial communication, however there's no response from the laser.

Very new to C++ and still confused on how Serial.print works/how to format the command for RS232 communication. Any help/explanation would be greatly appreciated. Below is m wiring diagram. Thanks!

Based on your labeling of your sketch, I suspect you need to swap TX and RX, at one end or the other, unless you have documentation indicating that TXD on the converter is an output.
I also think your button is wired wrong. Pullup has to be between 5V and the input pin. Though, there's also the built-in pullup resistor if you enable it.

99.99% of the time, using an interrupt for a button press is the wrong way to go, rising or falling. Code in loop detecting state change for the button, and debouncing it, will get you a lot further a lot more quickly.

2 Likes

I would also suggest using one of the other serial interfaces (Serial1, Serial2 or Serial3) on the Mega to allow Serial to be used for debugging

3 Likes

Thank you, debouncing is on my radar.

I used the button here as a proxy for a pin state change trigger (I had been using is for testing other code and just kept it for this), is attachInterrupt still a poor choice for detecting the leading edge?

What is the device being controlled? Who said

[quote="pdawg_gator, post:1, topic:1289612"]
The only info I get is RS232 (9600-8-N-1)
[/quote]

I agree with @UKHeliBob, my draft from before had

Since it's on a Nega, you could use one of the other hardware serial ports and leave rx0/tx0 for uploading and serial monitoring.

Both print and write send out data on the TX pin. It's hard to say what is appropriate in this circumstance, hence the desire to know what the laser thing is, or a link to where you learned anything about controlling it. Maybe it's a laser and is a little harder to make go. :expressionless:

a7

Here are some oscilloscope traces showing what your code sends when using Serial.write and Serial.println:

  • Channel 1 - yellow trace - button pin.
  • Channel 3 - blue trace - D1 TX (UART TTL level).
  • Channel 4 -green trace - Pin 2 of 9 way sub D connector (RS232 level).
  • The Serial output is decoded in both ASCII and hexadecimal.
Serial.write("$FIRE 01\r");

Serial.println("$FIRE 01");

Note that I have removed the \n, as Serial.println sends CR (0x0D) followed by LF(0x0A).

Thank you for the oscilloscope pics.

"Note that I have removed the \n, as Serial.println sends CR (0x0D) followed by LF(0x0A)."
To clarify, for Serial.write, I should always include \r or \n?

If you are using this TTL/RS232 Converter (Fig-1):


Figure-1:

then the connection beteen MEGA and the Converter should be similar to Fig-2:


Figure-2:

After uploading the relevant sketch in MEGA, enter $FIRE 01 in the InputBox of the Serial Monitor (Fig-3) with Carriage return option and then click on the Send Button.


Figure-3:

Yes, because a button will bounce many times, and putting debouncing in an interrupt routine is stand-on-your-head foolish.
You will find that without a lot of awkward work, the multiple interrupts emanating from bouncing contacts will result in multiple output messages, scrambling your attempt to turn the bus around at a consistent time.

I understand the bouncing issue for a physical contact trigger like a button, but for a non-button trigger (i.e. some other part of the code turns a trigger pin high), is attachinterrupt still a bad choice?

I Guess not, but then if the code sets an output, it can also set a flag variable. No need for the interrupt at all.
Not getting where you're coming from.

1 Like

That will work better, no bouncing problem… but it raises the question - if some other part of the code can turn a trigger pin high, it could just do whatever the interrupt service routine was meant to do right there at the same time.

a7

1 Like

There is one advantage of interrupt over polling the flag. If using interrupt, the MCU is free from spending time to poll the flag; let the event notify its presence to the MCU through interrupt.

On the other hand, if the code would be triggering an interrupt through a pin change, it could just as easily call a function directly to do the work right there and then (no need for any interrupts or flags at all).

1 Like

If the external event is asynchronous, there is no way for the main line program to decide the exact time of arrival of the event. In that case, either interrupt or flag has to be used to catch the event.

1 Like

I was referring to the suggestion of triggering a pin change from code and catching the pin change with an interrupt from within the same sketch. If the sketch is changing a pin only to catch the pin's state change in an interrupt, it would be better to instead do the action right there in place of changing the pin's state.

I see now that @alto777 made the same suggestion as me.

Yep I see the point @alto777 @christop !

I think my issue now is i'm not sure how to read the logic level change and send the command for laser operation only once (using the rising edge seemed like an accurate method for triggering a single fire command). So far, any code i've written for changing pin levels has been using digitalwrite() with delay(), but setting a delay time seemed less ideal than detecting the rising edge of a signal. I could be totally ignorant to some basic function for this.

Instead of discussing about right/wrong button trigger, why don't you just tx your laser directly from your code. Try all possible ways one after another (ascii, hex, print, write, /n, /r whatever) until that guy responds. It's not getting hurt. Then think about button.
Did I miss something??

Nope, you didnt miss anything, I just tried to do two things at once :upside_down_face:

Testing serial communication now.

The triggering/edge detection will be important in actual operation for precise triggering (the input will actually be from a different component not discussed here, which will be mediated via the arduino).

So waste of time until you have final trigger method. Anyway interrupt or loop, both are fine, one might be better than another in certain specific case... But don't do serial communication inside interrupt.

For now, kick that laser with all possible/impossible tx until it fires.