Hot!I2C + PIC16F873

Page: 123 > Showing page 1 of 3
Author
Enea
Starting Member
  • Total Posts : 86
  • Reward points : 0
  • Joined: 2017/05/18 12:36:53
  • Location: 0
  • Status: offline
2018/01/13 12:39:52 (permalink)
0

I2C + PIC16F873

Hi to everybody.
I'm still working in my project to "automate" my railway diorama N scale.

I'm using a pic16F873-04 and XC8 on MPLABX IDE.
Please, don't ask me why i'm using this device. I've already reply many time in other threads.

I would like to connect 4 controller to one master, and i'm trying to develope i2c comunication, for now, but i have some problems. Is possible in the future i'll switch to RS485, but for now i2c is my target.

In the next in each pic there will some sensors, and each one need tell to other controller wich sensor is activate in the net: for example, excluding pic1 (master), pic2 will have sens2, pic3 sens3, pic4 sens4....
I'll need to send, by master obviusly, the status about sens2 and sens4 to pic3. I think it is clear. I don't explain other combinations.

So, in the net must run the instructions starting by master, or through by it sent from each slave.
 
 
For the moment i'm trying to connect the master to one slave. Please look this http://www.webalice.it/e....ica/20171231173320.jpg

but don't care about the eprom.
 
 
I would like to switch on the led on slave by pushing the swith on master.
 
 
Forward the code for the master and the slave. It come from here, https://electrosome.com/i...controller-mplab-xc8/, and modified to my need.

It doesnt work very well. The transmission is visible on this link https://www.youtube.com/watch?v=W56Pnrpu144 . You can check the addressing group by master and the receiving proup. In this video the switch in the master was on RC0, now in on RC1. In the second group you can see the addressing on 0x31 and the data trasmitted by the slave Always on on. I think isn't ok, because the same signal is like withot the slave connected. I thik the master code have some problem, and i can't ceck the slave for this problem.

May someone help me to find the solution?
 
 
Sorry for the comments, many of this are in italian. 
 
Master
 
#pragma config FOSC = XT // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage In-Circuit Serial Programming Enable bit
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit
#pragma config WRT = OFF // Flash Program Memory Write Enable bits
#pragma config CP = OFF // Flash Program Memory Code Protection bit


#define _XTAL_FREQ 4000000//UL


//-----------------------------------------------
// INCLUDE
//-----------------------------------------------

#include "xc.h"
#include "pic16f873.h"

//-----------------------------------------------
//DEFINIZIONI (definitions)
//-----------------------------------------------

//-----------------------------------------------
//INIZIALIZZAZIONI ()
//-----------------------------------------------

void I2C_Master_Init(const unsigned long c)
{
  SSPCON = 0b00101000;
  SSPCON2 = 0;
  SSPADD = (_XTAL_FREQ/(4*c))-1;
  SSPSTAT = 0;
  TRISC3 = 1; //Setting as input as given in datasheet
  TRISC4 = 1; //Setting as input as given in datasheet
}

void I2C_Master_Wait()
{
  while ((SSPSTAT & 0b00000100) || (SSPCON2 & 0b00011111)); //((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
                                                            // (00000100 or 00011111)=00011111
  
                                                            //SSPSTAT
                                                            // 0 SMP: Sample bit
                                                            // 0 CKE: SPI Clock Edge Select
                                                            // 0 D/A: Data/Address bit (I2C mode only)
                                                            // 0 P: STOP bit
                                                            // 0 S: START bit
                                                            // 1 R/W: Read/Write bit Information (I2C mode only)
                                                            // 0 UA: Update Address (10-bit I2C mode only)
                                                            // 0 BF: Buffer Full Status bit
  
                                                            //SSPCON2
                                                            // 0 GCEN: General Call Enable bit (In I2C Slave mode only)
                                                            // 0 ACKSTAT: Acknowledge Status bit (In I2C Master mode only)
                                                            // 0 ACKDT: Acknowledge Data bit (In I2C Master mode only)
                                                            // 1 ACKEN: Acknowledge Sequence Enable bit (In I2C Master mode only)
                                                            // 1 RCEN: Receive Enable bit (In I2C Master mode only)
                                                            // 1 PEN: STOP Condition Enable bit (In I2C Master mode only)
                                                            // 1 RSEN: Repeated START Condition Enable bit (In I2C Master mode only)
                                                            // 1 SEN: START Condition Enable bit (In I2C Master mode only)
}

void I2C_Master_Start()
{
  I2C_Master_Wait();
  SEN = 1;
}

