Display
O tratamento do display não é muito diferente daquilo que já fiz em outros projetos. Um vetor de 16 bytes armazena o valor a apresentar no display, na forma de um dígito por byte. A rotina de tratamento da interrupção de timer faz dois tratamentos:
- A cada segundo soma um ao valor a apresentar
- A cada três interrupções seleciona um par de dígitos (sinais S2 a S0 do display) e coloca os valores correspondentes nos sinais Ax e Bx. Reparar que a ordem de seleção dos dígitos é diferente nas duas metades.
- #define DISP_S0 PIN_C0
- #define DISP_S1 PIN_C1
- #define DISP_S2 PIN_C2
- #define TAXA_DISP 3 // taxa de varredura do display
- #define INTS_SEG 3906 // interrupções por segundo
- // valor a apresentar no display
- int8 valor[16];
- //////////////////////////////////////////////
- // Interrupcao de tempo real
- // Ocorre a cada 512 uSeg
- #int_RTCC
- void RTCC_isr()
- {
- static unsigned int16 cont_seg = INTS_SEG;
- static unsigned int8 cont_disp = TAXA_DISP;
- static unsigned int8 disp = 0;
- // Atualização da contagem de tempo
- if (--cont_seg == 0)
- {
- int8 i=15;
- while ((i > 0) && (++valor[i] == 10))
- valor[i--] = 0;
- cont_seg = INTS_SEG;
- }
- // Atualização do Display
- if (--cont_disp == 0)
- {
- // seleciona o digito atual
- if (disp & 1)
- output_high (DISP_S0);
- else
- output_low (DISP_S0);
- if (disp & 2)
- output_high (DISP_S1);
- else
- output_low (DISP_S1);
- if (disp & 4)
- output_high (DISP_S2);
- else
- output_low (DISP_S2);
- // coloca os valores
- output_a ((valor[15-disp] << 4) | valor[disp]);
- // passa para o dígito seguinte
- disp = (disp + 1) & 7;
- cont_disp = TAXA_DISP;
- }
- }
Comunicação Serial
A comunicação serial é feita usando as rotinas do compilador C da CSC. A operação de acerto do relógio é bem simples: envia-se um CR (enter) e o PIC responde com um prompt '>'. Em seguida deve ser enviada a data e hora no formato ddmmaahhmmss, finalizado por outro CR. Antes do CR final o valor pode ser editado através do backspace. O valor digitado é enviado ao relógio (sem consistências...).
- // Caracteres ASCII
- #define BS 8
- #define LF 10
- #define CR 13
- #define ESC 27
- // valor a programar no relogio (ddmmaahhmmss)
- int8 horario[12];
- // data/hora para o relogio
- byte relogio[8];
- // Trata comunicação com o PC
- void TrataUart (void)
- {
- char c;
- int i;
- if (kbhit())
- {
- c = getc();
- if (c != CR)
- return;
- output_high (LED);
- putchar (CR);
- putchar (LF);
- putchar ('>');
- i = c = 0;
- //ddmmaahhmmss
- while ((c != CR) || (i != 12))
- {
- c = getc();
- if ((c == ESC) || (c == 0))
- break;
- if ((c == BS) && (i > 0))
- {
- putchar(BS);
- putchar(' ');
- putchar(BS);
- i--;
- }
- else if ((i < 12) && (c >= '0') && (c <= '9'))
- {
- putchar(c);
- horario[i++] = c-'0';
- }
- }
- putchar (CR);
- putchar (LF);
- if (c != ESC)
- {
- relogio[0] = (horario[10] << 4) | horario[11];
- relogio[1] = (horario[8] << 4) | horario[9];
- relogio[2] = (horario[6] << 4) | horario[7];
- relogio[3] = (horario[0] << 4) | horario[1];
- relogio[4] = (horario[2] << 4) | horario[3];
- relogio[5] = 1;
- relogio[6] = (horario[4] << 4) | horario[5];
- relogio[7] = 0x80;
- for (i = 0; i < 8; i++)
- {
- putchar (hexa[relogio[i] >> 4]);
- putchar (hexa[relogio[i] & 0x0F]);
- putchar (' ');
- }
- putchar (CR);
- putchar (LF);
- DS1302_WriteClock (relogio);
- LoadClk ();
- }
- output_low (LED);
- }
- }
Iniciação do Relógio
Após um reset ou acerto do relógio, o valor a ser apresentado no display é preenchido com o valor correspondente à data e hora no relógio. Isto requer converter uma data e hora em uma contagem de segundos. Na biblioteca padrão do C existe a rotina mktime para isto, no meu caso precisei fazer "na unha":
- // Dias por mês 31 28 31 30 31 30 31 31 30 31 30
- const int dias[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
- // EPOCH0 - fundação do GHC em segundos após 1/1/2000 00:00:00
- #define EPOCH0 351549263L
- // Coloca no display o valor do relógio não volátil
- void LoadClk (void)
- {
- byte i, aux;
- unsigned int32 time;
- DS1302_ReadClock (relogio);
- if ((relogio[3] & 0x3F) == 0)
- {
- // não programado
- for (i = 0; i < 16; i++)
- {
- valor[i] = 0;
- }
- return;
- }
- // Zera os bits não implementados no timer
- relogio[0] &= 0x7F;
- relogio[1] &= 0x7F;
- relogio[2] &= 0x3F;
- relogio[3] &= 0x3F;
- relogio[4] &= 0x1F;
- // Converte valores BCD para binário
- for (i = 0; i < 7; i++)
- {
- relogio[i] = (relogio[i] >> 4) * 10 + (relogio[i] & 0x0F);
- }
- // Determina o número de dias nos anos inteiros
- // Na faixa 2000 a 2099 os anos divisíveis por 4 são bissextos
- // Cada grupo de 4 anos tem 3*365+366 dias
- time = ((unsigned int32) (relogio[6] >> 2)) * (3L*365L+366L);
- aux = (relogio[6] & 3);
- if (aux > 0)
- {
- time += 366;
- if (aux > 1)
- time += 365;
- if (aux > 2)
- time += 365;
- }
- // Soma os dias até a data atual
- time += dias[relogio[4]-1];
- if ((aux == 0) && (relogio[4] > 2))
- time++; // ano bissexto
- time += relogio[3]-1;
- // Soma as horas
- time = time*24UL + (unsigned int32) relogio[2];
- // Soma os minutos
- time = time*60UL + (unsigned int32) relogio[1];
- // Soma os segundos
- time = time*60UL + (unsigned int32) relogio[0];
- // Contar a partir do EPOCH0
- time -= EPOCH0;
- // coloca no valor do display
- disable_interrupts (INT_RTCC);
- for (i = 0; i < 16; i++)
- {
- valor[15-i] = time % 10L;
- time = time / 10L;
- }
- enable_interrupts (INT_RTCC);
- }
Para completar o programa fica faltando somente o Programa Principal e a iniciação do Hardware:
- // Ponto de entrada e loop principal
- void main (void)
- {
- InitHw ();
- LoadClk ();
- enable_interrupts(GLOBAL);
- for (;;)
- {
- TrataUart();
- }
- }
- // Iniciação do hardware
- void InitHw (void)
- {
- // Bota para correr
- setup_oscillator (OSC_8MHZ);
- // Dispositivos não usados
- setup_comparator(NC_NC);
- setup_vref(FALSE);
- setup_adc(ADC_OFF);
- // E/S
- set_tris_a (0x00); // RA0-RA7 output
- set_tris_b (0xFA); // RB0 e RB2 output
- set_tris_c (0xF0); // RC0-RC3 output
- output_low (LED);
- // Timer
- setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
- setup_timer_1(T1_DISABLED);
- enable_interrupts (INT_RTCC);
- // Uart
- while (kbhit())
- getc();
- }
O conjunto completo de arquivos para gerar o software, usando o ambiente MPLAB e o compilador PCM da CCS estão em Epoch.zip no SkyDrive que você acessa pelo ícone na lateral do blog.
Nenhum comentário:
Postar um comentário