Stone HMI screen

Status
Not open for further replies.

Dulz

Active member
Hi everyone,

I'm trying to get a stone hmi screen running, so far with no success.

To start me off using it, i am simply trying to change 1 figure on the screen. I will be using the teensy 3.6 for the final product, but for testing purposes i'm just using my arduino leonardo to start with. So far the results are that the variable on the screen doesn't change, it just stays at 0 which is just the initial value stored in the screen. The code i'm sending should change it to a 1 if i have it right.

Hardware:

Arduino leonardo,

ttl to rs232 converter off ebay, https://www.ebay.com.au/itm/RS232-S...m=332547433576&_trksid=p2047675.c100012.m1985

RS232 male to male cable, https://www.ebay.com.au/itm/DTECH-R...var=423920386946&_trksid=p2057872.m2749.l2649

Stone HMI 7 inch advanced type 1000cd/m2 screen, http://www.stone-hmi.com/product/278138100

12v 1000mA power supply.


Code:

Code:
void setup() 
{
  Serial1.begin(9600);
  delay(1500);
}

void loop() 
{

 Serial1.print("A5 5A 05 82 FF C9 00 01");
/*A5 5A: frame header 
   05: command byte length
   82: write to variable memory interface
   FF C9: variable memory address to write to
   00 01: the new variable = 1.*/

}

Wiring:

Arduino D0 (RX) to rs232 converter TXD
Arduino D1 (TX) to rs232 converter RXD
Arduino 3.3v to rs232 converter VCC
Arduino GND to rs232 converter GND

12v power supply powers the screen

I will put photos in the next post.
 
Here you can see what is on the screen, and the variable address FF C9

stone screen.jpg
 
The manual section shown isn't clear if the data should be ASCII as above or binary, but there should not be spaces between the field values in any case:

This ' Serial1.print("A5 5A 05 82 FF C9 00 01"); ' may work with this: ' Serial1.print("A55A0582FFC90001"); '
 
The manual snippet only makes sense if the data is binary and not ASCII.

That is, you'll want to use something like
Code:
void setup() 
{
    Serial1.begin(9600);
    delay(1500);
}

void updateHMIi16(uint16_t address, int16_t value)
{
     uint8_t  data[8] = { 0xA5, 0x5A,           // Header
                          0x05,                 // Length
                          0x82,                 // Write to var memory
                          (address >> 8) & 255, // Address high byte
                          address & 255,        // Address low byte
                          (value >> 8) & 255,   // Value high byte
                          value & 255,          // Value low byte
                        };

    Serial1.write(data, 8);
}

void loop() 
{
    updateHMIi16(0xFFC9, 0x0100);
    delay(500);
    updateHMIi16(0xFFC9, 0x0001);
    delay(500);
}
 
Thanks for the replies guys, i put in the code above and it did upload, but also i got these errors:

C:\Users\Jas\Documents\Arduino\stone_hmi_screen_test1\stone_hmi_screen_test1.ino: In function 'void updateHMIi16(uint16_t, int16_t)':

C:\Users\Jas\Documents\Arduino\stone_hmi_screen_test1\stone_hmi_screen_test1.ino:14:42: warning: narrowing conversion of '(address >> 8)' from 'uint16_t {aka unsigned int}' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

(address >> 8) & 255, // Address high byte

^

C:\Users\Jas\Documents\Arduino\stone_hmi_screen_test1\stone_hmi_screen_test1.ino:15:35: warning: narrowing conversion of '(address & 255u)' from 'uint16_t {aka unsigned int}' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

address & 255, // Address low byte

^

C:\Users\Jas\Documents\Arduino\stone_hmi_screen_test1\stone_hmi_screen_test1.ino:16:40: warning: narrowing conversion of '(int16_t)(((unsigned int)value) >> 8)' from 'int16_t {aka int}' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

(value >> 8) & 255, // Value high byte

^

C:\Users\Jas\Documents\Arduino\stone_hmi_screen_test1\stone_hmi_screen_test1.ino:17:33: warning: narrowing conversion of '(value & 255)' from 'int16_t {aka int}' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

value & 255, // Value low byte
 
Thanks for the replies guys, i put in the code above and it did upload, but also i got these errors:
No, they're warnings, not errors. The difference is that a warning is just a warning that something might be an issue, but it does not abort the compilation; an error aborts the compilation.

In this particular case, the narrowing is deliberate, and can be annotated by casting. Because of the exact width (8 bits) of the uint8_t type, we can also drop the '& 255':
Code:
void setup() 
{
    Serial1.begin(9600);
    delay(1500);
}

void updateHMIi16(uint16_t address, int16_t value)
{
     uint8_t  data[8] = { 0xA5, 0x5A,               // Header
                          0x05,                     // Length
                          0x82,                     // Write to var memory
                          (uint8_t)(address >> 8),  // Address high byte
                          (uint8_t)(address),       // Address low byte
                          (uint8_t)(value >> 8),    // Value high byte
                          (uint8_t)(value),         // Value low byte
                        };

    Serial1.write(data, 8);
}

void loop() 
{
    updateHMIi16(0xFFC9, 0x0100);
    delay(500);
    updateHMIi16(0xFFC9, 0x0001);
    delay(500);
}

The question is, does it change the displayed value or not? It should switch between 0100 and 0001 twice per second (assuming the value is displayed in hex; if in decimal, between 256 and 1). I don't have a Stone HMI display myself, so all I had to go on was the original example and that little snippet from the manual.
 
Even though it uploaded (with the above errors) the value on the screen didn't change. i tryed swapping the tx and tx pins because i still wasn't sure they were the right way around, but it still didn't work.
 
Is this the manual for your product?

On page 10, it shows Screen Parameter Configuration. Since your control messages do not have a CRC check (would be ninth byte in the above code), you must have the two CRC16 related checkboxes not checked, just like the image in the manual.

It says on page 18 that "the user can define the content" of the frame header (0xA5 0x5A, above), in Intelligent ... tool, in Screen Parameter Configuration, for register R3, RA. Make sure that is A55A.

On page 39, it says that the default baud rate ("R1 (Serial baud rate)" in Screen Parameter Configuration) of the module is 115200 bps. The code snippet above uses 9600. You need to change one or both, so they match.

Edited to add: Because the RS232 module is just a driver, you need to connect TX-TX and RX-RX between it and the microcontroller. If you test the cable, you'll find that TX on one end is connected to RX on the other, and vice versa; the tx/rx swap is only done between devices.
 
Oh sorry Nominal animal, i only just noticed you were replying while i was posting that stuff!

So far the value has not changed.

screen 3.jpg

I have just switched the wires so they are rx to rx.
 
I wonder if the manufacturer forgot to mention that updates are only visible after an undocumented end-of-frame sequence, CC 33 C3 3C, is sent. The user manual does say on page 9, explicitly, that no such thing is needed to have the updated values display. Anyway, I guess trying that is worth a go:
Code:
void setup() 
{
    Serial1.begin(9600);
    delay(1500);
}

void updateHMIi16(uint16_t address, int16_t value)
{
     uint8_t  data[12] = { 0xA5, 0x5A,               // Header
                           0x05,                     // Length
                           0x82,                     // Write to var memory
                           (uint8_t)(address >> 8),  // Address high byte
                           (uint8_t)(address),       // Address low byte
                           (uint8_t)(value >> 8),    // Value high byte
                           (uint8_t)(value),         // Value low byte
                           0xCC, 0x33, 0xC3, 0x3C
                         };

    Serial1.write(data, 12);
}

void loop() 
{
    updateHMIi16(0xFFC9, 0x0100);
    delay(500);
    updateHMIi16(0xFFC9, 0x0001);
    delay(500);
}
I do find it quite telling that the example 8051 MCU program in the display datasheets omits the implementation of the en() function, too, which probably corresponds to that. That said, that example program just sends three hex bytes, AA 70 08, documented as "Send the command of picture switching", plus whatever that en() does.

