
;***************************  ИНДИКАТОР HD44780  *******************************     
;***************************  Checksum  0xa812   *******************************

	list     p=pic16f628a

	include  P16f628a.inc
    
    __CONFIG   3f14h
 
	errorlevel +207

cblock  0x20

rg_ligt
rg_int
phaze_tmp
W_TEMP
ST_TEMP
LCD_tmp 
dig_lo
dig_hi
bcd1
bcd2
bcd3
bin1
bin2
ctr
TenK 
Thou 
Hund 
Tens 
Ones 
      
endc
           
#define bank0    bcf STATUS,RP0       
#define bank1    bsf STATUS,RP0

#define phase_1  sublw b'00011000'
#define phase_2  sublw b'00010000'
#define phase_3  sublw b'00000000'
#define phase_4  sublw b'00001000'

#define func_on  btfss PORTA,2
#define func_off btfsc PORTA,2 

#define D7_1     bsf PORTA,1 
#define D7_0     bcf PORTA,1 
#define D6_1     bsf PORTA,0 
#define D6_0     bcf PORTA,0 
#define D5_1     bsf PORTA,7 
#define D5_0     bcf PORTA,7  
#define D4_1     bsf PORTA,6 
#define D4_0     bcf PORTA,6  

#define RS_1     bsf PORTB,4 
#define RS_0     bcf PORTB,4    
#define E_1      bsf PORTB,6 
#define E_0      bcf PORTB,6 

#define Ligt_on  bsf PORTB,5 
#define Ligt_off bcf PORTB,5 

#define CS_1     bsf PORTB,7
#define CS_0     bcf PORTB,7
#define CLK_1    bsf PORTB,0
#define CLK_0    bcf PORTB,0
#define Din_1    bsf PORTB,2
#define Din_0    bcf PORTB,2
#define Dout_1   btfsc PORTB,1
#define Dout_0   btfss PORTB,1
#define strob    call  strb 
                                          
        ORG      0h                   
        goto     Init 
;******************************************************************************* 
;************   ПОДПРОГРАММА ПРЕРЫВАНИЙ   **************************************
        ORG      4h                ; адрес вектора прерывания 
        movwf    W_TEMP            ; копируем W в регистр - дубликат
        movf     STATUS,W          ; копируем STATUS в W 
        movwf    ST_TEMP           ; копируем W в регистр - дубликат
;**********************

        comf     rg_int,f          ; заходим в обработку по и против часовой         
        btfsc    rg_int,0          ; стрелке по очереди ( через раз ) 
        goto     m_down                                      
                                   ; начало обработки движения валкодера по часовой стрелке
        btfsc    phaze_tmp,3       ; если  фаза 3 пройдена    
        goto     ph_4
        btfsc    phaze_tmp,2       ; если  фаза 2 пройдена    
        goto     ph_3
        btfsc    phaze_tmp,1       ; если  фаза 1 пройдена      
        goto     ph_2

ph_1    movf     PORTA,w
        andlw    b'00011000'       ; маскируем ненужные биты в W
        clrz
        phase_1                    ; ожидаемое положение валкодера ( фаза 1 )
        skpz                       ; если  cовпадение , пропуск сл. команды           
        goto     end_int
        bsf      phaze_tmp,1       ; ставим метку  ( фаза 1 пройдена )
            
ph_2    movf     PORTA,w
        andlw    b'00011000'       ; маскируем ненужные биты в W
        clrz
        phase_2                    ; ожидаемое положение валкодера ( фаза 2 )
        skpz                       ; если  результат = 0 , пропуск сл. команды           
        goto     end_int
        bsf      phaze_tmp,2       ; ставим метку  ( фаза 2 пройдена )
                     
ph_3    movf     PORTA,w
        andlw    b'00011000'       ; маскируем ненужные биты в W
        clrz
        phase_3                    ; ожидаемое положение валкодера ( фаза 3 )
        skpz                       ; если  результат = 0 , пропуск сл. команды           
        goto     end_int
        bsf      phaze_tmp,3       ; ставим метку  ( фаза 3 пройдена )
           
