[resolved] send hexa frame with RS485–protocol lib

Hello,

I've bought industrial display with controler.
It talk through RS485 module.
I am able to communicate with the display with "coolTerm" (serial tool on osx)
when i try to send the frame trought RS485, nothing happens...

I suppose i've misunderstood something on the way to send.
I use the RS485_protocol.h with SoftwareSerial lib.

on this forum there is example code to send message as master.

I have to send a frame in hexa like this:

80 89 00 34 8F

in the example (this is where is my pb i suppose) i write the message like this

byte msg [] = { 
       0x80,
       0x89,
       0x00,
       0x34,
       0x8F
    };
digitalWrite (ENABLE_PIN, HIGH);  // enable sending
sendMsg (fWrite, msg, sizeof msg);

when i send it... nothing

in fact i need some help to correctly build the message and be sure to send it as hexa not ascii
(if i try to communicate to display via serialtool an ascii string it does not work)

hope i'm clear.

please give some help...

regards

é.

Éric

You say

I've bought industrial display with controler.

What industrial display and what controller ?

It talk through RS485 module.

You mean it communicates through a RS-485 module, again, what module and to what device ?

Then you say

I am able to communicate with the display with "coolTerm" (serial tool on osx)

Is that via the RS-485 module or some other communication interface ?

When you say 'I am able to communicate', are you saying you are successful in communicating data from CoolTerm from your Mac to the display and the data is then displayed correctly ?

RS485_protocol.h

Where did you get that from ?
RS-485, or more EIA-485 is not a protocol, it is simply an electrical interface specification.
On EIA-485 you can use many different data protocols.

You need to be very clear and detail exactly what you are doing, what is working and how and what is not.
No, you are not clear enough.
Post your code as well.


Santé
Paul

well, i bought the 7seg display with a controler from alfazeta (flipdot techno).
7seg use RS485 and a "secret" protocol (frame look like modbus)

They've gave me a Windows app to test display, it works...
in first i've tried to send a frame (in hexa) from a serial tools (Coolterm on osx) through a usb-rs485 (the one who is working with alfazeta widows app)
and it works.

the usb-rs485 converter

the lib come from gammon forum (moderator) and the example come from...
i've just copy/past and change the pin setting for me.
and have modifying the "message"

the module used with the arduino is this one (ebay too) with a MAx485

and i've used this tutorial as ressource.

i think you've got all.

regards

And your code, are you going to show it here ?
Did you create the code or is it from Nick or from Alfazeta ?


Paul

i give the script who is a simple copy/paste from nick’s Master example…
there is no exaple from Alfazeta, just a “becoming” techdoc

#include <RS485_protocol.h>
#include <SoftwareSerial.h>


const byte ENABLE_PIN = 9;
const byte LED_PIN = 13;
int compteur= 0;

const byte data[7] = {0x01, 0x02,0x04,0x08,0x10,0x20,0x40};

SoftwareSerial rs485 (10, 8);  // receive pin, transmit pin
// rs485( DI , RO )                            

// callback routines
  
void fWrite (const byte what) {
  rs485.write (what);  
}
  
int fAvailable (){
  return rs485.available ();  
}

int fRead (){
  return rs485.read ();  
}

void setup(){
  rs485.begin (9600); // vitesse com
  pinMode (ENABLE_PIN, OUTPUT);  // driver output enable
  pinMode (LED_PIN, OUTPUT);  // built-in LED
  Serial.begin(9600);
}  // end of setup
  


void loop(){
   
    // assemble message
    byte msg [] = { 
       0x80,    // start byte
       0x89, // send byte and refresh
       0x00, // to all adress
       data[compteur%7],
       0x8F // end byte
    };


  Serial.println("loop");
  for (int i=0; i<=5;i++) {
  Serial.print(msg[i]);
  if (i<5) {
    Serial.print(",");
  }
  }
  Serial.println();
  // send to slave  
  digitalWrite (ENABLE_PIN, HIGH);  // enable sending
  sendMsg (fWrite, msg, sizeof msg);
  
  while (!(UCSR0A & (1 << UDRE0)))  // Wait for empty transmit buffer
    UCSR0A |= 1 << TXC0;  // mark transmission not complete
  while (!(UCSR0A & (1 << TXC0)));   // Wait for the transmission to complete
  
 
  digitalWrite (ENABLE_PIN, LOW);  // disable sending

  // receive response  
  byte buf [10];
  byte received = recvMsg (fAvailable, fRead, buf, sizeof buf);
  
  digitalWrite (LED_PIN, received == 0);  // turn on LED if error    
  
  compteur++;
  delay(2000);

}  // end of loop

Well, I don’t think you need Nick’s RS-485 library, as it is designed for communicating between two Arduinos.
You just need a simple straight forward serial print style bit of code.

I messed around with your code, I haven’t compiled it to see how it goes, but you can try.

What are you wanting to put on the display?
The data in your data array are not all ASCII printable characters if you need them to be.
Check online ASCII tables.

