View previous topic :: View next topic |
Author |
Message |
emaxxenon
Joined: 21 Jan 2020 Posts: 42
|
PIC 18F26K40 i2C Variable Address [SOLVED] |
Posted: Mon Feb 10, 2020 7:11 am |
|
|
Hello,
I am communicating with i2c.
I need to use a variable slave address.
I will assign the address according to the key status.
But there are questions i want to ask.
Code: |
#byte SSPADD = 0x0F93
void main()
{
int8 slave_address;
if(input_state(pin_a0)==1)
slave_address = 0x10;
if(input_state(pin_a1)==1)
slave_address = 0x20;
SSPADD = slave_address;
while(1);
}
|
I use this structure.
RB1 = SCL2
RB2 = SDA2
RC3 = SCL1
RC4 = SDA1
I couldn't understand which address to choose according to what.
Which address should I use for SCL1 and SDA1?
0x0F93 - is this address correct?
Last edited by emaxxenon on Tue Feb 11, 2020 1:16 am; edited 2 times in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Mon Feb 10, 2020 8:01 am |
|
|
You don't have to fiddle. Just use the CCS functions.
i2c_address(address_to_use);
So:
Code: |
if(input_state(pin_a0)==1)
I2C_address(0x10);
if(input_state(pin_a1)==1)
I2C_address(0x20);
|
However your approach seems slightly odd, since if A1 is high it'll
override whatever A0 is set to. You might want to think again.... |
|
|
emaxxenon
Joined: 21 Jan 2020 Posts: 42
|
|
Posted: Mon Feb 10, 2020 8:50 am |
|
|
Ttelmah wrote: | You don't have to fiddle. Just use the CCS functions.
i2c_address(address_to_use);
So:
Code: |
if(input_state(pin_a0)==1)
I2C_address(0x10);
if(input_state(pin_a1)==1)
I2C_address(0x20);
|
However your approach seems slightly odd, since if A1 is high it'll
override whatever A0 is set to. You might want to think again.... |
Thanks for your answer.
- Undefined identifier -- I2C_address
Do i need to add anything to the i2c definitions?
Code: | #use i2c (SLAVE, SDA=PIN_C4, SCL=PIN_C3, force_hw, fast=500000) |
My current settings are like this.
How should i make the i2c settings as you said? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Mon Feb 10, 2020 9:11 am |
|
|
Apologies. The command is I2C_slaveaddr.
That'll teach me to post without checking....
Your syntax though is wrong. You are not using the hardware I2C.
You need:
Code: |
#PIN_SELECT SCK1=PIN_C3
#PIN_SELECT SDA1=PIN_C4
#use i2c (SLAVE, I2C1, address=0x20)
void main()
{
if(input_state(pin_a0)==1)
I2C_slaveaddr(0x10);
if(input_state(pin_a1)==1)
I2C_slaveaddr(0x20);
|
The #use should always have an address. Make it the 'default', and then
change it to the new values you want.
If you don't specify an address you can get odd behaviour depending on
what is being sent on the bus. Safer to set it.
On chips using PPS, you have to select the port with PPS. #USE will
not reliably setup PPS for you (current compilers are partially doing it
but seem to get it wrong as often as right - again safer to use PPS
yourself). |
|
|
gjs_rsdi
Joined: 06 Feb 2006 Posts: 468 Location: Bali
|
|
Posted: Mon Feb 10, 2020 9:46 pm |
|
|
Why not:
Code: |
if(input_state(pin_a0)==1)
{
I2C_slaveaddr(0x10);
}
else
{
I2C_slaveaddr(0x20);
} |
Best wishes
Joe |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Feb 11, 2020 12:35 am |
|
|
Exactly.
Makes a lot more sense than what was being done. |
|
|
emaxxenon
Joined: 21 Jan 2020 Posts: 42
|
|
Posted: Tue Feb 11, 2020 12:59 am |
|
|
Thank you. Much better than before. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Feb 11, 2020 4:34 am |
|
|
In fact, assuming these inputs are just a jumper for example, then set the
default address in the #use, and just have it select the alternative is the
jumper is made. One jumper, and two addresses. Easy. |
|
|
emaxxenon
Joined: 21 Jan 2020 Posts: 42
|
|
Posted: Tue Feb 11, 2020 6:34 am |
|
|
There will be 8 slaves. All circuits are the same.
But they will be arranged in a certain order.
According to this order, their addresses will change.
I had to assign an address based on the switch location.
It worked the way you suggested.
Code: |
if(input_state(pin_a0)==1)
{
A=1;
}
if(input_state(pin_a1)==1)
{
B=2;
}
if(input_state(pin_a2)==1)
{
C=4;
}
SWITCH = A+B+C;
if(SWITCH==0)
{
I2C_slaveaddr(0x10);
}
if(SWITCH==1)
{
I2C_slaveaddr(0x12);
}
if(SWITCH==2)
{
I2C_slaveaddr(0x14);
}
if(SWITCH==3)
{
I2C_slaveaddr(0x16);
}
if(SWITCH==4)
{
I2C_slaveaddr(0x18);
}
if(SWITCH==5)
{
I2C_slaveaddr(0x20);
}
if(SWITCH==6)
{
I2C_slaveaddr(0x22);
}
if(SWITCH==7)
{
I2C_slaveaddr(0x24);
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Feb 11, 2020 8:04 am |
|
|
Too complex:
Code: |
A=0x20;
if(input_state(pin_a0)==1)
{
A+=2;
}
if(input_state(pin_a1)==1)
{
A+=4;
}
if(input_state(pin_a2)==1)
{
A+=8;
}
I2C_slaveaddr(A);
|
You get 0x20 if the inputs are 000. Then 0x22 if they are 001. 0x24 if
they are 010 etc. Right up to 0x2E if they are 111.
8 addresses, just one variable instead of three, and no switch statement. |
|
|
emaxxenon
Joined: 21 Jan 2020 Posts: 42
|
|
Posted: Wed Feb 12, 2020 1:32 am |
|
|
Ttelmah wrote: | Too complex:
Code: |
A=0x20;
if(input_state(pin_a0)==1)
{
A+=2;
}
if(input_state(pin_a1)==1)
{
A+=4;
}
if(input_state(pin_a2)==1)
{
A+=8;
}
I2C_slaveaddr(A);
|
You get 0x20 if the inputs are 000. Then 0x22 if they are 001. 0x24 if
they are 010 etc. Right up to 0x2E if they are 111.
8 addresses, just one variable instead of three, and no switch statement. |
Thanks for your answer.
A0 - A1 - A2
(0) - (0) - (0)
==> A=0x20;
A0 - A1 - A2
(0) - (0) - (1)
==> A=0x22;
A0 - A1 - A2
(0) - (1) - (0)
==> A=0x24;
A0 - A1 - A2
(0) - (1) - (1)
==> A=0x26;
A0 - A1 - A2
(1) - (0) - (0)
==> A=0x28;
A0 - A1 - A2
(1) - (0) - (1)
==> A=0x2A;
A0 - A1 - A2
(1) - (1) - (0)
==> A=0x2C;
A0 - A1 - A2
(1) - (1) - (1)
==> A=0x2E;
Will this be the case according to the code?
Code: |
if(input_state(pin_a0)==1)
{
A+=2;
}
|
I don't understand how this part works? (A+=2;) |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Wed Feb 12, 2020 2:39 am |
|
|
In C, there is a standard shortcut.
Variable mathsoperator = val;
If you have a variable 'A', then
A*=2;
multiplies A by 2 and stores the result back in A.
So
A+=2;
Adds 2 to A.
It's equivalent to A=A+2, but the compiler can optimise it a little better.
Use it whenever you want to do any maths operation on a variable and
put the result back into the same variable.
A/=4;
etc.. etc.. |
|
|
emaxxenon
Joined: 21 Jan 2020 Posts: 42
|
|
Posted: Wed Feb 12, 2020 5:49 am |
|
|
I have a lot to learn.
Thanks for information. My code has gotten much better. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Wed Feb 12, 2020 7:20 am |
|
|
Another possible way to do it as the address switches are on one port,in sequence..
Read the port, combine with a mask( lower 3 bits), the result should be the device address offset,so add it to the base address.
While I haven't tried it , it may produce shorter code, be quicker and be easier to understand.
Also, get into the habit of adding comments //at the end of a line of code
Comments cost nothing except the time to type them but hours or days from now you'll SEE what that line of code was supposed to do.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Wed Feb 12, 2020 7:52 am |
|
|
Potentially.
However it does mean having to do a byte wide read on B, which may
cause issues, and you have to multiply the result by two, since the I2C
address go up in twos.
I think given how small the test and additions are, the read, multiply and
add offset approach will probably be as large or larger, and given that
you probably don't want to do a whole port read, the existing approach
is probably the best way to go. |
|
|
|