LED display for compass heading

westaust55

Moderator
Having got my CMPS03 re-calibrated manually (no luck with the i2c method)
I have assembled the CMPS03 into a small plastic box, mounted on the inside top with nylon nuts and bolts.

On the cover of the box, I have assembled a circle of 16 LED's as a form of simple visual heading indicator. These LED's are controlled via two PCF8574 8-bit IO expanders - each controlling 8 LED's.

Tonight, I have successfully written a short program to drive the 16 LED's in 32 steps corresponding to the compass heading. Again I have used a maths based scheme (akin to my earlier bargraph logic) rather than the look-up table in EEPROM as often done.

Attached is a diagram showing how the LED patterns are used for 32 steps with a resolution of 11.25 degrees and below is a sample of the code I wrote to drive the LED's.

Code:
; =================================================
;   File....... CMPS03 LED heading Indicator Test
;   Purpose.... test operation of the set of 16 LEDs via i2c comms 
;   Author..... Westaust55
;   E-mail.....
;   Started.... 02-07-2008
;   Updated.... DD-MM-YYYY
;  ===============================================
;
; -----[ Program Description ]---------------------------------------------
;
; A program to test operation of the set of 16 LEDs mounted in a circle 
; as a visual heading indication for use with the CMPS03 cpompass module
; using i2c comms 
;
; -----[ Revision History ]------------------------------------------------
; First coding
; 
;
; -----[ I/O Definitions ]-------------------------------------------------
;
;
; -----[ i2c Devices ]-------------------------------------------------------
;

;
; PCF8574 8-BIT IO EXPANDERS
SYMBOL expand_0 = %01000000  ; %0100 = Chip ID, 000 = Addr 0 - For the 8 Red LED's
SYMBOL expand_1 = %01000010  ;                , 001 = Addr 1 - For Keypad Shift LED
SYMBOL expand_2 = %01000100  ;                , 010 = Addr 2 - For Compass LED display right half
SYMBOL expand_3 = %01000110  ;                , 011 = Addr 3 - For Compass LED display left half
;
;
; DS1338 REAL TIME CLOCK with 56 bytes of RAM
SYMBOL rtc1338  = %11010000  ; %1101 = Chip ID, 000 = hard addr
;
;
; -----[ Constants ]-------------------------------------------------------
;
;
; -----[ Variables ]-------------------------------------------------------
;
SYMBOL delaytime = b22
SYMBOL pattern   = w10
SYMBOL pattrn2   = w9
;
; -----[ EEPROM Data ]-----------------------------------------------------
;
;
;
; -----[ Initialization ]--------------------------------------------------
;
Init:   delaytime = 500
        
;
;
; -----[ Program Code ]----------------------------------------------------
;
Main:	  HI2CSETUP i2cmaster, expand_1, i2cslow, i2cbyte ; Set up for 9th LED
        HI2COUT (0) ; SHIFT LED off
        PAUSE 500
        HI2COUT (1) ; SHIFT LED on - just blink LED on and off
        PAUSE 1000
        HI2COUT (0) ; SHIFT LED off
        PAUSE 500
        HI2CSETUP  i2cmaster, expand_0, i2cslow, i2cbyte ; Set up for set of 8 LEDs
        HI2COUT (255) ; turn on all LEDs for 1 second
        PAUSE 1500
        HI2COUT (0)
        PAUSE delaytime

; the above line of code are just to turn of the LED's for the bargraph and keypad shit key
; these LED's use positive logic (1 = ON, 0 = OFF) done by adding a transistor to the expander outputs.
;
;
; the LED's for the compass heading are wired and using inverted logic 
; hence the INV command at the start of the shwpattn subroutine below.
        
        
circle: FOR w4 = 0 TO 359     ; degrees in circle
        
        w5 = w4 * 10          ; this is equal to actual reading will get from CMPS03
        w2 = w5 * 10 + 562    ; adjusted value 562 = half of the 11.25 degree resolution as offset
        w2 = w2 / 1125 AND 31 ; divide by 11.25 deg reolution for step 0 to 31 and rolling over to 0
        b6 = w2 / 2           ; bit position for the first LED posiiton 0 to 15
        b7 = w2 // 2          ; when b7 = 1 means the 2nd LED is required
        
        IF b7 = 1 THEN
          b7 = b6 + 1         ; get the corect bit position for the 2nd LED
        ENDIF
        
        pattern = DCD b6      ; 1st LED is encoded here
        
        IF b7 > 0 THEN
          pattern = DCD b7 OR pattern ; add/or in bit position for second LED when it is required
        ENDIF
                
        GOSUB shwpattn        ; now display the correct LED pattern
        
        PAUSE 100
        
        NEXT w4               ; advance to next degree of heading
        
        GOTO circle           ; and go around again and again
        
;       END
;
; -----[ Subroutines ]----------------------------
;
shwpattn: pattrn2 = INV pattern
          HI2COUT [expand_2], (b18)  ; pattern for right side of LED indicator
          PAUSE 10
          HI2COUT [expand_3], (b19)  ; pattern for left  side of LED indicator
          RETURN
;
; -----[ Interrupt Routines (if used) ]-----------
;
;Interrupt: 
;	     
;         RETURN
; =================================================
;      THE END
; =================================================

hmmm, I guess a Nokia 3310 graphic LCD screen would also make a nice compass heading display as well - likely even better angular resolution as well. Food for thought and future projects here.
 

Attachments

Last edited:

BeanieBots

Moderator
The CMPS03 can be configured to give 0-255 for 0-360 degrees.
Using that configuration would make the sums much easier!
 

Andrew Cowan

Senior Member
Excellent commenting on your program - comments on most lines, symbols (but not too many), and a decent introduction makes that a really legible piece of coding.

Andrew
 

krypton_john

Senior Member
Nice work.

This would be a sitter for a GLCD driven graphic LCD - if I recall correctly they allow drawing of circles and lines, as well as text, so you could implement a beautiful graphic compass rose and pointer.
 

westaust55

Moderator
The CMPS03 can be configured to give 0-255 for 0-360 degrees.
Using that configuration would make the sums much easier!
The CMPS03 provides both a 1-byte (0-255) and 2-byte (0-3599) output without any configuration. Just a matter of which registers you read.

In terms of the maths, I don't think that using 0-255 would reduce the maths. I still need to:
1. impliment an offset of 5.62 degrees as half the resolution so an LED sequence comes on 5.62 degrees before the "centre heading" and goes of 5.62 degrees after.
2. divide a value by a number representing 11.25 degrees being the resolution available with 16 LED's over 360 degrees with 32 illumination combinations.

If using a lookup table from EEPROM as opposed to maths, then yes, 0-255 would be a simpler solution.
 
Last edited:

westaust55

Moderator
LED display for compass and doing one's own maths

The Rev-Ed GLCD kit driver does pointers for you. No maths required.
True but the Rev_Ed gLCD module would cost me about $AUD200 here in Australia.

Experimenting with hardware is my hobby. Done for now using LED’s to date (as they were all parts to hand other than the CMPS030) and gave me an evening thinking about the maths to drive the 16 LED’s as “32 steps/headings” and writing the program.

Not knocking the Rev Ed gLCD module but for me personally the idea of say the Nokia 3310 graphic LCD screen, albeit smaller but then so is the pricing, has more appeal in terms of building my own hardware and software modules for experimenting.

Reminiscence time:
Back around 1982, I modified theA4 sized graphics card in my old OSI C2-4P and added 256 x 256 resolution chunky graphics (had to be better than the TRS-80 aka Trash-80 :D ) then modified BASIC to add SET and RESET commands to turn each “chunk” (2x2 pixels). Fun was as much doing the maths in M/C to be able to alter any one chunk without affecting any other chunk using additional character graphics by burning a new and larger EPROM as character graphic generator.

These days we buy a SPE030 speech module whereas around 1982 I bought the SC01 speech chip from the Federal Screw Works in the US (does not sound very semiconductor orientated does it – maybe that’s why it stuck in my mind all these years). Wrote my own machine code text to speech algorithms based on the US Naval Research Labs formulas and spliced this into the computer BASIC’s of the day (OSI first and later Commodore 64) by converting the keyword “LET” to “SAY”. Full test string manipulation and interrupt driven so computer could keep doing other things while speech was output.
 

BCJKiwi

Senior Member
Would like to see the layout of the 32 points/dual led approach to the display when you are ready - looks very interesting.
Current project just used the 16 points (leds in a circle) rather than multi led to get 32 points.
Base code is;

Code:
 hi2cin [CMP_0],2,(b3,b2)    '(w1) Read compass bearing as a word (0-3599 for full circle)
 b0 =w1+112/225     'add 112 (225/2) to offset zero to mid of 1/16 step, divide by 225 to get 16 values
 if w1 > 3485 then let b0 = 0 :Endif  '0 represents North, 0 - 15 and Centre result on zero degrees
 if b0 < 8 then 
  let b5 = %11111111
  b1 =b0 +LED_Compass   'compass bit patterns start eeprom LED_CompassBitPattern
  read b1,b4     'read stored bit pattern for compass reading
 else
  let b4 = %11111111
  b1=b0 -8 +LED_Compass  'compass bit patterns start at eeprom LED_CompassBitPattern, b1 =>8
  read b1,b5
 endif
 hi2cout [IO_0],$12,(b4,b5)  'MCP23017 - Compass
