ИК-приемник с PIC16F887, ассемблер

Я работаю над школьным проектом. Это включает в себя программирование сборки PIC. Я использую демонстрационную плату с 44 контактами, PIC16F887.

Мне нужно сделать ИК-приемник, у которого есть выход, изменяющий яркость светодиода. Я пока знаю, что для этого мне нужно сделать ШИМ-регулятор. Однако я все еще борюсь с расшифровкой кнопок. Я использую эмиттер с кодировкой NEC. Моя настройка входа - цифровая, подтянутая внутренним резистором PORTB, 0. Я пытаюсь опросить вход прерываниями TMR0.

Настройка системы - генератор 4 МГц, TMR0 увеличивается каждые Osc / 4. Предделитель 1: 2, поэтому каждые 2 мкс таймер увеличивается на 1. Предварительная нагрузка Timer0 равна D’206 ’, поэтому она прерывается 50 * 2 мкс = 100 мкс. Согласно протоколу NEC, логика 0 имеет низкий уровень 562,5 мкс, логика 1 имеет низкий уровень сигнала 1687,5 мкс после сигнала 562,5 мкс HIGH.

Итак, 1687,5 мкс / 100 мкс = 16 и 562,5 мкс / 100 мкс = 5. Я пытался вычесть их из 8. Итак, я могу проверить, что означает СТАТУС, НУЛЕВОЙ бит активен или низкий.

Я не знаю, в какой части я ошибаюсь. Я оставлю свой код внизу. В этом коде мигает светодиод, при этом предполагается, что индикатор PORTD, 0 загорится при нажатии кнопки громкости +. Таким образом, я бы знал, могу ли я обнаруживать кнопки и работать с ШИМ.

Мы ценим каждый ответ.

ISR:                        ;IF ISR GLOBAL INT 0  
    btfss   INTCON,T0IF   
    retfie                  ;if there is no interrupt
    banksel 0               ;ISR occur in Bank0
    movwf   W_save          ;save WORK register's value
    movf    STATUS,W       
    movwf   STATUS_save     ;save STATUS register's value

    call    IR              ;call IR
    goto    ISR_EXIT

ISR_EXIT:
    bcf     INTCON,T0IF     ;TMR0 interrupt flag clear
    movlw   b'01100110'     ;preload 206
    movwf   TMR0

    movf    STATUS_save,W
    movwf   STATUS          ;STATUS register original value reload
    swapf   W_save,f        ;WORK register original value reload
    swapf   W_save,W
    retfie                  ;retfie -> global int = 1

IR:
    btfss   PORTB,0         ;testing IR input
    bsf     ir_reg,0        ;button was pressed

    btfss   ir_reg,0        ;button was pressed?
    goto    NO_BUTTON

    btfsc   PORTB,0         ;HIGH signal?
    goto    HIGH_P

    btfss   ir_reg,1        ;previous was HIGH?
    goto    HIGH_TO_LOW

    incf    time,f          ;increment time
    goto    ISR_EXIT

HIGH_P:
    btfsc   ir_reg,1        ;was previous LOW?
    goto    LOW_TO_HIGH

    incf    time,f          ;increment time

    goto    ISR_EXIT

HIGH_TO_LOW:                ;transition between HIGH to LOW pulses
    bsf     PORTD,3
    movf    time,W     
    movwf   high_pulse      ;saving HIGH pulse's time
    clrf    time            ;time variable clear
    bcf     ir_reg,1        ;previous pulse was HIGH
    goto    CALC

CALC:
    movf    high_pulse,W    ;high pulse's time into Work
    bcf     STATUS,Z        ;STATUS ZERO CLEAR

    sublw   D'10'           ;LOW_P -> 5-10 = -5,HIGH_P - > 16-10 = 6
    btfsc   STATUS,Z        ;if subtraction = +
    bsf     ir_reg,3        ;subtraction ended positive -> LOGIC 1
    bcf     ir_reg,3        ;subtraction ended negative -> LOGIC 0
    goto    ADD_BITS

ADD_BITS:
    bsf     PORTD,2
    btfsc   ir_reg,3        ;if LOGIC 1
    bsf     STATUS,C        ;carry bit 1
    bcf     STATUS,C        ;carry bit 0

    goto    ROTATE

ROTATE:
    bsf     PORTD,1
    rlf     naddress        ;Carry is rotated to naddress LSB
    rlf     address         ;naddress MSB rotated to address LSB through Carry
    rlf     ncommand        ;address MSB rotated to ncommand LSB through Carry
    rlf     command         ;ncommand MSB rotated to command LSB through Carry

    incf    pulses          ;every time we have a rotation increment variable
    movf    pulses,W
    bcf     STATUS,Z        ;status zero clear
    sublw   D'32'           ;33-pulses,we have a decoded signal
    btfss   STATUS,Z        ;if Zero set
    goto    ISR_EXIT        ;goto NO_button
    goto    LED_FLASH

LED_FLASH:
    movf    command,W
    bcf     STATUS,Z
    sublw   b'10101000'     ;+ button command: b'10101000'
    btfss   STATUS,Z
    goto    NO_BUTTON
    bsf     PORTD,0
    goto    ISR_EXIT

LOW_TO_HIGH:                ;transition between LOW to HIGH pulses
    movf    time,W
    movwf   low_pulse       ;saving LOW pulse's time
    clrf    time            ;time variable clear
    bsf     ir_reg,1        ;previous pulse was LOW
    goto    ISR_EXIT

NO_BUTTON:
    btfsc   PORTB,0
    goto    ISR_EXIT

    clrf    pulses          ;clearing variables
    clrf    ir_reg
    clrf    time
    clrf    address
    clrf    naddress
    clrf    address
    clrf    ncommand
    clrf    command
    goto    ISR_EXIT

INIT:
;OSCCON INIT
    banksel OSCCON
    movlw   b'01100000'     ;4Mhz oscillator
    movwf   OSCCON

;OUTPUT INIT
    banksel TRISD
    clrf    TRISD           ;TRISD OUTPUT
    banksel PORTD
    clrf    PORTD           ;PORTD LOW

;INPUT INIT
    banksel TRISB
    bsf     TRISB,RB0       ;RB0 INPUT
    bsf     WPUB,RB0

    movlw   0x00
    banksel ANSELH
    movwf   ANSELH          ;RB0 DIGITAL

    call Delay

;OPTION REG INIT / TMR0
    banksel OPTION_REG
    movlw   b'00000000'     ;TMR0 prescale 1:2 increment every 2us
    movwf   OPTION_REG
    movlw   b'01100110'     ;preload 206
    movwf   TMR0            ;50 tick until overflow 50*2us = 100us

;INTCON INIT
    banksel INTCON
    bcf     INTCON,T0IF     ;TMR0 overflow flag clear
    bsf     INTCON,T0IE     ;TMR0 overflow enable
    bsf     INTCON,GIE      ;global interrupt enable

    return

MAIN:

    call INIT
    call FLASH              ;LED FLASH
    goto $-1
    END

person Martin Bokány    schedule 24.05.2020    source источник
comment
В опубликованном коде есть ошибки. - Первый - Это не полный файл программы, который можно собрать с помощью инструментов Microchip. Чтобы исправить это, требуется, по крайней мере, инициализация всех битов слова конфигурации. - Второй - Неправильная реализация обработки вектора прерывания. Это приведет к сбою программы. - В-третьих - Вам нужно лучше понимать инфракрасный протокол NEC. См .: протоколы Vishay IR и ИК-протокол NEC WB_IRRC.   -  person Dan1138    schedule 25.05.2020


Ответы (1)


В своем высокомерии я подумал, что ваше задание было простым и понятным.

Я не мог ошибиться больше. Мне потребовалось три дня, чтобы кодировать и тестировать приложение, которое может декодировать протокол инфракрасного дистанционного управления NEC.

Попытки понять предполагаемую документацию, найденную на различных веб-сайтах, создают серьезные проблемы. Все это вводит в заблуждение и является неполным. Он потратил целый день, просто разбираясь в этом беспорядке.

Вот что у меня получилось:

    list n=0,c=255,r=dec    ; Make .LST file look nice
    errorlevel -302         ; Suppress Register in operand not in bank 0 warning.
