Fork me on GitHub

Microcontrolandos

O Blog está passando por uma fase de mudanças. Todos os posts estão sendo atualizados, códigos, links e imagens estão sendo arrumados. Conteúdos novos ainda estão por vir.

PIC: PCF8583

Compartilhe:

PIC: PCF8583



O PCF8583 é um relógio/calendário e alarme digital da NXP Semiconductors com uma memória RAM de 256 x 8 bits, que controlado através de um microcontrolador, fornece data e hora em tempo real.

Utiliza o barramento I2C. Possui endereçamento selecionável através do pino A0, podendo assim, ligar até dois relógios no mesmo barramento.


O PCF8583 fornece informações do ano, mês, dia e dia da semana, hora, minuto, segundo e  centissegundo. Todos no formato BCD.

O endereço 0x00 é usado como um registro de controle e status. Os endereços de 0x01 até 0x07 são usados como contador para a função relógio. Os endereços de 0x08 até 0x0F podem ser programados como registro do alarme ou utilizado como memória RAM livre, quando o alarme está desativado.

CARACTERÍSTICAS

  • Barramento I2C;
  • Tensão de alimentação de 1.0V à 6.0V. Isso permite adicionar uma pequena bateria de backup de 3V no caso de ocorrer uma falha de energia;
  • Memória RAM de 256 x 8 bits;
  • Função relógio com 4 anos ( incluindo ano bissexto );
  • Formato de horas: 24h ou 12h ( AM/PM );
  • Alarme e Timer com interrupção programável.

REGISTRO DE CONTROLE E STATUS
Este registro contém as flags de interrupção do alarme e do timer, que são os bit 1 e 0, respectivamente. O bit 7 quando setado pausa o relógio. Os bits 5 e 4 configuram o clock. O bit 3 funciona como uma chave para habilitar/desabilitar todas as interrupções.

REGISTRO DE CONTROLE DO ALARME
Este registro contém a configuração de contagem do timer ( bits 2, 1 e 0 ). O bit 3 é usado para habilitar/desabilitar a interrupção do timer. Os bits 5 e 4 configuram o modo do alarme e o bit 7 habilita/desabilita a interrupção do alarme.

MODO ALARME
No modo alarme você define a hora para ele disparar. Quando a hora atual e a hora do alarme forem iguais uma interrupção será gerada, e a flag será setado. Esta flag deverá ser limpa via software. Para configurar como alarme você deve:

  1. Definir a hora do alarme ( endereços 0x09 até 0x0E )
  2. Configurar o modo do alarme ( bits 5 e 4 do registro de controle do alarme )
  3. Habilitar a interrupção do alarme ( bit 7 do registro de controle do alarme )
MODO TIMER
No modo timer você define um tempo para ele disparar. Esse tempo pode ser incrementado de segundos em segundos, ou minutos ou horas ou dias, configurando os bits 2, 1 e 0 do registro de controle do alarme. A contagem inicia a partir do valor definido pelo usuário até 99. Após isso ocorrerá um estouro, retornando a contagem para 0 e gerando uma interrupção. A flag também será setado. Esta flag deverá ser limpa via software, assim como o valor do timer. Para configurar o timer você deve:
  1. Definir um valor inicial do timer ( endereço 0x0F )
  2. Configurar o modo de contagem ( bits 2, 1 e 0 do registro de controle do alarme )
  3. Habilitar a interrupção do timer ( bit 3 do registro de controle do alarme )
BIBLIOTECA
MikroC PRO PIC
/*
PCF8583 - Clock and calendar with 240 x 8-bit RAM
Autor: Tiago
Compilador: MikroC PRO PIC
Criado em: 03/11/2014 por Tiago
Modificado em: 23/01/2015
- Possibilidade de trabalhar com dois PCF8583 no mesmo barramento
*/
/* Endereços disponíveis */
#define PCF8583_ADDR0 0b10100000
#define PCF8583_ADDR1 0b10100010
/* Registros */
#define PCF8583_CONTROL 0
#define PCF8583_MILISECONDS 1
#define PCF8583_SECONDS 2
#define PCF8583_MINUTES 3
#define PCF8583_HOURS 4
#define PCF8583_YEAR_DATE 5
#define PCF8583_WEEKDAY_MONTH 6
#define PCF8583_TIMER 7
#define PCF8583_ALARM_CONTROL 8
#define PCF8583_ALARM_MILISECONDS 9
#define PCF8583_ALARM_SECONDS 10
#define PCF8583_ALARM_MINUTES 11
#define PCF8583_ALARM_HOURS 12
#define PCF8583_ALARM_DATE 13
#define PCF8583_ALARM_MONTH 14
#define PCF8583_ALARM_TIMER 15
#define PCF8583_ALARM_RAM 16
/* Formato de hora */
#define PCF8583_FORMAT_24 0
#define PCF8583_FORMAT_12 1
/* Modos do timer */
#define PCF8583_TIMER_OFF 0
#define PCF8583_TIMER_CS 1
#define PCF8583_TIMER_SEC 2
#define PCF8583_TIMER_MIN 3
#define PCF8583_TIMER_HR 4
#define PCF8583_TIMER_DAY 5
/* Configurações do clock */
#define PCF8583_CLK_32768 0
#define PCF8583_CLK_50 1
#define PCF8583_CLK_EVENT_COUNTER 2
#define PCF8583_CLK_TEST 3
/* Funcionamento do clock */
#define PCF8583_CLK_START 0
#define PCF8583_CLK_STOP 1
#define PCF8583_CLK_TOGGLE 2
#define PCF8583_INT_ENABLE 1
#define PCF8583_INT_DISABLE 0
typedef struct
{
char Horas;
char Minutos;
char Segundos;
char Dia;
char Mes;
char Ano; //ano = 0 ( ano bissexto )
char DiaDaSemana;
char Milissegundos; //Centissegundos
union
{
char AM_PM : 1; // am ou pm
char F : 1; // formato de hora
};
}PCF8583;
/* Endereço do dispositivo */
extern char PCF8583_ADDRESS;
/* Rotinas */
void PCF8583_WriteRegister( char address, char value );
char PCF8583_ReadRegister( char address );
void PCF8583_Get_DateTime( PCF8583 * dt );
void PCF8583_Set_DateTime( PCF8583 * dt );
void PCF8583_Set_Alarm( PCF8583 *alarm );
void PCF8583_Set_Timer( char mode, char value );
char PCF8583_IsAlarm();
char PCF8583_IsTimer();
char PCF8583_Clock( char flag );
void PCF8583_Init( char ClockMode );
void PCF8583_Interrupt( char en );
/* Realiza a escrita para o registro */
void PCF8583_WriteRegister( char address, char value )
{
Soft_I2C_Start();
Soft_I2C_Write( PCF8583_ADDRESS );
Soft_I2C_Write( address );
Soft_I2C_Write( value );
Soft_I2C_Stop();
}
/* Realiza a leitura do registro */
char PCF8583_ReadRegister( char address )
{
char rData;
Soft_I2C_Start();
Soft_I2C_Write( PCF8583_ADDRESS );
Soft_I2C_Write( address );
Soft_I2C_Start();
Soft_I2C_Write( PCF8583_ADDRESS | 1 );
rData = Soft_I2C_Read(0);
Soft_I2C_Stop();
return rData;
}
/* Realiza a leitura da data e hora do relógio */
void PCF8583_Get_DateTime( PCF8583 * dt )
{
char i;
Soft_I2C_Start(); //Sinal de start
Soft_I2C_Write( PCF8583_ADDRESS ); //Seleciona o dispositivo com endereço 0, modo escrita
Soft_I2C_Write( PCF8583_MILISECONDS ); //Define o endereço inicial para leitura
Soft_I2C_Start(); //Restart
Soft_I2C_Write( PCF8583_ADDRESS | 1 ); ////Seleciona o dispositivo com endereço 0, modo leitura
dt->Milissegundos = Bcd2Dec( Soft_I2C_Read( 1 ) ); //Le os centissegundos
dt->Segundos = Bcd2Dec( Soft_I2C_Read( 1 ) ); //Le os segundos
dt->Minutos = Bcd2Dec( Soft_I2C_Read( 1 ) ); //Le os minutos
i = Soft_I2C_Read( 1 ); //Le as horas
dt->Horas = Bcd2Dec( i & ( dt->F ? 0x1F : 0x3F ) );
dt->AM_PM = i.B6;
dt->F = i.B7;
i = Soft_I2C_Read( 1 ); //Le o dia e ano
dt->Dia = Bcd2Dec( i & 0x3F );
dt->Ano = i >> 6;
i = Soft_I2C_Read(0); //Le o mes e dia da semana
Soft_I2C_Stop(); //Sinal de stop
dt->Mes = Bcd2Dec( i & 0x1F );
dt->DiaDaSemana = i >> 5;
}
/* Define a data e hora do relógio */
void PCF8583_Set_DateTime( PCF8583 * dt )
{
char i;
Soft_I2C_Start(); //Sinal de start
Soft_I2C_Write( PCF8583_ADDRESS ); //Seleciona o dispositivo com o endereço, modo escrita
Soft_I2C_Write( PCF8583_CONTROL ); //Define o endereço inicial para escrita
Soft_I2C_Write( 0x80 ); //Clock pausado
Soft_I2C_Write( Dec2Bcd( dt->Milissegundos ) ); //Define os centissegundos
Soft_I2C_Write( Dec2Bcd( dt->Segundos ) ); //Define os segundos
Soft_I2C_Write( Dec2Bcd( dt->Minutos ) ); //Define os minutos
i = Dec2Bcd( dt->Horas );
i.B6 = dt->AM_PM;
i.B7 = dt->F;
Soft_I2C_Write( i ); //Define as horas
i = ( dt->Ano << 6 ) | Dec2Bcd( dt->Dia );
Soft_I2C_Write( i ); //Define o dia e ano
i = ( dt->DiaDaSemana << 5 ) | Dec2Bcd( dt->Mes );
Soft_I2C_Write( i ); //Define o mes e dia da semana
Soft_I2C_Stop(); //Sinal de stop
PCF8583_Clock( PCF8583_CLK_START ); //Clock ativo novamente.
}
/* Define as horas do alarme */
void PCF8583_Set_Alarm( PCF8583 *alarm )
{
char i;
Soft_I2C_Start(); //sinal de start
Soft_I2C_Write( PCF8583_ADDRESS ); //seleciona o dispositivo com endereço 0, modo escrita
Soft_I2C_Write( PCF8583_ALARM_MILISECONDS ); //define o endereço inicial para escrita
Soft_I2C_Write( 0 ); //define os centissegundos
Soft_I2C_Write( Dec2Bcd( alarm->Segundos ) ); //define os segundos
Soft_I2C_Write( Dec2Bcd( alarm->Minutos ) ); //define os minutos
i = Dec2Bcd( alarm->Horas );
i.B6 = alarm->AM_PM;
i.B7 = alarm->F;
Soft_I2C_Write( i ); //define a hora
Soft_I2C_Write( 0 ); //define o dia
Soft_I2C_Write( 0 ); //define o mes
Soft_I2C_Stop();
i = PCF8583_ReadRegister( PCF8583_ALARM_CONTROL );
i &= 0b00001111;
i |= 0b10010000; //interrupçao do alarme habilitado
PCF8583_WriteRegister( PCF8583_ALARM_CONTROL, i );
}
// Define o tempo e o modo do timer */
void PCF8583_Set_Timer( char mode, char value )
{
char rData = PCF8583_ReadRegister( PCF8583_ALARM_CONTROL );
rData &= 0b11111000;
rData |= ( mode & 0x07 ); //configura o modo de contagem do timer
rData.B3 = 1; //habilita a interrupção do estouro do timer
PCF8583_WriteRegister( PCF8583_TIMER, Dec2Bcd( value ) ); //define o valor do timer
PCF8583_WriteRegister( PCF8583_ALARM_CONTROL, rData );
}
/* Verifica se a interrupção do alarme ocorreu */
char PCF8583_IsAlarm()
{
char rData = PCF8583_ReadRegister( PCF8583_CONTROL );
//tem que verificar se o alarme esta ativado!!
if( rData.B2 && rData.B1 )
{
rData.B1 = 0;
PCF8583_WriteRegister( PCF8583_CONTROL, rData );
return 1;
}
return 0;
}
/* Verifica se a interrupção do timer ocorreu */
char PCF8583_IsTimer()
{
char rData = PCF8583_ReadRegister( PCF8583_CONTROL );
//tem que verificar se o alarme esta ativado!!
if( rData.B2 && rData.B0 )
{
rData.B0 = 0;
PCF8583_WriteRegister( PCF8583_CONTROL, rData );
return 1;
}
return 0;
}
/* Configura o clock */
char PCF8583_Clock( char flag )
{
char rData = PCF8583_ReadRegister( PCF8583_CONTROL );
if( flag == 2 )
rData.B7 = ~rData.B7;
else
rData.B7 = flag.B0;
PCF8583_WriteRegister( PCF8583_CONTROL, rData );
return rData.B7;
}
/* Inicializa o RTC */
void PCF8583_Init( char clockMode )
{
char i = 0x04;
i.B4 = clockMode.B0;
i.B5 = clockMode.B1; //configura o clock
PCF8583_WriteRegister( PCF8583_CONTROL, i );
PCF8583_WriteRegister( PCF8583_ALARM_CONTROL, 0x00 );
}
/* Habilita ou desabilita a interrupção do alarme */
void PCF8583_Interrupt( char en )
{
char rData = PCF8583_ReadRegister( PCF8583_CONTROL );
rData.B2 = en.B0;
PCF8583_WriteRegister( PCF8583_CONTROL, rData );
}
view raw PCF8583.C hosted with ❤ by GitHub

