# ############################################################################# # # Copyright (c) 2000-2004 by Wayne C. Gramlich & William T. Benson. # All rights reserved. # # This is the code that implements the IREdge4 RoboBrick. Basically # it just waits for commands that come in at 2400 baud and responds # to them. See # # http://web.gramlich.net/projects/robobricks/iredge4/index.html # # for more details. # # ############################################################################# library $pic16f676 library clock4mhz library bit_bang 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 global analogs[analogs_size] array[byte] global thresholds_low[analogs_size] array[byte] global thresholds_high[analogs_size] array[byte] global delay_counter byte global channel byte global glitch byte global id_index byte global debug_character byte global debug_phase byte global debug_counter byte global debug_next bit constant vars_size = 17 global vars[vars_size] byte bind threshold_trim_pot = vars[0] bind inputs = vars[1] bind complement = vars[2] bind command = vars[3] bind last_sent = vars[4] bind last_received =vars[5] bind raw_inputs = vars[6] bind interrupt_bits = vars[7] bind falling = vars[8] bind high = vars[9] bind low = vars[10] bind raising = vars[11] bind threshold_enables = vars[12] bind command_previous = vars[13] bind command_last = vars[14] bind sent_previous = vars[15] bind sent_last = vars[16] 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 reset() # Set the direction: loop_forever # Wait for a command: command := byte_get() # Dispatch on command: switch command >> 6 case 0 # Command = 00xx xxxx: switch command >> 3 case 0 # Command = 0000 0xxx: switch command & 7 case 0, 1, 2, 3 # Read Pin (Command = 0000 00bb): call byte_put(analogs[command]) case 4 # Read Binary Values (Command = 0000 0100): call byte_put(inputs) case 5 # Read Raw Binary (Command = 0000 0101): call byte_put(raw_inputs) case 6 # Read Threshold Enables (Command = 0000 0110): call byte_put(threshold_enables) case 7 # Reset (Command = 0000 0111): call reset() case 1 # Command = 0000 1xxx: switch command & 7 case 0 # Read Complement Mask(Command = 0000 1000): call byte_put(complement) case 1 # Read High Mask (Command = 0000 1001): call byte_put(high) case 2 # Read Low Mask (Command = 0000 1010): call byte_put(low) case 3 # Read Raising Mask (Command = 0000 1011): call byte_put(raising) case 4 # Read Falling Mask (Command = 0000 1100): call byte_put(falling) case 5, 6, 7 # Undefined command: do_nothing case 2, 3 # Command = 0001 xxxx: bit := command & 3 switch (command >> 2) & 3 case 0 # Read High Threshold (Command = 0001 00bb): call byte_put(thresholds_high[bit]) case 1 # Read Low Threshold (Command = 0001 01bb): call byte_put(thresholds_low[bit]) case 2 # Set High Threshold (Command = 0001 10bb): thresholds_high[bit] := byte_get() case 3 # Set Low Threshold (Command = 0001 11bb): thresholds_low[bit] := byte_get() case 4, 5 # Set Complement Mask (Command = 0010 cccc): complement := command & io_mask case 6, 7 do_nothing case 1 # Command = 01xx xxxx: temporary := command & io_mask switch (command >> 4) & 3 case 0 # Set High Mask (Command = 0100 hhhh): high := temporary case 1 # Set Low Mask (Command = 0101 llll): low := temporary case 2 # Set Raising Mask (Command = 0110 rrrr): raising := temporary case 3 # Set Falling Mask (Command = 0111 ffff): falling := temporary case 2 # Do nothing (Command = 10xx xxxx): switch (command >> 3) & 7 case 0, 1 # Set Threshold Enables (1000 eeee): threshold_enables := command & 0xf case 2, 3, 4, 5, 6, 7 # Others: do_nothing case 3 # Command = 11xx xxxx: switch (command >> 3) & 7 case 0, 1, 2, 3, 4 # Command = 1100 xxxx or 1110 0xxx: do_nothing case 5 # Read Interrupt Bits (Command = 1110 1111): if (command & 7) = 7 # Return Interrupt Bits: call byte_put(interrupt_bits) case 6 # Shared Interrupt commands (Command = 1111 0xxx): switch command & 7 case 0, 1, 2, 3 # Set interrupt bits (Command = 1111 10ep): interrupt_enable := command@1 interrupt_pending := command@0 case 4, 5 # Set Interrupt Pending (Command = 1111 110p): interrupt_pending := command@0 case 6, 7 # Set Interrupt Enable (Command = 1110 111e): interrupt_enable := command@0 case 7 # Shared commands (Command = 1111 1xxx): switch command & 7 case 0 # Clock Decrement (Command = 1111 1000): $osccal := $osccal - $osccal_lsb case 1 # Clock Increment (Command = 1111 1001): $osccal := $osccal + $osccal_lsb case 2 # Clock Read (Command = 1111 1010): call byte_put($osccal) case 3 # Clock Pulse (Command = 1111 1011): call byte_put(0) case 4 # ID Next (Command = 1111 1100): call byte_put(id[id_index]) id_index := id_index + 1 if id_index >= id.size id_index := 0 case 5 # ID Reset (Command = 1111 1101): id_index := 0 case 6 # Glitch Read (Command = 1111 1110): call byte_put(glitch) glitch := 0 case 7 # Glitch (Command = 1111 1111): 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 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 #ansel := 0 #ans0 := 1 #ans1 := 1 #ans2 := 1 #ans4 := 1 #ans5 := 1 $adsel := (1 | 2 | 4 | 16 | 32) channel := 0 complement := 0 command := 0 debug_phase := 0 debug_counter := 0 delay_counter := 0 falling := 0 glitch := 0 high := 0 id_index := 0 interrupt_bits := 0 last_received := 0 last_sent := 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: debug_next := 0 serial_out := 1 debug_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\"