In the user manual, the very first example sequence an MCU is to send to the display is AA 98 00 73 00 B4 22 40 00 F8 00 FF FF 32 35 2E 33 CC 33 C3 3C. Unfortunately, this is the only place where AA or 98 is mentioned in the manual (except for as values in a CRC checksum table implementation); nor does it fit at all in the communications protocol the manual supposedly documents.

If I were you, I would not waste a second longer with such horribly badly documented device. At minimum, I'd email the company, and ask them for a minimal, working Arduino example.
 
Hey Nominal Animal, good news! I took everything to my mates place who has an oscilloscope, turns out the wires were wrong, so snipped off the factory plug, put a new one on there with the wires in the right spot and hey presto your code works! Thankyou so much for your help!

I don't suppose you could give me an example code of how to read info coming from the screen to the arduino as well?

Thanks
Jason
 
Hey Nominal Animal, good news! I took everything to my mates place who has an oscilloscope, turns out the wires were wrong, so snipped off the factory plug, put a new one on there with the wires in the right spot and hey presto your code works!
Nice! I still think the documentation is ... poor, but perhaps the device is workable after all.

I don't suppose you could give me an example code of how to read info coming from the screen to the arduino as well?
According to the user guide, only commands 0x81 (Read register) and 0x83 (Read variable memory) return info coming from the screen (when CRC16 is disabled as discussed earlier in this thread).

If those are only used for initialization and such (for example, to get/set the RTC clock, display version, and such), then a function that sends the request and waits until the response arrives, is sufficient. This is simple to implement, but your microcontroller will be "busy" until the response arrives.

If you need the microcontroller to do other work in the mean time (until the display responds), the receive side can be handled as an interrupt, using a state machine. The response always starts with three bytes (two-byte header, and the number of data bytes to follow), with the first byte of the data indicating the command; the state machine is quite straightforward. However, it is pretty advanced technique.

A third option is to write a function you need to call "often enough" -- meaning, within your main loop. It implements a much simpler state machine for receiving the display responses. First main state is when less than three bytes have been received. When three bytes have been received, the third byte tells the amount of additional data; waiting for enough data to arrive is the second main state. This is quite simple to write, especially if each register or memory read can be handled in that function or a helper function. This is similar to the interrupt, except that knowing that exactly one new character is available, we use[tt] Serial1.available() [/tt]to check how many bytes there are buffered. In general, it is somewhat simpler than the interrupt method, too. However, you must then construct your program as a state machine, running in a loop. This makes a lot of sense for implementing some kind of menu-driven system, but it may feel a bit complicated at first. (It turns out to be the easy way, too, when you get something more complex than a blinky button example running.)

I like the third best, although the first is the simplest one.

So, what do you actually need?
 
I've been mulling over this for a while now. What i'm building is a data logger, any variable change being sent back from the screen would generally be done before the logging starts. Once it is set, you would go out on the track and start logging your session.

However, there is the case where you might forget to change something and go out on the track, then you want to update a variable out there on the run.

The data loggers main thing that i can't interrupt is that it is reading rpm up to 20000rpm with a 2 stroke engine. It needs to maintain that, so the code needs to keep running without delaying to sit and wait for a signal. Maybe even just pick up 1 byte at a time each loop if that's possible might be an option?

A simple example of a variable that might need to be changed is the drivers name. I can have a list of drivers stored on the screen, if i click on change driver, then choose the driver, that button could send the name back to the teensy and update a variable called currentDriver, which i can then use in my logging.

Thanks for your help so far :) very much appreciated!

Jason
 
