View previous topic :: View next topic |
Author |
Message |
Futterama
Joined: 17 Oct 2005 Posts: 98
|
How to extract single decimal digit from int16 number? |
Posted: Thu Oct 20, 2005 5:57 pm |
|
|
Hi,
I was wondering, how can I extract a single decimal digit from a int16 like the DIG function in PicBasic do it with 16bit words?
Thanks.
Regards,
Futterama |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 20, 2005 8:13 pm |
|
|
This is probably a student question, so may I suggest that you use
http://www.google.com
Just type a search string that is likely to find C source code, such as:
"extract digits" int char
In the first ten hits, there's sample code. Look in the one on "LED.C"
and the Daniweb one, where a forum discusses routines to do it.
Use Google. It's got your answers. The key to using Google
effectively is to search for quoted strings. To find C source code,
put in some common C keywords, such as int and char as I have
done above. |
|
![](templates/subSilver/images/spacer.gif) |
Futterama
Joined: 17 Oct 2005 Posts: 98
|
|
Posted: Fri Oct 21, 2005 2:36 am |
|
|
I don't get the examples...
I'm pretty new to C, and I don't see the point with printf in a microcontroller.
It would be more helpful if you posted the code I needed, cause I've tried google before posting this question, and it didn't help me.
Or you could at least paste the code you think I need from the web, and perhaps explain in a few words how it works. |
|
![](templates/subSilver/images/spacer.gif) |
Futterama
Joined: 17 Oct 2005 Posts: 98
|
|
Posted: Wed Oct 26, 2005 4:31 am |
|
|
Well, since no one would bother posting some code, I have made my own function. Crude? Yes. Does it work? Yes. Do anyone in this forum have a better idea? No.
Code: | void SplitDigit(int16 data)
{
int8 DigitValue[5];
DigitValue[0] = 0;
DigitValue[1] = 0;
DigitValue[2] = 0;
DigitValue[3] = 0;
DigitValue[4] = 0;
if(data>9999)
{
while(data>9999)
{
data = data - 10000;
DigitValue[0]++;
}
}
else
DigitValue[0] = 0;
if(data>999)
{
while(data>999)
{
data = data - 1000;
DigitValue[1]++;
}
}
else
DigitValue[1] = 0;
if(data>99)
{
while(data>99)
{
data = data - 100;
DigitValue[2]++;
}
}
else
DigitValue[2] = 0;
if(data>9)
{
while(data>9)
{
data = data - 10;
DigitValue[3]++;
}
}
else
DigitValue[3] = 0;
DigitValue[4] = data;
} |
|
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Oct 26, 2005 6:02 am |
|
|
Quote: | Well, since no one would bother posting some code, I have made my own function. Crude? Yes. Does it work? Yes. Do anyone in this forum have a better idea? No. |
This sounds like you are a disappointed in the support you got here. What was wrong with the pointers PCM gave you? I had a look at the LED.C program he pointed you to and it looks like a good starting point.
Other alternatives:
- itoa()
- sprintf()
Last edited by ckielstra on Wed Oct 26, 2005 6:25 am; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
dyeatman
Joined: 06 Sep 2003 Posts: 1924 Location: Norman, OK
|
|
Posted: Wed Oct 26, 2005 6:07 am |
|
|
What don't you get about printf in a microcontroller? Printf is simply a means to output data from the PIC in a user defined format (hex, float etc.). If you use putc(x) the byte (x) is simply output as character without any "conversion" |
|
![](templates/subSilver/images/spacer.gif) |
Futterama
Joined: 17 Oct 2005 Posts: 98
|
|
Posted: Wed Oct 26, 2005 6:50 am |
|
|
ckielstra wrote: | This sounds like you are a disappointed in the support you got here. What was wrong with the pointers PCM gave you? I had a look at the LED.C program he pointed you to and it looks like a good starting point. |
I was a little disappointed, I came here to get help, not to be told "Use Google" (no offence, but it just didn't help me).
I looked at the file LED.C, and didn't understand what was going on, that's the problem.
Perhaps you could give an example on the use of the 2 functions you mentioned (I can't find itoa in the built in function list in CCS help).
dyeatman wrote: | What don't you get about printf in a microcontroller? Printf is simply a means to output data from the PIC in a user defined format (hex, float etc.). If you use putc(x) the byte (x) is simply output as character without any "conversion" |
I don't understand where the output will go. Output data where to?
Regards,
Futterama |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Oct 26, 2005 7:24 am |
|
|
Quote: | Perhaps you could give an example on the use of the 2 functions you mentioned (I can't find itoa in the built in function list in CCS help).
| You can download the October 2005 PDF version of the manual from the CCS website.
Code: | #include <stdlib.h>
int8 String[10];
int16 Value = 12345;
// Method 1
sprintf(String, "%Lu", Value);
// Method 2
itoa(Value, 10, String); |
|
|
![](templates/subSilver/images/spacer.gif) |
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Wed Oct 26, 2005 7:43 am |
|
|
Futterama wrote: | Well, since no one would bother posting some code, I have made my own function. Crude? Yes. Does it work? Yes. Do anyone in this forum have a better idea? No.
Code: | void SplitDigit(int16 data)
{
int8 DigitValue[5];
DigitValue[0] = 0;
DigitValue[1] = 0;
DigitValue[2] = 0;
DigitValue[3] = 0;
DigitValue[4] = 0;
if(data>9999)
<snip>
else
DigitValue[3] = 0;
DigitValue[4] = data;
} |
|
While I haven't tried to actually compile your code it looks like it should work. I would probably use the division and remainder operations instead of sucessive subtraction, but depending on the processor used your way might be faster. I know when converting a byte it is faster to subtract hundreds than to divide since you will only have to subtract at most only twice. Using printf is easier to program and to read, but will take much more code space unless you also use printf elsewhere anyway.
Your code puts the results in an array. Printf will print the results to either the standard C I/O port or to a function you provide. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
![](templates/subSilver/images/spacer.gif) |
neil
Joined: 08 Sep 2003 Posts: 128
|
where does the output go to? |
Posted: Wed Oct 26, 2005 7:47 am |
|
|
If you look in the help file in CCS under 'printf' it clearly tells you where the output goes by default. You can also direct the output to one of your own functions, by putting it inside the printf brackets, also described in the help file.
Do you own a textbook on C? If not, I suggest you get yourself one. Please don't flame us for not helping you enough, most of us on here answer questions in our spare time, we aren't paid to do this! We can only help those who help themselves!
Now, about itoa() - That isn't in the CCS library, or not in my version at least. Here is a description of what it does. Bear in mind though, that this is just an example of how to use itoa and is designed for PC type computers. http://www.cplusplus.com/ref/cstdlib/itoa.html
Here is an example of the actual code behind itoa from my text book.
Code: | /*itoa: convert n characters in s*/
void itoa(int n, char s[]){
int i, sign;
if((sign=n) < 0) // Record sign
n= -n; // Make n positive
i=0;
do{ /* generate digits in reverse order */
s[i++] = n % 10 + '0'; // Get next digit
} while((n/=10) > 0; // Delete it
if(sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
// Copied from "The C programming language" by Kernighan & Ritchie |
Now, some notes. This won't work as-is in CCS. For a start, this uses the PC default of signed int. In CCS ints are unsigned by default, so this would require re-writing to reflect this. If you don't want negative numbers, it will be a lot simpler than what I have copied out above. (No 'sign' testing)
reverse() does not exist in CCS, so you would need to write a routine to flip the string around yourself.
The reverse of this is in CCS (atoi() ). This converts an ASCII string into an integer. This is in stdlib.h. |
|
![](templates/subSilver/images/spacer.gif) |
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Wed Oct 26, 2005 8:16 am |
|
|
Here's a version of that function that I've used many times.
Code: |
void itos(char s[],signed int16 n) // convert an integer to a string
{
signed int8 i, c, j;
signed int16 sign;
if((sign = n) < 0)
n = -n;
i = 0;
do
{
s[i++] = n % 10 + '0';
}while((n /= 10) > 0);
if (sign < 0 )
s[i++] = '-';
s[i] = '\0';
for(i = 0, j = strlen(s) - 1; i < j; i++, j--)
{ c = s[i];
s[i] = s[j];
s[j] = c;
}
}
|
Ronald |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Oct 26, 2005 8:37 am |
|
|
Quote: | Printf will print the results to either the standard C I/O port or to a function you provide. | Or use sprintf which writes the data to a string (buffer).
Quote: | Now, about itoa() - That isn't in the CCS library, or not in my version at least. | It's a new addition, it was not in v3.226 but it is in v3.234. I just had a look at it, it's very flexible but large.
v3.234, PIC18F458
Standard itoa, 32 bit version: 780 bytes.
Modified itoa, 16 bits version: 480 bytes
itos from rnielsen: 466 bytes
Good old 16 bit sprintf: 224 bytes
Last edited by ckielstra on Thu Oct 27, 2005 3:02 am; edited 1 time in total |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Oct 26, 2005 11:45 am |
|
|
The reason I said to use Google was because this looked like just
one more homework assignment.
I'm stunned (somewhat) that you didn't try my search string for Google.
I mentioned the Daniweb link, which is in the first few hits.
It's got an entire forum discussion thread on stripping digits, with code:
http://www.daniweb.com/techtalkforums/printthread.php?t=21658 |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Oct 26, 2005 12:46 pm |
|
|
I was intrigued by how it was possible for sprintf to be more efficient than the hand coded routine from rnielsen. After some optimization rounds I discovered it has to do with the way sprintf accesses the string buffer, it uses the index registers efficiently.
I never before used the index registers and the feature of auto increment or decrement sounds very efficient. As an excercise I coded my own version of atoi which is a little more efficient than sprintf but not as flexible, only unsigned integers are accepted (I leave this to whoever needs this functionality).
Code: | #include <18f458.h>
#FUSES HS, NOPROTECT, NOPUT, NOBROWNOUT, NOWDT, NOLVP
// Register defines for the PIC18F458
unsigned int16 FSR0;
#locate FSR0=0x0FE9
unsigned char POSTDEC0;
#locate POSTDEC0=0x0FED
unsigned char POSTINC0;
#locate POSTINC0=0x0FEE
unsigned char INDF0;
#locate INDF0=0x0FEF
unsigned int16 FSR1;
#locate FSR1=0x0FE1
unsigned char POSTDEC1;
#locate POSTDEC1=0x0FE5
unsigned char POSTINC1;
#locate POSTINC1=0x0FE6
unsigned char INDF1;
#locate INDF1=0x0FE7
/////////////////////////////////////////////////////////////////////
// Converts a 16 bit unsigned integer to an ASCII string.
// This is a highly optimized verion of itoa() using the index registers
// of the PIC18 processor.
// Requires about 170 bytes on the PIC18 compared to about 224 bytes
// for sprintf("%Lu").
//
// Input:
// num The value to convert (only unsigned integer support)
// s Pointer to buffer for storing the result
// Returns:
// none
//
//
// C. Kielstra, 2005
// Free for distribution.
/////////////////////////////////////////////////////////////////////
void int16_to_a(int16 num, char *s)
{
char c;
// Initialise pointers to start of string
FSR0 = s; // Set FSR0 index register to start of string buffer
FSR1 = s; // Set FSR1 index register to start of string buffer
// Conversion
do
{
POSTINC1 = (num%10) + '0';
} while (num /= 10);
POSTDEC1 = '\0'; // End the string
// Points now to last character in string
// Reverse the string
// p0 points to first character and p1 to last character,
// finished when pointers meet in the middle of the string.
do
{
c = INDF0; // c = *p0
POSTINC0 = INDF1; // *p0++ = *p1
POSTDEC1 = c; // *p1-- = c
} while (FSR0 < FSR1);
}
void main()
{
int8 String[10];
int16 Value = 1234;
int16_to_a(Value, String);
while(1);
} |
|
|
![](templates/subSilver/images/spacer.gif) |
|