1

我是 Pic Programming 的新手,我正在使用 MPLAb 和 Hitech 编译器来执行上述代码。我正在尝试将 PIC16F886 与 ISL12022M 实时 I2C 设备连接。我复制了为带有 16F887A PIC 的 DS1307 接口编写的代码示例。我有能力与上述接口基本功能。在下面的代码中,虽然写入 ISL12022M o 可以看到我在内存寄存器中发送的数据但是当尝试读取 rtc 时间时,我可以从 SSPBUF 读取最后一个内存写入值。让我知道以下代码中的任何错误。一次 I2c 读取值应显示在 4 位七段显示器上。

我想我在这部分是在做 Misatake。在读取数据时,我只是发送地址,所以无论最后写入的地址是什么,它都会显示。

#include <htc.h>
    #include <stdio.h>
    #include<pic.h>
    #include<stdint.h>

#define _XTAL_FREQ 40000000
unsigned int i=0; 
unsigned int k=0;  
unsigned int count;
#define Pulse RA5

#define LED RC0
#define LED1 RC2
#define CONTROLREG 0xFF
#define SDA         RC4             // Data pin for i2c
#define SCK         RC3             // Clock pin for i2c
#define SDA_DIR     TRISC4          // Data pin direction
#define SCK_DIR     TRISC3          // Clock pin direction
#define DP RA4  
#define I2C_SPEED   100             // kbps 

unsigned short int cnt, num,Dgt=0;;
unsigned short int temp1,temp2,temp3;

unsigned short sec;
unsigned short min;
unsigned short hour;
unsigned short date;
unsigned short month;
unsigned short year;
unsigned short day;
unsigned short int temp=0;
unsigned short r_data;
#define Seg1 0x01
#define Seg2 0x02
#define Seg3 0x04
#define Seg4 0x08   



    void SetSeg(unsigned short data, unsigned short segno)

     { 
                    switch(data) 
                    { 
                        case 0: PORTB = 0x3F; break; 
                        case 1: PORTB = 0x06; break; 
                        case 2: PORTB = 0x5B; break; 
                        case 3: PORTB = 0x4F; break; 
                        case 4: PORTB = 0x66; break;
                        case 5: PORTB = 0x6D; break; 
                        case 6: PORTB = 0x7D; break; 
                        case 7: PORTB = 0x07; break;
                        case 8: PORTB = 0x7F; break; 
                        case 9: PORTB = 0x6F; break; 
                        default : PORTB = 0X00; break;
                    } 

              if(segno==1)
                  {
                     PORTA = Seg4; 
                  } 
            if(segno==2)
                  {
                     PORTA = Seg3; 
                  } 
            if(segno==3)
                  {
                     PORTA = Seg2; 
                  } 
            if(segno==4)
                  {
                     PORTA = Seg1; 
                  } 
     }


void Delay(int k)
{
 int j;
for(j=0;j<k;j++);
}


void InitI2C(void)
{
    SDA_DIR = 1;        // Make SDA and 
    SCK_DIR =0;     // SCK pins input
    SSPCON = 0b00111000;            //enables port for i2c
    SSPCON2 = 0b00000000;
    SSPADD = 10;                    // 100KHz = 8MHz/4(SSPADD+1)
   // SSPSTAT = 0b11000000;     // Slew rate disabled

}

void i2c_waitForIdle(void)
{
    unsigned int i2ctimeout;

    while(1)
     {

        i2ctimeout++;
        if(i2ctimeout > 10)
            {
            i2ctimeout = 0;
            return;
            }   
     }
}

void I2C_Start(void)
{
    SEN = 1;            // Send start bit
    i2c_waitForIdle();
/*  while(!SSPIF);      // Wait for it to complete
    SSPIF = 0;          // Clear the flag bit*/

}

void I2C_ReStart(void)
{
    RSEN = 1;           // Send Restart bit
    i2c_waitForIdle();
/*  while(!SSPIF);      // Wait for it to complete
    SSPIF = 0;          // Clear the flag bit
    while(RSEN==1);*/
}


void I2C_Stop(void)
{
    PEN = 1;            // Send stop bit
    i2c_waitForIdle();
}


void I2C_Send_ACK(void)
{
    ACKDT = 0;          // 0 means ACK
    ACKEN = 1;          // Send ACKDT value
    i2c_waitForIdle();
}


void I2C_Send_NACK(void)
{
    ACKDT = 1;          // 1 means NACK
    ACKEN = 1;          // Send ACKDT value
    i2c_waitForIdle();
}


unsigned char I2C_Write( unsigned char i2cWriteData )
    {
    i2c_waitForIdle();
    SSPBUF = i2cWriteData;
    return (!ACKSTAT);                      // function returns '1' 
    }