The data loggers main thing that i can't interrupt is that it is reading rpm up to 20000rpm with a 2 stroke engine.
I assume you have a Hall effect sensor or similar, that produces one or more pulses per revolution? (I haven't worked with combustion engines myself, only with electric motors.) If you feed that (via an optocoupler) to pin 13, you can use the freqCount library included in Teensyduino. The pulse counter is in hardware (for that pin). (If you pick a good optocoupler, you don't need additional buffering, as the output should be able to drive the LED too just fine. 20000 RPM is just 333 pulses per second if you get one pulse per second, so it's pretty low pulse rate in any case; nothing expensive needed.)

Technically, you should read the counter at specific intervals to get the accurate pulse count, but since you are interested in RPM (average frequency during short intervals), you can use the hardware cycle counter, CycCnt, to accurately count the number of clock cycles elapsed during the interval the pulses were counted. Divide the pulse count by the elapsed cycle count, multiply by the clock frequency you use, multiply by 60, and divide by the number of pulses per motor rotation, and you have sampled the motor RPM, without any strict timing requirements.

It looks to me like a main loop, where you check if the display has responded (and if so, act on that), and check the cycle counter if enough time has elapsed to record a new RPM sample, should be pretty straightforward, and quite robust.

Also, I'd definitely log the name changes as part of your log. Just a timestamp and the driver (number?). Makes it easier to detect ham-handed shenanigans. (I don't trust users much...)
 
Ahh so freqCount will work over on the side while the main loop runs?? That will make it easier, though I'd like to keep the main loop running fast still, as there is going to be a bunch of other sensors and also the lap timing.

The rpm pickup is a wire wrapped around the sparkplug lead, with some smoothing hardware, which then runs a transistor to send the signal back to the microcontroller. Though changing the transistor to a optocoupler might be a smart move. I had it working on the arduino using an interrupt, i put it on a car and the results matched the taco.

I haven't started looking at the logging yet, I'm starting with the screen, then the sensors then finally the actual logging. I'm assuming I'd log to SD card on the teensy?
 
Hi Nominal Animal, I've just been re-reading the development guide again, and noticed that when sending from the screen to the teensy that there is an extra command compared to when your sending from the teensy to the screen.

To read from the screen is:

A5 5A Header
Command byte length
83 Read variable register
Variable address
Data word length <-- this one is added.
Data content

Also it seems like text entering has ending flag bytes.

I still haven't managed to write any code to accept the inputs from the screen :S
 
Hi Nominal Animal, I've just been re-reading the development guide again, and noticed that when sending from the screen to the teensy that there is an extra command compared to when your sending from the teensy to the screen.

To read from the screen is:

A5 5A Header
Command byte length
83 Read variable register
Variable address
Data word length <-- this one is added.
Data content

Also it seems like text entering has ending flag bytes.

I still haven't managed to write any code to accept the inputs from the screen :S
 
Ahh so freqCount will work over on the side while the main loop runs?
Yes; counting happens without processor intervention.

The rpm pickup is a wire wrapped around the sparkplug lead, with some smoothing hardware, which then runs a transistor to send the signal back to the microcontroller. Though changing the transistor to a optocoupler might be a smart move. I had it working on the arduino using an interrupt, i put it on a car and the results matched the taco.
Sounds good to me -- although I haven't worked with combustion engines, and you might wish to keep the transistor to ensure it feeds enough current to the optocoupler infrared LED; typically something like 20mA.

I haven't started looking at the logging yet, I'm starting with the screen, then the sensors then finally the actual logging. I'm assuming I'd log to SD card on the teensy?
That is what I'd do. See the Datalogger example in Paul's SD library.


To receive a message from the display, I'd use something like the following. This uses 261 bytes, but supports all possible responses. You can make the buffer smaller if you need to conserve memory; just make sure you never set response_more larger than the buffer size.

The idea is that when header_have < 3, we add another header byte. When we read the third header byte, we initialize the response buffer. When we complete the response buffer, we call a function to handle the response, then reset header_have = response_more = response_left = 0 for the next response.
Code:
#define  DISPLAY_SERIAL  Serial1
#define  DISPLAY_HEADER1  0xA5
#define  DISPLAY_HEADER2  0x5A


