Author Topic: [PIC] Converting SFR/GPR values to strings  (Read 7097 times)

0 Members and 1 Guest are viewing this topic.

Offline iconTopic starter

  • Regular Contributor
  • *
  • Posts: 246
[PIC] Converting SFR/GPR values to strings
« on: March 22, 2014, 08:53:54 pm »
Hi

There's probably something really obvious I can do, but I can't spot it in the XC8 compiler manual, though there are loads of 'nearly' library routines available. I'm just trying to print a byte (char?) value to an LCD module, so I need to convert it to (up to) 3 ASCII characters. So 0xFF becomes '2','5','5', for example.

Hey; makes a change from an LED blinking...

Thanks
John


 

Offline iconTopic starter

  • Regular Contributor
  • *
  • Posts: 246
Re: [PIC] Converting SFR/GPR values to strings
« Reply #1 on: March 22, 2014, 09:14:42 pm »
Thinking about it a bit more, I think it comes down to binary to 3 byte BCD conversion, and  then adding '0' (as opposed to 0) to each?

Or might there be less/more to it?

John
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: [PIC] Converting SFR/GPR values to strings
« Reply #2 on: March 22, 2014, 09:15:16 pm »
Fairly simple:

Code: [Select]
  sRAM[2]=(val % 10) + '0'; val /= 10;  //convert the lowest digit
  sRAM[1]=(val % 10) + '0'; val /= 10;
  sRAM[0]=(val % 10) + '0';  //convert the highest digit

It can be applied for other approaches as well.

Alternatively, you can use a look-up table - more space intensive but faster.
================================
https://dannyelectronics.wordpress.com/
 

Offline mariush

  • Super Contributor
  • ***
  • Posts: 5018
  • Country: ro
  • .
Re: [PIC] Converting SFR/GPR values to strings
« Reply #3 on: March 22, 2014, 09:43:11 pm »
One version would be using sprintf.
If you don't want to add the complexity of stdio.h in your project, you can do as above.  Alternatively ... a couple of while (number > 100) , while ( number > 10 ) ... but more cycles wasted.
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: [PIC] Converting SFR/GPR values to strings
« Reply #4 on: March 22, 2014, 09:53:46 pm »
Thinking about it a bit more, I think it comes down to binary to 3 byte BCD conversion, and  then adding '0' (as opposed to 0) to each?

Or might there be less/more to it?

John

I like that approach, danny's code will work but here is how I would do it if you don't want to link with the modulus and division functions.

and mariush approach of using 2 while loops will work nice too.

Code: [Select]
   // hard coding input but this will come from the value to be converted.
   unsigned char in_val = 255;
   unsigned short accumulator=0;
   unsigned short count=8;
   char digits[3];

   while(count) {
      // shift accumulator left.
      accumulator <<=1;
      // if most significant bit in in_val is one
      // increment the accumulator, otherwise the shift was enough
      if(in_val&0x80) {
         accumulator++;
      }
      // Edit, no adjustment needed on the last loop
      if (count == 1) break;
      // check for adjustments (only 2 places since we are converting 0-255)
      if((accumulator&0x00f) > 0x004) {
         accumulator+=0x003;
      }
      if((accumulator&0x0f0) > 0x040) {
         accumulator+=0x030;
      }
      // shift in_val left chopping the already used most significant bit.
      in_val<<=1;
      count--;
   }

   // accumulator will now have 0000 0010 0101 0101
   for(count=0;count<3;count++) {
      digits[count] = (accumulator&0x000f)+'0';
      // you can early out and don't do the last shift if count is 2
      // if (count == 2 ) break;
      accumulator >>= 4;
   }

Edit added parenthesis on the adjustment comparisons and added an early out on the last loop so it wouldn't adjust the last result.

But I like mariush approach better even if it's probably less efficient as in expandable to larger BCD numbers, but it's more readable and doesn't use that many more cycles:

Code: [Select]
   unsigned char in_val = 255;
   char digits[3];

   digits[0] = digits[1] = digits [2] = '0';
   while (in_val > 99) {
      digits[2]++;
      in_val -= 100;
   }

   while (in_val > 9) {
      digits[1]++;
      in_val -= 10;
   }

   digits[0] += in_val;


edit, fixed code
« Last Edit: March 23, 2014, 12:23:40 am by miguelvp »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: [PIC] Converting SFR/GPR values to strings
« Reply #5 on: March 22, 2014, 11:13:03 pm »
Quote
while (in_val > 100) {

Quote
while (in_val > 10) {

Does that really work?
================================
https://dannyelectronics.wordpress.com/
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: [PIC] Converting SFR/GPR values to strings
« Reply #6 on: March 23, 2014, 12:01:41 am »
Quote
while (in_val > 100) {

Quote
while (in_val > 10) {

Does that really work?

yup, here is my debug output of the result:
Code: [Select]
- digits 0x0013ff70 "552Ì"
[0] 53 '5'
[1] 53 '5'
[2] 50 '2'

You are right, should be 99 and 9, fixed the code above
« Last Edit: March 23, 2014, 12:24:39 am by miguelvp »
 

Offline mariush

  • Super Contributor
  • ***
  • Posts: 5018
  • Country: ro
  • .
Re: [PIC] Converting SFR/GPR values to strings
« Reply #7 on: March 23, 2014, 12:03:05 am »
yeah, it should work.

if not, he can do something like this :

unsigned char number;
unsigned char digits[3];

for (number=original_number;number > 100;number=number-100) digits[0]++;
for (;number > 9;number=number-10) digits[1]++;
digits[2] = number;
 
or something like that.

I didn't check which syntax is converted in less bytes of program or fewer instructions. PIC chips do have div and mod and that code will probably result in the smallest instruction count (fewest cycles lost) but I can't tell for sure.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: [PIC] Converting SFR/GPR values to strings
« Reply #8 on: March 23, 2014, 12:35:48 am »
Quote
yeah, it should work.

Think about what happens when the number is multiples of 100 or 10 or the combinations of the two.
================================
https://dannyelectronics.wordpress.com/
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: [PIC] Converting SFR/GPR values to strings
« Reply #9 on: March 23, 2014, 12:48:59 am »
yeah, I already changed my implementation above.
Not proficient in PIC assembler, but this is his algorithm for an x86, the compiler doesn't even get close to this optimization.

Code: [Select]
   unsigned char in_val = 255;
   char digits[3];
   digits[0] = digits[1] = digits [2] = '0';

  _asm {
     mov bl,in_val
   
loop_100:
     cmp bl,100
     jb  exit_loop_100
     inc digits[2]
     sub bl,100
     jmp loop_100
exit_loop_100:

loop_10:
     cmp bl,10
     jb  exit_loop_10
     inc digits[1]
     sub bl,10
     jmp loop_10
exit_loop_10:

     add digits[0],bl
  }

   // similar code in C
   in_val = 255;
   digits[0] = digits[1] = digits [2] = '0';
   while (in_val > 99) {
      digits[2]++;
      in_val -= 100;
   }
   while (in_val > 9) {
      digits[1]++;
      in_val -= 10;
   }
   digits[0] += in_val;

Less instructions than my more general BCD algorithm that I posted earlier converted to assembler and without assigning the actual digits.
Code: [Select]
   unsigned char in_val = 255;
   unsigned short accumulator=0;
   unsigned short count=8;
   char digits[3];

    _asm {
       mov cx,count
       mov ax,accumulator
       mov bl,in_val
   
begin_loop:
       shl ax,1
       mov bh,bl
       and bh,80h
       je skip_inc
       inc ax
skip_inc:
       cmp cx,1
       je end_loop
       mov bh,al
       and bh,0fh
       cmp bh,04h
       jbe skip_plus0x03
       add al,3
skip_plus0x03:
       mov bh,al
       and bh,0f0h
       cmp bh,40h
       jbe skip_plus0x30
       add al,30h
skip_plus0x30:
       shl bl,1
       dec cx
       jne begin_loop
end_loop:
       mov accumulator,ax
    }
« Last Edit: March 23, 2014, 01:00:01 am by miguelvp »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: [PIC] Converting SFR/GPR values to strings
« Reply #10 on: March 23, 2014, 12:55:53 am »
Quote
PIC chips do have div and mod

On chips with hardware division, it is not sure if it is still worthwhile to subtract multiple times in lieu of divisions.
================================
https://dannyelectronics.wordpress.com/
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: [PIC] Converting SFR/GPR values to strings
« Reply #11 on: March 23, 2014, 01:17:24 am »
Quote
PIC chips do have div and mod

On chips with hardware division, it is not sure if it is still worthwhile to subtract multiple times in lieu of divisions.

That's true for PIC24 but we don't know what he has, but since he mentioned the XC8 compiler it's safe to assume it's not a PIC24.
 

Offline iconTopic starter

  • Regular Contributor
  • *
  • Posts: 246
Re: [PIC] Converting SFR/GPR values to strings
« Reply #12 on: March 23, 2014, 01:44:46 pm »
Hi

Yes, it's just a 16F690 (it happens to be the thing stuck in the Picdem Lab dev board I'm playing with).

I don't know how I missed 'sprintf()' on a first pass - I was looking for something called 'ctoa' or something like that. It works as advertised - except that one of the registers I'm looking at apparently occasionally has values in excess of 255, which will need some investigation...

Although it works, it takes a hefty chunk of code, so I think I experiment with some of the other solutions offered, too.

Thanks
John

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: [PIC] Converting SFR/GPR values to strings
« Reply #13 on: March 23, 2014, 02:21:56 pm »
-ctoa-

itoa?

on some compilers, it is done via sprintf, :)
================================
https://dannyelectronics.wordpress.com/
 

Offline iconTopic starter

  • Regular Contributor
  • *
  • Posts: 246
Re: [PIC] Converting SFR/GPR values to strings
« Reply #14 on: March 23, 2014, 08:15:14 pm »
one of the registers I'm looking at apparently occasionally has values in excess of 255, which will need some investigation...

And further investigation reveals that 'sprintf(buf,"%d",somechar)' left justifies, which is fair enough - should have thought of that. Slightly odder is the fact that the trailing 'spaces' are filled with something oddly oriental-looking, though I can't see it in the character set.

'sprintf(buf",%3d",somechar)' right justifies, and leading spaces are blank, as one would want.

J
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: [PIC] Converting SFR/GPR values to strings
« Reply #15 on: March 23, 2014, 08:27:36 pm »
make sure your buf has space for the null termination. So for 3 digits you want the buffer to be 4 big. If it's not there the next variable after the buffer will control the null termination and it will print whatever if finds in memory until a 0 is reached.

 

Offline iconTopic starter

  • Regular Contributor
  • *
  • Posts: 246
Re: [PIC] Converting SFR/GPR values to strings
« Reply #16 on: March 23, 2014, 09:01:03 pm »
make sure your buf has space for the null termination. So for 3 digits you want the buffer to be 4 big. If it's not there the next variable after the buffer will control the null termination and it will print whatever if finds in memory until a 0 is reached.

Ah, the benefits of reading the manual. I'd have known that if I'd bothered... I've just done so now, and it does say "The resultant string will be null terminated" quite clearly.

I'd just relied on knowing that buf was 3 digits, and doing a 'for' loop. I'll have to go and rewrite it properly.

Thanks!
John
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: [PIC] Converting SFR/GPR values to strings
« Reply #17 on: March 23, 2014, 09:20:12 pm »
That's one of the problems using printf or their derivatives, other than it brings a lot of code to your program.
You can still use the loop and use putchar (putc to stdout) to just print the characters one by one.
end it with a putchar('\n'); or putc('\n',stdout); to jump to the next line. This way you can just use the buffer size 3 instead.
« Last Edit: March 23, 2014, 09:22:03 pm by miguelvp »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf