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.