PDA

View Full Version : Embedded Strings in your Code Space



mytekcontrols
- 12th June 2005, 16:53
Thanks for the heads up on the PDS. I'll check go check it out. Although on the current project I extremely doubt I'll be jumping ship (... I can almost see the shore as we speak). However on another project, It might certainly be a consideration. How is the optimization of the code it produces?

Also as I said in my previous post, reliability plays a key role in my choice of programming tools. I tend to stick to what works, and usually find work arounds for minor ommisions. Case in point; the lack of string handling ability in PBP I quickly resolved by taking a different approach. At first I was stumped at not being able to set up a string variable that I could later pass to an I2C routine. Of course the solution came in the form of using lookup tables as shown below (printascii would go to a separate print routine for output, in my case a specialized I2C routine).

For y=0 To 255
Gosub mesghello
If ascii = Null Then exit
Gosub printascii
Next y

mesghello: Lookup y,["hello world",Null],ascii
Return

In my 6502 assembler days, I used a routine that would pop the return address off the stack, increment it by 1 to pick up the start of the ascii data to be sent, send the data, and then modify the RTS to return directly following the ascii data (next example).

jsr printascii
.byte "hello world",Null
-- rentry point upon return from printascii routine --

Much simpler, and some what more readable when looking at the source code (the messages appear where used, and not in a later table). However for messages that would be reused several times through out a program, the table approach is preferred in order to save code space. Unfortunately I haven't figured out a similar method that would work either within PBP or as an @asm script (can't pop the stack as far as I know).

I ran a suggestion by the makers of PBP about the possibility of including something like the LCDOUT command maybe in the form "BYTEOUT var{,item...} example:

ascii var byte[255]

BYTEOUT ascii,"hello world",Null
Gosub print ascii


printascii:
For y=0 To 255
If ascii[y] = Null Then Return
Gosub sendascii ' send character by whatever method desired
Next y
Return

This would yield something similar to the 6502 assembly example.

Anyway getting back to the original topic so to speak; picnaut thanks again for your sugestion about PDS.

Darrel Taylor
- 12th June 2005, 17:15
mytekcontrolsm,

Using a Lookup for strings can use up a huge amount of code. And I believe I may have the solution you're looking for.

How to store and retrieve strings in Code Space (http://www.pbpgroup.com/modules/wfsection/article.php?articleid=10)

Another person that I helped out a while back had his 877 completely maxed out with Lookups for strings to be displayed on an LCD. After converting them to the STRINGS in CODE format, it only took up 1.5K words. Leaving 6.5K for more program. We were both amazed.

And, I too will not be Jumping ship anytime soon. PBP is just to good.

Darrel

Bruce
- 12th June 2005, 17:49
Nice job Darrel, and thanks for the excellent resource. I've used several of
your routines on various projects.

Here's something similar for the 18F series.


DEFINE LOADER_USED 1
DEFINE OSC 4

ptr_pos VAR BYTE
temp VAR BYTE
x VAR BYTE

Main:
CALL USART_Init
ptr_pos = 0
CALL Start
ptr_pos = 16
CALL Start
ptr_pos = 48
CALL Start
ptr_pos = 176
CALL Start

Done:
GOTO Done

ASM
_USART_Init
movlw B'00100100' ;initialize USART
movwf TXSTA ;8-bit, Async, High Speed
movlw .25 ;value for 9600 bps @ 4MHz
movwf SPBRG ;set SPBRG for 9600 bps @ 4MHz
movlw B'10010000' ;enable USART
movwf RCSTA
return

;----Lookup & send text messages--------------------------
_Start
movlw UPPER msg_table
movwf TBLPTRU
movlw HIGH msg_table
movwf TBLPTRH
movlw LOW msg_table
movwf TBLPTRL
movf _ptr_pos,W ;prt_pos must hold message address
addwf TBLPTRL,F
clrf WREG
addwfc TBLPTRH,F
addwfc TBLPTRU,F

Next_Char
tblrd *+
movff TABLAT,_temp
bra Test_EOM ;test for EOM character

Continue
movf _temp,W ;move temp to w
movwf TXREG ;send it
btfss TXSTA,TRMT ;wait for data TX
goto $-2
bra Next_Char ;fetch next message character from table

Test_EOM
movlw "~" ;check for EOM character
cpfseq _temp, 1 ;compare temp with w, if temp = ~ then end
bra Continue ;no EOM, so continue
movlw "\r" ;move data into TXREG
movwf TXREG ;send carriage return
btfss TXSTA,TRMT ;wait for data TX
goto $-2
movlw "\n" ;move data into TXREG
movwf TXREG ;send line feed
btfss TXSTA,TRMT ;wait for data TX
goto $-2
return ;finished with message, return to caller
ENDASM

ASM
msg_table ; Message strings
data " Message #1~ ";Message #1 starts at msg_table 0
data " Message #2~ ";Message #2 starts at msg_table 16, etc,
data " Message #3~ ";32
data " Message #5~ ";48
data " Message #6~ ";64
data " Message #7~ ";80
data " Message #8~ ";96
data " Message #9~ ";112
data " Message #10~ ";128
data " Message #11~ ";144
data " Message #12~ ";160
data " Message #13~ ";176
ENDASM

Darrel Taylor
- 12th June 2005, 19:22
Now there's an endorsement I can be proud of.

Thanks Bruce!

mytekcontrols
- 13th June 2005, 00:28
Thanks Darrel and Bruce for your great examples. I would have to say I like Darrel's approach the best, since it seems less cryptic as to what the messages are (i.e; you can give them meaningfull names). Also I like the idea that they can be located anywhere in the program (kinda like my 6502 example). However I am using an 18F252 for my project, and apparently this approach wont work with a 16 bit processor. Any ideas how this could be changed?

Bruce
- 13th June 2005, 01:44
' Text message addresses w/specific names
Intro CON 0
PumpOn CON 16
PumpOFF CON 32 ' etc,,

ptr_pos = Intro ' print intro message
CALL Start
ptr_pos = PumpON ' print pump on message, etc,,,
CALL Start

You now have meaningful names for your strings. It's not that cryptic once
you've played with it a bit. The 18F series are easier to code in .asm than
16F parts.

Make your strings as long as you like. That was just a quick/simple example.

I don't have an example for placing strings all over code space since I would
never do that. PBP library functions & my app code get first pick. Huge
chunks of text messages get the left-overs at the bottom...;o]

Darrel Taylor
- 13th June 2005, 05:18
Hi again Michael,

I guess it was about time anyhow. Haven't updated it since 2003.

I've modified the Strings program to be able to work with 16-bit devices.

Between Bruce's example and the new one, I'm sure you'll get what you need.

It's still in the same place ... How to store and retrieve strings in Code Space (http://www.pbpgroup.com/modules/wfsection/article.php?articleid=10)

Best regards,
   Darrel

mytekcontrols
- 30th June 2005, 00:13
Hi Bruce,

I have been studying your code that you posted here on doing message tables from assembly code, and quite frankly I am baffled by parts of it. This wouldn't be problem if I could use it as is, but I really need to have the pointer increments to be by 1 (i.e.; 0,1,2,3,4,5,6, ect.).

Here are some snippits of your code with some questions I have next to them. If you get a chance can you please explain what is going on?



; This section appears to be locating the message table, but Im not
; really sure specifically what is going on especially with the first part
; where you are moving Upper msg_table into TBLPTRU
; (what is UPPER? I've used HIGH and LOW before, but never UPPER).
; TBLPTR is obviously short for Table Pointer.

movlw UPPER msg_table
movwf TBLPTRU
movlw HIGH msg_table
movwf TBLPTRH
movlw LOW msg_table
movwf TBLPTRL

; Now here we seem to be adding an offset into the message table using
; the same pointers we previously set to what I am asuming is the base
; address of our message table. This is where the beginning of a particular
; message resides within the table (correct?). Now here comes the questions
; of particular interest to me; does the fact that your pointers are in 16 byte
; increments mean that each message string can only be up to 16 bytes long?
; Or can the pointer be changed to any increment desired?

movf _ptr_pos,W ;prt_pos must hold message address
addwf TBLPTRL,F
clrf WREG
addwfc TBLPTRH,F
addwfc TBLPTRU,F

; Ok now that we have our index to a message set, we can begin retrieving
; the characters one by one, until we see the EOM character "~". What is
; tblrd *+ or more specifically *+ (is this doing a read and then increment?)
; Oh and what is "goto $-2" doing? (specifically $-2).

Next_Char
tblrd *+
movff TABLAT,_temp
bra Test_EOM ;test for EOM character

Continue
movf _temp,W ;move temp to w
movwf TXREG ;send it
btfss TXSTA,TRMT ;wait for data TX
goto $-2
bra Next_Char ;fetch next message character from table

; This part is fairly obvious, although there are some more of those $-2
; which I don't understand the purpose of, and what does "\r"
; and "\n" do? Actually to be more specific since I can see your comments,
; what my question really is; what or how does moving a literal of "\r" into
; W actually move the data (which I assume is a character from the table).

Test_EOM
movlw "~" ;check for EOM character
cpfseq _temp, 1 ;compare temp with w, if temp = ~ then end
bra Continue ;no EOM, so continue
movlw "\r" ;move data into TXREG
movwf TXREG ;send carriage return
btfss TXSTA,TRMT ;wait for data TX
goto $-2
movlw "\n" ;move data into TXREG
movwf TXREG ;send line feed
btfss TXSTA,TRMT ;wait for data TX
goto $-2
return ;finished with message, return to caller


If I was better versed in the assembly aspects of the 18F series I could probably figure this out on my own, but I only recently began working with this series of PIC chips.

Any help you can offer is appreciatted.
Thanks,

Bruce
- 30th June 2005, 04:48
Hi Michael,

Download the PICmicro® 18C MCU Family Reference Manual... or just the chapters you need from here;

http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2054

There's a whole section on table read/write with detailed explanations that should answer every question you have.

Much easier than me re-typing it all. If you have questions after reading section 8 let me know.

mytekcontrols
- 1st July 2005, 00:20
Hi Darrel - Hi Bruce,

Darrel I checked out your new message table code for 16 bit pics. Very Nice!

Bruce I read up on the info you linked me to, and I have a pretty good grasp of what you are doing in your code. I also figured out that the GOTO $-2 is just a slick way to skip backwards without having to use a labeled reference.

Well of course after getting my brain filled with a bit more knowledge I decided to try my hand at writing yet another variation on message string handling, but not without problems (and a smoking head). Check out this code:


DEFINE LOADER_USED 1
DEFINE OSC 40 ' change to suit oscillator speed
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 20h
DEFINE HSER_BAUD 19200 ' change to suit baud rate

message var byte[40]
stringsize var byte
x var byte
temp var byte
Clr

Main:
Call getSTR
@ data "This is a string",0
Gosub putSTR

' Call getSTR
'@ data "yet another string again",0
' Gosub putSTR
Done:
Goto Done

putSTR:
For x = 0 To (stringsize-1)
temp = message[x]
Hserout [temp]
Next x
Hserout [$0D,$0A] ; send carriage return + line feed
stringsize = 0 ; reset for next message
Return

asm
_getSTR
LFSR FSR0,_message ; set message array base address

;copy return address to TBLPTR and then pop it off the stack
movf TOSU,W
movwf TBLPTRU
movf TOSH,W
movwf TBLPTRH
movf TOSL,W
movwf TBLPTRL
POP

;TBLPTR should now be pointing to 1st character in string
Next_Char
tblrd *+ ; table read and post increment TBLPTR
movf TABLAT,W ; retrieve character to W register
movwf POSTINC0 ; xfer to message array and increment FSR
incf _stringsize,F ; keep track of message string size
movf TABLAT,W ; Is character = 0?
bnz Next_Char ; If not, then get next character

;use incremented value of TBLPTR as new return address (push it)
movf TBLPTRU,W
movwf TOSU
movf TBLPTRH,W
movwf TOSH
movf TBLPTRL,W
movwf TOSL
PUSH
return ;finished with message, return to caller
endasm

It's more of a variation of what Darrel's code does. Only I wanted to try using the POP and PUSH functions on the PIC18F to allow me to have embedded message strings (this is a pet peeve of mine). Anyway if you run the code as is (leave the 2nd message string commented out) everything works great. However if you try to use more then one message (uncomment the 2nd message string) then all hell breaks loose, and you end up with garbled messages and a runaway processor.

Any ideas what I am doing wroung?

Bruce
- 1st July 2005, 03:13
Well.. that certainly is a creative approach. I guess you did do some
reading ehh..;o]

Initialize your stringsize variable before you start incrementing it.

Move the PUSH up to the entry point of the section "before" modifying
TOS.

See how this works.


DEFINE LOADER_USED 1
DEFINE OSC 40 ' change to suit oscillator speed
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 20h
DEFINE HSER_BAUD 19200 ' change to suit baud rate

message var byte[40]
stringsize var byte
stringsize = 0 ; <-- initialize to zero here. Don't wanna incf if it's not
x var byte ; starting at zero
temp var byte
Clr

Main:
Call getSTR
@ data "This is a string",0
Gosub putSTR

Call getSTR
@ data "yet another string again",0
Gosub putSTR
Done:
Goto Done

putSTR:
For x = 0 To (stringsize-1)
temp = message[x]
Hserout [temp]
Next x
Hserout [$0D,$0A] ; send carriage return + line feed
stringsize = 0 ; reset for next message
Return

asm
_getSTR
LFSR FSR0,_message ; set message array base address

;copy return address to TBLPTR and then pop it off the stack
movf TOSU,W
movwf TBLPTRU
movf TOSH,W
movwf TBLPTRH
movf TOSL,W
movwf TBLPTRL
POP

;TBLPTR should now be pointing to 1st character in string
Next_Char
tblrd *+ ; table read and post increment TBLPTR
movf TABLAT,W ; retrieve character to W register
movwf POSTINC0 ; xfer to message array and increment FSR
incf _stringsize,F ; keep track of message string size
movf TABLAT,W ; Is character = 0?
bnz Next_Char ; If not, then get next character

;use incremented value of TBLPTR as new return address (push it)
PUSH ; <--- moved up to here
movf TBLPTRU,W
movwf TOSU
movf TBLPTRH,W
movwf TOSH
movf TBLPTRL,W
movwf TOSL
; PUSH
return ;finished with message, return to caller
endasm

Darrel Taylor
- 1st July 2005, 04:33
This is getting interesting, and now I have a few new ideas too.

But, I think We've gone past melanie's original post of "Which PBP Compiler are you using?". So I've SPLIT it into a new thread "Embedded Strings in your Code Space". In the "mel PIC BASIC Pro" forum.

Sorry if it caused any confusion. :o

More from me soon,
&nbsp;&nbsp;&nbsp;Darrel

mytekcontrols
- 1st July 2005, 05:02
Thanks Bruce, it works great!

And now here it is utilizing your RS232 code:


DEFINE LOADER_USED 1
DEFINE OSC 40 ' change to suit oscillator speed

temp var byte

Main:
CALL USART_Init

Call prntSTR
@ data "This is a string",0

Call prntSTR
@ data "yet another string again",0

Call prntSTR
@ data "and one more time!",0

Done:
Goto Done

asm
_USART_Init
movlw B'00100100' ; initialize USART
movwf TXSTA ; 8-bit, Async, High Speed
movlw .129 ; value for 19200 bps @ 40MHz
movwf SPBRG ; set SPBRG for 19200 bps @ 40MHz
movlw B'10010000' ; enable USART
movwf RCSTA
return

_prntSTR
;copy return address to TBLPTR and then pop it off the stack
movf TOSU,W
movwf TBLPTRU
movf TOSH,W
movwf TBLPTRH
movf TOSL,W
movwf TBLPTRL
POP

;TBLPTR should now be pointing to 1st character in string
Next_Char
tblrd *+ ; table read and post increment TBLPTR
movff TABLAT,_temp ; fetch character from message string
bra Test_EOM ; go test for EOM character

Continue ; If not EOM then...
movf _temp,W ; move character into TXREG and...
movwf TXREG ; send it!
btfss TXSTA,TRMT ; has it been transmitted?
goto $-2 ; If not, keep checking
bra Next_Char ; fetch next message character from table

Test_EOM
movlw .0 ; check for EOM character
cpfseq _temp,W ; compare temp with w, if temp = 0 then end
bra Continue ; no EOM, so continue
movlw "\r" ; move carriage return into TXREG and...
movwf TXREG ; send it!
btfss TXSTA,TRMT ; has it been transmitted?
goto $-2 ; If not, keep checking
movlw "\n" ; move line feed into TXREG and...
movwf TXREG ; send it!
btfss TXSTA,TRMT ; has it been transmitted?
goto $-2 ; If not, keep checking

;use incremented value of TBLPTR as new return address (push it)
PUSH
movf TBLPTRU,W
movwf TOSU
movf TBLPTRH,W
movwf TOSH
movf TBLPTRL,W
movwf TOSL
return ;finished with message, return to caller
endasm


This is real sweet, because all you have are 2 lines of code to send a message, and without any limitations as to how many or where they are located (assuming it fits in the program space).

Well this is what I wanted in the first place, all it took was a bit of head scratching and some terrific help from you and Darrel. Heck until I started reading through the PIC18F reference material, I had assumed that there was no way to PUSH and POP a PIC chip (BTW, that is a great link to all kinds of good information).

Next: Do the same thing for an LCD. Anyone got some good LCD asm code and an LCD to try it on?

(yet another challenge for some brave soul)

EDIT: Opps!! Darrel I guess you'll have to move this as well... Sorry

see ya,

Bruce
- 1st July 2005, 05:30
You know.. I just noticed from your earlier example that Clr wasn't returning
an error. So just out of curiosity, I tried this.

PBP v2.46, MPASM v4.01. Compiled for 18F452.


DEFINE LOADER_USED 1
DEFINE OSC 20

ptr_pos VAR BYTE
temp VAR BYTE
x VAR BYTE
Yahoo '
NoWay '
YeahSoWhat ' <-- none of this returns an error..?

Main:
High 0
pause 1000
low 0
pause 1000
goto Main
Anyone else get an error returned with this?

Darrel Taylor
- 1st July 2005, 05:49
Any single word lines in PBP automaticaly become a Label. Even though they don't show up in MicroCode Studio until they have a colon ":" after them.

So it should have been CLEAR. But it won't show up as an error if it's not.

DT

Darrel Taylor
- 1st July 2005, 05:51
I guess the move went well, it seems to still be notifying us, and replies are going to the new thread. That's the first time I've split a thread, so I wasn't sure.

Back to the topic, this isn't quite what I had thought of earlier, but the code changed since then. I haven't had a chance to try it yet, but it does compile.

So assuming everything is working, I wanted to add one thing that gets you closer to that 1 line "embedded message strings" that you're looking for.

Here's a simple macro that should do the same thing that you have now, but only takes 1 line (of PBP code) to do it. It needs to be before Main:
ASM
SendStr macro Astring
call _prntSTR
data Astring,0
endm
ENDASM


Now in the "Main" code, it'll look like this...
Main:
CALL USART_Init

@ SendStr "This is a string"
@ SendStr "yet another string again"
@ SendStr "and one more time!"OR, of course it could also be...
ASM
SendStr "This is a string"
SendStr "yet another string again"
SendStr "and one more time!"
ENDASM
Darrel

Bruce
- 1st July 2005, 05:57
Any single word lines in PBP automaticaly become a Label. Even though they don't show up in MicroCode Studio until they have a colon ":" after them.

So it should have been CLEAR. But it won't show up as an error if it's not.

DT
Interesting. I never noticed that one before until looking at where he had
Clr instead of clear.

mytekcontrols
- 1st July 2005, 17:26
Great job Darrel! It just keeps getting better and better.

Here is the tested version of the code incorporating your changes:


