ucl 2.0 # Copyright (c) 2005 by Wayne C. Gramlich # All rights reserved. library $pic16f688 library clock20mhz library $uart constant $eusart_clock = clock_rate constant $eusart_factor = 4 library $eusart configure fosc=hs package pdip pin 1 = power_supply pin 2 = osc1 pin 3 = ra4_in, name=io1, mask=io1_mask, bit=io1_bit pin 4 = ra3_nc, name=nc1 pin 5 = rx, name=rx, bit=rx_bit pin 6 = tx, name=tx, bit=tx_bit pin 7 = rc3_in, name=io7, mask=io7_mask, bit=io7_bit pin 8 = rc2_in, name=io6, mask=io6_mask, bit=io6_bit pin 9 = rc1_in, name=io5, mask=io5_mask, bit=io5_bit pin 10 = rc0_in, name=io4, mask=io4_mask, bit=io4_bit pin 11 = ra2_in, name=io3, mask=io3_mask, bit=io3_bit pin 12 = ra1_in, name=io2, mask=io2_mask, bit=io2_bit pin 13 = ra0_in, name=io0, mask=io0_mask, bit=io0_bit pin 14 = ground global module_address byte global echo_discard bit global rx9d bit global id_index byte origin 0 procedure main arguments_none returns_nothing local command byte local transmit bit local result byte local mode byte module_address := 2 echo_discard := $true # Warm up the UART: $trisc@5 := $true $trisc@4 := $true $txsta := 0 $tx9 := $true #$tx9 := $false $txen := $true $brgh := $true $rcsta := 0 $spen := $true $rx9 := $true #$rx9 := $false $cren := $true #$adden := $true $adden := $false $baudctl := 0 $brg16 := $true mode := 0 id_index := 0 #$spbrg := $eusart_19200_low #$spbrgh := $eusart_19200_high #$spbrg := $eusart_115200_low #$spbrgh := $eusart_115200_high #$spbrg := $eusart_230400_low #$spbrgh := $eusart_230400_high #$spbrg := $eusart_406800_low #$spbrgh := $eusart_406800_high $spbrg := $eusart_625000_low $spbrgh := $eusart_625000_high #$spbrg := $eusart_833333_low #$spbrgh := $eusart_833333_high loop_forever #command := $uart_byte_get() transmit := $false rx9d := $false while !$rcif do_nothing if $rx9d rx9d := $true command := $rcreg if rx9d # We have an address bit: if command = module_address # We have a match: $adden := $false result := 0x5a transmit := $true else # We need to disable non-address reception: $adden := $true mode := 0 else # We have a command: switch mode case 0 # Basic instruction decoding: switch command >> 6 case 0 # 00xx xxxx: switch (command >> 3) & 7 case_maximum 7 case 0 # 0000 0xxx: switch command & 7 case 0 # 0000 0000 (Digital8_Read): result := digital_read() transmit := $true case 1 # 0000 0001 (Digital8_Write): result := digital_read() transmit := $true mode := 1 case 2 # 0000 0010 (Direction_Read): result := direction_read() transmit := $true case 3 # 0000 0011 (Direction_Set): mode := 2 result := 0 transmit := $true case 4 # 0000 0100 (Analog_Read): result := analog_read() transmit := $true case 5 # 0000 0100 (Analog_Set): mode := 3 result := 0 transmit := $true case_maximum 7 case 2 # 0001 0ccc (Analog8_Read): do_nothing case 3 # 0001 1ccc (Analog10_Read): do_nothing case 4, 5 # 0010 dddd (Low_Set): result := digital_read() transmit := $true call digital_set(result & 0xf0 | command & 0xf) case 6, 7 # 0011 dddd (High_Set): result := digital_read() transmit := $true call digital_set(result & 0xf | (command & 0xf) << 4) case 3 # 11xx xxxx: switch (command >> 3) & 7 case 7 # 1111 1xxx: switch command & 7 case 4 # 1111 1100 (Address_Set) case 5 # 1111 1101 (Id_Next) transmit := $true result := 0 if id_index < id.size result := id[id_index] id_index := id_index + 1 #result := id_index case 6 # 1111 1110 (Id_Start) id_index := 0 result := 0 transmit := $true case 7 # 1111 1111 (Deselect): result := 0 transmit := $true $adden := $true case 1 # Digital8Write call digital_set(command) result := digital_read() transmit := $true mode := 0 case 2 # Direction_Set: call direction_set(command) result := command transmit := $true mode := 0 case 3 # Analog_Set: call analog_set(command) result := 0 transmit := $true mode := 0 #loop_exactly 10 # delay 200 # do_nothing if transmit call $uart_byte_put(result) # Dispose of echoed command in buffer: call $uart_byte_get() string id = "\16,0,3,1,3,12\Midimotor2-A\7\Gramson" procedure analog_read arguments_none returns byte # This procedure will return the analog selection bits. local analog byte analog := 0 if $ansel@0 analog@0 := $true if $ansel@1 analog@1 := $true if $ansel@2 analog@2 := $true if $ansel@3 analog@3 := $true if $ansel@4 analog@4 := $true if $ansel@5 analog@5 := $true if $ansel@6 analog@6 := $true if $ansel@7 analog@7 := $true return analog procedure analog_set argument analog byte returns_nothing # This procedure will set the analog inputs to be equal to {analog}. if analog@0 $ansel@0 := $true if analog@1 $ansel@1 := $true if analog@2 $ansel@2 := $true if analog@3 $ansel@3 := $true if analog@4 $ansel@4 := $true if analog@5 $ansel@5 := $true if analog@6 $ansel@6 := $true if analog@7 $ansel@7 := $true procedure digital_read arguments_none returns byte # This procedure will return the digital bits corresponding to # the 8 digital data inputs. local ra byte local rc byte local digital byte ra := $porta rc := $portc digital := 0 if ra@io0_bit digital@0 := $true if ra@io1_bit digital@1 := $true if ra@io2_bit digital@2 := $true if ra@io3_bit digital@3 := $true if rc@io4_bit digital@4 := $true if rc@io5_bit digital@5 := $true if rc@io6_bit digital@6 := $true if rc@io7_bit digital@7 := $true return digital procedure digital_set argument digital byte returns_nothing # This procedure will set the digital outputs to be equal to {digital}. local ra byte local rc byte ra := 0 rc := 0 if digital@0 ra@io0_bit := $true if digital@1 ra@io1_bit := $true if digital@2 ra@io2_bit := $true if digital@3 ra@io3_bit := $true if digital@4 rc@io4_bit := $true if digital@5 rc@io5_bit := $true if digital@6 rc@io6_bit := $true if digital@7 rc@io7_bit := $true $porta := ra $portc := rc procedure direction_read arguments_none returns byte # This procedure will return the digital bits corresponding to # the 8 digital data inputs. local trisa byte local trisc byte local direction byte direction := 0 # Get all data into data bank 0: trisa := $trisa trisc := $trisc if trisa@io0_bit direction@0 := $true if trisa@io1_bit direction@1 := $true if trisa@io2_bit direction@2 := $true if trisa@io3_bit direction@3 := $true if trisc@io4_bit direction@4 := $true if trisc@io5_bit direction@5 := $true if trisc@io6_bit direction@6 := $true if trisc@io7_bit direction@7 := $true return direction procedure direction_set argument direction byte returns_nothing # This procedure will set the direction outputs to be equal to {direction}. local trisa byte local trisc byte trisa := 0xc0 trisc := 0xc0 if direction@0 trisa@io0_bit := $true if direction@1 trisa@io1_bit := $true if direction@2 trisa@io2_bit := $true if direction@3 trisa@io3_bit := $true if direction@4 trisc@io4_bit := $true if direction@5 trisc@io5_bit := $true if direction@6 trisc@io6_bit := $true if direction@7 trisc@io7_bit := $true trisc@rx_bit := $true trisc@tx_bit := $true $trisa := trisa $trisc := trisc #procedure byte_put # argument response byte # returns_nothing # # # This procedure will send {response} back to the requestor. # # echo_discard := $true # while !$txif # do_nothing # $tx9d := $false # $txreg := response # # #procedure byte_get # arguments_none # returns byte # # # This procedure returns the next byte from the bus that is # # directed to this module. This procedure handles all address # # change (9th bit set) commands that come in. Thus, any byte # # returned from this procedure is a command byte that is directed # # at this module. # # local address byte # # # Keep processing bytes until we've got a command byte for us: # loop_forever # # Wait for a 9-bit "byte": # while !$rcif # do_nothing # if $rx9d # # We have an address byte; read the address: # if $rcreg = module_address # # We have been selected; start receiving all bytes: # $adden := $false # # Send a null byte to indicate that we alive and well: # $tx9d := $false # $txreg := 0 # echo_discard := $true # else # # We have a command or echo byte: # if echo_discard # # We have an echo: # echo_discard := $false # $fsr := $rcreg # else # # We have a real command: # return $rcreg