#define MAIN_ASM
;
; File:     main.asm
; Date:     2020-05-23
; Target:   PIC16F887
; Author:   dan1138
;
; Description:
;   Decoder for NEC Infrared Remote control protocol.
;
;   Physical transport:
;       Long flash  (> 8ms)
;       Pause       (COMMAND when pause is more than 4ms), 
;                   (REPEAT when pause is less than 4ms but greater than 2ms)
;       Short flash (0.5 to 0.6ms)
;     Repeats 32 times:
;       Pause       DATA is one when pause is more than 1ms, else DATA is zero.
;       Short flash (0.5 to 0.6ms)
;
;
;                         PIC16F887
;                 +----------:_:----------+
;       VPP ->  1 : RE3/MCLR/VPP  PGD/RB7 : 40 <> PGD
;           <>  2 : RA0/AN0       PGC/RB6 : 39 <> PGC
;           <>  3 : RA1/AN1      AN13/RB5 : 38 <>
;           <>  4 : RA2/AN2      AN11/RB4 : 37 <>
;           <>  5 : RA3/AN3   PGM/AN9/RB3 : 36 <> 
;           <>  6 : RA4/T0CKI     AN8/RB2 : 35 <> 
;           <>  7 : RA5/AN4      AN10/RB1 : 34 <> 
;           <>  8 : RE0/AN5  INT/AN12/RB0 : 33 <> IR_RECEIVERn
;           <>  9 : RE1/AN6           VDD : 32 <- 5v0
;           <> 10 : RE2/AN7           VSS : 31 <- GND
;       PWR -> 11 : VDD               RD7 : 30 -> LCD_ON
;       GND -> 12 : VSS               RD6 : 29 -> LCD_E
;           -> 13 : RA7/OSC1          RD5 : 28 -> LCD_RW
;           <- 14 : RA6/OSC2          RD4 : 27 -> LCD_RS
;           <> 15 : RC0/SOSCO   RX/DT/RC7 : 26 <>    
;           <> 16 : RC1/SOSCI   TX/CK/RC6 : 25 <>    
;           <> 17 : RC2/CCP1          RC5 : 24 <>
;           <> 18 : RC3/SCL       SDA/RC4 : 23 <>    
;    LCD_D4 <> 19 : RD0               RD3 : 22 <> LCD_D7
;    LCD_D5 <> 20 : RD1               RD2 : 21 <> LCD_D6
;                 +-----------------------:
;                          DIP-40
;
; Include Special Function Register definitions
;
#include "p16f887.inc"
#include "main.inc"
#include "lcd.inc"
;
; PIC16F887 Configuration Bit Settings
; Assembly source line config statements
;
 __CONFIG _CONFIG1, _FOSC_INTRC_NOCLKOUT & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _IESO_ON & _FCMEN_OFF & _LVP_OFF
 __CONFIG _CONFIG2, _BOR4V_BOR21V & _WRT_OFF
;
; Power on reset vector
;
RES_VECT    CODE    0x0000      ; processor reset vector
    pagesel START
    GOTO    START               ; go to beginning of program
;
; Interrupt context save area
;
ISR_DATA    UDATA_SHR
WREG_SAVE   res     1
STATUS_SAVE res     1
PCLATH_SAVE res     1
NEC_IR_State        res 1
NEC_IR_StartFlash   res 1
NEC_IR_CdPause      res 1
;
; Data area for protocol decoder
;
NEC_IR_DATA   UDATA
NEC_IR_RawData      res 4
NEC_IR_Address      res 1
NEC_IR_Command      res 1
NEC_IR_Flags        res 1
#define BIT_NEC_IR_Flags_COMMAND NEC_IR_Flags,0
#define BIT_NEC_IR_Flags_REPEAT  NEC_IR_Flags,1
;
; Interrupt Service Routine
;
ISR_VECT    CODE    0x0004      ; interrgot vector
ISR:
    movwf   WREG_SAVE           ; 
    movf    STATUS,W            ; These register: WREG, STATUS, PCLATH
    movwf   STATUS_SAVE         ; are what, at the minimum, must be saved 
    movf    PCLATH,W            ; and restored on an interrupt.
    movwf   PCLATH_SAVE         ;
    clrf    STATUS              ; Force to memory bank 0
    clrf    PCLATH              ; Force to code page 0
;
; Handle external INT interrupt request
;
    btfsc   INTCON,INTE
    btfss   INTCON,INTF
    goto    INT_End
    bcf     INTCON,INTF
;
; Block flash detection until application loop is done
;
    btfss   BIT_NEC_IR_Flags_COMMAND
    btfsc   BIT_NEC_IR_Flags_REPEAT
    goto    INT_End

    movf    NEC_IR_State,F
    skpz    
    goto    NEC_IR_NextState
;
; Look for initial long flash
;
    clrf    NEC_IR_StartFlash
    clrf    TMR0
    bcf     INTCON,T0IF
MeasureStartFlash:
    btfsc   PORTB,0             ; Skip if flash still on
    goto    EndOfFlash
    btfss   INTCON,T0IF
    goto    MeasureStartFlash
    bcf     INTCON,T0IF
    incfsz  NEC_IR_StartFlash,W
    movwf   NEC_IR_StartFlash
    goto    MeasureStartFlash
EndOfFlash:
    clrf    TMR0
    bcf     INTCON,T0IF
    clrf    NEC_IR_CdPause
    movlw   8
    subwf   NEC_IR_StartFlash,W
    btfss   STATUS,C            ; Skip if count equal or greater than 8 T0IF ticks
    goto    INT_End
;
; Measure pause after flash
;
MeasurePause:
    btfss   PORTB,0             ; Skip if flash still off
    goto    EndOfPause
    btfss   INTCON,T0IF
    goto    MeasurePause
    bcf     INTCON,T0IF
    incfsz  NEC_IR_CdPause,W
    movwf   NEC_IR_CdPause
    goto    MeasurePause
EndOfPause:
    btfss   PORTB,0             ; Skip when flash goes off
    goto    EndOfPause
    clrf    TMR0
    bcf     INTCON,T0IF
    bcf     INTCON,INTF
    movlw   4
    subwf   NEC_IR_CdPause,W
    btfsc   STATUS,C            ; Skip if count less than 4 T0IF ticks
    goto    ReceiveCommandState
    banksel NEC_IR_Flags
    bsf     BIT_NEC_IR_Flags_REPEAT ; Assert this is a REPEAT event
    goto    INT_End
ReceiveCommandState:
    movlw   d'32'
    movwf   NEC_IR_State      ; Advnace to state 32 when we expect ADDRESS/COMMAND data
INT_End:
;
    movf    PCLATH_SAVE,W       ;
    movwf   PCLATH              ; Restore the saved context of the
    movf    STATUS_SAVE,W       ; interrupted execution.
    movwf   STATUS              ;
    swapf   WREG_SAVE,F         ;
    swapf   WREG_SAVE,W         ;
    retfie                      ; Exit ISR and enable the interrupts.
;
; Receive COMMAND or REPEAT event
;
NEC_IR_NextState:
    banksel PORTB
    bcf     STATUS,C
    btfsc   INTCON,T0IF
    bsf     STATUS,C
    banksel NEC_IR_RawData
    rlf     NEC_IR_RawData,F
    rlf     NEC_IR_RawData+1,F
    rlf     NEC_IR_RawData+2,F
    rlf     NEC_IR_RawData+3,F
EndOfBit:
    banksel PORTB
    btfss   PORTB,0             ; Skip when flash goes off
    goto    EndOfBit
    clrf    TMR0
    bcf     INTCON,T0IF
    decf    NEC_IR_State,F
    btfss   STATUS,Z
    goto    INT_End
;
; Validate ADDRESS and COMMAND
;
    banksel NEC_IR_RawData
    comf    NEC_IR_RawData,W
    xorwf   NEC_IR_RawData+1,W
    btfss   STATUS,Z
    goto    INT_End
    comf    NEC_IR_RawData+2,W
    xorwf   NEC_IR_RawData+3,W
    btfss   STATUS,Z
    goto    INT_End

    movf    NEC_IR_RawData+1,W
    movwf   NEC_IR_Command
    movf    NEC_IR_RawData+3,W
    movwf   NEC_IR_Address
    bsf     BIT_NEC_IR_Flags_COMMAND
    goto    INT_End
;
; Initialize the PIC hardware
;
START:
    clrf    INTCON              ; Disable all interrupt sources
    banksel BANK1
    clrf    PIE1
    clrf    PIE2

    movlw   b'01100000'
    movwf   OSCCON              ; Set internal oscillator at 4MHz

    movlw   b'10000001'         ; Pull-ups off, INT edge high to low, WDT prescale 1:1
    movwf   OPTION_REG          ; TMR0 clock edge low to high, TMR0 clock = FCY, TMR0 prescale 1:4
                                ; TIMER0 will assert the overflow flag every 256*4 (1024)
                                ; instruction cycles, with a 4MHz oscilator this ia 1.024 milliseconds.

    movlw   b'11111111'         ;
    movwf   TRISA

    movlw   b'11111111'         ;
    movwf   TRISB

    movlw   b'11111111'         ;
    movwf   TRISC

    movlw   b'11111111'         ;
    movwf   TRISD

    ; Set all ADC inputs for digital I/O
    banksel BANK3
    movlw   b'00000000'
    movwf   ANSEL
    movlw   b'00000000'
    movwf   ANSELH
    banksel BANK2
    clrf    CM1CON0             ; turn off comparator
    clrf    CM2CON0             ; turn off comparator
    banksel BANK1
    movlw   b'00000000'
    movwf   ADCON1
    clrf    VRCON               ; turn off voltage reference
    banksel BANK0
    movlw   b'10000000'
    movwf   ADCON0

    pagesel main
    goto    main
;
; Main data
;
MAIN_DATA   UDATA
RepeatCount res     1
;
; Main application code
;
MAIN_PROG   CODE
; 
; Main application initialization
;
main:
    lcall   OpenXLCD

    movlw   LINE_ONE
    lcall   SetDDRamAddr

    movlw   LOW(LCD_message1)
    movwf   pszLCD_RomStr
    movlw   HIGH(LCD_message1)
    movwf   pszLCD_RomStr+1
    lcall   putrsXLCD

    banksel NEC_IR_Flags
    clrf    NEC_IR_Flags
    clrf    NEC_IR_State
    bcf     BIT_NEC_IR_Flags_COMMAND
    bcf     BIT_NEC_IR_Flags_REPEAT
    bcf     INTCON,INTF
    bsf     INTCON,INTE
    bsf     INTCON,GIE
;
; Application process loop
;
AppLoop:
    movf    NEC_IR_Flags,F      ; Check for event
    btfsc   STATUS,Z            ; Skip if any event bit set
    GOTO    AppLoop             ;

    banksel NEC_IR_Flags
    btfsc   BIT_NEC_IR_Flags_REPEAT ; skip of not a REPEAT event
    goto    IncrementCount
    banksel RepeatCount
    clrf    RepeatCount
;
; Increment repeat count
;
IncrementCount:
    banksel RepeatCount
    incfsz  RepeatCount,W
    movwf   RepeatCount

;
; Show measurement for Start Of Transmission (SOT) flash
;
    movlw   LINE_TWO
    lcall   SetDDRamAddr
    movf    NEC_IR_StartFlash,W
    lcall   PutDecXLCD
;
; Show measurement for pause after SOT flash
;
    movlw   ' '
    lcall   WriteDataXLCD
    movf    NEC_IR_CdPause,W
    lcall   PutDecXLCD
;
; Show decoded ADDRESS and COMMAND
;
    movlw   ' '
    lcall   WriteDataXLCD
    banksel NEC_IR_Address
    movf    NEC_IR_Address,W
    lcall   PutHexXLCD
    banksel NEC_IR_Command
    movf    NEC_IR_Command,W
    lcall   PutHexXLCD
;
; Show REPEAT count
;
    movlw   ' '
    lcall   WriteDataXLCD
    banksel RepeatCount
    movf    RepeatCount,W
    lcall   PutHexXLCD
;
; Clear event flags to enable capture of next event
;
    banksel NEC_IR_Flags
    clrf    NEC_IR_Flags

    lgoto   AppLoop
;
; LCD messages
;
MAIN_CONST   code
LCD_message1:
    dt  "NEC IR Decode v0",0
    END

Я написал много кода на ассемблере для 8-битных контроллеров PIC. Это приложение насыщено некоторыми очень тонкими уловками. В нем недостаточно комментариев, чтобы объяснить, как и почему это работает. Вам просто нужно будет проанализировать это самостоятельно.

Уловка с протоколом NEC IR заключается в том, что все дело в паузах между вспышками IR. Если в Интернете есть точное, полное и понятное описание протокола управления NEC IR, мне его не найти.

Я думал, что можно было бы научить вас программировать это, но не думаю, что я достаточно хорош, чтобы это осуществить. Я могу только надеяться, что это может сработать для вас в качестве примера.

person Dan1138    schedule 27.05.2020
comment
Привет, Дэн, да, я впервые использую PIC и сборку, поэтому я немного запутался. Тем не менее, большое спасибо за потраченное время. Мне удалось настроить и внедрить ваш код в свое приложение. Работает нормально. Я ценю вашу работу. :) - person Martin Bokány; 28.05.2020
comment
@ MartinBokány, я рад, что мой пост оказался для вас полезным. Удачи в завершении вашего проекта. - person Dan1138; 29.05.2020