DEFINE LOADER_USED 1
DEFINE OSC 40 ' change to suit oscillator speed
setSPBRG con 129 ' 19200 baudrate w/ 40Mhz OSC
' (change to suit requirements)

temp var byte ' temporary storage for character

Goto main
' Send String Macro (must be located prior to Main)
ASM
SendStr macro Astring
call _prntSTR
data Astring,0
endm
ENDASM

'=======================================
Main:
CALL USART_Init ' initialize hardware USART

' send messages through RS232
' format #1
@ SendStr "This is a string"
@ SendStr "yet another string again"
@ SendStr "and one more time!"

' format #2
ASM
SendStr "This is a string"
SendStr "yet another string again"
SendStr "and one more time!"
ENDASM

Done:
Goto Done ' loop forever

'=======================================

' USART initialization and print string code (locate anywhere)
asm
_USART_Init
movlw B'00100100' ; initialize USART
movwf TXSTA ; 8-bit, Async, High Speed
movlw _setSPBRG ; pass constant to SPBRG to
movwf SPBRG ; determine baudrate to be used
movlw B'10010000' ; enable USART
movwf RCSTA
return

_prntSTR
;copy return address to TBLPTR and then pop it off the stack
movf TOSU,W
movwf TBLPTRU
movf TOSH,W
movwf TBLPTRH
movf TOSL,W
movwf TBLPTRL
POP

;TBLPTR should now be pointing to 1st character in string
Next_Char
tblrd *+ ; table read and post increment TBLPTR
movff TABLAT,_temp ; fetch character from message string
bra Test_EOM ; go test for EOM character

Continue ; If not EOM then...
movf _temp,W ; move character into TXREG and...
movwf TXREG ; send it!
btfss TXSTA,TRMT ; has it been transmitted?
goto $-2 ; If not, keep checking
bra Next_Char ; fetch next message character from table

Test_EOM
movlw .0 ; check for EOM character
cpfseq _temp,W ; compare temp with w, if temp = 0 then end
bra Continue ; no EOM, so continue
movlw "\r" ; move carriage return into TXREG and...
movwf TXREG ; send it!
btfss TXSTA,TRMT ; has it been transmitted?
goto $-2 ; If not, keep checking
movlw "\n" ; move line feed into TXREG and...
movwf TXREG ; send it!
btfss TXSTA,TRMT ; has it been transmitted?
goto $-2 ; If not, keep checking

;use incremented value of TBLPTR as new return address (push it)
PUSH
movf TBLPTRU,W
movwf TOSU
movf TBLPTRH,W
movwf TOSH
movf TBLPTRL,W
movwf TOSL
return ;finished with message, return to caller
endasm

So now we have a single line RS232 messaging system that will work properly, assuming you don't use any interrupts in the rest of your code (that's right, this will probably fail with interrupts enabled).

Now to get the interrupt compatible version we'll need an efficient way to disable global interrupts when doing the stack manipulations. Since there are 2 levels of interrupts (GIEL and GIEH) possible on an 18 series pic it's a little more complicated. Before I dive into this does anyone have a good suggestion or example code?

Thanks,

mytekcontrols
- 1st July 2005, 19:08
If you look at the last code example you may be asking yourself "Hey isn't that the same thing as HSEROUT ["This is a string"]?"

Well... yes it is, sort of. What I really see to be accomplished here, has more to do with creating the framework for a customizable message string handling Function, then just mimicing an already available PicBasic Pro function. For testing purposes, it is just easier to send it out unaltered through the RS232 port. Ulimately, it will hopefully evolve into a great way to send either message strings, data, or both to any device you wish. While at the same time doing it in a way that is more like a built-in PicBasic Pro function.

A great example of what this could be used for, is imagine that you are interfaced to a device that would accept message strings via RS232, but always requires special commands to precede the message. Using what has already been developed here, all that would be required is to add these commands within the printSTR code (same as what was done for the carriage return and linefeed). Then every time you send a message such as @ SendStr "This is a string" the pre commands would be automatically sent as well.

Even better still, imagine if you were interfaced to several different devices or gateways, each one having special communication requirements (I2C, SPI, One-Wire, RS232, ect.). Every protocol could concievably be supported within the printSTR code, thereby allowing you to broadcast simultaneously to all devices via the single line SendStr function. Pretty cool huh!

We are only scratching the surface as to the possibilities.

Darrel Taylor
- 2nd July 2005, 06:07
Hiya Michael,

And for my next installment of things you can change with the program you already have working .... :eek:

Sometimes I go crazy with the macro's. But I kinda like this one.
'--[ Initialise USART for specified baud rate at current OSC speed ]------------
ASM
USART_Init macro Baud
clrf TXSTA, 0
_SPBRG = (OSC * 1000000) / 16 / Baud - 1 ; calc SPBRG @ High baud rate
if _SPBRG > 255 ; if SPBRG is too high
_SPBRG = (OSC * 1000000) / 64 / Baud - 1 ; calc for Low baud rate
bcf TXSTA, BRGH, 0 ; Set BRGH to Low Speed
if _SPBRG > 255
_SPBRG = 255
endif
else
bsf TXSTA, BRGH, 0 ; Set BRGH to High Speed
endif
bsf TXSTA, TXEN, 0 ; Set Transmit Enable bit
movlw _SPBRG
movwf SPBRG, 0 ; load the calulated SPBRG
movlw B'10010000' ; enable USART
movwf RCSTA, 0
endm
ENDASMNow to initialize the USART all you have to do is this...
@ USART_Init 19200
It should work with any OSC setting and any valid baud rate.

-------------------------

>> Ulimately, it will hopefully evolve into a great way to send either message strings, data, or both to any device you wish.

I've also got some MAJOR changes that allow you to do the above quote. Haven't tested them completely yet, but they look promising.

Best regards,
&nbsp;&nbsp;&nbsp;Darrel

mytekcontrols
- 2nd July 2005, 07:40
I've also got some MAJOR changes that allow you to do the above quote. Haven't tested them completely yet, but they look promising.
Hey Darrel, I really think we got you hooked on this :-)
Which is perfectly fine by me, and will surely be fun to see what's in store.

Any good ideas on the best way to deal with the interrupt disable issue? I was reading up on this a bit, and it seems like some approaches could cause latency problems. I am also not 100% sure of which parts of the stack manipulation are no no's while an interrupt is occuring (in otherwords, is it only during the PUSH, or POP or both).

My particular interest will be to implement the "printSTR" in an I2C format, since a video chip I am working with requires this. It also has fussy timing requirements that appear to lower than even the standard device speed. to top it off I have 2 chips on board, so I am using independant clock lines and a shared SDA, since they both have identical addresses. Presently I have everything working with a custom PicBasic Pro I2C routine, but I suspect I'll need to implement this as an ASM routine if it is to be incorporated into the "printSTR" routine. Unless your MAJOR changes would allow for this.

