I have added some code to my IR sampler so the chip/board can double as unknown/salvaged crystal identifier. For internal and external clocking of 4Mhz I am getting counts of about 55%. I used single comparator mode to catch pulses from a full rectifier through
1M/270K divider (with the current 9.2 Vac US Robatics wall adapter.) I have been wrestling with this program for a few days , ironing out some other problems, and my brain is a mush. I would appreciate some help with this.;********************************************************************** ; This file is a basic code template for object module code * ; generation on the PICmicro PIC16F628A. This file contains the * ; basic code building blocks to build upon. As a project minimum * ; the 16F628A.lkr file will also be required for this file to * ; correctly build. The .lkr files are located in the MPLAB * ; directory. * ; * ; If interrupts are not used all code presented between the * ; code section "INT_VECTOR and code section "MAIN" can be removed. * ; In addition the variable assignments for 'w_temp' and * ; 'status_temp' can be removed. * ; * ; If interrupts are used, as in this template file, the 16F628A.lkr * ; file will need to be modified as follows: Remove the lines * ; CODEPAGE NAME=vectors START=0x0 END=0x4 PROTECTED * ; and * ; SECTION NAME=STARTUP ROM=vectors * ; and change the start address of the page0 section from 0x5 to 0x0 * ; * ; Refer to the MPASM User's Guide for additional information on * ; features of the assembler and linker (Document DS33014). * ; * ; Refer to the respective PICmicro data sheet for additional * ; information on the instruction set. * ; * ;********************************************************************** ; * ; Filename: irs_osc_cntr.asm * ; Date: * ; File Version: * ; * ; Author: * ; Company: * ; * ; * ;********************************************************************** ; * ; Files required: * ; 16F628A.lkr * ; * ; * ;********************************************************************** ; * ; Notes: modified IR_sampler (unfinished, unresolved TX_max_char_count * ; outs all possible values ) * ; besides sampling ir signals, use of the comparators and * ; AC supply to count/measure the oscilator frequency * ; * ;**********************************************************************
list p=16F628A ; list directive to define processor #include ; processor specific variable definitions
errorlevel -302 ; suppress message 302 from list file
; __CONFIG _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT __CONFIG _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC
; '__CONFIG' directive is used to embed configuration word within .asm file. ; The lables following the directive are located in the respective .inc file. ; See data sheet for additional information on configuration word settings.
;***** VARIABLE DEFINITIONS (examples)
; example of using Shared Uninitialized Data Section INT_VAR UDATA 0x20
DD_PA equ 0xa6 DD_PB equ 0xf2
timer1_prescaler res 1 ; /start PB5_old_val res 1 PB5_new_val res 1 timer_lo res 1 timer_hi res 1 timer1_timeouts res 1 ; number of timeouts at 20, decrement the ; TX_max_char_count so that we can periodicaly ; check the degree of activity in the output buffer ; ( when external commands are implemented ) ; for now transfer the TX_max_char_count at first timeout. ResultsA res 1 ; port A outputs ; 0 - output ; 1 - comp- ; 2 - comp+ / ref out 120/60 Hz input ; 3 - ; 4 - ; 5 - VPP/!MCLR always input ; 6 - ; 7 - baud rate input HI/LO (BRGH bit) ResultsB res 1 ; port B outputs ; 0 - timer read hickup indicator ; 1 - Async RX ; 2 - Async Tx ; 3 - ?IR output? not yet implemented ; 4 - measure AC low / PGM ; 5 - IR input ; 6 - PGC ; 7 - PGD comp_flags res 1 AC_present equ 0 ; 0 - ac detected start_measurement equ 1 ; 1 - start measurement ( next zero cross) measuring equ 2 ; 2 - measurement in progress long equ 3 ; 3 - short(.1sec)/ long (1sec) comparator_old_state equ 4 ; 4 - comp old state ; 5 - ; 6 - comp new state ; 7 - reference_adjust res 1 ; incremented by Timer1 ; timeouts ( when marker is ; transmited ) when 4 or 8 and no AC ; reduce the reference reference_adjust_done equ 6 ; AC_found equ 7 ; flag indicating ac ; was just detected and reference ; should be reduced one more notch
zero_cross_count res 1 tmr0_temp res 1 t0_ovf1 res 1 t0_ovf2 res 1 t0_ovf3 res 1
;################################################################################### ; Commands from the serial port precceded by 00 AA sync chars ; Read or write registers ; 101 00001 read register specified in following byte ; 101 00010 write register specified in following byte with data in next additional byte
; sync_OK res 1 ; set to 0 when 0 received incremented when AA received Last_command res 1 ; if sync is 1 store bytes Command_data1 res 1 ; usualy address Command_data2 res 1 ; usualy data value
Free_ram:
INT_VAR_SHR UDATA_SHR 0x71 w_temp res 1 ; variable used for context saving status_temp res 1 ; variable used for context saving
temp1 res 1 ; used by place_byte_in_output_buffer temp2 res 1 ; used by place_byte_in_output_buffer temp3 res 1 buff_head res 1 ; points to where new data is stored buff_tail res 1 ; points to which byte is next to be transmited ( read advance ) buff_start res 1 ; buff_end res 1 new_buff_head res 1 TX_char_count res 1 TX_max_char_count res 1 ;********************************************************************** RESET_VECTOR CODE 0x000 ; processor reset vector goto main ; go to beginning of program
INT_VECTOR CODE 0x004 ; interrupt vector location movwf w_temp ; save off current W register contents swapf STATUS, w ; move status register into W register movwf status_temp ; save off contents of STATUS register bcf STATUS, RP0 bcf STATUS, RP1
; check for comparator state change movfw TMR0 movwf tmr0_temp
btfss PIR1, CMIF goto comparator_done bsf PORTA, 3 btfsc CMCON, C2OUT goto wrap_up_comp_int bsf comp_flags, AC_present bsf ResultsA, 0 bsf PORTA, 0 btfss comp_flags, start_measurement goto wrap_up_comp_int btfss comp_flags, measuring goto setup_measurement incf zero_cross_count, f ; movfw zero_cross_count ; call place_byte_in_output_buffer
btfsc comp_flags, long goto check_long movlw .12 subwf zero_cross_count, w btfss STATUS, Z goto measurement_incomplete goto transnit_count check_long: movlw .120 subwf zero_cross_count, w btfss STATUS, Z goto measurement_incomplete transnit_count: movfw t0_ovf3 call place_byte_in_output_buffer movfw t0_ovf2 call place_byte_in_output_buffer movfw t0_ovf1 call place_byte_in_output_buffer movfw tmr0_temp call place_byte_in_output_buffer ; movlw A'/' ; call place_byte_in_output_buffer ; movlw A'.' ; call place_byte_in_output_buffer ; movlw A'1' ; call place_byte_in_output_buffer btfsc comp_flags, long goto wrap_up_measurements bsf comp_flags, long bcf comp_flags, measuring goto wrap_up_comp_int
wrap_up_measurements: bcf PORTA, 0 bcf comp_flags, measuring bcf comp_flags, start_measurement bcf comp_flags, long bsf T1CON, TMR1ON goto wrap_up_comp_int
setup_measurement: ; 17 instruction cycles to get here movlw 0x13 ; start with 19 (19 instructions since ; ZERO crossing movwf TMR0 clrf zero_cross_count ; clrf TMR0 clrf t0_ovf1 clrf t0_ovf2 clrf t0_ovf3 bcf T1CON, TMR1ON bsf comp_flags, measuring
measurement_incomplete: wrap_up_comp_int: bcf PIR1, CMIF comparator_done: ; check timer0 overflow do_timer0: btfss INTCON, T0IF goto timer0_done incf t0_ovf1, f btfss STATUS, Z goto timer0_wrap_up incf t0_ovf2, f btfss STATUS, Z goto timer0_wrap_up incf t0_ovf3, f btfss STATUS, Z ; goto timer0_wrap_up
timer0_wrap_up: bcf INTCON, T0IF timer0_done:
; isr code can go here or be located as a call subroutine elsewhere test_PB_change: bcf STATUS, RP0 ; RAM PAGE 0 btfss INTCON, RBIF goto timer_overflow movfw PORTB andlw 0x20 movwf PB5_new_val subwf PB5_old_val, w btfsc STATUS, Z goto PB_change_wrap_up1 movfw TMR1H movwf timer_hi movfw TMR1L movwf timer_lo movf TMR1H, w ; Read high byte SUBWF timer_hi, W ; Sub 1st read with ; 2nd read BTFSC STATUS, Z ; Is result = 0 GOTO done_reading_timer ; Good 16-bit read bsf ResultsB, 0 decf timer_hi, f done_reading_timer: clrf TMR1H clrf TMR1L clrf timer1_timeouts ; output the data to the Async output buffer ; test if change is L/H or H/L
btfsc PB5_new_val, 5 goto bit_end ; on account of IR receiver being normaly high ; invert logic bsf timer_hi, 7 ; slap the bit start indicator into the highest bit movfw timer_hi call place_byte_in_output_buffer movfw timer_lo call place_byte_in_output_buffer goto PB_change_wrap_up bit_end: bcf timer_hi, 7 ; slap the bit end indicator into the highest bit movfw timer_hi call place_byte_in_output_buffer movfw timer_lo call place_byte_in_output_buffer PB_change_wrap_up: movwf PB5_new_val movfw PB5_old_val PB_change_wrap_up1: bcf INTCON, RBIF portB_no_change: timer_overflow; btfss PIR1, TMR1IF ; did timer 1 overflow? goto timer1_service_done bcf PIR1, TMR1IF ; clear a byte somewhere?
; handle first time out: send '#' followed by the maximun number of bytes ; in transmit buffer incf timer1_timeouts, f movlw 1 subwf timer1_timeouts, w btfss STATUS, Z goto handle_buff_treshold_counter movlw 23 call place_byte_in_output_buffer movfw TX_max_char_count call place_byte_in_output_buffer
;every 20 timeouts ( aprox 1 sec, 0.5 with 8MHz clock ) send '*' handle_buff_treshold_counter: movlw 14 subwf timer1_timeouts, w btfss STATUS, C goto timer1_service_done clrf timer1_timeouts incf timer1_timeouts, f movlw 2a call place_byte_in_output_buffer bcf STATUS, RP0 ; RAM PAGE 0
movlw 1 subwf TX_max_char_count, w btfss STATUS, Z decf TX_max_char_count, f
; btfsc reference_adjust, AC_found ; goto timer1_service_done ; clrf comp_flags btfss reference_adjust, 1 incf reference_adjust, f
; bsf comp_flags, start_measurement
timer1_service_done:
int_done: swapf status_temp, w ; 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 retfie ; return from interrupt
place_byte_in_output_buffer: ; pointers - test write/read advance movwf temp1 ; test if head + 1 is equal tail , if so buffer is full!!! ; first test if it hits end of buffer movfw buff_head addlw 1 movwf new_buff_head ; movwf temp2 subwf buff_end, w btfsc STATUS, Z goto head_hit_end ; now test it against the tail pointer movfw new_buff_head subwf buff_tail, w btfsc STATUS, Z goto buffer_full goto place_character head_hit_end: ; head will be pointing to beginning - is tail currently pointing to the beginning? movfw buff_tail subwf buff_start, w btfsc STATUS, Z goto buffer_full movfw buff_start movwf new_buff_head place_character: movfw buff_head movwf FSR movfw temp1 movwf INDF movfw new_buff_head movwf buff_head
character_qued_for_output: bcf STATUS, C return
buffer_full: bsf STATUS, C return
main ; remaining code goes here bcf STATUS, RP0 ; RAM PAGE 0 bcf STATUS, RP1 ; RAM PAGE 0
clrf PORTA movlw 0x04 movwf PORTB
banksel OPTION_REG bcf OPTION_REG, NOT_RBPU bsf STATUS, RP0 ; RAM PAGE 1 movlw 0x0f ; high speed int osc, POR and BOR movwf PCON movlw DD_PA movwf TRISA ; PA5, PA7 inputs
movlw DD_PB ; RB7-RB4 and RB1(RX)=input, others output movwf TRISB banksel PORTB movlw 0x04 movwf PORTB movwf ResultsB movlw 0x00 movwf PORTA movwf ResultsA ; setup voltage reference banksel VRCON ; bsf TRISA, 2 movlw 0xff ; low range max (3.593V) the length below this treshold could be measured ; and the reference adjusted depending on the voltage applied movwf VRCON
bcf STATUS, RP0 ; PAGE 0 movlw 5 ; comparator 2 only movwf CMCON
BCF PIR1,CMIF ; Clear pending interrupts comp_old_state ; setup timer 0 bsf STATUS, RP0 ; PAGE 0 bcf OPTION_REG, T0CS
clrf temp1 settle decfsz temp1,F goto settle
banksel T1CON movlw 0x20 ; prescale /8, enable timer movwf T1CON ; clrf T1CON movwf timer1_prescaler movlw 0x30 andwf timer1_prescaler, f movlw 0xc8 ; enable global interrupts, peripheral interrupts, interrupt on change of port B movwf INTCON bsf STATUS, RP0 ; RAM PAGE 1 ; bsf PIE1, TMR1IE ; enable timer 1 interrupts, timeout clears any in-progrees IR character reception?? ; postpone enabling the timer ints untill after the test messages have been sent ; to avoid the possibility that we are in place_byte_in_output_buffer() which is otherwise ; used by the interrupt routine movlw 1 ; set time outs to 1 to indicate we are not movwf timer1_timeouts ; in the middle of receiving IR code/char ;