void I2C_Master_RepeatedStart()
{
  I2C_Master_Wait();
  RSEN = 1;
}

void I2C_Master_Stop()
{
  I2C_Master_Wait();
  PEN = 1;
}

void I2C_Master_Write(unsigned d)
{
  I2C_Master_Wait();
  SSPBUF = d;
}

unsigned short I2C_Master_Read(unsigned short a)
{
  unsigned short temp;
  I2C_Master_Wait();
  RCEN = 1; //RCEN: Receive Enable bit
                        // 1 = Abilita la modalità di ricezione per I2C
                        // 0 = modalità ricezione inattiva
  I2C_Master_Wait();
  temp = SSPBUF;
  I2C_Master_Wait();
  ACKDT = (a)?0:1; //se "a" è 1 metti ACKDT a 0, altrimenti mettilo ad 1
  
                        //ACKDT: conferma dei bit di dati (SOLO in in modalità master I2C)
                        //Valore verrà trasmesso quando inizia una sequenza di conferma
                        //alla fine di una ricezione
                        // 1 = nessun Acknowledge
                        // 0 = Acknowledge
  
  ACKEN = 0; //ACKEN: abilita la sequenza di bit (SOLO in in modalità master I2C)
                        // 1 = avvia la procedura di riconoscimento dati sui pin SDA e SCL e
                        // trasmette il bit di ACKDT (viene azzerato Automaticamente dall'hardware)
                        // 0 = sequenza inattiva
  return temp;
}

//-----------------------------------------------
//MAIN - (MAIN PROGRAM)
//-----------------------------------------------

void main()
{
  INTCON = 0b00000000;
  //nRBPU = 0; //Enable PORTB internal pull up resistor
  
  // 0= USCITA
  // 1= INGRESSO
  
  TRISB = 0xFF; //PORTB as input
  TRISC0 = 1;
  TRISC1 = 1;
  TRISC7 = 0; //PORTC7 as output
  RC7=0;
  char pippo;
  
  I2C_Master_Init(100000); //Initialize I2C Master with 100KHz clock
  while(1)
  {
    
    I2C_Master_Start(); //Start condition
    I2C_Master_Write(0x30); //7 bit address + Write
    I2C_Master_Write(RC1<<1); //Write data
    I2C_Master_Stop(); //Stop condition
    
  __delay_us(100); //attesa

    I2C_Master_Start(); //Start condition
    I2C_Master_Write(0x31); //7 bit address + Read
    RC0 = I2C_Master_Read(0); //Read + Acknowledge
    I2C_Master_Stop(); //Stop condition
    
  __delay_ms(400); //attesa
    
  }
}

 
Slave

//-----------------------------------------------
// CONFIGURATION
//-----------------------------------------------
#pragma config FOSC = XT   // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF  // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = ON   // Low-Voltage In-Circuit Serial Programming Enable bit
#pragma config CPD = OFF   // Data EEPROM Memory Code Protection bit
#pragma config WRT = OFF   // Flash Program Memory Write Enable bits
#pragma config CP = OFF    // Flash Program Memory Code Protection bit

#define _XTAL_FREQ  4000000//UL

//-----------------------------------------------
// INCLUDE
//-----------------------------------------------
#include "xc.h"
#include "pic16f873.h"
//-----------------------------------------------
//DEFINIZIONI (definitions)
//-----------------------------------------------
#define I2cSlaveAddress 0x30
//-----------------------------------------------
//INIZIALIZZAZIONI ()
//-----------------------------------------------
#define testbit(var, bit) ((var) & (1 <<(bit))) 
#define setbit(var, bit) ((var) |= (1 << (bit))) 
#define clrbit(var, bit) ((var) &= ~(1 << (bit))) 
unsigned char temp_port;
short z;

