View previous topic :: View next topic |
Author |
Message |
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Keypad entries |
Posted: Sun Feb 21, 2016 1:23 pm |
|
|
I have my keypad entry software running which returns ASCII characters and echoes them on an LCD. I use PCM, PIC16F1938, MPLAB, ICD3 programmer.
I want to have interactive entries such as
Enter Serial number: (1 to 99, 8 bit integer)
Enter Amp-Hours: (mAH to 100 AH, some fractional such as 10.4AH)
I will have to use the * as a decimal point. The keypad has an ENTER key and UP and DOWN arrows.
The entries must be placed in strings and converted to integer and floating point numbers. I would prefer not to be forced to exact entries (e.g. S/N 7 having to be entered as 07), and have accidental letters rejected. Of course there have to be limits. I can start from scratch which would be foolish if most of the software exists already.
I have been through the CCS examples and ex_fixed.c, ex_float.c, and ex_str.c look useful. A search here in the forum only turned up programs to read the keypad such as I already have.
Does anyone have any suggestions? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 21, 2016 1:48 pm |
|
|
Look at this file:
Quote: | c:\program files\picc\drivers\input.c |
|
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Sun Feb 21, 2016 2:26 pm |
|
|
Yes, I have a printout of that and looked at it but it is uncommented, is just a page long, and does not even say what it is supposed to do. When I see code with no comments I tend to skip it which is what happened.
That said I checked the latest version and find it is now several pages instead of the one and does have a heading but still no comments in the code. It does indeed look like a useful place to start. Thank you for pointing that out PCM programmer.
I went through all the examples and even made a list of the headings for future reference. I found many examples disappointing from lack of commenting and some still have no headings and even have file names different from the example name. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9216 Location: Greensville,Ontario
|
|
Posted: Sun Feb 21, 2016 3:40 pm |
|
|
If it was me, I'd grab my 30 year old TRS80 Custom Basic book that has an entire chapter on 'formatted' data entry then convert the BASIC into CCS C. Or look at what's on my 30+ year old TRS-80 III.
Nowadays though, I suppose you could 'google' 'c code formated data entry examples' or some thing similar as you are not the first one needing this type of code 'formatted data entry' does allow for 'limits', 'alpha vs numerics', 'formats', etc. and is based upon a core of low level inputs( a keypressed) returned to a 'function' that decides what needs to be done. It is a 'layered' process and there must be a zillion examples on the Web. It's one of those 'do it once, save as a personal library' projects as you'll reuse it over and over again.
I do remember doing it with a 'telephone' style keypad so you could enter letters like 'B' by pressing #2 down 3 times (2AB) within a time slice,timeout and 'B' is the returned entry. Old school stuff , efficient and small code.
Jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 21, 2016 3:51 pm |
|
|
Quote: | I found many examples disappointing from lack of commenting. |
Which routines do you want to see commenting on ? |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Sun Feb 21, 2016 4:35 pm |
|
|
First of all I'm not using RS232 or higher level functions which is probably half my problem..
As an example consider the following code:
Code: | // get battery serial number
sprintf(buff, "Battery S/N ?"); // place text string in buffer
text_position(0,1); // start, second line
send_str(buff); // display text array
for (i=2; i>0; i--) // get S/N in reverse order
{
while (!key) // wait for ISR to trigger
NOP; // do nothing
bat_SN[i] = key; // save serial number
} |
The serial number is going to be entered backwards so I either have to enter as shown with a problem of the null for the string, or I have to reverse the array after entry.
The next problem is I cannot find an equivalent of assembly NOP unless the K&R dummy() function is what is required.
I could forget the ISR and make the keypad entry a function then use it within a C function like getc. I forget how but I think I did something similar once before.
What happens if I enter 10.3 ampere hours in one situation, then 0.1200 AH for the next. Am I just making life difficult expecting variable format floating point numbers and should all entries be xx.xx so the examples must be entered as 10.30 and 00.12 ?
This is a spinoff project from my battery monitor in my ROV. That was easier because there was no ASCII entries from a keypad to deal with. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 21, 2016 5:47 pm |
|
|
Quote: | The serial number is going to be entered backwards |
Why does it have to be entered backwards ?
Quote: | The next problem is I cannot find an equivalent of assembly NOP |
It's this:
But why do you need it ? You can just put a semi-colon at the end of
the while statement, and it will loop while key == 0. Example:
Quote: |
What happens if I enter 10.3 ampere hours in one situation, then 0.1200
AH for the next. |
Get those numbers as strings, and atof() will convert them to floats. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Sun Feb 21, 2016 6:13 pm |
|
|
Thanks PCM.
When you enter 23 on a keypad the 2 goes into the array first, then the 3 so if you read it out in sequence it comes out 32. It has to be switched somewhere.
It's getting the characters into strings that is the problem. Once converted to numbers the problem is solved.
Correction! I have been thinking shift registers. Of course the characters are stored first in first out. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9216 Location: Greensville,Ontario
|
|
Posted: Sun Feb 21, 2016 7:52 pm |
|
|
for (i=2; i>0; i--) // get S/N in reverse order
Not to sure WHY you're counting backwards......
for(i=0;i>2;i++) // should work for you...
Jay |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Sun Feb 21, 2016 9:49 pm |
|
|
temtronic see my correction above.
I now have my string entry working:
Code: | char buff[buff_size];
char bat_SN[8]="ABCDEF"; // batery serial number
// get battery serial number
sprintf(buff, "Battery S/N ?"); // place text string in buffer
text_position(0,1); // start, second line, LCD function
send_str(buff); // display text array, LCD function
for (i=0; i<2; i++) // get characters
{
while (!key); // wait for key press
bat_SN[i] = key; // store the character
key=0; // clear the flag for ISR
enable_interrupts(INT_RB); // reset the interrupts that
enable_interrupts(global); // were cleared in the ISR
}
// display S/N
sprintf(buff, "Battery S/N = %s", bat_SN); // place text string in buffer
text_position(0,2); // start, second line
send_str(buff); // display text array
|
The problem now is that I want to enter more parameters into the string but only access certain ones. I guess I have to copy them out to another array. I cannot selectively select with sprint() I don't think. Say to copy array(5 to 7) to the buffer. For example I can't do the following much as I would like to
Code: | for (i=5; i<8; i++)
sprintf(buff, "Battery S/N = %c", bat_SN[i]); // place text string in buffer
|
Most of the code is in my previous posting "Interrupt does not work with different PIC" that is resolved. I hope these relevant parts are enough to get the idea across. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19480
|
|
Posted: Mon Feb 22, 2016 2:36 pm |
|
|
If you have an array. Say text[10]. Then text[3] or *(text+3), is the single _character_ at the fourth location in the array. You can print this just as any other character.
What you post will do this, but because of the way you have it written, will output the whole line with just one character each time, rather than the multiple characters. You need to separate the message output, then just append the characters.
Code: |
sprintf(buff,"Battery S/N = ");
for (i=5; i<8; i++)
sprintf(buff+i+9, "%c", bat_SN[i]); // place characters in buffer
|
|
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Feb 22, 2016 8:31 pm |
|
|
Thanks for the great tips. I will try them out.
These are my thoughts on what I want to accomplish.
I want to store battery data in EEPROM (non-volatile memory) by battery serial number (s/n).
The first location will contain the last s/n stored and will be set to 0 at initial programming. Battery data will be stored in blocks accessed by the serial number of the battery and an offset. [(s/n – 1) * offset + 1] so, for example, with an offset of 10 the s/n 1 data starts at 1, s/n 2 starts at 11, etc. The s/n does not need to be stored.
A block of data may look like this:
Type of battery: 1=Lead Acid, 2=Gel, 3= NiCad, 4=NiMH, 5=LiPO, 6=LiFePO4 (integer)
Number of cells. This is used to get the battery voltage and the discharge voltage point. (integer)
Rated A-H. This is used to set the standard discharge current for testing. (float)
The measured A-H at the standard discharge current. (float)
The optional measured A-H for a specific current. (float)
The specific current for the optional A-H measurement. (float)
The program will ask for the s/n and if new will ask for Type, number of cells, and rated A-H. The rest will be calculated as requested. If the s/n is not new then the data is retrieved and displayed waiting for an instruction.
Display output will be to a working 128x64 serially driven graphics LCD described in one of my posts in this forum. It makes graphics a snap.
Input is the question now. I can input to an array as just described above but, and correct me if I’m wrong...
As has been pointed out to me there are better ways. There is a way to place a function to replace normal I/O. For example in another application I used
Code: | printf (lcd_putc,"\fVolts = %f\n", volts); |
where lcd_putc was a function in an include file.
It seems fgetc() will input a single character and fgets() will input a stream while scanf() does not seem suitable for this application. There may be others.
If I write a keypad input function I can place it in fgetc() or fgets() as the source string something like this:
Code: | char get_keypad (void); // function prototype
char buffer [20]; // buffer big enough for all entries
int max=2; // # of char expected
fgets(buffer, max, get_keypad); // get the string of ASCII characters into the buffer
| This would enter the characters into the buffer. Next I need to convert the characters to integer or floating point. atoi() will convert a string of ASCII entries into integer. atof() will convert a string of ASCII entries into floating point. Now I can store the data into EEPROM.
Question: Is there a way to use the ISR keypad entry with fgetc() or fgets() instead of re-writing it as a function ? Interrupt has the advantage of being able to abort the current operation.
Question: input.c looks interesting. How do I use it? I could copy the functions I need and modify them. Is it intended to be used as an include file? I know the general meaning of ifndef and ifdef but I have no idea how I would define anything for this program. I need just one example and where I would place it. |
|
|
|