PDA

View Full Version : Handling a lot of text data, any simple and practical ways?



CuriousOne
- 12th September 2021, 11:03
Hello.
I had a Noritake VFD module lying around, and decided to make a clock out of it.
Since it is HD47780 compatible, there were no issues for main display code, as you can see from the attached picture.
9073

And since this is 2x20 lines display, it is logical that for clock setup menu I'd like to use text, rather than icons or numbers.

This is the text strings I'd like to use in the setup menu.



Set Year
Set Month
Set Date
Set day of week
Set Hour
Set Minute
Set alarm mode
Off
On all week
On without weekends
Set alarm hours
Set alarm minutes
Set display format
Imperial (12Hr/F)
Metric (24Hr/C)
Display brightness
Auto
25%
50%
75%
100%


Total, 21 lines of text.
In a "classic", old school basic, I would do it via arrays, say like this:


DIM A$(21) ' declare string array
A$(1)="Set Year"
A$(2)="Set Month"

and so on, and when needed to display that text in the code below
I would just write
LCDOUT $FE, $C0, A$(2) or whatever number needed

With PBP I can't, so I have to introduce 21 separate LCDOUT statements.
So is there a way to avoid this?

HenrikOlsson
- 12th September 2021, 13:16
Here's one way, a bit wasteful on FLASH with the fixed length but compared to individual HSEROUT (or LCDOUT) statements I'd imagine it's quite a bit smaller.


Strings CON EXT

i VAR BYTE
Char VAR BYTE
StringNumber VAR BYTE
StartAddress VAR WORD

Goto OverStrings
ASM
Strings
; Strings, fixed length, 20 characters including null terminator.
; Actual string terminatesends with a NULL and is then padded to exactly 20 chars.
db "Set Year", 0, " " ; 0
db "Set Month", 0, " " ; 1
db "Set Date", 0, " " ; 2
db "Set day of week", 0, " " ; 3
db "Set Hour", 0, " " ; 4
db "Set Minute", 0, " " ; 5
db "Set alarm mode", 0, " " ; 6
db "Off", 0, " " ; 7
db "On all week", 0, " " ; 8
db "On without weekends", 0, "" ; 9
db "Set alarm hours", 0, " " ; 10
db "Set alarm minutes", 0, " " ; 11
db "Set display format", 0, " " ; 12
db "Imperial (12Hr/F)", 0, " " ; 13
db "Metric (24Hr/C)", 0, " " ; 14
db "Display brightness", 0, " " ; 15
db "Auto", 0, " " ; 16
db "25%", 0, " " ; 17
db "50%", 0, " " ; 18
db "75%", 0, " " ; 19
db "100%", 0, " " ; 20
ENDASM
OverStrings:


Init:
ANSELF = 0
WPUF.1 = 0
TRISF.3 = 0
TRISF.0 = 0
TRISF.1 = 1

Start:
HSEROUT["Program start",13]
HSEROUT["Address of first string: $", HEX4 Strings, 13]

Action:
StringNumber = 20 ' Select which string to print
GOSUB PrintString ' And, you guessed it, go print it.
PAUSE 100
END


PrintString:
StartAddress = Strings + (StringNumber * 20) ' Precalculate address of first char of string in question
For i = 0 to 19 ' Maximum string length is 20 characters
ReadCode (StartAddress + i), Char ' Get a char from string in question.
IF (Char = 0) THEN EXIT ' Break out if char is NULL
HSEROUT[Char] ' Otherwise print it.
NEXT
RETURN

/Henrik.

CuriousOne
- 12th September 2021, 14:29
Thanks!
I had a almost similar approach -
The text is stored in EEPROM part of the IC, in series.
There is a 40 byte area at beginning in EEPROM, which
has offset and length entries for these text messages
so all I have to do, to say display "Set Time" is call a routine like



READ 1,A 'read offset
READ 2,B 'read length
FOR C=A to A+B 'define a loop from this to that
READ C,D 'read eeprom at needed value
LCDOUT $FE,D,$14 'Display char and move cursor to next char
NEXT


But for some reasons it does not works, seems like that LCDOUT on initialization, resets the offset set by $14 (move cursor right)

HenrikOlsson
- 12th September 2021, 14:46
LCDOUT $FE,D,$14 'Display char and move cursor to next char
That line of code does NOT do what the comment says.

