Hi, am in the search of speed and efficiency.
The following code (a part only of the whole project) achieves the process of reading the current value of a compass chip, and of an accelerometer chip.
These values are used to output via MCP23016 I/O expanders which are arranged in two banks of 8 so output of the LEDs to turn on is achieved by sending two bytes to the MCP23016 representing the bit patterns required.
Later they will also be logged to USB or SD storage.
Have refined the code which follows but feel it could be better.
Have already established that using 'lookup' saves substantial code space. The subroutine using lookup at the program end saves 184 bytes over the alternative If/Else/Endif construct.
However both the If/Else/Endif construct and the Lookup code rely on a list of symbol statements to represent the bit patterns.
It seems that the bit pattern should be able to be calculated directly rather than looking up the value from the list. However I feel this would probably require a number of If/Else/Endif statements anyway and as the bit patterns required are not as straight-forward as it initially appears it may not actually be a lot more efficient.
At this stage I can't figure the best way to do the math so am not sure if its worth proceeding any further.
So much Kudos to those who can offer up a better (i.e. faster and/or smaller) solution.
Here's the code - I trust it is sufficiently commented to to provide the needed info for analysis.
Thanks
Well its a pain that the formatting is not retained but this is too big to re-edit here - is there a way to retain the code formatting?
The following code (a part only of the whole project) achieves the process of reading the current value of a compass chip, and of an accelerometer chip.
These values are used to output via MCP23016 I/O expanders which are arranged in two banks of 8 so output of the LEDs to turn on is achieved by sending two bytes to the MCP23016 representing the bit patterns required.
Later they will also be logged to USB or SD storage.
Have refined the code which follows but feel it could be better.
Have already established that using 'lookup' saves substantial code space. The subroutine using lookup at the program end saves 184 bytes over the alternative If/Else/Endif construct.
However both the If/Else/Endif construct and the Lookup code rely on a list of symbol statements to represent the bit patterns.
It seems that the bit pattern should be able to be calculated directly rather than looking up the value from the list. However I feel this would probably require a number of If/Else/Endif statements anyway and as the bit patterns required are not as straight-forward as it initially appears it may not actually be a lot more efficient.
At this stage I can't figure the best way to do the math so am not sure if its worth proceeding any further.
So much Kudos to those who can offer up a better (i.e. faster and/or smaller) solution.
Here's the code - I trust it is sufficiently commented to to provide the needed info for analysis.
Thanks
Code:
'####################################################################################
'# PICAXE 28X1, DIMENSION ENGINEERING DEACCM3D, MCP23016 I/O #
'####################################################################################
#picaxe 28x1
SetFreq m8
'####################################################################################
symbol CMP_0 = %11000000 'Devantech CMPS03 i2c address
symbol IO_0 = %01000000 'Compass - Microchip MCP23016 I/O expander i2c address
symbol IO_1 = %01000010 'Left/Right accelerometer
symbol IO_2 = %01000100 'Acceleration/Braking accelerometer
symbol IO_3 = %01000110
symbol LC0 = %11111111 'compass binary data for 16 LED heading display
symbol LC1 = %11111110 'LC == Led Compass
symbol LC2 = %11111101 '16 values - 0 thru 15 represent 360 degrees of compass
symbol LC3 = %11111011 'Displayed by turning on 1 led of 16
symbol LC4 = %11110111 ' on two banks of MCP23016 16 port I/O expander
symbol LC5 = %11101111
symbol LC6 = %11011111
symbol LC7 = %10111111
symbol LC8 = %01111111
'
symbol LA0 = %11111111 'Accelerometer binary data for LED Display
symbol LA1 = %11111110 'LA == Led Accelerometer
symbol LA2 = %11111100 '21 values - 0 thru 20 represent 0, and + 1 thru 10 & - 1 thru 10
symbol LA3 = %11111000 'Displayed by turning on LEDs of 10 led Bar graph
symbol LA4 = %11110000 'Leds turned on in bar graph mode - from left to right for +
symbol LA5 = %11100000 'Leds turned on in bar graph mode - from right to left for -
symbol LA6 = %11000000 'NO LEDs turned on at mid range (= value 10)
symbol LA7 = %10000000 '1 thru 8 on one bank of MCP23016 16 port I/O expander,
symbol LA8 = %00000000 ' 2 leds on the other
'
symbol LA10 = %11111111 'Accelerometer binary data for LED Display
symbol LA11 = %11111101 'LA == Led Accelerometer
symbol LA12 = %11111100
symbol LA21 = %01111111
symbol LA22 = %00111111
symbol LA23 = %00011111
symbol LA24 = %00001111
symbol LA25 = %00000111
symbol LA26 = %00000011
symbol LA27 = %00000001
symbol LA28 = %00000000
Init:
'MCP23016
hi2csetup i2cmaster,IO_0,i2cfast_8,i2cbyte
'%0100 0 0 0 0 is the address with A0,A1,A2 all tied to 0V
'%0100 A2 A1 A0 RW - there is no explanation for the 6th bit being '1'
'If using multiple devices of different speeds on the bus,
'then use this line to change speed and remove the [%01000000] in the next line.
hi2cout [IO_0],6,($00,$00)
'IRDIR0,IRDIR1 set port direction register to output
'Note:- MCP23016 documentation indicates this register pair (06 & 07)
'defaults to all 1's (all Inputs) on Power On Reset.
'However if this register pair is not configured to all 0's (Outputs)
' there is no function when driving LEDS.
hi2cout $0A,($00,$00) 'IOCON0
hi2cout 0,(LC0,LC0) 'turn off all the LEDs
hi2cout [IO_1],6,($00,$00) 'IRDIR0,IRDIR1 set port direction register to output`
hi2cout $0A,($00,$00) 'IOCON0
hi2cout 0,(LC0,LC0) 'turn off all the LEDs
Main:
'COMPASS
Compass:
' hi2csetup i2cmaster,%11000000,i2cfast_8,i2cbyte ' Set up i2c for device
' hi2csetup i2cmaster,[CMP_0],i2cfast_8,i2cbyte ' Set up i2c for device
'If using multiple devices of different speeds on the bus,
'then use this line and remove the [CMP_0] in the next line.
' hi2cin [CMP_0],0,(b22) 'Read CMPS03 Software Revision
'[CMP_0] ensures correct i2c is read - reqd if more than one
'i2c device on bus being read in sequence
hi2cin [CMP_0],2,(b27,b26) '(w13) Read compass bearing as a word (0-3599 for full circle)
'CMPS03 Register 2=HighByte,3=LowByte.w13(b26)=hibyte,(b27)=Lobyte
ptr=4
'Store w13 for datalogging; 0-3599
'future datalogging code here
If @ptr = b26 then EndCompass ' skip if MSB not changed
@ptr=b26 ' store MSB (35) to Scratchpad 4
inc ptr
@ptr=b27 ' store LSB (99) to Scratchpad 5
b0 = w13+113/225 ' add 113 (225/5) to offset zero to mid of 1/16 step,
' divide by 225 to get 16 values
if w13 > 3485 then let b0 = 0'0 represents North, 0 - 15 and Centre result on zero degrees
endif
if b0 < 8 then let b20 = LC0
lookup b0,(LC1,LC2,LC3,LC4,LC5,LC6,LC7,LC8),b21
else
let b21 = LC0
b0=b0-8
lookup b0,(LC1,LC2,LC3,LC4,LC5,LC6,LC7,LC8),b20
endif
IOEXP_0:
hi2cout [IO_0],0,(b21,b20)
' sertxd (" Compass Bearing:",#w13," ",#b0,cr,lf)
EndCompass:
'ACCELEROMETER
ACCEL_0:
'Read value and store to scratchpad
' use to calibrate actual output from ACCM3D
'sertxd ("X = ",#w0," Y = ",#w1)
'pause 10000 ' Current actual values == X = 333, Y = 340, Z = 398
'subtract 126 from X and Y values to obtain value for '0' - the min value.
'Divide by 12 to get 21 integers 0 thru 20
'range is 21 X 12 = 252 or 0 thru 251.
'Gives 10 leds for each direction plus no led for no g (1x10 led bar used on both directions)
IOEXP_1: 'Left / right Accelerometer
ReadADC10 1, w0 'Dimension Engineering DE-ACCM3D Accelerometer +- 3G in X,Y & Z Axes
b6=w0 Min 207 - 207 Max 251 / 12 'X - centre output on 126 (0g), limit to byte range (+-1.848G)
ptr=1
If @ptr = b6 then IOEXP_2 ' Skip if value not changed
@ptr = b6 ' store X axis - scratchpad 1
gosub Accel_Out
hi2cout [IO_1],0,(b0,b1) 'Turn on LEDs output
IOEXP_2: 'Acceleration/Braking accelerometer
ReadADC10 2, w1 '0g = 1.66V (ReadADC10 = 339) with 0.333v per g.
' X & Y read 0g when level and static
b7=w1 Min 214 - 214 Max 251 / 12 'Y - 1G = 68 units of ADC10 @ 5.0V Ref
ptr=2
If @ptr = b7 then ENDIOEXP 'IOEXP_3 ' Skip if value not changed
@ptr = b7 ' store Y axis - scratchpad 2
gosub Accel_Out
hi2cout [IO_2],0,(b0,b1) 'Turn on LEDs output
'IOEXP_3: 'Vertical Accelerometer
' ReadADC10 3, w2 'Z Axis reads 1g when level and static
' b8=w2 Min 272 - 272 Max 251 / 12 'Z - Correct Z Axis to centre output on 126 at 1g
' ptr=3
' If @ptr = b8 then ENDIOEXP ' Skip if value not changed
' @ptr = b8 ' store Z axis - scratchpad 3
' gosub Accel_Out
' hi2cout [IO_3],0,(b0,b1) 'Turn on LEDs output
ENDIOEXP:
Goto Main 'Loop for continuous display
'##############################################################################
'# SUBROUTINES #
'##############################################################################
Accel_Out:
' Lookup code saves 184 bytes over If/Elseif sequence below
If @ptr = 10 then let b0 = LA0 'Led Number
b1 = LA0 '10
ElseIf @ptr > 10 and @ptr <13 then @ptr = @ptr-11
lookup @ptr,(LA11,LA12),b1 '11 & 12
let b0=LA10
ElseIf @ptr > 1 and @ptr <10 then @ptr = @ptr-2
lookup @ptr,(LA8,LA7,LA6,LA5,LA4,LA3,LA2,LA1),b0 '2 thru 9
let b1=LA0
ElseIf @ptr > 12 then @ptr = @ptr - 13
lookup @ptr,(LA21,LA22,LA23,LA24,LA25,LA26,LA27,LA28),b0 '13 thru 20
let b1=LA12
else
lookup @ptr,(LA2,LA1),b1 '0 & 1
let b0=LA8
endif
#rem
If @ptr = 10 AND @ptr <130 then let b0 = LA0 : let b1=LA0 'no output 0g == 125
ElseIf @ptr = 9 then let b0 = LA1 : let b1=LA0 '9
ElseIf @ptr = 8 then let b0 = LA2 : let b1=LA0 '8
ElseIf @ptr = 11 then let b1 = LA11 : let b0=LA10 '11
ElseIf @ptr = 12 then let b1 = LA12 : let b0=LA10 '12
ElseIf @ptr = 7 then let b0 = LA3 : let b1=LA0 '7
ElseIf @ptr = 13 then let b1 = LA12 : let b0=LA21 '13
ElseIf @ptr = 6 then let b0 = LA4 : let b1=LA0 '6
ElseIf @ptr = 14 then let b1 = LA12 : let b0=LA22 '14
ElseIf @ptr = 5 then let b0 = LA5 : let b1=LA0 '5
ElseIf @ptr = 15 then let b1 = LA12 : let b0=LA23 '15
ElseIf @ptr = 4 then let b0 = LA6 : let b1=LA0 '4
ElseIf @ptr = 16 then let b1 = LA12 : let b0=LA24 '16
ElseIf @ptr = 3 then let b0 = LA7 : let b1=LA0 '3
ElseIf @ptr = 17 then let b1 = LA12 : let b0=LA25 '17
ElseIf @ptr = 2 then let b0 = LA8 : let b1=LA0 '2
ElseIf @ptr = 18 then let b1 = LA12 : let b0=LA26 '18
ElseIf @ptr = 1 then let b0 = LA8 : let b1=LA1 '1
ElseIf @ptr = 19 then let b1 = LA12 : let b0=LA27 '19
ElseIf @ptr = 0 then let b0 = LA8 : let b1=LA2 '0
ElseIf @ptr = 20 then let b1 = LA12 : let b0=LA28 '20
EndIf
#endrem
Return
Last edited: