;****************************************************************
;*  Name    : Часы на 4-х матрицах 8Х8 MAX7219                  *
;*  Author  : PINCOD                                            *
;*  Notice  : PROTON BASIC 3.5.5.5                              *
;*          :                                                   *
;*  Date    : 07-04-2017                                        *
;*  Version : 1.0                                               *
;*  Notes   :                                                   *
;*          :                                                   *
;****************************************************************

;                               PIC16F628A: 
;                                +------+                                        
;                               <[A2  A1]>                    
;                               <[A3  A0]>   
;                               <[A4  A7]>  кварц  20мгц     
;                               <[A5  A6]>  кварц          
;                           GND  [      ]  +5V                                   
;          пищалка с внутр.генр >[B0  B7]<  clock 13 нога max7219                              
;                   кнопка      >[B1  B6]<  load  12 нога max7219                             
;                   кнопка      >[B2  B5]<  data  1  нога max7219                             
;                   кнопка      >[B3  B4]<  нога DS18B20                                
;                                +------+                                               

Device 16F628A
Reminders = 0                        
Config HS_OSC, WDT_OFF, PWRTE_ON, LVP_OFF, BODEN_OFF, MCLRE_OFF
Reminders = 1                                                                        
Declare Xtal = 20
Declare Create_Coff = 1
;-----------------Назначим входы-выходы портов МК согласно схемы-----------------------                               
;        76543210             
TRISA = %00000000             
TRISB = %00001110
PORTA = %00000000
PORTB = %00000000
CMCON = 7 'Компаратор нам не нужен, отключим ...
Symbol T0IF = INTCON.2 ; T0IF Флаг прерывания по переполнению TMR0 
OPTION_REG = %00000111 
INTCON = %10100000 ;разрешим прерывания по переполнению TMR0 и Глобальное разрешение прерываний

