Menu

Retrograde Minute Hand Clock

mkstevo
2021-05-21
2021-05-29
  • mkstevo

    mkstevo - 2021-05-21

    Yes! Another clock! This one has a mechanical minute hand with a retrograde action. The hand moves from "zero" to the "sixty" minute position, once the minutes reach sixty, the hand rotates anticlockwise, back to zero and the hour indicated on the LED display progresses to the new hour.

    The video shows the clock being powered up and moving to the current time. When first plugged in, the LED display shows the software build date ( 21 - 05 - 21 ), the minute hand rotates anticlockwise to zero minutes, the hand then rotates to the sixty minute position (this is to check that the limit switches are working) during this proceedure, the LED display shows a count of the steps needed to move the hand from one position to the other - if this is less than that required, an error would be displayed. The minute hand then returns back to zero. The clock module is initialised (the LED momentarily shows "IC") and assuming the time can be loaded, the current time (hours then minutes) is shown on the LED. The minute hand then moves to point to the current time, the LED shows the hours and timekeeping commences.

    Inspired by the range of Reservoir Watches.

    Code updated with "Error" changed to "ErrorSub" following Anobium's suggestion. When the PCBs arrived I found that the steps required needed a change or two to allow a full rotation, not unexpected really given the prototype was made with a sheet of cardboard with holes punched to mount the motor. This code has those minor tweaks made.

    YouTube Video

    #Option Explicit
    'Pic 16F1829 Retrograde minute clock
    '(c) MkEDS 2021
    
    'This is to drive a 28YBJ-48 Stepper motor.
    'The motor driver transistor bases are connected
    'to MtrA, MtrB, MtrC and MtrD. The collectors of
    'these transistors are connected to the A,B,C and D
    'windings of the motor.
    
    'The wires of the motor are:
    'Red  5V
    'Ora  A
    'Yel  B
    'Pnk  C
    'Blu  D
    
    'A serial two digit LED display is connected to show the hours.
    'The stepper motor points to the minutes.
    
    'A DS3231 clock module is connected to keep the time.
    
    'The date is always set to the compile date as the date cannot be displayed.
    
    'When powered on, the compile date is shown on the display.
    
    'The stepper motor is then turned anticlockwise until the pointer makes contact
    'with the start switch.
    
    'The stepper motor is then turned clockwise until the pointer makes contact with
    'the end switch.
    
    'The stepper motor is then turned anticlockwise back to the start position.
    
    'The start contacts should be positioned and aligned with the zero minute marker.
    'The end contacts should be algned just past the sixty minute marker.
    
    'If the stepper motor fails to rotate for the correct number of steps (more than
    '2999 and less than 3500) the display will show "EH" and will halt to indicate
    'an error with the hand.
    
    'The DS3231 will be initialised with the display showing briefly "IC".
    'If the DS3231 is not detected the display will show "EC" and will halt to indicate
    'an error with the clock.
    
    'If there are no errors, the hours will be shown with a decimal point on the first
    'digit, followed by the minutes with a decimal point on the second digit.
    
    'The display will then show the current hour and the pointer will move to indicate the
    'current minutes.
    
    'At 59 minutes and 55 seconds, the minute pointer will move anticlockwise back to
    'zero minutes. This takes around 8 seconds, the hour will update to show the new
    'hour.
    
    'Hours are only ever displayed in 12 hour format with a leading zero.
    
    'If the DS3231 has stalled due to a power failure, the two decimal points will alternate
    'every second. This will indicate that the time needs checking. Setting the time will
    'clear this.
    
    'There are three buttons fitted, Up Down and OK.
    
    'While not in setting mode, pressing the "Up" button will show the temperature
    'on the display, with no decimal point. Pressing the "Down" button will show the
    'minute with a decimal point on the second digit.
    
    'To adjust the time:
    'Press and hold the "Ok" button for a second.
    'The clock will show the hour, with a decimal point on the first digit, pressing
    'the up or down buttons will adjust the hour. Press and release the "Ok" button
    'to store the hour and adjust the minute. The minute will be displayed with a
    'decimal point on the second digit, pressing the up or down buttons will adjust
    'the current minute. Press the "Ok" button to store the time. If the minutes
    'have been altered, the seconds will be set to zero and timekeeping will start
    'when the "Ok" button is finally pressed then released.
    
    'The date cannot be shown and is reset to the compile date when ever the time is
    'adjusted.
    
    'Should the pointer be turned accidentally:
    'If it is advanced, it will reach the end switch before sixty minutes, the pointer
    'will return to zero minutes, then rotate to the correct time.
    
    'If it is retarded, it will return to zero minutes at 59 minutes and 55 seconds
    'then continue as normal.
    
    #Chip 16F1829, 32
    #Config CP=On
    'Read protected
    
    Set Not_WPUEN = 0 'Enable pullups in general.
    Set WPUA0     = 0
    Set WPUA1     = 0
    Set WPUA2     = 0
    Set WPUA3     = 1 'OK
    Set WPUA4     = 1 'I2C_Dat
    Set WPUA5     = 1 'I2C_Clk
    
    Set WPUb4     = 0
    Set WPUb5     = 0
    Set WPUb6     = 0
    Set WPUb7     = 1 'P10
    
    Set WPUc0     = 0
    Set WPUc1     = 1 'P15
    Set WPUc2     = 1 'P14
    Set WPUc3     = 1 'StSw
    Set WPUc4     = 1 'Up
    Set WPUc5     = 1 'Dn
    Set WPUc6     = 1 'EnSw
    Set WPUc7     = 1 'P9
    
    #Include <DS3231.h>
    'Define I2C settings - S/W I2C
    #Define I2C_MODE Master
    #Define I2C_DISABLE_INTERRUPTS On
    
    #Define I2C_CLOCK       PortA.5 'Pin 2
    #Define I2C_DATA        PortA.4 'Pin 3
    
    #Define OkSw            PortA.3 'Pin 4 In only
    #Define DnSw            PortC.5 'Pin 5
    #Define UpSw            PortC.4 'Pin 6
    
    'These switches are made active when the pointer on the stepper motor contacts
    'with pins on the clockface. The pointer has solder points on it to attach a
    'loop of wire which is fabricated to short out the pins protruding from the clock
    'face. The start switch (at zero minutes) should be arranged to make contact when
    'the pointer is aligned with the zero minute marker. The end switch (at sixty
    'minutes) should be arranged so that it makes contact when the pointer has just
    'passed the sixty minute marker.
    #Define StSw            PortC.3 'Pin 7
    #Define EnSw            PortC.6 'Pin 8
    'These switches are made active when the pointer on the stepper motor contacts
    'with pins on the clockface. The pointer has solder points on it to attach a
    'loop of wire which is fabricated to short out the pins protruding from the clock
    'face. The start switch (at zero minutes) should be arranged to make contact when
    'the pointer is aligned with the zero minute marker. The end switch (at sixty
    'minutes) should be arranged so that it makes contact when the pointer has just
    'passed the sixty minute marker.
    
    #Define P9              PortC.7 'Pin 9
    #Define P10             PortB.7 'Pin 10
    
    #Define D_Lat           PortB.6 'Pin 11
    #Define D_Data          PortB.5 'Pin 12
    #Define D_Clk           PortB.4 'Pin 13
    
    #Define P14             PortC.2 'Pin 14
    #Define P15             PortC.1 'Pin 15
    
    #Define MtrD            PortC.0 'Pin 16
    #Define MtrC            PortA.2 'Pin 17
    #Define MtrB            PortA.1 'Pin 18
    #Define MtrA            PortA.0 'Pin 19
    
    #Define E_Hands         1
    #Define E_DS3231        2
    #Define E_Other1        3
    #Define E_Other2        4
    #Define Blank           5
    
    #Define S_Hrs           20 'Hours
    #Define S_Mns           21 'Minutes
    
    #Define Dp_Hr           2
    #Define Dp_Mn           1
    
    Dir     OkSw            In
    Dir     DnSw            In
    Dir     UpSw            In
    
    'These switches are made active when the pointer on the stepper motor contacts
    'with pins on the clockface. The pointer has solder points on it to attach a
    'loop of wire which is fabricated to short out the pins protruding from the clock
    'face. The start switch (at zero minutes) should be arranged to make contact when
    'the pointer is aligned with the zero minute marker. The end switch (at sixty
    'minutes) should be arranged so that it makes contact when the pointer has just
    'passed the sixty minute marker.
    Dir     StSw            In
    Dir     EnSw            In
    'These switches are made active when the pointer on the stepper motor contacts
    'with pins on the clockface. The pointer has solder points on it to attach a
    'loop of wire which is fabricated to short out the pins protruding from the clock
    'face. The start switch (at zero minutes) should be arranged to make contact when
    'the pointer is aligned with the zero minute marker. The end switch (at sixty
    'minutes) should be arranged so that it makes contact when the pointer has just
    'passed the sixty minute marker.
    
    Dir     D_Clk           Out
    Dir     D_Data          Out
    Dir     D_Lat           Out
    Dir     MtrA            Out
    Dir     MtrB            Out
    Dir     MtrC            Out
    Dir     MtrD            Out
    
    'Variables used
    
    Dim     Dat             As Word
    Dim     Temp            As Byte
    Dim     Clocks          As Byte
    Dim     Digit           As Byte
    
    
    Dim     D1              As Word
    Dim     D2              As Word
    Dim     D3              As Word
    Dim     D4              As Word
    Dim     Dt              As Word
    
    Dim CountedMv As Word
    
    Dim CENTURY_FLAG    As Byte
    Dim POWERLOSS       As Byte
    
    Dim Changed         As Bit
    Dim Hour            As Byte
    Dim Min             As Byte
    Dim Sec             As Byte
    Dim Am_Pm           As Byte
    
    
    Dim TimeT           As Byte
    Dim Target          As Word
    Dim LastHour        As Word
    Dim LastMin         As Word
    
    Dim Date            As Byte
    Dim Month           As Byte
    Dim Year            As Byte
    Dim DOW             As Byte
    Dim Century         As Byte
    
    Dim DecimalPoint    As Byte
    
    Dim TempMSB         As Byte
    Let TempMSB = 0
    'Dim TempLSB         As Byte
    'Let TempLSB = 0
    Dim Minus           As Bit
    Let Minus = 0
    
    Let CountedMv = 0
    
    'Whenever the time and date are saved, the date is reset to the compile date
    'As the date is never seen, we don't care about the date!
    #Define CompileDay  5  'Friday
    #Define CompileDate 21 '21st
    #define CompileMnth 5  'May
    #Define CompileYear 21 '2021
    'Whenever the time and date are saved, the date is reset to the compile date
    'As the date is never seen, we don't care about the date!
    
    
    #Define DelTime 2000  ' 2mS per step
    Dim StepSequence    As Byte
    
    Start_Up_Sub
    
    Start_Of_Program:
    
    Do
    
        GetTime
    
        If DnSw = 0 Then
            ShowValuesSub(Min,Dp_Mn)
            Wait 1000 mS
        End If
    
        If UpSw = 0 Then
            GetTemperature
            'If the temperature is below zero, this will not be indicated!
            ShowValuesSub(TempMSB,0)
            'If the temperature is below zero, this will not be indicated!
            Wait 1000 mS
        End If
    
        If OkSw = 0 Then
            Wait 500 mS
            If OkSw = 0 Then
                GetTime
                Let LastMin  = Min
                Let LastHour = Hour
                Set_Time
    
                If LastMin <> Min Then
                    Let Sec = 0 'Zero the seconds
                    SaveTimeDate
                Else
                    If LastHour <> Hour Then
                        Let LastHour = Hour 'Only save the hour
                        GetTime
                        Let Hour = LastHour
                        SaveTimeDate
                    End If
                End If
    
            End If
        End If
    
        ValidateHour
    
        If PowerLoss = True Then
            If DecimalPoint = 2 Then
                Let DecimalPoint = 1
            Else
                Let DecimalPoint = 2
            End If
        Else
            Let DecimalPoint = 0
        End If
        ShowValuesSub(Hour,DecimalPoint)
    
    ' 1 minute * 52 = 52
    ' every 15 seconds move 13
    ' 3 * 13 = 39
    ' then at the new minute move 13 = 52 per minute
    ' 53 * 60 minutes = 3120
    ' angle of hands need 3120 steps to move from zero to sixty
    
        Let Target = Min * 52
        If Sec > 14 Then
            Let Target = Target + 13
        End If
        If Sec > 29 Then
            Let Target = Target + 13
        End If
        If Sec > 44 Then
            Let Target = Target + 13
        End If
    
        If CountedMv < Target Then
            Do
                Move_ClockWise(1)
                Let CountedMv = CountedMv + 1
            Loop Until CountedMv >= Target
        End If
    
        If CountedMv > Target Then 'May have adjusted time?
            Do
                MoveAClockWise(1)
                Let CountedMv = CountedMv - 1
            Loop Until CountedMv <= Target
        End If
    
        If Min > 58 Then
            If Sec > 53 Then 'It takes about 8 seconds to return
            '  by the time we're home, the new hour should start
                Let Target = 0
                Do
                    MoveAClockWise(1)
                Loop Until StSw = 0
                Let CountedMv = 0
            End If
        End If
    
        If EnSw = 0 Then 'At end stop?
            Do
                MoveAClockWise(1)
            Loop Until StSw = 0
            Let CountedMv = 0
        End If
    
    'It may be that after returning to zero, the pointer needs moving a few steps to align better with
    'zero minutes?
    
    'Hopefully this can be accounted for by adjusting the position of the "loop" on the pointer, but
    'it may need some software "correction"?
    Loop
    
    Sub Move_ClockWise(In StepCnt As Word)
    
        Repeat StepCnt
            Select Case StepSequence
                Case 1
                    Step1
                Case 2
                    Step2
                Case 3
                    Step3
                Case 4
                    Step4
                Case 5
                    Step5
                Case 6
                    Step6
                Case 7
                    Step7
                Case 8
                    Step8
                Case Else
                    Let StepSequence = 1
            End Select
            Let StepSequence = StepSequence + 1
            If StepSequence > 8 Then
                Let StepSequence = 1
            End If
        End Repeat
    
    End Sub
    
    Sub MoveAClockWise(In AStepCnt As Word)
    
        Repeat AStepCnt
            Select Case StepSequence
                Case 1
                    Step8
                Case 2
                    Step7
                Case 3
                    Step6
                Case 4
                    Step5
                Case 5
                    Step4
                Case 6
                    Step3
                Case 7
                    Step2
                Case 8
                    Step1
                Case Else
                    Let StepSequence = 1
            End Select
            Let StepSequence = StepSequence + 1
            If StepSequence > 8 Then
                Let StepSequence = 1
            End If
        End Repeat
    
    End Sub
    
    '############################################################################################################
    'The below two are not used here
    Sub Spin_Clockwise(In SpinCount As Word)
    
    
        AllOff
        Repeat SpinCount
    
            Step1
            Step2
            Step3
            Step4
            Step5
            Step6
            Step7
            Step8
    
        End Repeat
        Let StepSequence = 1
    
    End Sub
    
    Sub SpinAClockwise(In ASpinCount As Word)
    
        AllOff
        Repeat ASpinCount
    
            Step8
            Step7
            Step6
            Step5
            Step4
            Step3
            Step2
            Step1
    
        End Repeat
        Let StepSequence = 1
    
    End Sub
    'The above two are not used here
    '#############################################################################################################
    
    Sub AllOff
        Let MtrA = 0
        Let MtrB = 0
        Let MtrC = 0
        Let MtrD = 0
    End Sub
    
    Sub Step1
        Let MtrD = 1
        Wait DelTime uS
    
        AllOff
    End Sub
    
    Sub Step2
        Let MtrD = 1
        Let MtrC = 1
        Wait DelTime uS
    
        AllOff
    End Sub
    
    Sub Step3
        Let MtrC = 1
        Wait DelTime uS
    
        AllOff
    End Sub
    
    Sub Step4
        Let MtrC = 1
        Let MtrB = 1
        Wait DelTime uS
    
        AllOff
    End Sub
    
    Sub Step5
        Let MtrB = 1
        Wait DelTime uS
    
        AllOff
    End Sub
    
    Sub Step6
        Let MtrB = 1
        Let MtrA = 1
        Wait DelTime uS
    
        AllOff
    End Sub
    
    Sub Step7
        Let MtrA = 1
        Wait DelTime uS
    
        AllOff
    End Sub
    
    Sub Step8
        Let MtrD = 1
        Let MtrA = 1
        Wait DelTime uS
    
        AllOff
    End Sub
    
    
    Sub ShowValuesSub(In D_Value As Word, In DP_On As Byte)
    
        Let Dt = D_Value
    
        If Dt > 99 Then
            Do
                Let Dt = Dt / 10
            Loop Until Dt < 100
        End If
    
        Let D1 = 255 'Space - There is only a two digit display!
        Let D2 = 255 'Space - There is only a two digit display!
    
        If Dt > 9 Then  '10s
           Let D3 = Dt / 10
           Let Dt = Dt - (10*D3)
           Let D3 = D3 + 1 'Lookup starts at 0
        Else
           Let D3 = 1    'Zero
        End If
    
        Let D4 = Dt + 1 '1s
    
        If D3 < 255 Then
           ReadTable Numerals, D3, Dt
           Let D3 = Dt
        End If
        If D4 < 255 Then
           ReadTable Numerals, D4, Dt
           Let D4 = Dt
        End If
    
        If Dp_On = Dp_Hr Then
            Let D3 = D3 - 128
        End If
        If Dp_On = Dp_Mn Then
            Let D4 = D4 - 128
        End If
    
        Let D_Lat  = 0                'Start output data latch
        ShiftData(D1) '1000s
        ShiftData(D2) '100s
        ShiftData(D3) '10s
        ShiftData(D4) '1s
        Let D_Lat  = 1                'End output data latch
    
    End Sub
    
    Sub ClearDisplay
        For Temp=1 to 4
            SendSpace
        Next Temp
    End Sub
    
    Sub SendSpace
    
        Let D_Lat  = 0                'Start output data latch
        Let D_Data = 1
    
        For Clocks = 1 to 8
          Let D_Clk = 0                'Shift register clocked
          Wait 1 uS
          Let D_Clk = 1
        Next Clocks
        Let D_Lat  = 1                'End output data latch
    
    End Sub
    
    Sub ShiftData (DataOut As Byte)
    
        For Clocks = 1 to 8
          Let D_Clk = 0               'Shift register clocked
          Let D_Data = DataOut.7
          Let D_Clk = 1
          Rotate DataOut Left Simple
        Next Clocks
    
    End Sub
    
    Sub ErrorSub(In E_Type As Byte)
    
        Do
            ShowMessage(E_Type)
            Wait 500 mS
            ShowMessage(Blank)
            Wait 500 mS
        Loop
    
    End Sub
    
    'A  136
    'B  128 b 131
    'C  198 c 167
    'D  192 d 161
    'E  134
    'F  142
    'G  194
    'H  137 h 139
    'I  207 i 239
    'J  241
    'K  137 k 139
    'L  199
    'M  200 248 n,n 171 187
    'N  200     n   171
    'O  192 o 163
    'P  140
    'q  152
    'R  206 r 175
    'S  146
    't  135
    'U  193 u 227
    'V  193 v 227
    'W  193 241 w 227 243
    'X  137
    'Y  145
    'Z  164
    'Deduct 128 from a value to show a decimal point
    '
    '0  192
    '1  249
    '2  164
    '3  176
    '4  153
    '5  146
    '6  130
    '7  248
    '8  128
    '9  152
    'Deduct 128 from a value to show a decimal point
    
    Sub ShowMessage(In Message As Byte)
    
        If Message = E_Hands Then
            Let D_Lat  = 0                'Start output data latch
            ShiftData(255) 'Space
            ShiftData(255) 'Space
            ShiftData(134) 'E
            ShiftData(137) 'H
            Let D_Lat  = 1                'End output data latch
        End If
    
        If Message = E_DS3231 Then
            Let D_Lat  = 0                'Start output data latch
            ShiftData(255) 'Space
            ShiftData(255) 'Space
            ShiftData(134) 'E
            ShiftData(198) 'C
            Let D_Lat  = 1                'End output data latch
        End If
    
        If Message = E_Other1 Then
            Let D_Lat  = 0                'Start output data latch
            ShiftData(255) 'Space
            ShiftData(255) 'Space
            ShiftData(134) 'E
            ShiftData(249) '1
            Let D_Lat  = 1                'End output data latch
        End If
    
        If Message = E_Other2 Then
            Let D_Lat  = 0                'Start output data latch
            ShiftData(255) 'Space
            ShiftData(255) 'Space
            ShiftData(134) 'E
            ShiftData(164) '2
            Let D_Lat  = 1                'End output data latch
        End If
    
        If Message = Blank Then
            Let D_Lat  = 0                'Start output data latch
            ShiftData(255) 'Space
            ShiftData(255) 'Space
            ShiftData(255) 'Space
            ShiftData(255) 'Space
            Let D_Lat  = 1                'End output data latch
        End If
    
    End Sub
    
    Sub ShowVersion
    
        ShowValuesSub(CompileDate,0)
        Wait 1000 mS
        ShowValuesSub(ComPileMnth,0)
        Wait 1000 mS
        ShowValuesSub(CompileYear,0)
        Wait 1000 mS
    
    End Sub
    
    Sub Start_Up_Sub
        AllOff
        ClearDisplay 'Wipe the LED Display
    
        ShowVersion
    
    'It may be that after returning to zero, the pointer needs moving a few steps to align better with
    'zero minutes?
    
    'Hopefully this can be accounted for by adjusting the position of the "loop" on the pointer, but
    'it may need some software "correction"?
    
        Do
            Do
                MoveAClockWise(1)
                Let CountedMv = CountedMv + 1
                ShowValuesSub(CountedMv,0)
                If CountedMv > 3500 Then
                    ErrorSub(E_Hands)
                End If
            Loop Until StSw = 0
            Let CountedMv = 0
            ShowValuesSub(CountedMv,0)
            Wait 1000 mS
            Do
                Move_ClockWise(1)
                Let CountedMv = CountedMv + 1
                ShowValuesSub(CountedMv,0)
                If CountedMv > 3500 Then
                    ErrorSub(E_Hands)
                End If
            Loop Until EnSw = 0
            ShowValuesSub(CountedMv,0)
            Wait 1000 mS
        Loop Until CountedMv > 2999
    
        Let CountedMv = 0
        Do
            MoveAClockWise(1)
            Let CountedMv = CountedMv + 1
            ShowValuesSub(CountedMv,0)
            If CountedMv > 3500 Then
                ErrorSub(E_Hands)
            End If
        Loop Until StSw = 0
    
        Let StepSequence = 1
        Let CountedMv = 0
        ShowValuesSub(CountedMv,0)
    
    'It may be that after returning to zero, the pointer needs moving a few steps to align better with
    'zero minutes?
    
    'Hopefully this can be accounted for by adjusting the position of the "loop" on the pointer, but
    'it may need some software "correction"?
    
        Initialise_I2C
        Start_DS3231
    
        GetTime 'Show the time stored in DS3231
        ValidateHour
        ShowValuesSub(Hour,Dp_Hr)
        Wait 1000 mS
        ShowValuesSub(Min,Dp_Mn)
        Wait 1000 mS
    
    End Sub
    
    Table Numerals as Byte
        192 '0
        249 '1
        164 '2
        176 '3
        153 '4
        146 '5
        130 '6
        248 '7
        128 '8
        144 '9
    End Table
    
    Table MonthDays ;# of days in Months
        31
        29 ;leap years only
        31
        30
        31
        30
        31
        31
        30
        31
        30
        31
    End Table
    
    Sub Start_DS3231
    
    '   aging offset' Zero compensation added here
        DS3231_WriteRegister ( 0x10, 0b0000000 )
    
        GetDate
        If Century_Flag = 1 Then
           DS3231_HandleCentury ( Century_Flag, Century )
        End If
    
        DS3231_SetHourMode(24)                    '24-Hour mode
    
        DS3231_EnableOscillator( True )           'and, ensure the clock is running
    
        DS3231_Set32kHz ( True )                  'and, enable the 32kHz Output (EN32kHz).
        DS3231_EnableSQW
        DS3231_SetSQW 0                           'and, turn ON output as we will use as the alarm port!
        DS3231_DisableSQW
    
        DS3231_DisableAlarm1
        DS3231_DisableAlarm2
    
        'initialise a tracking variable
        powerloss = False
    
    End Sub
    
    Sub Check_DS3231_Status
        If DS3231_OscillatorStopFlagStatus = True Then ' has a power loss occurred? and the oscillator has stopped?
          Let powerloss = True
          DS3231_ClearOscillatorStopFlag
        End If
    End Sub
    
    Sub Initialise_I2C
      #IfDef I2C_DATA
            I2CStart                          ' is DS3231 present?
            I2CSend(DS_AddrWrite)
            I2CStop
    
            Let D_Lat  = 0                'Start output data latch
            ShiftData(255) 'Space
            ShiftData(255) 'Space
            ShiftData(207) 'I
            ShiftData(198) 'C
            Let D_Lat  = 1                'End output data latch
            Wait 250 mS
    
            If I2CSendState = False  Then     ' is DS3231 present?
               ErrorSub(E_DS3231)
            End If
      #EndIf
    End Sub
    
    Sub GetTime
        DS3231_ReadTime(Hour, min, sec, am_pm)
        If Hour > 23 Then
            Let Hour = 0
        End If
        If Min > 59 Then
            Let Min = 0
        End If
        If Sec > 59 Then
            Let Sec = 0
        End If
    End Sub
    
    Sub GetDate
        DS3231_ReadDate(DOW, Date, Month, Year, Century_Flag )   'get initial date
    
        If Century_Flag = 1 Then
           DS3231_HandleCentury ( Century_Flag, Century )
        End If
    
        If DOW > 7 Then
            Let DOW = 1
        End If
        If DOW < 1 Then
            Let DOW = 1
        End If
    
        If Date > 31 Then
            Let Date = 1
        End If
        If Date < 1 Then
            Let Date = 1
        End If
    
        If Year > 99 Then
            Let DOW = 21
        End If
        If Year < 1 Then
            Let Year = 21
        End If
    End Sub
    
    Sub Set_Time
    
        ValidateHour
    
        Do
            ShowValuesSub(Hour,Dp_Hr)
            Wait 100 mS
        Loop Until OkSw = 1
    
        Wait 500 mS
    
        Do
            ShowValuesSub(Hour,Dp_Hr)
            If UpSw = 0 Then
                Let Hour = Hour + 1
                If Hour > 12 Then
                    Let Hour = 1
                End If
            End If
            If DnSw = 0 Then
                Let Hour = Hour - 1
                If Hour < 1 Then
                    Let Hour = 12
                End If
            End If
            Wait 250 mS
        Loop Until OkSw = 0
        Do
            ShowValuesSub(Min,Dp_Mn)
            Wait 100 mS
        Loop Until OkSw = 1
    
        Wait 500 mS
    
        Do
            ShowValuesSub(Min,Dp_Mn)
            If UpSw = 0 Then
                Let Min = Min + 1
                If Min > 59 Then
                    Let Min = 0
                End If
            End If
            If DnSw = 0 Then
                Let Min = Min - 1
                If Min > 59 Then
                    Let Min = 59
                End If
            End If
            Wait 250 mS
        Loop Until OkSw = 0
        Do
            Wait 100 mS
        Loop Until OkSw = 1
    
    End Sub
    
    Sub SaveTimeDate
    
    'Whenever the time and date are saved, the date is reset to the compile date
    'As the date is never seen, we don't care about the date!
        Let DOW   = CompileDay
        Let Date  = CompileDate
        Let Month = CompileMnth
        Let Year  = CompileYear
    'Whenever the time and date are saved, the date is reset to the compile date
    'As the date is never seen, we don't care about the date!
    
        DS3231_SetHourMode(24)
        DS3231_SetClock(Hour, Min, Sec, DOW, Date, Month, Year)
        powerloss  = False ' reset tracker variable
        DS3231_ClearOscillatorStopFlag
    
    End Sub
    
    Sub ValidateHour
        If Hour > 12 Then 'Not interested in 24Hr clock
            Let Hour = Hour - 12
        End If
        If Hour = 0 Then
            Let Hour = 12
        End If
    End Sub
    
    Sub GetTemperature
    
        Let TempMSB = DS3231_ReadRegister(0x11)
    '    Let TempLSB = DS3231_ReadRegister(0x12)
    
        If TempMSB > 127 Then 'Minus value
            Let Minus = 1
            Let TempMSB = TempMSB - 128
        Else
            Let Minus = 0
        End If
    
    '    Select Case TempLSB
    '    Case 0
    '        Let TempLSB = 0
    '    Case 64
    '        Let TempLSB = 25
    '    Case 128
    '        Let TempLSB = 50
    '    Case 192
    '        Let TempLSB = 75
    '    Case Else
    '        Let TempLSB = 0
    '    End Select
    
    End Sub
    
     

    Last edit: mkstevo 2021-05-29
    • Anobium

      Anobium - 2021-05-24

      Great project! Well done. I love the video!


      Recommendation in the source. Rename ERROR() to ERRORHANLDER(). I later version of the compiler ERROR is a reserved word.

      And, I just compiled your program using PIC-AS compiler. Works - I am very happy. :-) Means the PIC-AS compiler with MPLAB-IDE works.

       
      • mkstevo

        mkstevo - 2021-05-29

        Thanks for that. I'll get that changed.

         
  • stan cartwright

    stan cartwright - 2021-05-22

    That is impressive..well I like it.
    I think a rc servo could turn 270 degrees and do similar...for a minute timer.
    rc servos are just send pulseout to control position and a timer interrupt for the clock.
    I'm a tight hobbyist and always look for the cheapest solution...yeah..sad but c'est moi.

    My ambition is a small glcd that looks like 4 valve numeric displays. nixie tubes?

     
  • mkstevo

    mkstevo - 2021-05-22

    I looked at the 270 degree servos. They would have been ideal, but found the application notes rather ambiguous to say the least. The tiny geared stepper motor was much more predictable, and very inexpensive. I think three cost me £3, shipped from China.

    I have a fake "Nixie" which uses LCDs to simulate the "Nixie" tubes. It is very good. I also have a real "Nixie" clock, it looks more realistic than the fake one (as it should) but if you'd never seen a real one, you would be happy with the fake.

    Fake vs. real...

     
  • stan cartwright

    stan cartwright - 2021-05-22

    If of interest I have a frequency counter that uses nixie tubes but the top of valve jobs for display.
    Nostalgia is they were a pain to drive... but looked cool before leds were invented.

     
    • mkstevo

      mkstevo - 2021-05-23

      They needed a high-ish voltage to strike the glow, but I don't think they were a particular pain to drive? And they do look good.

       
  • stan cartwright

    stan cartwright - 2021-05-22

    rc servos ie 1 wire,gnd,supply are easy with gcb.
    I use them on my bots for moving the distance sensor and taken them apart to make them
    rotate continuously.
    You know the position from the pulseout sent.
    although not documented in gcb, if you attach a wire to the rc servo potentiometer wiper and connect to a-d pin then you can measure the servo position even when not powered.
    I could teach my thing to move fom a manuallu set pattern...maybe.

     
    • mkstevo

      mkstevo - 2021-05-23

      I couldn't get my head to work out how to move the servos to single (or partial) degree accuracy. I also found that some of them were 180 degree servos, extended in some way which might, or might not, have the capacity to move the full 270 degree range. They were my first choice as I would have liked the speed.

      My second choice was some DC motors, geared with position sensors. They looked better, but were larger and more expensive.

      The geared stepper motors did at least have the capability of moving the full range I needed. They do sometimes not move the full steps expected, which is why I fitted the "limit switches". With these "limit switches" on the face, should the hand get nudged out of position or fail to move the full number of steps, it will be corrected either when the hand gets to sixty minutes early, or when the new hour starts and the hand returns to the zero position.

       
  • mkstevo

    mkstevo - 2021-05-29

    I've added two further videos for those who don't have much to do...

    The first video shows the clock transitioning from 1.59 pm to 2.00 pm, it only lasts 30 seconds so won't take long to watch.

    Short version

    The second video shows (almost) an entire hour, 2pm - 3pm in time lapse. Shooting it in time lapse means it doesn't take a whole hour, it does take sixteen minutes though. Still, if you've got nothing better to do...

    One hour compressed into sixteen minutes

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.