From Tim's website
Jump to: navigation, search

PIC Software - clock.c for CCS

<source lang="c"> /* Device header and CCS compiler directives */

  1. include <16f873.h>
  1. device ICD=TRUE /* Incase we use the ICD */
  2. device ADC=8 /* Only use the 8 MSBs */
  3. use delay( clock=4000000 ) /* Set for a 4MHz Clock */

/* Include the code for the LCD display */

  1. include "lcd.c"


/* Define the hardware connections */ const int CLOCK_EN_LINE = PIN_B0; /* Enable device */ const int CLOCK_DATA_PIN = 0; /* Clock Data connected to ADC pin 0 */ const int CLOCK_DATA_LED = PIN_B5; /* LED to show incomming pulses */ const int CLOCK_EROR_LED = PIN_B4; /* LED to show error reading pulses */

const int THRESHOLD = 0x80;

enum PULSE_TYPE { PT_ERROR, /* Unidentified pulse */

                 PT_SHORT,    /*  75ms to 175ms pulse  */
                 PT_LONG,     /* 175ms to 375ms pulse  */
                 PT_DOUBLE,   /* Two short pulses      */
                 PT_START};   /* 375ms to 600ms pulse  */


/* Global Variables */ int seconds = 0;

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


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;
  
  set_adc_channel( CLOCK_DATA_PIN );
  output_low( CLOCK_DATA_LED );
  /* Wait for the input to go high */
  while( TRUE )
  {
     if( read_adc() > THRESHOLD )
        break;
  }
  output_high( CLOCK_DATA_LED );
  /* Wait for the input to go low  */
  while( TRUE )
  {
     if( read_adc() < THRESHOLD )
        break;
  }
  output_low( CLOCK_DATA_LED );
  /* Increment the seconds and display */
  lcd_command( LCD_DD_ADD_L2 + 7 );
  if( ++seconds == 60 )
     seconds = 0;
  lcd_number( seconds );
  pulse_shape = 0;
  factor = 2;
  /* Record the shape of the pulse */
  delay_ms( 70 );   /* after  70ms */
  if( read_adc() < THRESHOLD )
  {
     output_low( CLOCK_DATA_LED );
     pulse_shape += 1;
  }
  else
     output_high( CLOCK_DATA_LED );
  for( i = 0; i < 3; i++ )
  {
     /* After 170, 270 and 370ms */
     delay_ms( 100 );
     if( read_adc() < THRESHOLD )
     {
        output_low( CLOCK_DATA_LED );
        pulse_shape += factor;
     }
     else
        output_high( CLOCK_DATA_LED );
     factor *= 2;
  }
  /* Wait out the rest of the period */
  if( read_adc() > THRESHOLD )
     delay_ms( 600 );
  switch( pulse_shape )
  {
  case 0:
  case 2:
  case 4:
  case 8:
     output_low( CLOCK_EROR_LED );
     return PT_ERROR;
  case 1:
     return PT_SHORT;
  case 3:
  case 7:
     return PT_LONG;
  case 5:
     return PT_DOUBLE;
  case 15:
     /* Check the low ends after 500ms */
     delay_ms( 230 );   /* after 600ms */
     if( read_adc() < THRESHOLD )
     {
        output_low( CLOCK_EROR_LED );
        return PT_ERROR;
     }
     else
     {
        output_high( CLOCK_DATA_LED );
        output_high( CLOCK_EROR_LED );
        return PT_START;
     }
  }
  return PT_ERROR;

}


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. */ /* 255 is returned as an error. */ {

  PULSE_TYPE pulse;
  int p;
  int value = 0;
  
  for( p = 0; p < no_of_pulses; p++ )
  {
     pulse = clock_get_pulse();
     switch( pulse )
     {
     case PT_SHORT:
        value *= 2;
        break;
     case PT_LONG:
        value *= 2;
        value += 1;
        break;
     default:
        return 255;
     }
  }
  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;
  char please_wait[15] = "Please Wait...";
  char day[22] = "SunMonTueWedThuFriSat";
  char month[40] = "   JanFebMarAprMayJunJulAugSepOctNovDec";
  setup_counters( RTCC_INTERNAL, RTCC_DIV_256 );
  setup_adc( ADC_CLOCK_INTERNAL );
  setup_adc_ports( ALL_ANALOG );
  lcd_initialise( LCD_SIZE_SMALL );
  /* Enable the rugby clock */
  output_low( PIN_B0 );
  /* Put up the 'Please Wait...' message */
  for( i = 0; i < 14; i++ )
     lcd_character( please_wait[i] );
  seconds = 0;
  /* Wait for the start pulse from the clock */
  while( clock_get_pulse() != PT_START );
  lcd_command( LCD_CLEAR );
  seconds = 0;
  while( TRUE )
  {
     /* 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 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>