; ****************************************************************************** ; Copyright © [01/25/1999] Scenix Semiconductor, Inc. All rights reserved. ; ;Scenix Semiconductor, Inc. assumes no responsibility or liability for ; the use of this [product, application, software, any of these products]. ; Scenix Semiconductor conveys no license, implicitly or otherwise, under ; any intellectual property rights. ; Information contained in this publication regarding (e.g.: application, ; implementation) and the like is intended through suggestion only and may ; be superseded by updates. Scenix Semiconductor makes no representation ; or warranties with respect to the accuracy or use of these information, ; or infringement of patents arising from such use or otherwise. ;****************************************************************************** ; ; Filename: bell_103_tx.src ; ; Author: Chris Fogelklou ; Applications Engineer ; Scenix Semiconductor Inc. ; ; Revision: 1.08 ; ; Date: April 16, 1999. ; ; Part: SX28AC rev. 2.5 ; ; Freq: 50Mhz ; ; Compiled using Parallax SX-Key software v1.0 ; ; Version: 1.10 ; ; Program Description: This simple program encodes an outgoing bell103 signal. ; This program only creates the answer frequencies, since it ; cannot dial out to originate. ; ; To use this program, connect the SX-DTMF-DEMO board to a phone ; line and to a PC. The communications settings are 300,N,8,1. ; Now, from a remote BELL103 modem, simply dial the modem's number. ; When you here the line ringing on the dialing modem, press a key ; in the comm window of the SX-modem-board. This should force the ; modem board off-hook and cause it to send out an answer tone for ; 3 seconds. Once the answer tone is sent, the modem board will ; begin modulating the state of the RS-232 pin onto the carrier. ; If the terminal program is set up correctly, you will be able to ; receive the sent characters on the remote modem. ; ; Revision History: 1.0 Tried for weeks to get FSK-receive to work. Finally got it ; working. ; 1.01 Tried to eliminate all unnecessary code... ; 1.04 Originate and answer modes both working. AT command set added. ; 1.10 Changed the fsk receive code so it is simpler to understand and ; uses less RAM. ; ; INPUTS: ; Received RS-232 characters on rs-232 rx_pin (ra.1) ; OUTPUTS: ; Received RS-232 characters on tx_pin (ra.2) ; FSK output on PPM_pin ; LED flashes (rb.0) ; ; RESOURCES: ; Program memory: TBD ; Data memory: TBD ; I/O Count: TBD ; ;****************************************************************************** ; Device Directives ;****************************************************************************** SX28L_compiler IFDEF SX28L_compiler device SX28L,oscxt4,carryx ; 28-pin device, 4 pages, 8 banks of RAM device turbo,stackx_optionx ; High speed oscillator, turbo mode, ; option register extend, 8-level stack ELSE device pins28,pages4,banks8,carryx ; 28-pin device, 1 pages, 8 banks of RAM device oschs,turbo,optionx,stackx ; High speed oscillator, turbo mode, ENDIF ; option register extend, 8-level stack freq 50_000_000 ; default run speed = 50MHz ID 'B103TX10' ; Version = 1.0 reset reset_entry ; JUMP to reset_entry label on reset ;****************************************************************************** ; Watches (For Debug in SX_Key software V.1.0 +) ;****************************************************************************** watch fsk_answering,1,ubin watch freq_acc_low,16,udec watch freq_count_low,16,udec watch sine_index,8,udec watch D_to_A_val,8,udec watch freq_acc_high,16,uhex watch freq_count_high,8,uhex watch freq_count_low,8,uhex watch freq_count_high2,8,uhex watch freq_count_low2,8,uhex watch byte,1,fstr watch byte,8,udec watch curr_sine,8,sdec watch sine_index,8,sdec watch D_to_A_val,8,udec watch PPM0_acc,8,udec watch timer_flag,1,ubin watch timer_l,16,uhex watch temp,8,uhex watch wreg,8,uhex watch fsk_last_trans,8,udec watch fsk_trans_avg_l,16,udec watch fsk_avg_count,8,udec watch fsk_trans_count,8,udec watch fsk_glitch_acc,8,udec watch fsk_high_byte,8,udec watch fsk_average_index,8,udec watch fsk_temp_trans,8,udec watch fsk_processing_required1,1,ubin watch fsk_processing_required2,1,ubin watch fsk_carrier_detected,1,ubin watch fsk_rb_past_state,8,ubin ;************************************************************************** ; Equates for common data comm frequencies ;************************************************************************** f697_h equ $012 ; DTMF Frequency f697_l equ $09d f770_h equ $014 ; DTMF Frequency f770_l equ $090 f852_h equ $016 ; DTMF Frequency f852_l equ $0c0 f941_h equ $019 ; DTMF Frequency f941_l equ $021 f1209_h equ $020 ; DTMF Frequency f1209_l equ $049 f1336_h equ $023 ; DTMF Frequency f1336_l equ $0ad f1477_h equ $027 ; DTMF Frequency f1477_l equ $071 f1633_h equ $02b ; DTMF Frequency f1633_l equ $09c ;****************************************************************************** ; Equates for FSK generation ;****************************************************************************** f2225_h equ $03b f2225_l equ $06b f2025_h equ $036 f2025_l equ $014 f1070_h equ $01c f1070_l equ $093 f1270_h equ $021 f1270_l equ $0ea f2100_h equ $038 ; 2100Hz Signifies LOW data in Bell202 Spec f2100_l equ $015 ;************************************************************************** ; Equates for certain baud rates: ;************************************************************************** ;baud_bit = 4 ;for 19200 baud ;start_delay = 16+8+1 ; " " " ;int_period = 163 ; " " " ; *** 2400 baud (for slower baud rates, increase the RTCC prescaler) baud_bit = 7 ;for 2400 baud start_delay = 128+64+1 ; " " " fsk_start_delay = 128+96+1 int_period = 163 ; " " " ;****************************************************************************** ; Pin Definitions (These definitions are for SX DTMF DEMO boards) ;****************************************************************************** PPM_pin equ ra.0 ; D/A output pin rx_pin equ ra.1 ; RS-232 reception pin tx_pin equ ra.2 ; RS-232 transmission pin nothing equ ra.3 ; N/C ra_dir_mask equ %11111010 ; sets up the I/O directions of port ra ra_data_mask equ %11111111 ; sets up the output levels of the output pins on ra led_pin equ rb.0 ; LED pin rxa_pin equ rb.1 ; FSK receive pin cntrl_1 equ rb.2 ; drive cntrl_1 low to disable the output of the LPF ring equ rb.3 ; ring detection pin hook equ rb.4 ; drive hook low to go off-hook cntrl_3 equ rb.5 ; drive cntrl_3 low to disable the output of the HPF rts equ rb.6 ; indicates to the SX that the PC wants to transmit data cts equ rb.7 ; indicates to the PC that the SX is ready to receive data rb_dir_mask equ %01101110 ; sets up the I/O directions of port rb rb_data_mask equ %01011011 ; sets up the output levels of the output pins on ra LPF_mask equ %01001110 ; when LPF is enabled, tristate cntrl 1 and put cntrl 3 low HPF_mask equ %01101010 ; when HPF is enabled, tristate cntrl 3 and put cntrl 1 low LPF_HPF_mask equ %01101110 ; when both filters are enabled, tristate cntrl 1 and cntrl 3 dtmf_in_pin equ rc.0 dtmf_fdbk_pin equ rc.1 AtoD_in_pin equ rc.2 AtoD_fdbk_pin equ rc.3 imp_450_pin equ rc.4 imp_600_pin equ rc.5 imp_750_pin equ rc.6 imp_900_pin equ rc.7 rc_dir_mask equ %11010101 ; sets up the I/O directions of port rc rc_data_mask equ %00001111 ; sets up the output levels of the output pins on ra ;****************************************************************************** ; Global Variables ;****************************************************************************** org $8 ; Global registers flags ds 1 dtmf_gen_en equ flags.0 ; Signifies whether or not DTMF output is enabled sine_gen_en equ flags.1 timer_flag equ flags.2 fsk_tx_en equ flags.3 fsk_rx_en equ flags.4 ; Enables the FSK receiver. rx_flag equ flags.5 fsk_rx_flag equ flags.6 temp ds 1 task_switcher ds 1 ascii_index ds 1 command_index ds 1 ;****************************************************************************** ; Bank 0 Variables ;****************************************************************************** org $10 sine_gen_bank = $ freq_acc_low ds 1 ; 16-bit accumulator which decides when to increment the sine wave freq_acc_high ds 1 ; freq_count_low ds 1 ; 16-bit counter which decides which frequency for the sine wave freq_count_high ds 1 ; freq_count = Frequency * 6.83671552 sine_index ds 1 sine_index2 ds 1 ; The velocity of the sin wave freq_count_low2 ds 1 ; 16-bit counter which decides which frequency for the sine wave freq_count_high2 ds 1 ; freq_count = Frequency * 6.83671552 freq_acc_high2 ds 1 ; freq_acc_low2 ds 1 ; 16-bit accumulator which decides when to increment the sine wave curr_sine ds 1 ; The current value of the imitation sin wave curr_sine2 ds 1 ; The current value of the imitation sin wave sine2_temp ds 1 ; This register is used to do a temporary shift/add register PPM_bank = $ PPM0_acc ds 1 ; PPM accumulator D_to_A_val ds 1 ; current PPM output ;****************************************************************************** ; Bank 1 Variables ;****************************************************************************** org $30 timers = $ timer_l ds 1 timer_h ds 1 timer_hh ds 1 serial = $ ;UART bank tx_high ds 1 ;hi byte to transmit tx_low ds 1 ;low byte to transmit tx_count ds 1 ;number of bits sent tx_divide ds 1 ;xmit timing (/16) counter rx_count ds 1 ;number of bits received rx_divide ds 1 ;receive timing counter rx_byte ds 1 ;buffer for incoming byte rx_count2 ds 1 ;number of bits received rx_divide2 ds 1 ;receive timing counter rx_byte2 ds 1 ;buffer for incoming byte string ds 1 byte ds 1 plus_count ds 1 ;****************************************************************************** ; Bank 2 Variables ;****************************************************************************** org $50 ;bank3 variables fsk_receive_bank = $ fsk_transmit_bank = $ fsk_last_trans ds 1 fsk_trans_avg_l ds 1 fsk_trans_avg_h ds 1 fsk_avg_count ds 1 fsk_trans_count ds 1 ; This register counts the number of counts ; between transitions at the pin fsk_rb_past_state ds 1 ; This register keeps track of the previous ; state of port RB, to watch for transitions fsk_glitch_acc ds 1 fsk_average ds 1 fsk_high_byte ds 1 fsk_average_index ds 1 fsk_temp_trans ds 1 fsk_no_carrier_count ds 1 fsk_flags ds 1 fsk_answering equ fsk_flags.0 fsk_tx_bit equ fsk_flags.1 fsk_rx_bit equ fsk_flags.2 fsk_processing_required1 equ fsk_flags.3 fsk_processing_required2 equ fsk_flags.4 fsk_rx_bit_last equ fsk_flags.5 fsk_carrier_detected equ fsk_flags.6 fsk_answer_tone equ fsk_flags.7 ;************************************************************* ; Bank 4, 5, 6, 7 (for ascii buffer, but can be reused.) ;************************************************************* org $90 ascii_buffer = $ org $b0 ascii_buffer2 = $ org $d0 ascii_buffer3 = $ org $f0 ascii_buffer4 = $ ;************************ Beginning of program space *************************** ;****************************************************************************** ; Interrupt org $0 ; The interrupt Service routine starts at location zero. ; ; With a retiw value of -163 and an oscillator frequency of 50MHz, this ; code runs every 3.26us. ;****************************************************************************** PPM_output bank PPM_bank ; Update the PPM pin clc add PPM0_acc,D_to_A_val snc setb PPM_pin sc clrb PPM_pin ;****************************************************************************** FSK_output jnb dtmf_gen_en,:dtmf_disabled call @sine_generator1 jmp :task_switcher :dtmf_disabled snb sine_gen_en ; Output the frequencies set by the freq_count registers call @sine_generator2 snb fsk_rx_en call @fsk_receive :task_switcher inc task_switcher mov w,task_switcher and w,#$07 clc jmp pc+w jmp :fsk_process_1 ;0 jmp :fsk_process_2 ;1 jmp :fsk_process_3 ;2 jmp :fsk_transmit ;3 jmp :fsk_get_carrier;4 jmp do_timers ;5 jmp :transmit ;6 jmp :receive ;7 :fsk_process_1 call @FSK_RECEIVE_PROCESSING1 jmp do_timers :fsk_process_2 call @FSK_RECEIVE_PROCESSING2 jmp do_timers :fsk_process_3 call @FSK_RECEIVE_PROCESSING3 jmp do_timers :fsk_transmit snb fsk_tx_en call @TRANSMIT_FSK ; into its corresponding frequencies jmp do_timers :fsk_get_carrier call @FSK_GET_CARRIER jmp do_timers ;************************************************************************** :transmit ; This is an asynchronous RS-232 transmitter ; INPUTS: ; tx_divide.baud_bit - Transmitter only executes when this bit is = 1 ; tx_high - Part of the data to be transmitted ; tx_low - Some more of the data to be transmitted ; tx_count - Counter which counts the number of bits transmitted. ; OUTPUTS: ; tx_pin - Sets/Clears this pin to accomplish the transmission. ;************************************************************************** bank serial clrb tx_divide.baud_bit ;clear xmit timing count flag inc tx_divide ;only execute the transmit routine STZ ;set zero flag for test SNB tx_divide.baud_bit ; every 2^baud_bit interrupt test tx_count ;are we sending? JZ do_timers ;if not, go to :receive clc ;yes, ready stop bit rr tx_high ; and shift to next bit rr tx_low ; dec tx_count ;decrement bit counter movb tx_pin,/tx_low.6 ;output next bit jmp do_timers ;************************************************************************** :receive ; This is an asynchronous receiver for RS-232 reception ; INPUTS: ; rx_pin - Pin which RS-232 is received on. ; OUTPUTS: ; rx_byte - The byte received ; rx_flag - Set when a byte is received. ;************************************************************************** bank serial movb c,rx_pin ;get current rx bit test rx_count ;currently receiving byte? jnz :rxbit ;if so, jump ahead mov w,#9 ;in case start, ready 9 bits sc ;skip ahead if not start bit mov rx_count,w ;it is, so renew bit count mov rx_divide,#start_delay ;ready 1.5 bit periods :rxbit djnz rx_divide,:rxdone ;middle of next bit? setb rx_divide.baud_bit ;yes, ready 1 bit period dec rx_count ;last bit? sz ;if not rr rx_byte ; then save bit snz ;if so setb rx_flag ; then set flag :rxdone ;************************************************************************** do_timers bank timers ; Update the timers inc timer_l snz inc timer_h snz setb timer_flag snz inc timer_hh setb led_pin sb timer_h.6 clrb led_pin ;****************************************************************************** :ISR_DONE ; This is the end of the interrupt service routine. Now load 163 into w and ; perform a retiw to interrupt 163 cycles from the start of this one. ; (3.26us@50MHz) ;****************************************************************************** mov w,#-163 ;1 ; interrupt 163 cycles after this interrupt retiw ;3 ; return from the interrupt ;****************************************************************************** ; End of the Interrupt Service Routine ;****************************************************************************** ;************************************************************************** time_n_ticks ; This subroutine times 'w' ticks, and returns with a '1' in w when ; the specified time has timed out. Each tick is 213.647 ms. ; This subroutine uses the TEMP register ; INPUT w - # of milliseconds to delay for. ; OUTPUT Returns after n milliseconds. ;************************************************************************** bank timers test wreg jz :check_time clc add w,timer_hh mov temp,w retw 0 :check_time mov w,temp xor w,timer_hh sz retw 0 retw 1 ;****************************************************************************** reset_entry ; Program Starts Here on Power Up ;****************************************************************************** call @init mov !option,#%00011111 ; enable wreg and rtcc interrupt mov w,#_hello call @send_string main_2 _send_prompt mov w,#_CR call @send_string mov w,#_prompt ; send prompt call @send_string _cmd_loop jnb rx_flag,$ clrb rx_flag bank serial mov byte,rx_byte call @uppercase ; convert it to uppercase stc cje byte,#$20,_cmd_loop ; if it equals a space, ignore it. stc cje byte,#$0d,:enter ; if it equals a carriage return, parse the string. mov w,byte ; if it does not resemble the above characters, echo it. call @send_byte stc cje byte,#$08,:backspace ; if it equals a backspace, delete one character in the buffer. call @buffer_push ; otherwise, store it jmp _cmd_loop ; and come back for more. :backspace call @buffer_backspace jmp _cmd_loop :enter ; If the user presses enter, then parse the string. ;************************************************************************** ; String parser (Checks to see if buffer = any commands) ; -Checks contents of ascii buffer against any commands stored in ROM ; -If a command = the contents of the ascii buffer, a routine will be called ; -Each routine MUST perform a retw 0 on exit, or parse_string will not ; know that a routine has run and it should exit back to command mode. ; -Exits back to command mode when it detects a zero after the table look-up. ; -Outputs 'OK' if no commands are matched. ;************************************************************************** parse_string clr ascii_index ; Clear the index into the ascii buffer clr command_index ; And the index into the commands :loop call @buffer_get ; Get a vale from the buffer at ascii_index call command_table ; Get a character from one of the commands test wreg ; If the return value is 0, then this matched jz :nothing ; the command and ran a routine. Exit. bank serial xor w,byte ; compare the command's character with the jnz :not_equal ; buffer's character. call @inc_ascii_index ; Increment the index into the buffer. jmp :loop :not_equal inc command_index ; If the buffer did not equal the command, clr ascii_index ; start from the beginning of a new command stc cjne command_index,#6,:loop ; and the buffer. (This number = # of commands) :nothing mov w,#_CR call @send_string mov w,#_OK ; If we have checked all 4 commands, then this call @send_string ; did not equal any so send an 'OK' message. :done bank ascii_buffer clr ascii_index clr ascii_buffer jmp _send_prompt ;************************************************************************** command_table mov w,command_index clc add pc,w jmp command_1 jmp command_2 jmp command_3 jmp command_4 jmp command_5 jmp command_6 ;************************************************************************** command_1 ; Dial command mov w,ascii_index add PC,w retw 'A' retw 'T' retw 'D' retw 'T' jmp DIAL_MODE ;************************************************************************** command_2 ; Hang up command mov w,ascii_index add PC,w retw 'A' retw 'T' retw 'H' jmp HANG_UP ;************************************************************************** command_3 ; Initialize mov w,ascii_index add PC,w retw 'A' retw 'T' retw 'Z' jmp INITIALIZE ;************************************************************************** command_4 ; Answer/ Auto answer mov w,ascii_index add PC,w retw 'A' retw 'T' retw 'A' jmp AUTO_ANSWER ;************************************************************************** command_5 ; Data mode mov w,ascii_index add PC,w retw 'A' retw 'T' retw 'O' jmp FSK_IO ;************************************************************************** command_6 ; Help mov w,ascii_index add PC,w retw '?' jmp HELP ;************************************************************************** ; END of String parser (Checks to see if buffer = any commands) ;************************************************************************** HANG_UP setb hook retw 0 INITIALIZE call @init clr flags retw 0 AUTO_ANSWER jmp Answer retw 0 HELP retw 0 ;************************************************************************** ; Dial Mode: ; -Dials contents of ascii buffer, starting from location pointed ; to by ascii_index. ; -Responds to these commands: ; 0-9, *, # - Dials the specified number ; , - Pause for 2 seconds ; -Jumps to data mode after dialing. ;************************************************************************** DIAL_MODE mov w,#_CR call @send_string mov w,#_DIALING ; send Dialing call @send_string clrb hook mov w,#255 call @delay_10n_ms bank serial :dial_loop call @buffer_get ; wait for an input character call @uppercase ; convert it to uppercase mov w,byte snz jmp :originate_mode call @send_byte cje byte,#',',:pause ; if the character = ',', pause for 2s call @digit_2_index ; convert the ascii digit to an ; index value call @load_frequencies ; load the frequency registers call @dial_it ; dial the number for 60ms and return. :inc call @inc_ascii_index ; increment the index into the table jmp :dial_loop :pause mov w,#201 ; delay 2s call @delay_10n_ms jmp :inc :originate_mode ;****************************************************************** ; Go off-hook ;****************************************************************** mov m,#$0f mov !rb,#HPF_mask ; Enable HPF and disable LPF clrb cntrl_1 clr flags bank fsk_transmit_bank clrb fsk_answering setb fsk_rx_en setb fsk_tx_bit setb sine_gen_en setb fsk_tx_en mov w,#140 ; wait 30 seconds for answer_tone call time_n_ticks :loop ; clr w ; call time_n_ticks ; test wreg ; jnz no_carrier ; bank fsk_receive_bank ; jnb fsk_answer_tone,:loop jmp FSK_IO Answer clrb hook ; Go off-hook mov m,#$0f mov !rb,#LPF_mask ; Enable LPF and disable HPF clrb cntrl_3 call @answer_tone ; Send out the answer tone for 3 seconds bank fsk_transmit_bank ; Clear all the flags clr flags setb fsk_answering ; enable answering frequencies setb fsk_tx_bit ; Set the tx_bit to output a high frequency setb fsk_tx_en ; enable FSK transmit setb sine_gen_en ; enable sine generation mov w,#255 call @delay_10n_ms mov w,#255 call @delay_10n_ms bank fsk_receive_bank ; enable FSK receive setb fsk_rx_en FSK_IO mov w,#47 call time_n_ticks :loop clr w call time_n_ticks test wreg ; jnz no_carrier bank fsk_receive_bank ; jnb fsk_carrier_detected,:loop mov w,#_DATA_MODE call @send_string mov w,#_prompt call @send_string clr plus_count :loop2 bank fsk_receive_bank ; jnb fsk_carrier_detected,no_carrier movb fsk_tx_bit,rx_pin ; move the rs-232 pin to the fsk_tx_bit movb tx_pin,fsk_rx_bit ; and move the fsk_rx_bit to the rs-232 pin jb rx_flag,:check_for_plus jmp :loop2 ; jump here forever (ISR does all the work) :check_for_plus bank serial clrb rx_flag inc plus_count mov w,#'+' xor w,rx_byte sz clr plus_count mov w,#3 xor w,plus_count snz retw 0 jmp :loop2 no_carrier setb tx_pin mov w,#255 call @delay_10n_ms mov w,#_no_carrier call @send_string bank serial :loop test tx_count jz INITIALIZE jmp :loop org $200 ;****************************************************************************** FSK_RECEIVE ;************************************************************************** bank fsk_receive_bank ; switch to fsk_receive_bank of RAM inc fsk_trans_count ; Increment the transition count snz dec fsk_trans_count ; If the result is zero, keep fsk_trans_count in range clc mov w,fsk_rb_past_state ; Check for a transition xor w,rb and w,#%00000010 snz retp ; return if there has been no transition xor fsk_rb_past_state,w ; save the new value of the FSK_pin jb fsk_answering,:dont_double sb fsk_rb_past_state.1 retp :dont_double clc mov w,#-30 add w,fsk_trans_count jnc :glitch mov fsk_temp_trans,fsk_trans_count clc add fsk_trans_avg_l,w snc inc fsk_trans_avg_h inc fsk_avg_count clr fsk_trans_count setb fsk_processing_required1 retp :glitch ; Save any glitches in the glitch accumulator, to be added to ; the transition count before processing clc add fsk_glitch_acc,fsk_trans_count retp ;************************************************************************** FSK_RECEIVE_PROCESSING1 ; This code is not very speed critical and can ; run every so often in the ISR. ;************************************************************************** bank fsk_receive_bank sb fsk_processing_required1 retp clrb fsk_processing_required1 setb fsk_processing_required2 retp ;************************************************************************** FSK_RECEIVE_PROCESSING2 ; This code is not very speed critical and can ; run every so often in the ISR. ;************************************************************************** ;****************************************************************** ; If no processing is required, exit ;****************************************************************** bank fsk_receive_bank ;1 sb fsk_processing_required2 ;1 retp ;1 clrb fsk_processing_required2 ;1 ;****************************************************************** ; Add the last transition time to this one, and divide by two. ; and also add the glitch accumulator. ;****************************************************************** clc rr fsk_glitch_acc clc mov w,fsk_last_trans add w,fsk_temp_trans rr wreg clc add w,fsk_glitch_acc clr fsk_glitch_acc ;****************************************************************** ; Now compare the result to 130 for answer mode or to 145 for ; originate mode. Anything above this threshold is a "high" bit, ; and anything below this threshold is a "low" bit. ;****************************************************************** mov fsk_last_trans,w ;1 mov w,#-130 ;1 sb fsk_answering ;1 mov w,#-145 ;1 clc ;1 add w,fsk_last_trans ;1 setb fsk_rx_bit ;1 snc ;1 clrb fsk_rx_bit ;1;50 ;3;53 mov fsk_last_trans,fsk_temp_trans retp ;************************************************************************** FSK_RECEIVE_PROCESSING3 ;************************************************************************** retp bank fsk_receive_bank sb fsk_rx_bit jmp :rx_bit_low :rx_bit_high snb fsk_rx_bit_last retp setb fsk_rx_bit_last mov w,#121 sb fsk_answering mov w,#138 jmp :hysterises :rx_bit_low sb fsk_rx_bit_last retp clrb fsk_rx_bit_last mov w,#144 sb fsk_answering mov w,#152 :hysterises mov fsk_last_trans,w retp ;************************************************************************** FSK_GET_CARRIER ;************************************************************************** bank fsk_receive_bank mov w,fsk_avg_count sz retp inc fsk_avg_count clrb fsk_answer_tone clrb fsk_carrier_detected jb fsk_answering,:low_freqs mov w,#-135 clc add w,fsk_trans_avg_h jnc :get_answer_tone; If the average transition ; time is less than 138, error... mov w,#-152 clc add w,fsk_trans_avg_h sc setb fsk_carrier_detected :get_answer_tone mov w,#-142 clc add w,fsk_trans_avg_h jnc :no_answer_tone mov w,#-148 clc add w,fsk_trans_avg_h sc setb fsk_answer_tone :no_answer_tone clr fsk_trans_avg_h clr fsk_trans_avg_l retp :low_freqs mov w,#-118 clc add w,fsk_trans_avg_h jnc :no_carrier ; If the average transition ; time is less than 138, error... mov w,#-145 clc add w,fsk_trans_avg_h sc setb fsk_carrier_detected :no_carrier clr fsk_trans_avg_h clr fsk_trans_avg_l retp ;************************************************************************** TRANSMIT_FSK ;************************************************************************** bank fsk_transmit_bank jb fsk_answering,transmit_answer_tones transmit_originate_tones jnb fsk_tx_bit,:low_freq :high_freq bank sine_gen_bank mov freq_count_high2,#f1270_h mov freq_count_low2,#f1270_l retp :low_freq bank sine_gen_bank mov freq_count_high2,#f1070_h mov freq_count_low2,#f1070_l retp transmit_answer_tones jnb fsk_tx_bit,:low_freq :high_freq bank sine_gen_bank mov freq_count_high2,#f2225_h mov freq_count_low2,#f2225_l retp :low_freq bank sine_gen_bank mov freq_count_high2,#f2025_h mov freq_count_low2,#f2025_l retp ;************************************************************************** answer_tone ;************************************************************************** bank sine_gen_bank ; send out the answer tone for 3 seconds clr curr_sine mov freq_count_high2,#f2100_h mov freq_count_low2,#f2100_l setb sine_gen_en ; enable the FSK transmitter mov w,#255 call @delay_10n_ms mov w,#45 call @delay_10n_ms retp ;************************************************************************** org $300 ;************************************************************************** ; String data (for RS-232 output) and tables ;************************************************************************** _hello dw 13,10,'SX Modem V 4.0',13,10,0 _instructions dw '- ? For Help',0 _DIALING dw 'DIAL ',0 _ANSWERING dw 'ANSWERING ',0 _AUTO_ANSWER dw 'AUTO ANSWER ',13,10,0 _RING dw 'RING',13,10,0 _PROMPT dw 13,10,'>',0 _HANGING_UP dw 'HANG UP ',13,10,0 _ATDT dw 13,10,'ATDT=',0 _ATA dw 'ATA =',0 _ATH dw 'ATH =',0 _ATZ dw 'ATZ =',0 _ATO dw 'ATO =',0 _plus dw 13,10,'+++ =',0 _OK dw 'OK',13,10,0 _CR dw 13,10,0 _COMMAND_MODE dw 'COMMAND MODE',13,10,0 _DATA_MODE dw 13,10,'CONNECT 300',0 _no_carrier dw 13,10,'NO CARRIER',0 _INIT dw 'INIT',0 org $400 ; Miscellaneous subroutines ;************************************************************************** buffer_push ; This subroutine pushes the contents of byte onto the 32-byte ascii buffer. ;************************************************************************** bank serial ; Move the byte into the buffer mov temp,byte mov fsr,#ascii_buffer clc add fsr,ascii_index mov indf,temp ; Increment index and keep it in range call @inc_ascii_index mov fsr,#ascii_buffer ; Null terminate the buffer. clc add fsr,ascii_index clr indf bank serial retp ;************************************************************************** ;************************************************************************** buffer_backspace ; This subroutine deletes one value of the buffer and decrements the index ;************************************************************************** dec ascii_index and ascii_index,#%01101111 mov fsr,#ascii_buffer clc add fsr,ascii_index clr indf bank serial retp ;************************************************************************** inc_ascii_index ; This subroutine increments the index into the buffer ;************************************************************************** mov w,ascii_index and w,#%00001111 xor w,#%00001111 jnz :not_on_verge inc ascii_index mov w,#16 clc add w,ascii_index and w,#$7f mov ascii_index,w retp :not_on_verge inc ascii_index retp ;************************************************************************** buffer_get ; This subroutine retrieves the buffered value at index ;************************************************************************** mov fsr,#ascii_buffer clc add fsr,ascii_index mov w,indf bank serial mov byte,w retp ;************************************************************************** delay_10n_ms ; This subroutine delays 'w'*10 milliseconds. ; This subroutine uses the TEMP register ; INPUT w - # of milliseconds to delay for. ; OUTPUT Returns after 10 * n milliseconds. ;************************************************************************** mov temp,w bank timers :loop clrb timer_flag ; This loop delays for 10ms mov timer_h,#$0f4 mov timer_l,#$004 jnb timer_flag,$ dec temp ; do it w-1 times. jnz :loop clrb timer_flag retp ;************************************************************************** delay_n_ms ; This subroutine delays 'w' milliseconds. ; This subroutine uses the TEMP register ; INPUT w - # of milliseconds to delay for. ; OUTPUT Returns after n milliseconds. ;************************************************************************** mov temp,w bank timers :loop clrb timer_flag ; This loop delays for 1ms mov timer_h,#$0fe mov timer_l,#$0cd jnb timer_flag,$ dec temp ; do it w-1 times. jnz :loop clrb timer_flag retp ;************************************************************************** zero_ram ; Subroutine - Zero all ram. ; INPUTS: None ; OUTPUTS: All ram locations (except special function registers) are = 0 ;************************************************************************** CLR FSR :loop SB FSR.4 ;are we on low half of bank? SETB FSR.3 ;If so, don't touch regs 0-7 CLR IND ;clear using indirect addressing IJNZ FSR,:loop ;repeat until done retp ;************************************************************************** init ;************************************************************************** mov m,#$0d mov !ra,#$00 ; initialize all ports to CMOS levels mov !rb,#$00 mov !rc,#$00 mov m,#$0f ; initialize the ports mov !ra,#ra_dir_mask mov ra,#ra_data_mask mov !rb,#rb_dir_mask mov rb,#rb_data_mask mov !rc,#rc_dir_mask mov rc,#rc_data_mask setb hook ; go on hook. setb led_pin ; turn on LED clr flags ; Clear all flags call zero_ram retp ;************************************************************************** ; Subroutine - Get byte via serial port and echo it back to the serial port ; INPUTS: ; -NONE ; OUTPUTS: ; -received byte in rx_byte ;************************************************************************** get_byte jnb rx_flag,$ ;wait till byte is received clrb rx_flag ;reset the receive flag bank serial mov byte,rx_byte ;store byte (copy using W) ; & fall through to echo char back ;************************************************************************** ; Subroutine - Send byte via serial port ; INPUTS: ; w - The byte to be sent via RS-232 ;************************************************************************** send_byte bank serial :wait test tx_count ;wait for not busy jnz :wait ; not w ;ready bits (inverse logic) mov tx_high,w ; store data byte setb tx_low.7 ; set up start bit mov tx_count,#10 ;1 start + 8 data + 1 stop bit RETP ;leave and fix page bits ;************************************************************************** ; Subroutine - Send string pointed to by address in W register ; INPUTS: ; w - The address of a null-terminated string in program ; memory ; OUTPUTS: ; outputs the string via. RS-232 ;************************************************************************** send_string bank serial mov string,w ;store string address :loop mov w,string ;read next string character mov m,#3 ; with indirect addressing iread ; using the mode register mov m,#$F ;reset the mode register test w ;are we at the last char? snz ;if not=0, skip ahead RETP ;yes, leave & fix page bits call send_byte ;not 0, so send character inc string ;point to next character jmp :loop ;loop until done ;************************************************************************** ; Subroutine - Make byte uppercase ; INPUTS: ; byte - The byte to be converted ; OUTPUTS: ; byte - The uppercase byte ;************************************************************************** uppercase stc csae byte,#'a' ;if byte is lowercase, then skip ahead RETP stc sub byte,#'a'-'A' ;change byte to uppercase RETP ;leave and fix page bits ;************************************************************************** ; Subroutine - Disable the outputs ; Load DC value into PPM and disable the output switch. ;************************************************************************** disable_o bank PPM_bank ; input mode. mov D_to_A_val,#128 ; put 2.5V DC on PPM output pin retp ;************************************************************************** org $600 ; These subroutines are on page 3. ;************************************************************************** ; DTMF transmit functions/subroutines ;************************************************************************** ;************************************************************************** DTMF_TABLE ; DTMF tone constants ; This routine returns with the constant used for each of the frequency ; detectors. ; INPUT: w - Index into the table (0-15 value) ; OUTPUT: w - Constant at that index ;************************************************************************** clc jmp PC+w retw f697_l retw f697_h retw f770_l retw f770_h retw f852_l retw f852_h retw f941_l retw f941_h retw f1209_l retw f1209_h retw f1336_l retw f1336_h retw f1477_l retw f1477_h retw f1633_l retw f1633_h ;************************************************************************** ASCII_TABLE ; Ascii value at index (0-15) ; INPUT: w - Index into the table (0-15 value) ; OUTPUT: w - Constant at that index ;************************************************************************** clc jmp PC+w retw '1' retw '2' retw '3' retw 'A' retw '4' retw '5' retw '6' retw 'B' retw '7' retw '8' retw '9' retw 'C' retw '*' retw '0' retw '#' retw 'D' ;************************************************************************** index_2_digit ; This subroutine converts a digit from 0-9 or a '*' or a '#' to a table ; lookup index which can be used by the load_frequencies subroutine. To use ; this routine, pass it a value in the 'byte' register. No invalid digits ; are used. (A, B, C, or D) ;************************************************************************** call ASCII_TABLE retp ;************************************************************************** digit_2_index ; This subroutine converts a digit from 0-9 or a '*' or a '#' to a table ; lookup index which can be used by the load_frequencies subroutine. To use ; this routine, pass it a value in the 'byte' register. No invalid digits ; are used. (A, B, C, or D) ;************************************************************************** bank serial clr temp :loop mov w,temp call ASCII_TABLE xor w,byte jz :done inc temp jb temp.4,:done jmp :loop :done mov w,temp retp ;************************************************************************** load_frequencies ; This subroutine loads the frequencies using a table lookup approach. ; The index into the table is passed in the byte register. The DTMF table ; must be in the range of $400 to $500. ;************************************************************************** mov temp,w bank sine_gen_bank mov w,>>temp and w,#%00000110 call DTMF_TABLE mov freq_count_low,w mov w,>>temp and w,#%00000110 inc wreg call DTMF_TABLE mov freq_count_high,w rl temp setb temp.3 mov w,temp and w,#%00001110 mov temp,w call DTMF_TABLE mov freq_count_low2,w mov w,temp inc wreg call DTMF_TABLE mov freq_count_high2,w retp ;************************************************************************** dial_it ; This subroutine puts out whatever frequencies were loaded ; for 1000ms, and then stops outputting the frequencies. ;************************************************************************** bank sine_gen_bank clr sine_index clr sine_index2 enable_o ; enable the output mov w,#10 call @delay_10n_ms ; delay 30ms setb dtmf_gen_en mov w,#12 call @delay_10n_ms ; delay 100ms clrb dtmf_gen_en call @disable_o ; now disable the outputs :end_dial_it retp ;************************************************************************** sine_generator1 ;(Part of interrupt service routine) ; This routine generates a synthetic sine wave with values ranging ; from -32 to 32. Frequency is specified by the counter. To set the ; frequency, put this value into the 16-bit freq_count register: ; freq_count = FREQUENCY * 6.83671552 (@50MHz) ;************************************************************************** bank sine_gen_bank clc add freq_acc_low,freq_count_low add freq_acc_high,freq_count_high sc jmp :no_change inc sine_index mov w,sine_index and w,#$1f call sine_table mov curr_sine,w ;1 ; add the velocity to sin :no_change ;************************************************************************** sine_generator2 ;(Part of interrupt service routine) ; This routine generates a synthetic sine wave with values ranging ; from -32 to 32. Frequency is specified by the counter. To set the ; frequency, put this value into the 16-bit freq_count register: ; freq_count = FREQUENCY * 6.83671552 (@50MHz) ;************************************************************************** bank sine_gen_bank clc add freq_acc_low2,freq_count_low2 add freq_acc_high2,freq_count_high2 sc jmp :no_change inc sine_index2 mov w,sine_index2 and w,#$1f call sine_table mov curr_sine2,w :no_change mov D_to_A_val,curr_sine2 ; mov sin2 into PPM0 mov sine2_temp,w ; mov the high_frequency sin wave's current value clc ; into a temporary register snb sine2_temp.7 ; divide temporary register by four by shifting right stc ; (for result = (0.25)(sin2)) rr sine2_temp clc snb sine2_temp.7 stc mov w,>>sine2_temp clc add D_to_A_val,w ; (1.25)(sin2) = sin2 + (0.25)(sin2) add D_to_A_val,curr_sine ; add the value of SIN into the PPM output add D_to_A_val,#128 ; for result = PPM0 = 1.25*sin2 + 1*sin retp ; return with page bits intact ;****************************************************************************** sine_table ; The values in this table can be changed to increase/decrease the amplitude of ; the output sine wave. ;****************************************************************************** clc jmp pc+w retw 0 retw 4 retw 8 retw 11 retw 14 retw 16 retw 18 retw 19 retw 20 retw 19 retw 18 retw 16 retw 14 retw 11 retw 8 retw 4 retw 0 retw -4 retw -8 retw -11 retw -14 retw -16 retw -18 retw -19 retw -20 retw -19 retw -18 retw -16 retw -14 retw -11 retw -8 retw -4 ;************************************************************************** ;****************************************************************************** ; Copyright © 1998 Scenix Semiconductor, Inc. All rights ; reserved. ; ; Scenix Semiconductor, Inc. assumes no responsibility or liability for ; the use of this [product, application, software, any of these products]. ; ; Scenix Semiconductor conveys no license, implicitly or otherwise, under ; any intellectual property rights. ; Information contained in this publication regarding (e.g.: application, ; implementation) and the like is intended through suggestion only and may ; be superseded by updates. Scenix Semiconductor makes no representation ; or warranties with respect to the accuracy or use of these information, ; or infringement of patents arising from such use or otherwise. ; ; Scenix Semiconductor products are not authorized for use in life support ; systems or under conditions where failure of the product would endanger ; the life or safety of the user, except when prior written approval is ; obtained from Scenix Semiconductor. ;******************************************************************************
file: /Techref/scenix/lib/io/dev/modem/bell_103_full_dup_1_13.SRC, 45KB, , updated: 2002/12/12 09:23, local time: 2024/8/14 20:07,
3.139.235.177:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/techref/scenix/lib/io/dev/modem/bell_103_full_dup_1_13.SRC"> scenix lib io dev modem bell_103_full_dup_1_13</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Ashley Roll has put together a really nice little unit here. Leave off the MAX232 and keep these handy for the few times you need true RS232! |
.