1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

Master Slave Clocks with PIC16F887

Discussion in 'Microcontrollers' started by koolguy, Mar 31, 2015.

  1. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    Because its classified as a 7 bit address... 0x69... BUT!!! to address an I2C bus we need to shift it up to allow for the R/W bit

    0110 1000 = ox69
    1101 0000/1 = 0xD0 or 0xD1
    When running on power the DS1302 can charge suitable back-up batteries..
    If the BLDC has feedback control then you could read motor position, Obviously that chip only moved the motors..
     
  2. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    Hello,
    Please tell how to make 7 segment clocks using DS1307!
    By hardware I2C not by software.
     
  3. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    Hello,
    Please tell how to code for i2c for 7 segment how to read from DS1307?
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK

    I will be at home in about an hour... I'll put the basics in a file and let you finish it!!

    I'll try and remark it as well as I can..

    P.S.

    How are you driving the seven seg display... Also how many digits???
     
  6. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    Okay.... Simple RTC to Display.... I have only used time....

    Code (c):

    #include<xc.h>

    void delayUs(int x)
       {
       x>>= 5;
       while(x--);           // delay Usv ( aprox...)
       }

    void delayMs(int x)
       {
       while(x--)
         delayUs(1000);       // delay Ms
       }
     
    void InitI2C()
       {
       TRISC3=1;
       TRISC4=1;
       SSPCON=0b00101000;
       SSPCON2=0;
       SSPSTAT=0b10000000;
       SSPADD=50;  //20000/(4*100);  //Fosc/(4*baud)
       SSPIF=0;
       BCLIF=0;
       }

    //Wait for the module to finish it's last action.
    void WaitSSP()
       {
       while(SSPIF==0);
       SSPIF=0;
       }

    //send start bit
    void SendStart()
       {
       SEN=1;
       WaitSSP();
       }

    //Send stop bit.
    void SendStop()
       {
       PEN=1;
       WaitSSP();
       }

    //Send restart bit
    void SendRestart()
       {
       RSEN=1;
       WaitSSP();
       }

    //Send byte and return ack bit - 1=Ack  0=NAck
    char SendByte(char Byte)
       {
       SSPBUF=Byte;
       WaitSSP();
       return(!ACKSTAT);
       }

    //Get a byte from the slave
    char ReceiveByte()
       {
       RCEN=1;         // get byte
       WaitSSP();
       return(SSPBUF);
       }

    //Send a Not Acknowledge (NAck) to the slave
    void SendNack()
       {
       ACKDT=1;       // Not Acknowledge
       ACKEN=1;
       WaitSSP();
       }

    //Send an Acknowledge (Ack) to the slave
    void SendAck()
       {
       ACKDT=0;       // Acknowledge
       ACKEN=1;
       WaitSSP();
       }

    //Sends the start and device address.
    //If the device is busy then it resends until accepted.
    void SendID(char DeviceID)
       {
       SendStart();
       if(SendByte(DeviceID)==1)     // Send ID until accepted..
         return;
       do
         {
         SendRestart();
         }while(SendByte(DeviceID)==0);
       }


    //Write a byte to The RTC
    char WriteRTC(char Address, char Byte)
       {
       SendID(0b11010000);         // Send 0xD0
       if(SendByte(Address&0xff)==0)   // Send address
         return(0);
       if(SendByte(Byte)==0)       // Send byte
         return(0);
       SendStop();             // All done
       return(1);
       }

    //Read a byte from the RTC
    char ReadRTC(char Address)
       {
       char Byte;
       SendID(0b11010000);         // Send 0xD0
       if(SendByte(Address&0xff)==0)   // Send address
         return(0);
       SendRestart();           // Re-start
       if(SendByte(0b11010001)==0)     // Read 0xD1
         return(0);
       Byte=ReceiveByte();         // Get byte
       SendNack();             // No more
       SendStop();             // Stop bus
       return(Byte);           // All done
       }

    void WriteClock(char *array)       // Not used
       {
       char x;
       int tmp;
       for(x=0;x<7;x++)
         {
         tmp = array[x] / 10;
         tmp << = 4;
         tmp += array[x] % 16;
         WriteRTC(x,tmp);
         }  
       }  

    void ReadClock(char *array)
       {
       char x;
       for(x=0;x<7;x++)
         array[x] = ReadRTC(x);       // No need to BCD-BIN
       }  

    unsigned char Time[7];
    unsigned char DISP[6];
    unsigned char digits[] = {0x3f,0x6,0x5b,0x4f,0x66,0x6d,0x7d,0x7,0x7f,0x6f};
                 
    void main(void)
       {
       int idx, SCL;           // loop variables
       unsigned char DIGIT;       // A temporary store for manipulation
       TRISC = 0;             // portc tris bits
       TRISD = 0;             // portd tris bits
       InitI2C();             // prepare the RTC bus
       RC0 = 1;             // MR high
       RC1 = 0;             // OE low
     
       while(1)
         {
         ReadClock(&Time[0]);               // Get time ( BCD format as
         delayMs(250);                   // we are using  7 seg )
         DISP[5] = Time[2]>>4; DISP[4] = Time[2] & 0xf;   // fill display buffer
         DISP[3] = Time[1]>>4; DISP[2] = Time[1] & 0xf;   // backwards so it's
         DISP[1] = Time[0]>>4; DISP[0] = Time[0] & 0xf;   // readable...
         for(idx = 0;idx < 6;idx++)
           {
           DIGIT = digits[DISP[idx]];         // retrive 7 seg code
           for(SCL = 0; SCL < 8; SCL++)         // 8 clocks
             {
             RD2 = 1;                 // No data ( swap for CC )
             if(DIGIT & 0x80)RD2 = 0;         // Data to send?? ( swap for CC )
             DIGIT<<=1;
             RD0 = 1;                 // data clock
             NOP();
             RD0 = 0;        
             }
         
           }
         RD1 = 1;                     // Latch clock..
         NOP();
         RD1 = 0;
         }  
     
       }
     
    Capture.jpg

    I have used 74ls595 to give visual stability.... See if you can follow the code. NO INTERRUPTS so you should be okay!!!
     
    • Like Like x 1
  7. MCU88

    MCU88 Member

    Joined:
    Apr 1, 2015
    Messages:
    121
    Likes:
    7
    Ian, don't take your years of expertise for granted. There is nothing simple in electronics. Electronics is in essence 'physics'
     
  8. dr pepper

    dr pepper Well-Known Member Most Helpful Member

    Joined:
    Oct 6, 2008
    Messages:
    4,757
    Likes:
    258
    Location:
    North west UK
    I think you'd better crack open that jd mr rogers.

    P.S. after staring at datasheets wondering why an i2c device wasnt responding I've run a i2c scanner and found that the address isnt as published in the datasheet, on a couple of devices.
     
  9. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    Hello,
    I am using PORTB directly with 120 ohm to 4 seven segment, and common anode to RD0-RD3 via BJT. the circuit is working fine.
    I am using array stored and set to PORTB for Driving 7 segments.!
     
  10. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    Hi again,

    This is what i want to understand
    Thanks

    If you want to write to the device you have to:

    setup a start condition ( if bus is ready )
    write device address ( wait for ack )
    write register address ( wait for ack )
    write device data ( wait for ack )
    send nack ( to stop device )
    send stop ( to free bus )


    If you want to read from the device you have to:

    setup a start condition ( if bus is ready )
    write device address ( wait for ack )
    write register address ( wait for ack )
    send re-start( wait for ack )
    read device ( send ack if more data needed )
    send nack ( to stop device )
    send stop ( to free bus )
     
    Last edited: Apr 9, 2015
  11. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    Hello,
    I have modified the code simple version.
    please have a look i have write 0x0f in sec register @ 0x00h addr to watch the change after this i am reading the i2c buffer register to get value!
    In MPLAB build successful, hanging at in debugger can we test code in this?
    void i2c_Wait(void){
    while((SSPCON2 & 0X1F || (SSPSTAT & 0X04)));
    }



    Code (C):
    #include <htc.h>

    __CONFIG(LVP_OFF & BOREN_OFF & PWRTE_ON & WDTE_OFF & FOSC_HS);
    #define _XTAL_FREQ 20000000
    #define SDATA RC4
    #define SCLK RC3
    void I2C_init(),I2C_start(void),I2C_write(char x), I2cSTOP(void);  
    void i2c_Wait(void);
    char data[13]={  0b00010000,0b01111101,0b00100011,0b00101000,0b01001101,0b10001000,
    0b10000000, 0b00111101,0X00,0b00001000};

    void main(void){
    ANSELH = 0;
        TRISC3=1; //direction to input have be changed
        TRISC4=1;
    unsigned char ch=0;
        unsigned char i;
    TRISC0=0;
    TRISB=0X00;
    TRISD=0X00;
    TRISC1=0;
    TRISC2=0;
    RC0=0;
    RC1=0;
    RC2=0;
    //__delay_ms(500);
        I2C_init();
    //__delay_ms(50);

        I2C_start();
        I2C_write(0xd0);

    I2C_write(0x00);
    I2C_write(0x0f);

     
    I2cSTOP();

    while(1){
        I2C_start();
        I2C_write(0xd0);
        I2C_write(0x00);
        I2cSTOP();
        I2C_start();
        I2C_write(0xD1);
       i= SSPBUF;

        I2cSTOP();
    }


    RD0=0;
    RD1=0;
    RD2=0;
    RD3=1;
    PORTB=data[i];
    __delay_ms(500);
    PORTB=0B00000000;


    }

    void I2C_init(void)
        {
      SSPCON = 0x38;      // set I2C master mode
    SSPCON2 = 0x00;
    SSPADD = 0x0C;  //400KHZ  20MHz xtal
    SSPSTAT|=0X80;
    PSPIF=0;      // clear SSPIF interrupt flag
    BCLIF=0;      // clear bus collision flag
    }
    void I2C_start(void)
    {
        i2c_Wait();
        SEN=1;
    }
    void I2C_write(char x){
        i2c_Wait();  
    SSPBUF=x;
            }
    void i2c_Wait(void){
        while((SSPCON2 & 0X1F || (SSPSTAT & 0X04)));
    }
    void I2cSTOP(void)
    {
        i2c_Wait();
        PEN=1;
    }








     
     
  12. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    Hi again,
    What should be next step, how to remove error?
     
  13. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    You have to make a stimulus file that injects the data into the serial buffer.... Then at the appropriate time file the stimulus
     
  14. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    OK, do you find any eror in this upper code it is display only 8 in 7 segment.
    not changing the digit is there any error?
     
  15. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    Well yeah!! The LED write is only once AND!! its outside the while loop.... It will never be updated...

    One other thing... i will be a BCD figure... so you also need to and it with 0xf so the data array can separate tens and units... to display the tens shift i 4 times.... i >>= 4;
     
  16. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    Hi again,
    It is not working..



    Code (C):
    #include <htc.h>

    __CONFIG(LVP_OFF & BOREN_OFF & PWRTE_ON & WDTE_OFF & FOSC_HS);
    #define _XTAL_FREQ 20000000
    #define SDATA RC4
    #define SCLK RC3
    void I2C_init(),I2C_start(void),I2C_write(char x), I2cSTOP(void);  
    void i2c_Wait(void);
    char data[13]={  0b00010000,0b01111101,0b00100011,0b00101000,0b01001101,0b10001000,
    0b10000000, 0b00111101,0X00,0b00001000};

    void main(void){
    ANSELH = 0;
        TRISC3=1; //direction to input have be changed
        TRISC4=1;
    unsigned char ch=0;
    unsigned char i=0;

    TRISB=0X00;
    TRISD=0X00;
    PORTB=0B00000000;
    __delay_ms(500);
        I2C_init();
    __delay_ms(50);

        I2C_start();
        I2C_write(0xd0);

    I2C_write(0x00);
    I2C_write(0x00);

    I2cSTOP();
       RD0=0;
    RD1=0;
    RD2=1;
    RD3=0;
    PORTB=data[0];
    __delay_ms(800);
    PORTB=0B00000000;
       
    while(1){

        I2C_start();
        I2C_write(0xd0);
        I2C_write(0x00);
        I2cSTOP();
        I2C_start();
        I2C_write(0xD1);
       i= SSPBUF;

        I2cSTOP();

    i=i&0xf;
    RD0=1;
    RD1=0;
    RD2=0;
    RD3=0;
    PORTB=data[i];
    PORTB=0x00;
    __delay_ms(500);

    i>>=4;
    RD0=0;
    RD1=1;
    RD2=0;
    RD3=1;
    PORTB=data[i];
    PORTB=0x00;
    __delay_ms(500);





    }
    }
    void I2C_init(void)
        {
      SSPCON = 0x38;      // set I2C master mode
    SSPCON2 = 0x00;
    SSPADD = 0x0C;  //400KHZ  20MHz xtal
    SSPSTAT|=0X80;
    PSPIF=0;      // clear SSPIF interrupt flag
    BCLIF=0;      // clear bus collision flag
    }
    void I2C_start(void)
    {
        i2c_Wait();
        SEN=1;
    }
    void I2C_write(char x){
        i2c_Wait();  
    SSPBUF=x;
            }
    void i2c_Wait(void){
        while((SSPCON2 & 0X1F || (SSPSTAT & 0X04)));
    }
    void I2cSTOP(void)
    {
        i2c_Wait();
        PEN=1;
    }








     
     
  17. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    I am tired now with DS1307 it is still 8 on display...
    how to work out from it?
    i am using 6V adapter.
     
  18. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
  19. koolguy

    koolguy Active Member

    Joined:
    Aug 24, 2010
    Messages:
    2,196
    Likes:
    9
    Hello, can we use it as shift register ?
    serial trans and rx to make it work!
     
  20. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    Arrrgghh!!!
    Code (text):

    PORTB=data[i]; <------- LOOK   If  i  is seconds it will be.....
    say 0x58 BCD  or dec 88  HOW CAN YOU ASK FOR data[i].....
    data[88] doesn't exsist!!!!!!
     
    The Ds1307 stores the data in BCD format..... if seconds = 11 it is stored 0x11 ( dec 17 ).....#

    You need to modulus i.... and i / 16....

    data[ i %16]; units
    data[ i >> 4]; tens
     
    • Like Like x 1
  21. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    Also...

    You turn the port back off again before you see anything!!!!!!
     

Share This Page