PDA

View Full Version : The EXT (external) modifier.



Darrel Taylor
- 17th May 2006, 10:54
Here's a subject where RTFM does NOT apply.
In fact, the only place the PBP manual even mentions it is in the Reserved Words (Appendix C).

The EXT modifier for Variables and Constants can solve many problems that seem impossible otherwise. It can save TONs of code space in certain situations. And, it can also confuse the hell out of you if you're not sure how it works. Hopefully this will help with the latter part.

EXT's only function is to tell PBP that it doesn't need to figure out where a Variable is located, or what a Constant's value is. Because it will be handled in ASM at compile time. And, since PBP doesn't "Lock it in" we can change it to anything we want later on, even in the middle of the program if need be.

<a href="http://www.picbasic.co.uk/forum/showthread.php?t=3891#CON">Using EXT with Constants</a><br><a href="http://www.picbasic.co.uk/forum/showthread.php?t=3891#LAB">Using EXT with Labels</a><br><a href="http://www.picbasic.co.uk/forum/showthread.php?t=3891#VAR">Using EXT with Variables</a><br><a href="http://www.picbasic.co.uk/forum/showthread.php?t=3891#TYP">Typecasting Variables inside of Arrays</a><br><a href="http://www.picbasic.co.uk/forum/showthread.php?t=3891#ARAR">Arrays within Arrays</a><br><a href="http://www.picbasic.co.uk/forum/showthread.php?t=3891#LIM">Limitations of EXT</a>


<a name="CON"></a><hr>Using EXT with Constants

<b><pre>@MyConstant = 1234h ;no space between @ and Name<br>MyConstant CON EXT</pre></b>&nbsp;&nbsp;... is exactly the same as ...

<b><pre>MyConstant CON $1234</pre></b>However, by using the EXT modifier you can change it at any point in the program. And, you can use the Power of a 32-bit assembler to calculate what those values should be.

For instance, if you wanted to select a constant to be loaded in a timer on each interrupt depending on the crystal being used, you might do something like this
<b>TimerConst CON EXT</b>

ASM
IF OSC == 4 ; Constants for 100hz interrupt from Timer1
TimerConst = 0D8F7h ; Executed at compile time only
EndIF
If OSC == 8
TimerConst = 0B1E7h
EndIF
If OSC == 10
TimerConst = 09E5Fh
EndIF
If OSC == 20
TimerConst = 03CB7h
EndIF
ENDASM

Or, you could let the assembler do the math ...
TimerConst CON EXT
Freq CON 100
@TimerConst = 65543-(OSC*1000000/4/_Freq) ; 100hz Constant for Timer1 reload
Either way it does not use any program space in the pic. It's all done at "Compile Time".

<a name="LAB"></a><hr>Using EXT with Labels ...

