That was my initial reaction too.
But I've since found that it is EXTREMELY inexpensive, if you consider the value vs. cost.
You can't even buy a decent Digital O-Scope for that much.
But Proteus gives you Multiple 4ch-DSO's, 32ch-logic analyzers, voltmeters, ammeters, virtual terminals, signal generators, pattern generators, power supplies, I2C debuggers, SPI debuggers, frequency counters ...
There's a whole boat load of PIC's to choose from, plus all the other chips and discrete parts.
You can simulate multiple PIC's in the same circuit simultaneously.
And with PBP 2.60a, it integrates right into the MPLAB IDE for step by step debugging.
$479 gives you all that and either the 16F's or 18F's.
Can't get much cheaper than that.
I should be getting a commission, I sound like a commercial.
P.S. You can download the Demo Version and run your PBP programs on the sample circuits. You just can't modify the circuit.
Take a test drive.
<br>
<br>
Last edited by Darrel Taylor; - 17th August 2010 at 20:57. Reason: .
DT
Would it be possible to easily change one of these example routines to use the MSSP module for I2C Master?
In my program I change the clock speed from 12MHz to 250kHz, and it takes about 50ms to execute an I2CWRITE command at the slower speed. I measured the I2C clock to be about 800µs which is 1,2kHz... that's not much. I'm guessing that the PBP command includes it's own set of hardcoded delay... I'd like to save power, and if running I2C at 100kHz, I could get the PIC back to sleep 100 time faster.
I'm understanding quite well changes to make in registers to configure the hardware part, but I must say that when it get to assembler I don't understand too much of it right now...
Hi, I'm interested to try the master-slave(I2C) worked by Daniel and other members, sorry if it is not obvious for me in the code given, but can someone share the schematic used in the example?
I'm using Pic16877(master) and Pic16F88(salve).
Thanks,
tacbanon
Last edited by tacbanon; - 24th April 2012 at 09:37.
From the code provided, here is how I interpret the pin connection between pics.
Master(Pic16F877A) Slave(Pic16F88)
(SCL)RB5 <---> RB4
(SDA)RB7 <---> RB1
but with this connection, LCD displays "Time out", can anyone help me what I'm missing?
Did you pullup SCL and SDA with a 3.3K resistor?
Cheers
Al.
All progress began with an idea
Hi aratti,
Thanks for replying, I added the resistors but I have the same output("Time out" on the lcd). Any idea what causing the issue?
Thanks in advance,
tacbanon
Attachment 6422
Last edited by tacbanon; - 25th April 2012 at 07:13.
You should post the schematic of your setup along with the code you are using. Without more info it is difficult to give you proper answers.
Al.
All progress began with an idea
Hi again,
Here is the code I'm using..
Master pic using Pic16F877A
Here is the code for the Slave Pic16F88Code:'------------------------------------------------------------------------------- ' Master '------------------------------------------------------------------------------- '------------------------------------------------------------------------------- DEFINE OSC 4 'OPTION_REG.7 = 0 ADCON1 = 7 '------------------------------------------------------------------------------ DEFINE I2C_SLOW 1 TRISB.5 = 1 TRISB.7 = 1 '------------------------------------------------------------------------------ scl VAR PORTB.5 ' i2c clock input sda VAR PORTB.7 ' i2c data input '------------------------------------------------------------------------------ I2Caddress VAR BYTE valor VAR BYTE '------------------------------------------------------------------------------ ' Set LCD Data port DEFINE LCD_DREG PORTD ' Set starting Data BIT (0 OR 4) IF 4-BIT bus DEFINE LCD_DBIT 4 ' Set LCD Register Select port DEFINE LCD_RSREG PORTC ' Set LCD Register Select BIT DEFINE LCD_RSBIT 6 ' Set LCD Enable port DEFINE LCD_EREG PORTC ' Set LCD Enable BIT DEFINE LCD_EBIT 7 ' Set LCD bus size (4 OR 8 bits) DEFINE LCD_BITS 4 ' Set number of lines ON LCD DEFINE LCD_LINES 2 ' Set command delay time in us DEFINE LCD_COMMANDUS 2000 ' Set Data delay time in us DEFINE LCD_DATAUS 50 '------------------------------------------------------------------------------ Pause 500 ' Wait for LCD to startup LCDOut $fe, 1 LCDOut $fe, "Daniel" Pause 500 ' Wait for LCD to startup valor = 0 '------------------------------------------------------------------------------ main: I2Caddress = $3 LCDOut $fe, 1 LCDOut "Write 1 - LED ON" Pause 500 I2CWrite SDA, SCL, I2Caddress, [6], bogus ' Write offset to slave Pause 500 LCDOut $fe, 1 LCDOut "Write 1 - LED OFF" Pause 500 I2CWrite SDA, SCL, I2Caddress, [8], bogus ' Write to slave Pause 500 LCDOut $fe, 1 LCDOut "Reading 1..." Pause 500 I2CRead SDA, SCL, I2Caddress, [valor], bogus ' Read from slave LCDOut $fe, 1 LCDOut "Value1: ", DEC valor Pause 500 '-------- I2Caddress = $5 LCDOut $fe, 1 LCDOut "Write 2 - LED ON" Pause 500 I2CWrite SDA, SCL, I2Caddress, [4], bogus ' Write to slave Pause 500 LCDOut $fe, 1 LCDOut "Write 2 - LED OFF" Pause 500 I2CWrite SDA, SCL, I2Caddress, [10], bogus ' Write to slave Pause 500 LCDOut $fe, 1 LCDOut "Reading 2..." Pause 500 I2CRead SDA, SCL, I2Caddress, [valor], bogus ' Read from slave LCDOut $fe, 1 LCDOut "Value2: ", DEC valor Pause 500 '-------- GoTo main ' Do it forever '------------------------------------------------------------------------------- bogus: LCDOut $fe,1, "Time out" ' I2C command timed out Pause 500 GoTo main '------------------------------------------------------------------------------- End
The codes I'm using is from Daniel(copy and paste).Code:DEFINE OSC 8 OSCCON = 110001 '8mhz '------------------------------------------------------------------------------ CMCON = 7 ADCON1 = 0 ' Disable A/D converter ADCON0 = 0 ANSEL = 0 ' all analog pins to digital '--- tris port config here (don't use SCL & SDA pins other than I2C) ---------- DEFINE I2C_HOLD 1 TRISB.1 = 1 TRISB.4 = 1 '--- Alias pins --------------------------------------------------------------- SDADIR VAR TRISB.1 SCLDIR VAR TRISB.4 '--- Define here your variables and alias ------------------------------------- LEDT VAR PORTA.2 LEDL VAR PORTB.7 LEDM VAR PORTB.6 LEDR VAR PORTB.5 readcnt VAR BYTE datain VAR BYTE WrData VAR BYTE '--- Define used register flags ------------------------------------------------ SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag SSPIE VAR PIE1.3 BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full R_W VAR SSPSTAT.2 ' SSP (I2C) Read/Write D_A VAR SSPSTAT.5 ' SSP (I2C) Data/Address CKP VAR SSPCON.4 ' SSP (I2C) SCK Release Control SSPEN VAR SSPCON.5 ' SSP (I2C) Enable SSPOV VAR SSPCON.6 ' SSP (I2C) Receive Overflow Indicator WCOL VAR SSPCON.7 ' SSP (I2C) Write Collision Detect STAT_BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full STAT_RW VAR SSPSTAT.2 ' SSP (I2C) Read/Write STAT_DA VAR SSPSTAT.5 ' SSP (I2C) Data/Address CKE VAR SSPSTAT.6 ' SSP (I2C) Data/Address '--- Rx Buffer defintion ------------------------------------------------------ RxBufferLEN CON 1 RxBuffer VAR BYTE[Rxbufferlen] RxBufferIndex VAR BYTE '--- Tx Buffer defintion ------------------------------------------------------ TxBufferLEN CON 1 TxBuffer VAR BYTE[txbufferlen] TxBufferIndex VAR BYTE '--- Define constants --------------------------------------------------------- I2Caddress CON $3 ' Make address = 3 '--- Initialize I2C slave mode ------------------------------------------------ SCLDIR = 1 ' SCL must be an input before enabling interrupts SDADIR = 1 SSPADD = I2Caddress ' Set our address SSPCON = $36 ' Set to I2C slave with 7-bit address SSPSTAT = 0 SSPIE = 1 SSPIF = 0 RxBufferIndex = 0 TxBufferIndex = 0 '--- Initialization Done! ----------------------------------------------------- GoTo main '--- I2C subroutine ---------------------------------------------------------- i2cslave: ' I2C slave subroutine SSPIF = 0 ' Clear interrupt flag IF R_W = 1 Then i2crd ' Read data from us IF BF = 0 Then i2cexit ' Nothing in buffer so exit IF D_A = 1 Then i2cwr ' Data for us (not address) IF SSPBUF != I2Caddress Then i2cexit ' Clear the address from the buffer readcnt = 0 ' Mark as first read GoTo i2cexit i2cwr: ' I2C write data to us datain = SSPBUF ' Put buffer data into array Rxbuffer[Rxbufferindex]=datain Rxbufferindex=rxbufferindex+1 IF rxbufferindex=RxBufferLEN Then ' end of buffer transfer WrData=1 rxbufferindex=0 EndIF GoTo i2cexit i2crd: ' I2C read data from us IF D_A = 0 Then TxBufferIndex = 0 EndIF While STAT_BF : Wend ' loop while buffer is full wcol = 0 ' clear collision flag SSPBUF = TxBuffer[TxBufferIndex] While wcol wcol = 0 SSPBUF = TxBuffer[TxBufferIndex] Wend CKP = 1 ' release clock, allowing read by master TxBufferIndex = TxBufferIndex + 1 ' increment index IF TxBufferIndex = TxBufferlen Then ' all bytes have been tx TxBufferIndex = 0 ' reset index EndIF i2cexit: Return '--- End I2C subroutine ------------------------------------------------------ Main: pause 100 txbuffer = 12 IF SSPIF = 1 Then GoSub i2cslave EndIF SSPOV = 0 WCOL = 0 Select Case RxBuffer[0] Case 6 High LEDT Case 8 Low LEDT End Select WrData=0 GoTo Main '------------------------------------------------------------------------------ End
BTW I'm using a simulator...
regards,
tacbanon
Last edited by tacbanon; - 25th April 2012 at 10:07.
Very likely is a simulator problem!
Al.
All progress began with an idea
Okay, I will try it in the real hardware(need first to buy Pic16F88), and post here the result. Can anybody in the forum who has Proteus to try to test if similar output I'm having?
Thanks,
tacbanon
Last edited by tacbanon; - 25th April 2012 at 16:27.
Hello,
While waiting for my Pic16F88(probable by next week) I tried to play with this code below with success in the simulation...
master(Pic18F2620)
Slave(Pic18F2620)Code:DEFINE OSC 40 DEFINE I2C_HOLD 1 DEFINE LCD_DREG PORTB DEFINE LCD_DBIT 0 DEFINE LCD_RSREG PORTB DEFINE LCD_RSBIT 4 DEFINE LCD_EREG PORTB DEFINE LCD_EBIT 5 DEFINE LCD_BITS 4 DEFINE LCD_LINES 2 DEFINE LCD_COMMANDUS 2000 DEFINE LCD_DATAUS 50 PAUSE 100 LCDOUT $FE,1,$FE,2 ADCON1=001111 CMCON=000111 scl VAR PORTC.3 sda VAR PORTC.4 i2c_address VAR BYTE i2c_data VAR BYTE[6] main: i2c_address=$02 I2CREAD sda,scl,i2c_address,[STR i2c_data\6] LCDOUT $FE,$80,DEC i2c_data[0] LCDOUT " ", DEC i2c_data[1] LCDOUT " ", DEC i2c_data[2] LCDOUT " ", DEC i2c_data[3] LCDOUT " ", DEC i2c_data[4] LCDOUT " ", DEC i2c_data[5] GOTO main
As I understood, in the master pic the code below tries to communicate to the Slave having the address $02Code:DEFINE OSC 40 INCLUDE "DT_INTS-18.bas" INCLUDE "ReEnterPBP-18.bas" ADCON1=001111 CMCON=000111 i2c_buffer_full VAR SSPSTAT.0 i2c_read VAR SSPSTAT.2 i2c_release_scl VAR SSPCON1.4 i2c_data VAR BYTE[6] i2c_data_index VAR BYTE dummy VAR BYTE ;---------------------------------- i var byte i=1 SSPADD=$02 ' I2C Address: $0A SSPCON1=$36 SSPCON2.0=1 i2c_data[0]=6 i2c_data[1]=5 i2c_data[2]=4 i2c_data[3]=3 i2c_data[4]=2 i2c_data[5]=1 i2c_data_index=0 ASM INT_LIST macro INT_Handler SSP_INT, _i2c_int_handler, PBP, yes endm INT_CREATE INT_ENABLE SSP_INT endasm main: goto main i2c_int_handler: IF i2c_read then dummy=SSPBUF IF i2c_buffer_full=0 THEN SSPBUF=i2c_data[i2c_data_index] i2c_data_index=i2c_data_index+1 IF i2c_data_index=6 THEN i2c_data_index=0 ENDIF ENDIF i2c_release_scl=1 @ INT_RETURN
and display data from Slave to the Master pic LCD. Then I tried to modify the setup and add another Slave#2 with address $0B like the this code below..Code:i2c_address=$02 I2CREAD sda,scl,i2c_address,[STR i2c_data\6] LCDOUT $FE,$80,DEC i2c_data[0] LCDOUT " ", DEC i2c_data[1] LCDOUT " ", DEC i2c_data[2] LCDOUT " ", DEC i2c_data[3] LCDOUT " ", DEC i2c_data[4] LCDOUT " ", DEC i2c_data[5]
What I get is "6 5 4 3 2 1" and "0 0 0 0 0 0 " should be "1 2 3 4 5 6" for Slave#2Code:main: i2c_address=$02 I2CREAD sda,scl,i2c_address,[STR i2c_data\6] LCDOUT $FE,$80,DEC i2c_data[0] LCDOUT " ", DEC i2c_data[1] LCDOUT " ", DEC i2c_data[2] LCDOUT " ", DEC i2c_data[3] LCDOUT " ", DEC i2c_data[4] LCDOUT " ", DEC i2c_data[5] PAUSE 1000 LCDOUT 254,1 pause 500 i2c_address=$0B I2CREAD sda,scl,i2c_address,[STR i2c_data\6] LCDOUT $FE,$80,DEC i2c_data[0] LCDOUT " ", DEC i2c_data[1] LCDOUT " ", DEC i2c_data[2] LCDOUT " ", DEC i2c_data[3] LCDOUT " ", DEC i2c_data[4] LCDOUT " ", DEC i2c_data[5] PAUSE 1000 GOTO main
Slave#2
I was only hoping that it would work that way(I guess not ), how can I add another Slave and get data from it? I appreciate any help and the time for sharing.Code:DEFINE OSC 40 INCLUDE "DT_INTS-18.bas" INCLUDE "ReEnterPBP-18.bas" ADCON1=001111 CMCON=000111 i2c_buffer_full VAR SSPSTAT.0 i2c_read VAR SSPSTAT.2 i2c_release_scl VAR SSPCON1.4 i2c_data VAR BYTE[6] i2c_data_index VAR BYTE dummy VAR BYTE ;---------------------------------- i var byte i=1 SSPADD=$0B ' I2C Address: $0B SSPCON1=$36 SSPCON2.0=1 i2c_data[0]=1 i2c_data[1]=2 i2c_data[2]=3 i2c_data[3]=4 i2c_data[4]=5 i2c_data[5]=6 i2c_data_index=0 ASM INT_LIST macro INT_Handler SSP_INT, _i2c_int_handler, PBP, yes endm INT_CREATE INT_ENABLE SSP_INT endasm main: goto main i2c_int_handler: IF i2c_read then dummy=SSPBUF IF i2c_buffer_full=0 THEN SSPBUF=i2c_data[i2c_data_index] i2c_data_index=i2c_data_index+1 IF i2c_data_index=6 THEN i2c_data_index=0 ENDIF ENDIF i2c_release_scl=1 @ INT_RETURN
Thanks in advance,
tacbanon
Last edited by tacbanon; - 26th April 2012 at 12:56.
In your previous code with the F88, 3 is not a valid I2C address.
In the current code, $B is not a valid I2C address.
They should be a multiple of 2.
Bit 0 is reserved for the R/W bit.
DT
Hi Darrel,
Thanks for replying, I did some testing on 1Master and 1Slave with these address($02,$04,$06,$08,$10,$12,$14) and works fine. But when I trying to add Slave #2 I get "0 0 0 0 0 0". It only reads on the Slave #1 correct (displays "1 2 3 4 5 6").
This is how I code to read the 2nd Slave.
BTW the code for Slave1 and Slave2 are identical (Slave#1 is address $10 and Slave#2 is address $14)Code:DEFINE OSC 40 DEFINE I2C_HOLD 1 DEFINE LCD_DREG PORTB DEFINE LCD_DBIT 0 DEFINE LCD_RSREG PORTB DEFINE LCD_RSBIT 4 DEFINE LCD_EREG PORTB DEFINE LCD_EBIT 5 DEFINE LCD_BITS 4 DEFINE LCD_LINES 2 DEFINE LCD_COMMANDUS 2000 DEFINE LCD_DATAUS 50 PAUSE 100 LCDOUT $FE,1,$FE,2 ADCON1=001111 CMCON=000111 scl VAR PORTC.3 sda VAR PORTC.4 i2c_address VAR BYTE i2c_address2 VAR BYTE i2c_data VAR BYTE[6] i2c_data2 VAR BYTE[6] main: i2c_address=$10 pause 200 I2CREAD sda,scl,i2c_address,[STR i2c_data\6] LCDOUT $FE,$80,"1> ",DEC i2c_data[0] LCDOUT " ", DEC i2c_data[1] LCDOUT " ", DEC i2c_data[2] LCDOUT " ", DEC i2c_data[3] LCDOUT " ", DEC i2c_data[4] LCDOUT " ", DEC i2c_data[5] PAUSE 500 LCDOUT $FE,1 '********************************************* i2c_address2=$14 pause 200 I2CREAD sda,scl,i2c_address2,[STR i2c_data2\6] LCDOUT $FE,$80,"2> ",DEC i2c_data2[0] LCDOUT " ", DEC i2c_data2[1] LCDOUT " ", DEC i2c_data2[2] LCDOUT " ", DEC i2c_data2[3] LCDOUT " ", DEC i2c_data2[4] LCDOUT " ", DEC i2c_data2[5] PAUSE 500 LCDOUT $FE,1 GOTO main
What I'm doing wrong in the code? I appreciate very much your help.
Thanks,
Tacbanon
Last edited by tacbanon; - 27th April 2012 at 11:53.
If you comment out the first I2CREAD, is it able to read from the second slave?
If you change the order so that it reads the second slave first, is it then unable to read the first slave?
DT
Yes it is able to read.If you comment out the first I2CREAD, is it able to read from the second slave?
Nope, displays "0 0 0 0 0 0" for first Slave, 2nd Slave shows "6 5 4 3 2 1"If you change the order so that it reads the second slave first, is it then unable to read the first slave?
Last edited by tacbanon; - 27th April 2012 at 16:57.
It sounds like a buffer overflow.
... bad comment deleted ... duh!!
If you post or email your .DSN, I'll take a closer look.
Last edited by Darrel Taylor; - 28th April 2012 at 02:20.
DT
Thanks Darrel, oh sorry to ask this, but how do I send a winrar file?
Steve
It's not a bug, it's a random feature.
There's no problem, only learning opportunities.
Thanks mister_e
Or you can stuff it in a ZIP file and post it here. The forum accepts ZIPs as attachments.
Some RAR programs can also save as ZIP format.
Robert
Thanks for the info Robert...
and here is the zip file.
Regards,
tacbanon
Last edited by tacbanon; - 28th April 2012 at 05:03.
Oops here are the codes I'm using for the master, Slave1 and Slave 2.
Thanks for the files tacbanon.
Well, this code for the slaves will allow it to read from both devices.
But it's still not right. And is not a complete slave.Code:main: IF SSPCON1.6 THEN SSPCON1.6 = 0 goto main i2c_int_handler: IF i2c_read then IF i2c_buffer_full=0 THEN SSPBUF=i2c_data[i2c_data_index] i2c_data_index=i2c_data_index+1 ELSE dummy = SSPBUF ENDIF ELSE i2c_data_index=0 ENDIF i2c_release_scl=1 @ INT_RETURN
According to AN734 there are 5 states to maintain. 6 including the ERROR state.
Your original code only handles 1 state, and this modification only does 2 states.
I think by adding the other 4 states, it will get rid of the buffer overflows, but I'm not absolutely sure.
I'm going to convert AN734 state machine to PBP and see what happens.
May take me awhile.
Last edited by Darrel Taylor; - 28th April 2012 at 17:17.
DT
Thank you for the code, and thanks in advance DT for your valuable time...looking forward for the end result(I wish and pray that things goes well). I've been reading about I2C on net, trying to understand and the applications that might be done(particularly on Master-(multi-Slave/Multi-master)) are very interesting...
Regards,
tacbanon
Last edited by tacbanon; - 29th April 2012 at 02:26.
Although my slave example may not be as robust as AN734, I have systems running that have 14 slaves running. All 14 slaves are polled on 2 second intervals. The master uses bit-banging (I2CWrite). I have never had trouble with the code below. I have tested it with -
18F8723, 18F2221, 18F2321, 18F2523 and had excellent results.
Code:'**************************************************************** '* Name : I2C slave * '* Author : Charles Linquist * '* Notice : Copyright (c) 2010 [select VIEW...EDITOR OPTIONS] * '* : All Rights Reserved * '* Date : 10/20/2010 * '* Version : 1.0 * '* Notes : Transmits 100 bytes in ~14 ms (Master SEND) * '* : Recives 100 bytes in ~12 ms (Master RECEIVE) * '* : Could possibly go faster. Master used for the * '* : test used bit-banging (I2CREAD/I2CWRITE * '* : settings on that end were * '* : DEFINE I2C_SLOW 1 ,DEFINE I2C_HOLD 1 * '**************************************************************** ASM ifndef __18F2221 error "18F2221 not selected" endif ENDASM ASM movlw 0x62 ; %0110 0010 = 4 Mhz, internal osc block movwf OSCCON movlw 0x80 ; %1000 0000 = PLL disabled movwf OSCTUNE ENDASM DATA @0,0 ; programming flag DEFINE OSC 4 DEFINE NO_CLRWDT 1 ' Don't waste cycles clearing WDT Define USE_LFSR 1 define USE_LOWPRIORITY 1 ;---------------- Alias the bits ------------------------------------ SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag SSPIE VAR PIE1.3 ' Int Enable SSPUA VAR SSPSTAT.1 SSPS VAR SSPSTAT.3 SSPP VAR SSPSTAT.4 SSPSMP VAR SSPSTAT.7 BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full R_W VAR SSPSTAT.2 ' SSP (I2C) Read/Write D_A VAR SSPSTAT.5 ' SSP (I2C) Data/Address CKP VAR SSPCON1.4 ' SSP (I2C) SCK Release Control SSPEN VAR SSPCON1.5 ' SSP (I2C) Enable SSPOV VAR SSPCON1.6 ' SSP (I2C) Receive Overflow Indicator WCOL VAR SSPCON1.7 ' SSP (I2C) Write Collision Detect GENCALL VAR SSPCON2.7 ' General Call enabled MainTimer var word bankA System I2CTimer var word bankA System I2CTimerGate var byte bankA System I2CErr var byte bankA System ;------------------------------------------------------------------------- ;Alias pins SCL VAR PORTC.3 ' I2C clock input SDA VAR PORTC.4 ' I2C data input LED VAR PORTB.5 '------------------- Rx Buffer defintion -------------------- RxBufferLEN con 10 RxBuffer var BYTE[Rxbufferlen + 1] TxBufferLEN CON 10 TXBuffer VAR BYTE[TxBufferLEN + 2] InBuff VAR BYTE GeneralCall VAR BIT RXBufferOverFlow VAR BIT TxBufferUnderFlow VAR BIT RXBufferPointer VAR Byte TXBufferPointer VAR Byte address VAR BYTE x VAR BYTE dummy var byte I2CAddress VAR BYTE WCOLCounter VAR BYTE ;------------------------------------------------------------- TXBuffer[TxBufferLen + 1] = $FF ; Char to send if requestor asks for too much. I2CDeviceAddress VAR BYTE I2CMajorAddress CON $3 I2CDeviceAddress = $8 I2CAddress = (I2CMajorAddress <<4) | I2CDeviceAddress ;--------------------------------------------------------------- SSPADD = I2Caddress ' Set our address SSPCON2.0 = 1 ; Stretch the clock SSPSTAT = 0 SSPEN = 1 SSPIE = 1 SSPIF = 0 GenCall = 1 ; Turn general call on SSPCON2.7 = 1 ' General call address ENABLED SSPCON1 = $36 ' Set to I2C slave with 7-bit address ;--------------------------------------------------------------- TRISA = %11111111 TRISB = %11011111 TRISC = %11111111 ' -------------- Turn on Ints ------------------------ INTCON.7 = 1 ; global ints INTCON.6 = 1 ; peripheral ints ;------------------ Clear parameters -------------- RXBufferPointer = 0 TxBufferPointer = 0 GeneralCall = 0 RxBufferOverFlow = 0 TXBufferUnderFlow = 0 WCOLCounter = 0 ;--------------------------------------------------------------------- INCLUDE "DT_INTS-18.bas" ' Base Interrupt System INCLUDE "ReEnterPBP-18.bas" ' Use PBP interrupts include "ReEnterPBP-18LP.bas" ASM INT_LIST macro ; IntSource, Label, Type, ResetFlag? INT_Handler TMR0_INT, TimerInt, ASM, yes endm INT_CREATE ; Creates the interrupt processor INT_LIST_L macro ; IntSource, Label, Type, ResetFlag? INT_Handler SSP_INT, _I2C_Int, PBP, yes endm INT_CREATE_L ; Creates the LP interrupt processor endasm ''----------------- Initialization Done! ----------------------------- Goto OverInt ; jump over ISR asm TimerInt infsnz MainTimer incf MainTimer + 1 btfsc I2CTimerGate,0 ; Don't count if low bit is clr incf I2CTimer btfss I2CTimer,2 ; Bit 2 is set , we have at least 4 counts, we must be hung bra NoProb bcf PIR1,3 ; Clear Int flag bcf SSPCON1,5 ; Stop the bsf SSPCON1,5 bsf I2CErr,0 clrf I2CTimer NoProb bcf INTCON,2 INT_RETURN endasm '------------------------- I2C subroutine -------------------------------- I2C_Int: ; We don't get here uless someone has matched our address register. @ bsf I2CTimerGate,0 ; start the counter If R_W = 0 then 'This is a WRITE by the master to us IF BF = 0 Then goto i2CEXIT ; Nothing for us! if D_A = 0 then 'We have an address address = SSPBUF 'Need to READ to satisfy Microchip IF Address = 0 THEN GeneralCall = 1 ELSE GeneralCall = 0 ENDIF else IF WCOL OR SSPOV THEN I2CExit RXBuffer [RxBufferPointer] = SSPBuf ; RxBufferPointer = RXBufferPointer + 1 IF RXBufferPointer > RxBufferLen THEN RXBufferOverFlow = 1 RXBufferPointer = 0 ENDIF ENDIF else ' R_W = 1 Master wants to read FROM us IF !D_A Then TxBufferPointer = 0 ' Mark as first read RXBufferPointer = 0 EndIF IF CKP THEN I2CExit dummy = SSPBUF ;NECESSARY! If TXBufferPointer < TxbufferLen THEN SENDI2C: WCOL = 0 SSPBUF = TXBuffer[TXBufferPointer] ' Get data from array IF WCOL THEN WCOLCounter = WCOLCounter + 1 ; Don't hang the bus with infinite WRITES! IF WColCounter = 0 Then goto I2CExit ; Rolled over Goto SendI2C ; Rety ELSE WColCounter = 0 ENDIF TXBufferPointer = TXBufferPointer +1 TXBufferPointer = TXBufferPointer MIN TXBufferLen + 1 ; Don't let it get larger than this ; Send FFs if requestor asks for too much data ELSE TXBufferPointer = 0 TXBufferUnderflow = 1 ENDIF ENDIF I2CEXIT: Asm bcf SSPCON1,6 bcf SSPSTAT,0 bcf PIR1,3 bsf SSPCON1,4 bcf I2CTimerGate,0 ; stop the counter INT_ENABLE SSP_INT ; probably don't need this, but want to make certain it gets reenabled INT_RETURN endasm ' -------------------------end I2C subroutine -------------------------------- '--------------------[ main program loop]--------------------------------------- OverInt: Asm clrf MainTimer clrf I2CTimer bcf INTCON,2 bcf PIR1,3 ; Clear the I2C flag before we turn on the INT. movlw 0x83 movf T0CON INT_ENABLE SSP_INT INT_ENABLE TMR0_INT endasm MAIN PROGRAM LOOP GOES HERE!
Charles Linquist
Hi Charles, thanks for sharing..I will try it out..
tacbanon
@Charles
Sorry I was not able to make it work on my setup..I'm not really sure what the following code is doing, so I tried to comment it and assign a value, but no effect.
I hope it will be alright if you share the master side code?Code:I2CMajorAddress CON $3 I2CDeviceAddress = $8 'I2CAddress = (I2CMajorAddress <<4) | I2CDeviceAddress I2CAddress =$14
Thanks,
tacbanon
At this point, I'm thinking Al (aratti) was right.
AN734 didn't work either.
Bytes are being put in the SSPBUF without an address match.
So the slaves that aren't being accessed are overflowing during reads from other devices.
The code I gave earlier works because it's resetting the overflow in the main loop, but that's just not right.
I'm trying to get some more info from Labcenter.
DT
I am using a slight variant of the code I posted, and it is working fine. The only major change is that I'm sending a packet length byte, and I'm handling the entire receive packet inside the ISR. This is safe because I have my ( higher priority) timer interrupt watching over the whole process.
Charles Linquist
Hi,
Just want to ask if anyone tried to extend say 50meters communication between master and slave using I2C bus extender P82B715PN or similar?
Regards,
tacbanon
tacbannon,
The problem with Proteus and multiple I2C slaves has been fixed by Labcenter.
If you update Proteus to 7.10 SP1, you should have better luck.
DT
@ DT, Thanks for the update..I will find time to play with it(I2C multiple slaves) this weekend(so many work, little time to play )
Kind regards,
tacbanon
Hi all,
for info to all: I have the code from Aretti here on a 18F25K22, works fine with one slave on one master. When i connect more slaves (up to 31) i get the effect that a NACK comes right behind the address, the SDA line is high during the 9th clock cycle... my bus is about 70cm long (long backplane) and i use a 3.3k on the i2c bus. It seems that this "NACK" effect is coming sporadic, does someone tried to do the same like me?
Regards,
Ralf
Hi again,
found the bug: the bus i am using is splitted in two 2 x 25cm long busses which is not the best solution. Sometimes because of layout reasons it must be done this way. In this case two 100 Ohm resistors close to the Master in series with SDA and SCL and pullup's 2 x 10kOhm at both ends of the splittet bus make the bus working fine. I checked the timing with a logic analyser and the quality of the signals with a scope, both ok, no glitches or other dirty effects. Hope this help others having same trouble. I must say best solution is always making the bus from one end to the other end in one direction, i tested this also with 80cm. Adding also two 100 Ohm resitors in series with SDA and SCL close to the master makes the signal quality better also.
Both versions run with 80kHz very fine now.
Regards,
Ralf
Excuse me for my English.
How can I send data from a PIC 16F876 to four slaves
using the I2C bus protocol, with the same address?
Could you help me, a piece of code would be welcome!
mimie64.
I2C bus protocol requires unique addresses for each slave. Just code the address into each slave if you are building the slaves yourself of course.
Thanks to all of you for your greath wok!
... just to avoid to have trouble in future and have a clear view of a new project, I have in plan to use the slave routine on almost 12 PIC of 18F2550 and one Master with 18F4550.
The idea is that:
I shall have the Master far from the first slaves at about two to three meters and the second slave is far from the first slave around 50 cm, and all other slaves are distanced 50 cm between them.
At the end the total length shall be more than 10 meters. but less that 12 meters.
Also, I would use the RJ45 connectors to make interconnection between the PCBs and use the preassembled CAT5 Ethernet patch cable to carry the supply voltage from the Master to the slaves.
I have thinked to put on pin 1, 2 and 3 the VCC, on pin 4 the Clk, on pin 5 the Dat and on pin 6. 7 and 8 the GND?
The lenght of the cables can be a problem?
The idea to use the RJ45 with the CAT5 patch cable is good?
Leo
Last edited by Wirecut; - 27th March 2016 at 12:19. Reason: typo error
Leo
WIKI I2C
CAT5 CAPACITANCEThe maximum number of nodes is limited by the address space, and also by the total bus capacitance of 400 pF, which restricts practical communication distances to a few meters.
52pF / metre
cat5 balanced cable / i2c unbalanced signal.
cat5 characteristic impedence of 100 ohms is probably a big load for the i2c pins also.
its not a good match , and won't go far
A regular CAT5 RJ45 has 4 twisted pairs, but they're not "in order"
1,2 orange,orange/wht
3,6 green,green/wht
4,5 blue,blue/wht
7,8 brown,brown/wht
I'd pair the SDA and SCL signals each with a GND (ie 1=GND, 2=SDA, and 7=SCL, 8=GND) and use the others for PWR/GND.
10 meters is a long way for a single-ended TTL level signal. They make I2C bus extenders for this sort of thing.
Bookmarks