Программа управления БП 16f876, глюк

Поклонники продукции Microchip Technology Inc тусуются тут.
Ответить
Аватара пользователя
4uvak
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт авг 16, 2012 10:41:42

Программа управления БП 16f876, глюк

Сообщение 4uvak »

Пишу программу управления блоком питания. И наткнулся на небольшую проблему. Суть проблемы - нажимаю кнопку энкодера, - устройство отключается. Все работает как надо. Но если нажать кнопку энкодера, и удерживая кнопку крутить энкодер - начинаются глюки. Билибирда на дисплее, зависание, - перезагрузка. Такой вариант управления не предусмотрен в устройстве, но все же хотелось разобраться. При нажатии и удерживании кнопки энкодера выполняется следующая программа.
Спойлер

Код: Выделить всё

; если мы попали сюда -> было сгенерировано прерывание по изменению состояния на входах RB4, RB5, RB6, RB7
            ORG         4h          ; адрес вектора прерывания 
            movwf       W_TEMP      ; копируем W в регистр - дубликат
            movf        STATUS,W    ; копируем STATUS в W 
            movwf       ST_TEMP      ; копируем W в регистр - дубликат
            movf        PORTB, W    ; производим чтение порта B для исключения несоответствия
            bcf         INTCON, RBIF; сбрасываем флаг RBIF
            btfss       SUP_VS      ; выявляем источник прерывания в порядке приоритетов - опрашиваем супервизор
            goto        SAVE        ; сохраняем настройки в EEPROM, если супервизор в сброшенном состоянии
            btfss       ON_OFF_ENC  ; опрашиваем кнопку энкодера
            goto        Button      ; уходим в ПП обработки данных с кнопки, если кнопка была нажата 
........
Button      movlw       .1          ; вводим константы для ожидания отжатия кнопки (1s)
            movwf       Reg_1        ; -//- 
            movlw       .69          ; -//- 
            movwf       Reg_2        ; -//-
            movlw       .21          ; -//- 
            movwf       Reg_3        ; -//-
trc         decfsz      Reg_1, F
            goto        trc
            btfsc       ON_OFF_ENC  ; ждем момента отжатия кнопки энкодера
            goto        incMETKA    ; перескакиваем сюда, если отжата кнопка менее чем за 1 сек
            clrwdt
            decfsz      Reg_2, F
            goto        trc
            decfsz      Reg_3, F
            goto        trc
            goto        Power_off    ; отключаем устройство
Все выполняется как надо. Устройство отключается. Но если во время нажатия крутить энкодер, то устройство глючит. Почему? Ведь в этой части программы опрашивается в порядке приоритетов только кнопка энкодера. До опроса тактирующих импульсов и данных с энкодера в этом участке программы не доходит. Но тем не менее изза тактирующих импульсов или данных устройство глючит. А так зависаний никаких не происходит (если не нажать кнопку энкодера и крутить). Устройство работает стабильно. Кнопка энкодера прицеплена на RB6, данные и тактирующие импульсы энкодера RB5, RB4

Полный текст разрабатываемой программы.
Спойлер

Код: Выделить всё

           LIST      p=16F876A
            #include  <P16F876A.inc> 
            __CONFIG  (_LVP_OFF & _CP_OFF & _CPD_OFF & _PWRTE_OFF & _WDT_ON & _HS_OSC & _BODEN_ON & _DEBUG_OFF )

cblock      0x20 
W_TEMP                              ; временный регистр - дубликат W
ST_TEMP                              ; временный регистр - дубликат STATUS
Reg_1                                ; временные регистры для ПП задержек в прерывании
Reg_2                                ; -//-
Reg_3                                ; -//-
TEMPS                                ; используем для меток установки U или I
Reg_tmp_I_L                          ; временные регистры для хранения уставок U и I
Reg_tmp_I_H                          ; -//-
Reg_tmp_U_L                          ; -//-
Reg_tmp_U_H                          ; -//-
Reg_4                                ; тут храним шаблон для сравнения с нулевым результатом и подменой пустым знакоместом
Reg_tmpL                            ; сюда переносим данные перед трансформацией двоичного числа в десятичное
Reg_tmpH                            ; -//-
ctr                                  ; временные регистры в ПП конвертации двоичного числа в десятичное
bcd1                                ; -//-
bcd2                                ; -//-
bcd3                                ; -//-
bin1                                ; -//-
bin2                                ; -//-
TenK                                ; десятки тысяч
Thou                                ; тысячи
Hund                                ; сотни
Tens                                ; десятки
Ones                                ; единицы



Reg_tmp1                            ; временные регистры для ПП задержек
Reg_tmp2                            ; -//-
Reg_tmp3                            ; -//-
Reg_tmp4                            ; временные регистры для ПП задержек для ПП прерывания
Reg_tmp5                            ; -//-
LCD_tmp                              ; временный регистр для вывода данных на LCD
endc      



#define METKA           TEMPS,0      ; используем для меток установки U или I
#define DAT_ENC         PORTB,RB4    ; назначаем порт для ввода данных с энкодера
#define CLK_ENC         PORTB,RB5    ; назначаем порт для ввода тактирующих импульсов с энкодера
#define ON_OFF_ENC      PORTB,RB6    ; назначаем порт для кнопки энкодера
#define SUP_VS          PORTB,RB7    ; назначаем порт для опроса супервизора
#define LED_ON      bsf PORTC,RC7    ; назначаем вывод для управления подсветкой LCD
#define LED_OFF     bcf PORTC,RC7    ; назначаем вывод для управления подсветкой LCD
#define E_1         bsf PORTC,RC6    ; назначаем вывод для команд E на PORTC для LCD
#define E_0         bcf PORTC,RC6    ; назначаем вывод для команд E на PORTC для LCD
#define RS_1        bsf PORTC,RC5    ; назначаем вывод для команд RS на PORTC для LCD
#define RS_0        bcf PORTC,RC5    ; назначаем вывод для команд RS на PORTC для LCD
#define D7_1        bsf PORTB,RB0    ; назначаем порты для вывода данных на LCD
#define D7_0        bcf PORTB,RB0    ; -//-
#define D6_1        bsf PORTB,RB1    ; -//-
#define D6_0        bcf PORTB,RB1    ; -//-
#define D5_1        bsf PORTB,RB2    ; -//-
#define D5_0        bcf PORTB,RB2    ; -//-
#define D4_1        bsf PORTB,RB3    ; -//-
#define D4_0        bcf PORTB,RB3    ; -//-

            org         2100h        ; На стадии "прошивки", записываем в EEPROM-ячейку,
            de          .100        ; с адресом 00h, число 100 (64)
            org         2101h        ; На стадии "прошивки", записываем в EEPROM-ячейку,
            de          .0          ; с адресом 01h, число 0 (0)
            org         2102h        ; На стадии "прошивки", записываем в EEPROM-ячейку,
            de          .30          ; с адресом 02h, число 30 (1E)
            org         2103h        ; На стадии "прошивки", записываем в EEPROM-ячейку,
            de          .0          ; с адресом 03h, число 0 (0)
            org         2104h        ; На стадии "прошивки", записываем в EEPROM-ячейку,
            de          .0          ; с адресом 04h, число 0 (0)

                          ;;;;;;;;;;;;;;;;;;;
                          ; старт программы;
                          ;;;;;;;;;;;;;;;;;;;
            org         0
            goto        START 

                          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                          ; подпрограмма приема данных с энкодера;
                          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; если мы попали сюда -> было сгенерировано прерывание по изменению состояния на входах RB4, RB5, RB6, RB7
            ORG         4h          ; адрес вектора прерывания 
            movwf       W_TEMP      ; копируем W в регистр - дубликат
            movf        STATUS,W    ; копируем STATUS в W 
            movwf       ST_TEMP      ; копируем W в регистр - дубликат
            movf        PORTB, W    ; производим чтение порта B для исключения несоответствия
            bcf         INTCON, RBIF; сбрасываем флаг RBIF
            btfss       SUP_VS      ; выявляем источник прерывания в порядке приоритетов - опрашиваем супервизор
            goto        SAVE        ; сохраняем настройки в EEPROM, если супервизор в сброшенном состоянии
            btfss       ON_OFF_ENC  ; опрашиваем кнопку энкодера
            goto        Button      ; уходим в ПП обработки данных с кнопки, если кнопка была нажата 

