PDA

View Full Version : Masking address bits



Demon
- 17th November 2005, 17:30
Hi,

Can someone explain how masking works please?

I've seen Mr. E use it a lot in his code, but he likes using HEX which makes it a 'bit' more foreign to me. :D I'd appreciate an example using binary masking if at all possible, that way I'll be able to have maximum control over data.

The application I have right now is how to control bits within the address byte (A0, A1 and A2). I have 7 MCP23016 I/O expanders and I'd like to poll them in a loop.

Thanks!

Robert
:)

Demon
- 17th November 2005, 17:40
It turns out PIC BASIC calls this isolating bits, not masking. I found instructions for that on p.37 of my manual:

B0 = B0 & %00000001 ' Isolate bit 0 of B0

This brings up another question, is it possible to concatenate bits? Like this:

A0 = (B0 & %00000111) SomeBitCommand (C0 & %11111000)

Robert
:)

Demon
- 17th November 2005, 17:42
D'uh, nevermind, I found the answer to that also.

Just shift the 2nd value over by the proper number of digits and then add both together.

(don't mind me, I'm talking to myself - god I hate finding the answer a few minutes after giving up and posting)

Robert
:)

mister_e
- 17th November 2005, 18:11
Dear Sir De La Demon ;)

Everything is based on logical operation. you can use Decimal, Hex or binary... use the one you're confortable with

