|
|
View previous topic :: View next topic |
Author |
Message |
adrian
Joined: 08 Sep 2003 Posts: 92 Location: Glasgow, UK
|
knotty problem with string functions |
Posted: Sun Nov 16, 2003 10:59 am |
|
|
I am trying to create a function that reads an ASCII number that a user types on a keyboard. This number will always be in the decimal format, unsigned, and in the range of 0 to 65535. Once this number has been read into the PIC, I wish to convert it into an unsigned long.
So far I have a working programme that uses the gets() function to read in the number. Unfortunately, gets() does not echo back what has been entered, so the user is effectively typing blind. I know the string function is correct, as I call atol and printf the result. Anybody got a better idea?
Secondly, is there an unsigned version of atol? The signed long atol(char *s) from stdlib.h is an over kill for what I need. As my number will ALWAYS be decimal and unsigned. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sun Nov 16, 2003 2:01 pm |
|
|
Use getc() and then putc() to read in the string. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Nov 16, 2003 3:27 pm |
|
|
You can use the CCS function get_string(), instead of gets().
It echoes the characters. It also has other features, like backspace,
and a maximum char limit, so you don't overflow the buffer.
It's in INPUT.C, which is in this folder: c:\Program Files\Picc\Drivers
For a cheap version of atol, which only handles ascii decimal to long,
I have this function:
Code: | // Convert a string of up to 5 ascii decimal digits
// ("65535" max) to a binary long. Any value that
// is not ascii decimal will end the conversion.
// For example "25," will convert the first two digits
// and then stop at the comma, and return 25 as the result.
long adtol(char *ptr)
{
long retval;
char c;
char i;
retval = 0;
for(i = 0; i < 5; i++)
{
c = *ptr++; // Read char from string
if(c < '0') // Test if it's an ascii decimal value
break;
if(c > '9')
break;
// Multiply retval * 10, and subtract the ascii bias of 0x30.
retval = (retval << 3) + (retval << 1) + (c - '0');
}
return(retval);
} |
|
|
|
adrian
Joined: 08 Sep 2003 Posts: 92 Location: Glasgow, UK
|
|
Posted: Sun Nov 16, 2003 4:11 pm |
|
|
Mark wrote: | Use getc() and then putc() to read in the string. |
OK I could do that, but how do I group up to 5 individual characters together to perform a atol function? |
|
|
adrian
Joined: 08 Sep 2003 Posts: 92 Location: Glasgow, UK
|
|
Posted: Sun Nov 16, 2003 4:19 pm |
|
|
PCM programmer wrote: | You can use the CCS function get_string(), instead of gets(). |
OK I see from this that it takes the following form:
void get_string(char * s,int max)
Does this mean that 'max' defines the maximum number of characters that can be accepted by this function? What does 'len' do?
Also your long adtol(char *ptr) function looks ideal, I shall give it a bash. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sun Nov 16, 2003 4:34 pm |
|
|
What is your definition of a string? An array of char. As each char is read place it in the array or you could use a pointer.
I like to use interrupts to receive. I use something like this in the int_rda
Code: |
if ((RCSTA1bits.FERR) || (RCSTA1bits.OERR))
{
Comstat.Rx_Bufferoverrun = TRUE;
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
}
else if (Comstat.Rx_Bytes++ < RX_BUFFER_SIZE - 1)
{
Rx_Buffer[Comstat.RxHead++] = RCREG1;
/* Stick a Null on the end to let us use str functions on our
* buffer */
Rx_Buffer[Comstat.RxHead] = 0;
}
else
{
Comstat.Rx_Bufferoverrun = TRUE;
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
}
|
Then I have a function that I call from main
Code: |
/* *************************************************************************
NAME: TerminalHandler
DESCRIPTION: Handles the terminal operation PARAMETERS: port (IN)
communication port GLOBALS: none
RETURN: none
ALGORITHM: none
NOTES: none
*************************************************************************** */
void TerminalHandler(
enum porttypes port) /* FIX ME: add comment */
{
static UINT8 index1 = 0; /* index of buffer */
static UINT8 index2 = 0; /* index of buffer */
int i; /* character from buffer */
char ch; /* character from buffer */
static char buf1[MAX_LINE_LEN]; /* for the line entry */
static char buf2[MAX_LINE_LEN]; /* for the line entry */
UINT8 *p_index;
char *buf;
/* setup pointers to the buffers for the port that we are reading */
p_index = &index1;
buf = buf1;
switch (port)
{
case pt_RS232:
/* p_index and buf are already initialized */
break;
case pt_RS485:
p_index = &index2;
buf = buf2;
break;
default:
return;
}
while (TRUE)
{
i = HostReadChar(port);
/* port error */
if (i < 0)
return;
ch = (char)i;
switch (ch)
{
/* illegal characters */
case '\a':
case '\f':
case '\n':
case '\t':
case '\v':
/* escape */
case 0x1B:
break;
/* backspace */
case '\b':
if (*p_index)
{
--(*p_index);
/* do a destructive backspace */
HostWriteChar(port, '\b');
HostWriteChar(port, ' ');
HostWriteChar(port, '\b');
}
break;
/* enter */
case '\r':
HostWriteChar(port, '\r');
HostWriteChar(port, '\n');
buf[*p_index] = '\0';
/* did we get something? */
if (*p_index)
{
if (!CommandHandler(port, buf, &CommandData[0]))
HostWriteRomString(port, "Invalid Command. Type ? for help.\r\n");
}
buf[0] = '\0';
*p_index = 0;
/* write the prompt */
HostWriteChar(port, '>');
break;
/* all the rest of the characters */
default:
/* leave room for null at the end */
if (*p_index < (MAX_LINE_LEN - 1))
{
buf[*p_index] = ch;
if (!ch)
ch = 0;
HostWriteChar(port, ch);
(*p_index)++;
}
break;
}
}
}
|
The above function actually is used to handle 2 serial ports but it gives you an idea as to how I do it. CommandHandler() is a function that looks at the string and decides what to do by removing the first word and comparing it to a list of command. Then the proper function is called. I will post the code but it uses pointers to functions and some string functions that I wrote myself.
Code: |
static BOOLEAN CommandHandler(
enum porttypes port, /* FIX ME: add comment */
char *pArgs, /* FIX ME: add comment */
COMMAND_DATA *pCommandData) /* FIX ME: add comment */
{
static char cmd[MAX_LINE_LEN]; /* local buffer */
BOOLEAN found = 0; /* valid command? */
if (pArgs)
{
/* parse and remove the only the first command */
pArgs = stptok(pArgs, cmd, sizeof(cmd), " ");
/* find and execute command function */
while (pCommandData->pStr != NULL)
{
if (strcmpipgm2ram(cmd, pCommandData->pStr) == 0)
{
if (pCommandData->pFunction != NULL)
{
(void)strupr(cmd);
(void)pCommandData->pFunction(port, cmd, pArgs);
}
found = 1;
break;
}
pCommandData++;
}
}
return (found);
}
|
Here is how I declare the commands:
Code: |
/* local typedefs */
typedef rom struct _cmd_t
{
const rom char *pStr; /* command */
void (*pFunction) (enum porttypes port, char *pCmd, char *pArgs); /* command function */
const rom char *pDescription; /* command description (for help) */
} COMMAND_DATA;
static COMMAND_DATA CommandData[] =
{
/* hidden commands - description is NULL */
{ { "help" }, VHelpCommand, { NULL } },
{ { "OK" }, NULL, { NULL } },
{ { "RING" }, AnswerCommand, { NULL } },
{ { "CONNECT" }, ConnectCommand, { NULL } },
{ { "SELFTEST" }, SelfTestCommand, { NULL } },
{ { "VIRGINIZE" }, VirginCommand, { NULL } },
{ { "date" }, DateCommand, { "get/set date mm/dd/yyyy" } },
{ { "time" }, TimeCommand, { "get/set time hh:mm:ss" } },
/* application commands */
{ { "ver" }, VersionCommand, { "get program version" } },
{ { "name" }, NameCommand, { "program/view device name" } },
{ { "modem" }, ModemCommand, { "program/view modem data" } },
{ { "event" }, EventCommand, { "program/view event data" } },
{ { "eventlist" }, EventListCommand, { "view current event schedule" } },
{ { "holiday" }, HolidayCommand, { "program/view holiday data" } },
{ { "relay" }, RelayCommand, { "program/view relay data" } },
{ { "input" }, InputCommand, { "program/view input data" } },
{ { "photocell" }, PhotocellCommand, { "program/view photocell data" } },
{ { "remote" }, RemoteCommand, { "program/view remote input data" } },
{ { "mask" }, MaskCommand, { "program/view mask data" } },
{ { "location" }, LocationCommand, { "program/view location" } },
{ { "password" }, PasswordCommand, { "program/view password data" } },
{ { "data" }, DataCommand, { "view program data" } },
{ { "reinit" }, ReInitCommand, { "reinitialize program data" } },
{ { "restart" }, RestartCommand, { "restart system" } },
{ { "bootmode" }, BootCommand, { "puts the device into bootmode" } },
{ { "checksum" }, ChecksumCommand, { NULL } },
{ { "??" }, VHelpCommand, { "verbose help" } },
{ { "?" }, THelpCommand, { "terse help" } },
{ { NULL }, NULL, { NULL } },
};
|
And here is one of the functions:
Code: |
static void TimeCommand(
enum porttypes port, /* (IN) communication port */
char *pCmd, /* (IN) command string */
char *pArgs) /* (IN) optional arguments */
{
UINT8 hour = 0;
UINT8 minute = 0;
UINT8 second = 0;
UINT8 count = 0;
char buf[MAX_LINE_LEN]; /* local buffer */
(void)pCmd;
if (pArgs && isdigit(pArgs[0]))
{
count = sscanf(pArgs, "%b:%b:%b", &hour, &minute, &second);
if (count >= 2)
{
if (Time_SetTime(hour, minute, second))
{
Event_Restart();
PrintStatus(port, TRUE);
}
else
PrintStatus(port, FALSE);
}
else
PrintStatus(port, FALSE);
}
else
{
hour = Time_GetHours(Systemtime.time);
minute = Time_GetMinutes(Systemtime.time);
second = Systemtime.second;
sprintf(buf, "%02d:%02d:%02d\r\n", (int)hour, (int)minute, (int)second);
HostWrite(port, buf);
}
return;
}
|
If some of the syntax seem unfamilar, it is because these are actually snippets from some code that I wrote for the Microchip C18 compiler. Hey, it is C though! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Nov 16, 2003 6:01 pm |
|
|
Quote: | OK I see from this that it takes the following form:
void get_string(char * s,int max)
Does this mean that 'max' defines the maximum number of characters that can be accepted by this function? What does 'len' do? |
'max' is actually the buffer size. The number of chars you
can enter is 1 less than this amount. ie, in the following
program, you can enter up to 3 chars. The last buffer element
is reserved for the string terminator char of 0, which is
inserted by get_string().
'len' is an internal variable used by the function to keep
track of how many chars you have entered. You don't
have to deal with 'len', because it's not part of the parameter
list. You only have to specify the buffer pointer, and the
buffer size.
Code: | #include <16F877.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 8000000)
#use rs232(baud = 9600, xmit=PIN_C6, rcv = PIN_C7, ERRORS)
#include <input.c>
#define BUF_SIZE 4
main()
{
char array[BUF_SIZE];
// Type in a string, and then press the Enter key.
get_string(array, BUF_SIZE);
printf("\n\r%s", array); // Display the string.
while(1);
} |
|
|
|
adrian
Joined: 08 Sep 2003 Posts: 92 Location: Glasgow, UK
|
|
Posted: Tue Nov 18, 2003 2:15 am |
|
|
Many thanks for your help guys - I now have working code. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|