;********************************************************************** ; Filename: sigmod.asm * ; Date: 2004-01-06 * ; File Version: 1.0 * ; * ; Author: Per Zander * ;********************************************************************** ; Files required: p16c505.inc * ;********************************************************************** ; ; Description: ; ; General: ; ; This is a program for model railroad signal control via a 9600 baud ; serial link. The program supports soft light change via a table at ; the end of the program. ; ; Serial protocol: ; ; 9600 baud, 8 bits, no parity, no handshaking. Data is inverted, so that ; an rs232 signal can be used directly (after appropriate clamping). ; ; Signal control packet: ; ; A signal control packet consists of two or more bytes. ; First byte: ; ; 7 6 5 4 3 2 1 0 ; _______________________________ ; | 0 | Device address | ; |___|___________________________| ; ; Second and further byte: ; ; 7 6 5 4 3 2 1 0 ; _______________________________ ; | 1 | 0 | c | 0 | h |Port number| ; |___|___|___|___|___|___________| ; ; A correct packet addressed to the device, and with the c bit set, ; activates the selected port/ports. If the c bit is cleared, the ; selected port is deactivated. ; ; The h field is used to select the upper or lower half of a signal ; module with 16 ports. ;********************************************************************** ;*---------- Device address definition. ----------* my_addr EQU 0x00 ; Change for each unit. MSB should be 0. hi_addr EQU 0x80 ; Should be 1000h000 (bin). ;*---------- Device select. ----------* list p=16c505 ; List directive to define processor #include ; Processor specific variable definitions ;*---------- Configuration specification. ----------* __CONFIG _CP_OFF & _WDT_OFF & _MCLRE_OFF & _XT_OSC ;*---------- Port definitions. ----------* din EQU 0x05 ; Data in on RC5 led0 EQU 0x00 ; LED 0 on RB0 led1 EQU 0x01 ; LED 1 on RB1 led2 EQU 0x02 ; LED 2 on RB2 led3 EQU 0x00 ; LED 3 on RC0 led4 EQU 0x01 ; LED 4 on RC1 led5 EQU 0x02 ; LED 5 on RC2 led6 EQU 0x04 ; LED 6 on RC4 led7 EQU 0x03 ; LED 7 on RC3 ;*---------- Variable definitions. ----------* ; For receiver: ser_st EQU 0x08 ; Serial state pointer. rec_d EQU 0x09 ; Receive data shift register. new_d EQU 0x0A ; Received_data. ; For command handler: cmd_st EQU 0x0B ; For signal output: sig_msk EQU 0x0C ; Mask for outputs. wrap_c EQU 0x0D ; Counter. led_st EQU 0x0E led0_c EQU 0x10 ; Counter values led1_c EQU 0x11 led2_c EQU 0x12 led3_c EQU 0x13 led4_c EQU 0x14 led5_c EQU 0x15 led6_c EQU 0x16 led7_c EQU 0x17 led0_t EQU 0x18 ; Timer values. Use bank 3. led1_t EQU 0x19 led2_t EQU 0x1A led3_t EQU 0x1B led4_t EQU 0x1C led5_t EQU 0x1D led6_t EQU 0x1E led7_t EQU 0x1F ; General: cmd_fl EQU 0x0F ;*---------- Program flag definitions. ----------* dav EQU 0x00 ; Data available flag from receiver. dend EQU 0x01 ; Serial receiver end of byte flag. bs EQU 0x02 ; Select bank for counter. ;*---------- Constant definitions. ----------* led_srl EQU 0x09 ; Length of LED subroutines. ;********************************************************************** ;* The program starts here after reset. ;********************************************************************** ORG 0x3FF ; Processor reset vector. movlw 0x38 ; Osc. cal. value. ORG 0x000 ; Coding begins here. startofprog movwf OSCCAL ; Update register with factory cal value. clrf FSR ; Ensure FSR register points to Bank0. goto init_code ; Jump over a few words to enable ; reprogramming. ORG 0x006 ;***************************************************** ;*---------- Serial receive state machine. ----------* ;***************************************************** ;*---------- Jump to current state. ----------* serial_proc movf ser_st, W ; t2 movwf PCL ; t3, t4 ;*---------- Idle state. Must see stop bit to leave it. ----------* ser_idle btfss PORTC, din ; t5 movlw wait_start movwf ser_st nop retlw led_srl ; t9, t10 ;*---------- Wait for start bit. ----------* wait_start btfsc PORTC, din movlw sample_data movwf ser_st bcf cmd_fl, dend ; Clear data end flag. retlw led_srl ;*---------- Sample data in. ----------* sample_data btfsc PORTC, din bcf rec_d, 7 ; Clear data bit if input is logic 0. movlw get_end_bit movwf ser_st retlw led_srl ;*---------- Wait for next bit. ----------* get_end_bit btfss rec_d, 0 bsf cmd_fl, dend movlw shift_data movwf ser_st retlw led_srl ;*---------- Shift data in. ----------* shift_data rrf rec_d, F ; Shift received data. bsf rec_d, 7 ; Preset current bit to 7. movlw test_bitnr movwf ser_st retlw led_srl ;*---------- Check if it is the last bit. ----------* test_bitnr movlw sample_data btfsc cmd_fl, dend movlw sample_last ; Last bit if start bit is in rec_bit. movwf ser_st retlw led_srl ;*---------- Sample last bit. ----------* sample_last btfsc PORTC, din bcf rec_d, 7 ; Clear data bit if input is 0. movlw wait_end ser_return movwf ser_st retlw led_srl ;*---------- Wait before sampling stop bit. ----------* wait_end movlw set_new_data goto ser_return ;*---------- Move new data. ----------* set_new_data movf rec_d, W movwf new_d movlw preset_rec movwf ser_st retlw led_srl ;*---------- Set receive data to all 1's. ----------* preset_rec movlw 0xFF movwf rec_d movlw sample_stop movwf ser_st retlw led_srl ;*---------- Sample stop bit. ----------* sample_stop btfss PORTC, din bsf cmd_fl, dav ; Set dav if correct stop bit. movlw ser_idle movwf ser_st retlw led_srl ;**************************************************** ;*---------- Timer handler state machine. ----------* ;**************************************************** led0_st movf led0_t, W ; t14 bsf STATUS, PA0 ; t15 call led_table ; t16, t17 bcf STATUS, PA0 ; t22 btfss cmd_fl, bs ; t23 bcf FSR, 6 ; t24 movwf led0_c ; t25 call serial_proc ; Ser call 3 goto continue_loop ; t11, t12 led0_cst btfss cmd_fl, bs ; t14 bcf FSR, 6 btfsc led0_t, 6 incf led0_t, F btfss led0_t, 6 decf led0_t, F btfsc led0_t, 7 incf led0_t, F goto continue_short ; t22, t23 led1_st movf led1_t, W ; t14 bsf STATUS, PA0 ; t15 call led_table ; t16, t17 bcf STATUS, PA0 ; t22 btfss cmd_fl, bs ; t23 bcf FSR, 6 ; t24 movwf led1_c ; t25 call serial_proc ; Ser call 3 goto continue_loop ; t17, t18 led1_cst btfss cmd_fl, bs ; t14 bcf FSR, 6 btfsc led1_t, 6 incf led1_t, F btfss led1_t, 6 decf led1_t, F btfsc led1_t, 7 incf led1_t, F goto continue_short ; t22, t23 led2_st movf led2_t, W ; t14 bsf STATUS, PA0 ; t15 call led_table ; t16, t17 bcf STATUS, PA0 ; t22 btfss cmd_fl, bs ; t23 bcf FSR, 6 ; t24 movwf led2_c ; t25 call serial_proc ; Ser call 3 goto continue_loop ; t17, t18 led2_cst btfss cmd_fl, bs ; t14 bcf FSR, 6 btfsc led2_t, 6 incf led2_t, F btfss led2_t, 6 decf led2_t, F btfsc led2_t, 7 incf led2_t, F goto continue_short ; t22, t23 led3_st movf led3_t, W ; t14 bsf STATUS, PA0 ; t15 call led_table ; t16, t17 bcf STATUS, PA0 ; t22 btfss cmd_fl, bs ; t23 bcf FSR, 6 ; t24 movwf led3_c ; t25 call serial_proc ; Ser call 3 goto continue_loop ; t17, t18 led3_cst btfss cmd_fl, bs ; t14 bcf FSR, 6 btfsc led3_t, 6 incf led3_t, F btfss led3_t, 6 decf led3_t, F btfsc led3_t, 7 incf led3_t, F goto continue_short ; t22, t23 led4_st movf led4_t, W ; t14 bsf STATUS, PA0 ; t15 call led_table ; t16, t17 bcf STATUS, PA0 ; t22 btfss cmd_fl, bs ; t23 bcf FSR, 6 ; t24 movwf led4_c ; t25 call serial_proc ; Ser call 3 goto continue_loop ; t17, t18 led4_cst btfss cmd_fl, bs ; t14 bcf FSR, 6 btfsc led4_t, 6 incf led4_t, F btfss led4_t, 6 decf led4_t, F btfsc led4_t, 7 incf led4_t, F goto continue_short ; t22, t23 led5_st movf led5_t, W ; t14 bsf STATUS, PA0 ; t15 call led_table ; t16, t17 bcf STATUS, PA0 ; t22 btfss cmd_fl, bs ; t23 bcf FSR, 6 ; t24 movwf led5_c ; t25 call serial_proc ; Ser call 3 goto continue_loop ; t17, t18 led5_cst btfss cmd_fl, bs ; t14 bcf FSR, 6 btfsc led5_t, 6 incf led5_t, F btfss led5_t, 6 decf led5_t, F btfsc led5_t, 7 incf led5_t, F goto continue_short ; t22, t23 led6_st movf led6_t, W ; t14 bsf STATUS, PA0 ; t15 call led_table ; t16, t17 bcf STATUS, PA0 ; t22 btfss cmd_fl, bs ; t23 bcf FSR, 6 ; t24 movwf led6_c ; t25 call serial_proc ; Ser call 3 goto continue_loop ; t17, t18 led6_cst btfss cmd_fl, bs ; t14 bcf FSR, 6 btfsc led6_t, 6 incf led6_t, F btfss led6_t, 6 decf led6_t, F btfsc led6_t, 7 incf led6_t, F goto continue_short ; t22, t23 led7_st movf led7_t, W ; t14 bsf STATUS, PA0 ; t15 call led_table ; t16, t17 bcf STATUS, PA0 ; t22 btfss cmd_fl, bs ; t23 bcf FSR, 6 ; t24 movwf led7_c ; t25 call serial_proc ; Ser call 3 goto continue_loop ; t11, t12 led7_cst btfss cmd_fl, bs ; t14 bcf FSR, 6 btfsc led7_t, 6 incf led7_t, F btfss led7_t, 6 decf led7_t, F btfsc led7_t, 7 incf led7_t, F goto continue_short ; t22, t23 ;---------- LED counter idle state. ----------* led_idle_st movlw 0x04 ; t14 decfsz wrap_c, F ; goto led_no_wrap ; t16, t17 xorwf cmd_fl, F ; Toggle bs flag. movlw 0x10 ; t18 movwf wrap_c ; Re-initialize counter. movlw led0_st - led_srl led_set_state movwf led_st ; Next state - 9. goto continue_short ; t22, t23 led_no_wrap movlw led7_cst ; led_idle_st - 9. goto led_set_state ; t19, t20 ;*********************************************** ;*---------- Short delay subroutine. ----------* ;*********************************************** short_delay retlw 1 ;****************************************************** ;*---------- Command handler state machine. ----------* ;****************************************************** idle_w_dav goto idle_w_dav_c wait_dav goto wait_dav_c check_hi_addr goto check_hi_addr_c perform_cmd ;*---------- Perform the command. ----------* movlw wait_dav ; Return to wait_dav enables several LEDs ; to be controlled without giving new addr. movwf cmd_st movf new_d, W iorlw 0x78 ; Up to bank 3 ledX_t variables. movwf FSR btfsc new_d, 3 goto perform_cmd_c bsf INDF, 6 btfss new_d, 5 bcf INDF, 6 perform_cmd_e goto main_loop perform_cmd_c goto perform_cmd_e ;*---------- Idle state, wait for dav. ----------* ORG 0x100 idle_w_dav_c movlw my_addr ; t16 xorwf new_d, W ; Check for my address. movlw wait_dav ; Default next state btfsc cmd_fl, dav btfss STATUS, Z movlw idle_w_dav ; Stay if no dav or address mismatch. movwf cmd_st bcf cmd_fl, dav goto main_loop ; t24, t25 ;*---------- Address match found, wait for new dav. ----------* wait_dav_c movlw my_addr xorwf new_d, W movlw check_hi_addr btfsc cmd_fl, dav btfsc STATUS, Z movlw wait_dav ; Stay here if no dav or address match. movwf cmd_st bcf cmd_fl, dav goto main_loop ;*---------- Check high address bits. ----------* check_hi_addr_c movlw hi_addr xorwf new_d, F movlw 0xd0 andwf new_d, W ; Mask out relevant bits, and set Z flag. movlw perform_cmd btfss STATUS, Z movlw idle_w_dav ; Go to idle if there is hi addr mismatch. movwf cmd_st goto main_loop ;*********************************************** ;*---------- End of command handler. ----------* ;*********************************************** init_code movlw 0xc7 ; Internal timer clock, max prescaler. option clrf PORTB ; Clear output ports. clrf PORTC movlw 0x38 ; Set output ports to out. tris PORTB movlw 0x20 tris PORTC movlw ser_idle movwf ser_st ; Initial state of serial receiver. movlw idle_w_dav movwf cmd_st ; Initial state of command handler. movlw led7_st movwf led_st ; Initialize LED state. movlw 0x04 movwf wrap_c init_clr_loop clrf led0_t clrf led1_t clrf led2_t clrf led3_t clrf led4_t clrf led5_t clrf led6_t clrf led7_t movlw 0x80 movwf led0_c ; Clear all pulse counters. movwf led1_c movwf led2_c movwf led3_c movwf led4_c movwf led5_c movwf led6_c movwf led7_c movlw 0x20 addwf FSR, F decfsz wrap_c, F goto init_clr_loop ; Loop over all four banks. clrf cmd_fl ; Clear bs, dav and dend flags clrf sig_msk ; Clear the mask for output values. movlw 0xff movwf rec_d ; Set receiver shift register to all 1's. movlw 0x1 movwf wrap_c ; Initialize intensity counter to 1. ;****************************************** ;*---------- Main program loop. ----------* ;****************************************** main_loop call serial_proc ; Ser call 0, returns subroutine length. addwf led_st, F ; Set next state for LED control. btfsc cmd_fl, bs bcf FSR, 6 ; Select bank 1 or 3. decf led6_c, F rlf led6_c, W rlf sig_msk, F decf led7_c, F rlf led7_c, W rlf sig_msk, F decf led5_c, F rlf led5_c, W rlf sig_msk, F decf led4_c, F rlf led4_c, W rlf sig_msk, F call serial_proc ; Ser call 1. decf led3_c, F decf led2_c, F rlf led3_c, W rlf sig_msk, W movwf PORTC ; t15 rlf led2_c, W rlf sig_msk, F decf led1_c, F rlf led1_c, W rlf sig_msk, F decf led0_c, F rlf led0_c, W rlf sig_msk, W bsf FSR, 6 movwf PORTB ; t25 call serial_proc ; Ser call 2. ;*---------- Jump to current LED intensity control state. ----------* movf led_st, W movwf PCL ; t12, t13, jump to LED state. ;*---------- Continue the main loop after executing LED state. ----------* continue_short btfss cmd_fl, bs bcf FSR, 6 call serial_proc ; Ser call 3. goto continue_loop continue_loop movlw 0x40 xorwf FSR, F ; Select bank 1 or 3. decf led6_c, F rlf led6_c, W rlf sig_msk, F decf led7_c, F rlf led7_c, W rlf sig_msk, F decf led5_c, F rlf led5_c, W rlf sig_msk, F decf led4_c, F decf led3_c, F call serial_proc ; Ser call 4, returns 1. rlf led4_c, W rlf sig_msk, F rlf led3_c, W rlf sig_msk, W movwf PORTC ; t15 decf led2_c, F rlf led2_c, W rlf sig_msk, F decf led1_c, F rlf led1_c, W rlf sig_msk, F decf led0_c, F rlf led0_c, W rlf sig_msk, W movwf PORTB ; t25 call serial_proc ; Ser call 5. ;*---------- Jump to current command handler state. ----------* command_proc movf cmd_st, W ; t11 movwf PCL ; t12, t13 ;*----- The command procedure ends with a jump to main_loop. -----* ;****************************************** ;*---------- LED intensity table. --------* ;****************************************** ORG 0x200 ; Upper program bank led_table addwf PCL, F ; t18, t19 ;*----- Decreasing intensity table. ----------* retlw 0x80 ; t20, t21 retlw 0x81 ; All values are intensity + 0x80. retlw 0x80 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x81 retlw 0x80 retlw 0x81 retlw 0x81 retlw 0x81 retlw 0x81 retlw 0x81 retlw 0x81 retlw 0x82 retlw 0x82 retlw 0x82 retlw 0x83 retlw 0x83 retlw 0x83 retlw 0x84 retlw 0x84 retlw 0x85 retlw 0x85 retlw 0x86 retlw 0x87 retlw 0x88 retlw 0x8a retlw 0x8b retlw 0x8d retlw 0x8f retlw 0x91 retlw 0x93 retlw 0x96 retlw 0x9a retlw 0x9e retlw 0xa1 retlw 0xa6 retlw 0xab retlw 0xb0 retlw 0xc0 ;*----- Increasing intensity table. -----* retlw 0x80 retlw 0x81 retlw 0x81 retlw 0x81 retlw 0x81 retlw 0x81 retlw 0x82 retlw 0x82 retlw 0x82 retlw 0x82 retlw 0x83 retlw 0x83 retlw 0x83 retlw 0x84 retlw 0x84 retlw 0x84 retlw 0x85 retlw 0x85 retlw 0x85 retlw 0x86 retlw 0x86 retlw 0x87 retlw 0x87 retlw 1x87 retlw 0x88 retlw 0x89 retlw 0x89 retlw 0x8a retlw 0x8b retlw 0x8c retlw 0x8c retlw 0x8d retlw 0x8e retlw 0x8f retlw 0x91 retlw 0x92 retlw 0x94 retlw 0x96 retlw 0x97 retlw 0x99 retlw 0x9b retlw 0x9e retlw 0xa0 retlw 0xa3 retlw 0xa6 retlw 0xa9 retlw 0xac retlw 0xae retlw 0xb0 retlw 0xb2 retlw 0xb4 retlw 0xb6 retlw 0xb7 retlw 0xb9 retlw 0xba retlw 0xbb retlw 0xbc retlw 0xbd retlw 0xbd retlw 0xbe retlw 0xbf retlw 0xbf retlw 0xbf retlw 0xc0 ;*----- The End. -----* endofprog END ; directive 'end of program'