BTW: I like the USART routine, it makes it very easy which we all love.

mytekcontrols
- 2nd July 2005, 08:05
Darrel this incorporates your USART macro (works great):


DEFINE LOADER_USED 1 ' use for Boot Loader
DEFINE OSC 40 ' change to suit oscillator speed

'============================================
' Equates
'============================================

temp var byte ' temporary storage for character

Goto main ' skip around Macros

'============================================
' Macros
'============================================
' Send String Macro (must be located prior to Main)
ASM
SendStr macro Astring
call _prntSTR
data Astring,0
endm
ENDASM

' USART Initialization Macro (must be located prior to Main)
' [ Initialize USART for specified baud rate at current OSC speed ]
ASM
USART_Init macro Baud
clrf TXSTA, 0
_SPBRG = (OSC * 1000000) / 16 / Baud - 1 ; calc SPBRG @ High baud rate
if _SPBRG > 255 ; if SPBRG is too high
_SPBRG = (OSC * 1000000) / 64 / Baud - 1 ; calc for Low baud rate
bcf TXSTA, BRGH, 0 ; Set BRGH to Low Speed
if _SPBRG > 255
_SPBRG = 255
endif
else
bsf TXSTA, BRGH, 0 ; Set BRGH to High Speed
endif
bsf TXSTA, TXEN, 0 ; Set Transmit Enable bit
movlw _SPBRG
movwf SPBRG, 0 ; load the calulated SPBRG
movlw B'10010000' ; enable USART
movwf RCSTA, 0
endm
ENDASM

'============================================
' Main Program
'============================================
Main:
@ USART_Init 19200 ; set RS232 baudrate

' send messages through RS232
' format #1
@ SendStr "This is a string"
@ SendStr "yet another string again"
@ SendStr "and one more time!"

' format #2
ASM
SendStr "This is a string"
SendStr "yet another string again"
SendStr "and one more time!"
ENDASM

Done:
Goto Done ' loop forever

'============================================
' String Extraction and Print Routines
'============================================
' print string code (locate anywhere)
ASM
_prntSTR
;copy return address to TBLPTR and then pop it off the stack
movf TOSU,W
movwf TBLPTRU
movf TOSH,W
movwf TBLPTRH
movf TOSL,W
movwf TBLPTRL
POP

;TBLPTR should now be pointing to 1st character in string
Next_Char
tblrd *+ ; table read and post increment TBLPTR
movff TABLAT,_temp ; fetch character from message string
bra Test_EOM ; go test for EOM character

Continue ; If not EOM then...
movf _temp,W ; move character into TXREG and...
movwf TXREG ; send it!
btfss TXSTA,TRMT ; has it been transmitted?
goto $-2 ; If not, keep checking
bra Next_Char ; fetch next message character from table

Test_EOM
movlw .0 ; check for EOM character
cpfseq _temp,W ; compare temp with w, if temp = 0 then end
bra Continue ; no EOM, so continue
movlw "\r" ; move carriage return into TXREG and...
movwf TXREG ; send it!
btfss TXSTA,TRMT ; has it been transmitted?
goto $-2 ; If not, keep checking
movlw "\n" ; move line feed into TXREG and...
movwf TXREG ; send it!
btfss TXSTA,TRMT ; has it been transmitted?
goto $-2 ; If not, keep checking

;use incremented value of TBLPTR as new return address (push it)
PUSH
movf TBLPTRU,W
movwf TOSU
movf TBLPTRH,W
movwf TOSH
movf TBLPTRL,W
movwf TOSL
return ;finished with message, return to caller
ENDASM

Darrel Taylor
- 3rd July 2005, 12:26
That's great Michael, glad you liked it. And it's good to have willing particpants around.

And, if you wanted more macro's... then I'm sure to make you happy today. :)

Oh boy, where to start.... I guess I'll start at the end result.

What this does is to allow the strings to be sent to up to 7 different "Destinations". Those destinations can be easily defined like this.
@ Make_Destination HSER, _HSER_SendThis creates a Destination named "HSER", and everytime the program needs to send a character, it will call the _HSER_Send subroutine.

Each destination needs it's own subroutine to actually send the data. The character is placed in the temp variable before calling it. Here's one for HSER.
HSER_Send:
While PIR1.4 = 0 : Wend
TXREG = temp
return
To make another Destination for the LCD, is just as easy...
@ Make_Destination LCD, _LCD_Send

LCD_Send:
LCDOUT temp
Return
Now when using the SendStr macro, you can tell it which destination you want it to go to.

@ SendStr "This is a string", HSER
@ SendStr "1 for the LCD", LCD

You can even combine them to send the data to multiple Destinations.

@ SendStr "This is a string", HSER + LCD

Destination #8 is reserved for a CR,LF option that can be used like this...

@ SendStr "This is a string", HSER + CRLF

Of course, here's the one you were after...
@ Make_Destination I2C, _I2C_Send

I2C_Send:
' However you need to do it here...
RETURN

In order to make this work, I ripped up your code pretty bad. Sorry!

For instance, I got rid of the whole Pushing and Popping stuff. I hated to do that, but at least it solves the interrupt problem. The TBLPTR is now loaded from the SendStr macro so that it doesn't need to use the stack to get the address. Major changes to the prntSTR section too. It had all the USART stuff in there that had to come out. The Make_Destination and Director macro's are the real difference that allows the data to be re-directed. I'm sure there will be some questions on them, but for now I'll let you try to figure it out first.

Here's the whole thing.

SER2_TX VAR PORTE.0
SER2_Baud CON 396
TRISB.6 = 1 ' Set USART TX pin to Output

temp var byte
Destination VAR BYTE

@CRLF = 0x080 ; Reserve destination #8 for CR,LF after string

'--[ Initialise USART for specified baud rate at current OSC speed ]------------
asm
USART_Init macro Baud
clrf TXSTA, 0
_SPBRG = (OSC * 1000000) / 16 / Baud - 1 ; calc SPBRG @ High baud rate
if _SPBRG > 255 ; if SPBRG is too high
_SPBRG = (OSC * 1000000) / 64 / Baud - 1 ; calc for Low baud rate
bcf TXSTA, BRGH, 0 ; Set BRGH to Low Speed
if _SPBRG > 255
_SPBRG = 255
endif
else
bsf TXSTA, BRGH, 0 ; Set BRGH to High Speed
endif
bsf TXSTA, TXEN, 0 ; Set Transmit Enable bit
movlw _SPBRG
movwf SPBRG, 0 ; load the calulated SPBRG
movlw B'10010000' ; enable USART
movwf RCSTA, 0
endm
ENDASM

