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