Página 1 de 1

Partilhando o I2C

MensagemEnviado: 04 Jan 2010 10:32
por antonio
Pessoal tudo bem!

Pessoal depois de algumas pesquisas sobre como partilhar o I2C com dois chips DS1307+DS1631 com o 16F877A não toh conseguindo.
Pesquisando aqui no Forum não achei nada para meu caso , vi que o colega "tcpipchip" tem algo pronto aqui(http://www.asm51.eng.br/phpbb/viewtopic ... hlight=i2c)mas o link não està mais no ar!

O negocio è o seguinte, eu estou tentando comunicar o DS1307+DS1631 com o 16F877A com o mesmo barramento e ou seja com ´soh dois pinos do 16F877A para os dois chips, eu penso que isto è possivel!

A biblioteca para o Ds1631 uso a que vem com o CCS e para o Ds1307 a que vai em baixo, mas de jeito ninhum funciona!? eu penso que serà o endereço que não està legal, mas não sei melhor não!?algem tem algo que possa ajudar?

O pessoal pode dar um jeito ?

Um abraço

Código: Selecionar todos
////////////////////////////////////////////////////////////////////////////////
///                               DS1307.C                                   ///
///                     Driver for Real Time Clock                           ///
///                                                                          ///
/// ds1307_init() - Enable oscillator without clearing the seconds register -///
///                 used when PIC loses power and DS1307 run from 3V BAT     ///
///               - Disable squarewave output                                ///
///                                                                          ///
/// ds1307_set_date_time(day,mth,year,dow,hour,min,sec)  Set the date/time   ///
///                                                                          ///
/// ds1307_get_date(day,mth,year,dow)               Get the date             ///
///                                                                          ///
/// ds1307_get_time(hr,min,sec)                     Get the time             ///
///                                                                          ///
////////////////////////////////////////////////////////////////////////////////

//#define RTC_SDA  PIN_C4
//#define RTC_SCL  PIN_C3

//#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)

BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);

void ds1307_init(void)
{
   BYTE seconds = 0;

   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x00);      // REG 0
   i2c_start();
   i2c_write(0xD1);      // RD from RTC
   seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307
   i2c_stop();
   seconds &= 0x7F;

   delay_us(3);

   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x00);      // REG 0
   i2c_write(bin2bcd(seconds));     // Start oscillator with current "seconds value
   i2c_start();
   i2c_write(0xD0);      // WR to RTC
   i2c_write(0x07);      // Control Register
   i2c_write(0x80);     // Disable squarewave output pin
   i2c_stop();

}

void ds1307_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min, BYTE sec)
{
  sec &= 0x7F;
  hr &= 0x3F;

  i2c_start();
  i2c_write(0xD0);            // I2C write address
  i2c_write(0x00);            // Start at REG 0 - Seconds
  i2c_write(bin2bcd(sec));      // REG 0
  i2c_write(bin2bcd(min));      // REG 1
  i2c_write(bin2bcd(hr));      // REG 2
  i2c_write(bin2bcd(dow));      // REG 3
  i2c_write(bin2bcd(day));      // REG 4
  i2c_write(bin2bcd(mth));      // REG 5
  i2c_write(bin2bcd(year));      // REG 6
  i2c_write(0x80);            // REG 7 - Disable squarewave output pin
  i2c_stop();
}

void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, BYTE &dow)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x03);            // Start at REG 3 - Day of week
  i2c_start();
  i2c_write(0xD1);
  dow  = bcd2bin(i2c_read() & 0x7f);   // REG 3
  day  = bcd2bin(i2c_read() & 0x3f);   // REG 4
  mth  = bcd2bin(i2c_read() & 0x1f);   // REG 5
  year = bcd2bin(i2c_read(0));            // REG 6
  i2c_stop();
}

void ds1307_get_time(BYTE &hr, BYTE &min, BYTE &sec)
{
  i2c_start();
  i2c_write(0xD0);
  i2c_write(0x00);            // Start at REG 0 - Seconds
  i2c_start();
  i2c_write(0xD1);
  sec = bcd2bin(i2c_read() & 0x7f);
  min = bcd2bin(i2c_read() & 0x7f);
  hr  = bcd2bin(i2c_read(0) & 0x3f);
  i2c_stop();

}

BYTE bin2bcd(BYTE binary_value)
{
  BYTE temp;
  BYTE retval;

  temp = binary_value;
  retval = 0;

  while(1)
  {
    // Get the tens digit by doing multiple subtraction
    // of 10 from the binary value.
    if(temp >= 10)
    {
      temp -= 10;
      retval += 0x10;
    }
    else // Get the ones digit by adding the remainder.
    {
      retval += temp;
      break;
    }
  }

  return(retval);
}


// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
  BYTE temp;

  temp = bcd_value;
  // Shifting upper digit right by 1 is same as multiplying by 8.
  temp >>= 1;
  // Isolate the bits for the upper digit.
  temp &= 0x78;

  // Now return: (Tens * 8) + (Tens * 2) + Ones

  return(temp + (temp >> 2) + (bcd_value & 0x0f));

MensagemEnviado: 04 Jan 2010 12:00
por ze
veja algumas rotinas que usei com sucesso há alguns anos. Note que são básicas ou seja não pra ler data e hora
especificamente. Passar os olhos pelo datashit num machuca muito. Use óculos. Veja nele os endereços e crie uns #define´s. As rotinas se resumem em i2cclockw(a,d) e i2cclockr(a). Entenda-se o parâmetro a como endereço do chip que contêm o dado d a ser lido/escrito
Também pode acessar a área de ram. Note a condição pra formatar o dado. Note o i2c_repStart().
Que o outro chip não tenha 0xd0 como end de acesso
Hitech-c
abç

Código: Selecionar todos
// inicialização do i2 no início do do main()
...
SSPCON1 = 0x38;      // set I2C master mode
CKE=0; // use I2C levels      worked also with '0'
SMP=0; // disable slew rate control  worked also with '0'
SSPCON2 = 0x00;
//SSPADD = 0x6;     // 400kHz bus with 10MHz xtal - use 0x0C with 20MHz xtal
SSPADD = 0x28;      // 100k at 4Mhz clock
//SSPADD=60; // 100k at 24Mhz clock = 24/4/60
//            PSPIF=0;      // clear SSPIF interrupt flag
BCLIF=0;      // clear bus collision flag
//------------
...

rotinas...

/******************************************************************************************/
void i2c_waitForIdle()
{
while ((SSPCON2 & 0x1F) | RW ); // wait for idle and not writing (PIC18F252)
//while ((SSPCON2 & 0x1F) | STAT_RW ); // wait for idle and not writing (PIC16F876A)
}
/******************************************************************************************/
void i2c_start()
{
i2c_waitForIdle();
SEN=1;
}
/******************************************************************************************/
void i2c_repStart()
{
i2c_waitForIdle();
RSEN=1;
}
/******************************************************************************************/
void i2c_stop()
{
i2c_waitForIdle();
PEN=1;
}
/******************************************************************************************/
unsigned char i2c_write( unsigned char i2cWriteData )
{
 i2c_waitForIdle();
 SSPBUF = i2cWriteData;
 return ( ! ACKSTAT  ); // function returns '1' if transmission is acknowledged
}
/******************************************************************************************/
unsigned char i2c_read( unsigned char ack )
{
 unsigned char i2cReadData;
 i2c_waitForIdle();
 RCEN=1;
 i2c_waitForIdle();
 i2cReadData = SSPBUF;
 i2c_waitForIdle();
 if (ack)
        {
        ACKDT=0;
        }
 else
        {
        ACKDT=1;
        }
ACKEN=1;               // send acknowledge sequence
return i2cReadData;
}

//**********************************************************************
unsigned char i2cclockr(unsigned char a)
{
unsigned char d,tmp;
i2c_start();
i2c_write(0xD0);//comando escreve relogio . Obs:cada fabr relógio tem seu byte de comando!
i2c_write(a); //endereço
i2c_repStart();
i2c_write(0xD1);//comando lê relogio
d=i2c_read(0); //lê o dado
i2c_stop();
if (a<7) //se for relógio formata o dado para decimal
   {
   tmp=d&0x0f;
   d>>=4;
   d*=10;
   d+=tmp;
   }
return d;
}
//------------------------------------------
i2cclockw(unsigned char a, unsigned char d)
{
unsigned char tmp;
if (a<7) //se for relógio, formata o dado para hexadecimal
   {
   tmp=d/10;
   d-=(tmp*10);
   tmp<<=4;
   d|=tmp;   
   }
i2c_start();
i2c_repStart();
i2c_write(0xD0);//comando escreve
i2c_write(a); //endereço
i2c_write(d); //dado
i2c_stop();
}


corrija o título e selecione seu fonte e clique em "Code"

MensagemEnviado: 04 Jan 2010 13:00
por antonio
Brigado Lellis, a correção foi jah feita!