;-----------------------------------------------------------------------------------------
Symbol ClockPin = PORTB.7 ;порт упр. max7219            
Symbol DataPin  = PORTB.5 ;порт упр. max7219          
Symbol Load     = PORTB.6 ;порт упр. max7219
Symbol BEEP     = PORTB.0 ;порт упр. писк в начале каждого часа
Symbol Meny     = PORTB.1 ;порт упр. кнопкой  
Symbol PLUS     = PORTB.2 ;порт упр. кнопкой
Symbol MINUS    = PORTB.3 ;порт упр. кнопкой
Symbol Dq       = PORTB.4 ;порт упр. DS18B20
;-----------------------------------------------------------------------------------------
Dim Y As Byte  
Dim X As Byte
Dim DES As Word
'----------------------------------------------------------------------------------------
Dim Temp As Word  ' считаное значение с датчика
Dim TempC As Byte '
Dim Dummy As Word
Dim G    As Bit
Dim Flash As Bit
Dim A As Byte : Dim B As Byte : Dim C As Byte : Dim D As Byte;транзитные переменные
Dim address           As Byte            ;Адресация MAX7219 
Dim DataArray         As Byte            ;Данные MAX7219
Dim digit             As Byte            ;селекция цифр
Dim DigNumbur         As Byte
Dim Array_ [104]      As Byte 
Dim BIG As Dword  
Dim BIG1 As BIG.HighWord
Dim Tochka  As Byte
Dim N       As Byte
Dim E       As Byte
Dim Flag    As Word
Dim ButtMIN  As Byte ;для работы с кнопками функция автоповтор
Dim ButtPlus As Byte ;для работы с кнопками функция автоповтор
Dim SECONDS As Byte
Dim MINUTES As Byte
Dim HOUR    As Byte
Dim SetCorr As Word
Dim MemtCorr As Bit
Dim BIG2 As Dword 
;---------------------------------Массив цифр и знаков -------------------------------------------------------  
'ZERO              ; Массив цифры 0      Массив цифры 1       Массив цифры 2        Массив цифры 3      Массив цифры 4
Array_[0]  =  0   :  Array_[8]  =  0    :  Array_[16] =  0   : Array_[24] =  0    : Array_[32] =  0    : Array_[40] =  0
Array_[1]  =  0   :  Array_[9]  =  62   :  Array_[17] =  0   : Array_[25] =  66   : Array_[33] =  34   : Array_[41] =  7
Array_[2]  =  0   :  Array_[10] =  81   :  Array_[18] =  2   : Array_[26] =  97   : Array_[34] =  65   : Array_[42] =  8
Array_[3]  =  0   :  Array_[11] =  73   :  Array_[19] =  127 : Array_[27] =  81   : Array_[35] =  73   : Array_[43] =  8
Array_[4]  =  0   :  Array_[12] =  69   :  Array_[20] =  0   : Array_[28] =  73   : Array_[36] =  73   : Array_[44] =  8
Array_[5]  =  0   :  Array_[13] =  62   :  Array_[21] =  0   : Array_[29] =  70   : Array_[37] =  54   : Array_[45] =  127
Array_[6]  =  0   :  Array_[14] =  0    :  Array_[22] =  0   : Array_[30] =  0    : Array_[38] =  0    : Array_[46] =  0
Array_[7]  =  0   :  Array_[15] =  0    :  Array_[23] =  0   : Array_[31] =  0    : Array_[39] =  0    : Array_[47] =  0
'=================================================================================================================
; Массив цифры 5      Массив цифры 6        Массив цифры 7        Массив цифры 8        Массив цифры 9
Array_[48] =  0    :  Array_[56] =  0    : Array_[64] =  0    :  Array_[72] =  0    :  Array_[80] =  0
Array_[49] =  39   :  Array_[57] =  62   : Array_[65] =  1    :  Array_[73] =  54   :  Array_[81] =  38
Array_[50] =  69   :  Array_[58] =  73   : Array_[66] =  113  :  Array_[74] =  73   :  Array_[82] =  73
Array_[51] =  69   :  Array_[59] =  73   : Array_[67] =  9    :  Array_[75] =  73   :  Array_[83] =  73
Array_[52] =  69   :  Array_[60] =  73   : Array_[68] =  5    :  Array_[76] =  73   :  Array_[84] =  73
Array_[53] =  57   :  Array_[61] =  50   : Array_[69] =  3    :  Array_[77] =  54   :  Array_[85] =  62
Array_[54] =  0    :  Array_[62] =  0    : Array_[70] =  0    :  Array_[78] =  0    :  Array_[86] =  0
Array_[55] =  0    :  Array_[63] =  0    : Array_[71] =  0    :  Array_[79] =  0    :  Array_[87] =  0
'=================================================================================================================
'знак градуса      'знак плюса         
Array_[88] =  6    :  Array_[96]  =  0    
Array_[89] =  9    :  Array_[97]  =  0    
Array_[90] =  9    :  Array_[98]  =  8    
Array_[91] =  6    :  Array_[99]  =  8     
Array_[92] =  124  :  Array_[100] = 62    
Array_[93] =  130  :  Array_[101] =  8    
Array_[94] =  130  :  Array_[102] =  8     
Array_[95] =  68   :  Array_[103] =  0    
'===============   '===============   
'---------------------------------------------------------------------------------------------
  MemtCorr = ERead 0 ;Со считать из EEPROM по адресу 0 и присвоить значение  MemtCorr
  If MemtCorr = 1 Then ;Если MemtCorr = 1,значит было сохранено значение 
  SetCorr = ERead 1 ;Со считать сохранёное значение и присвоить его SetCorr
  Else 
  SetCorr = 5000 ;Иначе SetCorr = 5000
  EWrite 0, [1];Устанавливаем влаг,что сохранили значение,по адресу 0  
  EWrite 1, [SetCorr];Сохраняем значение SetCorr,по адресу 1
  EndIf		
  BIG2 = 4995000 + SetCorr '++++++++++++++++++++ 
  BIG = BIG2
  '--------------------------------------------------------------------------------------------                
 E = 3;яркость
 Flag = 1;для корректной работы с экраном
 Flash = 1 ;для корректной работы с экраном
 MINUTES = 0 : HOUR = 0 : SECONDS = 0                              
 ButtPlus = 0 : ButtMIN = 0
 
GoSub MAX7219_Init
;-----------------------------------------------------------------------------------           
 On_Interrupt GoTo MYINT 
   GoTo main ; Переход на начало программы 

MYINT:'-------------------------Обработчик прерывания--------------------------------
 Context Save
   big1 = big1 - 1  
   If BIG < 0 Then   
   BIG = BIG + BIG2
   Inc SECONDS  
   Flag  = 1  
   EndIf     
   T0IF = 0 
 Context Restore
;-----------------------------------------------------------------------------------
main:
GoSub KontrolTime

If Meny = 1 Then       ;Уходим в настройки точности хода часов
    While Meny = 1     ;яркости зкрана и сброс секунд
    GoSub KontrolTime
    Wend
    Tochka  = 0
    GoTo SetCor
    EndIf
   If MINUS = 1 Then Inc ButtMIN 'Устанавливаем минуты      
   If ButtMIN > 5 Then ButtMIN = 0 : Inc MINUTES ;если держим втоповтор  
   If MINUS = 0 And ButtMIN > 2 Then ButtMIN = 0 : Inc MINUTES ;короткое нажатие +1
    
   If PLUS = 1 Then Inc ButtPlus 'Устанавливаем часы                           
   If ButtPlus > 20 Then ButtPlus = 0 : Inc  HOUR ;если держим втоповтор
   If PLUS = 0 And ButtPlus > 2 Then ButtPlus = 0 : Inc  HOUR ;короткое нажатие +1
   
   If MINUTES >= 60 Then MINUTES = 0
   If HOUR > 23 Then HOUR = 0 
   
  A = Dig MINUTES,0 : B = Dig MINUTES,1 : C = Dig HOUR,0 : D = Dig HOUR,1
'-------------------------------------------------------------------------------
  If HOUR < 10 Then D = 12 ;уберем не значащий нуль в дес.часов
  If SECONDS > 54 Then     ;на 54секунде показываем температуру в доме
  Flash = 0
  Tochka  = 0
  GoSub Termo
  GoSub Clears'анимация очищения экрана перед загрузкой в регистры след. инфы
  Flag  = 1
  A = 10 : B = Dig TempC ,0 : C = Dig TempC ,1 : D = 11
EndIf

digit = 0
N = A  
GoSub Maska
GoSub Write_8x8_display

digit = 1
N = B  
GoSub Maska
GoSub Write_8x8_display

digit = 2
N = C  
GoSub Maska
GoSub Write_8x8_display

digit = 3
N = D  
GoSub Maska
GoSub Write_8x8_display;здесь покрутимся 5 сек показ температуры
While SECONDS > 55
GoSub KontrolTime
Wend
If Flag = 1 And SECONDS = 0  Then
Flag = 0
GoSub Clears 'анимация очищения экрана перед загрузкой в регистры след. инфы
EndIf
GoTo main

;-----------------------------------------------------------------------------------
MAX7219_Init:;подготовим микросхемы MAX7219,записью нужных нам битов в память

For digit = 0 To 4         ; очистим экран
   DigNumbur = 0                   
   GoSub Write_8x8_display
Next
'----------------------------------------------------------------
address = $09              ;Режим декодирования. Битами DATA
DataArray = $0               ;0 – не декодировать знакоместо
GoSub MAX7219_DIGITS1
GoSub MAX7219_DIGITS2
GoSub MAX7219_DIGITS3                     
GoSub MAX7219_DIGITS4
'----------------------------------------------------------------
address = $0B              ;Выбор кол-ва отображаемых знакомест
DataArray = $07              ;отображаются все восемь знакомест.
GoSub MAX7219_DIGITS1      ;Digit 0,1,2,3,4,5,6,7 ($00-$07)
GoSub MAX7219_DIGITS2
GoSub MAX7219_DIGITS3
GoSub MAX7219_DIGITS4
'----------------------------------------------------------------
address = $0C              ;Спящий режим. При DATA = 0 микросхема впадает в
DataArray = $01              ;спящий режим
GoSub MAX7219_DIGITS1      ;DATA = 1 является нормальным режимом.     
GoSub MAX7219_DIGITS2
GoSub MAX7219_DIGITS3
GoSub MAX7219_DIGITS4
'----------------------------------------------------------------
address = $0F              ;Тест. Если DATA = 1 – тест включен,
DataArray = $00              ; если DATA = 0 – выключен.
GoSub MAX7219_DIGITS1
GoSub MAX7219_DIGITS2
GoSub MAX7219_DIGITS3
GoSub MAX7219_DIGITS4
'----------------------------------------------------------------
 Bright:
   address = $0A           ;Интенсивность свечения (яркость). Битами D0…D3           
   DataArray = E             ;выбирается яркость свечения. от 0 - 15           
   GoSub MAX7219_DIGITS1
   GoSub MAX7219_DIGITS2
   GoSub MAX7219_DIGITS3
   GoSub MAX7219_DIGITS4
Return  

;----------------------------------------------------------------
MAX7219_DIGITS4:
Load = 0
SHOut DataPin, ClockPin, MsbFirst, [0,0,0,0,0,0,address,DataArray]
Load = 1
                            
Return
;----------------------------------------------------------------
MAX7219_DIGITS3:
If address = 8 Then DataArray = DataArray + Tochka
Load = 0
SHOut DataPin, ClockPin, MsbFirst, [0,0,0,0,address,DataArray,0,0]
Load = 1
                            
