# ############################################################################# # # Copyright (c) 2000-2004 by Wayne C. Gramlich and Bill Benson # All rights reserved. # # This is the code that implements the LED10 RoboBrick. Basically # it just waits for commands that come in at 2400 baud and responds # to them. See # # http://web.gramlich.net/projects/robobricks/led10/index.html # # for more details. # # ############################################################################# library $pic16f630 library clock4mhz library bit_bang package pdip pin 1 = power_supply pin 2 = ra5_out, name = led0 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 = led5 pin 9 = rc1_out, name = led6 pin 10 = rc0_out, name = led7 pin 11 = ra2_out, name = serial_out pin 12 = ra1_out, name = led8 pin 13 = ra0_out, name = led9 pin 14 = ground constant leds_count = 10 global leds_mask_low byte global leds_mask_high byte global blink_masks[leds_count] array[byte] global command_previous byte global command_last byte global sent_previous byte global sent_last byte procedure main arguments_none returns_nothing local ledx byte local command byte local data byte local glitch byte local index byte local mask byte local rate byte local result byte local temp byte # Initialize blink_masks: index := 0 loop_exactly leds_count blink_masks[index - 1] := 0xff index := index + 1 # Initialize remaining registers: glitch := 0 index := 0 leds_mask_low := 0 leds_mask_high := 0 # Process commands: loop_forever # Wait for command: command := byte_get() # Dispatch on command: switch command >> 6 # xx = 00: write upper and write lower commands case 0 # (Command = 00xx xxxx): if command@5 # Write Upper (Command = 001a bcde): leds_mask_high := command & 0x1f else # Write Lower (Command = 000a bcde): leds_mask_low := command # xx = 01: Bit operations - clear, set, toggle & read case 1 # Bit commands:(Command = 01cc bbbb): ledx := command & 0xf data := leds_mask_low if ledx >= 5 ledx := ledx - 5 data := leds_mask_high # Compute the mask: mask := 1 while ledx != 0 mask := mask << 1 ledx := ledx - 1 ledx := command & 0xf switch (command >> 4) & 3 case 0 # Bit Clear (Command = 0100 bbbb): data := data & (0xff ^ mask) case 1 # Bit Set (Command = 0100 bbbb): data := data | mask case 2 # Bit Toggle (Command = 0100 bbbb): data := data ^ mask case 3 # Bit Read (Command = 0100 bbbb): result := (mask_to_bit(blink_masks[ledx]) ^ 7) << 5 if data & mask != 0 result := result + 1 call byte_put(result) # Stuff the data back: if ledx < 5 leds_mask_low := data else leds_mask_high := data case 2 # Do nothing (Command = 10xx xxx): switch (command >> 4) & 3 case 0 # Command = 1000 xxxx: switch (command >> 2) & 3 case 0 # Command = 1000 00xx: switch command & 3 case 0 # Read All (Command = 1000 0000): call byte_put(leds_mask_high) call byte_put(leds_mask_low) case 1 # Read Lower (Command = 1000 0001): call byte_put(leds_mask_low) # xx = 10: read-all, lower, upper; # blink rate; inc/dec leds;pwr mode case 2 # Read Upper (Command = 1000 0010): call byte_put(leds_mask_high) # xx = 11: shared commands case 3 # Blink Rate Set (Command = 1000 0011): command := byte_get() ledx := command & 0xf if ledx >= 10 ledx := 0 blink_masks[ledx] := bit_to_mask[command >> 5] case 1, 2, 3 do_nothing case 1 # Increment LED's (Command = 1001 bbbb): ledx := command & 0xf mask := 1 if ledx < 5 while ledx != 0 mask := mask << 1 ledx := ledx - 1 leds_mask_low := leds_mask_low + mask if leds_mask_low@5 leds_mask_low := leds_mask_low & 0x1f leds_mask_high := leds_mask_high + 1 else ledx := ledx - 5 while ledx != 0 mask := mask << 1 ledx := ledx - 1 leds_mask_high := leds_mask_high + mask leds_mask_high := leds_mask_high & 0x1f case 2 # Decrement LED's (Command = 1010 bbbb): ledx := command & 0xf mask := 1 if ledx < 5 while ledx != 0 mask := mask << 1 ledx := ledx -1 leds_mask_low := leds_mask_low - mask if leds_mask_low@5 leds_mask_low := leds_mask_low & 0x1f leds_mask_high := leds_mask_high - 1 else ledx := ledx - 5 while ledx != 0 mask := mask << 1 ledx := ledx -1 leds_mask_high := leds_mask_high - mask leds_mask_high := leds_mask_high & 0x1f case 3 # Power Level Set (Command = 1011 llll): ledx := command & 0xf mask := 0 if ledx <= 5 while ledx != 0 mask := (mask << 1) | 1 ledx := ledx - 1 leds_mask_low := mask leds_mask_high := 0 else ledx := ledx - 5 while ledx != 0 mask := mask << 1 | 1 ledx := ledx - 1 leds_mask_low := 0x1f leds_mask_high := mask & 0x1f case 3 # (Command = 11xx xxxx): if (command >> 3) & 7 = 7 # 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): temp := 0 if index < id.size temp := id[index] index := index + 1 call byte_put(temp) case 5 # ID Reset (Command = 1111 1101): 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 mask_to_bit argument mask byte returns byte local bit byte if mask = 0xff return 7 bit := 0 mask := mask | 0x80 while !(mask@0) mask := mask >> 1 bit := bit + 1 return bit procedure delay arguments_none returns_nothing exact_delay delay_instructions # This procedure delays 1/3 of a bit. local blink byte local high byte local low byte # This procedure is called 7200 times a second. We want to # slow the fastest blink rate down to something more manageable, # like 4 times a second. # Kick the dog: watch_dog_reset # Slow the blink rate down: low := low + 1 if $z high := high + 1 # 7200/256 ~= 28; for fastest blink rate: # 28/7 = 4 => 4 blinks a second, or # 28/4 = 7 => 7 blinks a second if high > 2 high := 0 blink := blink + 1 # We never let the blink mask go to all zeros because the way # we indicate that an LED is to stay on always is that we set # its blink mask to all one's. If the blink variable ever goes # to all zeros, there would be a small glitch for LED's that # are supposed to be always on. Hence we skip over a value of 0. if $z blink := blink + 1 if leds_mask_low@0 # led0 := 0 if blink & blink_masks[0] != 0 led0 := 0 else led0 := 1 else led0 := 1 if leds_mask_low@1 if blink & blink_masks[1] != 0 led1 := 0 else led1 := 1 else led1 := 1 if leds_mask_low@2 if blink & blink_masks[2] != 0 led2 := 0 else led2 := 1 else led2 := 1 if leds_mask_low@3 if blink & blink_masks[3] != 0 led3 := 0 else led3 := 1 else led3 := 1 if leds_mask_low@4 if blink & blink_masks[4] != 0 led4 := 0 else led4 := 1 else led4 := 1 if leds_mask_high@0 if blink & blink_masks[5] != 0 led5 := 0 else led5 := 1 else led5 := 1 if leds_mask_high@1 if blink & blink_masks[6] != 0 led6 := 0 else led6 := 1 else led6 := 1 if leds_mask_high@2 if blink & blink_masks[7] != 0 led7 := 0 else led7 := 1 else led7 := 1 if leds_mask_high@3 if blink & blink_masks[8] != 0 led8 := 0 else led8 := 1 else led8 := 1 if leds_mask_high@4 if blink & blink_masks[9] != 0 led9 := 0 else led9 := 1 else led9 := 1 constant zero8 = "\0,0,0,0,0,0,0,0\" constant module_name = "\6\LED10E" constant vendor_name = "\15\Gramlich&Benson" string id = "\1,0,9,0,0,0,0,0\" ~ zero8 ~ zero8 ~ module_name ~ vendor_name string bit_to_mask = "\255,64,32,16,8,4,2,1\"