circuitcellar.com
Magazine Support   Digital Library   Products & Services   Suppliers Directory 
 
 





 

October 2004, Issue 171

Test Your EQ

Answer 4—It is always a good practice to keep your resume updated. However, Frugalson need not panic. Integer arithmetic functions are simple to implement in assembly. As long as Frugalson can download a free assembler, the project is not lost yet!

With a known domain (range of input values) and range (range of output values), floating-point numbers are generally unnecessary. In this case, each count of the ADC represents 10 V/4096, and the MCU can use the same units for internal storage and computation. When it is time to convert an internal value (v) to volts with two digits after the decimal point, Frugalson can use simple integer arithmetic operations.

Although Frugalson could implement a full 16 × 16 bit integer multiplication function, all he really needs is to multiply by 10, or 1010 binary. Because 10 = 2 + 8, and 2 and 8 are both powers of two, he can rewrite v × 10 as v × 2 + v × 8. Simply simply shifting v to the left can generate the two terms. On an 8-bit processor, this requires a total of six shift operations and two additions, along with 2 bytes of temporary storage.

The other thing Frugalson needs to realize is that he can think of the 12-bit binary value from the ADC as a fixed-point fractional value, with the binary point between the fourth and fifth bits: 0000.vvvvvvvvvvvv. This fraction represents some value between 0 and 10 V (e.g., 0x0FFF or 0000.11111111111 represents 9.9976 V). Each time you multiply this value by 10, the integer part of the result is another digit in the output representation that he needs.   

 

The pseudo-code is as follows, assuming v is a 16-bit register: 

 

This code executes quickly when properly implemented in assembly. Multiplying by 10 involves six 8-bit shifts and two 8-bit additions. Shifting by 12 is really just shifting the high byte by four places. Similarly, masking with 0x0FFF only involves one 8-bit AND of the most significant byte. The variables unit, tenth, and hundredth only need to be 4 bits wide (unsigned).

There are 18 8-bit shifts and six 8-bit additions for the multiplication steps, plus 12 more 8-bit shifts to isolate the digits, and two 8-bit ANDs to do the masking. A total of 38 8-bit operations are needed. For an MCU that executes most 8-bit operations in one cycle, this code should take no more than 80 cycles. At a modest 5-MHz clock speed, the conversion takes at most 16 µs, much less than the transmission time for even 1 byte at 230,400 bps. It is time that Frugalson ask for a raise!

One other point that Frugalson may want to consider is the fact that the decimal conversion has been truncated to three digits rather than rounded. If he adds 0.005 V (0000.000000000010 in binary) to v before starting the conversion, the result will be rounded correctly. However, full-scale inputs will now generate an output value of 10.00, which will require a fourth digit to be generated. It may be better to leave it well enough alone.

 

Contributor: David Tweed

   

E-mail eq@circuitcellar.com with questions or comments.

Back to Questions