One reason this project uses eeprom and (read/write/ptr) in the (not shown) associated code is that a sequence of data from a number of inputs is built up then written out to a uAlfat data logger in a single consecutive sequence.
Another reason is that I find it easier (simple mind I guess) to keep the math simpler and refer to the patterns in eeprom. The patterns are easier to fiddle with in eeprom than in code. e.g. the INV function is implemented in the eeprom patterns.

Without spending a lot of time on the comparison, I think the basic math is pretty similar. The reads from eeprom could be substituted for direct calculation as Westy does. The eeprom patterns don't actually take any program memory (on a 28X1).

Anyway, as has been said many times before, there are many valid ways to do these things and we all have our favorites which suit our style of working.
 
Last edited:

westaust55

Moderator
LED display for compass heading layout+schematic

Hi BCJKiwi,

I presume that you have looked at the attachment to post 1 which gave some details of when each LED is illuminated relative to the compass direction.

Attached is a rough layout depicting the arrangement of the LED’s as shown from the front and a part schematic showing how I have each LED connected to the 8-bit IO Expander chips.

With a 16-bit IO expander possibly you can set that up to write a single word (rather than the 2 bytes I write).

As a simple description for the first few degrees of the compass (0 to 45),
1. when the direction is at 0 degrees +/-5.6degrees, only LED 0 is ON = North
2. when the direction is at 11.2 degrees +/-5.6deg both LED 0 and LED1 are ON = NNE
3. when the direction is at 22.5 degrees +/-5.6deg only LED1 is ON = North East
4. when the direction is at 33.7 degrees +/-5.6deg both LED 1 and LED2 are ON = ENE
5. when the direction is at 45 degrees +/-5.6deg only LED1 is ON = North East

The maths all work on this basis sectors of 11.25 degree arc with a +/-5.6 degree “zone” for each sector.
This arrangement gives twice the resolution over just bringing on one LED with each having a 22.5 degree arc.

In terms of the LED colours I used, just so happened that I did not have enough red LED’s in the “junk” box for a full circle and then thought that the added colours will give a better idea of orientation. Alternative if only used in a lit area would be markings beside the LED’s but as the compass module box is black and so is the Letraset I have that was a non event.

Hope this answers your question. Could see if I get time tonight to take a couple of photos if this may help you further.
 

Attachments

BCJKiwi

Senior Member
Thanks for that - makes much more sense now - only had a quick look at your post before and assumed there were more than 16 LEDS and so the layout did not immediately present itself.

Will you manage brightness differently for two vs one LED? The circuit does not seem to and the PCF8754's do not have brightness control as far as I can see. The I/O expanders that do have brightness control seem inordinately complicated - won't work for me anyway as I supply the LEDs from a PWM'd dimming control.

Just wondering what happens when two LEDs are on as opposed to one being on and thought you might need to run the pairs at less intensity so two LEDs are at least no brighter than one on if not a little dimmer.

Had briefly thought about double the number of LEDs for my project and put it to one side and got on with the rest of it - just seemed to complicated and too many chips. The display is relatively compact and a lot of LEDs seemed overkill but your solution overcomes that issue. I've decided to use rectangular LEDs and have not yet settled on a radial or a circumferential arrangement of LEDs on the circle.

Just brainstorming here but one option would be to double the number of LEDS and set them up in two banks, primary and secondary with a toggle of V+ between banks. That way all the same basic code can be used and if the the bearing is between the LEDS in bank 1, then V+ is switched OFF bank 1 and ON to bank 2 to light the other LEDs through the same I/O expander logic. Hmmm... have to think about this a bit more - Bankieplexing?!?
 
Last edited:

BCJKiwi

Senior Member
Not practical - see revised post #16
Thinking further on my last post,
If the same V+ is used to supply the I/O expander and the LEDs, then use of an MCP23017 (or similar) 16 port I/O expander which has IODIRection registers and GPIO source/sink control on every I/O, then;

32 LEDs should be able to be controlled by placing pairs of LEDs in parallel facing the opposite way. In a compass display, only one LED is on at a time so there should be no issues switching register direction and which I/O are source sink - unless there is a 'blink' as the registers are switched around!

Code:
[COLOR=silver]      V+ ----> I/O Expander ----  R --+----|>|----> 0v[/COLOR]
[COLOR=silver]                                      |[/COLOR]
[COLOR=silver]      0V <---- I/O Expander           +----|<|----< V+[/COLOR]
This would mean that there would be no additional parts or issues switching supply to different banks of LEDs.
Unfortunately this is of no use in my current project as the LED supply is a varying PWM controlling LED brightness and that can't be used to supply the I/O expander.
 
