#include <p16f690.inc> list p=16f690 __config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOR_ON & _IESO_OFF & _FCMEN_OFF ; ; This program will read until eight pwm inputs and will send its values ; through serial port at 115200bps. ; ; ; +5V -| VDD VSS |- GND ; input 6 -| RA5 RA0 |- input 1 ; input 5 -| RA4 RA1 |- input 2 ; input 4 -| RA3 RA2 |- input 3 ; output 4 -| RC5 RC0 |- n. c. ; output 3 -| RC4 RC1 |- status led ; output 2 -| RC3 RC2 |- output 1 ; n.c. -| RC6 RB4 |- input 8 ; n.c. -| RC7 RB5 |- rx ; tx* -| RB7 RB6 |- input 7 ; ; ; * In order to keep IO voltage at 3.3V use a voltage divider on TX. ; ; PS: outputs are not covered by this program yet. ; ; The INPUT_NUM is attached to input_mask and the ; interruption. Do not change this value without ; changing the interruption and mask. #define INPUT_NUM 8 #define MAGIC 0x55AA cblock 0x020 ; input_value, input_rise and input_mirror ; are at the bank's beginning to make easy ; the exchange of data between them. input_value:(INPUT_NUM * 2) input_previous input_current input_changed input_mask input_updated sent_update endc cblock 0x72 save_w save_status save_fsr timer_l timer_h count tmr1if_count endc cblock 0x0a0 ; see input_value input_rise:(INPUT_NUM * 2) endc cblock 0x120 ; see input_value input_mirror:(INPUT_NUM * 2) endc ; Reset Vector org 0x0000 nop nop nop goto Main ; Interrupts Vector org 0x0004 ; save the current context movwf save_w swapf STATUS, w clrf STATUS movwf save_status movf FSR, w movwf save_fsr ; it's a input event btfss INTCON, RABIF goto IntInputDone ; capture timer 1 movf TMR1H, w movwf timer_h movf TMR1L, w movwf timer_l movf TMR1H, w subwf timer_h, w btfsc STATUS, Z goto IntTMR1Done movf TMR1H, w movwf timer_h movf TMR1L, w movwf timer_l IntTMR1Done: ; capture the current input state movf PORTA, w btfsc PORTB, RB6 iorlw (1<<6) btfsc PORTB, RB4 iorlw (1<<7) bcf INTCON, RABIF ; identify the changed inputs movwf input_current xorwf input_previous, w movwf input_changed movf input_current, w movwf input_previous ; prepare for loop movlw .1 movwf input_mask movlw input_rise movwf FSR goto IntInputLoop IntInputNext: incf FSR, f IntInputNextHalf: ; ... and ensure bank 0 selection incf FSR, f bsf FSR, 7 ; done if no more channels bcf STATUS, C rlf input_mask, f btfsc STATUS, C goto IntInputDone IntInputLoop: ; skip if channel not changed movf input_mask, w andwf input_changed, w btfsc STATUS, Z goto IntInputNext ; check if it is raising or falling andwf input_current, w btfss STATUS, Z goto IntInputRise ; calculate and move the lsb to input_value movf INDF, w subwf timer_l, w bcf FSR, 7 movwf INDF ; calculate and move the msb to input_value bsf FSR, 7 incf FSR, f movf INDF, w btfss STATUS, C incf INDF, w subwf timer_h, w bcf FSR, 7 movwf INDF goto IntInputNextHalf IntInputRise: ; tell main loop we have all channels btfsc input_mask, 1 incf input_updated, f ; save the rise instant movf timer_l, w movwf INDF incf FSR, f movf timer_h, w movwf INDF goto IntInputNextHalf IntInputDone: ; restore the previous context movf save_fsr, w movwf FSR swapf save_status, w movwf STATUS swapf save_w, f swapf save_w, w retfie Main: ; bank 0 clrf STATUS clrf PORTA clrf PORTB clrf PORTC ; bank 1 bsf STATUS, RP0 movlw (b'111'<<IRCF0) movwf OSCCON ; set internal oscillator frequency to 8 MHz movlw (0<<NOT_RABPU) movwf OPTION_REG ; ,------ input 6 ; |,----- input 5 ; ||,---- input 4 ; |||,--- input 3 ; ||||,-- input 2 ; |||||,- input 1 movlw b'11111111' movwf TRISA ; set PORTA as input movwf WPUA ; enable weak pull-up movwf IOCA ; enable interrupt-on-change ; ,-------- tx ; |,------- input 6 ; ||,------ rx ; |||,----- input 7 movlw b'01111111' movwf TRISB ; ,------ output 4 ; |,----- output 3 ; ||,---- output 2 ; |||,--- output 1 ; ||||,-- status ; |||||,- n. c. movlw b'11000001' movwf TRISC movlw (1<<TXEN|1<<BRGH) movwf TXSTA ; enable async transmitter and select high baud rate movlw (1<<BRG16) movwf BAUDCTL ; 16-bit baud rate generator movlw .16 ; use value 16 for SPBRG:SPBRGH to get 115200bps baud rate movwf SPBRG clrf SPBRGH ; Bank 2 bcf STATUS, RP0 bsf STATUS, RP1 clrf ANSEL clrf ANSELH ; ,------- input 6 ; | ,----- input 7 movlw b'01010000' movwf WPUB movwf IOCB ; bank 0 clrf STATUS ; clear the first two banks movlw 0x020 call ClearBank movlw 0x0A0 call ClearBank movlw (1<<SPEN|1<<CREN) movwf RCSTA movlw (1<<T1CKPS0|1<<TMR1ON) movwf T1CON ; enable timer and set frequency to 1MHz (=8Mhz/4/2) movlw (1<<GIE|1<<PEIE|1<<RABIE) movwf INTCON MainLoopNoUpdate: ; toggle status led if idle for more than INPUT_NUM * 2000 usec movf timer_h, w subwf TMR1H, w sublw high(.2000 * INPUT_NUM) btfsc STATUS, C goto MainLoop ; toggle status led at each 8 timer1 overflows, i.e., about 0.52 sec btfss PIR1, TMR1IF goto MainLoop bcf PIR1, TMR1IF incf tmr1if_count, f movlw H'07' andwf tmr1if_count, w btfss STATUS, Z goto MainLoop ; toggle status led movf PORTC, w xorlw (1<<RC1) movwf PORTC MainLoop: ; loop if no updates movf sent_update, w subwf input_updated, w btfsc STATUS, Z goto MainLoopNoUpdate ; prepare for mirroring addwf sent_update, f movlw (INPUT_NUM * 2) movwf count movlw input_value movwf FSR MirrorLoop: movf INDF, w bsf STATUS, IRP movwf INDF bcf STATUS, IRP incf FSR, f decfsz count, f goto MirrorLoop ; restart if there was update while mirroring movf input_updated, w subwf sent_update, w btfss STATUS, Z goto MainLoop ; finally send the captured values ; send a magic number to sync movlw low(MAGIC) call Send movlw high(MAGIC) call Send ; prepare for send loop movlw (INPUT_NUM * 2) movwf count movlw low(input_mirror) bsf STATUS, IRP movwf FSR SendLoop: movf INDF, w call Send incf FSR, f decfsz count, f goto SendLoop bcf STATUS, IRP ; set led on bcf PORTC, RC1 goto MainLoop Send: btfss PIR1, TXIF goto $ - 1 movwf TXREG return ClearBank: ; clears the gpr bank pointed by w plus irp, ; but preserves the common 16 bytes. ; ensure the beginning of the bank andlw b'10100000' movwf FSR movlw .80 movwf count ClearBankLoop: clrf INDF incf FSR, f decfsz count, f goto ClearBankLoop return end