Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Непонятное поведение PIC16F690
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры > PIC
Grigorij
Здравствуйте.

Столкнулся с непонятным поведение PIC16F690. Имеется следующий код (только часть с непонятным поведением):

Файл Main.asm:
Код
....
EXTERN    UARTHnd
EXTERN    InitADC,ResetADC    
GLOBAL    MainLoop,InitMCU


Reset:    CODE
                    GOTO    InitMCU

Int:    CODE
                    GOTO    UARTHnd
            
Main:     CODE

InitMCU:
    
    INTERRUPT_OFF            
    CALL        InitSFR
    CALL        InitADC
    
   ;отправляем что-нибудь по uart-у для проверки работоспособности
   ;----------------------------------------------
    BANKSEL    TXREG
    MOVLW        0xAA
    MOVWF        TXREG
        
    WT1:
    BTFSS    PIR1,TXIF
    GOTO    WT1
   ;----------------------------------------------

    MOVLW        cINTCON
    MOVWF        INTCON
        
    MainLoop:
        CALL        StartTimeOut
        CALL        UpDateADC
            WaitTimeOut:
                BANKSEL    PIR1
                BTFSS    PIR1,TMR1IF
            GOTO    WaitTimeOut    
        GOTO    MainLoop

StartTimeOut:
.....
RETURN

InitSFR:    
....
RETURN    
    END

Файл CMD.asm
Код
...
EXTERN    MainLoop
GLOBAL    UARTHnd
    
;нужный буду топом
GenRegs:    UDATA_OVR
    R6:    RES    1
    R5:    RES    1
    R4:    RES    1
    R3:    RES    1
    R2:    RES    1
    R1:    RES    1
    R0:    RES    1

;нужный буду топом
UARTData:    UDATA
    Temp:        RES    d'1'
    Counter:    RES    d'1'
    NBytes:        RES    d'1'
    CmdBuf        RES    MAX_CMD_LENGTH
    ChekSum:    RES    d'2'

Interface:    CODE

;Обработчик прерываний от UART, возникающего при получении очередного байта
UARTHnd:
    BANKSEL    RCREG
    MOVF        RCREG,W
    MOVWF        TXREG
        
    WT:
        BTFSS    PIR1,TXIF
        GOTO    WT
    RETFIE
        
END


Файл Comp.asm
Код
...
    GLOBAL    InitADC,ResetADC,SetGain,UpDateADC,WrByteADC,WrCommReg
....
Comp:    CODE

; Description:     Отправка байта на АЦП
WrByteADC:                
    BANKSEL    ADC_CS_PORT
    BCF        ADC_CS        
    SEL_BANK0
    MOVWF        R3;отправляемые данные
    MOVLW        d'8'
    MOVWF        R2;кол-во отправляемых бит

    WBAL0:        ;цикл отправки бит

        BANKSEL    ADC_SCLK_PORT
        BCF        ADC_SCLK
        
        SEL_BANK0
        RLF        R3,F

       ;ДОЛЖНО БЫТЬ (В этом случае начинаются глюки)
       ;------------------------------------------------------------
       ;BANKSEL    ADC_DIN_PORT
       ;BCF        ADC_DIN
       ;BTFSC    STATUS,C            
       ;BSF        ADC_DIN
       ;------------------------------------------------------------

       ;ТАК РАБОТАЕТ (Хотя это форменный изврат)
       ;------------------------------------------------------------
        BANKSEL    ADC_DIN_PORT
        BCF        ADC_DIN
        BTFSC    STATUS,C            

        GOTO    tmp    
        tmp:                
                BSF    ADC_DIN
       ;------------------------------------------------------------

        BANKSEL    ADC_SCLK_PORT            
        BSF        ADC_SCLK

        SEL_BANK0
        DECFSZ    R2,F
        GOTO    WBAL0    
    
    BANKSEL    ADC_CS_PORT
    BSF        ADC_CS
RETURN

;Инициализация АЦП
InitADC:
    INTERRUPT_OFF
    CALL        ResetADC
    WR_CLOCK_REG
    MOVLW        b'00010010'
    CALL        WrByteADC
    CALL        SetGain
RETURN
....


Глюк заключается в следующим, если восстановить подпрограмму WrByteADC согласно приведенным, в ней комментариям, то в главной программе (Main) при попытке отправить байт по UART-у вместо 0xAA приходит, например, 0xFE (или еще что-нибудь, но не то что хотим). В обработчике прерывания от UART-а также вместо отправки принятого байта отправляется полная чушь.

Подскажить в каком направлении искать правду.
xemul
Может стОит попробовать сохранять используемые в прерывании регистры (сейчас это W, STATUS и PCLATH, если UARTHnd живет далеко от Int) при входе в прерывание и восстанавливать их при выходе?
=GM=
Цитата(Grigorij @ Jul 7 2008, 10:12) *
Столкнулся с непонятным поведение PIC16F690. Имеется следующий код (только часть с непонятным поведением)
Код
UARTHnd:    BANKSEL    RCREG
    MOVF    RCREG,W
    MOVWF    TXREG
WT:    BTFSS    PIR1,TXIF
    GOTO    WT
    RETFIE

1) При работе с UARТ по прерываниям не надо опрашивать флаг TXIF, иначе может быть непредсказуемое поведение.

2) Если в прерывании играетесь со статус-регистром и W, надо их сохранять и восстанавливать в конце прерывания, иначе будет непредсказуемое поведение.

Цитата(Grigorij @ Jul 7 2008, 10:12) *
Глюк заключается в следующим, если восстановить подпрограмму WrByteADC согласно приведенным, в ней комментариям, то в главной программе (Main) при попытке отправить байт по UART-у вместо 0xAA приходит, например, 0xFE (или еще что-нибудь, но не то что хотим). В обработчике прерывания от UART-а также вместо отправки принятого байта отправляется полная чушь. Подскажите в каком направлении искать правду.


3) Добейтесь устойчивой передачи по уарту в режиме опроса, а уж потом переходите к прерываниям. А вообще, если надо передавать одиночные байты, то лучше делать передачу по опросу: опросил флаг, не готово - подождал, готово - толкнул байт в регистр данных и ушёл делать другие дела.

4) Странно, что вам надо байты на ацп передавать, а данные с ацп как бы и не нужны.

5) Зачем так много играться с выбором банков памяти?
Grigorij
Цитата(=GM= @ Jul 7 2008, 18:10) *
1) При работе с UARТ по прерываниям не надо опрашивать флаг TXIF, иначе может быть непредсказуемое поведение.

Исправление не помогло.
Цитата(=GM= @ Jul 7 2008, 18:10) *
2) Если в прерывании играетесь со статус-регистром и W, надо их сохранять и восстанавливать в конце прерывания, иначе будет непредсказуемое поведение.

3) Добейтесь устойчивой передачи по уарту в режиме опроса, а уж потом переходите к прерываниям. А вообще, если надо передавать одиночные байты, то лучше делать передачу по опросу: опросил флаг, не готово - подождал, готово - толкнул байт в регистр данных и ушёл делать другие дела.

В том то все и дело, что если я убираю подпрограмму записи байтов в АЦП (WrByteADC), то UART начинает работает как часы. При этом WrByteADC, в приведенном примере, вызывается только один раз в начале программы. Т.к. все остальное время программа ждет прерывания от UART и выдает принятые данные, то STATUS и WREG я не стал сохранять.
Цитата(=GM= @ Jul 7 2008, 18:10) *
4) Странно, что вам надо байты на ацп передавать, а данные с ацп как бы и не нужны.

Это еще впереди smile.gif.
Цитата(=GM= @ Jul 7 2008, 18:10) *
5) Зачем так много играться с выбором банков памяти?

Здесь я просто промолчу smile.gif

2xemul:

А что подразумевается под "если UARTHnd живет далеко от Int"? Может имеется в виду, что UARTHnd будет находится на другой странице? Если так, то вся программа находит на одной странице и, насколько я знаю, при вызове GOTO и CALL никаких манипуляций с PCLATH делать не надо (таблицы я не рассматриваю).
=GM=
Цитата(Grigorij @ Jul 8 2008, 03:30) *
Исправление не помогло. В том то все и дело, что если я убираю подпрограмму записи байтов в АЦП (WrByteADC), то UART начинает работает как часы. При этом WrByteADC, в приведенном примере, вызывается только один раз в начале программы. Т.к. все остальное время программа ждет прерывания от UART и выдает принятые данные, то STATUS и WREG я не стал сохранять

1) Исправление не помогло и не поможет, поскольку вы не используете прерывание. По крайней мере, в том тексте программы, что я видел.

2) Всё остальное время ваша программа не ждет прерывания от UART, а находится в цикле mainloop, вызывая поочередно StartTimeOut и UpDateADC, текст которой вы, кстати, не показали.

3) Биты выбора банка находятся в STATUSе, если вы его меняете в прерывании, то надо сохранять на входе и восстанавливать на выходе, это закон, не понимаю, чего здесь упираться. Также и с WREG.

4) Давайте посмотрим на все ваши назначения для ADC_CS_PORT, ADC_CS и т.д.

5) Изменения в WrByteADC означают всего-навсего задержку в два МЦ. Вы уверены в правильности формирования временной диаграммы? Какой ацп вы используете? Почему бы вместо программного обмена не использовать SSP модуль?
xemul
Цитата(Grigorij @ Jul 8 2008, 08:30) *
...
А что подразумевается под "если UARTHnd живет далеко от Int"? Может имеется в виду, что UARTHnd будет находится на другой странице?

И это тоже. Попадая в прерывание с PCLATH & 0x18 != high(UARTHnd) & 0x18, на какую страницу Вы отправитесь по goto UARTHnd?
Цитата
Если так, то вся программа находит на одной странице и, насколько я знаю, при вызове GOTO и CALL никаких манипуляций с PCLATH делать не надо (таблицы я не рассматриваю).

Нравится заботливо и загодя раскладывать для себя, любимого, грабельки? Вперед...
W и STATUS Вам необходимо сохранять по любому, т.к. Вы их модифицируете в прерывании.
kisslove
Цитата
Глюк заключается в следующим, если восстановить подпрограмму WrByteADC согласно приведенным, в ней комментариям, то в главной программе (Main) при попытке отправить байт по UART-у вместо 0xAA приходит, например, 0xFE (или еще что-нибудь, но не то что хотим). В обработчике прерывания от UART-а также вместо отправки принятого байта отправляется полная чушь.

Подскажить в каком направлении искать правду.


Проверь банки, скорей всего передаешь по юарту значение из соседнего банка.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.