void interrupt I2C_Slave_Read()
{
  if(SSPIF == 1)                    // check to see if SSP interrupt
  {
    SSPCONbits.CKP = 0;             // Clock Polarity Select bit CKP:
                                    //0 = mantiene il clock a zero
                                    //(lascia tempo ai dati per stabilizzarsi)
    if ((SSPCONbits.SSPOV) || (SSPCONbits.WCOL))   
                                    //valuta se sta arrivando qualche dato (SSPOV or WCOL)=1
                                    //SSPOV: indicatore di ricezione in Overflow   
                                    //      1 = Un nuovo byte viene ricevuto mentre SSPBUF conserva
                                    //      i dati precedenti. In modalità Slave, si deve
                                    //      leggere SSPBUF, anche se trasmette solo dati, per evitare
                                    //      overflow. (Deve essere azzerato dal firmware)
                                    //WCOL: Indicatore di bit di collisione in scrittura
                                    //      1 = Il registro SSPBUF viene scritto mentre continua
                                    //      a trasmettere la parola precedente
                                    //      (Deve essere azzerato dal firmware)
    {
      z = SSPBUF;                   // Legge il valore precedente del buffer
      SSPCONbits.SSPOV = 0;         // SSPOV: 0 = Nessun overflow
      SSPCONbits.WCOL = 0;          // WCOL: 0 = Nessuna collision
      SSPCONbits.CKP = 1;           // Clock Polarity Select bit
                                    // CKP: 1 = Enable clock
    }
    if(!SSPSTATbits.D_nA && !SSPSTATbits.R_nW)      // se  l'ultimo byte era indirizzo+scrittura
                                    //se vale 1 l'operazione (!D/A && !R/W),
                                    //cioè se D/A = 0 e R/W = 0 => (0 && 0)=0
                                    //D/A: Data/Address bit (I2C mode only)
                                    //      1 = indica che l'ultimo byte ricevuto o
                                    //          trasmesso era un dato
                                    //      0 = Indica che l'ultimo byte ricevuto o
                                    //          trasmesso era un indirizzo
                                    //R/W: bit di indicazione modalità lettura/scrittura (I2C mode only)
                                    //    Questo bit contiene le informazioni sul bit R / W
                                    //    seguenti l'ultima corrispondenza dell'indirizzo.
                                    //    Questo bit è valido solo dalla corrispondenza dell'indirizzo
                                    //    al prossimo bit START, STOP bit o /ACK bit.
                                    //    1 = lettura
                                    //    0 = scrittura
    {
      z = SSPBUF;                   //Legge il valore precedente del buffer
      while(!BF);                   //SSPSTAT.BF: Buffer Full Status bit
                                    //      IN RICEZIONE:
                                    //          1 = Receive complete, SSPBUF is full
                                    //          0 = Receive not complete, SSPBUF is empty
                                    //      IN TRASMISSIONE:
                                    //          1 = Data transmit in progress (does
                                    //              not include the ACK and STOP bits), SSPBUF is full
                                    //          0 = Data transmit complete (does not
                                    //              include the ACK and STOP bits), SSPBUF is empty
      //RC0 = SSPBUF;               // scrive in RC0 il buffer
     
      temp_port = SSPBUF;           // assegno a temp_port il valore del buffer
      if (testbit(temp_port, 0))    // se il bit 0 del char temp_port è 1
      {
        setbit(PORTC,0);            // metto ad 1 il bit 0 della Porta C (RC0))
      }
      else
        clrbit(PORTC,0);            // azzera RC0
     
      SSPCONbits.CKP = 1;           // CKP: 1 = Enable clock
      temp_port=0;
    }
    else if(!SSPSTATbits.D_nA && SSPSTATbits.R_nW)     // se  l'ultimo byte era indirizzo+lettura
                                    //se vale 1 l'operazione (!D/A && R/W),
                                    //cioè se D/A = 0 e R/W = 1 => (0 && 1)=0
                                    //D/A: Data/Address bit (I2C mode only)
                                    //      1 = indica che l'ultimo byte ricevuto o
                                    //          trasmesso era un dato
                                    //      0 = Indica che l'ultimo byte ricevuto o
                                    //          trasmesso era un indirizzo
                                    //R/W: bit di indicazione modalità lettura/scrittura (I2C mode only)
                                    //    Questo bit contiene le informazioni sul bit R / W
                                    //    seguenti l'ultima corrispondenza dell'indirizzo.
                                    //    Questo bit è valido solo dalla corrispondenza dell'indirizzo
                                    //    al prossimo bit START, STOP bit o /ACK bit.
                                    //    1 = lettura
                                    //    0 = scrittura
    {
      z = SSPBUF;                   // Legge il valore precedente del buffer
      BF = 0;                       //SSPSTAT.BF: Buffer Full Status bit
     
      SSPBUF = RC1 ;                //scrive in SSBUF lo stato di RC1
           
      SSPCONbits.CKP = 1;           // CKP: 1 = Enable clock
      while(SSPSTATbits.BF);        //Buffer Full Status bit BF:
                                    //1 = Data transmit in progress (does not include
                                    //the ACK and STOP bits), SSPBUF is full
                                    //0 = Data transmit complete (does not include the
                                    //ACK and STOP bits), SSPBUF is empty
    }
    SSPIF = 0;
  }
}
void I2C_Slave_Init()
{
  TRISC3 = 1;                   //RC3 input per I2C
  TRISC4 = 1;                   //RC4 input per I2C
 
  SSPCON = 0b00110110;          //era 0x36
  SSPCON2bits.SEN = 1;          //SEN: 1 = Initiate START condition on SDA and
                                //SCL pins. Automatically cleared by hardware.
                                //Clock stretching is enabled for a received
                                //address/data byte, ignoring the state of the
                                //SSPOV bit only if the BF bit = 0 the falling
                                //edge of SCL
                               
  SSPSTAT = 0b10000000;         //era 0x28
  SSPADD = I2cSlaveAddress;     // carica l'indirizzo dello Slave
 
  SSPIF = 0;                  // Clear the serial port interrupt flag
  BCLIF = 0;                  // Clear the bus collision interrupt flag
  BCLIE = 1;                  // Enable bus collision interrupts
  SSPIE = 1;                  // Enable serial port interrupts
  PEIE = 1;                   // Enable peripheral interrupts
  GIE = 1;                    // Enable global interrupts
 
}