ENC         movlw       .48          ; вводим константы ожидания приема данных 1 на CLK_ENC (150ms)
            movwf       Reg_1        ; -//- 
            movlw       .11          ; -//- 
            movwf       Reg_2        ; -//- 
            movlw       .4          ; -//- 
            movwf       Reg_3        ; -//- 
ers         btfsc       CLK_ENC      ; опрашиваем тактовый вход энкодера
            goto        READ_ENC    ; уходим считывать данные, если на тактовом входе 1
            decfsz      Reg_1, F
            goto        ers
            clrwdt
            decfsz      Reg_2, F
            goto        ers
            decfsz      Reg_3, F
            goto        ers
            goto        END_ENC      ; уходим из ПП если закончилось время ожидания приема данных (150ms) (не дождались 1)

READ_ENC    call        del_1msc    ; необходимо для устранения дребезга
            movlw       .48          ; вводим константы ожидания приема данных 0 на CLK_ENC (150ms)
            movwf       Reg_1        ; -//- 
            movlw       .11          ; -//- 
            movwf       Reg_2        ; -//-
            movlw       .4          ; -//- 
            movwf       Reg_3        ; -//- 
rew         btfss       CLK_ENC      ; опрашиваем тактовый вход энкодера
            goto        READY        ; уходим считывать данные, если на тактовом входе 0
            decfsz      Reg_1, F
            goto        rew
            clrwdt
            decfsz      Reg_2, F
            goto        rew
            decfsz      Reg_3, F
            goto        rew
            goto        END_ENC      ; уходим из ПП если закончилось время ожидания приема данных (150ms) (не дождались 0)

READY       btfsc       METKA        ; для начала проверяем метку и исходя из этого меняем уставки U или I при повороте энкодера
            goto        UST_I        ; -//- 
            btfss       METKA        ; -//- 
            goto        UST_U        ; -//- 

UST_I       btfsc       DAT_ENC
            goto        I_UP
            btfss       DAT_ENC
            goto        I_DOWN

I_UP        bcf         STATUS, Z    ; сбрасываем флаг Z
            movlw       0x01        ; загружаем шаблон для проверки предельного результата 500         
            xorwf       Reg_tmp_I_H,W; сравниваем со старшим регистром
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=совпали данные)
            goto        I_UPs
            movlw       0xF4        ; загружаем шаблон для проверки предельного результата 500      
            xorwf       Reg_tmp_I_L,W; сравниваем с младшим регистром
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=совпали данные)
            goto        I_UPs
            goto        ENC          ; уходим отсюда (ничего не делаем если результат 500)

I_DOWN      bcf         STATUS, Z    ; сбрасываем флаг Z
            movlw       0x00        ; загружаем шаблон для проверки нулевого результата 001          
            xorwf       Reg_tmp_I_H,W; сравниваем со старшим регистром 
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=совпали данные)
            goto        I_DOWNs
            movlw       0x01        ; загружаем шаблон для проверки нулевого результата 001
            xorwf       Reg_tmp_I_L,W; сравниваем с младшим регистром
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=совпали данные)
            goto        I_DOWNs
            goto        ENC          ; уходим отсюда (ничего не делаем если результат 001)

I_UPs       bcf         STATUS, Z    ; сбрасываем флаг Z
            incf        Reg_tmp_I_L,F; увеличиваем содержимое Reg_tmp_I_L
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=был перенос)
            goto        OUTPUT_I1
            incf        Reg_tmp_I_H,F; увеличиваем содержимое Reg_tmp_I_H
            goto        OUTPUT_I1

I_DOWNs     bcf         STATUS, Z    ; сбрасываем флаг Z
            decf        Reg_tmp_I_L,F; уменьшаем содержимое Reg_tmp_I_L
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=был перенос)
            goto        OUTPUT_I1
            decf        Reg_tmp_I_H,F; уменьшаем содержимое Reg_tmp_I_H
            goto        OUTPUT_I1

OUTPUT_I1   call        OUTPUT_I
            goto        ENC
UST_U       btfsc       DAT_ENC
            goto        U_UP
            btfss       DAT_ENC
            goto        U_DOWN

U_UP        bcf         STATUS, Z    ; сбрасываем флаг Z
            movlw       0x00        ; загружаем шаблон для проверки предельного результата 240          
            xorwf       Reg_tmp_U_H,W; сравниваем со старшим регистром
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=совпали данные)
            goto        U_UPs
            movlw       0xF0        ; загружаем шаблон для проверки предельного результата 240          
            xorwf       Reg_tmp_U_L,W; сравниваем с младшим регистром
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=совпали данные)
            goto        U_UPs
            goto        ENC          ; уходим отсюда (ничего не делаем если результат 240)

U_DOWN      bcf         STATUS, Z    ; сбрасываем флаг Z
            movlw       0x00        ; загружаем шаблон для проверки нулевого результата 001          
            xorwf       Reg_tmp_U_H,W; сравниваем со старшим регистром 
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=совпали данные)
            goto        U_DOWNs
            movlw       0x01        ; загружаем шаблон для проверки нулевого результата 001
            xorwf       Reg_tmp_U_L,W; сравниваем с младшим регистром
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=совпали данные)
            goto        U_DOWNs
            goto        ENC          ; уходим отсюда (ничего не делаем если результат 001)

U_UPs       bcf         STATUS, Z    ; сбрасываем флаг Z
            incf        Reg_tmp_U_L,F; увеличиваем содержимое Reg_tmp_U_L
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=был перенос)
            goto        OUTPUT_U1
            incf        Reg_tmp_U_H,F; увеличиваем содержимое Reg_tmp_U_H
            goto        OUTPUT_U1

U_DOWNs     bcf         STATUS, Z    ; сбрасываем флаг Z
            decf        Reg_tmp_U_L,F; уменьшаем содержимое Reg_tmp_U_L
            btfss       STATUS, Z    ; проверяем состояние флага Z, пропускаем если 1 (1=был перенос)
            goto        OUTPUT_U1
            decf        Reg_tmp_U_H,F; уменьшаем содержимое Reg_tmp_U_H
            goto        OUTPUT_U1

OUTPUT_U1   call        OUTPUT_U
            goto        ENC


Button      movlw       .1          ; вводим константы для ожидания отжатия кнопки (1s)
            movwf       Reg_1        ; -//- 
            movlw       .69          ; -//- 
            movwf       Reg_2        ; -//-
            movlw       .21          ; -//- 
            movwf       Reg_3        ; -//-
trc         decfsz      Reg_1, F
            goto        trc
            btfsc       ON_OFF_ENC  ; ждем момента отжатия кнопки энкодера
            goto        incMETKA    ; перескакиваем сюда, если отжата кнопка менее чем за 1 сек
            clrwdt
            decfsz      Reg_2, F
            goto        trc
            decfsz      Reg_3, F
            goto        trc
            goto        Power_off    ; отключаем устройство

TABL_dig    andlw       b'00001111'  ; маскируем старший полубайт W (обнуляем 4 старших байта)
            addwf       PCL,f        ; Содержимое счетчика команд PC увеличивается на величину содержимого аккумулятора W.
            retlw       0x30        ; 0
            retlw       0x31        ; 1 
            retlw       0x32        ; 2 
            retlw       0x33        ; 3 
            retlw       0x34        ; 4 
            retlw       0x35        ; 5  
            retlw       0x36        ; 6 
            retlw       0x37        ; 7 
            retlw       0x38        ; 8 
            retlw       0x39        ; 9
            retlw       0x41        ; A
            retlw       0x42        ; B
            retlw       0x43        ; C
            retlw       0x44        ; D
            retlw       0x45        ; E
            retlw       0x46        ; F

incMETKA    movlw       B'00000001'  ; инвертируем нулевой бит регистра TEMPS
            xorwf       TEMPS, F    ; -//-
            btfss       METKA        ; обновляем местоположение метки
            call        METKA_L      ; -//-
            btfsc       METKA        ; -//-
            call        METKA_H      ; -//-
            goto        END_ENC      ; метка установлена, выходим из прерывания



END_ENC     movf        ST_TEMP,W    ; возвращаем прежние значения в STATUS и W
            movwf       STATUS      ; -//-
            swapf       W_TEMP,f    ; -//-
            swapf       W_TEMP,W    ; -//-
            bsf         INTCON, GIE  ; разрешаем прерывания
            retfie                  ; возврат из прерывания GIE устанавливается в 1  


                          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                          ; подготовительные операции;
                          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
START       bcf         STATUS,RP0  ; переход в банк 0
            banksel     OPTION_REG  ; переходим в регистр OPTION_REG
            movlw       b'00001101'  ; включаем подтягивающие резисторы PORTB, включаем предделитель перед WDT 1:32
            movwf       OPTION_REG  ; -//-
            banksel     INTCON      ; переходим в регистр INTCON
            movlw       b'00001000'  ; глобальный запрет прерываний, разрешение прерываний по изменению сигнала на входах RB4 - RB7
            movwf       INTCON      ; -//-
            banksel     PIE1        ; переходим в регистр PIE1
            movlw       b'00000000'  ; глобальный запрет периферийных прерываний
            movwf       PIE1        ; -//-
            banksel     TRISA        ; переходим в регистр PORTA
            movlw       b'00101111'  ; настраиваем RA0, RA1, RA2, RA3, RA5 на вход, остальные на выход
            movwf       TRISA        ; -//-
            banksel     TRISB        ; переходим в регистр PORTB
            movlw       b'11110000'  ; настраиваем все порты на выход, RB4, RB5, RB6, RB7 на вход
            movwf       TRISB        ; -//-
            banksel     TRISC        ; переходим в регистр PORTC
            movlw       b'00000000'  ; настраиваем все порты на выход
            movwf       TRISC        ; -//-
            banksel     T1CON        ; переходим в регистр T1CON
            movlw       b'00000000'  ; отключаем модуль T1CON
            movwf       T1CON        ; -//-
            banksel     T2CON        ; переходим в регистр T2CON
            movlw       b'00000000'  ; отключаем модуль T2CON
            movwf       T2CON        ; -//-
            banksel     CCP1CON      ; переходим в регистр CCP1CON
            movlw       b'00000000'  ; отключаем модуль CCP1
            movwf       CCP1CON      ; -//-
            banksel     CCP2CON      ; переходим в регистр CCP2CON
            movlw       b'00000000'  ; отключаем модуль CCP2
            movwf       CCP2CON      ; -//-
            banksel     SSPSTAT      ; переходим в регистр SSPSTAT
            movlw       b'00000000'  ; отключаем модуль SSPSTAT
            movwf       SSPSTAT      ; -//-
            banksel     SSPCON      ; переходим в регистр SSPCON
            movlw       b'00000000'  ; отключаем модуль SSPCON
            movwf       SSPCON      ; -//-
            banksel     SSPCON2      ; переходим в регистр SSPCON2
            movlw       b'00000000'  ; отключаем модуль SSPCON2
            movwf       SSPCON2      ; -//-  
            banksel     TXSTA        ; переходим в регистр TXSTA
            movlw       b'00000000'  ; отключаем модуль TXSTA
            movwf       TXSTA        ; -//-  
            banksel     RCSTA        ; переходим в регистр RCSTA
            movlw       b'00000000'  ; отключаем модуль RCSTA
            movwf       RCSTA        ; -//- 
            banksel     ADCON0      ; переходим в регистр ADCON0
            movlw       b'00000000'  ; отключаем модуль АЦП
            movwf       ADCON0      ; -//- 
            banksel     ADCON1      ; переходим в регистр ADCON1
            movlw       b'00000000'  ; отключаем модуль АЦП
            movwf       ADCON1      ; -//- 
            bcf         STATUS,RP0  ; переход в банк 0



            call        READY_EEP    ; отправляемся читать данные из EEPROM
            clrf        Reg_tmp_U_H  ; удаляем данную строку, если необходимо хранить уставки напряжения выше 25,5V

                          ;;;;;;;;;;;;;;;;;;;;;;;;;
                          ; инициализация дисплея;
                          ;;;;;;;;;;;;;;;;;;;;;;;;;
            call        del_100ms    ; начальная задержка 100 милисекунд 
            movlw       b'00110011'  ; инициализация дисплея пока вкл 8 разрядов 
            call        LCD_com      ; грузим 0011 3 раза и один раз 0010  
            movlw       b'00110010'  ; -//-
            call        LCD_com      ; -//-   
            movlw       b'00100000'  ; инициализация дисплея уже по 4х2 разрядам 
            call        LCD_com      ; -//-   
            movlw       b'00101000'  ; вкл 4 разрядный ввод данных, размер символа 5х8 символов
            call        LCD_com      ; -//- 
            movlw       b'00000110'  ; сдвиг курсора вправо
            call        LCD_com      ; -//-  
            movlw       b'00001100'  ; отключаем курсор
            call        LCD_com      ; -//-   
            movlw       b'00010100'  ; двигаем курсор вправо
            call        LCD_com      ; -//-  
            movlw       b'00000001'  ; очищаем дисплей
            call        LCD_com      ; -//-

; выставляем метку уставок I или U
            btfss       METKA
            call        METKA_L
            btfsc       METKA
            call        METKA_H

; выставляем значение уставки U и I
            call        OUTPUT_U
            call        OUTPUT_I



gooo        LED_ON

            movlw       0x80        ; курсор в пределах первой строки ( 0x80 - начало )
            call        LCD_com      ; загружаем команду 
            movlw       0x55        ; U
            call        LCD_dig      ; загружаем данные
            movlw       0x3D        ; =
            call        LCD_dig      ; загружаем данные
            movlw       0x32        ; 2
            call        LCD_dig      ; загружаем данные
            movlw       0x33        ; 3
            call        LCD_dig      ; загружаем данные
            movlw       0x2E        ; .
            call        LCD_dig      ; -//- 
            movlw       0x30        ; 0
            call        LCD_dig      ; загружаем данные
            movlw       0x56        ; =
            call        LCD_dig      ; загружаем данные

            bsf         INTCON, GIE  ; разрешаем прерывания
            call        del_100ms
            call        del_100ms
            call        del_100ms
            bcf         INTCON, GIE  ; запрещаем прерывания
            goto        gooo



                          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                          ; Подпрограмма конвертации двоичного числа в десятичное;
                          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TRANSFORMER_dig
            movf        Reg_tmpL,W  ; копируем младший байт результата преобразования АЦП в   
            movwf       bin2        ; в bin2               
            movf        Reg_tmpH,W  ; копируем старший байт результата преобразования АЦП в    
            movwf       bin1        ; в bin1
;bin2 = младший байт преобразуемого числа
;bin1 = старший байт преобразуемого числа
;bcd3 ( младший полубайт ) = единицы
;bcd3 ( старший полубайт ) = десятки
;bcd2 ( младший полубайт ) = сотни
;bcd2 ( старший полубайт ) = тысячи
;bcd1 ( младший полубайт ) = десятки тысяч                                          
            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      ; распределение результата по регистрам        
            movwf       TenK        ; десятки тысяч 
            swapf       bcd2,w
            movwf       Thou        ; тысячи 
            movf        bcd2,w
            movwf       Hund        ; сотни 
            swapf       bcd3,w
            movwf       Tens        ; десятки 
            movf        bcd3,w
            movwf       Ones        ; единицы
            return 


                          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                          ; Подпрограмма вывода данных на HD44780;
                          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; загрузка комманды
LCD_com     movwf       LCD_tmp           
            E_0
            RS_0
            call        LCD_load
            return     

; загрузка цифры 
LCD_dig     movwf       LCD_tmp           
            E_0
            RS_1
            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 

; ЗАДЕРЖКА 20 mcs
del_20mcs   movlw       .26
            movwf       Reg_tmp1
wr1         decfsz      Reg_tmp1, F
            goto        wr1
            return

; ЗАДЕРЖКА 1 ms
del_1ms     movlw       .46
            movwf       Reg_tmp1
            movlw       .6
            movwf       Reg_tmp2
wr2         decfsz      Reg_tmp1, F
            goto        wr2
            decfsz      Reg_tmp2, F
            goto        wr2
            return     

; ЗАДЕРЖКА 1 ms в ПП прерывания
del_1msc    movlw       .46
            movwf       Reg_tmp4
            movlw       .6
            movwf       Reg_tmp5
wr4         decfsz      Reg_tmp4, F
            goto        wr4
            decfsz      Reg_tmp5, F
            goto        wr4
            return  

; ЗАДЕРЖКА 5 ms 
del_5ms     call        del_1ms
            call        del_1ms
            call        del_1ms
            call        del_1ms
            call        del_1ms
            return

; ЗАДЕРЖКА 50 ms
del_50ms    movlw       .186
            movwf       Reg_tmp1
            movlw       .4
            movwf       Reg_tmp2
            movlw       .2
            movwf       Reg_tmp3
wr3         decfsz      Reg_tmp1, F
            goto        wr3
            decfsz      Reg_tmp2, F
            goto        wr3
            decfsz      Reg_tmp3, F
            goto        wr3
            clrwdt
            return

; ЗАДЕРЖКА 100 ms 
del_100ms   call        del_50ms
            call        del_50ms
            return

; ставим верхнюю метку
METKA_L     movlw       0x89        ; курсор в пределах первой строки ( 0x80 - начало )
            call        LCD_com      ; загружаем команду 
            movlw       0x3E        ; > ставим верхнюю метку
            call        LCD_dig      ; загружаем данные
            movlw       0xC9        ; курсор в пределах второй строки ( 0xC0 - начало )
            call        LCD_com      ; загружаем команду
            movlw       0x20        ; стираем нижнюю метку
            call        LCD_dig      ; загружаем данные
            return

; ставим нижнюю метку
METKA_H     movlw       0x89        ; курсор в пределах первой строки ( 0x80 - начало )
            call        LCD_com      ; загружаем команду 
            movlw       0x20        ; стираем верхнюю метку
            call        LCD_dig      ; загружаем данные
            movlw       0xC9        ; курсор в пределах второй строки ( 0xC0 - начало )
            call        LCD_com      ; загружаем команду
            movlw       0x3E        ; > ставим нижнюю метку
            call        LCD_dig      ; загружаем данные
            return

; выводим данные устаки U
OUTPUT_U    movf        Reg_tmp_U_L,W; копируем в W содержимое Reg_tmp_U_L
            movwf       Reg_tmpL
            movf        Reg_tmp_U_H,W; копируем в W содержимое Reg_tmp_U_H
            movwf       Reg_tmpH
            movlw       0x8B        ; курсор в пределах первой строки ( 0x80 - начало )
            call        LCD_com      ; загружаем команду
            call        TRANSFORMER_dig
            movlw       0x30        ; подменяем пустым знакоместом , если первый 0 
            movwf       Reg_4        ; -//-
            movf        Hund,W      ; -//-
            call        TABL_dig    ; -//-
            xorwf       Reg_4,F      ; -//-
            skpnz                    ; -//-
            movlw       0x20        ; -//-
            call        LCD_dig      ; -//-
         end
Реклама
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15573
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Программа управления БП 16f876, глюк

Сообщение BOB51 »

чтоб не вчитываться...
Опрос энкодера программный, а кнопка обрабатывается прерыванием?
:)
Реклама
otest
Друг Кота
Сообщения: 7853
Зарегистрирован: Ср фев 11, 2009 20:35:58

Re: Программа управления БП 16f876, глюк

Сообщение otest »

А где выход из прерывания ?
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15573
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Программа управления БП 16f876, глюк

Сообщение BOB51 »

Да вроде как он (retfie) там где-то в процедуре END_ENC закопан.
В остальном, на первом этапе множественные условные ветвления (угорза повторного вызова до завершения обработки), да еще супервизор замечен (возможно внешний). а в месиве из нескольких прерываний с разными источниками на ПИКах разбираться весьма невесело. :)
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25263
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Программа управления БП 16f876, глюк

Сообщение КРАМ »

Программа принципиально порочна.
Обработку энкодера и кнопки нужно проводить в одном обработчике по нулевому таймеру.
Получается очень короткий и быстрый код.
Только кнопку, в отличии от энкодера, нужно обрабатывать не в каждом прерывании, а примерно в 5...10 раз реже.
По поводу прерываний у младших ПИКов.
Если семафор построен корректно, то никакой разницы с архитектурами с отдельными векторами на источник нет...
Реклама
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15573
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Программа управления БП 16f876, глюк

Сообщение BOB51 »

Только не у начинающего... 8)
Реклама
Аватара пользователя
4uvak
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт авг 16, 2012 10:41:42

Re: Программа управления БП 16f876, глюк

Сообщение 4uvak »

Программу переписал, прерывание сократил до минимума. Мало того, - в качестве эксперимента полностью отключил прерывания. Глюк все равно остался. Программа дает сбои при нажатии и одновременном вращении. Очень странно. Такой режим работы в устройстве не предусмотрен, и программа стабильно работает, но все равно природа этого глюка не дает покоя.
Спойлер

Код: Выделить всё

           LIST      p=16F876A
            #include  <P16F876A.inc> 
            __CONFIG  (_LVP_OFF & _CP_OFF & _CPD_OFF & _PWRTE_OFF & _WDT_OFF & _HS_OSC & _BODEN_ON & _DEBUG_OFF )

cblock      0x20 
TEMPS                                ; используем для для хранения меток установки U или I
W_TEMP                               ; временный регистр - дубликат W
ST_TEMP                              ; временный регистр - дубликат STATUS
LCD_tmp                              ; временный регистр для вывода данных на LCD
Reg_tmp1                             ; временные регистры для ПП задержек
Reg_tmp2                             ; -//-
Reg_tmp3                             ; -//-
Reg_tmp_I_L                          ; временные регистры для хранения уставок U и I
Reg_tmp_I_H                          ; -//-
Reg_tmp_U                            ; -//-
Reg_4                                ; тут храним шаблон для сравнения с нулевым результатом и подменой пустым знакоместом
Reg_tmpL                             ; сюда переносим данные перед трансформацией двоичного числа в десятичное
Reg_tmpH                             ; -//-
ctr                                  ; временные регистры в ПП конвертации двоичного числа в десятичное
bcd1                                 ; -//-
bcd2                                 ; -//-
bcd3                                 ; -//-
bin1                                 ; -//-
bin2                                 ; -//-
TenK                                 ; десятки тысяч
Thou                                 ; тысячи
Hund                                 ; сотни
Tens                                 ; десятки
Ones                                 ; единицы
endc      



#define METKA           TEMPS,0      ; используем для меток установки U или I
#define DAT_ENC         PORTB,RB4    ; назначаем порт для ввода данных с энкодера
#define CLK_ENC         PORTB,RB5    ; назначаем порт для ввода тактирующих импульсов с энкодера
#define ON_OFF_ENC      PORTB,RB6    ; назначаем порт для кнопки энкодера
#define LED_ON      bsf PORTC,RC7    ; назначаем вывод для управления подсветкой LCD
#define LED_OFF     bcf PORTC,RC7    ; назначаем вывод для управления подсветкой LCD
#define E_1         bsf PORTC,RC6    ; назначаем вывод для команд E на PORTC для LCD
#define E_0         bcf PORTC,RC6    ; назначаем вывод для команд E на PORTC для LCD
#define RS_1        bsf PORTC,RC5    ; назначаем вывод для команд RS на PORTC для LCD
#define RS_0        bcf PORTC,RC5    ; назначаем вывод для команд RS на PORTC для LCD
#define D7_1        bsf PORTB,RB0    ; назначаем порты для вывода данных на LCD
#define D7_0        bcf PORTB,RB0    ; -//-
#define D6_1        bsf PORTB,RB1    ; -//-
#define D6_0        bcf PORTB,RB1    ; -//-
#define D5_1        bsf PORTB,RB2    ; -//-
#define D5_0        bcf PORTB,RB2    ; -//-
#define D4_1        bsf PORTB,RB3    ; -//-
#define D4_0        bcf PORTB,RB3    ; -//-
#define ON_OFF_ENC_F    TEMPS,7      ; используем установок флага нажатия кнопки
#define INC_F           TEMPS,6      ; используем установок флага поворота энкодера



            org         2100h        ; На стадии "прошивки", записываем в EEPROM-ячейку,
            de          .100         ; с адресом 00h, число 100 (64)
            org         2101h        ; На стадии "прошивки", записываем в EEPROM-ячейку,
            de          .0           ; с адресом 01h, число 0 (0)
            org         2102h        ; На стадии "прошивки", записываем в EEPROM-ячейку,
            de          .30          ; с адресом 02h, число 30 (1E)
            org         2103h        ; На стадии "прошивки", записываем в EEPROM-ячейку,
            de          .0           ; с адресом 03h, число 0 (0)

                           ;;;;;;;;;;;;;;;;;;;
                           ; старт программы;
                           ;;;;;;;;;;;;;;;;;;;
            org         0
            goto        START 

                           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                           ; подпрограмма приема данных с энкодера;
                           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; если мы попали сюда -> было сгенерировано прерывание по изменению состояния на входах RB4, RB5, RB6, RB7
            ORG         4h           ; адрес вектора прерывания 
            movwf       W_TEMP       ; копируем W в регистр - дубликат
            movf        STATUS,W     ; копируем STATUS в W 
            movwf       ST_TEMP      ; копируем W в регистр - дубликат
            movf        PORTB, W     ; производим чтение порта B для исключения несоответствия
            bcf         INTCON, RBIF ; сбрасываем флаг RBIF
            btfss       ON_OFF_ENC   ; опрашиваем кнопку энкодера
            goto        button       ; отправляемся ставить метку о срабатывании кнопки
            bsf         INC_F        ; устанавливаем флаг о повороте энкодера
            goto        ENDS         ; выходим из прерывания
button      bsf         ON_OFF_ENC_F ; устанавливаем флаг о срабатывании кнопки
ENDS        movf        ST_TEMP,W    ; возвращаем прежние значения в STATUS и W
            movwf       STATUS       ; -//-
            swapf       W_TEMP,f     ; -//-
            swapf       W_TEMP,W     ; -//-
            retfie                   ; возврат из прерывания GIE устанавливается в 1  

TABL_dig    andlw       b'00001111'  ; маскируем старший полубайт W (обнуляем 4 старших байта)
            addwf       PCL,f        ; Содержимое счетчика команд PC увеличивается на величину содержимого аккумулятора W.
            retlw       0x30         ; 0
            retlw       0x31         ; 1 
            retlw       0x32         ; 2 
            retlw       0x33         ; 3 
            retlw       0x34         ; 4 
            retlw       0x35         ; 5  
            retlw       0x36         ; 6 
            retlw       0x37         ; 7 
            retlw       0x38         ; 8 
            retlw       0x39         ; 9
            retlw       0x41         ; A
            retlw       0x42         ; B
            retlw       0x43         ; C
            retlw       0x44         ; D
            retlw       0x45         ; E
            retlw       0x46         ; F

                           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                           ; подготовительные операции;
                           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
START       bcf         STATUS,RP0   ; переход в банк 0
            banksel     OPTION_REG   ; переходим в регистр OPTION_REG
            movlw       b'00001101'  ; включаем подтягивающие резисторы PORTB, включаем предделитель перед WDT 1:32
            movwf       OPTION_REG   ; -//-
            banksel     INTCON       ; переходим в регистр INTCON
            movlw       b'00001000'  ; глобальный запрет прерываний, разрешение прерываний по изменению сигнала на входах RB4 - RB7
            movwf       INTCON       ; -//-
            banksel     PIE1         ; переходим в регистр PIE1
            movlw       b'00000000'  ; глобальный запрет периферийных прерываний
            movwf       PIE1         ; -//-
            banksel     TRISA        ; переходим в регистр PORTA
            movlw       b'00101111'  ; настраиваем RA0, RA1, RA2, RA3, RA5 на вход, остальные на выход
            movwf       TRISA        ; -//-
            banksel     TRISB        ; переходим в регистр PORTB
            movlw       b'11110000'  ; настраиваем все порты на выход, RB4, RB5, RB6, RB7 на вход
            movwf       TRISB        ; -//-
            banksel     TRISC        ; переходим в регистр PORTC
            movlw       b'00000000'  ; настраиваем все порты на выход
            movwf       TRISC        ; -//-
            banksel     T1CON        ; переходим в регистр T1CON
            movlw       b'00000000'  ; отключаем модуль T1CON
            movwf       T1CON        ; -//-
            banksel     T2CON        ; переходим в регистр T2CON
            movlw       b'00000000'  ; отключаем модуль T2CON
            movwf       T2CON        ; -//-
            banksel     CCP1CON      ; переходим в регистр CCP1CON
            movlw       b'00000000'  ; отключаем модуль CCP1
            movwf       CCP1CON      ; -//-
            banksel     CCP2CON      ; переходим в регистр CCP2CON
            movlw       b'00000000'  ; отключаем модуль CCP2
            movwf       CCP2CON      ; -//-
            banksel     SSPSTAT      ; переходим в регистр SSPSTAT
            movlw       b'00000000'  ; отключаем модуль SSPSTAT
            movwf       SSPSTAT      ; -//-
            banksel     SSPCON       ; переходим в регистр SSPCON
            movlw       b'00000000'  ; отключаем модуль SSPCON
            movwf       SSPCON       ; -//-
            banksel     SSPCON2      ; переходим в регистр SSPCON2
            movlw       b'00000000'  ; отключаем модуль SSPCON2
            movwf       SSPCON2      ; -//-  
            banksel     TXSTA        ; переходим в регистр TXSTA
            movlw       b'00000000'  ; отключаем модуль TXSTA
            movwf       TXSTA        ; -//-  
            banksel     RCSTA        ; переходим в регистр RCSTA
            movlw       b'00000000'  ; отключаем модуль RCSTA
            movwf       RCSTA        ; -//- 
            banksel     ADCON0       ; переходим в регистр ADCON0
            movlw       b'00000000'  ; отключаем модуль АЦП
            movwf       ADCON0       ; -//- 
            banksel     ADCON1       ; переходим в регистр ADCON1
            movlw       b'00000000'  ; отключаем модуль АЦП
            movwf       ADCON1       ; -//- 
            bcf         STATUS,RP0   ; переход в банк 0



            call        READY_EEP    ; отправляемся читать данные из EEPROM


                           ;;;;;;;;;;;;;;;;;;;;;;;;;
                           ; инициализация дисплея;
                           ;;;;;;;;;;;;;;;;;;;;;;;;;
            call        del_100ms    ; начальная задержка 100 милисекунд 
            movlw       b'00110011'  ; инициализация дисплея пока вкл 8 разрядов 
            call        LCD_com      ; грузим 0011 3 раза и один раз 0010  
            movlw       b'00110010'  ; -//-
            call        LCD_com      ; -//-   
            movlw       b'00100000'  ; инициализация дисплея уже по 4х2 разрядам 
            call        LCD_com      ; -//-   
            movlw       b'00101000'  ; вкл 4 разрядный ввод данных, размер символа 5х8 символов
            call        LCD_com      ; -//- 
            movlw       b'00000110'  ; сдвиг курсора вправо
            call        LCD_com      ; -//-  
            movlw       b'00001100'  ; отключаем курсор
            call        LCD_com      ; -//-   
            movlw       b'00010100'  ; двигаем курсор вправо
            call        LCD_com      ; -//-  
            movlw       b'00000001'  ; очищаем дисплей
            call        LCD_com      ; -//-

; выставляем метку уставок I или U
            btfss       METKA
            call        METKA_L
            btfsc       METKA
            call        METKA_H

; выставляем значение уставки U и I
            call        OUTPUT_U
            call        OUTPUT_I



gooo        LED_ON
            clrwdt
            bsf         INTCON, GIE  ; разрешаем прерывания
            movlw       0x80         ; курсор в пределах первой строки ( 0x80 - начало )
            call        LCD_com      ; загружаем команду 
            movlw       0x55         ; U
            call        LCD_dig      ; загружаем данные
            movlw       0x3D         ; =
            call        LCD_dig      ; загружаем данные
            movlw       0x32         ; 2
            call        LCD_dig      ; загружаем данные
            movlw       0x33         ; 3
            call        LCD_dig      ; загружаем данные
            movlw       0x2E         ; .
            call        LCD_dig      ; -//- 
            movlw       0x30         ; 0
            call        LCD_dig      ; загружаем данные
            movlw       0x56         ; =
            call        LCD_dig      ; загружаем данные

            goto        gooo


                           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                           ; Подпрограмма конвертации двоичного числа в десятичное;
                           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TRANSFORMER_dig
            movf        Reg_tmpL,W   ; копируем младший байт результата преобразования АЦП в   
            movwf       bin2         ; в bin2               
            movf        Reg_tmpH,W   ; копируем старший байт результата преобразования АЦП в    
            movwf       bin1         ; в bin1
;bin2 = младший байт преобразуемого числа
;bin1 = старший байт преобразуемого числа
;bcd3 ( младший полубайт ) = единицы
;bcd3 ( старший полубайт ) = десятки
;bcd2 ( младший полубайт ) = сотни
;bcd2 ( старший полубайт ) = тысячи
;bcd1 ( младший полубайт ) = десятки тысяч                                          
            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       ; распределение результата по регистрам        
            movwf       TenK         ; десятки тысяч 
            swapf       bcd2,w
            movwf       Thou         ; тысячи 
            movf        bcd2,w
            movwf       Hund         ; сотни 
            swapf       bcd3,w
            movwf       Tens         ; десятки 
            movf        bcd3,w
            movwf       Ones         ; единицы
            return 

                           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                           ; Подпрограмма вывода данных на HD44780;
                           ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; загрузка комманды
LCD_com     movwf       LCD_tmp           
            E_0
            RS_0
            call        LCD_load
            return     

; загрузка цифры 
LCD_dig     movwf       LCD_tmp           
            E_0
            RS_1
            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 

; ставим верхнюю метку
METKA_L     movlw       0x89         ; курсор в пределах первой строки ( 0x80 - начало )
            call        LCD_com      ; загружаем команду 
            movlw       0x3E         ; > ставим верхнюю метку
            call        LCD_dig      ; загружаем данные
            movlw       0xC9         ; курсор в пределах второй строки ( 0xC0 - начало )
            call        LCD_com      ; загружаем команду
            movlw       0x20         ; стираем нижнюю метку
            call        LCD_dig      ; загружаем данные
            return

; ставим нижнюю метку
METKA_H     movlw       0x89         ; курсор в пределах первой строки ( 0x80 - начало )
            call        LCD_com      ; загружаем команду 
            movlw       0x20         ; стираем верхнюю метку
            call        LCD_dig      ; загружаем данные
            movlw       0xC9         ; курсор в пределах второй строки ( 0xC0 - начало )
            call        LCD_com      ; загружаем команду
            movlw       0x3E         ; > ставим нижнюю метку
            call        LCD_dig      ; загружаем данные
            return

; выводим данные устаки U
OUTPUT_U    movf        Reg_tmp_U,W  ; копируем в W содержимое Reg_tmp_U
            movwf       Reg_tmpL
            clrf        Reg_tmpH
            movlw       0x8B         ; курсор в пределах первой строки ( 0x80 - начало )
            call        LCD_com      ; загружаем команду
            call        TRANSFORMER_dig
            movlw       0x30         ; подменяем пустым знакоместом , если первый 0 
            movwf       Reg_4        ; -//-
            movf        Hund,W       ; -//-
            call        TABL_dig     ; -//-
            xorwf       Reg_4,F      ; -//-
            skpnz                    ; -//-
            movlw       0x20         ; -//-
            call        LCD_dig      ; -//-
            movf        Tens,W       ; копируем в W содержимое Tens
            call        TABL_dig     ; отправляем на дисплей содержимое Tens
            call        LCD_dig      ; -//- 
            movlw       0x2E         ; .
            call        LCD_dig      ; -//-
            movf        Ones,W       ; копируем в W содержимое Ones
            call        TABL_dig     ; отправляем на дисплей содержимое Ones
            call        LCD_dig      ; -//- 
            movlw       0x55         ; U
            call        LCD_dig      ; загружаем данные
            return

; выводим данные уставки I
OUTPUT_I    movf        Reg_tmp_I_L,W; копируем в W содержимое Reg_tmp_I_L
            movwf       Reg_tmpL
            movf        Reg_tmp_I_H,W; копируем в W содержимое Reg_tmp_I_H
            movwf       Reg_tmpH
            movlw       0xCB         ; курсор в пределах второй строки ( 0xС0 - начало )
            call        LCD_com      ; загружаем команду
            call        TRANSFORMER_dig
            movf        Hund,W       ; копируем в W содержимое Hund
            call        TABL_dig     ; отправляем на дисплей содержимое Hund
            call        LCD_dig      ; -//- 
            movlw       0x2E         ; .
            call        LCD_dig      ; -//- 
            movf        Tens,W       ; копируем в W содержимое Tens
            call        TABL_dig     ; отправляем на дисплей содержимое Tens
            call        LCD_dig      ; -//- 
            movf        Ones,W       ; копируем в W содержимое Ones
            call        TABL_dig     ; отправляем на дисплей содержимое Ones
            call        LCD_dig      ; -//- 
            movlw       0x41         ; A
            call        LCD_dig      ; загружаем данные
            return

; считываем данные уставок из EEPROM
READY_EEP   
            banksel     EEADR        ; переходим в регистр EEADR
            movlw       0            ; считывается содержимое
            movwf       EEADR        ; EEPROM-ячейки с адресом 00h
            banksel     EECON1       ; переходим в регистр EECON1
            bcf         EECON1,EEPGD ; работа с EEPROM
            bsf         EECON1,RD    ; разрешение чтения
            banksel     EEDATA       ; переходим в регистр EEDATA
            movf        EEDATA,W     ; считанный байт записывается в W
            bcf         STATUS,RP0   ; переход в банк 0
            bcf         STATUS,RP1   ; -//-
            movwf       Reg_tmp_I_L  ; W -> Reg_tmp_I_L 

            banksel     EEADR        ; переходим в регистр EEADR
            movlw       1            ; считывается содержимое
            movwf       EEADR        ; EEPROM-ячейки с адресом 01h
            banksel     EECON1       ; переходим в регистр EECON1
            bcf         EECON1,EEPGD ; работа с EEPROM
            bsf         EECON1,RD    ; разрешение чтения
            banksel     EEDATA       ; переходим в регистр EEDATA
            movf        EEDATA,W     ; считанный байт записывается в W
            bcf         STATUS,RP0   ; переход в банк 0
            bcf         STATUS,RP1   ; -//-
            andlw       b'00000001'  ; обнуляем 7 старших бита (для исключения ошибок записи в EEPROM)
            movwf       Reg_tmp_I_H  ; W -> Reg_tmp_I_H

            banksel     EEADR        ; переходим в регистр EEADR
            movlw       2            ; считывается содержимое
            movwf       EEADR        ; EEPROM-ячейки с адресом 02h
            banksel     EECON1       ; переходим в регистр EECON1
            bcf         EECON1,EEPGD ; работа с EEPROM
            bsf         EECON1,RD    ; разрешение чтения
            banksel     EEDATA       ; переходим в регистр EEDATA
            movf        EEDATA,W     ; считанный байт записывается в W
            bcf         STATUS,RP0   ; переход в банк 0
            bcf         STATUS,RP1   ; -//-
            movwf       Reg_tmp_U    ; W -> Reg_tmp_U_L

            banksel     EEADR        ; переходим в регистр EEADR
            movlw       3            ; считывается содержимое
            movwf       EEADR        ; EEPROM-ячейки с адресом 04h
            banksel     EECON1       ; переходим в регистр EECON1
            bcf         EECON1,EEPGD ; работа с EEPROM
            bsf         EECON1,RD    ; разрешение чтения
            banksel     EEDATA       ; переходим в регистр EEDATA
            movf        EEDATA,W     ; считанный байт записывается в W
            bcf         STATUS,RP0   ; переход в банк 0
            bcf         STATUS,RP1   ; -//-
            movwf       TEMPS        ; W -> TEMPS
            return

; ЗАДЕРЖКА 1 ms
del_1ms     movlw       .46
            movwf       Reg_tmp1
            movlw       .6
            movwf       Reg_tmp2
wr2         decfsz      Reg_tmp1, F
            goto        wr2
            decfsz      Reg_tmp2, F
            goto        wr2
            return     


; ЗАДЕРЖКА 5 ms 
del_5ms     call        del_1ms
            call        del_1ms
            call        del_1ms
            call        del_1ms
            call        del_1ms
            return

; ЗАДЕРЖКА 50 ms
del_50ms    movlw       .186
            movwf       Reg_tmp1
            movlw       .4
            movwf       Reg_tmp2
            movlw       .2
            movwf       Reg_tmp3
wr3         decfsz      Reg_tmp1, F
            goto        wr3
            decfsz      Reg_tmp2, F
            goto        wr3
            decfsz      Reg_tmp3, F
            goto        wr3
            clrwdt
            return

; ЗАДЕРЖКА 100 ms 
del_100ms   call        del_50ms
            call        del_50ms
            return

            end
Последний раз редактировалось 4uvak Сб май 31, 2014 16:54:20, всего редактировалось 1 раз.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25263
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Программа управления БП 16f876, глюк

Сообщение КРАМ »

Уважаемый, не нужно приводить всю портянку кода в открытом состоянии.
Убирайте ее в спойлер...
Аватара пользователя
4uvak
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт авг 16, 2012 10:41:42

Re: Программа управления БП 16f876, глюк

Сообщение 4uvak »

КРАМ А не могли бы Вы дать ссылку на грамотную обработку энкодера таймером? А то это сочинял сам))
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25263
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Программа управления БП 16f876, глюк

Сообщение КРАМ »

Ссылку - нет, а свой код можно.
Правда не уверен, что он есть на моем ноуте... Сейчас поищу...
ЗЫ. Да и уточните к каким пинам присоединен энкодер, а к какой кнопка.


Нашел, но не совсем то что хотел.
Принцип думаю поймете.
Контроллер PIC18, поэтому сохранение-восстановление контекста отсутствует и при выходе retfie FAST
Кнопка висит на RB2
Энкодер на RB0, RB1
Обработка кнопки здесь с той же частотой, что и энкодер, но буфер кнопки st_button сделан на три бита.
То есть если три раза подряд кнопка будет прочитана нулем (нажата), то в основном цикле определится как нажатая, а если три раза как единица, то как ненажатая.
Обработчик энкодера использует расположение разрядов порта для получения на выходе в переменной inc_dec готовую величину для управления. Если энкодер неподвижен, то она равна нулю, если крутится по часовой стрелке, то +1 (0x01), а если против часовой, то -1 (0xFF).
Переменная temp_enc - это текущее ФИЗИЧЕСКОЕ его состояние
Переменная stack_enc - это предыдущее его ФИЗИЧЕСКОЕ состояние
Переменная old_enc - это последнее ПРОГРАММНОЕ состояние энкодера (уже очищенное от дребезга). После вычисления переменной inc_dec происходит перезапись temp_enc в old_enc.

Код: Выделить всё

IsrTMR0		bcf		INTCON, TMR0IF
;
; тут может быть код для других устройств
; висящих на системном таймере TMR0
;
; антидребезг и обработка кнопки энкодера
		movlw		b'00000100'
		andwf		PORTB, w
		rrncf		WREG, f
		rrncf		WREG, f
		rrcf		WREG, f
		rlcf		st_button, f
		movlw		b'00000111'
		andwf		st_button, f
;---
; антидребезг и обработка энкодера
		movf		PORTB, w
		andlw	b'00000011'
		movwf	temp_enc
		xorwf	stack_enc, w
		movff	temp_enc, stack_enc
		btfss		STATUS, Z
		retfie	FAST		; выход если уровень пинов изменился(дребезг)
		movf		temp_enc, w
		xorwf	old_enc, w
		btfsc		STATUS, Z
		retfie	FAST		; выход с 0 если старое состояние = новому
		movf		old_enc, f
		movff	temp_enc, old_enc
		btfss		STATUS, Z
		retfie	FAST		; выход с 0 если старое состояние не ноль
		bcf		STATUS, C
		rlcf			old_enc, w	; *2
		addlw		0xFD		; -3
		movwf		inc_dec
		retfie		FAST


; фрагмент инициализации по TMR0
		movlw		b'11000001'		; prescaler :4 (16MHz->500nS->TMR0)
		movwf		T0CON



Последний раз редактировалось КРАМ Сб май 31, 2014 17:36:22, всего редактировалось 1 раз.
Аватара пользователя
4uvak
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт авг 16, 2012 10:41:42

Re: Программа управления БП 16f876, глюк

Сообщение 4uvak »

Спасибо! Попробую разобраться
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25263
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Программа управления БП 16f876, глюк

Сообщение КРАМ »

Объяснения по переменным дописал.
Некоторые особенности команд PIC18 поймете.
Гланое тут понять, что в прерывании с тактом переполнения TMR0 происходит заполнение буфера кнопки и полная обработка энкодера.
Чтение БУФЕРА кнопки с его анализом происходит уже в ГЛАВНОМ ЦИКЛЕ.
Нужно не забывать после применения переменной inc_dec в основном цикле ее сбрасывать...
Кстати, такой способ формирования данных от энкодера позволяет элементарно его буферизовать, если исполнительный механизм работающий с энкодером медленный. Достаточно создать буферную переменную энкодера к которой и прибавлять переменную inc_dec, а по мере исполнения эту переменную декрементировать/инкрементировать...
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15573
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Программа управления БП 16f876, глюк

Сообщение BOB51 »

16F876 и серия 18F по обработек прерываний не одно и то же! :)
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25263
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Программа управления БП 16f876, глюк

Сообщение КРАМ »

Если не считать сохранения контекста, о чем я написал, то никакой разницы нет.
Тем более, что вход в обработчик я не привел, а выход может следовать не на retfie FAST, а на произвольную метку через goto, а уже там восстановить контекст и выйти стандартно.
Увы, на личном ноуте варианта для 12-16-х ПИКов у меня нет..., а на работе я буду только послезавтра.
Да и самостоятельно переработать под свой вариант ТС будет полезно.
Лишь бы понял идею...
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15573
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Программа управления БП 16f876, глюк

Сообщение BOB51 »

Я то как раз за эти два вида (простое и быстрое) речь и веду... там дополнительные заморочки и по правилам входа и по обработке векторов + "быстрый стек" коего в среднемладших нету (а работает он в аппаратных прерываниях в обязательном порядке "по умолчанию").
Штука полезная и интересная, но для начала слишком мозги выносит... :cry:
А типовой обработчик прерываний для среднемладших обычно в заголовочном файле IDE (mplab) обязательно присутствует,
к примеру вот такой (мплаб 8.92, для "абсолютной" адресации):
16F876ATEMP.ASM
(3.97 КБ) 352 скачивания
:)
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25263
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Программа управления БП 16f876, глюк

Сообщение КРАМ »

BOB51 писал(а):а работает он в аппаратных прерываниях в обязательном порядке "по умолчанию"
Я не вполне понял что там может выносить мозги? Цитата , мягко говоря, не точна... :cry:
Если бы автоматического сохранения контекста не было, то тогда это может принести некоторые неудобства, а если оно есть, то можно им пользоваться, а можно не обращать на него внимания, соответственно не используя параметр FAST у команды возврата из обработчика retfie и сохраняя контекст самостоятельно.
Я об этом и написАл.
То есть просто не нужно изменять правила для 12...16-х, а параметра FAST в них и так нет.
Значит и ошибиться ТС в этом вопросе попросту не в состоянии...
ЗЫ. Кстати, при разного рода извратах типа вложенных прерываний сохранение контекста ПО ЛЮБОМУ возможно только в ручном режиме...
ЗЗЫ. И если учесть, что ТС в первом варианте кода постоянно вызывал в обработчике разные подпрограммы, то еще нужно проверить реентерабельность этих подпрограмм... :dont_know:
Ответить

Вернуться в «PIC»