;----[Make_Destination]---- Compile Time Only - Does not use any Code space ----
ASM
DestinationCount = 0 ; Global

Make_Destination macro Nam, Sub
Nam = 1 << DestinationCount ; Generate a unique ID
Destination#v(DestinationCount) = Sub ; Save Subroutines Address
DestinationCount += 1
endm
ENDASM

;----[SendStr] -----------------------------------------------------------------
ASM
SendStr macro Astring, Dest
local TheStringData, BypassData
goto BypassData ; Jump over the data
TheStringData
data Astring,0 ; Place String Data here
BypassData
MOVE?CB Dest, _Destination
MOVE?CB low TheStringData, TBLPTRL ; Load the address of
MOVE?CB low (TheStringData >> 8), TBLPTRH ; TheStringData into
MOVE?CB low (TheStringData >> 16), TBLPTRU ; TABLPTR
L?CALL prntSTR
if (Dest && CRLF) > 0
L?CALL _Send_CRLF
endif
endm
ENDASM

;----[ This macro will call each of the specified Destinations in sequence ]----
ASM
Director macro
local counter
counter = 0
while counter < DestinationCount
btfsc _Destination, counter
CALL Destination#v(counter)
counter += 1
endw
endm
ENDASM


;---[ These define the Destinations that will be called to output each byte ]---
; There is currently a
; Name, _Subroutine MAXimum of 7 destinations
@ Make_Destination HSER, _HSER_Send
@ Make_Destination SER2, _SER2_Send
@ Make_Destination LCD, _LCD_Send
@ Make_Destination I2C, _I2C_Send


Main:
@ USART_Init 19200
@ SendStr "This is a string", HSER + CRLF
@ SendStr "yet another string again", (HSER + SER2 + CRLF)
@ SendStr "and one more time!", I2C
@ SendStr "1 for the LCD", LCD

Done:
Goto Done

;-------------------------------------------------------------------------------
HSER_Send:
While PIR1.4 = 0 : Wend
TXREG = temp
return

;-------------------------------------------------------------------------------
SER2_Send:
SEROUT2 SER2_TX, SER2_Baud, [temp]
Return

;-------------------------------------------------------------------------------
LCD_Send:
LCDOUT temp
Return

;-------------------------------------------------------------------------------
I2C_Send:
' However you need to do it here...
RETURN

;----[prntStr]------------------------------------------------------------------
ASM
;--- TBLPTR should be pointing to 1st character in string before calling -------
prntSTR
Next_Char
tblrd *+ ; table read and post increment TBLPTR
movff TABLAT,_temp ; fetch character from message string
bra Test_EOM ; go test for EOM character
Continue ; If not EOM then...
Director ; Send the byte to each specified destination
bra Next_Char ; fetch next message character from table
Test_EOM
movlw .0 ; check for EOM character
cpfseq _temp,W ; compare temp with w, if temp = 0 then end
bra Continue ; no EOM, so continue
return ;finished with message, return to caller
endasm