Cara ...eu dei uma olhada no seu codigo e fiquei meio confuso! eu estudei o data e um pouca as bibliotecas dos bichi e no endereço de comunicação que è de ter am atenção ou seja se estiver a usar um I2C para dois despositivos o endereço não pode ser igual? acho que se referindo ao A2-A1-A0! que nao pode igual!

Neste monento não tenho mais ideia de como continuar!

Desde jah agradeço

MensagemEnviado: 04 Jan 2010 19:10
por Djalma Toledo Rodrigues
Comunicação individual (com cada um ) conseguiu ?

Colocou a R de Pull Up ?

DJ

MensagemEnviado: 05 Jan 2010 07:53
por antonio
Djalma Toledo Rodrigues escreveu:Comunicação individual (com cada um ) conseguiu ?

Colocou a R de Pull Up ?

DJ


Ola Djalma tudo bem!!

Não....Por enquanto ainad não consegui a comunicação individual não, e è isso que eu soh tentando conseguir!? mas nesto momento men ideia faço como conseguir !

As R de PullUp sim foi colocado nas linhas SDA SCL e o positivo de 47K cada,e tambem jà fiz experiencias com 10K, mas não funca não !

desde jà agradeço mais ajuda.

MensagemEnviado: 05 Jan 2010 08:01
por fabim
so tõen..
Cho perguntar.
Em separado as rotinas funcionam com os chipus ?
Ou seja, esta tudo funcionando em separado? as duas rotinas ?
Poderia colocar o main, do seu source aqui pra gente dar uma olhada.
não tem como não funcionar essa do DS.. ta certinha.

A não ser que você esteja esquecendo de inicializar o I2C, periferico..

Abraços

MensagemEnviado: 05 Jan 2010 10:34
por antonio
Fala...Cara.. eu estoh fazendo os testes em separado e funcionou sim!,mas quando foi tentar fazer o I2C para o dois chips na mesma linha do I2C não funciona tanto um como o outro chip!

Isto para uma questao de usar soh 2 pinos do micro, se realmente eh possivel fazer os 2 chips funcinar com a mesma linha do I2C?

Claro que posso por aqui o codigo pra vc dar uma olhada sim, as bibliotecas sao as que eu descrevi no primeiro poste!

Voce inclusive pode alterar o codigo a vontade !ok

Desde jah agradeço

Código: Selecionar todos
#include <16f877A.h>                                   
#use delay(clock=4000000)
#fuses XT,NOWDT,NOPROTECT,PUT,NOLVP,NOBROWNOUT                                                 
#use i2c(master,sda=PIN_D0,scl=PIN_D1)// pinos de comunicaçao I2C...Pic+DS1307+DS1631
#include <kbd4x4ABCD_PROTEUS.c> //teclado
#include <flex_lcd.c>
#include <DS1307.c> //RTC DS1307
//#include <DS1631.c>

#use standard_io (b)                                         
#use standard_io (a)
#use standard_io(c)                                                 
#use standard_io(D)                                                                         


void main()      //Funçao principal
{
  BYTE sec;
  BYTE min;
  BYTE hrs;                                                                         
  BYTE day;
  BYTE month;
  BYTE yr;
  BYTE dow;

     float value; 
 
 lcd_init();  // iniciar LCD                                   
    delay_ms(100);
                  init_temp();   // iniciar DS1631     
                     delay_ms(100);
     
                        ds1307_init(); // iniciar Ds1307
                     //  data -> 5. 1. 2010
                      // horario -> 10:00:55
                       ds1307_set_date_time(5,1,10,2,10,00,55);     
       
  while(1)
  {                                                                                       
 
   delay_ms(1000);                                                                       
   
    ds1307_get_date(day,month,yr,dow);                                                   
    ds1307_get_time(hrs,min,sec);                     
                                                                       
    lcd_gotoxy(2,1);
    printf(lcd_Putc,"\f%02u/\%02u/\%02u",day,month,yr);
   
    lcd_gotoxy(2,2);                                         
    printf(lcd_Putc,"\f%02u:\%02u:\%02u",hrs,min,sec);
                                                               
     {
      value = (float)read_full_temp();
      value /= 100.0;
      value=(value-32)/1.8;
      lcd_gotoxy(8,1);
      printf(lcd_putc,"\ftemp.%03.1f", value);                           
      delay_ms(100);
     }
     
   
  }                         
}

MensagemEnviado: 05 Jan 2010 10:40
por fabim
o primo, onde é que tu esta inicializando a interface I2C ?
tu ai pelo que vi, ja esta indo escrever ler etc... mais nada de inicializar o periferico I2C.

PAgina 7 pra frente,..
http://www.sparkfun.com/datasheets/Comp ... DS1307.pdf