//-----------------------------------------------
//MAIN - (MAIN PROGRAM)
//-----------------------------------------------
void main()
{
  INTCON  = 0b00000000;           //GIE: 0 = Disables all interrupts
                                  //PEIE: 0 = Disables all peripheral interrupts
                                  //T0IE: 0 = Disables the TMR0 interrupt
                                  //INTE: 0 = Disables the RB0/INT external interrupt
                                  //RBIE: 0 = Disables the RB port change interrupt
                                  //T0IF: 0 = TMR0 register did not overflow
                                  //INTF: 0 = The RB0/INT external interrupt did not occur
                                  //RBIF: 0 = None of the RB7:RB4 pins have changed state
 
 
  OPTION_REG = 0b11010111;        //RBPU: 1 = PORTB pull-ups are disabled
                                  //INTEDG: 1 = Interrupt on rising edge of RB0/INT pin
                                  //T0CS: 0 = Internal instruction cycle clock (CLKOUT)
                                  //T0SE: 1 = Increment on high-to-low transition on RA4/T0CKI pin
                                  //PSA: 0 = Prescaler is assigned to the Timer0 module
                                  //PS2÷PS0: 111 = TMR0-> 1:256, WDT Rate-> 1:128
 
  nRBPU = 0;                      //Enable PORTB internal pull up resistor
 
  // 0= USCITA
  // 1= INGRESSO
 
  TRISB = 0b11111111;             //PORTB as input
  TRISC0 = 0;
  TRISC1 = 1;
  TRISC7 = 0;                     //PORTC7 as output
  I2C_Slave_Init();               //Initialize as a I2C Slave
  while(1);
}

 
#1