Really, you don’t need software serial either, by not printing what you have to the console.
I modified it so that on each pass of the loop the data byte gets modified in a fashion I believe replicates your data array.

#include <SoftwareSerial.h>

//const byte data[7] = {0x01, 0x02,0x04,0x08,0x10,0x20,0x40}; // not needed

// assemble message
byte msg [] = {
    0x80,    // start byte
    0x89,    // send byte and refresh
    0x00,    // to all adress
    0x01,    // first data thingy to display, is non printable ASCII
    0x8F     // end byte
};

#define TX_ENABLE_PIN 9            // define the EIA-485 transmit driver pin
SoftwareSerial rs485(10, 8);       // receive pin, transmit pin

void setup(){
  pinMode(TX_ENABLE_PIN, OUTPUT);  // driver output enable
  rs485.begin (9600);              // vitesse com
  Serial.begin(9600);
}

void loop(){
    digitalWrite (TX_ENABLE_PIN, HIGH);     // enable transmit driver

    for (int i = 0; i < 5; i++)
    {
        Serial.print(msg[i]);               // console print the data
        rs485.write(msg[i]);                // flip display print
        if (i < 4)
        {
            Serial.print(", ");             // print a comma between data
        }

    }
    Serial.println();

    digitalWrite(TX_ENABLE_PIN, LOW);       // disable transmit driver

    if (msg[3] < 0x40)
       msg[3] = msg[3] << 1                 // left shift to multiply by 2 while less than 0x40

    delay(2000);
}

Santé
Paul

you certainly right, i do not need the lib... neither the software serial.

it is important to send the frame in hexa
i've tested in my serial tools,
if i send in ascii, it does not work, if i send in hex it's working...

the frame i have to send in hex is

80 89 00 34 8F
[start byte]  [command]  [adress]  [data]  [end byte]

my question is about the message to send.
do i need a comma or... i don't know how does it talk, send...

The data does not care if it is HEX or ASCII, that is only how you see it on a terminal, the way it is represented.
HEX 40, or 0x40 is the exact same as decimal 64 or binary 01000000. They are all the same thing, really.

Ok, so modify the msg array to have the 0x34 in there.
Modify the line

msg[3] = msg[3] << 1

to
msg[3] = msg[3] << 1;I forgot the ending semicolon.

I think it should work for you, maybe with a peu de travail :slight_smile:


Paul

rockwallaby:
The data does not care if it is HEX or ASCII, that is only how you see it on a terminal, the way it is represented.
HEX 40, or 0x40 is the exact same as decimal 64 or binary 01000000. They are all the same thing, really.

I know that hex equal dec equal bin, equal oct...
in the serial tool, if i send to controler in ascii, it does not work.
i've tried (with the serial tool) by changing the number in decimal and have sent it in ascii... it does not work...
:confused:
this why i'm confused...

i'll try with your simplified version...

thanks very much.

é.

It's hard for me to imagine, and that is why I asked 'what are you wanting to display'
With the code you presented it appeared to me the data was be altered every 2 seconds.
Now you want just to send 0x34 which is the ASCII numeral '4'.
So, what are you trying to display, changing data or just one number?

With the data to the flip display, no, you do not need to send coma, just the data bytes as the code I presented should do for you.

The coma in the code is only there for feed back on your serial terminal screen your Mac, not the flip display.

So, have you compiled the code and tested it yet?


Paul

You say

in the serial tool, if i send to controler in ascii, it does not work.

Yes, but if you use the ASCII equivalents it will work perfectly.

So, you wish to send, in hex 0x80 0x89 0x00 0x34 0x8F, the very same result will be if you send in ASCII the following, Çè(null)4ÅExcept you can not type a null, or 0x00 on a keyboard. That is the ASCII copy of the Hex version.


Paul

rockwallaby:

msg[3] = msg[3] << 1;

the forth byte of the frame is a number between 0-127 (0x0 - 0x7F)
segment setup as a normal seven7,
one bit per segment, coded on 7bits, the last, at right is useless…

i’m not understand why your are bit shifting number… it’s nonsens :wink:

in my code i use an array to switch on each segment of the display… i could use a random value…

random(0,128);

rockwallaby:
You say Yes, but if you use the ASCII equivalents it will work perfectly.

So, you wish to send, in hex 0x80 0x89 0x00 0x34 0x8F, the very same result will be if you send in ASCII the following, Çè(null)4ÅExcept you can not type a null, or 0x00 on a keyboard. That is the ASCII copy of the Hex version.


Paul

