quarta-feira, junho 15, 2011

Projeto 'Epoch' - Parte3 - Software

Vamos começar a examinar o software pelas rotinas de interface do microcontrolador PIC com o módulo de relógio DS1302.

Como vimos na parte anterior, a ligação do DS1302 ao PIC é feita por três sinais: CE, SCLK e I/O. O sinal CE (chip enable) deve ser colocado em nível "1" para inicial uma operação e só ser retornado a "0" ao seu final. O sinal SCLK (serial clock) determina quando cada bit deve ser lido ou escrito na linha I/O. Os sinais CE e SCLK são sempre comandados pelo microcontrolador, o sinal I/O é bi-direcional.

As transferência de dados são compostas por bytes (8 bits). O primeiro byte de toda transferência é enviado do microcontrolador para o DS1302 e determina a operação que será realizada e endereça um registrador do relógio ou uma posição da memória Ram do DS1302:


Os bits são transferidos serialmente do menos significativo para o mais. Os bits devem ser enviados pelo transmissor na borda de descida de SCLK e lidos pelo receptor na borda de subida. A figura abaixo mostra os ciclos básicos de leitura e escrita de um byte:


O byte de comando possui 5 bits de endereçamento. No acesso ao relógio, existem 9 registradores; na Ram são 31 posições. Nos dois casos o endereço 11111 indica o modo burst. Neste modo, múltiplos bytes são transferidos com o endereço começando em zero e incrementando automaticamente a cada byte lido ou escrito. A figura abaixo mostra um resumo dos registradores e endereços:


Um cuidado necessário ao escrever nos registradores do relógio é que é preciso desprotegê-los primeiro (escrevendo 0 em WP).

Para concluir esta descrição do DS1302, vejamos o funcionamento do circuito de carga da bateria. O DS1302 alimenta a bateria a partir da sua própria alimentação (no caso 5V), podendo colocar em série 1 ou 2 diodos (para reduzir a tensão) e um dentre 3 resistores (para limitar a corrente):


A programação que usei coloque em série os dois diodos e a resistência de 2K. Desta forma, a tensão máxima será 5 - 2*0,7 = 3,6V e a máxima corrente (supondo a bateria totalmente zerada) será 3.6V / 2K = 1,8 mA.

Vamos, finalmente, ao código. As rotinas abaixo são responsáveis pelo envio e recepção de bytes:
  1. #define  DS1302_CE   PIN_B0  
  2. #define  DS1302_IO   PIN_B1  
  3. #define  DS1302_SCLK PIN_B2  
  4.   
  5. // Envia um byte ao DS1302  
  6. void DS1302_TxByte (byte b)  
  7. {  
  8.   int i;  
  9.    
  10.   set_tris_b (0xF8); // I/O é output  
  11.   for (i = 0; i < 8; i++)  
  12.   {  
  13.      if (b & 1)  
  14.         output_high (DS1302_IO);  
  15.      else  
  16.         output_low (DS1302_IO);  
  17.      delay_us (1);  
  18.      output_high (DS1302_SCLK);  
  19.      delay_us (1);  
  20.      output_low (DS1302_SCLK);  
  21.      b = b >> 1;  
  22.   }  
  23.   set_tris_b (0xFA); // I/O volta a ser input  
  24. }  
  25.   
  26. // Recebe um byte do DS1302  
  27. byte DS1302_RxByte ()  
  28. {  
  29.   int i;  
  30.   byte dado;  
  31.    
  32.   for (i = 0; i < 8; i++)  
  33.   {  
  34.      delay_us (1);  
  35.      dado = dado >> 1;  
  36.      if (input (DS1302_IO))  
  37.         dado |= 0x80;  
  38.      output_high (DS1302_SCLK);  
  39.      delay_us (1);  
  40.      output_low (DS1302_SCLK);  
  41.   }  
  42.   return dado;  
  43. }  
Usando estas rotinas, fica fácil implementar a leitura e escrita tanto em um registrador do relógio como em todos eles (modo burst):
  1. // Alguns registradores do DS1302  
  2. #define  DS1302_WP    0x0E  
  3. #define  DS1302_TC    0x10  
  4. #define  DS1302_CBURST 0x3E  
  5.   
  6. // Lê relogio em modo burst  
  7. void DS1302_ReadClock (byte *regs)  
  8. {  
  9.   byte i;  
  10.   
  11.   output_high (DS1302_CE);  
  12.   delay_us (4);  
  13.   DS1302_TxByte (DS1302_CBURST | 0x81);  
  14.   for (i = 0; i < 8; i++)  
  15.   {  
  16.      *regs++ = DS1302_RxByte ();  
  17.      delay_us (4);  
  18.   }  
  19.   output_low (DS1302_CE);  
  20. }  
  21.   
  22. // Escreve relogio em modo burst  
  23. void DS1302_WriteClock (byte *regs)  
  24. {  
  25.   byte i;  
  26.   
  27.   DS1302_Write (DS1302_WP, 0x00);  
  28.   DS1302_Write (DS1302_TC, 0xA9); // tricle charger, 2 diodes, 2Kohms  
  29.   
  30.   output_high (DS1302_CE);  
  31.   delay_us (4);  
  32.   DS1302_TxByte (DS1302_CBURST | 0x80);  
  33.   for (i = 0; i < 8; i++)  
  34.   {  
  35.      DS1302_TxByte (*regs++);  
  36.      delay_us (4);  
  37.   }  
  38.   output_low (DS1302_CE);  
  39. }  
  40.   
  41. // Lê um byte de um endereço do DS1302  
  42. byte DS1302_Read (byte ender)  
  43. {  
  44.   byte result;  
  45.    
  46.   output_high (DS1302_CE);  
  47.   delay_us (2);  
  48.   DS1302_TxByte (ender | 0x81);  
  49.   result = DS1302_RxByte ();  
  50.   delay_us (2);  
  51.   output_low (DS1302_CE);  
  52.   return result;  
  53. }  
  54.   
  55. // Escreve um byte em um endereço do DS1302  
  56. void DS1302_Write (byte ender, byte dado)  
  57. {  
  58.   output_high (DS1302_CE);  
  59.   delay_us (2);  
  60.   DS1302_TxByte (ender | 0x80);  
  61.   DS1302_TxByte (dado);  
  62.   delay_us (2);  
  63.   output_low (DS1302_CE);  
  64. }  

Nenhum comentário: