ucl 1.0 # Copyright (c) 2000-2004 by Wayne C. Gramlich & William T. Benson. # All rights reserved. library $pic16f676 library clock4mhz library bit_bang library debug_port package pdip pin 1 = power_supply pin 2 = ra5_out, name = serial_out pin 3 = ra4_out, name = led1 pin 4 = ra3_in, name = serial_in pin 5 = rc5_out, name = led2 pin 6 = rc4_out, name = led3 pin 7 = rc3_out, name = led4 pin 8 = rc2_out, name = debug_out pin 9 = an5, name = in0 pin 10 = an4, name = in1 pin 11 = an2, name = cal pin 12 = an1, name = in2 pin 13 = an0, name = in3 pin 14 = ground constant analogs_size = 4 constant io_mask = 0xf constant threshold_default = 0x80 constant state_size = 16 + 12 constant state_size2 = state_size << 1 global state[state_size] array[byte] bind command_previous = state[0] bind command_last = state[1] bind sent_previous = state[2] bind sent_last = state[3] bind threshold_trim_pot = state[4] bind inputs = state[5] bind complement = state[6] bind command = state[7] bind raw_inputs = state[8] bind interrupt_bits = state[9] bind falling = state[10] bind high = state[11] bind low = state[12] bind raising = state[13] bind threshold_enables = state[14] bind thresholds_low[0] = state[16] bind thresholds_high[0] = state[20] bind analogs[0] = state[24] global delay_counter byte global channel byte global glitch byte global id_index byte bind interrupt_enable = interrupt_bits@1 bind interrupt_pending = interrupt_bits@0 procedure main arguments_none returns_nothing local bit byte local temporary byte call debug_port_reset() call reset() # Set the direction: loop_forever # Wait for a command: command := byte_get() # Dispatch on command: switch command >> 6 case 0 # 00xx xxxx: switch command >> 3 case 0 # 0000 0xxx: switch command & 7 case 0, 1, 2, 3 # 0000 00bb (Read Pin): call byte_put(analogs[command]) case 4 # 0000 01000 (Read Binary Values): call byte_put(inputs) case 5 # 0000 0101 (Read Raw Binary): call byte_put(raw_inputs) case 6 # 0000 0110 (Read Threshold Enables): call byte_put(threshold_enables) case 7 # 0000 0111 (Reset): call reset() case 1 # 0000 1xxx: switch command & 7 case 0 # 0000 1000 (Read Complement Mask): call byte_put(complement) case 1 # 0000 1001 (Read High Mask): call byte_put(high) case 2 # 0000 1010 (Read Low Mask): call byte_put(low) case 3 # 0000 1011 (Read Raising Mask): call byte_put(raising) case 4 # 0000 1100 (Read Falling Mask): call byte_put(falling) case 5, 6, 7 # 0000 111x or 0000 1101 do_nothing case 2, 3 # 0001 ccbb: bit := command & 3 switch (command >> 2) & 3 case 0 # 0001 00bb (Read High Threshold): call byte_put(thresholds_high[bit]) case 1 # 0001 01bb (Read Low Threshold): call byte_put(thresholds_low[bit]) case 2 # 0001 10bb (Set High Threshold): thresholds_high[bit] := byte_get() case 3 # 0001 11bb (Set Low Threshold): thresholds_low[bit] := byte_get() case 4, 5 # 0010 cccc (Set Complement Mask): complement := command & io_mask case 6, 7 # 0011 xxxx: do_nothing case 1 # 01cc mmmm: temporary := command & io_mask switch (command >> 4) & 3 case 0 # 0100 hhhh (Set High Mask): high := temporary case 1 # 0101 llll (Set Low Mask): low := temporary case 2 # 0110 rrrr (Set Raising Mask): raising := temporary case 3 # 0111 ffff (Set Falling Mask): falling := temporary case 2 # 10xx xxxx: switch (command >> 3) & 7 case 0, 1 # 1000 eeee (Set Threshold Enables): threshold_enables := command & 0xf case 2, 3, 4, 5, 6, 7 # 1001 xxxx or 101x xxxx: do_nothing case 3 # Command = 11xx xxxx: switch (command >> 3) & 7 case 0, 1, 2, 3, 4 # 1100 xxxx or 1110 0xxx: do_nothing case 5 # Read Interrupt Bits (Command = 1110 1111): switch command & 7 case 0, 1, 2, 3, 4, 5 # 1110 10xx or 1110 1110x: case 6 # 1110 1110 (Reset): call reset() case 7 # 1110 1111 (Return Interrupt Bits): call byte_put(interrupt_bits) case 6 # Shared Interrupt commands (Command = 1111 0xxx): switch command & 7 case 0, 1, 2, 3 # 1111 10ep (Set interrupt bits): interrupt_enable := command@1 interrupt_pending := command@0 case 4, 5 # 1111 110p (Set Interrupt Pending): interrupt_pending := command@0 case 6, 7 # 1110 111e (Set Interrupt Enable): interrupt_enable := command@0 case 7 # Shared commands (Command = 1111 1xxx): switch command & 7 case 0 # 1111 1000 (Clock Decrement): $osccal := $osccal - $osccal_lsb case 1 # 1111 1001 (Clock Increment): $osccal := $osccal + $osccal_lsb case 2 # 1111 1010 (Clock Read): call byte_put($osccal) case 3 # 1111 1011 (Clock Pulse): call byte_put(0) case 4 # 1111 1100 (ID Next): call byte_put(id[id_index]) id_index := id_index + 1 if id_index >= id.size id_index := 0 case 5 # 1111 1101 (ID Reset): id_index := 0 case 6 # 1111 1110 (Glitch Read): call byte_put(glitch) glitch := 0 case 7 # 1111 1111 (Glitch): if glitch != 0xff glitch := glitch + 1 procedure delay arguments_none returns_nothing exact_delay delay_instructions local chan byte local changed byte local current byte local hexify bit local index byte local mask byte local not_current byte local previous byte local temp byte local thresholds_index byte local high byte local low byte watch_dog_reset call debug_port_service() switch delay_counter case 0 # Perform A/D: chan := chans[channel] # Acquiring the signal takes approximately 20uS. # We'll pad that out a little to 30uS to be safe: $adcon0 := (chan << 2) | 1 delay 30 do_nothing # Getting the value takes 11 & Tad, where Tad = 2uS = 22uS. # We'll add 5uS for a little pad: $go := 1 delay 28 do_nothing # A/D result is ready: temp := 0xff - $adresh # Store the result away: if channel@2 # Deal with threshold trim pot: threshold_trim_pot := temp else analogs[channel] := temp # Next time around, do case 1: delay_counter := delay_counter + 1 case 1 # Process A/D result if !(channel@2) mask := masks[channel] temp := analogs[channel] if (temp >= thresholds_high[channel]) raw_inputs := raw_inputs | mask else_if (temp <= thresholds_low[channel]) raw_inputs := raw_inputs & (0xff ^ mask) # Bump to next channel: channel := channel + 1 if channel >= chans.size channel := 0 # Light up the LED's: inputs := raw_inputs ^ complement led1 := inputs@0 led2 := inputs@1 led3 := inputs@2 led4 := inputs@3 # Setup for interrupts: previous := current # Read the I/O port once: current := inputs ^ complement not_current := current ^ 0xf changed := current ^ previous # See about triggering the interrupt_pending flag: if (low & not_current) | (high & current) | (changed & current & raising) | (changed & not_current & falling) != 0 interrupt_pending := 1 # Send an interrupt if interrupts are enabled: if interrupt_pending && interrupt_enable # Shove serial out to low: interrupt_enable := 0 serial_out := 0 # Next time around, perform case 2: delay_counter := delay_counter + 1 case 2 # Process threshold trim pot: thresholds_index := (thresholds_index + 1) & 3 mask := masks[thresholds_index] if threshold_enables & mask != 0 low := thresholds_low[thresholds_index] high := thresholds_high[thresholds_index] if threshold_trim_pot > low low := low + 1 if high != 255 high := high + 1 else_if threshold_trim_pot < temp low := low - 1 if high != 0 high := high - 1 thresholds_low[thresholds_index] := low thresholds_high[thresholds_index] := high # Next time around, perform case 3: delay_counter := delay_counter + 1 case 3 do_nothing procedure reset arguments_none returns_nothing # This procedure will initialize all of the registers: local index byte # Initialize the A/D module: # A/D Conversion clock is Fosc/8 (Tad=2uS) and AD is on: $adcon0 := 1 $adcon1 := 0 $adcs0 := 1 $adif := 0 $adie := 0 $gie := 0 $adsel := (1 | 2 | 4 | 16 | 32) channel := 0 complement := 0 command := 0 delay_counter := 0 falling := 0 glitch := 0 high := 0 id_index := 0 interrupt_bits := 0 low := 0 raising := 0 raw_inputs := 0 # Initialize threshold vectors: index := 0 while index < 4 thresholds_high[index] := threshold_default thresholds_low[index] := threshold_default index := index + 1 # Bit resets: serial_out := 1 constant zero8 = "\0,0,0,0,0,0,0,0\" constant module_name = "\8\IREdge4C" constant vendor_name = "\13\Mondo-tronics" string id = "\1,0,25,2,0,0,0,0\" ~ zero8 ~ zero8 ~ module_name ~ vendor_name string chans = "\4,1,0,2,5\" string masks = "\1,2,4,8\"