EXEMPLO
MikroC PRO PIC
/*
PROJETO: RTC com PCF8583
MCU: PIC16F628A
COMPILADOR: MikroC PRO PIC
AUTOR: Tiago
Bibliotecas Utilizadas: PCF8583, Conversions, Eeprom, LCD, Software_I2C
Criado em: 03/11/2014
Modificado em: 23/01/2015
- Adicionado o endereço do dispositivo
*/
/* pinos do PCF8583 */
sbit Soft_I2C_Scl at RA0_bit;
sbit Soft_I2C_Sda at RA1_bit;
sbit Soft_I2C_Scl_Direction at TRISA0_bit;
sbit Soft_I2C_Sda_Direction at TRISA1_bit;
/* pinos do LCD */
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;
sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;
/* pinos dos botões */
sbit STOP at RA4_Bit;
sbit LED1 at RB6_Bit;
sbit LED2 at RB7_Bit;
/* variáveis */
PCF8583 rtc, alarm; //relógio e alarme
char msg[12]; //usado para armazenar a conversão de um número em string
char anoInicial = 12; //2012 foi ano bissexto
char PCF8583_ADDRESS = PCF8583_ADDR0; //Seleciona o dispositivo 0
void main()
{
CMCON = 7; //desliga o comparador analógico
//configura os pinos
TRISB.B6 = 0; //LED 1 como saida
PORTB.B6 = 0;
TRISB.B7 = 0; //LED 2 como saida
PORTB.B7 = 0;
TRISA.B4 = 1; //botao STOP como entrada
Soft_I2C_Init(); //iniclializa a comunicação I2C
Lcd_Init(); //iniclializa o display LCD
Lcd_Cmd( _LCD_CURSOR_OFF ); //desativa o cursor do LCD
/* Configura a data e hora */
rtc.Horas = 23;
rtc.Minutos = 59;
rtc.Segundos = 57;
rtc.Dia = 31;
rtc.Mes = 12;
rtc.Ano = 3; //2012 + 3 = 2015
rtc.DiaDaSemana = 2;
rtc.F = 0; //formato 24h
/* Configura o alarme */
alarm.Horas = 11;
alarm.Minutos = 0;
alarm.Segundos = 0;
alarm.F = 0;
PCF8583_Init( PCF8583_CLK_32768 ); //Inicializa o RTC com cristal de 32768Hz
PCF8583_Set_DateTime( &rtc ); //Define a data e hora
PCF8583_Set_Alarm( &alarm ); //Define o alarme
PCF8583_Set_Timer( PCF8583_TIMER_SEC, 40 ); //Define o timer com tempo de 60s ( 100 - 40 )
PCF8583_Interrupt( 1 ); //Habilita a interrupção do PCF8583
while(1)
{
PCF8583_Get_DateTime( &rtc ); //le a data e hora
//ajusta o ano, quando o ano for bissexto ( rtc.ano == 0 )
//somar mais 4 ano ao 'anoIncical'.
//utilzei varias comparações para evitar ficar perdendo tempo lendo a eeprom
//as horas devem estar no formato 24h
if( !rtc.Horas && !rtc.Minutos&& !rtc.Segundos && !rtc.Ano && ( EEPROM_Read(0) != anoInicial ) )
{
anoInicial += 4;
EEPROM_Write( 0, anoInicial ); //armazena o ano atual
}
/* Converte as horas, minutos e segundos para string e escreve no LCD */
ByteToStr( rtc.Horas, msg );
ByteToStr( rtc.Minutos, msg+3 );
ByteToStr( rtc.Segundos, msg+6 );
msg[3] = ':';
msg[6] = ':';
if( msg[4] == ' ' ) msg[4] = '0';
if( msg[7] == ' ' ) msg[7] = '0';
Lcd_Out( 1, 5, msg+1 );
/* Converte o dia, mes e ano para String e escreve no LCD */
ByteToStr( rtc.Dia, msg );
ByteToStr( rtc.Mes, msg+3 );
ByteToStr( anoInicial + rtc.Ano, msg+6 );
msg[3] = '/';
msg[6] = '/';
if( msg[4] == ' ' ) msg[4] = '0';
if( msg[7] == ' ' ) msg[7] = '0';
Lcd_Out( 2, 5, msg+1 );
if( !STOP ) //Botao STOP foi pressionado
{
LED1 = 0; // Desliga o LED 1
LED2 = 0; // Desliga o LED 2
}
if( PCF8583_IsTimer() ) //Ocorreu a interrupção do timer
{
PCF8583_Set_Timer( PCF8583_TIMER_SEC, 40 ); //Recarrega o timer
STOP = 1; //Acende o LED 2
}
if( PCF8583_IsAlarm() ) //Ocorreu a interrupção do alarme
LED1 = 1; //Acende o LED 1
Delay_ms( 200 );
}
}
view raw PCF8583_demo.C hosted with ❤ by GitHub

Escreva um comentário

2 comentários:

  1. oi Tiago os teus codigo fonte são fixe, tenho testado quase todos e dão sempre certo... ola aprendi a programar o pic com voce e hoje tenho criado muitos projectos... obrigado...

    ResponderExcluir
  2. Olá Tiago,
    Será que me poderia ajudar a fazer um código deste género para um dsPIC33FJ64MC802?
    Obrigado,
    jm93

    ResponderExcluir