Boolean operation, short tutorial and truth table (http://www.learn-c.com/boolean.htm)

Short example:

I have 4 push buttons attach to PORTB<3:0> (<3:0> mean on PORTB.0, PORTB.1, PORTB.2 AND PORTB.3) the other PORTB pins ae used for something else.

I want to read the status of those pushbutton and discard the other pins. In this case you have two choice. Read every single bit OR read the whole PORT and keep only PORTB<3:0>. I prefer the last one.

To keep only the 4 lower bits you can use bitwise AND


PushButton=PORTB & $0F

OR


PushButton=PORTB & 15

OR


PushButton=PORTB & %00001111


OR bitwise OR


PushButton=PORTB | $F0

OR


PushButton=PORTB | 240

OR


PushButton=PORTB | %11110000


Depending of your pushButton 'normal state' you'll read the result as follow. In my case 'normal state=0'


'
' Reading PushButtons on PORTB
' Using AND
'
start:
PushButton=PORTB & $0F ' or PORTB & %00001111
'
' Using select case to handle pushbutton and
' jump to specific Subroutines
'
Select case PushButton
case 1 ' %00000001 or $1
Gosub PORTB_0
case 2 ' %00000010 or $2
Gosub PORTB_1
case 4 ' %00000100 or $4
Gosub PORTB_2
case 8 ' %00001000 or $8
Gosub PORTB_3
end select


You can even use bitwise OR and change the results...


'
' Reading PushButtons on PORTB
' Using AND
'
start:
PushButton=PORTB | $F0 ' or PORTB | %11110000
'
' Using select case to handle pushbutton and
' jump to specific Subroutines
'
Select case PushButton
case 241 ' %11110001 or $F1
Gosub PORTB_0
case 242 ' %11110010 or $F2
Gosub PORTB_1
case 244 ' %11110100 or $F4
Gosub PORTB_2
case 248 ' %11111000 or $F8
Gosub PORTB_3
end select


Now let's say that i want to turn off a led on a specific PORTB pin.


LedOnPORTB var byte

LedOnPORTB=%11001111
PORTB=LedOnPORTB
'
' Let's turn off the LED on PORTB.7
'
LedOnPORTB=LedOnPORTB %01111111
PORTB=LedOnPORTB


that's just an example, read and understand the boolean operator, you'll find them handy... even if you just want to toglle a bit state..


PORTB=%11110001

start:
PORTB.0=PORTB.0 ^ 1
pause 500
goto start

this will blink led on PORTB.0

HTH


EDIT: DOH! just notice you found something... BAH, this could be handy for somebody here.. one day or another... i guess.



The application I have right now is how to control bits within the address byte (A0, A1 and A2). I have 7 MCP23016 I/O expanders and I'd like to poll them in a loop.

You can even use an array to store their specific control byte then use it in a loop


IOExpander var byte[7]
IOExpander[0]=%11110000
IOExpander[1]=%11110001
IOExpander[2]=%11110010
IOExpander[3]=%11110011
IOExpander[4]=%11110100
IOExpander[5]=%11110101
IOExpander[6]=%11110110

For Loop = 0 to 6
I2cWRITE blah,blah2,IoExpander[Loop],[SteakBledindePatate]
pause 5
next

Dave
- 17th November 2005, 20:41
mister_e, I don't think the statement:
I2cWRITE blah,blah2,IoExpander[Loop],[SteakBledindePatate] will work as the variable "IoExpander" is not a constant but rather an array. I have tried using this syntax in the past with no success.

Dave Purola,
N8NTA

mister_e
- 18th November 2005, 08:22
mmm, interesting, never tried it before... Thanks Dave!

Anybody else tried that before and got bad results with this ?

anyways, here's an easy workaround.



IOExpander var byte[7]
WichIOExpander var byte
IOExpander[0]=%11110000
IOExpander[1]=%11110001
IOExpander[2]=%11110010
IOExpander[3]=%11110011
IOExpander[4]=%11110100
IOExpander[5]=%11110101
IOExpander[6]=%11110110

For Loop = 0 to 6
WichIOExpander=IoExpander[Loop]
I2cWRITE blah,blah2,WichIOExpander,[SteakBledindePatate]
pause 5
next

OR


IOExpander=%11110110

For Loop = 0 to 6
I2cWRITE blah,blah2,(IOExpander+Loop),[SteakBledindePatate]
pause 5
next

And if it doesn't work..


WichIOExpander var byte
IOExpander=%11110110

For Loop = 0 to 6
WichIOExpander=IOExpander+Loop
I2cWRITE blah,blah2,WichIOExpander,[SteakBledindePatate]
pause 5
next

Sorry, i can't check any of the above where i am right now.

Dave
- 18th November 2005, 12:51
mister_e, That is the exact work around I tried in the past with no success. It is still using a variable instead of a constant. I do wish any upcomming versions of PBP will fix this problem. I have 6 PCF8574's that I have addressed in succession and thought I would use 1 address and then just offset it in a formula to access the others. The problem is it only accesses the base address. I had to write seprate statements to access the others. I just thought you and others would like to know.. If any other people on this forum have found a workaround I'm all ears....Chears for now....

Dave Purola,
N8NTA

Demon
- 18th November 2005, 17:03
Dave, are you serious? You can't use a variable for that field?

I'm up the creek also then, my project relies heavily on MCP23016 ICs and controlling them within a loop. One easy alternative would be a bunch of IFs:

IF loop = 0 THEN I2cWRITE blah,blah2,Constant0,[SteakBledindePatate]
IF loop = 1 THEN I2cWRITE blah,blah2,Constant1,[SteakBledindePatate]
IF loop = 2 THEN I2cWRITE blah,blah2,Constant2,[SteakBledindePatate]
IF loop = 3 THEN I2cWRITE blah,blah2,Constant3,[SteakBledindePatate]
IF loop = 4 THEN I2cWRITE blah,blah2,Constant4,[SteakBledindePatate]
IF loop = 5 THEN I2cWRITE blah,blah2,Constant5,[SteakBledindePatate]
IF loop = 6 THEN I2cWRITE blah,blah2,Constant6,[SteakBledindePatate]
IF loop = 7 THEN I2cWRITE blah,blah2,Constant7,[SteakBledindePatate]

But I'm not very keen on this idea.

Robert
:(

Dave
- 18th November 2005, 17:28
Demon, This is the code I assumed would work:

UNIT0 CON %01110000 'U5's CONTROL BYTE (PCF8574A) I/O EXPANDER

************************************************** ********
R_WI2CSW:'READ DIGITAL INPUTS FROM or WRITE DIGITAL OUTPUTS TO PCF8574'S
************************************************** ********
SWCNTR = 0
WHILE SWCNTR < 6
CONTROL = UNIT0 | (SWCNTR << 1)
IF READ_WRITE = 0 THEN 'READ INPUT STATUS FROM PCF8574'S
I2CREAD SDA,SCL,CONTROL,[SWITCHES(SWCNTR)]
ELSE 'WRITE OUTPUT STATE TO PCF8574'S
I2CWRITE SDA,SCL,CONTROL,[OUTPUTS(SWCNTR)]
ENDIF
SWCNTR = SWCNTR + 1
WEND
RETURN

But it didn't work as explained in my earlyer post. This is what I had to do instead:

UNIT0 CON %01110000 'U5's CONTROL BYTE (PCF8574A) I/O EXPANDER
UNIT1 CON %01110010 'U6's CONTROL BYTE (PCF8574A) I/O EXPANDER
UNIT2 CON %01110100 'U7's CONTROL BYTE (PCF8574A) I/O EXPANDER
UNIT3 CON %01110110 'U11's CONTROL BYTE (PCF8574A) I/O EXPANDER
UNIT4 CON %01111000 'U12's CONTROL BYTE (PCF8574A) I/O EXPANDER
UNIT5 CON %01111010 'U13's CONTROL BYTE (PCF8574A) I/O EXPANDER


************************************************** ********
R_WI2CS:'READ DIGITAL INPUTS FROM or WRITE DIGITAL OUTPUTS TO PCF8574'S
************************************************** ********
IF READ_WRITE = 0 THEN 'READ INPUT STATUS FROM PCF8574'S
I2CREAD SDA,SCL,UNIT0,[SWITCHES(0)]
I2CREAD SDA,SCL,UNIT1,[SWITCHES(1)]
I2CREAD SDA,SCL,UNIT2,[SWITCHES(2)]
I2CREAD SDA,SCL,UNIT3,[SWITCHES(3)]
I2CREAD SDA,SCL,UNIT4,[SWITCHES(4)]
I2CREAD SDA,SCL,UNIT5,[SWITCHES(5)]
ELSE
I2CWRITE SDA,SCL,UNIT0,[OUTPUTS(0)]
I2CWRITE SDA,SCL,UNIT1,[OUTPUTS(1)]
I2CWRITE SDA,SCL,UNIT2,[OUTPUTS(2)]
I2CWRITE SDA,SCL,UNIT3,[OUTPUTS(3)]
I2CWRITE SDA,SCL,UNIT4,[OUTPUTS(4)]
I2CWRITE SDA,SCL,UNIT5,[OUTPUTS(5)]
ENDIF
RETURN

Now very elegant......

Dave Purola,
N8NTA

mister_e
- 18th November 2005, 20:13
I'll have an eye on this once back in town. Interesting...

Is the same thing happen with Lookup too?



WichIOExpander var byte

For Loop = 0 to 6
Lookup WichIOExpander,[%11110000,%11110001,%11110010,%11110011,_
%11110100,%11110101,%11110110]
I2cWRITE blah,blah2,WichIOExpander,[SteakBledindePatate]
pause 5
next

About now? Just curious

Demon
- 18th November 2005, 22:20
Steve, I'm not set up to test right now.

Dave, are you sure you used a BYTE?

I reread the manual and there is nothing for I2CREAD that says CONTROL byte must be a constant.

Robert
:)

Demon
- 19th November 2005, 03:33
Dave, here's my complete code using a 16F877 and MCP23016:

ADCON1 = 7 ' A/D off, all digital
ASM
@ DEVICE PIC16F877, HS_OSC, WDT_OFF, PWRT_ON, BOD_ON, LVP_OFF, CPD_OFF, WRT_OFF, DEBUG_OFF, PROTECT_OFF
ENDASM
define OSC 20
DEFINE I2C_SLOW 1 ' Access I2C device above 8MHz
DEFINE I2C_HOLD 1 ' Permit I2C device to hold clock line low
I2CSCL VAR PortC.3
I2CSDA VAR PortC.4
I2CCTRL con %01000000
I2CLOCB VAR BYTE
I2CWORD VAR WORD
I2CLOCB = $06 ' Set location to IODIR register
I2CWORD = %0000000000000000
i2cWRITE I2CSDA,I2CSCL,I2CCTRL,I2CLOCB,[I2CWORD]
PAUSE 12
I2CLOCB = $00 ' Set location to GPIO register
I2CWORD = %1111111111111111
i2cWRITE I2CSDA,I2CSCL,I2CCTRL,I2CLOCB,[I2CWORD]
end

It doesn't work, and it is using a constant.

I don't understand why either, I had this circuit working a few weeks ago. I'm sure I have something screwed in the code, but I don't see what it can be.

Robert
:(

Demon
- 19th November 2005, 03:34
Just a bit more on the code above, the 1st I2CWRITE sets the pins as output, the 2nd turns them all ON.