int I2C_Read( unsigned char ack )
    {
    unsigned char i2cReadData;
     //unsigned int  i2cReadData;
    i2c_waitForIdle();
    RCEN = 1;
    SDA=1;
    SCK=1;
    i2c_waitForIdle();

    i2cReadData = SSPBUF;
    SCK=0;
    i2c_waitForIdle();
    SCK=1;
    if(ack)
        {
        ACKDT = 0;
        }
    else
        {
        ACKDT = 1;
        }
    ACKEN = 1;               // send acknowledge sequence

    return( i2cReadData );
    }

  unsigned int bcdtodecimal(unsigned int bcd) 
{
    unsigned int decimal;
    decimal = (((bcd & 0xF0) >> 4) * 10) + (bcd & 0x0F);
    return decimal;
}

void Init_ISL12022M(void) 
{
    I2C_Start(); // Start I2C communication
    I2C_Write(0XD0); //Write Device Address  
    I2C_Write(0X08); // 
    I2C_Write(0X41); // Write 0x00 to Control register to disable SQW-Out
    I2C_Stop(); // Stop I2C communication after initilizing
}


unsigned int  Write_ISL12022M(unsigned short address, unsigned short w_data)
 {
     I2C_Start(); // Start I2C communication
     I2C_Write(0XD0); 
     I2C_Write(address); //write address to write data
     I2C_Write(w_data); //write data into hexadecimal
     I2C_Stop();//stop I2C communication
     return(w_data);
}

unsigned short Read_ISL12022M(unsigned short address) 
{

    I2C_Start();
    I2C_Write(address); //address 0x68 followed by direction bit (0 for write, 1 for read) 0x68 followed by 0 --> 0xD0
    I2C_Write(address);
    I2C_ReStart();
    I2C_Write(0xD1); //0x68 followed by 1 --> 0xD1
    r_data=I2C_Read(0);
    I2C_Stop();
  return(r_data);
}

void SetDateTime()
{

        I2C_Start();   
        I2C_Write(0xD0);  
        I2C_Write(0x00); 
        sec= Write_ISL12022M(0X00, 12); //01 sec
        min = Write_ISL12022M(0X01,52); //01 sec
        hour = Write_ISL12022M(0X02,9); //01 sec
        day= Write_ISL12022M(0X03,7); //01 sec
        date = Write_ISL12022M(0X04, 29); //01 sec
        month =Write_ISL12022M(0X05,07); //01 sec
        year = Write_ISL12022M(0X06,17); //01 sec
        I2C_Stop();

}




void RTC_GetDateTime()
{
    I2C_Start();                            // Start I2C communication
    I2C_Send_ACK();
    sec = I2C_Read(1);                // read second and return Positive ACK
    I2C_Send_ACK();
    min = I2C_Read(1);                 // read minute and return Positive ACK
    I2C_Send_ACK();
    hour= I2C_Read(0);               // read hour and return Negative/No ACK
    I2C_Send_ACK();
    day = I2C_Read(1);           // read weekDay and return Positive ACK
    I2C_Send_ACK();
    date= I2C_Read(1);              // read Date and return Positive ACK
    I2C_Send_ACK();
    month=I2C_Read(1);            // read Month and return Positive ACK
    I2C_Send_ACK();
    year =I2C_Read(0);             // read Year and return Negative/No ACK
    I2C_Send_ACK();
    I2C_Stop();                              // Stop I2C communication after reading the Date
}


    void interrupt isr(void)
    {
             if(TMR1IF==1)
            {
                TMR1H=0xF6; // Load the time value(0xBDC) for 100ms delay
                TMR1L=0x18; //Timer1 Interrupt for 65000
                TMR1IF=0; // Clear timer interrupt flag
                Dgt++;

               if(Dgt>=5)
                 {
                    Dgt=0; 
                    LED=!LED;

                 } 

             }        

  }   


     void Timer1_Interrupt()
    {

     INTCON = 0b00000000;
     PIE1=0b00000001;
     PIR1=0x01;
     TMR1H=0x0B;
     TMR1L=0xDC; 
     T1CON=0x31;

    }

    void Init_Controller()
    {
    cnt=100;        
    TRISC=0b01000000;                           // Intialize INput & output pheripherals
    TRISB=0b10000000;
    PORTB = 0b00000000;
    TRISA=0b0000000;                            
    ADCON0 = 0b00000000;
    ANSEL = 0b00000000;
    Timer1_Interrupt();

    }

        void main(void)
     {

              Init_Controller();
             /* GIE=1;
              PEIE=1;
              TMR1IE=1; */
             InitI2C();   
             Init_ISL12022M();
              SetDateTime(); 

              while(1)

               {
                    RTC_GetDateTime();
                    SetSeg(year/ 10,2);
                    SetSeg(year%10,1);
               }

        }   
4

1 回答 1

0

像这样的行:

I2C_Write(0XD0); //Write Device Address

不是有效的设备地址。使用 0xDE(或 0xAE 用于用户 SRAM)

从数据表:

在启动条件之后,主机必须输出一个从机地址字节。7 个 MSB 是设备标识符。这些位是 RTC 寄存器的“1101111”和用户 SRAM 的“1010111”。

于 2017-08-03T14:40:58.717 回答