2
\$\begingroup\$

I need to pass integer values from one PIC to another through serial port

for char I can use the following code

char data1='a';
TXREG=data1;                                     
while(PIR1.TXIF==0); 

but when I try to pass int type variable it returns an ASCII equivalent..

Is there anyway to receive the data as integer instead of char type?

\$\endgroup\$
  • \$\begingroup\$ What do you mean by "pass int type variable"? Are you trying to send a value larger than 8 bits over the UART peripheral? If so, show your code. \$\endgroup\$ – Dan Laks Dec 17 '14 at 18:50
  • \$\begingroup\$ No. I nee to send int values ranging from 0 to 64.. that comes under 8bit only. The code is shown above.. i tried to pass the int type variable there as i've stated in the ques.. \$\endgroup\$ – Suraj Bhawal Dec 17 '14 at 18:58
  • \$\begingroup\$ How are you confirming the ASCII equivalent of the value is arriving at the receiving PIC? \$\endgroup\$ – Dan Laks Dec 17 '14 at 19:01
  • \$\begingroup\$ By transmitting the received data then see the output from my pc using serial port \$\endgroup\$ – Suraj Bhawal Dec 17 '14 at 19:03
  • \$\begingroup\$ Ah, you're displaying the data on a terminal emulator. That's an important piece of information you left out of your question. So, to clarify, if you send the numeric value 55 (for example), you're seeing a "7" show up on your computer screen? \$\endgroup\$ – Dan Laks Dec 17 '14 at 19:05
7
\$\begingroup\$

You already are sending integer values over the UART with the code you show. Your problem is apparently sending integers that are more than 8 bits wide.

The UART inherently only sends 8 bit bytes (in the most common configuration) at a time. If you want to send a wider integer, you have to send more than one byte to represent that integer. For example, you might decide that all multi-byte integers are to be sent in least to most significant byte order. If you have a 16 bit integer to send, then you send the low 8 bits first, then the high 8 bits. The receiving PIC does the reverse. It receives the low 8 bits first, then the high 8 bits, and writes those consecutively in memory so that the rest of the system can access the value as a 16 bit integer.

24 bit integers, for example, are sent the same way except that 3 bytes are needed instead of 2. 32 bit integers require sending 4 bytes.

Note that none of this has anything to do with sending numeric values to show up on a terminal emulator. Terminals display characters. Each possible character has a pre-determined binary code. You send the byte containing the code for a character, and that character shows up on the terminal. For example, the code for the letter "A" is 65. If you send the byte 65, then a terminal will show "A". Likewise, sending 48 causes the terminal to show "0". Look up something called ASCII code. That will tell you what the byte values are for each of the characters the terminal can show.

Here is a example to illustrate all of the above. Suppose you wanted to send the 16 bit integer value 9525. Let's convert that to HEX so we can see the individual bytes easily: 2535h. You have previously decided to send multi-byte values in low to high byte order. The two bytes you will send are therefore 35h and 25h in that order. These have the decimal values 53 and 37. You send these bytes, and the other PIC receives 53 and 37. Note that (37 * 256) + 53 = 9525, which is the value you are transmitting.

If these bytes were to be intercepted by a terminal, then you'd get whatever characters map to 53 and 37, which happen to be "5" and "%". So the terminal will display "5%" when you send 9525. If you wanted the terminal to display "9525" you'd have to send the byte values for the characters "9", "5", "2", and "5". Those happen to be 57, 53, 50, and 53. That is a lot more complicated since the PIC has to figure out the decimal digits of the binary integer it has, convert them to the character codes for those digits, then send those.

Generally it's a lot easier to do any kind of user interface conversion on the PC and let the PIC send and receive native binary. Converting the binary integer 9525 to the characters "9525" is trivial for the PC, but can require substantial code space and cycles on a small PIC.