static unsigned char  header_have;
static unsigned char  header[2];
static unsigned char  response_more;
static unsigned char  response_have;
static unsigned char  response[255];
static unsigned char  response_pending;

void setup(void)
{
    header_have = 0;
    response_have = 0;
    response_pending = 0;
}

void received_display_registers(unsigned char first, unsigned char data[], unsigned char len)
{
    /* Received 'len' bytes of register contents in 'data[0 .. len-1]',
        with first register being 'first'. */
}

void received_display_value(unsigned short address, unsigned short value)
{
    /* Received 'value' for address 'address'. */
}

static void check_display_response(void)
{
    int  byte;

    while (DISPLAY_SERIAL.available() > 0) {

        byte = DISPLAY_SERIAL.read();
        if (byte < 0)
            return;  /* No additional data */

        if (header_have < 2) {
            header[header_have++] = byte;
            continue;

        } else
        if (header_have == 2) {
            response_have = 0;
            response_more = byte;
            if (byte < 1) {
                /* Zero response length should not occur, but handle that too. */
                header_have = 0;
                response_pending = 0;
            }
            continue;

        } else {
            response[response_have++] = byte;
            if (--response_more < 1) {
                header_have = 0;
                response_pending = 0;

                if (response_have < 2)
                    continue;

                if (header[0] != DISPLAY_HEADER1 || header[1] != DISPLAY_HEADER2)
                    continue;

                if (response[0] == 0x81 && response[2] == response_have - 2) {
                    received_display_registers(response[1], response + 3, response[2]);
                    continue;

                } else
                if (response[0] == 0x83 && response[3] * 2 == response_have - 3) {
                    unsigned short  r0 = response[1]*256 + response[2];

                    for (unsigned char r = 0; r < response[3]; r++)
                        received_display_value(r0 + r, response[4 + 2*r]*256 + response[5 + 2*r]);

                    continue;
                }
            }
        }
    }
}
If you call the above in a loop (that does other stuff too, obviously, like checking your sensors, whether enough time has elapsed to store a new RPM sample, and so on), it will eventually call received_display_registers() and/or received_display_value(). received_display_registers() is called for the entire set of registers received, since they consecutive registers contain interesting values. We could expand that a bit, to handle registers 0x07-0x0A (touch position), 0x0C-0x0F (uptime), and so on.

For example, to detect user touches, it'd make sense to read registers 0x05-0x0A inclusive (six registers) whenever there is no pending command, and no pending response (header_have == 0). Then, changing the end of the above to
Code:
        } else {
            response[response_have++] = byte;
            if (--response_more < 1) {
                header_have = 0;
                response_pending = 0;

                if (response_have < 2)
                    continue;

                if (header[0] != DISPLAY_HEADER1 || header[1] != DISPLAY_HEADER2)
                    continue;

                if (response[0] == 0x81 && response_have == 9 &&
                    response[1] == 5 && response[2] == 6 && response[3] == 0x5A) {
                    if (response[4] == 0x01) {
                        display_touch_press(response[5] + response[6]*256, response[7] + response[8]*256);
                    } else
                    if (response[4] == 0x03) {
                        display_touch_move(response[5] + response[6]*256, response[7] + response[8]*256);
                    } else
                    if (response[4] == 0x02) {
                        display_touch_release(response[5] + response[6]*256, response[7] + response[8]*256);
                    }
                    continue;

                } else
                if (response[0] == 0x81 && response[2] == response_have - 2) {
                    received_display_registers(response[1], response + 3, response[2]);
                    continue;

                } else
                if (response[0] == 0x83 && response[3] * 2 == response_have - 3) {
                    unsigned short  r0 = response[1]*256 + response[2];

                    for (unsigned char r = 0; r < response[3]; r++)
                        received_display_value(r0 + r, response[4 + 2*r]*256 + response[5 + 2*r]);

                    continue;
                }
            }
        }
    }
}
would cause display_touch_press(x, y) to be called whenever the user touches the display; display_touch_move(x, y) if the user still touches the display, and display_touch_release(x, y) when the user lifts their finger from the display -- assuming you send the 0xA5 0x5A 0x03 0x83 0x05 0x06 register request often enough (whenever response_pending==0; set it to nonzero whenever you send a register or memory read that the display responds).

