Por fim encerraremos o tópico de comunicação I²C utilizando neste artigo o RTC DS1340 como exemplo, com toda parte de rotinas de comunicação feita, basta enviar os dados necessários para comunicação com dispositivo, antes disso, uma breve descrição do que faz um RTC, e finalizando com as rotinas necessárias para a implementação.
Um relógio de tempo real (RTC ou real-time clock, em inglês) é um relógio de computador que mantém o controle do tempo presente. Os RTCs estão presentes na maioria dos dispositivos eletrônicos que precisam manter um controle preciso do tempo.
Os benefícios de usar um RTC podem ser o baixo consumo de energia, liberar o sistema principal para tarefas mais críticas, maior precisão e costumam ter uma fonte de energia alternativa, podendo continuar a contagem do tempo enquanto a fonte principal está desligada.
Para o nosso exemplo iremos usar o DS1340 da Maxim, que entre outras características comuns aos RTCs tem um carregador (trickle-charge) para bateria, o relógio fornece um calendário completo, detecta falhas de energia e muda automaticamente para a fonte de backup, calibração via software.
O DS1340 suporta o barramento I²C bidirecional e o protocolo de transmissão dados. Um dispositivo que manda dados pelo barramento é definido como transmissor. O Dispositivo que controla as mensagens é o mestre.
Os dispositivos que são controlados pelo mestre são considerados escravos. O dispositivo mestre é que gera o relógio serial (SCL - serial clock), controla o acesso ao barramento e gera as condições de INICIO E PARADA que controlam o barramento.
O DS1340 opera como escravo no barramento da I²C. Conexões ao barramento são feitas pelas portas de entrada/saída SDA e SCL. Dentro das especificações do barramento o modo padrão (taxa máxima de 100khz) e modo rápido (taxa máxima de 400khz) estão definidos.
O seguinte protocolo de barramento foi definido:
1.                     Transferência de dados somente poderá ser iniciada quando o barramento não estiver ocupado.
2.                      Durante a transferência de dados, a linha de dados deve se manter estável enquanto a linha do relógio (clock) estiver alta. Mudanças na linha de dados enquanto a linha do relógio estiver alta será interpretada como sinais de controle.
Apenas duas rotinas serão necessárias para termos o básico da utilização, como extra incluiu uma terceira rotina para configurar o tricle-charge.
MAPA DE ENDEREÇAMENTO
| End. | Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0 | Função | Faixa | 
| 00H | EOSC | 10   SECONDS | SECONDS | SECONDS | 0-59 | |||||
| 01H | X | 10   MINUTES | MINUTES | MINUTES | 0-59 | |||||
| 02H | CEB | CB | 10 HOURS | HOURS | CENT/HOUR | 0-1;0-23 | ||||
| 03H | X | X | X | X | X | DAY | DAY | 01-07 | ||
| 04H | X | X | 10DATE | DATE | DATE | 01-31 | ||||
| 05H | X | X | X | 10MONTH | MONTH | MONTH | 01-12 | |||
| 06H | 10 YEAR | YEAR | YEAR | 00-99 | ||||||
| 07H | OUT | FT | S | CAL4 | CAL3 | CAL2 | CAL1 | CAL0 | CONTROL | |
| 08H | TCS3 | TCS2 | TCS1 | TCS0 | DS1 | DS0 | ROUT1 | ROUT0 | T.CHARGER | |
| 09H | OSF | 0 | 0 | 0 | 0 | 0 | 0 | 0 | FLAG | |
| typedef struct tagPERIODO {     int iDia;     int iMes;     int iAno;     int iHor;     int iMin;     int iSeg; }SPERIODO; #define  ADDRTC          0xD0             typedef enum tagADD_REG     {                   eSECONDS,                       // 0x00           eMINUTES,                       // 0x01                eHOUR,                          // 0x02         eDAY,                           // 0x03         eDATE,                          // 0x04         eMONTH,                         // 0x05         eYEAR,                          // 0x06           eCONTROL,                       // 0x07           eTRICKLE_CHARGER,               // 0x08         eFLAG                           // 0x09     }ADD_REG;     | 
| Propósito | Carregar no DS1340 os novos dados de   data e hora | 
| Parâmetros | ptrSP - ponteiro da estrutura com a   nova informação de data e hora | 
| Retorno | 1 - SUCESSO - atualizou os   registradores de data e hora do DS1340 0 - ERRO - a informação não foi salva | 
| Protocolo |     Condições de Start e Stop são reconhecidas como o inicio e fim da   transferência serial. O hardware faz o reconhecimento do endereço após   receber o byte com endereço do dispositivo escravo e o bit de direção.      O byte com endereço do dispositivo escravo é o primeiro a ser recebido   após o dispositivo mestre ter gerado a condição de START.     O byte de endereço do dispositivo escravo contem o endereço de 7 bits   do DS1340, que é 1101 000, seguido pelo bit de direção (R/W),  que é 0 para escrita. Após enviar o   byte de endereço o DS1340 responde com uma confirmação, logo em seguida envia   o endereço do registrador a ser acessado do DS1340 com o mesmo confirmando.     Isto configura o DS1340 a apontar para o registrador desejado, o   dispositivo mestre pode então transmitir os bytes de dados, com o DS1340   confirmando cada byte. O ponteiro do registrador incrementa a cada byte   transferido.     Para terminar a escrita de dados o dispositivo mestre deve gerar uma   condição de STOP. | 
| Descrição | Inicia a comunicação com o   dispositivo, e o 1º passo é configurar o bit EOSC.       O bit 7 do registrador 0 é o que habilita oscilador (EOSC):                 1 - o oscilador fica   desabilitado.                  0 - o oscilador fica   habilitado. Após ajustar os valores de Hexa para   BCD (formato usado pelo DS1340), inicia o 2º passo ao escrever a informação   de tempo e calendário acessando os registradores apropriados.   Por fim acessa o registrador de flag para   limpar o OSF.       O bit OSF(Oscilator Stop Flag):                 0 - Oscilador não parou.                 1 - indica se o oscilador   parou ou esteve parado por algum período, usado para verificar a validade da   hora e do calendário. | 
| BOOL ds1340_AtualizaRelogio(SPERIODO   *ptrSP) {     SPERIODO sTemp;     BOOL bOk = TRUE;     // primeiro passo habilita o oscilador     i2c_Start();                 bOk = i2c_Write(ADDRTC); // endereco do escravo + hab escrita     if  (bOk)    bOk = i2c_Write(eSECONDS); //end. do 1ºregistrador     if (bOk)    bOk =   i2c_Write(0x00);// zero no segundo, limpa o bit   EOSC     i2c_Stop();     if (bOk)   {         // leituras   estaoh em Hexa, para o RTC muda para BCD         sTemp.iSeg =   ByteHexToBcd(ptrSP->iSeg);         sTemp.iMin = ByteHexToBcd(ptrSP->iMin);         sTemp.iHor =   ByteHexToBcd(ptrSP->iHor);         sTemp.iDia =   ByteHexToBcd(ptrSP->iDia);         sTemp.iMes =   ByteHexToBcd(ptrSP->iMes);         sTemp.iAno =   ByteHexToBcd(ptrSP->iAno);     }     // a partir   daqui carregamos a data e hora passada     i2c_Start();     if  (bOk)    bOk = i2c_Write(ADDRTC);// endereco do escravo + hab escrita     if  (bOk)    bOk = i2c_Write(eSECONDS); // endereco dos segundos     if  (bOk)    bOk = i2c_Write(sTemp.iSeg); // segundo     if (bOk)      bOk = i2c_Write(sTemp.iMin); // minuto                if (bOk)      bOk = i2c_Write(sTemp.iHor); // hora     if (bOk)    bOk =   i2c_Write(0x01);       // dia da semana(naoh usado)            if  (bOk)    bOk = i2c_Write(sTemp.iDia); // dia                                                          if (bOk)      bOk = i2c_Write(sTemp.iMes); // mes           if (bOk)      bOk = i2c_Write(sTemp.iAno); // ano           if (bOk)      bOk = i2c_Write(0x40);       // controle          i2c_RepeatedStart();     if (bOk)      bOk = i2c_Write(ADDRTC);// endereco do   escravo + hab escrita     if (bOk)      bOk = i2c_Write(eFLAG); // aponta para o   flag do DS1340     if (bOk)      bOk = i2c_Write(0x00);// limpa o bit do OSF     i2c_Stop();     return  bOk; }             | 
| Propósito | Carregar no Dspic as informações de   data e hora do RTC | 
| Parâmetros | ptrSP - ponteiro de uma estrutura para   armazenar a data e hora | 
| Retorno | 1 - SUCESSO - conseguiu carregar a informação   de data e hora 0 - ERRO - falha ao tentar carregar informação | 
| Protocolo | O primeiro byte é recebido e   manipulado da mesma forma que no modo de escrita. Entretanto, neste modo, o   bit de direção indica que direção da transferência está invertida. O DS1340 transmite dados pela linha   SDA, enquanto o dispositivo mestre controla o pulso pela linha SCL. Condições de Start e Stop são   reconhecidas como o inicio e fim da transferência serial. O hardware faz o   reconhecimento do endereço após receber o byte com endereço do dispositivo   escravo e o bit de direção. O byte com endereço do dispositivo   escravo é o primeiro a ser recebido após o dispositivo mestre ter gerado a condição   de START. O byte de endereço do dispositivo   escravo contem o endereço de 7 bits do DS1340, que é 1101 000, seguido pelo   bit de direção (R/W), que é 1 para leitura. Após enviar o byte de endereço o   DS1340 responde com uma confirmação. A partir de então o DS1340 fica   configurado para transmitir dados e inicia a mesma, usando os dados indicados   pelo ponteiro do registrador, se o ponteiro do registrador não foi escrito   antes de configurar o modo de leitura, ele usara o ultimo endereço   armazenado. Para terminar a leitura de dados o   dispositivo mestre deve enviar para o DS1340 uma não confirmação NACK seguido   por uma condição de STOP. | 
| Descrição | O 1º passo é certificar-se de que o   ponteiro de registradores tem o endereço desejado, para isso, escrevemos a   posição desejada Seguindo para o 2º passo, começamos a leitura, adicionando o   bit De direção de transferência ao endereço do DS1340. Conforme as leituras forem executadas   armazena a informação lida na estrutura correspondente. Após comunicar com o RTC DS1340 pelo   protocolo do I²C, ajusta o formato dos valores de data e hora lidos como BCD,   para o formato usado pelo Dspic. | 
| BOOL   ds1340_CarregaRelogio(SPERIODO *ptrSP) {     BOOL bOk = TRUE;     ptrSP->iSeg =   0;     ptrSP->iMin   = 0;     ptrSP->iHor = 0;     ptrSP->iDia = 1;     ptrSP->iMes = 1;     ptrSP->iAno = 0;     //   primeiro,carrega no ponteiro de registradores, o endereco desejado     i2c_Start();     if (bOk)      bOk = i2c_Write(ADDRTC);  //escravo + hab escrita     if (bOk)    bOk =   i2c_Write(eSECONDS);//endereco do 1ºRegistrador do   RTC     // segundo,   inicia o procedimento de leitura     i2c_RepeatedStart();     if (bOk)      bOk = i2c_Write(ADDRTC | 1);//  escravo + hab leitura     if (bOk) {         ptrSP->iSeg = i2c_Read(ACK);// le os dados no endereco passado         ptrSP->iMin = i2c_Read(ACK);           ptrSP->iHor = i2c_Read(ACK);           i2c_Read(ACK);           ptrSP->iDia = i2c_Read(ACK);           ptrSP->iMes = i2c_Read(ACK);           ptrSP->iAno = i2c_Read(NACK);     }     i2c_Stop();     // ajusta os   valores lidos eliminando     // as   informacoes desnescessarias                                //                 ____     ptrSP->iSeg &= 0x7F;// elimina o bit 7 EOSC, da leitura     ptrSP->iHor &= 0x3F;// elimina os bits 7 e 6, indicacao seculo (CEB e CB)     // as leituras   estaoh em formato BCD, modifica o horario para Hexa     ptrSP->iSeg =   ByteBcdToHex(ptrSP->iSeg);     ptrSP->iMin =   ByteBcdToHex(ptrSP->iMin);     ptrSP->iHor =   ByteBcdToHex(ptrSP->iHor);     ptrSP->iDia =   ByteBcdToHex(ptrSP->iDia);     ptrSP->iMes =   ByteBcdToHex(ptrSP->iMes);     ptrSP->iAno = ByteBcdToHex(ptrSP->iAno);     return  bOk; }  | 
REGISTRADOR DE CARGA FLUTUANTE
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | |
| tcs 3 | tcs 2 | tcs 1 | tcs 0 | ds 1 | ds 0 | rout 1 | rout 0 | função | 
| x | x | x | x | 0 | 0 | x | x | desabilitado | 
| x | x | x | x | 1 | 1 | x | x | Desabilitado | 
| x | x | x | x | x | x | 0 | 0 | Desabilitado | 
| 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | sem diodo,   250 resistor | 
| 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | um diodo,   250 resistor | 
| 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | sem diodo,   2k resistor | 
| 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | um diodo,   2k resistor | 
| 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | sem diodo, 4k resistor | 
| 1 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | um diodo, 4k resistor | 
| 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | Valor ao   iniciar | 
| #define HABILITA_CARGA_FLUTUANTE        1 //#define HABILITA_CARGA_FLUTUANTE          0 //#define USA_DIODO                         1 #define USA_DIODO                       0 #define RESISTOR                        250 //#define RESISTOR                          2000 //#define RESISTOR                          4000 #ifndef HABILITA_CARGA_FLUTUANTE     #error  "CARGA FLUTUANTE DO DS1340 NAO CONFIGURADO" #elif (HABILITA_CARGA_FLUTUANTE == 1)     #define  TCS_CONFIG      0xA     // 1010         #elif (HABILITA_CARGA_FLUTUANTE == 0)     #define  TCS_CONFIG      0x0 #else     #error  "VALOR INVALIDO PARA HABILITAR CARGA FLUTUANTE" #endif #ifndef USA_DIODO     #error  "USO DE DIODO NAO CONFIGURADO" #elif (USA_DIODO == 1)     #define DS_CONFIG      0x2        // 10 #elif (USA_DIODO == 0)     #define  DS_CONFIG      0x1      // 01     #else     #error  "VALOR INVALIDO PARA CONFIGURAR DIODO" #endif #ifndef RESISTOR     #error  "USO DE RESISTOR NAO CONFIGURADO" #elif  (RESISTOR == 250)     #define ROUT_CONFIG      0x1        // 01 #elif  (RESISTOR == 2000)     #define ROUT_CONFIG      0x2        // 10 #elif  (RESISTOR == 4000)     #define ROUT_CONFIG      0x3        // 11 #else     #error  "VALOR INVALIDO PARA CONFIGURAR RESISTOR" #endif #define TRICKLE_CHARGER_CFG   (TCS_CONFIG << 4 | DS_CONFIG << 2 | ROUT_CONFIG) | 
| Propósito | Configurar o controle de carga da   bateria usada pelo DS1340 | 
| Parâmetros | nenhum | 
| Descrição | O RTC possui um registrador que   controla a flutuante, o registrador possui os seguintes bits acessíveis:      TCS (Trickle Charger Select) <7:4> - controlam a seleção da   carga flutuante que para evitar acionamento acidental, aceita somente como   entrada 1010 para ser habilitado.     DS   (Diode Select) <3:2> - configura se existe algum diodo conectado entre   o Vcc e Vbackup.              01 - sem diodo            10 - com diodo      ROUT (Resistor OUT) <1:0> - Selecionam o valor do resistor   conectado entre o Vcc e Vbackup.            01 - 250 resistor            10 - 2k resistor            11 - 4k resistor | 
| void ds1340_CfgCargaFlutuante(void) {     i2c_Start();     i2c_Write(ADDRTC);              //   endereco do escravo + hab escrita     i2c_Write(eTRICKLE_CHARGER);    // carrega endereco   do controle de carga     i2c_Write(TRICKLE_CHARGER_CFG); // configuracao o carregador flutuante     i2c_Stop(); }            | 
Finalizamos o assunto que foi iniciado em postagens anteriores, o assunto era amplo e por isso a necessidade de fragmentar o assunto,  lembrando que esse exemplo de comunicação entre dispositivos pode ser feito também através de uma SPI, mas isso é assunto para uma próxima postagem, até breve.






 
0 comentários:
Postar um comentário