the third number is the display adress and by default the display have a "0" adress (for sure i can broadcast message to all display by using "0xFF"

in the 4th byte, i can avoid "0" by using "0x80"
all these "hack" will solve "0" prob...

é.

something like that

if (i == 4 and msg[i]< 0x80) {
          msg[4]|= 0x80; // bitwise OR
        }

YES! i kiss your cute little tongs, nails, yes the huggly one too… your ha…
no no no no!
IT WORKS…
YOU’RE GREAT!!!
:art:
THANKS SOOOOOOOOOO MUCH!

the trick IS :

  • the Serial.write() not the Serial.print()
  • i inverted tx/rx pin for SoftwareSerial → SoftwareSerial rs485(RO, DI); // pins name on the module

the code that works
it generate a random pattern on the display every half second.

#include <SoftwareSerial.h>
// assemble message
byte msg [] = {
    0x80,    // start byte
    0x89,    // send byte and refresh
    0xFF,    // to all adress , by default display is configured in 0,1 or 255
    0x00,    // first data thingy to display, is non printable ASCII
    0x8F     // end byte
};

#define TX_ENABLE_PIN 9            // define the EIA-485 transmit driver pin ( RE + DE pin's modules)
SoftwareSerial rs485(8, 10); // SoftwareSerial rs485(RO, DI); pins name on the module

void setup(){
  pinMode(TX_ENABLE_PIN, OUTPUT);  // driver output enable
  rs485.begin (9600);              // vitesse com
  Serial.begin(9600);
}

void loop(){
  digitalWrite (TX_ENABLE_PIN, HIGH);     // enable transmit driver
  msg[3] = random(0,128); // generate a random display
  
    for (int i = 0; i < 5; i++) {
        Serial.print(msg[i], HEX);          // console print the data
        rs485.write(msg[i]);                // flip display print
        if (i < 4){
            Serial.print(", ");             // print a comma between data for console only :art: 
        }
    }
    Serial.println();
    digitalWrite(TX_ENABLE_PIN, LOW);       // disable transmit driver
    delay(500);
}

hope these lines will help you (next user)…
love!
long life to arduino!

rockwallaby:
Except you can not type a null, or 0x00 on a keyboard.

i was loving the idea to add 1 to the useless 8th bit (to never have a value lower than 0x40), that i've found pretty smart...
But in fact it doesn't care...
message is transmit with the good values. (0 or up)

Éric, that’s great to know you were finally successful. :slight_smile:

Now, a few things:

    if (msg[3] < 0x40)
       msg[3] = msg[3] << 1;  // left shift to multiply by 2 while less than 0x40

you say

i’m not understand why your are bit shifting number… it’s nonsens :wink:

If you think more about it to understand you will come to see that it is an efficient way to simply change the bits of the display. In this method you use one byte, the actual data byte, where as with your method of data array, you use 7 times more space, 56 bits, as opposed to 8 bits.

Then your code:

if (i == 4 and msg[i]< 0x80) {
          msg[4]|= 0x80; // bitwise OR
        }

Would seem to me as not doing anything. Take a value and then ‘OR’ it with a constant doesn’t create a changing bit pattern, it just stays the same after the initial ‘OR’.

Yes, Serial.write, just as I had in my original code, it sends out the bytes exactly as you need.
The Serial.print to console is simply to your screen, whether you use

Serial.print(msg[i], HEX)

or

Serial.print(msg[i])

Will make no difference to what you see on your flip display.
This is only for the information coming back to your Mac terminal screen.

In fact, if the flip display does not send data back to Arduino, then you do not need to toggle the TX_ENABLE_PIN, just leave it high all the time.

But if you do need to operate the TX_ENABLE_PIN, then you should also have a very small delay before the TX_ENABLE_PIN being made LOW, such as:

delay(6);     // time to allow all data to be sent before disable of TX_ENABLE_PIN
digitalWrite(TX_ENABLE_PIN, LOW);       // disable transmit driver

Based on my quick calculation of 9600 bits per second and at around 11 bits per sent data inclusive of start and stop bits. Each data sent then takes 1.15mSec. So then 5 data will then take just under 6mSec. This delay is to make sure all the data has been sent before you disable the TX_ENABLE_PIN.

I guess you can now make your program. do what you want and have fun with it. :slight_smile:


Paul

rockwallaby:

    if (msg[3] < 0x40)

msg[3] = msg[3] << 1;  // left shift to multiply by 2 while less than 0x40

ok for the bit shift, it make sens but it works only one time, with an array and a modulo it repeats.

rockwallaby:

if (i == 4 and msg[i]< 0x80) {

msg[4]|= 0x80; // bitwise OR
       }

try it… it add a 1 to the bit on the left (8th)… the controler don’t read it, the value “0x0” become “0x80”, it is a printable ASCII value :wink:

and for the advice about delay to disable TX_ENABLE_PIN…
the controler answer with only one command (asking current display adress)

in the Nick’s example, there is these line added to avoid this problem…

  while (!(UCSR0A & (1 << UDRE0)))  // Wait for empty transmit buffer
    UCSR0A |= 1 << TXC0;  // mark transmission not complete
  while (!(UCSR0A & (1 << TXC0)));   // Wait for the transmission to complete

i have a question here what if we have binary data to send through RS232 what changes should be done in the code???

please guide me. will be very thankful to you.

Nothing.
The hardware do the rs485...
You should use this code for rs323 with the rigth shield