ph_4    movf     PORTA,w
        andlw    b'00011000'       ; маскируем ненужные биты в W
        clrz
        phase_4                    ; ожидаемое положение валкодера ( фаза 4 )
        skpz                       ; если  результат = 0 , пропуск сл. команды           
        goto     end_int

        clrz
        comf     CCPR1L,w          ; если CCPR1L = 255 , уходим 
        skpnz
        clrf     phaze_tmp         ; стираем регистр с метками прохождения фаз валкодера 
        skpnz
        goto     end_int
        
        incf     CCPR1L,f
        ;movf     CCPR1L,w          ; копируем регистр ШИМа в регистр dig_lo для отображения на дисплее       
        ;movwf    dig_lo

        clrf     phaze_tmp         ; стираем регистр с метками прохождения фаз валкодера 

        goto     end_int           ; окончание обработки движения валкодера по часовой стрелке
                       
m_down  btfsc    phaze_tmp,6       ; начало обработки движения валкодера против часовой стрелки   
        goto     ph_8
        btfsc    phaze_tmp,5          
        goto     ph_7
        btfsc    phaze_tmp,4            
        goto     ph_6

ph_5    movf     PORTA,w
        andlw    b'00011000'    
        clrz
        phase_3                 
        skpz                                 
        goto     end_int
        bsf      phaze_tmp,4     
            
ph_6    movf     PORTA,w
        andlw    b'00011000'     
        clrz
        phase_2                  
        skpz                              
        goto     end_int
        bsf      phaze_tmp,5     
                     
ph_7    movf     PORTA,w
        andlw    b'00011000'   
        clrz
        phase_1                
        skpz                              
        goto     end_int
        bsf      phaze_tmp,6      
           
ph_8    movf     PORTA,w
        andlw    b'00011000'    
        clrz
        phase_4                  
        skpz                                
        goto     end_int

        clrz
        movf     CCPR1L,w           ; если CCPR1L = 0 , уходим 
        skpnz
        clrf     phaze_tmp          ; стираем регистр с метками прохождения фаз валкодера 
        skpnz
        goto     end_int
        
        decf     CCPR1L,f
        ;movf     CCPR1L,w           ; копируем регистр ШИМа в регистр dig_lo для отображения на дисплее  
        ;movwf    dig_lo

        clrf     phaze_tmp          ; стираем регистр с метками прохождения фаз валкодера 

        goto     end_int            ; окончание обработки движения валкодера против часовой стрелки 

end_int clrf     TMR0               ; начинаем отсчет до следующего прерывания      
        bcf      INTCON,2
        CLRWDT 
;**********************
        movf    ST_TEMP,W           ; возвращаем прежние значения в STATUS 
        movwf   STATUS              ; и W
        swapf   W_TEMP,f
        swapf   W_TEMP,W
        retfie                      ; возврат из прерывания GIE устанавливается в 1                                                      
;*******************************************************************************
;***********   ИНИЦИАЛИЗАЦИЯ КОНТРОЛЛЕРА  ************************************** 
Init 			
        bank1
        movlw    b'11111111'          
        movwf    PR2^80H            ; Период для ШИМ 
        movlw    b'00111100'           
        movwf    TRISA
        movlw    b'00000010'
        movwf    TRISB
	    movlw    b'00000000'        
        movwf    OPTION_REG^80H
        movlw    b'10100000'
        movwf	 INTCON	    	    ; прерывания разрешены от TMR0
        bank0
        movlw    b'00000000' 
        movwf    CCPR1L             ; скважность  
        movlw    b'00001100'    
        movwf    CCP1CON            ; активировать ШИМ ( биты 4 и 5 мл биты скважности )
        movlw    b'00000100'
        movwf    T2CON              ; Включить таймер 2
        movlw    .49
        movwf    T1CON              ; Разрешаем TMR1 c макс временем

        clrf	 RCSTA			    ; запрещение работы посл. порта USART
        clrf     PORTA  
        clrf     PORTB
        movlw    0x07
	    movwf	 CMCON			    ; выключаем модуль компараторов
        CS_1                        ; стоп конвертированию АЦП  
;******************************************************************************* 
;***********   МЕСТО ДЛЯ ТЕСТИРОВАНИЯ  *****************************************
nop
        ;call     Conversion
nop 
;*******************************************************************************
;***********   ИНИЦИАЛИЗАЦИЯ ДИСПЛЕЯ  ****************************************** 
        call     del_100ms         ; начальная задержка 100 милисекунд 
        movlw    b'00110011'       ; инициализация дисплея пока вкл 8 разрядов 
        call     LCD_com           ; грузим 30h 3 раза и один раз 20h
        movlw    b'00110010'       ; из каждого полубайта , начиная со старшего 
        call     LCD_com           
        movlw    b'00100000';20h   ; инициализация дисплея уже по 4х2 разрядам 
        call     LCD_com
        movlw    b'00001100';0Ch   ; включить отображение символов 
        call     LCD_com
        movlw    b'00000110';06h   ; автоматическое размещение знаков 
        call     LCD_com
        movlw    b'00101000'       ; включить двустрочную развертку
        call     LCD_com
        movlw    b'10000000'       ; курсор в начало первой строки
        call     LCD_com
        movlw    b'00000001'       ; очистить дисплей 
        call     LCD_com 
;*******************************************************************************
;***********   ОСНОВНАЯ ПРОГРАММА  *********************************************
BEGIN  
        movlw    0x85              ; курсор в пределах первой строки ( 0x80 - начало )
        call     LCD_com
        movlw    0x55              ; U
        call     LCD_dig 
 
        movlw    0x20              ; пусто  
        call     LCD_dig

        movlw    0x3D              ; =  
        call     LCD_dig
 
        movlw    0x8E              ; курсор в пределах первой строки ( 0x80 - начало )
        call     LCD_com
        movlw    0x56              ; V
        call     LCD_dig
 

        movlw    0xC5              ; курсор в пределах второй строки ( 0xС0 - начало )
        call     LCD_com 
        movlw    0x49              ; I
        call     LCD_dig 

        movlw    0x20              ; пусто  
        call     LCD_dig 

        movlw    0x3D              ; =        
        call     LCD_dig 

        movlw    0xCE              ; курсор в пределах второй строки ( 0xС0 - начало )
        call     LCD_com 
        movlw    0x41              ; A
        call     LCD_dig
 
        
        

        ;movlw    b'00000000'
        ;movwf    dig_lo

        ;movlw    b'00000000'
        ;movwf    dig_hi

        clrf     phaze_tmp
        clrf     rg_ligt

        call     EEPROM_RD         ; считать из памяти значение ШИМ
        
        ;movwf    dig_lo            ; значение ШИМ в dig_lo для отображения 


;******************************************************************************* 
;***********   ЗДЕСЬ КРУТИМСЯ ВСЕ ВРЕМЯ   **************************************

        call     LCD_mov
        func_on                    ; если нажата кнопка валкодера
        call     Func
        goto     $-3

;******************************************************************************* 
;*******************************************************************************
TABL_dig
        andlw  b'00001111'         ; маскируем старший полубайт W
        addwf  PCL,f
        retlw  0x30 
        retlw  0x31 
        retlw  0x32 
        retlw  0x33 
        retlw  0x34 
        retlw  0x35  
        retlw  0x36 
        retlw  0x37 
        retlw  0x38 
        retlw  0x39
;******************************************************************************* 
;*******************************************************************************
Func    clrf     TMR1L
        clrf     TMR1H
        bcf      PIR1,0
        func_off                   ; если кн валкодера отпущена до 0,5 сек 
        goto     $+5 
        btfss    PIR1,0
        goto     $-3
        call     EEPROM_WR         ; запомнить текущее значение ШИМ
        goto     $+6 
        comf     rg_ligt,f         ; инвертировать регистр состояния 
        btfss    rg_ligt,0
        Ligt_off                   ; выключить подсветку 
        btfsc    rg_ligt,0
        Ligt_on                    ; включить подсветку
        func_off                   ; дожидаемся отжатия 
        return
        goto     $-2         
;******************************************************************************* 
;*******************************************************************************
TRANSFORMER_dig
;***********
 movf    dig_lo,W              ; копируем младший байт в   
 movwf   bin2                  ; в bin2               
 movf    dig_hi,W              ; копируем старший байт в   
 movwf   bin1                  ; в bin1
;***********
;bin2 = младший байт преобразуемого числа
;bin1 = старший байт преобразуемого числа

;bcd3 ( младший полубайт ) = единицы
;bcd3 ( старший полубайт ) = десятки
;bcd2 ( младший полубайт ) = сотни
;bcd2 ( старший полубайт ) = тысячи
;bcd1 ( младший полубайт ) = десятки тысяч 
;***********                                               
Bin_bcd                         ; начало конвертирования                       
bin2bcd movlw    .16 
        movwf    ctr 
        clrf     bcd1 
        clrf     bcd2 
        clrf     bcd3 
        goto     start 
adjdec  movlw    0x33 
        addwf    bcd1,f 
        addwf    bcd2,f 
        addwf    bcd3,f 
        movlw    0x03 
        btfss    bcd1,3 
        subwf    bcd1,f 
        btfss    bcd2,3 
        subwf    bcd2,f 
        btfss    bcd3,3 
        subwf    bcd3,f 
        movlw    0x30 
        btfss    bcd1,7 
        subwf    bcd1,f 
        btfss    bcd2,7 
        subwf    bcd2,f 
        btfss    bcd3,7 
        subwf    bcd3,f 
start   rlf      bin2,f 
        rlf      bin1,f 
        rlf      bcd3,f 
        rlf      bcd2,f 
        rlf      bcd1,f 
        decfsz   ctr,f 
        goto     adjdec          ; окончание конвертирования   
                       
        movf    bcd1,w           ; распределение результата по регистрам         
        call    TABL_dig
        movwf   TenK             ; десятки тысяч 

        swapf   bcd2,w
        call    TABL_dig
        movwf   Thou             ; тысячи 

        movf    bcd2,w
        call    TABL_dig
        movwf   Hund             ; сотни 

        swapf   bcd3,w
        call    TABL_dig
        movwf   Tens             ; десятки 

        movf    bcd3,w
        call    TABL_dig
        movwf   Ones             ; единицы

        return         
;******************************************************************************* 
;*******************************************************************************
LCD_mov 
        call     CH_U            
        call     Conversion      ; измеряем напряжение ( время преобразования 600 ns ) 

        movlw    0x88            ; курсор в пределах первой строки ( 0x80 - начало )
        call     LCD_com 

        call     TRANSFORMER_dig  

        ;movf     TenK,w
        ;call     LCD_dig

        clrz
        movlw    0x30
        subwf    Thou,w          
        skpnz
        movlw    0x20
        skpnz
        movwf    Thou            ; подменяем пустым знакоместом , если первый 0  
          
        movf     Thou,w
        call     LCD_dig    
        
        movf     Hund,w
        call     LCD_dig

        movlw    0x2C            ; запятая 
        call     LCD_dig  

        movf     Tens,w
        call     LCD_dig
 
        ;movf     Ones,w
        ;call     LCD_dig 

;**************
        call     CH_I 
        call     Conversion      ; измеряем ток ( время преобразования 600 ns ) 
        
        movlw    0xC9            ; курсор в пределах второй строки ( 0xС0 - начало )
        call     LCD_com 

        call     TRANSFORMER_dig  

        ;movf     TenK,w
        ;call     LCD_dig
 
        movf     Thou,w
        call     LCD_dig

        movlw    0x2C           ; запятая 
        call     LCD_dig 
 
        movf     Hund,w
        call     LCD_dig 

        movf     Tens,w
        call     LCD_dig
 
        ;movf     Ones,w
        ;call     LCD_dig 

        return  
;******************************************************************************* 
;*******************************************************************************
LCD_dig
        movwf    LCD_tmp        ; загрузка цифры 
        E_0
        RS_1  
        call     LCD_load
        return 
;******************************************************************************* 
;*******************************************************************************
LCD_com                         ; загрузка комманды
        movwf    LCD_tmp
        E_0
        RS_0   
        call     LCD_load
        return     
;******************************************************************************* 
;*******************************************************************************
LCD_load                         ; загрузка данных непосредственно в дисплей
        btfsc    LCD_tmp,7       ; со стробированием
        D7_1      
        btfss    LCD_tmp,7
        D7_0
        btfsc    LCD_tmp,6
        D6_1      
        btfss    LCD_tmp,6
        D6_0
        btfsc    LCD_tmp,5
        D5_1      
        btfss    LCD_tmp,5
        D5_0
        btfsc    LCD_tmp,4
        D4_1      
        btfss    LCD_tmp,4
        D4_0
        E_1
        call     del_1ms
        E_0
        call     del_1ms
        btfsc    LCD_tmp,3
        D7_1      
        btfss    LCD_tmp,3
        D7_0
        btfsc    LCD_tmp,2
        D6_1      
        btfss    LCD_tmp,2
        D6_0
        btfsc    LCD_tmp,1
        D5_1      
        btfss    LCD_tmp,1
        D5_0
        btfsc    LCD_tmp,0
        D4_1      
        btfss    LCD_tmp,0
        D4_0
        E_1
        call     del_1ms
        E_0
        call     del_1ms     
        return 
;******************************************************************************* 
;***********   ЗАДЕРЖКА 500 ms *************************************************
del_500ms 
        clrf   TMR1L                
        clrf   TMR1H            
        bcf    PIR1,0                      
        btfss  PIR1,0
        goto   $-1 
        return            
;******************************************************************************* 
;***********   ЗАДЕРЖКА 100 ms *************************************************
del_100ms 
        call   del_50ms
        call   del_50ms
        return
;******************************************************************************* 
;***********   ЗАДЕРЖКА 50 ms *************************************************
del_50ms 
        clrf   TMR1L                
        movlw  .232
        movwf  TMR1H              
        bcf    PIR1,0                      
        btfss  PIR1,0
        goto   $-1 
        return                                    
;******************************************************************************* 
;***********   ЗАДЕРЖКА 1 ms  **************************************************
del_1ms 
        movlw  .136
        movwf   TMR1L                
        movlw  .255
        movwf  TMR1H              
        bcf    PIR1,0                      
        btfss  PIR1,0
        goto   $-1 
        return
;******************************************************************************* 
;***********   ЗАДЕРЖКА 10 ns  **************************************************
del_10ns 
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        return
;*******************************************************************************
;*******************************************************************************
EEPROM_RD
        CLRWDT
        bcf	     INTCON,GIE		  ; запретить прерывания
        movlw    .0               ; копируем в EEADR адрес ячейки
        banksel  EEADR  
        movwf    EEADR            ; Чтение байта из EEPROM
	    bsf      EECON1,RD        ; начать чтение
	    movf     EEDATA,W         ; копируем в W цифру из ячейки
        bsf	     INTCON,GIE       ; разрешить прерывания
        bank0
        movwf    CCPR1L
        return
;*******************************************************************************
;*******************************************************************************
EEPROM_WR 
        CLRWDT
        bcf	      INTCON,GIE	  ; запретить прерывания  
        movlw     .0              ; Адрес ячейки куда производится запись
        banksel   EEADR
        movwf     EEADR
        bank0
        movf      CCPR1L,w        ; Данные для записи  
        banksel   EEDATA
        movwf     EEDATA
        banksel   EECON1
        bsf	      EECON1,WREN     ; Разрешить запись в ЕЕPROM 
        call      ee_wr
        bsf	      INTCON,GIE      ; разрешить прерывания
        return
;*******************************************************************************
;*******************************************************************************
ee_wr   CLRWDT
        banksel   EECON2
     	movlw     55H            		 
	    movwf     EECON2		       
    	movlw     0AAH			        
    	movwf     EECON2		  ; Макро вызывается перед записью в EEPROM
    	bsf	      EECON1,WR	      ; Начать запись в EEPROM по адресу EEADR
ee_wr1	CLRWDT
        banksel   EECON1;
        btfsc	  EECON1,WR	      ; Запись завершена ?
	    goto      ee_wr1		  ; нет
        banksel   EECON1;
        bcf    	  EECON1,WREN	  ; Запретить запись в ЕЕPROM
        bank0
        return           
;*******************************************************************************  
;*******************************************************************************    
CH_U    clrf      dig_lo
        clrf      dig_hi
        bcf	      INTCON,GIE	   ; запретить прерывания  
        CS_0                       ; разрешить работу АЦП 
        Din_1                      ; cтартовый бит                                         
        strob
        Din_1                      ; SGL/DIFF                      
        strob
        Din_0                      ; ODD/SIGN                     
        strob
        Din_1                      ; MC/BF                      
        strob
        Din_0                      ; получение результата преобразования АЦП 
        return 
;*******************************************************************************  
;*******************************************************************************    
CH_I    clrf      dig_lo
        clrf      dig_hi
        bcf	      INTCON,GIE	   ; запретить прерывания  
        CS_0                       ; разрешить работу АЦП 
        Din_1                      ; cтартовый бит                                         
        strob
        Din_1                      ; SGL/DIFF                      
        strob
        Din_1                      ; ODD/SIGN                     
        strob
        Din_1                      ; MC/BF                      
        strob
        Din_0                      ; получение результата преобразования АЦП 
        return 
;*******************************************************************************  
;*******************************************************************************
Conversion
       
        CLK_0
        call       del_10ns 
        Dout_1                     ; нулевой бит ( всегда = 0 )
        bsf        dig_hi,4                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns
        Dout_1                     ; 11 бит  
        bsf        dig_hi,3                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns
        Dout_1                     ; 10 бит  
        bsf        dig_hi,2                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns
        Dout_1                     ; 9 бит  
        bsf        dig_hi,1                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns
        Dout_1                     ; 8 бит  
        bsf        dig_hi,0                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns 
        Dout_1                     ; 7 бит  
        bsf        dig_lo,7                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns 
        Dout_1                     ; 6 бит  
        bsf        dig_lo,6                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns
        Dout_1                     ; 5 бит  
        bsf        dig_lo,5                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns 
        Dout_1                     ; 4 бит  
        bsf        dig_lo,4                  
        CLK_1
        call       del_10ns    

        CLK_0
        call       del_10ns 
        Dout_1                     ; 3 бит  
        bsf        dig_lo,3                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns
        Dout_1                     ; 2 бит  
        bsf        dig_lo,2                  
        CLK_1
        call       del_10ns

        CLK_0
        call       del_10ns 
        Dout_1                     ; 1 бит  
        bsf        dig_lo,1                  
        CLK_1
        call       del_10ns 
        
        CLK_0
        call       del_10ns 
        Dout_1                     ; 0 бит  
        bsf        dig_lo,0                  
        CLK_1
        call       del_10ns

        CS_1                       ; стоп конвертированию АЦП 
        
        bsf	      INTCON,GIE      ; разрешить прерывания
        
        return
;*******************************************************************************  
;*******************************************************************************
strb    CLK_0
        call       del_10ns
        CLK_1
        call       del_10ns
        return 
;*******************************************************************************  
;******************************************************************************* 
        end
