// // Copyright (C) Quaketronics.com // Released under a Creative Commons License // Attribution-Noncommercial-Share Alike 3.0 United States // See http://creativecommons.org/licenses/by-nc-sa/3.0/us/ // For attribution link to http://www.quaketronics.com/ // Alternative licenses available, contact tom@quaketronics.com // // Firmware for Flash Controller on PIC project // Uses PIC16F616 as a target // uses PICC PCM c compiler(4.048) and MPLab(7.60) // Pin Assignments for 20MHz External Resonator Version // 1 Vdd (+5) // 2 RA5, PIN_A5 [ Spare Input ] // 3 AN3 [ Delay Pot Input ] // 4 /MCLR, Vpp [ Reset, In-Circuit Programming Voltage ] // 5 RC5, PIN_C5 [ Blanking Jumper Input: 0=Blanking (with Jumper), 1=No Blanking (no Jumper) ] // 6 RC4, PIN_C4 [ Delay Jumper Input: 1=Long Delay (16ms - 512ms) (No Jumper), 0=Short Delay (2ms - 16ms) (with Jumper), Zero Delay handled separately ] // 7 RC3, PIN_C3 [ LED Output ] // 8 C12IN2- [ Comparator Input ] // 9 C12IN1- [ Comparator Input ] // 10 C2IN+ [ Comparator Input ] // 11 RA2, PIN_A2 [ Trigger Output ] // 12 ICSPCLK [ In-Circuit Programming Clock ] // 13 C1IN+, ICSPDAT [ Comparator Input, In-Circuit Programming Data ] // 14 Vss (GND) #if defined(__PCM__) #include <16F616.h> #fuses INTRC_IO,IOSC4, NOPROTECT // internal 4 MHz Clock; no protection (yet) #fuses MCLR, NOBROWNOUT, NOWDT // 4 MHz Fosc, use /MCLR for reset, no brownout detect, no watchdog timer #priority INT_TIMER1, INT_AD #endif #define BLANK_INTERVAL 183 // ~3 seconds blanking holdoff #define ZERO_LATENCY 0x10 // ~10% of total 10 bit range of the ADC #define ADC_INTERVAL 15 // ~.25 s conversion interval #define SHORT_DELAY ~0x1F40 // set timer for 2 ms delay // states #define IDLE 0 #define DELAY 1 #define PULSE_OUT 2 #define BLANK 3 #define ERROR 4 volatile unsigned long timer_overflows; // holds the number of times trigger timer1 overflowed volatile unsigned int adc_overflows; // holds the number of times adc timer1 overflowed volatile unsigned long flash_delay; // holds the adc value, used to set the delay volatile unsigned int zero_delay; // set for short delays, enables faster response volatile unsigned int state; // see state diagram #INT_AD void adc_isr(void) { flash_delay = read_adc(ADC_READ_ONLY); // starts conversion zero_delay = (flash_delay < ZERO_LATENCY); // zero delay is an int, so it speeds up the compare later disable_interrupts(INT_AD); return; } #INT_TIMER1 void timer_isr(void) { // this code replaces all of the 555's switch (state) { case IDLE: if(adc_overflows++ > ADC_INTERVAL) { read_adc(ADC_START_ONLY); enable_interrupts(INT_AD); adc_overflows = 0; } break; case DELAY: if(!(timer_overflows)) { // use overflows for long delays, timer for short delays output_high(PIN_A2); // flash trigger output state = PULSE_OUT; set_timer1(SHORT_DELAY); // ~15ms trigger out } else { if(timer_overflows > 0) { timer_overflows--; } } break; case PULSE_OUT: output_low(PIN_A2); if (input(PIN_C5) == 0) { // blanking if(timer_overflows++ > BLANK_INTERVAL) { state = BLANK; } if(!(timer_overflows % 5)) { // blink while blanked ~6 Hz rate output_toggle(PIN_C3); } } else { // no blanking, restart after set_timer1(SHORT_DELAY); // a short delay, ~5ms blanking state = BLANK; } break; case BLANK: state = IDLE; timer_overflows = 0; C1IF = 0; C2IF = 0; break; case ERROR: if(!(timer_overflows++ % 20)) { output_toggle(PIN_C3); // this is a slower ~2Hz blink rate timer_overflows = 0; } break; default: state = ERROR; break; } return; } void init_app(void) { // configure i/o's set_tris_a(~0x04); // PIN_A2 is output, rest inputs -- see page 207 in the CCS book for the set_tris_x routine set_tris_c(~0x08); // port c pin_C3(LED) is output, rest inputs port_a_pullups(0x22); // port A pullups on PIN_A1, PIN_A5 output_high(PIN_C3); // LED ON output_low(PIN_A2); // flash trigger output OFF // configure adc setup_adc_ports(SAN3); // PIN_A4 setup_adc(ADC_CLOCK_DIV_64); // see 9.1.3 in PIC16F616 datasheet VCFG = 0; set_adc_channel(3); // this corresponds to SAN3 from what I can tell timer_overflows = 0; adc_overflows = 0; flash_delay = 128; // initial value before reading A/D // configure comparators -- for now, the comparator outputs are copied to external pins // setup_comparator(CP1_C2_A0 | CP2_C1_C0 | CP1_OUT_ON_A2 | CP2_OUT_ON_C4 ); // output comparator value on pins A2, C4 setup_comparator(CP1_C2_A0 | CP1_INVERT | CP2_C1_C0 | CP2_INVERT); // do not use output pins for comparators // configure timer setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); // overflows every 16 ms = 2^16/(4 MHz / 1) T1ACS = 1; // sets timer clock to Fosc (T1ACS = 0 for Fosc/4) // initialize interrupts state = IDLE; set_timer1(0); clear_interrupt(INT_TIMER1); clear_interrupt(INT_AD); enable_interrupts(GLOBAL); enable_interrupts(INT_TIMER1); return; } void main(void) { while(1) { init_app(); while(!(C1OUT || C2OUT)) // busy wait for comparator trigger ; if(zero_delay) { // zero delay is about 500 ns for instruction cycles + comparator latency (?) #pragma use fast_io(A) // uses pins without changing port direction bits first, must setup port prior with tris_a output_high(PIN_A2); // output trigger high disable_interrupts(INT_AD); set_timer1(SHORT_DELAY); // short delay for trigger out duration ~2 ms state = PULSE_OUT; } else { disable_interrupts(INT_AD); if(input(PIN_C4)) { // long programmed delay timer_overflows = ((flash_delay - ZERO_LATENCY + 1) >> 3) + 1; // set long delay 16 ms .. 512 ms } else { // short programmed delay set_timer1(~((flash_delay - ZERO_LATENCY + 1) << 8)); // set short delay 1 ms .. 16 ms timer_overflows = 0; } state = DELAY; } output_low(PIN_C3); // LED Off at trigger while(state != IDLE) ; output_high(PIN_C3); // LED back On waiting for trigger } }