From Tim's website
Revision as of 22:13, 22 February 2010 by Tim (talk | contribs) (New page: == PIC Software - clock.c == <pre> →‎Device header and CCS compiler directives: #include <16f873.h> #device ICD=TRUE →‎Incase we use the ICD: #device ADC=8 ...)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

PIC Software - clock.c

/* Device header and CCS compiler directives */
#include <16f873.h>

#device ICD=TRUE               /* Incase we use the ICD */
#device ADC=8                  /* Only use the 8 MSBs   */
#use delay( clock=4000000 )    /* Set for a 4MHz Clock  */

/* Include the code for the LCD display */
#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 );
   }
}