Hola y gracias. Trouble with conversion

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, I found a code for RTC using UART.
I understand almost all code, but I confused about BCD and ASCII conversion. I use google as much as I could, but I think my problem is specific.'cause I can't find a code like this (I'm reading books about C). Can anyone help me a little, or give me a brief explanation or something.

I know everyone has their own logic, and thats why I don't undestand this code, but I also know that experts can understand it.

char getbcd(void)
{
	unsigned char c, buff[3], i=0;
	while(1) {
		c = getchar();
		if(('0'<=c)&&(c<='9')&&(i<2)) { // Si c es dígito 0..9 y si i>0
		buff[i++] = c;              // Guardar en buffer
		putchar(c);                 // Eco
	}
	else if((c=='\b')&&(i)) {    // Si c es BACKSPACE y si i>0
	i--;                     //
	putchar(c);              // Eco
}
else if((c=='\r')&&(i))      // Si c es ENTER y si i>0
break;                   // Salir del bucle
    }
    c = buff[0]-'0';
    if (i>1) {                       // (i==2)
        c <<= 4;
        c |= (buff[1]-'0');
    }
    return c;
}

All about RTC is clear to me.

I repeat, I don't write this code :S. If my post is in the wrong place, forgive me. I don't want to use copy and paste, Im learning how to write my own codes.

THANKS IN ADVANCE and sorry i dont' speak good english

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had this open so copied and pasted:

BCD - Binary Coded Decimal

Binay Coded Decimal is a coding trick that eases the storage and conversion of binary numbers, say a count of the crystal beats, to decimal numbers, like you’d want to display on a watch LCD. We can divide an 8-bit byte into two 4-bit nibbles each of which can represent a number with a range of 0 to 16. That’s one of the reasons for the use of hexadecimal notation discussed earlier. And it allows us to store as single decimal integers, 0 to 9, in a nibble and two in a byte, one integer in each nibble. 

If a the decimal number in a byte is less than 99, we can convert it to a BCD byte using the following algorithm:

Set the initial byte (in C we use char) to some two digit value.

	char initialbyte = 54; 
	
Declare a variable for the upper nibble value.
	
   	 char high = 0;
    
Count the tens in initialbyte.

    	while (initialbyte >= 10)               
    	{
        		high++;
        		initialbyte -= 10;
    	}

After this runs the initialbyte now contains only the ones integer from the original byte and high char contains the tens, that is: high = 5 and intialbyte = 4. We combine the high and low nibbles to get the converted byte.

    	convertedbyte  =  (high << 4) | initialbyte;      

This algorithm is used in the CHAR2BCD2 function in the software.

Converting a byte to the ASCII equivalent decimal character using BCD.

We define two bytes Tens and Ones and a third byte, Number, which we set to a value in the range of 0 to 99.
	
	char Tens = 0;
	char Ones = 0;
char Number = 54;

We use the character to BCD algorithm written as the function CHAR2BCD2(char) in the software section below to convert the Number to the BCD equivalent in Tens.

    	Tens = CHAR2BCD2(Number);   
       
Now Tens has the BCD of the tens in the upper nibble and of the ones in the lower nibble. We can convert this to an ASCII character for the integer by remembering that the numerical value of ASCII ‘0’ is 48 and each following char integer is a simple increment of the previous one. Meaning that adding the number 4 to the value of the ASCII character ‘0’, which is  48, yields the ASCII character ‘4’,  (48+4 = 52 which is the ASCII decimal value of the character ‘4’). So the conversion of a decimal integer to its ASCII equivalent character is the simple addition of 48 to the decimal integer.

Since the CHAR2BCD2 function loaded both the tens and ones parts of Number into Tens, we need to extract the Ones and the Tens so that we can add 48 to get the ASCII characters for Number. 

	Ones = Tens;
    	Ones = (Ones & 0x0F) + '0'; 

Finally we get the Tens by right shifing the byte 4-bits, which we use as the ASCII character offset.

    	Tens = (Tens >> 4) + '0';

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your fonction has two blocks
1) a (at most) two digits string is received through the serial line; it becomes a valid string if a CR is entered -line 14 -or if there are more than two digits... Backspace is managed, too, to cancel an already enterd character -line 10-12.
Only characters between '0' and '9' are stored -and echo'ed- in the string, buff, to be decoded.