It would make a lot of sense to write the serial commands/responses into a library (with callback functions for touches and register updates), but without such a display to test, it's not fun to write code without being able to test or verify it.
 
Wow iv'e read this so many times tonight and i still haven't really wrapped my head around it!

This is how i'm understanding it at the moment in very basic terms... to change a variable name or number in the teensy, i would need to call void received_display_value in the loop, which will give me the address and the new data? I don't think i would need the void received_display_registers as that is just the header and data length? Am i on the right track there?

The next part about touch position i'm not to sure i understand at all to be honest.. Do you mean use a touch event to start looking for incoming data?

If i'm on the right track, and i want to change a name, if we add a char 'name' to the code, lets say we change the name to Barry on the screen and press enter. And the variable address it is stored in is 0001.

Code:
#define  DISPLAY_SERIAL  Serial1
#define  DISPLAY_HEADER1  0xA5
#define  DISPLAY_HEADER2  0x5A


static unsigned char  header_have;
static unsigned char  header[2];
static unsigned char  response_more;
static unsigned char  response_have;
static unsigned char  response[255];
static unsigned char  response_pending;

char name;  //We want this name to change to Barry

void setup(void)
{
    header_have = 0;
    response_have = 0;
    response_pending = 0;
}

void received_display_registers(unsigned char first, unsigned char data[], unsigned char len)
{
    /* Received 'len' bytes of register contents in 'data[0 .. len-1]',
        with first register being 'first'. */
}

void received_display_value(unsigned short address, unsigned short value)
{
    /* Received 'value' for address 'address'. */
}

static void check_display_response(void)
{
    int  byte;

    while (DISPLAY_SERIAL.available() > 0) {

        byte = DISPLAY_SERIAL.read();
        if (byte < 0)
            return;  /* No additional data */

        if (header_have < 2) {
            header[header_have++] = byte;
            continue;

        } else
        if (header_have == 2) {
            response_have = 0;
            response_more = byte;
            if (byte < 1) {
                /* Zero response length should not occur, but handle that too. */
                header_have = 0;
                response_pending = 0;
            }
            continue;

        } else {
            response[response_have++] = byte;
            if (--response_more < 1) {
                header_have = 0;
                response_pending = 0;

                if (response_have < 2)
                    continue;

                if (header[0] != DISPLAY_HEADER1 || header[1] != DISPLAY_HEADER2)
                    continue;

                if (response[0] == 0x81 && response[2] == response_have - 2) {
                    received_display_registers(response[1], response + 3, response[2]);
                    continue;

                } else
                if (response[0] == 0x83 && response[3] * 2 == response_have - 3) {
                    unsigned short  r0 = response[1]*256 + response[2];

                    for (unsigned char r = 0; r < response[3]; r++)
                        received_display_value(r0 + r, response[4 + 2*r]*256 + response[5 + 2*r]);

                    continue;
                }
            }
        }
    }
}

What would i need to do to get the char name; to change to Barry?

but without such a display to test, it's not fun to write code without being able to test or verify it.
Sorry to be such a pain! I do wish there was a library for it, as its the only screen i've found that has all the graphics stored on the screen, with reasonably easy to use software, has a bright enough display, and isn't extremely laggy. So it has the ingredients to be a great screen, but programming it is sure doing my head in!!
 
This is how i'm understanding it at the moment in very basic terms... to change a variable name or number in the teensy, i would need to call void received_display_value in the loop, which will give me the address and the new data? I don't think i would need the void received_display_registers as that is just the header and data length? Am i on the right track there?
No.

The idea is that you have a loop that checks the various sensors, and also calls check_display_response(). That function checks if any characters are received (buffered) from the device, and if so, handles the responses.

To detect touches on the display, you need to check the registers 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A. You can do this in one register read. Do that whenever response_pending is nonzero, after calling check_display_response(); also set response_pending nonzero after a successful write. The request to the display is six bytes, 0xA5 0x5A 0x03 0x83 0x05 0x06.

The next part about touch position i'm not to sure i understand at all to be honest.. Do you mean use a touch event to start looking for incoming data?
When a human pokes a finger to the display, moves their finger on the display, or removes their finger from the display surface, the display does not automatically send any data. You need to check the registers 05..0A to detect if one of those events has happened.

I don't know how strings are stored on the display, so I don't know how one would "change a name" on the display.

Why don't you get an USB RS232 dongle, and connect your computer to the display? Use e.g. Python (and pyserial) to open a serial connection to the display, and then see what it sends.

Sorry to be such a pain! I do wish there was a library for it, as its the only screen i've found that has all the graphics stored on the screen, with reasonably easy to use software, has a bright enough display, and isn't extremely laggy. So it has the ingredients to be a great screen, but programming it is sure doing my head in!!
It's also hard to help with it, because the only reference, the manual, is quite horrible.

In particular, at one point the manual says that for two-byte values, the high byte is sent first. However, later on, in an example byte sequence, 0x0005 is shown as 05 00 (low byte first). Contradictory information is annoying: which one is right?
 
I did some testing, I didn't try python as i've never tried it before, but i just did a serial read and print to serial monitor in the arduino ide. Hopefully you understand the results because im fairly confused..

So i set a button on the screen to send a variable. The variable location is FFCF, and it is sending 1111

variable.jpg

I used this code to receive the variable and then print it (a code i found online here https://forum.arduino.cc/index.php?topic=396450)

Code:
char receivedChar;
boolean newData = false;

void setup() {
    Serial.begin(9600);
    while (!Serial){}
    delay(1000);
    Serial.println("<Arduino is ready>"); 
    Serial1.begin(9600);
   while (!Serial1) {}
 pinMode(13,OUTPUT);
}

void loop() {
    recvOneChar();
    showNewData();
}

void recvOneChar() {
    if (Serial1.available() > 0) {
        receivedChar = Serial1.read();
        newData = true;
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChar);
        newData = false;
    }
}

This was the result in serial monitor.

variable1.jpg

I changed the code slightly from Serial.println(receivedChar); too Serial.println(receivedChar,HEX);

variable2.jpg

And finally changed it again to Serial.println(receivedChar,BIN);

variable3.jpg


When i did the Serial.println(receivedChar,HEX) it seems to make sense, its showing mostly what i was expecting except has alot of FFFF printed in front of some of the figures that confuses me a bit.

Jason
 
So i set a button on the screen to send a variable. The variable location is FFCF, and it is sending 1111
Right, so the display does send a report itself as well. A5 5A 06 83 FF CF 01 11 11 can be written as A5 5A 06: 83: FF CF: 01: 11 11, meaning you get a six-byte payload, memory receive (83) for that address (FF CF, most significant byte first), report containing one value: 0x1111.

My example code above should be able to handle those just fine; you should see it call received_display_value(0xFFCF, 0x1111) when you press that button.

When i did the Serial.println(receivedChar,HEX) it seems to make sense, its showing mostly what i was expecting except has alot of FFFF printed in front of some of the figures that confuses me a bit.
That is due to integer promotion rules. Essentially, the char variable gets promoted to integer type when calling the function. Since it is signed (by default in this case), it is sign extended.

To fix, use Serial.println(receivedChar & 255, HEX); to restrict the printed value to 8-bit range, 0 .. 255 inclusive.
 
Status
Not open for further replies.
Back
Top