Return
;----------------------------------------------------------------
MAX7219_DIGITS2:
'If address = 1 Then DataArray = DataArray + Tochka
Load = 0
SHOut DataPin, ClockPin, MsbFirst, [0,0,address,DataArray,0,0,0,0]
Load = 1
                            
Return
;----------------------------------------------------------------
MAX7219_DIGITS1:
Load = 0
SHOut DataPin, ClockPin, MsbFirst, [address,DataArray,0,0,0,0,0,0] 
Load = 1
                           
Return
;----------------------------------------------------------------
Write_8x8_display:
For address = 1 To 8
GoSub KontrolTime
If Flash = 1 Then
If BIG < 2500000 Then
   Tochka  = 0
   Else
   Tochka  = 34 ;для двоеточия секунд
   EndIf
   EndIf
   DataArray = Array_ [address - 1 + DigNumbur]
   
   Select digit
   Case 0 
        GoSub MAX7219_DIGITS1
   Case 1
        GoSub MAX7219_DIGITS2
   Case 2
       GoSub MAX7219_DIGITS3
   Case 3
       GoSub MAX7219_DIGITS4    
   EndSelect
Next                                                 
Return
'------------------------------------------------------------------------------------------- 
Maska:
' DigNumbur = LookUp N,[8,16,24,32,40,48,56,64,72,80,88,96,0]
 Select N
 Case 0
  DigNumbur = 8
 Case 1
  DigNumbur = 16
 Case 2
  DigNumbur = 24
 Case 3
  DigNumbur = 32
 Case 4
  DigNumbur = 40
 Case 5
  DigNumbur = 48
 Case 6
  DigNumbur = 56
 Case 7
  DigNumbur = 64
 Case 8
 DigNumbur = 72
 Case 9
  DigNumbur = 80
 Case 10
  DigNumbur = 88
 Case 11
  DigNumbur = 96
 Case 12
  DigNumbur = 0 
 EndSelect            
Return
'------------------------------------------------------------------------------------------- 
Termo:
     
     OWrite Dq, 1, [$CC,$44]    ' Послать датчику DS18S20 команду старта измерения температуры      
     Repeat                     ' Начать внутренний цикл      
     ORead Dq, 4, [G]           ' сигнализирующий об окончании преобразования
     GoSub KontrolTime
     Until G > 0                ' Выйти из цикла если от DS18S20 поступил бит конца преобразования       
     OWrite Dq, 1, [$CC,$BE]    ' Послать команду чтения из ОЗУ датчика DS18S20 значения температурыe      
     ORead    Dq, 2, [Temp.LowByte, Temp.HighByte] ; считывание t'C                      
     'IF Temp.11 = 1 THEN       ; если бит полярности температуры = 1 
     'Dummy  = 625 * (~Temp + 1); подсчитаем
     'TempC  = DIV32 10000      ;отрицательную температуру  
     'ELSE                      ; если нет, 
     Dummy = 625 * Temp         ; подсчитаем Dummy 
     TempC = Div32 10000        ; положительную температуру
     A = 22 : B = Dig TempC ,0 : C = Dig TempC ,1 : D = 21 ': Flash = 0
     Return
'------------------------------------------------------------------------------------------- 
Clears:;проталкиваем 0 поочередно столбы регистров

   For Y = 0 To 8
   DataArray = 0
   address = y+1 : DataArray = DataArray << 1   
   Load = 0
   SHOut DataPin, ClockPin, MsbFirst, [0,0,0,0,0,0,address,DataArray]
   Load = 1
   GoSub Delay  ;замедлим анимацию для глаз
   Next Y
'--------------------------------------------------------------------
  For Y = 0 To 8
  DataArray = 0
  address = y+1 : DataArray = DataArray << 1 
  Load = 0
  SHOut DataPin, ClockPin, MsbFirst, [0,0,0,0,address,DataArray,0,0]
  Load = 1
  GoSub Delay  ;замедлим анимацию для глаз
 Next Y
'--------------------------------------------------------------------
  For Y = 0 To 8
  DataArray = 0
  address = y+1 : DataArray = DataArray << 1
  Load = 0
  SHOut DataPin, ClockPin, MsbFirst, [0,0,address,DataArray,0,0,0,0]
  Load = 1
  GoSub Delay ;замедлим анимацию для глаз
 Next Y
