Help driving analog multiplexer

MFB

Senior Member
The number of analog channels on a PICAXE can be increased by connecting the output of a multiplexer to one of its ADC inputs. The multiplexer channels are addressed using PICAXE output lines, as shown by the following example.

low 0: low 1: low 2 ; select channel 0
readadc 0, b0 ; read channel 0
high 0: low 1: low 2 ; select channel 1
readadc 0, b1 ; read channel 1
etc…

This approach allows eight multiplexer addresses to be generated, without effecting the state the other output bits. However, the state of the address bits cannot change simultaneously but ripple through with a 300uS delay between each bit (28X1 running at 16MHz). It therefore takes over 1mS for the multiplexer output to settle on the next channel.

Is there a way of simultaneously changing the multiplexer address bits, without altering the state of the other output pins?
 

Jeremy Leach

Senior Member
Yes, I think so. I'd use b0 and issue pins = b0 to set all outputs at the same time. However before doing this, I'd check the output states of the pins you don't want to change and make sure the relevant bits of b0 are set (using the bit variables that make up b0).
 

MFB

Senior Member
The 'let pins =' command looked promising but would have to be used together with a &% mask, to allow only selected bits to be change simultaneously. Unfortunately, my early attempts have been unsuccessful and I can’t find any examples of this technique in the Manual. Help!
 

lbenson

Senior Member
PEEK setting of output port (B) on 28X1, 40X1

As I understand it from past posts and westaust55's SFR document referenced here -- http://www.picaxeforum.co.uk/showthread.php?t=11514 -- the PORTB register, 0x06, can be peeked to determine the settings of the standard 28X1 output pins.

So your code would look like this (assuming that you have set the lower 3 bits of b0 as you wish).

symbol PORTB = 0x06

peek PORTB, b1 ' get the current settings
pins = b1 & %11111000 | b0 ' or in your new 3 bits

I simulated this with the following. Set display to binary and break on "pause 1".

Code:
#picaxe 28X1

w6 = timer

main:
  random w6
  b0 = b13 & %00000111  ' simulate a random setting of 3 bits
  b1 = b12                     ' and a random setting of the outputs
  b2 = b1 & %11111000 | b0
  pins = b2
  pause 1
  goto main
I have not confirmed that PEEK 0x06 will do what you want.
 

lbenson

Senior Member
Perhaps the fastest, if you know the other output bits won't change while you do 8 readings, would be

symbol PORTB = 0x06

peek PORTB, b0 ' get the current settings
b0 = b0 & %11111000 ' low order 3 bits set to zero

pins = b0
readadc 0, b0 ; read channel 0
inc b0
pins = b0
readadc 0, b1 ; read channel 1
inc b0
pins = b0
readadc 0, b2 ; read channel 2
inc b0
pins = b0
readadc 0, b3 ; read channel 3
inc b0
pins = b0
readadc 0, b4 ; read channel 4
inc b0
pins = b0
readadc 0, b5 ; read channel 5
inc b0
pins = b0
readadc 0, b6 ; read channel 6
inc b0
pins = b0
readadc 0, b7 ; read channel 7

This would not likely save more than 250us per read (at 4mHz)--and the savings could well be swamped by the time the readadc takes.
 
Last edited:

hippy

Ex-Staff (retired)
You could use Gray coding for the channel and only change one address bit at a time. Though the channel order will not be sequential the values will still go into b0-b7 ...

Code:
Low  2 : Low  1 : Low  0 : Readadc 0, b0 ' 000
                  High 0 : ReadAdc 0, b1 ' 001
         High 1          : ReadAdc 0, b3 ' 011
                  Low  0 : ReadAdc 0, b2 ' 010
High 2                   : ReadAdc 0, b6 ' 110
                  High 0 : ReadAdc 0, b7 ' 111
         Low  1          : ReadAdc 0, b5 ' 101
                  Low  0 : ReadAdc 0, b4 ' 100
 

MFB

Senior Member
Decided to go with the following 'let pins =' approach in the end, but without masking I just have to keep track of the original set up on the non-mux address pins.
Many thanks for all the advice. 'The loop time is about 12 mS for a 28X1 running at 16MHz.(eg. all eight channels scanned at 80Hz).


'SIMULTANOUSLY CHANGE STATE OF MULTIPLEXER ADDRESS LINES.


high 7 'Setup non-mux output pins to arbitery state for following test.
low 6
high 5
low 4
high 3

read_mux:
let pins = %00101000 'Select analog channel 0, and send low scan pulse from pin 7. readadc 0, b0 'Read analog channel 0.

let pins = %10101001 'Select analog channel 1, but maintain original setup on pins 3-7
readadc 0, b1 'Read analog channel 1.

let pins = %10101010 'etc...
readadc 0, b2

let pins = %10101011
readadc 0, b3

let pins = %10101100
readadc 0, b4

let pins = %10101101
readadc 0, b5

let pins = %10101110
readadc 0, b6

let pins = %10101111
readadc 0, b7

goto read_mux
 

MFB

Senior Member
I did mean to send a low pulse from bit 7 at the start of each scan, to trigger a scope. However, my approach does have the disadvantage that such actions can be introduced by mistake.

I would therefore recommend hippy’s more elegant approach, because it meets my original criteria of not being able to change non-mux related pins when generating new channel addresses.

The loop time for his code was also about 12mS. Thanks yet again hippy!
 

hippy

Ex-Staff (retired)
Real thanks goes to whoever recently mentioned Gray coding ( I'm afraid I forget who ); without that it might not have triggered that solution.
 
Top