CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Read String RS232

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
AndresRam



Joined: 27 May 2017
Posts: 16
Location: Colombia

View user's profile Send private message

Read String RS232
PostPosted: Sat Sep 16, 2017 4:53 pm     Reply with quote

Hello, I would greatly appreciate an orientation.
I am trying to read the data or variables sent by a NEXTION display.

All right. It sends via RS232 the following string:
0x3B 0x00 0x00 0x00

These values are the number "59".

What I need is to store that string in a variable with the value "59" in the microcontroller.

I attach the routine in which I am working but I can not get any value.

The purpose of the routine is to read and store the data received in a buffer, wait 10 seconds and then transmit the stored value again via RS232.
Remember: I receive data in the following form: 0x3B 0x00 0x00 0x00 and I must forward it from the PIC to the screen in the form "59".

Code:

#include <16F1937.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=8000000)

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PORTC)
#use rs232(baud=9600,parity=N,xmit=PIN_C1,rcv=PIN_c0,bits=8,stream=PORTB)

#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;

#int_rda
void serial_isr() {
   int t;

   buffer[next_in]=getc();
   t=next_in;
   next_in=(next_in+1) % BUFFER_SIZE;
   if(next_in==next_out)
     next_in=t;           // Buffer full !!
}

#define bkbhit (next_in!=next_out)

BYTE bgetc() {

   BYTE c;
   while(!bkbhit) ;
   c=buffer[next_out];
   next_out=(next_out+1) % BUFFER_SIZE;
   return(c);
   }

void main() {

   enable_interrupts(int_rda);
   #if defined(__PCD__)
   enable_interrupts(intr_global);
   #else
   enable_interrupts(global);
   #endif
   
                 // The program will delay for 10 seconds and then send
               // any data that came in during the 10 second delay
 
   do {
      delay_ms(10000);
      printf("\r\nBuffered data => ");
      while(bkbhit)
      putc( bgetc() );
     
   } while (TRUE);
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Sep 16, 2017 8:42 pm     Reply with quote

Do you really get ASCII spaces inbetween bytes ?
And do you really get "0x" in ASCII characters in front of each byte ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Sun Sep 17, 2017 1:19 am     Reply with quote

You say you 'cannot get any value'. Yet you also say 'I receive data in the following form'. So are you receiving the data and seeing it on a terminal?. If this is not happening, then nothing we can say applies.....
I'm guessing you are actually displaying in Hex mode on a terminal. This is what PCM_Programmer is trying to work out. If the data is actually coming in hex as you show, then things get more complex.

Assuming you are just displaying in Hex mode, then this is not a 'string'. The unit is sending a simple int32. However the format is very 'suspect', unless there is something to mark the boundaries between the data. Problem is that if any byte is missed, the code can never recover....
Looking at the NEXTION manual, the only values the language itself returns as raw int32 numbers, are things like numbers read from the EEPROM. So presumably somebody has written a program which is running in the NEXTION and sending this data. If so, then they ought to 'rethink', and work out an alternative way of sending the data that does carry some form of marker to ensure synchronisation. Otherwise 'long term', this is a disaster waiting to happen....

So assuming that is returning an int32 like this, you would simply need something like:
Code:

   int32 val=0;
   int8 ctr=0;
   
   do {
      if (bkbhit)
      {
          val*=256;
          val+=bgetc(); //add one byte to the int32
          ctr++;
          if (ctr==4) 
          {
              //We have received 4 bytes so number is complete
              printf("%lu", val); //print the number
              ctr=0; //reset for the next value
              val=0;
          }
      }
   } while (TRUE);
}
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Sep 17, 2017 4:50 am     Reply with quote

I have to ask is the hardware correct? I seem to recall that MMI is a 3 volt device on the serial lines though needs 5 to run, so how have you conected the PIC to it? What voltage is the PIC powered by?
Do you have the proper 'MAX232' devices installed?

Just need to confirm the HARDWARE is right BEFORE debugging code !

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Sun Sep 17, 2017 8:13 am     Reply with quote

Yes.

Though it's a 5v device, this is used for the display, not the logic.

3.2v as the output high. So a buffer would be needed to talk to a normal 5v PIC serial input.
AndresRam



Joined: 27 May 2017
Posts: 16
Location: Colombia

View user's profile Send private message

PostPosted: Sun Sep 17, 2017 5:47 pm     Reply with quote

Thank you all so much for your help.

I will answer the questions I know (what I do not know, I will do to the manufacturer of the display):

I already have communication with the display and it is not a problem of hardware. in fact sending PIC data to the display are perfect and it is checked.

The problem is when I tell the display to send me the value of a variable to the PIC, since it does so in the way mentioned.

The programming software of the Nextion display has a simulator. and when I give the order to send some variable (number) the following are observed:
" Simulator return data: 0x15 0x23 0x00 0x12 "

On the other hand,
The datasheet of display say:
"the device will directly return the variable’s 4-byte hexadecimal data, value is stored as little-endian mode (ie low level in the front, high level at the back )."

Now, there are options to send this value, with an initial and final data:

0X71 + variable binary data (4 bytes little endian mode, low in front) + End, for example:

0X71 0X66 0X00 0X00 0X00 0XFF 0XFF 0XFF

"0XFF 0XFF 0XFF" is the "end"
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Sep 17, 2017 5:56 pm     Reply with quote

That quote comes from this page here, and it comes from the Remarks section:
https://www.itead.cc/wiki/Nextion_Instruction_Set
Quote:

Remarks:

1. When the variable obtained by using print command is string type,
the device directly returns string ASCII; if it is numeric type (such as
progress val property), the device will directly return the variable’s 4-byte
hexadecimal data, value is stored as little-endian mode (ie low level in the
front, high level at the back).

The implication is that your data in your first post is really sent as this:
Code:
3B00000

It's not in ASCII. It's four bytes of data. Do we know if this is true, for sure ?
I have read several webpages on the Nextion and I can't find any
of them that flat out says what the real form of the output data is.
AndresRam



Joined: 27 May 2017
Posts: 16
Location: Colombia

View user's profile Send private message

PostPosted: Sun Sep 17, 2017 8:06 pm     Reply with quote

Ok, I already made some inquiries in the forum of the MANUFACTURER and this I have answered:


Okay, considering your background
I think the piece you maybe missing is a programming fundamental

10 even time width electrical pulses on a wire make up a byte
- start bit always low
- 8 data bits (sent least significant first)
- stop bit always high

of the 8 data bits, although does make a byte ... but also an unsigned char
It is how you format the data structure as to how you see/view it

0x02 0x00 0x00 0x00 would be 32-bit or 4 bytes (in little endian order)
decimal value 2, binary 10, as a char not printable, as hex 02, as octal 002
Hex is chosen as all values from 0 to 255 can be seen
noted by the prefix "0x", the next two chars are hexadecimal or 4 bit nibbles

If you were to loop Nextion output to a serial terminal
the values 0 to 31 and others are not printable and empty - therefore missing
So hex is the standard that is used.
So you actually are indeed seeing exactly what will be returned



I hope this clarifies how to send the data to be able to treat them in the PIC.
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Sun Sep 17, 2017 11:23 pm     Reply with quote

There is also the second question.

You say "sending PIC data to the display are perfect and it is checked", but not whether the PIC is actually seeing the replies?.

The communication from the PIC to the display _will work_. It is communication from the display to the PIC that may well have signal level problems.
How have you tested this?.
Have you done it using interrupt driven serial as you are showing in your code here?.

Now there is a major fault in your code - you are using streams, but not reading streams. The line to get characters in the interrupt, needs to be:

buffer[next_in]=fgetc(PORTC);

and assuming you mean to be sending the data to the second software port, the output line need to be:
Code:

      fprintf(PORTB,"\r\nBuffered data => ");
//etc...

Currently the I/O won't be working.

I also think it very dangerous to be using stream names that correspond to hardware register names in the PIC. Call them something like

"NEXTION", and (assuming the output is for debugging), "DEBUG".

Even if the display comms is working, if you are running the PIC off 5v, this will be a matter of luck, and you need to rethink, if this is going to be reliable long term....
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Mon Sep 18, 2017 2:33 am     Reply with quote

I decided to modify your code, so assuming that the second serial is a debug output, we will see what is actually being received:

Code:

#include <16F1937.h>
#fuses HS,PLL_SW,NOWDT,NOPROTECT,NOLVP
#use delay(clock=8000000)

#use rs232(UART1,baud=9600,parity=N,bits=8,ERRORS,stream=DISPLAY)
#use rs232 (baud=9600,parity=N,xmit=PIN_C1,rcv=PIN_c0,bits=8,stream=DEBUG)

#define BUFFER_SIZE 32
char buffer[BUFFER_SIZE];
int8 next_in = 0;
int8 next_out = 0;
int8 count=0;

#int_rda
void serial_isr(void)
{
   int8 t;

   buffer[next_in]=fgetc(DISPLAY);
   t=next_in;
   if (++next_in==BUFFER_SIZE)
      next_in=0;
   if (next_in==next_out)
      next_in=t;           // Buffer full - throw oldest char
   else
      ++count;
}

#define bkbhit (count!=0)

char bgetc(void)
{
   char c;
   while(!bkbhit)
      ;
   c=buffer[next_out];
   if (++next_out==BUFFER_SIZE)
      next_out=0;
   count--;
   return(c);
}

void main(void)
{
   enable_interrupts(int_rda);
   enable_interrupts(global);
 
   //Simply output data when four bytes have been seen
   do
   {
      while (count<4)
         ;
      while (bkbhit)
      {
          fprintf(DEBUG,"%02X ",bgetc());
      }
   } while (TRUE);
}

This will wait for four bytes, and echo these _in hex_ to the debug serial.

If this does not work, then you have a receive serial level problem.

Also your code as posted would not work. You have the PLL enabled, so if it was using an 8MHz crystal, it'd be trying to run at 32MHz, and all the timings would be wrong. I have disabled this. This is why we commonly say the first thing you must do when trying to write code, is the 'flash an LED' test, to verify the clock is doing what you expect.
AndresRam



Joined: 27 May 2017
Posts: 16
Location: Colombia

View user's profile Send private message

PostPosted: Tue Sep 19, 2017 8:56 am     Reply with quote

Hello gentlemen, thank you very much.

Between yesterday and today I have been "nailed" working to the routine and I have not been successful.

I have already organized some things that you have suggested to me how to configure the PPL and properly call the transmission functions with the respective Stream name.

I already checked the communication and hardware between the screen and the pic, everything is OK.

Find a routine in Arduino that reads the "string" I want to read. I also connected the screen to a serial monitor on the PC and I can see exactly the "string" that transmits it. I hope this can guide you to try to know how to receive the data in the PIC.
Code:

unsigned int Nextion::getComponentValue(String component){
  String getValue = "get "+ component +".val";//Get component value
    unsigned int value = 0;
  sendCommand(getValue.c_str());
  uint8_t temp[8] = {0};
  nextion->setTimeout(20);
  if (sizeof(temp) != nextion->readBytes((char *)temp, sizeof(temp))){
    return -1;
  }//end if
  if((temp[0]==(0x71))&&(temp[5]==0xFF)&&(temp[6]==0xFF)&&(temp[7]==0xFF)){
    value = (temp[4] << 24) | (temp[3] << 16) | (temp[2] << 8) | (temp[1]);//Little-endian conversion
  }//end if
  return value;
}//get_component_value */


NOTE: The above code is for arduino. Attach the URL where the whole library is, inside this function: "getComponentValue" which is the one I previously put.
Keep the following in mind in order to interpret the code:

The display has the option to send 0x71 + [four hex] + 0xff + 0xff + 0xff
0x71: means that you are sending a numerical value
[four hex]: the variable we want to get in the micro, converted into the format 0x00 0x00 0x00 0x00
0xff + 0xff + 0xff: means end of data transmission

https://github.com/bborncr/nextion/blob/master/Nextion.cpp

Warmest regards.
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Wed Sep 20, 2017 1:13 am     Reply with quote

If you look at the Arduino code, it sends the command 'get' to the Nextion, with the attribute value it want, to get the reply. (get n0.val). No wonder you don't see anything on the PIC without this.....

I'd honestly suggest reading the Nextion manual.

The routine I've already posted:
Code:

   do {
      if (bkbhit)
      {
          val*=256;
          val+=bgetc(); //add one byte to the int32
          ctr++;
          if (ctr==4)
          {
              //We have received 4 bytes so number is complete
              printf("%lu", val); //print the number
              ctr=0; //reset for the next value
              val=0;
          }
      }
   } while (TRUE);


Will read the reply from The Nextion (_with the big proviso, that I think you will find you really do need a hardware buffer for the PIC to actually see this value, or need to be running the PIC at 3.3v_), once the command is sent to the Nextion, but without the command nothing is going to be sent.
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Wed Sep 20, 2017 8:25 am     Reply with quote

So:

Code:

//crude timeout exit with zero value
#define TIME_OUT    delay_us(20); if (timeout++>10000) return 0

unsigned int32 getComponentValue(char * component)
{
    char temp_str[20]; //temporary buffer
    unsigned int16 timeout=0;
    unsigned int32 value=0;
    unsigned int32 mask=1;
    unsigned int8 ctr=0;
    strcpy(temp_str, "get "); //get command & space
    strcat(temp_str, component); //add component name
    strcat(temp_str, ".val\0xFF`0xFF,0xFF"); //and the .val plus terminator
    //Now have the array built to send

    fprintf(NEXTION,"%s"); //send the command
    //Now need to wait for the 0x71 reply

    do
    {
        if (bkbhit)
        {
            if (bgetc()==0x71)
                break; //reply has started
        }
        TIME_OUT; //will exit routine with '0' if comms times out
    } while (TRUE);
    //Now have read the 0x71, so can read the data
    timeout=0;
    do
    {
        if (bkbhit)
        {
            val+=(bgetc()*mask); //add one byte to the int32
            mask*=256;
            ctr++;
            if (ctr>=4)
            {
                break; //finished the numeric value
           }
       }
       TIME_OUT;
    } while (TRUE);
    //Now need to throw the three 0xFF bytes
    timeout=0;
    ctr=0;
    do
    {
        if (bkbhit)
        {
            if (bgetc()==0xFF)
                ctr++; //terminator byte
        }
        if (ctr>=3)
           return value; //finished
        TIME_OUT;
    }
}


Used with the existing buffer handling code, and assuming that the PIC can actually see the serial data (understand 'why' I keep saying this - the PIC has a higher input threshold voltage than the Arduino, or Pi, on the serial receive. It needs the voltage to get up to 0.8*Vdd to be seen as a '1' by the serial - the Nextion will not do this for a PIC at 5v....), with #device PASS_STRINGS=IN_RAM, added to the chip setup, this would accept a command like:

Code:

    reply=getComponentValue("dim");


To read the display brightness value for example.

I've probably got some typing errors, 'typed untried' here.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group