;---[Send Carriage Return, Line feed to the dest's specified in last SendStr]---
Send_CRLF:
temp = 13
@ Director
temp = 10
@ Director
RETURN

end

Note that prntSTR and Send_CRLF must be at the end of the program for the Director to work properly.

Well, have fun, and I hope this is closer to what you were looking for.

Best regards,
Darrel

mytekcontrols
- 4th July 2005, 18:52
And, if you wanted more macro's... then I'm sure to make you happy today.Wow! Am I ever! It'll keep me quite busy this week trying it out in my application.


In order to make this work, I ripped up your code pretty bad. Sorry!

For instance, I got rid of the whole Pushing and Popping stuff. I hated to do that, but at least it solves the interrupt problem.I have no problem at all with this. At the time it was the only way I knew how to start heading in the direction I wanted to go. Perhaps it'll still be of use to someone, since there doesn't appear to be too much info out on the net showing actual application of this 18F series ability.


Major changes to the prntSTR section too. It had all the USART stuff in there that had to come out.As you probably saw in my last code post, I had already ripped this out and gone ahead and used your USART initialize macro.


The Make_Destination and Director macro's are the real difference that allows the data to be re-directed. I'm sure there will be some questions on them, but for now I'll let you try to figure it out first.
Yes I do have questions, but I'll hold off until I have had ample time to digest it. And perhaps I wont if my brain can take it all in.


Well, have fun, and I hope this is closer to what you were looking for.This is EXACTLY (and more) what I was looking for!
Thanks so very, very much,

mister_e
- 27th August 2005, 17:55
Here's my own version. Not as brilliant as all the above but allow to send String and numeric value. Have fun!


' ///////////////////////////////////|\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
' Embedded String and Data handling
' =================================
' Steve Monfette
' Mister E Enr
'
' This program show how to use/define/send a combination of String and Data
' to a PC terminal or else @9600 bauds.
'
' We can still use HSEROUT and do the same thing, of course but the
' following use another approach wich :
' 1. Allow to modify one or all string/data in a snap when needed.
' 2. Call a string many time only by calling his name with the macro.
' That is still more code efficient than if you create and use
' a specific SUBROUTINE.
'
' Also, if you compare this method to the use of multiple HSEROUT,
' you'll notice a slight difference in the size of the generated code.
'
' This program could also be usefull to send string/data to various device
' like I2C, LCD,...
' ///////////////////////////////////|\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

@ errorlevel 0,-207 ' avoid anoying MPASM error message
' -- found label after column 1 --

' PIC Definition
' ==============
' Done with an old & dusty PIC16F877 @ 20MHZ
'
DEFINE LOADER_USED 1
DEFINE OSC 20

' Hardware define
' ===============
'
TRISC=%10111111

' Serial Comm definition
' ======================
'
RCSTA=$90 ' Enable USART, continuous receive
TXSTA=$24 ' Enable transmit, BRGH=1
SPBRG=129 ' 9600 Bauds

' Variable definition
' ===================
'
Char var byte ' Character to be read/send
SAddr var word ' String adress pointer

' Software initialisation
' =======================
'
clear ' set all variable to 0
goto Start ' Skip any Macro And string Definition

' String Definition
' =================
' String must be defined as follow
' <label> dt <data>,0
'
' could also be
' <label> dt <data>
' dt <data>
' .........
' dt <data>,0
'
' Any String must be NULL terminated. Can contain text and numeric value
'
asm

s1 dt "String #1",13,10,0

s2 dt "String #2",13,10
dt "********************",13,10,0

s3 dt "String #3",13,10,0

s4 dt "String #4..... THE LAST ONE",13,10,0

endasm

' Macro Definition
' ================
'
' SendString:
' ===========
' This send the according string via USART
' Format:
' =======
' SendString <StringName>
'
asm
SendString macro StringLabel
CHK?RP _SAddr ; Reach the right BANK of SAddr
MOVE?CW StringLabel,_SAddr ; Store address of StringLabel in SAddr
L?CALL SendIt ; Send the string.
endm
endasm
@SendIt
Readcode SAddr, char ' Read character
if Char then ' if not NULL, send it
ASM
MOVE?BB _Char,TXREG ; Load TXREG with Char
IsFull
BIT?GOTO 0, PIR1, 4, IsFull ; Loop while TXREG is full
; The above is the same as
; IF PIR1.4=0 THEN GOTO IsFull
;
INCF _SAddr,1 ; Point to the next character
GOTO SendIt ; Do it again
ENDASM
endif
return


' /////////////////////////////////|\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
Start:
' /////////////////////////////////|\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
'
' Here we will send our data by using the above macro
'
@ SendString s1 ; Send string with label 's1'
@ SendString s2 ; Send string with label 's2'
@ SendString s3 ; Send string with label 's3'
@ SendString s4 ; Send string with label 's4'
pause 1500 ; wait a little bit
goto Start ; do it again

Darrel Taylor
- 27th August 2005, 20:01
Hi Steve,

While I don't see any advantages over the previous examples, it does present a few problems that weren't there before.

They are the same problems I came across when writing the strings program I pointed out in the 2nd post of this thread.

By using the "dt" directive, it uses twice as much code space by only storing 1 byte per word. The "da" directive is much more efficient. It packs two 7-bit characters in each word.

Also, when using the MOVE?CW macro inside another macro, it makes it so that all string data has to be placed at the beginning of the program. If you place the string data after the SendString command that's trying to use it, you will get a "Address label duplicate or defferent in second pass" error.

John Barrat figured out how to get around that problem with this macro. It compiles to the exact same thing as the MOVE?CW, but because of which "Pass" it gets compiled on, it can find an address either before or after the code that uses it.


'------------GetAddress Macro - Location insensitive -------------------------
ASM
GetAddress macro Label, Wout ; Returns the Address of a Label as a Word
CHK?RP Wout
movlw low Label
movwf Wout
movlw High Label
movwf Wout + 1
endm
ENDASMI think, once you fix those 2 things, you'll have something that looks just like my Strings prog. See second post.
<hr>
I do like this though
@ errorlevel 0,-207 ' avoid anoying MPASM error message
' -- found label after column 1 --
Sure makes things look better when you can indent labels.
<br>

mister_e
- 27th August 2005, 20:09
Yep i understand it... the only thing... HOW TO use DA to send numeric Value, say 13,10 or else 8 bits value with the string???

I tried the \ option... doesn't seems to work as i want. well i can miss something really stupid/easy... once again.

BUT it works with dt. BUT i agree with you, i take 2 time the needed space.

Darrel Taylor
- 27th August 2005, 20:37
"DA" works fine with anything under 128, so 10,13 isn't a problem.
da "Danger Will Robinson",13,10,0But you're right. Unless you are using an 18F part, if you want 8-bit data, it will take 2x the code space.

mister_e
- 27th August 2005, 20:50
mmm i already tried the above... MIIIIIIIIP doesn't work. GOT YA... for the first time in my life... probably the last too :)

We must send a 14 bit pack stuff... as it's suppose to!

So i just found that


@ da "This is a string....",0x068a,0

the above will send cr+lf.

Sounds like


CR con 13
LF con 10
CRLF var WORD

CRLF.HighByte=CR
CRLF=CRLF>>1
CRLF.LOWBYTE=CRLF.LowByte | LF

it works... just harder to figure out. BAH could be worst. And BTW, a 18F will be more appropriate for that.

About the String placement... you're right. As i figure to place all string at the top, it shouldn't be a problem. All the string together. Make it easy if some modification have to be done.

mister_e
- 27th August 2005, 21:10
mmm, another solution...


String1 da "My string",13,10,"blah blah",13,10,125,126,127,0


Just modify a little bit the StringOut Sub


StringOut: ' Send the string out via Hserout
Readcode Addr, TwoChars ' Get the 14 bit packed characters
Char = TwoChars >> 7 ' Separate first char
if Char then ' Look for Null char, Stop if found
hserout [Char] ' Send first char
endif

Char = TwoChars & $7F ' Separate second char
if Char then ' Look for Null char, Stop if found
hserout [Char] ' Send the second char
Addr = Addr + 1 ' Point to next two characters
goto StringOut ' Continue with rest of the string
endif
return

that way it works. BUT it don't take all the advantage of the 14 BIT pack stuff. It's just more readable the the previous.

Darrel Taylor
- 27th August 2005, 21:12
Hmmmpf,

Apparently, none of them are right.

With mine, it puts 00's in front of each byte (13,10), that will cause the send routine to terminate early.

With the 0x068a, if there's an ODD number of characters in the string, it will pad the string with a 00, again causing the send routine to terminate early.

So there doesn't seem to be a way to add CRLF on the end of a string with "DA".

Your program seems to have an advantage after all. My apologies.
<br>

Darrel Taylor
- 27th August 2005, 21:18
How dare you fix my program while I'm still posting that you were right!

Ha ha, Good job!
<br>

mister_e
- 27th August 2005, 21:27
OK as i will probably never happen again, i'll write the date/month/year in my notebook with the note


once in my life, i beat Mr Darrel Taylor
THE Canadian 1
United State 0

Just kidding Darrel :) I learn a lot from all of your previous posts.

Keep up the good work !!!

Darrel Taylor
- 27th August 2005, 21:47
Oh shoot,

Still has that "Padding the string" problem.


010D 26F9 1073 3A72 00255 String1 da "My string",13,10,"blah blah",13,10,125,126,127,0
34EE 3380 000D
000A 316C 30E8
1062 3661 3400
000D 000A 007D
007E 007F 0000


Sendstring still terminates early if the string has an ODD number of charaters.

Almost there.

P.S.
THE Canadian 0.99
<br>

Darrel Taylor
- 27th August 2005, 22:14
Maybe this...
StringOut: ' Send the string out via Hserout
Readcode Addr, TwoChars ' Get the 14 bit packed characters
IF TwoChars <> 0 then
Char = TwoChars >> 7 ' Separate first char
if Char then ' Look for Null char, Don't send if found
hserout [Char] ' Send first char
endif

Char = TwoChars & $7F ' Separate second char
if Char then ' Look for Null char, Don't send if found
hserout [Char] ' Send the second char
endif
Addr = Addr + 1 ' Point to next two characters
goto StringOut ' Continue with rest of the string
ENDIF
return

mister_e
- 27th August 2005, 22:37
hmmpff... is it me or


IF TwoChars <> 0 then