o DS1307 tem endereço slave default 0;
coloque o sensor de temperatura para endereço 1;

quando for setar a comunicação para cada um, não se esqueça de o startbyte, setar endereço 0 para 1307 e 1 para o outro.

Abraços

MensagemEnviado: 05 Jan 2010 12:25
por antonio
fabim escreveu:o primo, onde é que tu esta inicializando a interface I2C ?
tu ai pelo que vi, ja esta indo escrever ler etc... mais nada de inicializar o periferico I2C.

PAgina 7 pra frente,..
http://www.sparkfun.com/datasheets/Comp ... DS1307.pdf

o DS1307 tem endereço slave default 0;
coloque o sensor de temperatura para endereço 1;

quando for setar a comunicação para cada um, não se esqueça de o startbyte, setar endereço 0 para 1307 e 1 para o outro.

Abraços


Fabim cada vez tou tomando mais bronca! eu não quero nada pronto não,mas esta meio dificil entender.

Então para inicializar o periferico I2C não eh esta linha de codigo aqui??->#use i2c(master,sda=PIN_D0,scl=PIN_D1)//
O pino D0 vai ligar ao SDA dos dois chips
O pino D1 vai ligar ao SCL dos dois chips

Quanto aos endereço dos chips no data, por o que estou percebendo Eh o seguinte!
Para o Ds1307;
i2c_write(0xD0);Ou seja 11010000 pra escrever
i2c_write(0xD1);ou seja 11010001 pra ler

Para o Ds1631;
i2c_write(0x90);Ou seja 10010000 pra escrever
i2c_write(0x91);Ou seja 10010001 pra ler

Por o que estou lendo e entendendo os dois chips tem endereços diferentes por isso deveria funcionar?não havendo nenhuma colisão!?

Fabim vc esvreveu isto ;
(coloque o sensor de temperatura para endereço 1;
quando for setar a comunicação para cada um, não se esqueça de o startbyte, setar endereço 0 para 1307 e 1 para o outro.)

Aqui não estou entendendo como fazer isto!

Mais uma vez agraeço

MensagemEnviado: 06 Jan 2010 17:17
por tcpipchip
Olhando o teu codigo, voce ainda nao incializou o ds1307 para ativar o relogio e calendário...por exemplo, o bit mais significativo do registrador segundos...

MensagemEnviado: 22 Out 2011 14:38
por mhagnumdw
Uma dúvida quanto ao DS1307... I2C...

Usei com sucesso o DS1307 com o PIC16F874A nos pinos C3/SCK/SCL e C4/SDI/SDA.

Pelo manual do CCS C, posso especificar outros pinos para o SCL e SDA.
Estou querendo usar o DS1307 nos pinos B0 e B1, então fiz:
#define RTC_SDA PIN_B0
#define RTC_SCL PIN_B1
#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)
Mas não deu certo. Vejo no Proteus que os pinos B0 e B1 mudam de estado enquanto enviando dados para o DS1307, mas hora e data do DS1307 não mudam. Também configurei a porta B como entrada, e nada.

O que pode ser?

--
MhagnumDw

MensagemEnviado: 22 Out 2011 15:38
por andre_luis
O DS1307 pressupõe que se dê um comando de Start para iniciar o oscilador do RTC ( bit 7 dos segundos )
http://datasheets.maxim-ic.com/en/ds/DS1307.pdf

Bit 7 of Register 0 is the clock halt (CH) bit. When this bit is set to 1, the oscillator is disabled. When cleared to 0, the oscillator is enabled.


Voce fez isso ?

+++

MensagemEnviado: 22 Out 2011 18:11
por mhagnumdw
Andre, estou usando o código postado pelo antonio no primeiro post. Eu havia baixado esse mesmo código do fórum do CCS.

Quanto ao que você perguntou, sim, está sendo feito. Veja o código no primeiro post e observe que as linhas abaixo em conjunto executam o que você me perguntou (beleza?):
Código: Selecionar todos
...
seconds = bcd2bin(i2c_read(0));
...
seconds &= 0x7F;
...
i2c_write(bin2bcd(seconds));
...


Como eu disse: funciona certinho ligando o SCL e SDA do DS1307 aos pinos C3 e C4 do PIC, respectivamente.

Mas, quando configuro para os pinos B0 e B1, deixa de funcionar. Por quê?

PS: PIC16F874A.
--
MhagnumDw

MensagemEnviado: 22 Out 2011 18:29
por mhagnumdw
Acaba de dar certo!
Foi uma bizonhada minha aqui... eu havia invertido os pinos SCL e SDA! :D
Valeu!

--
MhagnumDw