Perhaps this part would be easier to understand if it was well indented.... (I often use http://www.gnu.org/software/indent/ to have *.c automagically indented)

2) this string is decoded and Smiley explained it very well.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

oh, ok thank you Smiley and dbrion0606, I understand the logic, now I will write my own code 'cause the other one seems confused to me

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so, if in that code are using " - '0' " instead of " + '0' "?

thats mean conversion ASCII to BCD, not BCD to ASCII.

That is correct? Thanks in advance

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The numerical value of the ASCII code for ASCII '0' is 48. If you subtract this value from any of the ASCII number codes for 0 to 9 you get the actual value that the number represents. For instance '5' - '0' is the same as 53 - 48 and the result is the number 5. This converts ASCII to a number. Adding '0' to a single digit number 0 to 9 provides the ASCII code for that number. These facts are used in calculating BCD, but are in and of themselves not related to BCD.

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, but

c = buff[0]-'0'; 
    if (i>1) {                       // (i==2) 
        c <<= 4; 
        c |= (buff[1]-'0'); 
    } 
    return c; 

first subtract '0' from ascii number (stored in buffer[0]) and gets the actual value in dec, then with c << 4, seems like manipulation of binary, and then use "or" operator (in buffer[1]). I thought that was for the separation of nibbles and BCD converion. Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Consider this. The far end sends '3','7',,'9',. When the '3' arrives it executes this bit of the code:

      c = getchar();
      if(('0'<=c)&&(c<='9')&&(i<2)) { // Si c es dígito 0..9 y si i>0
      buff[i++] = c;              // Guardar en buffer
      putchar(c);                 // Eco
   }

i was 0. it is now 1. This has put '3' into buff[0] and echoed the character back to you the typist. The '7' arrives so again it executes this:

      c = getchar();
      if(('0'<=c)&&(c<='9')&&(i<2)) { // Si c es dígito 0..9 y si i>0
      buff[i++] = c;              // Guardar en buffer
      putchar(c);                 // Eco
   }

That make i==2 and buff[0] holds '3' while buff[1] holds '7'. The '7' is also echoed back to the typist.

Next the backspace ('\b') arrives so this time it's this bit of the code that executes:

   else if((c=='\b')&&(i)) {    // Si c es BACKSPACE y si i>0
   i--;                     //
   putchar(c);              // Eco
}

That reduces i by one (from 2 to 1) and sends the '\b' back to your terminal so the cursor probably moves back one space.

Next '9' arrives. Remember that i is currently 1. This code executes:

      c = getchar();
      if(('0'<=c)&&(c<='9')&&(i<2)) { // Si c es dígito 0..9 y si i>0
      buff[i++] = c;              // Guardar en buffer
      putchar(c);                 // Eco
   }

So now you have buff[0]='3' and buff[1]='9'. Finally arrives. So this code executes:

else if((c=='\r')&&(i))      // Si c es ENTER y si i>0
break;                   // Salir del bucle 

and it breaks from the initial while(1) loop with buff[0] still holding '3' and buff[1] holding '9'.

Now it executes this code:

    c = buff[0]-'0';

The ASCII '3' that was in buff[0] leads to c getting the value 3 (not '3'). It then goes on to execute this:

    if (i>1) {                       // (i==2)
        c <<= 4;
        c |= (buff[1]-'0');
    }

It does execute this conditional code because i holds 2 (that is 2 digits were typed) so first it does:

        c <<= 4;

that takes the 0x03 that is currently in c and moves it 4 places to the left (into the upper nibble) so it becomes 0x30. Finally it executes this line:

        c |= (buff[1]-'0');

buff[1] is holding '9' so (buff[1] - '0') is just 9 (not '9'). The statement uses the OR operator to combine this with the 0x30 that is already in c so 0x30 becomes 0x39. Therefore the "39" that was entered (after correcting "37" to be "39") has been combined from two bytes ('3' and '9') into a single binary coded decimal byte holding 0x39.

HTH

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, clawson, it really helped me.
Bit a bit I'm understanding how to write a code, I have a lots of things I want to do.
Sorry if I'm annoying, but soon I will be able to contribute knowledge to this forum. :D