Re: Вопросы начинающих PIC ASM
Добавлено: Пн авг 22, 2016 14:12:24
Доброго времени суток. Снова я со свои программным UART-ом. Никак не получается написать прием на прерываниях. Ниже код, в нем есть закоментированый кусок передачи лат. символа "А", он работает нормально. Тоесть передача работает нормально (она пока не на прерываниях, всему свое время). Проблема возникает, когда пытаюсь передавать символ, который принял (в прерывании) - передает не то, что отправлял в терминале. Просьба подсказать, где ошибка.
Спойлер
Код: Выделить всё
list p=16f629
__config _CPD_OFF & _CP_OFF & _BODEN_OFF & _MCLRE_ON & _PWRTE_ON & _WDTE_OFF & _FOSC_INTRCIO
include p12f629.inc
#define RX_ 2
#define TX_ 1
#define RX GPIO,RX_ ; В качестве приемника может быть только эта ножка
#define TX GPIO,TX_ ; А вот в качестве передатчика можем назначить любую, даже ту же
#define BITS_DELAY .30 ; Задержка длинной 1 бит - 104 мкс при 9600 бод и частоте 4 МГц
#define RX_Complete 0 ; Флаг завершения приема
; В прерывании только прием байта (побитно), и выставление флага окончания приема, который уже анализируется в основном цикле
;======================
Soft_UART udata_shr
w_temp res 1
status_temp res 1
TX_byte res 1
RX_byte res 1
UART_counter res 1
delay_counter res 1
Flags res 1
;======================
push macro
; movwf w_temp
; swapf STATUS,w
; movwf status_temp
movwf w_temp ; save off current W register contents
movfw STATUS ; move status register into W register
movwf status_temp ; save off contents of STATUS register
endm
pop macro
; swapf status_temp,w
; movwf STATUS
; swapf w_temp,f
; swapf w_temp,w
movfw status_temp ; retrieve copy of STATUS register
movwf STATUS ; restore pre-isr STATUS register contents
swapf w_temp,f
swapf w_temp,w ; restore pre-isr W register contents
endm
;======================
RESET_VECTOR code 0h
goto Ini
;======================
ISR code 4h ; Вектор прерывания
Interrupt_Heandler
push ; Сохраним контекст
btfsc INTCON,INTF
goto Start_bit ; Если есть флаг внешнего прерывания - пришел старт-бит
btfsc INTCON,T0IF
goto Receive_bit ; Если флаг таймера, значит принимаем очередной бит посылки
End_Interrupt_Heandler
pop ; Восстановим контекст
retfie
;======================
Start_bit
bcf INTCON,INTF ; Сбросим флаг внешнего прерывания
movlw .191 ; Перезапишем таймер для периода переполнения в 156 мкс (середина 1 бита данных)
movwf TMR0
movlw .8 ; Загрузим количество принимаемых битов
movwf UART_counter
clrf RX_byte ; Очистим приемник
bcf INTCON,INTE ; Запрещаем внешнее прерывание (4 бит)
bsf INTCON,T0IE ; Разрешаем прерывание по переполнению Таймера 0 (5 бит)
bcf INTCON,T0IF ; Сбросим флаг переполнения Таймера 0, он почти наверняка переполнился, пока мы ждали старт-бит
goto End_Interrupt_Heandler
;======================
Receive_bit
movlw .211 ; Перезапишем таймер для периода переполнения в 104 мкс
movwf TMR0
bcf INTCON,T0IF ; Сбросим флаг переполнения Таймера 0
bcf STATUS,C ; Сбросим бит переноса
rrf RX_byte ; Задвигаем сброшеный бит переноса в приемный регистр
btfsc RX ; А теперь проверяем, что на самом деле надо было туда задвинуть
bsf RX_byte,7 ; Если 1, надо срочно подкорректировать, ведь мы задвинули 0
decfsz UART_counter ; Весь байт принят ?
goto End_Interrupt_Heandler ; Нет, идем принимать следующий бит
bsf Flags,RX_Complete ; Поставим флажок окончания приема байта
bcf INTCON,T0IE ; Запрещаем прерывание по переполнению Таймера 0 (5 бит)
bsf INTCON,INTE ; Разрешаем внешнее прерывание (4 бит) для приема следующего старт-бита
goto End_Interrupt_Heandler ; На выход
;======================
Ini
clrf Flags ; Сбросим все флаги
movlw b'111111' ; Заранее установим необходимые уровни на выходах, чтобы в момент переключения с входов на выходы му уже имели на них нужные значения
movwf GPIO ; Init GPIO
banksel OSCCAL ; Bank 1
call 3FFh
movwf OSCCAL
if RX_ != TX_
bcf TX ; Настроим TX на выход
endif
movlw b'11000000' ; Подтягивающие резисторы включены, внешнее прерывание по переднему фронту, тактирование Таймера 0 от внутреннего генератора, пределитель 1 к 2, что дает 512 мкс на частоте 4 Мгц
movwf OPTION_REG
banksel GPIO ; Bank 0
movlw b'00000111'
movwf CMCON ; Выключим аналоговый компаратор
movlw b'10010000' ; Разрешаем прерывания вообще (7 бит) и внешнее прерывание (4 бит)
movwf INTCON
;======================
; movlw 'A'
; call Send_TX_byte
Main
; goto Main
btfss Flags,RX_Complete ; Анализируем флажок приема байта
goto Main ; Нет флажка - нет принятого байта
movfw RX_byte ; Засунем принятый байт в рабочий регистр
call Send_TX_byte ; И отправим назад
bcf Flags,RX_Complete ; Скинем флажок принятого байта
goto Main
;======================
Send_TX_byte ; Подпрограмма передачи 1 байта
bcf INTCON,GIE ; Запрещаем прерывания
if RX_ == TX_
banksel TRISIO ; Bank 1
bcf TX ; Настроим TX на выход
banksel GPIO ; Bank 0
endif
;-----------------------------------------------------------------------------------------------
bcf TX ; Шлем старт бит
movwf TX_byte ; Загрузим передавемый байт
movlw .8 ; Загрузим количесвто передаваемых битов
movwf UART_counter
nop
Transmit_Next_Bit
nop
call Delay_1bit ; Длинной 1 бит
rrf TX_byte ; Продвигаем в бит переноса все биты, начиная с младшего
btfsc STATUS,C ; Проверяем, что выдавилось в бит переноса
bsf TX ; Если 1, выставляем 1 на ТХ
btfss STATUS,C
bcf TX ; Если 0, выставляем 0 на ТХ
decfsz UART_counter ; Весь байт отослан ?
goto Transmit_Next_Bit ; Нет, идем слать следующий бит
call Delay_1bit ; Задержка длинной 1 бит
nop
nop
nop
nop
nop
bsf TX ; Шлем стоп-бит
call Delay_1bit ; Задержка длинной 1 бит
;-----------------------------------------------------------------------------------------------
if RX_ == TX_
banksel TRISIO ; Bank 1
bsf TX ; Настроим ножку на вход
banksel GPIO ; Bank 0
endif
bcf INTCON,T0IF ; Сбросим флаг переполнения Таймера 0
bcf INTCON,INTF ; Сбросим флаг внешнего прерывания
bsf INTCON,GIE ; Разрешаем прерывания
return
;======================
Delay_1bit
movlw BITS_DELAY ; 104 мкс для 9600 бод
movwf delay_counter
Loop_Delay
decfsz delay_counter
goto Loop_Delay
return
end