41 Replies Related Threads

    qɥb
    Monolothic Member
    • Total Posts : 3332
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: I2C + PIC16F873 2018/01/13 14:30:11 (permalink)
    0
    Why does everyone ignore ACK when writing master code?
    That is the easiest way to test if things are working.
      I2C_Master_Init(100000); //Initialize I2C Master with 100KHz clock
      while(1)
      {
        I2C_Master_Start(); //Start condition
        I2C_Master_Write(0x30); //7 bit address + Write

    At this point, you should do a wait, and then read the received ACK bit to see if the Slave responded.
    If it did, great, things are working so far.
    If it did not, things are not working, and it is totally pointless proceeding.
     

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #2
    qɥb
    Monolothic Member
    • Total Posts : 3332
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: I2C + PIC16F873 2018/01/13 14:31:57 (permalink)
    0
     p.s. Why go to all the effort of passing the bus speed as a parameter to the   I2C_Master_Init() function ?
    That is needlessly complicating things.
    It's far easier just to just make it constant, and let the compiler do the calculation rather than doing it at runtime.

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #3
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 02:49:56 (permalink)
    0
    qɥb
    Why does everyone ignore ACK when writing master code?
    That is the easiest way to test if things are working.
      I2C_Master_Init(100000); //Initialize I2C Master with 100KHz clock
      while(1)
      {
        I2C_Master_Start(); //Start condition
        I2C_Master_Write(0x30); //7 bit address + Write

    At this point, you should do a wait, and then read the received ACK bit to see if the Slave responded.
    If it did, great, things are working so far.
    If it did not, things are not working, and it is totally pointless proceeding.
     

     

     So, what do you suggest? What do you think about this on forward?

    while(1)
      {
        I2C_Master_Start(); //Start condition
        I2C_Master_Write(0x30); //7 bit address + Write
        while (ACKDT==0){}
       ...
       ...
     

     
    qɥb
    p.s. Why go to all the effort of passing the bus speed as a parameter to the   I2C_Master_Init() function ?
    That is needlessly complicating things.
    It's far easier just to just make it constant, and let the compiler do the calculation rather than doing it at Runtime.

     
    What do you suggest? May you write some code?
    #4
    qɥb
    Monolothic Member
    • Total Posts : 3332
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 03:11:22 (permalink)
    0
    Enea
    ...
    So, what do you suggest? What do you think about this on forward?

    while(1)
      {
        I2C_Master_Start(); //Start condition
        I2C_Master_Write(0x30); //7 bit address + Write
        while (ACKDT==0){}
     

    No, that is wrong on two counts.
    One, I said "do a wait", i.e. wait until the previous action has completed, then the received ACK status will be in the ACKSTAT bit, ACKDT is for when you are sending, not receiving.
    Only read it once. If it's high (which is NAK), then the slave didn't respond. There's no point waiting for it to go low, it never will after that, so abort and report an error.
     
    qɥb
    p.s. Why go to all the effort of passing the bus speed as a parameter to the   I2C_Master_Init() function ?
    That is needlessly complicating things.
    It's far easier just to just make it constant, and let the compiler do the calculation rather than doing it at Runtime.

    What do you suggest? May you write some code?

    Rather than pass a 32 bit value as parameter "c" to your init code (which is pretty inefficient)
    Just put this early in your C file
    #define I2C_SPEED 100000

    then change
     SSPADD = (_XTAL_FREQ/(4*c))-1;

    to
     SSPADD = (_XTAL_FREQ/(4*I2C_SPEED))-1;

    so now all the numbers in the expression are known at compile time, so the compiler can just calculate the required constant value to write into SSPADD, rather than having to do a 32 bit calculation at run time.
    32 bit arithmetic in an 8 bit processor is always inefficient.
     
     
    post edited by qɥb - 2018/01/14 03:13:14

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #5
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 03:34:08 (permalink)
    0
    qɥb
    Enea
    ...
    So, what do you suggest? 
    ...

    No, that is wrong on two counts.
    One, I said "do a wait", i.e. wait until the previous action has completed, then the received ACK status will be in the ACKSTAT bit, ACKDT is for when you are sending, not receiving.
    Only read it once. If it's high (which is NAK), then the slave didn't respond. There's no point waiting for it to go low, it never will after that, so abort and report an error.
     
     
    Ok, do you mean a simply __delay_us(10) or more,  or is better add a "I2C_Master_Wait()" where is it present the SSPCON2:4 bit
     
    bit 4 ACKEN: Acknowledge Sequence Enable bit (In I1415C Master mode only)
    In Master Receive mode:

    1 = Initiate Acknowledge sequence on SDA and SCL pins and transmit ACKDT data bit.Automatically cleared by hardware.
    0 = Acknowledge sequence idle
     

    void I2C_Master_Wait()
    {
      while ((SSPSTAT & 0b00000100) || (SSPCON2 & 0b00011111));
          //((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
          // (00000100 or 00011111)=00011111
          //SSPSTAT
          //  0 SMP:  Sample bit
          //  0 CKE:  SPI Clock Edge Select
          //  0 D/A:  Data/Address bit (I2C mode only)
          //  0 P:    STOP bit
          //  0 S:    START bit
          //  1 R/W:  Read/Write bit Information (I2C mode only)
          //  0 UA:   Update Address (10-bit I2C mode only)
          //  0 BF:   Buffer Full Status bit
      
          //SSPCON2
          //  0 GCEN:     General Call Enable bit (In I2C Slave mode only)
          //  0 ACKSTAT:  Acknowledge Status bit (In I2C Master mode only)
          //  0 ACKDT:    Acknowledge Data bit (In I2C Master mode only)
          //  1 ACKEN:    Acknowledge Sequence Enable bit (In I2C Master mode only)
          //  1 RCEN:     Receive Enable bit (In I2C Master mode only)
          //  1 PEN:      STOP Condition Enable bit (In I2C Master mode only)
          //  1 RSEN:     Repeated START Condition Enable bit (In I2C Master mode only)
          //  1 SEN:      START Condition Enable bit (In I2C Master mode only)
    }

     
     
     
    while(1)
      {
        I2C_Master_Start();           //Start condition
        I2C_Master_Write(0x30);       //7 bit address + Write
        I2C_Master_Wait();
        I2C_Master_Write(RC1<<1);     //Write data
        I2C_Master_Stop();            //Stop condition

     
    qɥb
    p.s. Why go to all the effort of passing the bus speed as a parameter to the   I2C_Master_Init() function ?
    That is needlessly complicating things.....
    32 bit arithmetic in an 8 bit processor is always inefficient.

    May be in the future i would have done it, in the optimization moment, i'm used to groupin define and other thing in the dadicated zones... so, for now i didn' care about this.
    However Understood, it is a new for me. Thanks, i don't know all the programmers trick.

    #6
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 03:39:18 (permalink)
    0
    Ok, do you mean a simply __delay_us(10) or more,  or is better add a "I2C_Master_Wait()" where is it present the SSPCON2:4 bit
     
    bit 4 ACKEN: Acknowledge Sequence Enable bit (In I14C Master mode only)
    In Master Receive mode:
     
    1 = Initiate Acknowledge sequence on SDA and SCL pins and transmit ACKDT data bit.Automatically cleared by hardware.
    0 = Acknowledge sequence idle
     

     
    void I2C_Master_Wait()
    {
      while ((SSPSTAT & 0b00000100) || (SSPCON2 & 0b00011111));
     
          //((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
          // (00000100 or 00011111)=00011111
          //SSPSTAT
          //  0 SMP:  Sample bit
          //  0 CKE:  SPI Clock Edge Select
          //  0 D/A:  Data/Address bit (I2C mode only)
          //  0 P:    STOP bit
          //  0 S:    START bit
          //  1 R/W:  Read/Write bit Information (I2C mode only)
          //  0 UA:   Update Address (10-bit I2C mode only)
          //  0 BF:   Buffer Full Status bit
      
          //SSPCON2
          //  0 GCEN:     General Call Enable bit (In I2C Slave mode only)
          //  0 ACKSTAT:  Acknowledge Status bit (In I2C Master mode only)
          //  0 ACKDT:    Acknowledge Data bit (In I2C Master mode only)
          //  1 ACKEN:    Acknowledge Sequence Enable bit (In I2C Master mode only)
          //  1 RCEN:     Receive Enable bit (In I2C Master mode only)
          //  1 PEN:      STOP Condition Enable bit (In I2C Master mode only)
          //  1 RSEN:     Repeated START Condition Enable bit (In I2C Master mode only)
          //  1 SEN:      START Condition Enable bit (In I2C Master mode only)
    }
     

     
     
     
     
    while(1)
      {
        I2C_Master_Start();           //Start condition
        I2C_Master_Write(0x30);       //7 bit address + Write
        I2C_Master_Wait();
        I2C_Master_Write(RC1<<1);     //Write data
        I2C_Master_Stop();            //Stop condition
     

     
    qɥb
    p.s. Why go to all the effort of passing the bus speed as a parameter to the   I2C_Master_Init() function ?
    That is needlessly complicating things.....
    32 bit arithmetic in an 8 bit processor is always inefficient.

     
    May be in the future i would have done it, in the optimization moment, i'm used to groupin define and other thing in the dadicated zones... so, for now i didn' care about this.
    However Understood, it is a new for me. Thanks, i don't know all the programmers trick.
    #7
    qɥb
    Monolothic Member
    • Total Posts : 3332
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 04:35:19 (permalink)
    +1 (1)
    Enea
    Ok, do you mean a simply __delay_us(10) or more,  or is better add a "I2C_Master_Wait()"

    Use I2C_Master_Wait()
     

    where is it present the SSPCON2:4 bit
     
    bit 4 ACKEN: Acknowledge Sequence Enable bit (In I14C Master mode only)
    In Master Receive mode:
     
    1 = Initiate Acknowledge sequence on SDA and SCL pins and transmit ACKDT data bit.Automatically cleared by hardware.
    0 = Acknowledge sequence idle
     

    That is for sending an acknowledge sequence, not for receiving it.
     

    qɥb
    p.s. Why go to all the effort of passing the bus speed as a parameter to the   I2C_Master_Init() function ?
    That is needlessly complicating things.....
    32 bit arithmetic in an 8 bit processor is always inefficient.

     
    May be in the future i would have done it, in the optimization moment, i'm used to groupin define and other thing in the dadicated zones... so, for now i didn' care about this.
    However Understood, it is a new for me. Thanks, i don't know all the programmers trick.

    Personally, I consider the way I suggest as the EASIER way to do it.
    Passing the value as a parameter to the function is a more complicated way to do it.

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #8
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 04:47:38 (permalink)
    0
    Sorry, but reading the code don't really understand where i need to add I2C_Master_Wait()?
    It is already in any routine:
     
    - I2C_Master_Start
    - I2C_Master_RepeatedStart
    - I2C_Master_Stop
    - I2C_Master_Write
    - I2C_Master_Read
     
    Insert it in the code like forward is only to multiply the retard between two sequence? Is it your mean.

    while(1)
      {
        I2C_Master_Start();           //Start condition
        I2C_Master_Write(0x30);       //7 bit address + Write
        I2C_Master_Wait();
        I2C_Master_Write(RC1<<1);     //Write data
        I2C_Master_Stop();            //Stop condition
    }

    #9
    qɥb
    Monolothic Member
    • Total Posts : 3332
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 04:55:31 (permalink)
    +1 (1)
    Enea
    Sorry, but reading the code don't really understand where i need to add I2C_Master_Wait()?

    As I said, you need to do it BEFORE you read the ACKSTAT bit.
        I2C_Master_Start();           //Start condition
        I2C_Master_Write(0x30);       //7 bit address + Write
        I2C_Master_Wait();    //Wait until the Master_Write completes
        //READ ACKSTAT HERE. IF IT IS HIGH, then send a STOP condition and abort.
        I2C_Master_Write(RC1<<1);     //Write data
        I2C_Master_Stop();            //Stop condition
     

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #10
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 05:17:11 (permalink)
    0
    Understood,...may be. 
    Now while condition in wait cycle is "while ((SSPSTAT & 0b00000100) || (SSPCON2 & 0b00011111));".
    I need to change the while condition. ACKSTAT will be added to the while.
    I'll try it.
     

    void I2C_Master_Wait()
    {
      while ((SSPSTAT & 0b00000100) || (SSPCON2 & 0b01011111));
            //((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
            // (00000100 or 01011111)=01011111
            //SSPSTAT
            //  0 SMP:  Sample bit
            //  0 CKE:  SPI Clock Edge Select
            //  0 D/A:  Data/Address bit (I2C mode only)
            //  0 P:    STOP bit
            //  0 S:    START bit
            //  1 R/W:  Read/Write bit Information (I2C mode only)
            //  0 UA:   Update Address (10-bit I2C mode only)
            //  0 BF:   Buffer Full Status bit
            //SSPCON2
            //  0 GCEN:     General Call Enable bit (In I2C Slave mode only)
            //  1 ACKSTAT:  Acknowledge Status bit (In I2C Master mode only)
            //  0 ACKDT:    Acknowledge Data bit (In I2C Master mode only)
            //  1 ACKEN:    Acknowledge Sequence Enable bit (In I2C Master mode only)
            //  1 RCEN:     Receive Enable bit (In I2C Master mode only)
            //  1 PEN:      STOP Condition Enable bit (In I2C Master mode only)
            //  1 RSEN:     Repeated START Condition Enable bit (In I2C Master mode only)
            //  1 SEN:      START Condition Enable bit (In I2C Master mode only)
    }

    #11
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 05:24:42 (permalink)
    0
    Ok, now the SCD is 5v, and SCL is 0v. And now, Slave doesn't send AKC. 
     
    I put  this in the master main code:
    RC7 = ACKSTAT;
    and effectively it is off.
     
    May be thereis an error in the slave code? Where?
    #12
    qɥb
    Monolothic Member
    • Total Posts : 3332
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 05:29:34 (permalink)
    +1 (1)
    Enea
    ...
    I need to change the while condition. ACKSTAT will be added to the while.

    Why on earth would you do that?
    That is nothing like what I have been asking you to do.
    Waiting for ACKSTAT is WRONG, WRONG, WRONG.
    Once again, you wait for the write to be finished, then you read ACKSTAT once only.
    0 is ACK, which means it worked.
    1 is NAK, which means it didn't, which means you've done something wrong. There is absolutely no point reading it again. A NAK does not change to an ACK all by itself.
     

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #13
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 08:20:11 (permalink)
    0
    Sorry i misunderstood.
     
    Did you mean something like this? Do you like break, or with "abort" mean other?
     
     

    I2C_Master_Init(100000);        //Initialize I2C Master with 100KHz clock
      while(1)
      {
        RC7 = ACKSTAT;
      //Scrittura su slave: invio dati
        I2C_Master_Start();           //Start condition
        I2C_Master_Write(0x30);       //7 bit address + Write
        I2C_Master_Wait();
        if (ACKSTAT)
        {
          I2C_Master_Stop();            //Stop condition
          break;
        }
        I2C_Master_Write(RC1<<1);     //Scrive lo stato di RC1 al bit 1 del buffer SSPBUF
        I2C_Master_Stop();            //Stop condition
       
      __delay_us(100);                //attesa

    #14
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 09:03:39 (permalink)
    0
    Sorry, i'm doing some measures with the oscilloscope. I'm commenting row by row the master code, in the while cycle.
    0x30 = 0b00110000 -> 7 bit = 0110000+0(/W sending data)+1(No Acknowledge) = total 9 pulse clock
    0x18 = 0b00011000 -> 7 bit = 0011000+0(/W sending data)+1(No Acknowledge) = total 9 pulse clock
    Please, look on this link: https://cdn.sparkfun.com/assets/6/4/7/1/e/51ae0000ce395f645d000000.png
    I'm allowing enabled these two rows:
        I2C_Master_Start();               //Start condition
        I2C_Master_Write(0x30);       //7 bit address + Write
    referring to the image on the link: in the A6 and A5 clock top level SDA is low, in the A4 and A3 clock top level SDA is high, in the A2 A1 A0 clock level SDA is low, then is 8° SDA is low (master sending) then is always  high (slave do not responding).  Is the address corrisonponding to 0x18?
    other question.
    SDA goes down 250uS after SCL. It will be the opposite sequence?
    Look here, 12 second from start: https://www.youtube.com/watch?v=W56Pnrpu144
    For the correct encoding of address, I must to check on level, low or high , or in the edge, rising i falling, to verify the SDA status?
     
     
     
     
    #15
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/14 23:45:12 (permalink)
    0
    However, ACKSTAT on RC7 is always on, and the break in the if cycle in this way is always activated. Infact by the oscilloscope there is Always the addressing by the master end no more, each 400ms ~.
     
    If i put RC7 led, in the slave code, before the "interrupt I2C_Slave_Read()" the led is Always ON.
    If I put it inside  the if cycle if(SSPIF == 1) the led is Always off.
     
    The interrupt does not sended by master or it doesn't read by slave.
     
    At this point, it is the master or the slave that doesn't work?
     
    post edited by Enea - 2018/01/15 00:04:14
    #16
    qɥb
    Monolothic Member
    • Total Posts : 3332
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: I2C + PIC16F873 2018/01/15 01:15:53 (permalink)
    +1 (1)
    Enea
    However, ACKSTAT on RC7 is always on, and the break in the if cycle in this way is always activated. Infact by the oscilloscope there is Always the addressing by the master end no more, each 400ms ~.

    So that is indicating that your communication is not working at all.
    Does your scope confirm that the START is sent correctly,
    the correct address is then sent,
    and a ninth clock pulse is issued to fetch the ACK/NAK bit?
     
    What is the level on the SDA signal while the SCL signal; is high for the ninth time?
     

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #17
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/15 02:28:26 (permalink)
    0
    Please heck the same link posted back, https://cdn.sparkfun.com/assets/6/4/7/1/e/51ae0000ce395f645d000000.png,
    from left to right.
     
    At the left i have the first difference, may be it is the principal cause to the trouble.
    In a back post i wrote: SDA goes down 250uS after SCL. It will be the opposite sequence?
    In the SDA sequence, after the addressing, 7 clock (A6-A0), i have a 8th clock pulse corresponding to low level for R/nW (sending from master), the 9th clock i have high level (ack non received).
     
     
    #18
    qɥb
    Monolothic Member
    • Total Posts : 3332
    • Reward points : 0
    • Joined: 2017/09/09 05:07:30
    • Location: Jupiter
    • Status: offline
    Re: I2C + PIC16F873 2018/01/15 02:35:14 (permalink)
    +1 (1)
    Are you sure you don't have SDA and SCL swapped?
    The diagram is correct, SDA on pin 15, SCL on 14.
     

    This forum is mis-configured so it only works correctly if you access it via https protocol.
    The Microchip website links to it using http protocol. Will they ever catch on?
    PicForum "it just works"
    #19
    Enea
    Starting Member
    • Total Posts : 86
    • Reward points : 0
    • Joined: 2017/05/18 12:36:53
    • Location: 0
    • Status: offline
    Re: I2C + PIC16F873 2018/01/15 03:32:20 (permalink)
    0
    I think no, the board is at home. However, the most important is that all SDA in the net are connected and all SCL are connectet, like the schematic i sent some post back. Now the eprom in the schematic there aren't.
    For the moment I have only 2 micro in the board and both pin 14 and both pin 15 are connected. I will check, but i'm sure of this.
    #20
    Page: 123 > Showing page 1 of 3
    Jump to:
    © 2018 APG vNext Commercial Version 4.5