Last edited:

westaust55

Moderator
Yes that will work for a single IO pin on the MCP230XX type IO expanders as they do have the same current sink and source rating for each IO pin.
But . . . how do you set all LED's except the one you want to the OFF state?

By comparison, the PCF8574's can sink 20mA but only source around 0.5mA. :rolleyes:



Thinking further on my last post,
If the same V+ is used to supply the I/O expander and the LEDs, then use of an MCP23017 (or similar) 16 port I/O expander which has IODIRection registers and GPIO source/sink control on every I/O, then;

32 LEDs should be able to be controlled by placing pairs of LEDs in parallel facing the opposite way. In a compass display, only one LED is on at a time so there should be no issues switching register direction and which I/O are source sink - unless there is a 'blink' as the registers are switched around!

Code:
        V+ ----> I/O Expander ----  R --+----|>|----> 0v
                                        |
        0V <---- I/O Expander           +----|<|----< V+
This would mean that there would be no additional parts or issues switching supply to different banks of LEDs.
Unfortunately this is of no use in my current project as the LED supply is a varying PWM controlling LED brightness and that can't be used to supply the I/O expander.
 

westaust55

Moderator
Here are a couple of pics showing the internals and external of the plug-in compass module that I have assembled.

Few comments on the pics highlights some features.

Eclectic should be proud of me. He only just mentioned, today I think, about the issues of letting out the puff of smoke when the simple unpolarised conenctors are plugged in reversed. :eek:
Had already thought about that and with 9 wires, made the centre pin the +5V on both conenctors so any swapping or rotating of the two 9-pin conenctors might result in wrong LED coming on but chance of damage. :D

With respect to LED intensity, while the pic does not show it well, to the best of my visual ability, the LED's appear to be the same brightness whether one ON or two ON at the same time. The resistors would help regulate the current to a fair degree.
 

Attachments

BCJKiwi

Senior Member
This theory is fundamentally flawed. It attempts to get double duty from the I/O ports as they can be set for source/sink and current direction. However when connecting as in the proposed circuit;
Code:
[/COLOR]
[COLOR=black] 
      V+ ----> I/O Expander ----  R --+----|>|----> 0v
                                      |
      0V <---- I/O Expander           +----|<|----< V+[/COLOR]
There is a free current path from V+ throught one LED and out the other to 0V so both LEDS are on all the time. Addtional ports would be required, to implement a carlieplexing type of operation which defeats the purpose which was to save outputs!

Well this is all theory at the moment - will have to test in practice to prove it.

The MCP23xxx have both direction registers and I/O on/off registers. The 23017 has more control and additional registers so may be easier to work with in this case.

1.5 GPIO Port
Writing to the GPIOn register actually causes a write to
the latches (OLATn). Writing to the OLATn register
forces the associated output drivers to drive to the level
in OLATn. Pins configured as inputs turn off the
associated output driver and put it in high-impedance.
1.6.1 I/O DIRECTION REGISTER
Controls the direction of the data I/O.
When a bit is set, the corresponding pin becomes an
input. When a bit is clear, the corresponding pin
becomes an output.
1.6.2 INPUT POLARITY REGISTER
This register allows the user to configure the polarity on
the corresponding GPIO port bits.
If a bit is set, the corresponding GPIO register bit will
reflect the inverted value on the pin.
Figured that between all these interacting input or output, invert or not and sink or source, one should be able to effectively change the direction of current flow through the port AND change the the port to sink or source, effectively turning it on and off in both current flow directions. So both functions would need to be changed together to achieve the result.

Think of it like an output you turn on or off, and then turn the output around so it is an input which you can still turn on and off.

If you start from the present setup with LED with pointy end toward the I/O expander and V+ on the LED, then the LED is turned on/off by the GPIO which is actually switching between sink/source - same as an output on the PICAXE.

If you then change the I/O expander port direction, all LEDs pointing toward the I/O expander would turn off (no current path in that direction)
Then you turn on/off the GPIO port sink/source and current flows away from the I/O Expander through LEDs with pointy end to 0V.
 
Last edited:

westaust55

Moderator
Yes, if when a pin is set to an input there is no or insufficient current then there is small prospect that your theory just may work.

There are weak pull up resistors on the input mode - think these may be turned off as well but even if on, at 100 kOhm the current leakage into an LED will only be around 0.05mA. My past tests found that an LED will illuminate but very dull at between 0.1 and 0.5mA.

Issue of current thru both LEDs exist and at just 1 mA an LED can be visible.

At the end of the day, a bench test will be the best proof.
 

Attachments

Last edited:
Top