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:
- Definir a hora do alarme ( endereços 0x09 até 0x0E )
- Configurar o modo do alarme ( bits 5 e 4 do registro de controle do alarme )
- 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:
- Definir um valor inicial do timer ( endereço 0x0F )
- Configurar o modo de contagem ( bits 2, 1 e 0 do registro de controle do alarme )
- Habilitar a interrupção do timer ( bit 3 do registro de controle do alarme )
BIBLIOTECA
MikroC PRO PIC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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 ); | |
} |
EXEMPLO
MikroC PRO PIC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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 ); | |
} | |
} |
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...
ResponderExcluirOlá Tiago,
ResponderExcluirSerá que me poderia ajudar a fazer um código deste género para um dsPIC33FJ64MC802?
Obrigado,
jm93