Understanding ASCII in Embedded development

xox

Joined Sep 8, 2017
936
Just remember that a number itself is just an abstract mathematical object. The digits you see on a screen are a representational convention adopted to express numbers as a string of "symbols" (digits).

Here's a toy program (for simplicity) that print the digits of an integer in reverse:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void integer_print_reverse(unsigned integer, const char* digits) {
  unsigned base = strlen(digits);
  do {
    /*
      Extract next digit and print
    */
    unsigned index = integer % base;
    putchar(digits[index]);
    /*
      Remove digit
    */
    integer /= base;
  } while (integer != 0);
  putchar('\n');
}

void process(unsigned value) {
  printf(" Value: %u\n", value);
  puts("- Reversed -");
  printf(" Decimal: ");
  integer_print_reverse(value, "0123456789");
  printf(" Hexadecimal: ");
  integer_print_reverse(value, "0123456789ABCDEF");
  printf(" Octal: ");
  integer_print_reverse(value, "01234567");
  printf(" Binary: ");
  integer_print_reverse(value, "01");
}

int main(int argc, char** argv) {
  if (argc == 1)
    process(561);
  else
    for (;;) {
      char* arg = *(++argv);
      if (arg == NULL)
        break;
      process(atoi(arg));
    }
}
Normally of course we would print them in the "proper order" as dictated by the convention of the base-10 representation, which is sums of powers of ten, largest powers first. (eg: 561 = (5) * 10 ^ 2 + (6) * 10^1 + (1) * 10^0). I leave it up as an exercise in case you want to give it a go for yourself.

Anyway a string of ASCII characters is really just a sequence of 8-bit numbers, so we can extend it to that as well.


Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void integer_print_reverse(unsigned integer, const char* digits) {
  unsigned base = strlen(digits);
  do {
    /*
      Extract next digit and print
    */
    unsigned index = integer % base;
    putchar(digits[index]);
    /*
      Remove digit
    */
    integer /= base;
  } while (integer != 0);
  putchar('\n');
}

void process(const char* ascii) {
  const char* hexadecimal = "0123456789ABCDEF";
  size_t length = strlen(ascii);
  puts(ascii);
  puts("- Bytes in sequence (but digits reversed) in hexadecimal -");
  for (size_t index = 0; index < length; ++index)
    integer_print_reverse(ascii[index], hexadecimal);
}

int main(int argc, char** argv) {
  if (argc == 1)
    process("Hello World!");
  else
    for (;;) {
      char* arg = *(++argv);
      if (arg == NULL)
        break;
      process(arg);
    }
}
 

MrChips

Joined Oct 2, 2009
34,830
If you think that you fully understand the purpose of ASCII then we can move on.
If not, go back and read everything that I have written. If you do not understand don't be afraid to ask.
This is so important and fundamental that I will put it into a blog one day.

To review, for binary values 0 and 1, this works:
LUT[0] = 48;
LUT[1] = 49;

However, it would be better to write:
LUT[0] = '0';
LUT[1] = '1';

The two statements are identical to the two statements before. The compiler produces the exact same results.

Similarly, we can do the same thing with the numerals 0 to 9:
LUT[0] = '0';
LUT[1] = '1';
LUT[2] = '2';
LUT[3] = '3';
LUT[4] = '4';
LUT[5] = '5';
LUT[6] = '6';
LUT[7] = '7';
LUT[8] = '8';
LUT[9] = '9';

Here, we fill a 10-element array one at a time with the ASCII code of each numeral 0 to 9.
Rather than filling the array one at a time, why not let the compiler do it automatically.

const char LUT[ ] = "0123456789";

or we may as well do for all 16 values:

const char LUT[ ] = "0123456789ABCDEF";

So this works for binary 0/1, BCD 0-9, and 4-bit binary 0-F.
Let's change the name LUT to something else such as hex or display_code.

const char hex[ ] = "0123456789ABCDEF";

This is used to generate the display code for a single 1-bit binary value, 4-bit BCD value, or 4-bit binary value.
(Notice that I intentionally call it 4-bit binary and not hex, because it is not hex.)

Your next exercise is to convert an 8-bit, 16-bit, 32-bit, 64-bit binary value into any of the three display formats: binary, decimal, hexadecimal.

Can you do this on your own without assistance from someone else’s code?
 

Thread Starter

Pushkar1

Joined Apr 5, 2021
416
If you think that you fully understand the purpose of ASCII then we can move on.
If not, go back and read everything that I have written. If you do not understand don't be afraid to ask.
I think I understand lookup table and cards

We have two cards When data is in binary
We have sixteen cards. When data is in hex
We have ten cards When data is in decimal

Suppose we want to show 0101 on the screen There are only two cards [0] and [1]

we want to display 0 on the screen we call up card number 48 which is the first entry in the table.
we want to display 1 on the screen we call up card number 49 which is the second entry in the table.
we want to display 0 on the screen we call up card number 48 which is the third entry in the table.
we want to display 1 on the screen we call up card number 49 which is the fourth entry in the table.

LUT[3]= { 48, 49, 48, 49}; // This sequence show 0101 on the screen for 4 bit hardware

Your next exercise is to convert an 8-bit, 16-bit, 32-bit, 64-bit binary value into any of the three display formats: binary, decimal, hexadecimal.
8-bit binary value : I Look at the ASCII code for the letters that I want to show on the screen

Suppose we want to show 00000101 on the screen There are only two cards [0] and [1]
LUT[7]= {48, 48, 48, 48, 48, 49, 48, 49}; // This sequence show 00000101 on the screen

Can you do this on your own without assistance from someone else’s code?
I load the sequence into array that I want see on the screen
 

MrChips

Joined Oct 2, 2009
34,830
No. I am afraid you went off the track. You just went in the wrong direction.

What I wrote is:

const char LUT[ ] = "0123456789ABCDEF";

LUT[ ] is a constant. You cannot change change LUT.
I am using this to show one way how you find the ASCII code of the desired display character.
You do this by using a look-up table.

The other way is to add a value (offset) to the ASCII code of '0'.

At this point in the lesson I am not suggesting that you put the display characters into a string.
If you want to do this then you need to use another string, e.g. display[ ].
I suggest that you don't do this for now. Just output one character at a time:

putchar(character);
 

MrChips

Joined Oct 2, 2009
34,830
Scrap what you have written in post #23 and let's try to get back on track.

I have been very careful with the words I choose. This is to make sure that we both understand our thoughts precisely. I am aware that there could be a language issue hence we have to be doubly careful of how we say it.

You wrote:
We have two cards When data is in binary
We have sixteen cards. When data is in hex
We have ten cards When data is in decimal
No. Data is always binary.
You agreed to this in you very first post.

What changes is how we want to represent the data on the display device.
Let us take one case at a time.

Here is your assignment.

Write a program to display a 16-bit value in binary representation.

Try to do this on your own without relying on code that someone else has written.
I cannot offer you any code because these are all classic assignments that we give students at a very early stage in a course in computer programming.

Begin by drawing a flowchart or using pseudo code.
 

click_here

Joined Sep 22, 2020
548
I think that it is important to add that ASCII is only a subset of what is used world wide.

For a more complete table, look up the ISO/IEC 8859 standard.

The reason for this standard is that most other languages that use Latin alphabets need additional symbols not covered by ASCII.

If you are programming in C, there is a standard header "wchar" which covers extended multibyte and wide character utilities.
 
Top