'--------------------------------------------------------------------
  For Y = 0 To 8
  DataArray = 0 
  address = y+1 : DataArray = DataArray << 1 
  Load = 0
  SHOut DataPin, ClockPin, MsbFirst, [address,DataArray,0,0,0,0,0,0]
  Load = 1
  GoSub Delay ;замедлим анимацию для глаз
 Next Y
'--------------------------------------------------------------------
Return
'--------------------------------------------------------------------
 Delay:;замедлим анимацию для глаз
  For DES = 0 To 5000
  GoSub KontrolTime
  Next DES
  Return
'--------------------------------------------------------------------
KontrolTime:;Патруль времени               
      
   If SECONDS >= 60 Then
   SECONDS = 0   
   Flash = 1  
   Inc MINUTES                        
   If MINUTES >= 60 Then
'-------------------Короткий писк 50 млсек в начале каждого часа -----------------------------------
 BEEP = 1 : DelayMS 50 : BEEP = 0 
'---------------------------------------------------------------------------------------------------
   MINUTES = 0
   Inc HOUR
   If HOUR > 23 Then HOUR = 0
   If HOUR = 0 Then E  = 0 : GoSub Bright ;После 24.00 яркость на минимум
   If HOUR = 9 Then E  = 3 : GoSub Bright ;После 9.00 яркость на 3 
   EndIf
   EndIf 
   Return
     ;-----------------------Корректируем точность хода часов---------------------------------------
 SetCor:
 
   'For F = 0 To 10000   
   If MINUS = 1 Then Inc ButtMIN 'Устанавливаем минуты      
   If MINUS = 1 And ButtMIN > 20 Then ButtMIN = 21 : SetCorr = SetCorr + 10
   If MINUS = 0 And ButtMIN > 1 Then ButtMIN = 0 : SetCorr = SetCorr + 10
   If PLUS = 1 Then Inc ButtPlus 'Устанавливаем часы                           
   If PLUS = 1 And ButtPlus > 20 Then ButtPlus = 21 : SetCorr = SetCorr - 10 
   If PLUS = 0 And ButtPlus > 1 Then ButtPlus = 0 : SetCorr = SetCorr - 10
   If SetCorr > 10000 Then SetCorr = 10000
   If SetCorr < 10 Then SetCorr = 10
   A = Dig SetCorr,0 : B = Dig SetCorr,1 : C = Dig SetCorr,2 : D = Dig SetCorr,3
   GoSub Disp
   GoSub KontrolTime   
   If Meny = 1 Then  ;переходим  на сброс секунд
   While Meny = 1
   GoSub KontrolTime
   Wend
   EWrite 1, [SetCorr];Сохраняем значение SetCorr,по адресу 1 
   EWrite 0, [1];Устанавливаем влаг,что сохранили значение,по адресу 0
   BIG2 = 4995000 + SetCorr 
   BIG = BIG2
   GoTo SetSeconds   
   EndIf
   GoTo SetCor
;-------------------  После коррекции сбросим секунды по нолям  -------------------------------                                                                                       
SetSeconds:
  GoSub KontrolTime
  If MINUS = 1 Or PLUS = 1 Then SECONDS = 0 ;при нажатии на MINUS или PLUS, сброс секунд
  If Meny = 1 Then  ;переходим  настройкам яркости экрана
  While Meny = 1
  GoSub KontrolTime
  Wend
  GoTo SetBright
  EndIf
  A = 11 : B = Dig SECONDS,0 : C = Dig SECONDS,1 : D = 11
  GoSub Disp
  GoTo SetSeconds
;-------------------- Регулировка яркости экрана -----------------------------------------  
SetBright:
   If MINUS = 1 Then Inc ButtMIN          
   If MINUS = 0 And ButtMIN > 1 Then 'кратковременным нажатием + 1
   ButtMIN = 0
   Inc E
   If E > 15 Then E = 0
   GoSub Bright
   EndIf
   If Meny = 1 Then ;возвращаемся на исходную
   While Meny = 1
   GoSub KontrolTime
   Wend
   GoTo main
   EndIf
   A = 11 : B = Dig E,0 : C = Dig E,1 : D = 11
   GoSub Disp 
   GoTo SetBright 
 ;------------------------------------------------------------------------------------------   
    
Disp:   
 digit = 0
 N = A  
 GoSub Maska
 GoSub Write_8x8_display

 digit = 1
 N = B  
 GoSub Maska
 GoSub Write_8x8_display

 digit = 2
 N = C  
 GoSub Maska
 GoSub Write_8x8_display

 digit = 3
 N = D  
 GoSub Maska
 GoSub Write_8x8_display

Return
'------------------------------------------------------------------------------------------- 
