# PIC Lookup Table

Status
Not open for further replies.

#### Steve NA

##### New Member
Hi,

I'm new at programming Microchip, specifically - PIC16F872, which I have started with on this project.

The program works well and displays correctly, until the look-up table reaches the 188th count.

Table Start:
RETLW 0x00
RETLW 0x01
RETLW 0X02 "
"
"
RETLW 0X99
RETLW 0X00
RETLW 0X01
"
"
RETLW 0x88

The counter quits at this time and no more values are read.

Is there a setting that increases the count capability to allow greater that 188 to be read, and where is it put in the code.

Thanks for any assistance.
Steve.

#### Nigel Goodwin

##### Super Moderator
Tables (like that one) can't cross a 256 byte boundary - there are various techniques you can use though, check my tutorials for examples (in particular the 8x8 LED matrix one).

#### dougy83

##### Well-Known Member
As mentioned, you can't cross a 256 instruction boundary with the table if you want to access with a simple ADDWF PCL.f - you have to take into account the most significant bits also. Here's one way that it could be accomplished:
Code:
tableRead:
movwf	tabLow				; tabLow is just a temporary variable
movlw	HIGH(__tabstart)
btfsc 	STATUS,C
movwf	PCLATH
movfw	tabLow
movwf	PCL

__tabstart:
RETLW 00
... rest of table ...

#### Steve NA

##### New Member
Hi Dougy83,

Generally, a CALL is made from the main program and returns with the result. With your suggestion, where is your code inserted relative to the CALL instruction and does it CALL tableread or tabstart?
Is tabLow a temporary register I need to setup when naming bits??
I'm a novice and need help.

Thanks, Steve.

#### dougy83

##### Well-Known Member
Steve,

The call is made to tableRead, in the same manner that you previously were calling Table_start.

Yes, you need to set up the tabLow file register. If you place this variable in the shared memory section, you won't have to set the memory bank before calling tableRead.

#### Steve NA

##### New Member
Dougy83,

One more question. For the Low and High tabStart, are they the program line numbers where the table codes start and finish?

Cheers,

Steve.

#### dougy83

##### Well-Known Member
The __tabstart label I added is just before the first RETLW xx of your lookup table. This means that I can get the least significant byte (LSB) of the address of the lookup table using LOW(__tabstart) and I can get the most significant byte of the address using HIGH(__tabstart). This is needed because the address uses more than 8 bits.

The code I posted does the following: "PC <-- __tablestart + W"
If we only pay attention to the lower 8 bits (e.g. your original code), it's equivalent to performing the operation: "PC <-- (__tablestart & 0xFF00) + ( (__tablestart + W) & 0xFF)"... sorry if that is hard to understand, but it basically means that the address will wrap around the the 256 byte boundary. e.g. if you are at address 10 and you add 250 to PCL, PCL becomes (10 + 250 + 1) & 0xFF = 261 & 0xFF = 5, so we've actually jumped back 5 instructions rather than jumping forward 250.

#### dr pepper

##### Well-Known Member
If I had a quid for every time this happened to me.
As allready mentioned addwf pcl,f only adds 8 bits to the program counter, if the program counter is allready close the end of a 256 byte 'page' then crossing that page will end up sending the program counter backwards (confusing eh).
When I use lookups on a long program I assemble the program and then look at the .lst file which tells you all the memory locations for each line then put all the lookup tables at the start of the nearest 256 byte page, you can do this like so:

org 0x100
;
lookup table
;
movlw d'1'
movwf pclath
;
movf lookupvalue,w
;
retlw b'00000000'
retlw b'11111111'
etc

This directs the assembler to assemble the code at memory loc hex100, which is the start of the second page, and loading 1 into pclath tells the pcl function which page to work in (pclath is loaded into the high byte of the prog counter when you address pcl).
The org instruction tells the assembler to begin assembling at the specified address, if you had more than one table just assemble on a different page, 200, 300 etc, just make sure you dont go off the edge of the chip.
I'm sure there are other ways of doing this, this is my way.

Last edited:

#### Steve NA

##### New Member
Hi Dr Pepper,

I'm originally from Bolton, Lancs.

I tried a couple of suggestions received earlier and had trouble getting them to work.
What I ended up doing is reading ADRESH, where the A/D data was stored, moving it to a register and then adding to it so that the value looked as if had started from "0", so that
the look-up table didn't have to be large. I needed to display values from 0 to 250, so by adding 156 to the register once the value in ADRESH was 100 or more, it seemed to work fine.
This reduced the look-up table size to 150 places.
I will however try your suggestion as it seems simpler.

#### Diver300

##### Well-Known Member
You can save a lot of program space with a linear interpolation lookup, as long as the function is fairly linear.

There is an example here:-http://www.piclist.com/techref/microchip/interpolation.htm

It has a 17 element lookup table. The top nibble of x is used to look up a value from the table, and then the next value is collected as well. The difference between them is the slope, which is multiplied by the bottom nibble, and added to the first value looked up. If the slope is negative, the product is subtracted instead of added.

In the example on that web page, if looking up the cos of 0x8C (where 0x100 is scaled as 90°), then 0x8 is used to lookup a value (decimal 180) and then the next value is taken (decimal 162). The difference is 162 - 180 = -18
That is multiplied by 0x0C and divided by 16 to give -13, and that is added to the first lookup value of 180 to give 167.

The answer represents 167/256 = 0.652
( as a comparison, with a calculator, 0x8C represents 49.2°, and the cos of that is 0.653)

I have used a similar technique on arctangents. To keep the numbers small, above arctan(1), the program works out 90 - arctan(1/x) instead of arctan(x). That uses a 5 element look up table, and an interpolation function, and is within 1° for all values.