From Tim's website
Jump to: navigation, search

PIC Software - clock.c for Hi-Tech

<source lang="c"> /* This version is written to use the Hi-Tech lite (free) compiler */

  1. include <htc.h>
  1. include "lcd.h"

/* Crystal oscillator, no low-voltage programming or watch dog timer */ __CONFIG(FOSC_XT & LVP_OFF & WDTE_OFF);

/* Define the hardware connections */

  1. define CLOCK_EN_LINE RB0 /* Enable device */
  2. define CLOCK_DATA_PIN 0 /* Clock Data connected to ADC pin 0 */
  3. define CLOCK_DATA_LED RB5 /* LED to show incomming pulses */
  4. define CLOCK_ERROR_LED RB4 /* LED to show error reading pulses */

const int THRESHOLD = 0x80;

enum PULSE_TYPE { PT_ERROR, /* Unidentified pulse */

                 PT_SHORT,    /* 100ms pulse           */
                 PT_LONG,     /* 200ms pulse           */
                 PT_FINISH,   /* 300ms pulse           */
                 PT_START,    /* 500ms  pulse          */
                 PT_DOUBLE};  /* Two short pulses      */


/* Global Variables */ int seconds = 0;

/* Functions */ enum PULSE_TYPE clock_get_pulse(); int clock_get_value( int no_of_pulses );

int read_adc() {

  ADCON0 = 5;
  while (ADCON0 == 5);
  return ADRESH;

}

enum PULSE_TYPE clock_get_pulse() /* Waits for the next pulse and returns the type of pulse */ /* this can be LONG, SHORT, START, DOUBLE or ERROR as */ /* defined in the enumeration above */ {

  int pulse_shape;
  int i;
  int factor;
  enum PULSE_TYPE result;
  
  /* Wait for the input to go high */
  while( read_adc() <= THRESHOLD );
  CLOCK_DATA_LED = 1;
  /* Wait for the input to go low  */
  while( read_adc() >= THRESHOLD );
  CLOCK_DATA_LED = 0;
  /* Increment the seconds and display */
  lcd_command( LCD_DD_ADD_L2 + 7 );
  if( ++seconds == 60 )
     seconds = 0;
  lcd_number( seconds );
  pulse_shape = 0;
  factor = 1;
  /* Record the shape of the pulse */
  _delay( 60000 );  /* after  60ms */
  for( i = 0; i < 5; i++ )
  {
     if( read_adc() < THRESHOLD )
     {
        CLOCK_DATA_LED = 0;
        pulse_shape += factor;
     }
     else
        CLOCK_DATA_LED = 1;
     /* After 160, 260, 360, 460 and 560ms */
     _delay( 100000 );
     factor = factor << 1;
  }
  /* Wait out some of the period, leaving 200 ms */
  _delay( 240000 );
  switch( pulse_shape )
  {
  case 1:
     result = PT_SHORT;
     break;
  case 3:
     result = PT_LONG;
     break;
  case 5:
     result = PT_DOUBLE;
     break;
  case 7:
     result = PT_FINISH;
     break;
  case 31:
     CLOCK_ERROR_LED = 1;
     result = PT_START;
     break;
  default:
     CLOCK_ERROR_LED = 0;
     result = PT_ERROR;
  }
  return result;

}


int clock_get_value( int no_of_pulses ) /* Collects the given number of pulses and returns the */ /* decimal value where the first pulse is the most MSB. */ /* Errors are interpreted as zero. */ {

  enum PULSE_TYPE pulse;
  int p;
  int value = 0;
  
  for( p = 0; p < no_of_pulses; p++ )
  {
     pulse = clock_get_pulse();
     switch( pulse )
     {
     case PT_LONG:
        value *= 2;
        value += 1;
        break;
     default:
        value *= 2;
        break;
     }
  }
  if (value > 9)
  {
     value = 0;
  }
  return value;

}

void main() /* This loop Waits for the start pulse and then decodes */ /* the following 51 pulses to get the time and date. */ {

  int i;
  int value1;
  int value2;
  const char please_wait[15] = "Please Wait...";
  const char day[25] = "SunMonTueWedThuFriSat???";
  const char month[58] = "???JanFebMarAprMayJunJulAugSepOctNovDec??????????????????";
  TRISB = 0b00000000;
  TRISC = 0b00000000;
  lcd_initialise( LCD_SIZE_SMALL );
  /* Enable the rugby clock */
  CLOCK_EN_LINE = 0;
  /* Put up the 'Please Wait...' message */
  for( i = 0; i < 14; i++ )
     lcd_character( please_wait[i] );
  seconds = 0;
  /* Wait for the current minute to finish */
  while( clock_get_pulse() != PT_FINISH );
  seconds = 54;
  /* Wait for the start pulse from the clock */
  while( clock_get_pulse() != PT_START );
  lcd_command( LCD_CLEAR );
  seconds = 0;
  while( 1 )
  {
     /* Count the number of double pulses and display */
     value1 = 0;
     for( i = 0; i < 8; i++ )
     {
        if( clock_get_pulse() == PT_DOUBLE )
           value1--;
     }
     for( i = 8; i < 16; i++ )
     {
        if( clock_get_pulse() == PT_DOUBLE )
           value1++;
     }
     lcd_command( LCD_DD_ADD_L2 + 11 );
     lcd_character( '(' );
     lcd_character( '+' );
     if( value1 < 0 )
     {
        lcd_command( LCD_SHFT_CUR_L );
        lcd_character( '-' );
        value1 = -value1;
     }
     lcd_character( '0' + value1 );
     lcd_character( ')' );
        
     /* Get the Year and display */
     value1 = clock_get_value( 4 );
     value2 = clock_get_value( 4 );
     lcd_command( LCD_DD_ADD_L1 + 11 );
     lcd_character( '2' );
     lcd_character( '0' );
     lcd_character( '0' + value1 );
     lcd_character( '0' + value2 );
     /* Get the Month and display */
     value1 = clock_get_value( 1 );
     value2 = clock_get_value( 4 );
     lcd_command( LCD_DD_ADD_L1 + 7 );
     value1 = 10 * value1 + value2;
     for( i = 0; i < 3; i++ )
        lcd_character( month[ 3 * value1 + i ] );
     /* Get the Date and display */
     value1 = clock_get_value( 2 );
     value2 = clock_get_value( 4 );
     lcd_command( LCD_DD_ADD_L1 + 4 );
     lcd_character( '0' + value1);
     lcd_character( '0' + value2);
     /* Get the Day and display */
     value1 = clock_get_value( 3 );
     lcd_command( LCD_DD_ADD_L1 + 0 );
     for( i = 0; i < 3; i++ )
        lcd_character( day[ 3 * value1 + i ] );
     /* Get the Hour and display */
     value1 = clock_get_value( 2 );
     value2 = clock_get_value( 4 );
     lcd_command( LCD_DD_ADD_L2 + 1 );
     lcd_character( '0' + value1 );
     lcd_character( '0' + value2 );
     lcd_character( ':' );
     /* Get the Minutes but wait for zero seconds */
     value1 = clock_get_value( 3 ); 
     value2 = clock_get_value( 4 );
     
     /* Wait for the current minute to finish */
     while( clock_get_pulse() != PT_FINISH );
     /* Wait for the start pulse from the clock */
     while( clock_get_pulse() != PT_START );
     seconds = 0;
     /* Display the minutes */
     lcd_command( LCD_DD_ADD_L2 + 4 );
     lcd_character( '0' + value1 );
     lcd_character( '0' + value2 );
  }

} </source>