\$\endgroup\$
  • \$\begingroup\$ Olin, wow, you really invest some effort into these explanations. Anyway, when I need to deal with a channel that has some equipment that does translations on data, such as modems or rs-to-ethernet converters etc, I often send a byte b with two characters as 'A'+(b>>4) and 'a'+(b&0xf). So 0 will be "Aa", 1 will be "Ab", 16 will be "Ba" etc. It's easy to translate and the capital letter vs small letter bit (bit 5) serves as a rudimentary sync bit so that if the communication is interrupted, at least the bytes are aligned correctly. I'm not expecting any applause, but it's worked for me... \$\endgroup\$ – PkP Dec 17 '14 at 20:22
  • \$\begingroup\$ @PkP That's actually a really cunning way of doing it. You have basically created your own bit-level packet, with a recognizable start sequence. You could fit more data in by encoding as two 7-bit values, with the 8th bit of the first byte as the "start" bit. \$\endgroup\$ – Majenko Dec 17 '14 at 23:14
  • \$\begingroup\$ @Olin thanks that's a really nice explaination... btw i only need to send 8bit integer values... can u show me send/receive codes cuz i can't seems to find anywhere! \$\endgroup\$ – Suraj Bhawal Dec 18 '14 at 4:02
  • \$\begingroup\$ @SurajBhawal I have updated my answer to deal with 8-bit values rather than 16. \$\endgroup\$ – tcrosley Dec 18 '14 at 4:26
  • \$\begingroup\$ @Suraj: 8 bit values fit in single bytes, so just send them. \$\endgroup\$ – Olin Lathrop Dec 18 '14 at 14:14
4
\$\begingroup\$

If you send a single 8-bit value from a UART to another computer, it will just be a binary value. Lets say you had a number like 52.

char data = 52;        // or char data = 0x34;

and sent the data over the UART;

TXREG = data;
while(PIR1.TXIF==0);

If you hooked a terminal program like RealTerm, set it up to receive your data, and set the Display As to Hex[space] it will show the value in hexadecimal as:

34

since hex 34 (3*16 + 4) is the same as 52. If you changed the display to ASCII, it would instead show just a 4 since the ASCII code for 4 is 0x34, which is an incorrect representation for the value that was sent.

Next, you can send the 8-bit value in hex, one 4-bit nibble at a time:

char data = 52;    // or char data = 0x34;

TXREG = (data & 0xf0) >> 4;
while(PIR1.TXIF==0);

TXREG = data & 0x0f;
while(PIR1.TXIF==0);

This could be put into a loop, but it's easier to see this way.

To display the characters, once again you need to put RealTerm into Hex[space] mode. The nibbles will then display on the screen as 03 04. Since these are not proper ASCII digits, they will not show up properly under the ASCII display setting.

If you want to see actual ASCII characters, you will need to add a character '0' (0x30) to each value, like this:

char nibble;
nibble = ((data & 0xf0) >> 4) + '0';

However this will only work for values 0-9; hex values A-F won't be displayed correctly since 9 and A are not next to each other in the ASCII alphabet. So you have to add in an if statement to handle this:

char data = 52;    // or char data = 0x34;
char nibble;

nibble = ((data & 0xf0) >> 4) + '0';
if (nibble > '9') nibble += 'A' - '9';
TXREG = nibble;
while(PIR1.TXIF==0);

nibble = (data & 0x0f) + '0';
if (nibble > '9') nibble += 'A' - '9';
TXREG = nibble;
while(PIR1.TXIF==0);

Now the digits will show up on the ASCII display as 34.

There's one more way to do this, and that is to send the value as decimal characters. That requires a conversion from the binary number 52 (or 0x34) to an equivalent string representation of the decimal number, in this case "52". There are a couple of ways to do this in C, one is itoa (integer to ASCII), and the other is sprintf. Either one is going to need a bit of library code, which, depending on the flash size of your microcontroller, may or may not be an issue.

Here is how to do it using sprintf:

char buf[5];    
char data = 52;       // or char data = 0x34;
unsigned char i;

sprintf(buf,"%d",data);

i = 0;
while (buf[i]!='\0')
{
    TXREG = buf[i++];
    while(PIR1.TXIF==0);
}

The printf converts the value in data to decimal (because of the %d) and stores it as ASCII characters in the character array buf. The maximum size of the number is four characters, since a signed 8-bit number can go from -127 to 128. C strings are terminated with a '\0' (null) so the array has to have five elements. The while loop then sends out characters until the null character is reached.

\$\endgroup\$
3
\$\begingroup\$

To send an integer value over the UART you have to send 2 bytes. For example:

int data = 0x1234;
TXREG = data & 0xff;
while(PIR1.TXIF==0); 
TXREG = (data >> 8) & 0xff;
while(PIR1.TXIF==0);
\$\endgroup\$
  • \$\begingroup\$ I thought this is what the OP was confused about at first as well, but from discussion in the comments, it doesn't seem to be the case. He/She is displaying the values on a terminal emulator, which is converting the transmitted values into ASCII symbols. \$\endgroup\$ – Dan Laks Dec 17 '14 at 19:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.