One of best uses of EXT is to find out the Address of ANYTHING (that's already been declared) in the program.

To the assembler, Variables, Constants and Labels are all the same thing. Numbers! It's how those numbers get used that makes the difference.

A Constant is just a number.
A variable is a number that represents the Address of a Ram location.
And a Label is a number that represents the Address of a location in Program Space.

So any of these items can be assigned to a constant for PBP.

In this example, a list of 14-bit WORD values can be created in a lookup "Table".
With DataTable defined as an "External" constant, it will be assigned the Address of the Label with the same name. This allows you to easily locate items stored in Program memory.

DataWord VAR WORD
Offset VAR WORD
<b>DataTable CON EXT</b>

'-----[The DATA table]--------------------------------------------------------
GOTO OverData ; Make sure data doesn't try to execute
ASM
<b>DataTable</b>
DW 1234h, 2178h ; etc.
endasm
OverData:

'-----[Retrieve from DATA table]----------------------------------------------
Offset = 1
ReadCODE (<b>DataTable</b> + Offset), DataWord

LCDOUT $FE, 1, HEX4 DataWord

Or for 16-bit WORDS on an 18F, use this ReadCODE statement.
ReadCODE (DataTable + (Offset<<1)), DataWord Absolutely HUGE tables can be created in a small fraction of the space used by LOOKUP2.

Note: Only PIC chips that can access their own Flash memory can use ReadCODE.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;And, DW only works properly in MPASM, not PM. (thanks BigWumpus).

<a name="VAR"></a><hr>Using EXT with Variables ...

<pre>@MyVar = 20h<br>MyVar VAR BYTE EXT</pre>&nbsp;&nbsp;... is similar to ...

<pre>MyVar VAR BYTE $20</pre>With the exception that PBP doesn't know about it. &nbsp; Reading or writing to the EXT MyVar will use the RAM location at $20, but PBP will assign another variable there since it doesn't know about it yet. &nbsp; So trying to use EXT to create NEW variables is pretty much useless. &nbsp;
However, using EXT to create variables that reference other variables, or other RAM/SFR locations, is Priceless.

This example shows how to use a 16-bit timer value as if it were just another word.
@Timer1 = TMR1L
Timer1 VAR WORD EXTWith that, and the TimerConst example shown above. Re-Loading the timer is as simple as this ...
T1CON.0 = 0 ; stop timer
Timer1 = Timer1 + TimerConst
T1CON.0 = 1 ; turn timer back on You should stop the timer before reading or writing it's value, or it might overflow in-between the Low and High bytes.
Note: Do NOT enable RD16 when using a Timer value as a WORD. (T?CON.7) (Thanks Bruce!)
On an 18F, Timer0 is always RD16. You cannot use Timer0 as a WORD value.

Another example along the same lines ...
@Capture = CCPR1L
Capture VAR WORD EXTThen the whole capture value can be used as a Word variable.

But here's the good stuff.

<a name="TYP"></a><hr>Typcasting Variables inside of Arrays

Using the EXT modifier, you can create combinations of Word and Byte variables that point to locations inside of Array variables.

Let's say that you received a "Packet" of information from some other device using the STR function of HSERIN. But the problem is that it's not all byte sized data, even though it was stored in a byte-sized array.
It's received 8 bytes and you need to separate them into different WORD and BYTE sized variables.

<pre> 01 AE 7A 8B 00 00 10 2C<br> \ / \ / \ /<br> Arg0 Arg1 Arg2 Arg3 Arg4<br> WORD BYTE WORD WORD BYTE</pre>

With a few EXTernal variables, you can Parse the entire Packet, without a single WORD of program space.
MyArray VAR BYTE[8] BANK0
ASM
Arg0 = _MyArray ; word
Arg1 = _MyArray + 2 ; byte
Arg2 = _MyArray + 3 ; word
Arg3 = _MyArray + 5 ; word
Arg4 = _MyArray + 7 ; byte
ENDASM

Arg0 VAR WORD EXT
Arg1 VAR BYTE EXT
Arg2 VAR WORD EXT
Arg3 VAR WORD EXT
Arg4 VAR BYTE EXT
Now you simply read the Packet into the Array, and each Arg variable will have the correct value in it. This is also much quicker to run, since it doesn't need to do all the Array indexing that PBP would normally do.

If there are multiple types of packets being received, you can just create another set of variables pointing to the same Array space, with different combinations of bytes and words. Since they don't use any program space, you can make as many as you want. &nbsp; Sure beats using 4 or 5 different HSERIN statements for the different packet types.

And of course, it works the other way too. By setting the Arg variables first, you can easily SEND the "pre-formatted" packet with the STR function.

If you get an "Unable to fit variable ____ in requested bank x" warning, change the BANK0 modifier to BANK1 or another bank that has room.
The entire array must be in a single bank for this technique to work. (Thanks Charles_Leo)

<a name="LIM"></a><hr>Limitations of EXT

Since the value of an EXTernal constant/variable/label isn't known until the program is being Assembled. PBP cannot use the values itself.

@MyConstant = 1234h
MyConstant CON EXT

AnotherCON CON MyConstant + 100 ; This will fail

MyArray VAR BYTE[MyConstant] ; This will fail
Both of the lines above will fail since PBP needs to know what the value is for those statements when it's compiling. But they won't be known till it's assembled.

<hr width=100>
This also holds true throughout the program. &nbsp;The value of an EXT var/con/label must be declared prior to anything trying to use it. If a label occurs after the current point in the program, you should get an error, but it's not always evident what the problem is.
Sometimes it will give a "Symbol not previously defined" error. Other times you might get an "Address label duplicated or different in second pass" error.

The error will indicate the name of the Label, so it's not too hard to figure out.

<hr width=100>
You can't use EXT with Arrays. That would just be too convenient. :(
<br>

Jerson
- 18th May 2006, 06:04
Very good treatise on the EXT. Thank you Darrell. This is wonderful as I was trying to work out a convenient way to do structures in PBP. I guess you could consider putting this post in the announcements as a sticky. It is very useful.

Jerson

Darrel Taylor
- 18th May 2006, 10:15
Thanks Jerson! Here's some more to chew on.
<a name="ARAR"></a><hr>Arrays within Arrays

Along with BYTEs and WORDs, you can have Arrays as part of the "Packet". It's just up to you to make sure that everything fits properly.

Perhaps you need to send a series of A/D samples along with the previous Packet to a VB program on a PC.
By Mapping a WORD Array inside the BYTE array, the Sample data automatically becomes part of the Packet.

This adds a 10 WORD array to the previous Packet. And just for good measure I'll put another BYTE variable after it for a CheckSum.

MyArray VAR BYTE[29] BANK0
ASM
Arg0 = _MyArray ; word
Arg1 = _MyArray + 2 ; byte
Arg2 = _MyArray + 3 ; word
Arg3 = _MyArray + 5 ; word
Arg4 = _MyArray + 7 ; byte
Samples = _MyArray + 8 ; 10 WORD array (20 bytes)
ChkSUM = _MyArray + 28
ENDASM

Arg0 VAR WORD EXT
Arg1 VAR BYTE EXT
Arg2 VAR WORD EXT
Arg3 VAR WORD EXT
Arg4 VAR BYTE EXT
Samples VAR WORD EXT ; 10 WORD array
ChkSUM VAR BYTE EXT
Note here that you don't need to specify the array size for the Samples variable. But you do have to leave enough room for it in the array.
And if you get an "Unable to fit variable ____ in requested bank x" warning, change the BANK0 modifier to BANK1 or another bank that has room.
The entire array must be in a single bank for this technique to work.

Now you can just take the A/D samples and store them in the WORD array...(which is really in the MyArray).

FOR X = 0 to 9
ADCIN 0, Samples(X)
NEXT XCalculate a CheckSum for the whole Packet...
ChkSUM = 0
FOR X = 0 to 27
ChkSUM = ChkSUM ^ MyArray(X)
NEXT XAnd with very little program space used, you have a Complete Packet with 5 WORD or BYTE variables, 10 word sized A/D samples and a checksum for data integrity, ready to send with ...
HSEROUT ["Header", STR MyArray\29]

And, once again, it's bi-directional. You can receive the Packet of Samples just as easily, with ...
HSERIN [wait("Header"), STR MyArray\29]

SteveB
- 19th May 2006, 04:49
Thanks for your great work on this. I was looking at doing just this type of process.

I plan to capture a series of equally timed ADCs. This data would eventually be sent to my computer. It will have a time stamp header to indicate the time of the first capture, followed by the series of ADC values, followed by a parity word. It seems you have given me just the tool I need for the task at hand. I can't wait to try it out.
Have you been shuffling through that pile of scribbled notes on my desk?

Thanks again for your contribution. I'm quite new to PICs and this forum, but it is clear from the reading I've done so far that you stand out as one of the top shelf folks here. I've learned a lot.

Steve

BTW, what about instant interrupts for the 16-bit flavors? My project requires quite a bit of RAM (more than any 14-bit PIC) and I really like what I saw reading through those threads. I even thought about trying to shoehorn them into my 18F4620, but balked. I am still quite the newbie. I know it would teach me a lot to work it out on my own, and I would enjoy the process, but I can't spare the time right now.

mister_e
- 22nd May 2007, 01:53
Just found some erratic results on a 18F2431, the following work


<font color="#000000"> <font color="#008000">'
' Pic Configuration
' =================
</font><font color="#000080">ASM
__CONFIG _CONFIG1H, _OSC_XT_1H &amp; _FCMEN_OFF_1H &amp; _IESO_OFF_1H
__CONFIG _CONFIG2L, _PWRTEN_ON_2L &amp; _BOREN_ON_2L &amp; _BORV_45_2L
__CONFIG _CONFIG2H, _WDTEN_OFF_2H &amp; _WINEN_OFF_2H </font><font color="#008000">;&amp; WDPS_32768_2
</font><font color="#000080">__CONFIG _CONFIG3L, _T1OSCMX_OFF_3L &amp; _HPOL_LOW_3L &amp; _LPOL_HIGH_3L &amp; _PWMPIN_OFF_3L
__CONFIG _CONFIG3H, _MCLRE_ON_3H
__CONFIG _CONFIG4L, _LVP_OFF_4L &amp; _DEBUG_OFF_4L
ENDASM
DEFINE </font>OSC 4

<font color="#008000">'
' Hardware configuration
' ======================
'
' I/Os
' ----
</font>PORTA = 0
LATA = 0
PORTB=0
LATB = 0
PORTC =0
LATC = 0

TRISA = 0
TRISB = 0
TRISC = 0
<font color="#008000">'
' ADCs
' ----
</font>ANSEL0 = 0
<font color="#008000">'
' Timers &amp; pouet pouet
' --------------------
</font>T0CON = 0
T1CON = 0
T5CON = 0
CAP1CON=0
CAP2CON = 0
CAP3CON = 0
DFLTCON = %00111010
QEICON = 0
<font color="#008000">'
' MSSP
' ----
</font>SSPSTAT = 0
SSPCON <font color="#000080">VAR BYTE </font>EXT
SSPCON = 0

<font color="#008000">'
' CCP
' ---
</font>PTCON0=0
PTCON1= %10000000
PWMCON0 = %01001111
PWMCON1 = %00000001

PTPERL=$FF
PTPERH=$3F

DTCON = 0
OVDCOND= 255
OVDCONS=255
FLTCONFIG = %00000000
SEVTCMPL = 0
SEVTCMPH = 0

<font color="#008000">'
' Software variables
' ==================
</font>DUTY <font color="#000080">VAR WORD
</font><font color="#008000">'
' Software constants
' ==================
</font>Duty0 <font color="#000080">VAR WORD
</font>Duty0 = 16383

<font color="#008000">'------------------------------&lt; Main program &gt;-----------------------------------
'
</font>Start:
<font color="#008000">'
' Those bellow work 100%
' ----------------------
</font><font color="#000080">FOR </font>DUTY = 0 <font color="#000080">TO </font>Duty0
PDC0L=DUTY.LowByte
PDC0H=DUTY.HighByte
<font color="#000080">PAUSEUS </font>50
<font color="#000080">NEXT
FOR </font>DUTY = 0 <font color="#000080">TO </font>Duty0
PDC1L=DUTY.LowByte
PDC1H=DUTY.HighByte
<font color="#000080">PAUSEUS </font>50
<font color="#000080">NEXT

FOR </font>DUTY = 0 <font color="#000080">TO </font>Duty0
PDC2L=DUTY.LowByte
PDC2H=DUTY.HighByte
<font color="#000080">PAUSEUS </font>50
<font color="#000080">NEXT

GOTO </font>Start


while the following work weird, and depending the code overhead, results are different...

<font color="#000000"> <font color="#008000">'
' Pic Configuration
' =================
</font><font color="#000080">ASM
__CONFIG _CONFIG1H, _OSC_XT_1H &amp; _FCMEN_OFF_1H &amp; _IESO_OFF_1H
__CONFIG _CONFIG2L, _PWRTEN_ON_2L &amp; _BOREN_ON_2L &amp; _BORV_45_2L
__CONFIG _CONFIG2H, _WDTEN_OFF_2H &amp; _WINEN_OFF_2H </font><font color="#008000">;&amp; WDPS_32768_2
</font><font color="#000080">__CONFIG _CONFIG3L, _T1OSCMX_OFF_3L &amp; _HPOL_LOW_3L &amp; _LPOL_HIGH_3L &amp; _PWMPIN_OFF_3L
__CONFIG _CONFIG3H, _MCLRE_ON_3H
__CONFIG _CONFIG4L, _LVP_OFF_4L &amp; _DEBUG_OFF_4L
ENDASM
DEFINE </font>OSC 4

<font color="#008000">'
' Hardware configuration
' ======================
'
' I/Os
' ----
</font>PORTA = 0
LATA = 0
PORTB=0
LATB = 0
PORTC =0
LATC = 0

TRISA = 0
TRISB = 0
TRISC = 0
<font color="#008000">'
' ADCs
' ----
</font>ANSEL0 = 0
<font color="#008000">'
' Timers &amp; pouet pouet
' --------------------
</font>T0CON = 0
T1CON = 0
T5CON = 0
CAP1CON=0
CAP2CON = 0
CAP3CON = 0
DFLTCON = %00111010
QEICON = 0
<font color="#008000">'
' MSSP
' ----
</font>SSPSTAT = 0
SSPCON <font color="#000080">VAR BYTE </font>EXT
SSPCON = 0

<font color="#008000">'
' CCP
' ---
</font>PTCON0=0
PTCON1= %10000000
PWMCON0 = %01001111
PWMCON1 = %00000001

PTPERL=$FF
PTPERH=$3F

DTCON = 0
OVDCOND= 255
OVDCONS=255
FLTCONFIG = %00000000
SEVTCMPL = 0
SEVTCMPH = 0

<font color="#008000">'
' Software variables
' ==================
</font><font color="#000080">ASM
PDC0REG=PDC0L
PDC1REG=PDC1L
PDC2REG=PDC2L
ENDASM
</font>PDC0REG <font color="#000080">VAR WORD </font>EXT
PDC1REG <font color="#000080">VAR WORD </font>EXT
PDC2REG <font color="#000080">VAR WORD </font>EXT

DUTY <font color="#000080">VAR WORD
</font><font color="#008000">'
' Software constants
' ==================
</font>Duty0 <font color="#000080">VAR WORD
</font>Duty0 = 16383

<font color="#008000">'------------------------------&lt; Main program &gt;-----------------------------------
'
</font>Start:
<font color="#000080">FOR </font>DUTY = 0 <font color="#000080">TO </font>Duty0
PDC0REG=DUTY
<font color="#000080">PAUSEUS </font>50
<font color="#000080">NEXT

FOR </font>DUTY = 0 <font color="#000080">TO </font>Duty0
PDC1REG=DUTY
<font color="#000080">PAUSEUS </font>50
<font color="#000080">NEXT

FOR </font>DUTY = 0 <font color="#000080">TO </font>Duty0
PDC2REG=DUTY <font color="#008000">' wierd stuff :o(
</font><font color="#000080">PAUSEUS </font>50
<font color="#000080">NEXT
GOTO </font>Start


When i say weird, PDC2 PWM duty cycle seems to be affected.. work or not, blink and so on.

Any idea?

mister_e
- 22nd May 2007, 02:09
a LITTLE results report


==============================================
DUTY =402
DUMMY_H =01 DUMMY_L = 91
PDC2_H =00 PDC2_L = 92
==============================================
DUTY =403
DUMMY_H =01 DUMMY_L = 92
PDC2_H =00 PDC2_L = 93
==============================================
DUTY =404

DUMMY_H =01 DUMMY_L = 93
PDC2_H =00 PDC2_L = 94
==============================================
DUTY =405
DUMMY_H =01 DUMMY_L = 94
PDC2_H =00 PDC2_L = 95
==============================================
DUTY =406
DUMMY_H =01 DUMMY_L = 95
PDC2_H =00 PDC2_L = 96
==============================================
DUTY =407
DUMMY_H =01 DUMMY_L = 96
PDC2_H =00 PDC2_L = 97
==============================================
DUTY =408
DUMMY_H =01 DUMMY_L = 97
PDC2_H =00 PDC2_L = 98
==============================================
DUTY =409
DUMMY_H =01 DUMMY_L = 98
PDC2_H =00 PDC2_L = 99
==============================================
DUTY =410
DUMMY_H =01 DUMMY_L = 99
PDC2_H =00 PDC2_L = 9A
==============================================
DUTY =411
DUMMY_H =01 DUMMY_L = 9A
PDC2_H =00 PDC2_L = 9B
==============================================
DUTY =412
DUMMY_H =01 DUMMY_L = 9B
PDC2_H =00 PDC2_L = 9C
==============================================

as this happen on PDC2, i use the following to produce the above report


Start:
FOR DUTY = 0 TO duty0
PDC0reg=duty
pauseus 50
NEXT

FOR DUTY = 0 TO duty0
pdc1reg=duty
pauseus 50
NEXT

FOR DUTY = 0 TO duty0
pdc2reg=duty ' wierd stuff :o(
pauseus 50
DUMMY=PDC2REG
HSEROUT ["DUTY =", DEC DUTY,13,10,_
"DUMMY_H =", HEX2 DUMMY.HIGHBYTE," DUMMY_L = ",HEX2 DUMMY.LOWBYTE, 13,10,_
"PDC2_H =", HEX2 PDC2H ," PDC2_L = ",HEX2 PDC2L,13,10,_
"==============================================",13,10]

NEXT
GoTo Start

seems to don't pass the Highbyte eh!

Darrel Taylor
- 22nd May 2007, 02:18
Yes, weirdness indeed.

But the weirdness is why Microchip can't seem to keep things consistant between their products. :eek:

In the case of PDCxH:L, the HighByte comes first.

But in most other registers like TMRxL:H, the LowByte comes first.

So unfortunately, PDCxH:L, CAPxBUF and probably others won't work with the EXT type variables.

HTH,

mister_e
- 22nd May 2007, 02:25
<img SRC="http://www.mister-e.org/Pics/pan"> aaaaahhhh.. cr... and the RTFM datasheet section 5 of the day goes to me...

sorry :(

Darrel Taylor
- 22nd May 2007, 02:37
No, that's good info to have in this thread.

Until now, I didn't know it either.

Gotta ask questions. :)
<br>

sayzer
- 27th May 2009, 14:21
Hi DT,

I have a question as follows.




MyArray1 VAR BYTE[200] ' This one won't fit into 16F877.




But instead of one array with 200 elements,
I can create five separate arrays with 40 elements each; in total I get 200.

Example:



MyArray1 VAR BYTE[40]
MyArray2 VAR BYTE[40]
MyArray3 VAR BYTE[40]
MyArray4 VAR BYTE[40]
MyArray5 VAR BYTE[40]



However, it requries me to write more code to access them in a line.

Using your ASM magic as swhon in the previous posts, can we put these five arrays into one
array say Arg0 ?

Thus, I can then use something like,




MyArray1 VAR BYTE[40]
MyArray2 VAR BYTE[40]
MyArray3 VAR BYTE[40]
MyArray4 VAR BYTE[40]
MyArray5 VAR BYTE[40]

ASM
' DT's magical hands come in here !
'....
'......
'........
ENDASM

' Then,

Arg0 VAR ' something


'Then, finally I can use Arg0[180], Arg0[120], etc...




Is this doable?

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

Acetronics2
- 27th May 2009, 14:41
Hi, Sayzer

Why not use Peekcode and Pokecode ... or simply LOOKUP ( if no change in values ) ??? ... 255 values is the limit for Pic 16F.

With Peekcode/Pokecode, you also can load your data at once including a txt file ...


( No thought to the project section, of course ... !!! )

Alain

mister_e
- 28th May 2009, 00:15
Sayzer, are you saying that Using EXT with Labels in post #1 doesn't work? I don't think so :(

Darrel Taylor
- 28th May 2009, 07:05
Is this doable?
Hi Sayzer,

No, EXT won't work that way.
The arrays would not be contiguous, and located in different banks.

I've never tried using big arrays on a 16F before, I'd just use an 18F when I need more than 96 bytes.
However, confronted with a challenge ... I have to try.
Here's what I've come up with ...
<font color="#000000"><b>Array1Size </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>64
</b></font><b>Array2Size </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>96 </b></font><font color="#0000FF"><b><i>; 96 is the largest for 16F877
</i></b></font><b>Array3Size </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>96 </b></font><font color="#0000FF"><b><i>; 96 + 96 + 64 = 256 bytes
</i></b></font><b>MyArray1 </b><font color="#008000"><b>VAR BYTE</b></font>[<b>Array1Size</b>]
<b>MyArray2 </b><font color="#008000"><b>VAR BYTE</b></font>[<b>Array2Size</b>]
<b>MyArray3 </b><font color="#008000"><b>VAR BYTE</b></font>[<b>Array3Size</b>]

<b>Idx </b><font color="#008000"><b>VAR BYTE
</b></font><b>Abyte </b><font color="#008000"><b>VAR BYTE
</b></font><font color="#0000FF"><b><i>;---------------------------------------------------------------------------
</i></b></font><b>GetArray</b>: <font color="#0000FF"><b><i>; Set Idx before calling, result is in Abyte
</i></b></font><font color="#008000"><b>SELECT CASE </b></font><b>Idx
</b><font color="#008000"><b>CASE IS </b></font>&lt; <b>Array1Size
Abyte </b>= <b>MyArray1</b>(<b>Idx</b>)
<font color="#008000"><b>CASE IS </b></font>&lt; (<b>Array1Size </b>+ <b>Array2Size</b>)
<b>Abyte </b>= <b>MyArray2</b>(<b>Idx </b>- <b>Array1Size</b>)
<font color="#008000"><b>CASE ELSE
</b></font><b>Abyte </b>= <b>MyArray3</b>(<b>Idx </b>- (<b>Array1Size </b>+ <b>Array2Size</b>))
<font color="#008000"><b>END SELECT
RETURN

</b></font><b>PutArray</b>: <font color="#0000FF"><b><i>; set Idx and Abyte before calling
</i></b></font><font color="#008000"><b>SELECT CASE </b></font><b>Idx
</b><font color="#008000"><b>CASE IS </b></font>&lt; <b>Array1Size
MyArray1</b>(<b>Idx</b>) = <b>Abyte
</b><font color="#008000"><b>CASE IS </b></font>&lt; (<b>Array1Size </b>+ <b>Array2Size</b>)
<b>MyArray2</b>(<b>Idx </b>- <b>Array1Size</b>) = <b>Abyte
</b><font color="#008000"><b>CASE ELSE
</b></font><b>MyArray3</b>(<b>Idx </b>- (<b>Array1Size </b>+ <b>Array2Size</b>)) = <b>Abyte
</b><font color="#008000"><b>END SELECT
RETURN</b></font>

Then to use it ...

Idx = 180
Abyte = 123
GOSUB PutArray

Idx = 180
GOSUB GetArray
LCDOUT DEC Idx,"=",DEC Abyte

Or something like this, which sets each element to it's own Idx value, then reads them back and displays the saved value.
Main:
FOR Idx = 0 to 255
Abyte = Idx
GOSUB PutArray
NEXT Idx

FOR Idx = 0 to 255
GOSUB GetArray
HSEROUT ["G-",IDEC3 Idx," ",IDEC Abyte,13,10]
NEXT Idx

STOP


Not as easy as MyArray(180), but it's an option.<hr>
Then if you want, you can add a couple macros to make it look more like what you wanted ...
ASM
#GetArray macro Idx, Bout
MOVE?BB Idx, _Idx
L?CALL _GetArray
MOVE?BB _Abyte, Bout
endm
#define GetArray(Idx, Bout) #GetArray Idx, Bout

#PutArray macro Idx, Bin
MOVE?BB Idx, _Idx
MOVE?BB Bin, _Abyte
L?CALL _PutArray
endm
#define PutArray(Idx, Bin) #PutArray Idx, Bin
ENDASM

Which then lets you do this...

MyByte VAR BYTE

@ PutArray(_Idx, _MyByte) ; similar to MyArray(Idx) = MyByte

@ GetArray(_Idx, _MyByte) ; similar to MyByte = MyArray(Idx)


HTH,

sayzer
- 28th May 2009, 08:00
Hi, Sayzer

Why not use Peekcode and Pokecode ... or simply LOOKUP ( if no change in values ) ??? ... 255 values is the limit for Pic 16F.

With Peekcode/Pokecode, you also can load your data at once including a txt file ...


( No thought to the project section, of course ... !!! )

Alain

Hi Alain,
Yes, as you mentioned, the values change. I get data from PC into a Mem array.



Sayzer, are you saying that Using EXT with Labels in post #1 doesn't work? I don't think so :(


Hi Steve, I need an array not a table. In post#1, the table is for constants, isn't it?

BTW, Apart from this subject, I have spent so much time working on that table but could not read the correct values back from that table. It was not stable.



Hi Sayzer,

No, EXT won't work that way.
The arrays would not be contiguous, and located in different banks.

I've never tried using big arrays on a 16F before, I'd just use an 18F when I need more than 96 bytes.
However, confronted with a challenge ... I have to try.
Here's what I've come up with ...
<font color="#000000"><b>Array1Size </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>64
</b></font><b>Array2Size </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>96 </b></font><font color="#0000FF"><b><i>; 96 is the largest for 16F877
</i></b></font><b>Array3Size </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>96 </b></font><font color="#0000FF"><b><i>; 96 + 96 + 64 = 256 bytes
</i></b></font><b>MyArray1 </b><font color="#008000"><b>VAR BYTE</b></font>[<b>Array1Size</b>]
<b>MyArray2 </b><font color="#008000"><b>VAR BYTE</b></font>[<b>Array2Size</b>]
<b>MyArray3 </b><font color="#008000"><b>VAR BYTE</b></font>[<b>Array3Size</b>]

<b>Idx </b><font color="#008000"><b>VAR BYTE
</b></font><b>Abyte </b><font color="#008000"><b>VAR BYTE
</b></font><font color="#0000FF"><b><i>;---------------------------------------------------------------------------
</i></b></font><b>GetArray</b>: <font color="#0000FF"><b><i>; Set Idx before calling, result is in Abyte
</i></b></font><font color="#008000"><b>SELECT CASE </b></font><b>Idx
</b><font color="#008000"><b>CASE IS </b></font>&lt; <b>Array1Size
Abyte </b>= <b>MyArray1</b>(<b>Idx</b>)
<font color="#008000"><b>CASE IS </b></font>&lt; (<b>Array1Size </b>+ <b>Array2Size</b>)
<b>Abyte </b>= <b>MyArray2</b>(<b>Idx </b>- <b>Array1Size</b>)
<font color="#008000"><b>CASE ELSE
</b></font><b>Abyte </b>= <b>MyArray3</b>(<b>Idx </b>- (<b>Array1Size </b>+ <b>Array2Size</b>))
<font color="#008000"><b>END SELECT
RETURN

</b></font><b>PutArray</b>: <font color="#0000FF"><b><i>; set Idx and Abyte before calling
</i></b></font><font color="#008000"><b>SELECT CASE </b></font><b>Idx
</b><font color="#008000"><b>CASE IS </b></font>&lt; <b>Array1Size
MyArray1</b>(<b>Idx</b>) = <b>Abyte
</b><font color="#008000"><b>CASE IS </b></font>&lt; (<b>Array1Size </b>+ <b>Array2Size</b>)
<b>MyArray2</b>(<b>Idx </b>- <b>Array1Size</b>) = <b>Abyte
</b><font color="#008000"><b>CASE ELSE
</b></font><b>MyArray3</b>(<b>Idx </b>- (<b>Array1Size </b>+ <b>Array2Size</b>)) = <b>Abyte
</b><font color="#008000"><b>END SELECT
RETURN</b></font>

Then to use it ...

Idx = 180
Abyte = 123
GOSUB PutArray

Idx = 180
GOSUB GetArray
LCDOUT DEC Idx,"=",DEC Abyte

Or something like this, which sets each element to it's own Idx value, then reads them back and displays the saved value.
Main:
FOR Idx = 0 to 255
Abyte = Idx
GOSUB PutArray
NEXT Idx

FOR Idx = 0 to 255
GOSUB GetArray
HSEROUT ["G-",IDEC3 Idx," ",IDEC Abyte,13,10]
NEXT Idx

STOP


Not as easy as MyArray(180), but it's an option.<hr>
Then if you want, you can add a couple macros to make it look more like what you wanted ...
ASM
#GetArray macro Idx, Bout
MOVE?BB Idx, _Idx
L?CALL _GetArray
MOVE?BB _Abyte, Bout
endm
#define GetArray(Idx, Bout) #GetArray Idx, Bout

#PutArray macro Idx, Bin
MOVE?BB Idx, _Idx
MOVE?BB Bin, _Abyte
L?CALL _PutArray
endm
#define PutArray(Idx, Bin) #PutArray Idx, Bin
ENDASM

Which then lets you do this...

MyByte VAR BYTE

@ PutArray(_Idx, _MyByte) ; similar to MyArray(Idx) = MyByte

@ GetArray(_Idx, _MyByte) ; similar to MyByte = MyArray(Idx)


HTH,


Hi DT,

I had made something similar to your first example, but as you mentioned, it is not as easy as using something like Arg0[180].

I must learn this ASM thingie in much upper level to comeup with my own routines.

Thanks very much to all.
----------------------------

boroko
- 9th July 2010, 11:11
Hi all,

Darrell mentioned in his first post that EXT will not work with arrays,
Can anyone suggest an elegant way to receive serial BYTE data in and convert it to WORD data and then sort it? Obviously, this won't work and to do it straight-line would be a mess.

ByteData var byte[32] BANK0

ASM
Arg0 = _ByteData ; word
Arg1 = _ByteData + 2 ; word
Arg2 = _ByteData + 4 ; word
Arg3 = _ByteData + 6 ; word
Arg4 = _ByteData + 8 ; word
Arg5 = _ByteData + 10 ; word
Arg6 = _ByteData + 12 ; word
Arg7 = _ByteData + 14 ; word
Arg8 = _ByteData + 16 ; word
Arg9 = _ByteData + 18 ; word
Arg10 = _ByteData + 20 ; word
Arg11 = _ByteData + 22 ; word
Arg12 = _ByteData + 24 ; word
Arg13 = _ByteData + 26 ; word
Arg14 = _ByteData + 28 ; word
Arg15 = _ByteData + 30 ; word
ENDASM

Arg0 VAR WORD EXT
Arg1 VAR word EXT
Arg2 VAR WORD EXT
Arg3 VAR WORD EXT
Arg4 VAR word EXT
Arg5 VAR WORD EXT
Arg6 VAR word EXT
Arg7 VAR WORD EXT
Arg8 VAR WORD EXT
Arg9 VAR word EXT
Arg10 VAR WORD EXT
Arg11 VAR word EXT
Arg12 VAR WORD EXT
Arg13 VAR WORD EXT
Arg14 VAR word EXT
Arg15 VAR word EXT
...........
'***Sort Array SUB ** collects 16 readings, sorts, and averages middle 8 ******
SortArray:
CounterA=0
SortLoop: ' sorts 16 readings of RawData in order
If Arg(CounterA+1) < Arg(CounterA) then
DataA=Arg(CounterA)
Arg(CounterA)=Arg(CounterA+1)
Arg(CounterA+1+0)=DataA
If CounterA > 0 then CounterA=CounterA-2
endif
CounterA=CounterA+1
If CounterA < 15 then goto SortLoop

Thanks
Bo

Darrel Taylor
- 9th July 2010, 19:20
Hi Bo,

You just need to map a WORD variable to the beginning of the BYTE array.

ByteData VAR BYTE[32]
Arg VAR WORD EXT

@Arg = _ByteData
The Arg word array now overlaps the ByteData array.

PBP does not do any bounds checking on arrays, so even though Arg is defined as a single WORD, you can use it as a 16 word Array.

boroko
- 10th July 2010, 12:09
Thank you again, Darrel for going deeper than most could ever go alone!

I'm afraid that the neutrons just didn't thermalize....(when the energy doesn't slow down enough for it to transfer)

I understand the Arg word array now overlapping the ByteData array.
What I'm at a loss with is how to address the Arg words.

I tried: Arg0, Arg1,... Arg0 = Arg + 1, ... Arg0 = _Arg + 1, ... cant get anything to fly.

Compiled this:

ByteData var byte[32] BANK0
Arg VAR WORD EXT
@Arg = _ByteData

CounterB var byte
for CounterB = 0 to 31
ByteData[CounterB]= CounterB
next CounterB

ASM
Arg0 = Arg + 2 ; word
Arg1 = Arg + 4 ; word
ENDASM
and could see in the .lst file that:
Arg 00000080
Arg0 00000082
Arg1 00000084 So it looks like it assigned addresses. As soon as I added this to the end:
hserout[dec Arg0,10,13]
hserout[dec Arg1,10,13] I got a "Bad Expression" error. I would have expected to fill ByteData with sequential numbers 0-31 and be able to send them out to verify that the WORDs were filled with BYTE{0], BYTE[1] and BYTE{2], BYTE[3].

Your humble servant requests more enlightenment....
Bo

Darrel Taylor
- 10th July 2010, 21:12
Arrays are accessed with an index inside brackets.

Arg(Idx)
Arg(0)
etc.

boroko
- 11th July 2010, 00:40
OOPs!
Thank You

Sometimes RTFM is feels like looking at a forest and someone saying "the bunnies are right there, can't you see them?". Guess I just have to go into the woods and try again!
Bo

boroko
- 11th July 2010, 01:21
I was having trouble understanding the results that I was getting. I ran this to get a better view of how things were working. ...he can be taught...
INCLUDE "AllDigital.pbp"
DEFINE OSC 8 ' this was run on an 18F2525
OSCCON = %01110000
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE HSER_SPBRG 34 ' 57600 Baud @ 8MHz, -0.79%
SPBRGH = 0
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator
ByteData var byte[32] BANK0
Arg VAR WORD EXT
ArgWd0 var word
ArgHi0 var byte
ArgLo0 var byte
ArgWd1 var word
ArgHi1 var byte
ArgLo1 var byte
@Arg = _ByteData
hserout["ArgTest",10,13]
start:
CounterB var byte
for CounterB = 0 to 31
ByteData[CounterB]= CounterB
next CounterB

hserout["Byte0= ",dec bytedata[0],", Byte1= ",dec bytedata[1],10,13]
ArgWd0 = Arg[0]
ArgHi0 = ArgWd0.highbyte
ArgLo0 = ArgWd0.lowbyte
hserout["Arg0 HiBtD= ",dec ArgHi0,10,13]
hserout["Arg0 LoBtD= ",dec ArgLo0,10,13]
hserout["Arg0 HiBtB= ",bin ArgHi0,10,13]
hserout["Arg0 LoBtB= ",bin ArgLo0,10,13]
hserout["Arg0 HiBtH= ",hex ArgHi0,10,13]
hserout["Arg0 LoBtH= ",hex ArgLo0,10,13]
hserout["Arg0= ",dec Arg[0],10,13]
hserout["Byte2= ",dec bytedata[2],", Byte3= ",dec bytedata[3],10,13]
hserout["Arg1= ",dec Arg[1],10,13]
ArgWd1 = Arg[1]
ArgHi1 = ArgWd1.highbyte
ArgLo1 = ArgWd1.lowbyte
hserout["Arg1 HiBtD= ",dec ArgHi1,10,13]
hserout["Arg1 LoBtD= ",dec ArgLo1,10,13]
hserout["Arg1 HiBtB= ",bin ArgHi1,10,13]
hserout["Arg1 LoBtB= ",bin ArgLo1,10,13]
hserout["Arg1 HiBtH= ",hex ArgHi1,10,13]
hserout["Arg1 LoBtH= ",hex ArgLo1,10,13]
hserout["Arg1= ",dec Arg[1],10,13]
end
The results were:
ArgTest
Byte0= 0, Byte1= 1
Arg0 HiBtD= 1
Arg0 LoBtD= 0
Arg0 HiBtB= 1
Arg0 LoBtB= 0
Arg0 HiBtH= 1
Arg0 LoBtH= 0
Arg0= 256
Byte2= 2, Byte3= 3
Arg1= 770
Arg1 HiBtD= 3
Arg1 LoBtD= 2
Arg1 HiBtB= 11
Arg1 LoBtB= 10
Arg1 HiBtH= 3
Arg1 LoBtH= 2
Arg1= 770 That let me see that it was being stored like this:
00000001 00000000 = 256
00000011 00000010 = 770
Don't know if that will help anyone, but it helped me understand a bit more.
Bo