You're telling it to interpret whatever you read from EEPROM (into the D variable) as a command, then you're sending a constant $14 which it will interpret as data and print whatever character that code corresponds to (see datasheet).

To do what the comment says it would look like this:

LCDOUT D, $FE, $14
With that said, the adress counter in the HD44780 will automatically increment each time you write to DDRAM (ie send it a byte not preceded by $FE) so by doing the above you will end up with a blank space between the characters.

CuriousOne
- 12th September 2021, 14:51
Oh thanks, will give it a try!

richard
- 13th September 2021, 05:15
on a 16f like this


;16f1825#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_OFF & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF
#ENDCONFIG


DEFINE OSC 32
OSCCON=$70
ANSELA=0
ANSELC=0
TRISA = %001110
trisc = %11100010 ' set PORTC I/O
Strings CON EXT


i VAR BYTE
Char VAR BYTE
ctemp VAR WORD
StringNumber VAR BYTE
StartAddress VAR WORD
rand VAR WORD
lata.0=1
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0 ; if not used for pwr
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0
pause 2000
Debug "Start",13 ,10
Goto OverStrings
ASM
Strings
; Strings, fixed length, 20 characters including null terminator.
; Actual string terminatesends with a NULL and is then padded to exactly 20 chars.
da "Set Year", 0, " " ; 0
da "Set Month", 0, " " ; 1
da "Set Date", 0, " " ; 2
da "Set day of week", 0, " " ; 3
da "Set Hour", 0, " " ; 4
da "Set Minute", 0, " " ; 5
da "Set alarm mode", 0, " " ; 6
da "Off", 0, " " ; 7
da "On all week", 0, " " ; 8
da "On without weekends", 0, "" ; 9
da "Set alarm hours", 0, " " ; 10
da "Set alarm minutes", 0, " " ; 11
da "Set display format", 0, " " ; 12
da "Imperial (12Hr/F)", 0, " " ; 13
da "Metric (24Hr/C)", 0, " " ; 14
da "Display brightness", 0, " " ; 15
da "Auto", 0, " " ; 16
da "25%", 0, " " ; 17
da "50%", 0, " " ; 18
da "75%", 0, " " ; 19
da "100%", 0, " " ; 20
ENDASM
OverStrings:


Start:
Debug "Program start",13,10
Debug "Address of first string: $", HEX4 Strings, 13 ,10


Action:
RANDOM rand
StringNumber = rand//20 ' Select which string to print
GOSUB PrintString ' And, you guessed it, go print it.
PAUSE 1000
goto Action
END


PrintString:
StartAddress = Strings + (StringNumber * 11) ' Precalculate address of first char of string in question
For i = 0 to 19 ' Maximum string length is 20 characters
ReadCode (StartAddress + i), CTEMP ' Get a char from string in question.
Char = (CTEMP>>7)
IF (Char = 0) THEN EXIT ' Break out if char is NULL
Debug Char ' Otherwise print it
Char = CTEMP&$7f
IF (Char = 0) THEN EXIT ' Break out if char is NULL
Debug Char ' Otherwise print it
NEXT
RETURN

or if all that padding is troubling , using random length null terminated strings

;16f1825#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_OFF & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF
#ENDCONFIG


DEFINE OSC 32
OSCCON=$70
ANSELA=0
ANSELC=0
TRISA = %001110
trisc = %11100010 ' set PORTC I/O
Strings CON EXT
i VAR BYTE
Char VAR BYTE
ctemp VAR WORD
rand VAR WORD
StringNumber VAR BYTE
StartAddress VAR WORD
isa VAR WORD
lata.0=1
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0 ; if not used for pwr
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0
pause 2000
Debug "Start",13 ,10
Goto OverStrings
ASM
Strings
; string terminates with a NULL
da "Set Year", 0 ; 0
da "Set Month", 0 ; 1
da "Set Date", 0 ; 2
da "Set day of week", 0 ; 3
da "Set Hour", 0 ; 4
da "Set Minute", 0 ; 5
da "Set alarm mode", 0 ; 6
da "Off", 0 ; 7
da "On all week", 0 ; 8
da "On without weekends", 0 ; 9
da "Set alarm hours", 0 ; 10
da "Set alarm minutes", 0 ; 11
da "Set display format", 0 ; 12
da "Imperial (12Hr/F)", 0 ; 13
da "Metric (24Hr/C)", 0 ; 14
da "Display brightness", 0 ; 15
da "Auto", 0 ; 16
da "25%", 0 ; 17
da "50%", 0 ; 18
da "75%", 0 ; 19
da "100%", 0 ; 20
dw 3 ;eof
ENDASM
OverStrings:


Start:
Debug "Program start",13,10
Debug "Address of first string: $", HEX4 Strings, 13 ,10


Action:
RANDOM rand
StringNumber = rand//20 ' Select which string to print
GOSUB findIndex
GOSUB PrintString ' And, you guessed it, go print it.
PAUSE 1000
goto Action
END


findIndex:
isa = Strings
while StringNumber
ReadCode isa, CTEMP
isa=isa+1
if CTEMP ==3 then
isa=0
return
endif
if (CTEMP.highbyte==0) then
StringNumber=StringNumber-1
if StringNumber == 0 then return
endif
wend
return


PrintString:
if isa then
Debug 13,10
For i = 0 to 19 ' Maximum string length is 20 characters
ReadCode (isa + i), CTEMP ' Get a char from string in question.
Char = (CTEMP>>7)
IF (Char = 0) THEN EXIT ' Break out if char is NULL
Debug Char ' Otherwise print it
Char = CTEMP&$7f
IF (Char = 0) THEN EXIT ' Break out if char is NULL
Debug Char ' Otherwise print it
NEXT
endif
RETURN
9074

HenrikOlsson
- 13th September 2021, 05:52
Thanks for stepping in Richard, I should've mentioned my example was for 18F series of course. Yeah, the padding... It's a tradeoff, either waste memory or waste some time :-)

In your code I see

if (CTEMP.highbyte==0) || (CTEMP.highbyte ==0) then
I suppose one of those should be CTEMP.lowbyte, right?

richard
- 13th September 2021, 05:57
I suppose one of those should be CTEMP.lowbyte, right?

̶y̶e̶s̶ ̶,̶ ̶c̶o̶p̶y̶ ̶p̶a̶s̶t̶e̶ ̶t̶r̶a̶p̶ ̶f̶o̶r̶ ̶t̶h̶e̶ ̶i̶n̶o̶b̶s̶e̶r̶v̶a̶n̶t̶

its a pity the the forum edit restraints are so limiting

needs to be this , adding lowbyte breaks it
if (CTEMP.highbyte==0) then

richard
- 13th September 2021, 06:38
adding lowbyte breaks it
i remember it now , if you really want to be sparing with flash space odd length strings must not have the ,0 termination
the assembler adds the 0 for odd lengths automatically. the code then needs to check lowbyte for 0-ness

if you add the ,0 you wind up with 3 nulls in a row to account for hence only a check of highbyte works

CuriousOne
- 14th September 2021, 21:07
And what if I add some special character to my data array, so when reading it, I do not no longer need to store length of each string? This should allow me to skip all that ASM things.
And meanwhile, I have a little problem with usability.

I have this routine for handling two buttons connected via ADC.



do
adcin 0,cnt
if CNT<900 then'if any button pressed, increase debounce variable
dly=dly+1
pause 1
endif
if CNT<100 and DLY>100 then 'if left is still pressed
dly=0 'reset debounce counter
task1:
endif
if CNT<900 and CNT>100 and DLY>100 then 'if right is still pressed
dly=0 'reset debounce counter
task2:
endif
loop


It analyzes, whenever any button is pressed, and launches debouncer loop, to avoid accidental presses. That works fine. This code is repeated several times in sequence, according to menu items, with different task1/task2 -s inside.
But the problem is, that if user keeps pressing the "left" button, he scrolls thru the all menu items, and I want to avoid this, so when he presses the left button and keeps it pressed, He does not advance to next item, until he releases the button and presses it again. I know, this feature is a part of BUTTON statement, but due to shortage of pins, I'm using ADC input, and BUTTON statement does not works there.

any ideas?

richard
- 15th September 2021, 01:25
And what if I add some special character to my data array, so when reading it, I do not no longer need to store length of each string? This should allow me to skip all that ASM things
how do imagine that would that work ?



And meanwhile, I have a little problem with usability.

nothing that a state machine approach can't resolve

http://www.picbasic.co.uk/forum/showthread.php?t=21109
http://www.picbasic.co.uk/forum/showthread.php?t=23840

CuriousOne
- 15th September 2021, 07:03
Well say I add $FF to end of each string.
So I need only to know start address of each sentence
and start reading from there in loop, until inputchar=FF

And for the input, I can't relate capacitive input or encoder handling with my task.
These both are yes/no condition, and mine is analog reading...

richard
- 15th September 2021, 07:38
Well say I add $FF to end of each string.
So I need only to know start address of each sentence
and start reading from there in loop, until inputchar=FF


precisely what was offered except using the more useful and commonly accepted null in lieu of the FF


And for the input, I can't relate capacitive input or encoder handling with my task.
These both are yes/no condition, and mine is analog reading.


its the overall concept of key/sw reading to observe, its a universal concept

CuriousOne
- 16th September 2021, 13:15
Well, my code has no ASM :)

P.S. A big brother just arrived :)
But can't make it work with PBP :(

9075

richard
- 17th September 2021, 04:20
Well, my code has no ASM

or code either it seems

mpgmike
- 17th September 2021, 05:30
It was once stated by someone with a certifiable IQ that boggles the mind, "There is nothing new in the universe". On a more micro scale, many issues we face as we try to get tiny little black plastic blocks to do what we want them to, using resources available, we have to realize that many of our challenges have been faced and conquered in the past. I try to make it a habit to search forums for clues, or out-right answers before posting questions. Not to discourage anyone from creating a new post, but when effective answers don't seem to be forthcoming, maybe as a second resort, do a search. Don't forget, this is not the only PBP forum (ME Labs, the creator of PBP, has their own forum -- though not as popular -- at http://support.melabs.com).

I faced some programming challenges in the past using newer PIC chips with Peripherals not dealt with by standard PBP commands. My solution was to familiarize myself with the Microchip Data Sheets, and manipulate the registers manually; which PBP competently allows me to do. I have successfully done what you're struggling with, but not with magic PBP commands. I don't know how to answer or contribute to this thread, because how I accomplished things cannot easily be transferred in a simple post. Try doing Forum searches, varying key search words and phrases. It will probably surprise you just how many different ways folks in the past have fought your struggles, and the solutions they found. Both sites are good at keeping older legacy posts available. Good luck!

CuriousOne
- 17th September 2021, 07:25
Ok thanks :)
I'm trying to read, but the main issue is, that there are very FEW code examples on forums focused exactly on topic being asked.
Say someone asks "how to debounce ADC input" and someone posts a huge code for completed device, where that code is present, but it is hidden somewhere and you have to guess where is it, which other variables and changes it uses, from that code and so on.

Contrary to them, the code examples supplied by melabs are short and spot on - they do what they have to do, only few extra lines are present.

By the way, I got big module running with parallel interface with PBP. The issue was that it needs about 330mA to operate, and PicKit 3 was not able to provide enough juice. With the help of external 5V supply, issues solved :)

richard
- 17th September 2021, 11:25
but the main issue is, that there are very FEW code examples on forums focused exactly on topic being asked.
Say someone asks "how to debounce ADC input" and someone posts a huge code for completed device, where that code is present, but it is hidden somewhere and you have to guess where is it, which other variables and changes it uses, from that code and so on.

you have to laugh . it describes this thread to a tee , well thought out practical solutions offered, that were some how unacceptable
for reasons not given " Well, my code has no ASM " perhaps. op supposedly has better solution not posted


as you sow so shall you reap

ps thanks ioannis for the edit on post 6

HenrikOlsson
- 17th September 2021, 15:38
Haha, yeah, wow :-)
You post a snippet and you get complaints about it not working because someone can't be bothered to clear TRIS and ANSEL by them them selves. So, next time you post a fully working, tailor made solution that solves exactly what was asked (which then turns out to not be what op actually MEANT) only to get complains that the code is too verbose :-)

I've spent countless hours writing snippets and full verified-to-be-working programs, both in response to questions asked on this forum and posted as examples. I enjoy doing it, I hope it helps users. I don't get paid to do it, on the contrary I've SPENT my own money buing devices, development boards, breakout boards and what not to help solve peoples issues because I've found (and still find) it interesting and fun.

Rarely have I asked myself why bother...

CuriousOne
- 19th September 2021, 13:55
I'm not complaining, I'm trying to explain.
The things that are dead simple for you, might be dead hard for me, and vice versa.
Not everyone has skills and talents for all these digital things.
You're good in coding - I'm good in something different, and someone else is good in something else.
That is the way humans are made.
So that's not a good idea to blame someone for not understanding things that you do understand.

9078