is unecesary since we check both character anyway???

Darrel Taylor
- 27th August 2005, 22:48
But it has to stop sometime.

When you add a final ,0 to the end of the line, DA generates a 0x0000 word. So only if the whole word is 0 will it consider it the end of the "string".

Any other 0 characters within the "string" are ignored.
<br>

mister_e
- 27th August 2005, 23:15
Got it..


StringOut: ' Send the string out via Hserout
Readcode Addr, TwoChars ' Get the 14 bit packed characters
IF TwoChars then
Char = TwoChars >> 7 ' Separate first char
if Char then ' Look for Null char, Don't send if found
hserout [Char] ' Send first char
endif

Char = TwoChars & $7F ' Separate second char
if Char then ' Look for Null char, Don't send if found
hserout [Char] ' Send the second char
endif
Addr = Addr + 1 ' Point to next two characters
goto StringOut ' Continue with rest of the string
ELSE
Addr=Addr+1
Goto StringOut
ENDIF
return

mister_e
- 27th August 2005, 23:36
NARGH forget the above. It depend on the previous and the next string... wich doesn't happen with my first version with DT...mmm

Darrel Taylor
- 27th August 2005, 23:52
Forgotten :)

mister_e
- 28th August 2005, 00:35
Well, if we want to create and send a mix of String and Numeric Value, da is not the one to use even if it gives some codespace advantages.

O.K. for Text String only. So i'll stick to my first solution that used dt

Thanks for the tips anyway !

Mike, K8LH
- 29th August 2005, 02:57
Hi Guys,

Hope you don't mind me butting in...

I've been using a similar method for 18F' devices in assembler for awhile now and I wonder if you might need to account for the occasional odd length character string to make sure the address is word aligned before placing it back into TOS?

Regards, Mike



;
; Example macro usage
;
_Title "K8LH Az/El Controller\r\n\n"
_Print "Satellite AOS:\r\n"
_Print "Satellite LOS:\r\n"

;************************************************* *****************
;
; print the in-line string using Stack Pointer & TBLPTR
;
PutString
movff TOSH,TBLPTRH ; copy SP address to TBLPTR
movff TOSL,TBLPTRL ;
clrf TBLPTRU ;
PutNxt tblrd *+ ; get character
movf TABLAT,W ; last character (00)?
bz PutXit ; yes, exit
rcall Put232 ; else, print character
bra PutNxt ; do another
PutXit btfsc TBLPTRL,0 ; odd address?
tblrd *+ ; yes, make it even (fix PC)
movf TBLPTRH,W ;
movwf TOSH ; update the return stack
movf TBLPTRL,W ;
movwf TOSL ;
return ;
;
;************************************************* *****************

Squibcakes
- 7th September 2006, 01:36
I'm using this for my LCD display, but what if....

I want to send two lines of text to my LCD?

Normally we would send $FE, $C0 to start the second line but coding this doesn't work using your example....

@ da "First line",$FE,$C0,"Second Line",0

I see you guys are doing this when sending serial data, by adding 13,10,0 to the string.

Cheers
J

mister_e
- 7th September 2006, 01:59
using DA it won't work. Da pack two ascii character in a 14bit packet... 2X7Bits
$FE (wich should be write h'FE') is over the 127 dec or 7F Hex.

What you can do is to use something else something like


DA "first line",1,2,"Second Line",0
.
.
.
If char = 1 then char = $FE
If char = 2 then char = $C0

Homerclese
- 9th March 2007, 06:20
I use DEBUG to get to my serial pic LCD readout at 2400 baud. I have been trying to replace the hserout functions in the "string storage" thread with my usual debug output with no luck. I get repeating characters but not the expected string. I see now where there may be an issue because of the 14 bit word length but how to correct this is not clear.

mister_e
- 9th March 2007, 16:39
and when you use HSEROUT ["HELLO"] it works or not?

Homerclese
- 9th March 2007, 19:54
Using pin 25 RC6/TX and monitoring with MCS serial communicator at 9600 baud I get a repeating string of garbage characters. Hserout ["hello"] test result was the same. Isn't there an issue with hserout and inverted output?

In the mean time playing around I found this code works:


StringOut: ' Send the string out via serout
Readcode Addr, TwoChars ' Get the 14 bit packed characters
Char = TwoChars >> 7 ' Separate first char
if Char = 0 then StringDone ' Look for Null char, Stop if found
Gosub Out ' Send first char
Char = TwoChars & $7F ' Separate second char


if Char = 0 then StringDone ' Look for Null char, Stop if found
Gosub out ' Send the second char
Addr = Addr + 1 ' Point to next two characters

Goto StringOut ' Continue with rest of the string

StringDone:
Return

out:
Serout PORTE.1,N2400,[char]:Return
end

I'm trying to find a way to select ASCI character tag pairs based on a numerical index something like my flawed example below.

Lookup index,["A1","A2","A3","A4","B1","B2","B3","B4".........],#tag

I can use codespace strings if there is no simpler way to go.

Bruce
- 9th March 2007, 20:14
Isn't there an issue with hserout and inverted output?
Yes. HSEROUT & HSERIN work with non-inverted data. There is no way
to force inverted when using the hardware USART without an external
inverter.

DavidK
- 9th March 2008, 07:43
This was a new one on me. I was trying to work DT’s "STRINGS.PBP" code for the first time and ran across an error from MPASM, the likes of which I had never seen before.

“The Microchip assembler (MPASM) only allows up to 62 characters for path and file name. Current length is 72 characters”

AHHHH ??Now, I am not 100% efficient on doing a forum search, but I could not find anything like this. Stumped big time and no where to go.

Contacted the author and low and behold I had my code buried 5 levels deep into subdirectories on my C:\ drive. Each subdirectory had long names, hence 72 characters by the time I got to the directory where I placed my "STRINGS.PBP" code. Changed the subdirectory names to shorter lengths and bingo, works fine. Even though all my projects have worked fine over the years, one needs to think how and where they store their projects,

Thought I would share this little “tidbit” just incase someone else runs into it.

skimask
- 9th March 2008, 07:50
“The Microchip assembler (MPASM) only allows up to 62 characters for path and file name. Current length is 72 characters”
You aren't the 1st one to get bitten by that one. That used to bite me every once in awhile for no particular reason...and would stump me for literally hours each time.
To cure it, awhile back I started a completely separate partition just for MPLAB, PBP, MCS, PICKIT2, all my programming stuff and keep it all in the root directory.
Even if I do have to type something out at the command line, the line ends up being relatively short. Not to mention, I can 'dynamically' adjust the partition size with Partition Magic since the partition is so small. And I backup the whole thing at PC startup with a simple ZIP batch file straight to a thumbdrive. Practically bullet proof...and transportable...