Technical discussions about Freescale Microcontrollers: M68HC11. (Freescale Semiconductor is a Subsidiary of Motorola).
|
----- Original Message ----- From: "bal_gill21" <> To: < > Does anyone know how I can convert a hex number coming from the > analog to digital convertor ($00-$ff) to a ASCII character from 0-100 > that I would like to display on a screen? > One method i've thought of is generating a conversion table but it > would have been easier if I only had data coming from $00-$64 as its > a one to one conversion. Thanks in advance. To scale to a new range, multiply by the new max and divide by the current max (if both scales start from the same value). So, to scale from $00-$FF to 0-100, multiply YOUR_VALUE by the fraction 100/255 (or 20/51 if you simplify things). For example, $80 (or 128) in the original scale will become (128*100/255=) 50.20 in the new scale. > Bal |
|
|
|
----- Original Message ----- From: "bal_gill21" <> To: < > Thanks for that Tony, > from your example I would be left with 50.2 ($32) in the new scale, > in my application I would like to display that as 50 Centigrade. In > ASCII that would be $35 & $30. ie 0-$FF = 0-100 centigrade on the > display. but I would need the ASCII code conversion. How would this > be normally achieved. To get the number in ASCII you just need to add '0' to each digit before you display it. So, binary 5 with an added '0' (48) becomes a '5' (53). > Bal |
|
|
|
----- Original Message ----- From: "bal_gill21" <> To: < > If you had a binary A with an added '0' (48) it would become a ':'(58) No such thing as binary A. Binary means 0 and 1. Don't confuse the representation of numbers in various systems with the actual value. 10 decimal = 1010 binary = A hex = 12 octal No matter how you write them, the above numbers always have a value of 10 (decimal). > this would be the case for anything between and including A & F. > Would something else need to be done here? It seems I forgot to state the obvious, then. Once you have scaled your $00..$FF number to 0..100 you'll then have to convert it to decimal. You need a separate routine that will do that. Then, to display that decimal in ASCII you need to add '0' to each digit. So, you need three routines: 1. Scale from $00..$FF to 0..100 2. Convert the number to decimal 3. Print the decimal number as ASCII string. [2] and [3] should be part of your standard libraries that you use in nearly any program. Hope it's clearer now. |
|
|
|
Hi All, Does anyone know how I can convert a hex number coming from the analog to digital convertor ($00-$ff) to a ASCII character from 0-100 that I would like to display on a screen? One method i've thought of is generating a conversion table but it would have been easier if I only had data coming from $00-$64 as its a one to one conversion. Thanks in advance. Bal |
|
|
|
To print it out in c is easy.... printf("the value is %d\n",value); I guess you want assembler...... you need to write a subroutine called 'itoa' (int to ascii)... biggest int is 65536...the algorithm is: 1) subtract 10000 till number is < 10000. That's the 10,000s digit (+$30). 2) subtract 1000 till ans < 1000. That's the 1000s dig. Keep going like this for 100s, 10s, 1s. [Non-text portions of this message have been removed] |
|
|
|
Thanks for that Tony, from your example I would be left with 50.2 ($32) in the new scale, in my application I would like to display that as 50 Centigrade. In ASCII that would be $35 & $30. ie 0-$FF = 0-100 centigrade on the display. but I would need the ASCII code conversion. How would this be normally achieved. Thanks Bal > > Does anyone know how I can convert a hex number coming from the > > analog to digital convertor ($00-$ff) to a ASCII character from 0- 100 > > that I would like to display on a screen? > > One method i've thought of is generating a conversion table but it > > would have been easier if I only had data coming from $00-$64 as its > > a one to one conversion. Thanks in advance. > > To scale to a new range, multiply by the new max and divide by the current > max (if both scales start from the same value). > > So, to scale from $00-$FF to 0-100, multiply YOUR_VALUE by the fraction > 100/255 (or 20/51 if you simplify things). > > For example, $80 (or 128) in the original scale will become (128*100/255=) > 50.20 in the new scale. > > > Bal > > tonyp@a... |
|
If you had a binary A with an added '0' (48) it would become a ':'(58) this would be the case for anything between and including A & F. Would something else need to be done here? > > > Thanks for that Tony, > > from your example I would be left with 50.2 ($32) in the new scale, > > in my application I would like to display that as 50 Centigrade. In > > ASCII that would be $35 & $30. ie 0-$FF = 0-100 centigrade on the > > display. but I would need the ASCII code conversion. How would this > > be normally achieved. > > To get the number in ASCII you just need to add '0' to each digit before you > display it. > > So, binary 5 with an added '0' (48) becomes a '5' (53). > > > Bal > > tonyp@a... |
|
As I understand the problem, it is to display temperatures from 0 to 100 with as much precision as is available from an 8 bit analog to digital conversion. If I were doing it, I would first scale the analog input so that it covers the converted range 0 to 250. When this is multiplied by 4 and divided by 10 you have the range 0 to 100 in steps of 0.4. A conversion of the range 0 to 1000, produced by the initial multiplication by 4, to decimal digits can then be carried out by first dividing by 1000 to get the hundreds digit (rounded down) which can be converted to ASCII numerals by adding $30 (48 in decimal). The result of the division can now be multiplied by 1000 and subtracted from the number to get a remainder which can be treated in the same way to get the next digit, this time dividing by 100 instead of 1000. This process is repeated using 10 as the divisor so that there is a remainder less than 10 which represents the number to be displayed after the decimal point. It is the placing of the decimal point which carries out the division by 10. I hope this helps. On Sat, 2004-10-30 at 20:50, Tony Papadimitriou wrote: > ----- Original Message ----- > From: "bal_gill21" <> > To: < > > If you had a binary A with an added '0' (48) it would become a ':'(58) > > No such thing as binary A. Binary means 0 and 1. Don't confuse the > representation of numbers in various systems with the actual value. > > 10 decimal = 1010 binary = A hex = 12 octal > > No matter how you write them, the above numbers always have a value of 10 > (decimal). > > > this would be the case for anything between and including A & F. > > Would something else need to be done here? > > It seems I forgot to state the obvious, then. > > Once you have scaled your $00..$FF number to 0..100 you'll then have to > convert it to decimal. You need a separate routine that will do that. > Then, to display that decimal in ASCII you need to add '0' to each digit. > > So, you need three routines: > > 1. Scale from $00..$FF to 0..100 > 2. Convert the number to decimal > 3. Print the decimal number as ASCII string. > > [2] and [3] should be part of your standard libraries that you use in nearly > any program. > > Hope it's clearer now. > > > Yahoo! Groups Links > > -- Bob Mitchell PO Box 68 Phone (+61 2) 9449 4736 (21 Hudson Close) Fax (+61 2) 9449 1976 Turramurra, 2074 Mobile 0411554117 NSW, Australia Email |
|
On Sun, 2004-10-31 at 00:19, wrote: > subtract 10000 till number is < 10000. How about "while number is > 9999, subtract 10000"? -- Cheers, Paul B. |
|
Thanks all, it makes sense now. I hope implementing it makes just as much sense ! Bal > > If you had a binary A with an added '0' (48) it would become a ':'(58) > > No such thing as binary A. Binary means 0 and 1. Don't confuse the > representation of numbers in various systems with the actual value. > > 10 decimal = 1010 binary = A hex = 12 octal > > No matter how you write them, the above numbers always have a value of 10 > (decimal). > > > this would be the case for anything between and including A & F. > > Would something else need to be done here? > > It seems I forgot to state the obvious, then. > > Once you have scaled your $00..$FF number to 0..100 you'll then have to > convert it to decimal. You need a separate routine that will do that. > Then, to display that decimal in ASCII you need to add '0' to each digit. > > So, you need three routines: > > 1. Scale from $00..$FF to 0..100 > 2. Convert the number to decimal > 3. Print the decimal number as ASCII string. > > [2] and [3] should be part of your standard libraries that you use in nearly > any program. > > Hope it's clearer now. > > tonyp@a... |
|
--- In , "bal_gill21" <bal_gill21@y...> wrote: > > Does anyone know how I can convert a hex number coming from the > analog to digital convertor ($00-$ff) to a ASCII character from > 0-100 that I would like to display on a screen? > One method i've thought of is generating a conversion table but it > would have been easier if I only had data coming from $00-$64 as > its a one to one conversion. Thanks in advance. Ok, I've read the various messages posted on this topic, and will attempt to summarize all the info provided to make it easier for you, along with adding my own suggestions/comments. First, I recall someone suggesting that you scale your analog signal such that you would get a reading of 250 decimal ($FA hex) from the A/D converter (hereinafter abbreviated as 'ADC') when your temperature reading is 100 C. This is good advice, and you should consider modifying your hardware as suggested as it would improve your resolution. Another thing to consider is reducing your readable temperature range. Do you really need to read temps up to 100 C ? Would 50 C be sufficient? If you restrict your range (and increase your amp gain accordingly) you could increase your resolution. For example, if you want to measure temps from 0 - 50 C, with 50 C = 250 ($FA) on the ADC, you would have an effective resolution of 0.2 C per ADC step. I am guessing (correct me if I'm wrong) that you are using a LM35 "Precision Centigrade Temperature Sensor". This sensor, in the most basic configuration, has an output that is at 0.0V at 0 C, and increases 10 mV per degree C. Thus, at 50 C, the output would be 500 mV (0.5V). Assuming you are using a 5.0V reference for the ADC (which is typical for the HC11 and most eval boards based on it), and you want to achieve a ADC reading of 250 ($FA) at 50 C, then you need to add an amplifier with a gain of: Gain = ADC Vref * Max ADC value / 256 / (10 mV (0.01) * Max temp) Where: Gain = Amplifier gain ADC Vref = Voltage applied to HC11 Vrh pin, typically 5.0 V Max ADC value = Desired ADC count at (Max temp) - e.g. 250 Max temp = Highest temperature you wish to measure - e.g. 50 Plugging in appropriate values for the above, we get: Gain = 5.0 * 250 / 256 / (0.01 * 50) = 4.88 / 0.5 = 9.77 If you are using a op-amp in a non-inverting DC gain configuration, you could get close to this gain by using a 10K resistor to ground on the inverting input, with a 96K feedback resistor (output to inverting input) with the temp sensor output connected to the noninverting input. For a 0-100 C range, you'd need a (ideal) gain of 4.88, which can be approximated by using 10K and 47K resistors. You could make the gain adjustable (for trimming/greater accuracy) by adding a pot in series with your feedback resistor. There are also some sofware based 'tricks' I could discuss that would let you calibrate your measurement without having to resort to adjustment pots, but the methods I have in mind would require 16-bit integer math capability that I don't want to go into now. As for the software techniques you'll need, if you wish to express/output your temperature value in 'human readable' form (e.g. ASCII decimal number output via SCI/serial port) then you'll need to write a integer-to-ASCII decimal routine. You will also want to take your ADC reading and scale it upward depending on the resolution of your reading. I will address this last point first. Let's say that you are interested in reading temps between 0-50 C, and you have scaled your sensor reading such that you get a ADC reading of 250 when the temp is at 50 C (as discussed above). Your effective temperature resolution in this configuration is 0.2 C per ADC unit. If you want to display your temperature with the maximum resolution possible, and furthermore, avoid having to deal with 'floating point' math, the best approach would be to scale the ADC reading such that the value you would have for display/output is expressed in 1/10 degree C units - that is, if the temperature were 28.6 C, the value you would get (after scaling) that you would display would be 286. All you have to do to scale your value (assuming you are using the configuration I discussed earlier) would be to take the value from the ADC and multiply it by an appropriate scaling factor, which is: Scaling factor = Max temp * 10 / ADC value at max temp = 50 * 10 / 250 = 2 As long as the scaling factor is a integer, you can perform the multiplication using the HC11 MUL instruction. Since, in this case, the scaling factor is a power of 2, you don't even have to use MUL - you can do it with a shift-left operation. Since the value you will get may exceed 8 bits (> 255), the shift operation has to be done as a 16-bit operation, like this: LDAB ADR1 ;Get value from ADC CLRA ;Set MSB of result = 0 LSLD ;16-bit shift left (*2) STD ScaledTemp ;(optional) save for later processing Note that if you set your sensor gain such that you get a ADC reading of 250 when the temperature is 100 C, you would need to use a scaling factor of 4 to get a temperature in 0.1 C units. Since 4 is also a power of 2, all you would need to do is add another 'LSLD' instruction to the code shown above. For ADC=250 at 50 C, the value in D will be 500 if the temperature is 50 C. For ADC=250 at 100 C, the value in D will be 1000 if the temperature is 100 C. As I mentioned earlier, you will need to create a integer-to-decimal ASCII conversion routine if you wish to output/display the temp reading in human readable form. There are two approaches that can be used to do this. The first, most compact, approach converts the number 'backwards' using successive divisions by 10, and works like this (expressed in C-like pseudocode): enter this routine with D = value to convert Y = address of digit buffer do D = D / 10 digit = remainder of (D / 10) digit += '0' (add ASCII '0', $30, to remainder) *Y = digit (write <digit> to buffer pointed to by Y) Y++ (increment buffer pointer Y) until (D == 0) The above algorithim is nice and relatively compact, but has the disadvantage of converting the number 'backwards', with the least significant decimal digit being converted first. Since normal output order of numbers is most significant digit first, you have to create a RAM buffer to hold the converted digits until the entire number is converted, then output the contents of the buffer 'backward' so the digits are displayed/output in the right order. For example, if you were to convert the number 12345 to ASCII decimal using the above routine, and the address of the digit buffer is $0080, the contents of your buffer would look like this after the conversion is finished: 0080 : '5' ($35) 0081 : '4' ($34) 0082 : '3' ($33) 0083 : '2' ($32) 0084 : '1' ($31) To output the value in this buffer, add this code to the end of the conversion routine discussed above: (on entry, Y points to the location following the last digit converted) do Y-- (decrement buffer pointer) A = *Y (get byte stored in buffer at address Y) Output value in (A) while (Y > start of buffer) The second approach to doing integer-to-decimal conversion involves dividing the integer by powers of 10 to isolate each decimal digit. It has the advantage of converting the number in most- to least- significant digit order (thus allowing output directly, without a buffer) but has the disadvantage of not supressing leading '0's, or at least requiring extra code and complexity to perform the leading zero supression. The pseudocode for this approach looks like this: Power10[] = (10000,1000,100,10,1) (asm: Power10 DW 10000,1000,100,10,1) Y = @Power10 (address of Power10 table) do digit = D / *Y (divide D by value in Power10 table) number = remainder (save remainder of division in RAM) digit += '0' ($30) Output <digit> D = number (recover remainder for next iteration) Y += 2 (increment Power10 table index) while (Y <= @Power10 + 8) (continue until 1's digit is converted) My personal preference is to use the first method I discussed, even though it converts the number backwards, because it tends to be easier to code and is (in my opinion) simply a 'better' and cleaner way to perform the task. I have presented the integer-to-ASCII routines in pseudocode rather than actual assembly code for two reasons: (1) It was easier than trying to write a assembly code version 'on the fly' as I write this, and (2) converting the pseudocode I've provided into actual assembly code is a good excercise for the beginner. Good luck... -- Mark |