📄 avr pocsag rev 1_1.asm
字号:
;***************************************************************************
;* Title: AVR_POCSAG pocsag encoder test code Rev. 1.1
;* Made available for educational, and non-commercial use.
;* Commercial use forbidden without license from author.
;* Code may be modified as long as it is released publicly and credit
;* is given to the original author(s).
;* (c) copyright 2000 Henry Carl Ott N2RVQ, All Rights Reserved.
;* Questions, comments or offers of cash? carlott@rcn.net http://users.rcn.com/carlott/
;***************************************************************************
;* Description: A standalone pocsag encoder. Unit will accept strings from console and encode
;* as standard POCSAG. Alphanumeric, numeric only, and tone messages can be encoded at
;* 512/1200/2400 baud and as inverted or non-inverted data. In addition support is provided for
;* transmission of Morse encoded strings at varying speed rates, radio control, and certain
;* debugging functions. Please see companion documentation for schematics, use, and command syntax.
;****************************************************************************
;* Credits: The asc2bin routine is a modified/limited version of a routine by Jack Tidwell as made
;* available in his avrmath.asm code. Credit is also given to everyone who made example AVR
;* code available on the net for me to learn how to program these Atmel processors.
;***************************************************************************
;* Disclaimer: This code is provided "as is". Don't use this code/design for any
;* application where human life is at risk or property damage may occur.
;***************************************************************************
;Versions:
; 1.1 fixed timing error in isr timer reload value
; 1.0 first release
.nolist
.include "2313def.inc"
.list
.listmac
;***************************************************************************
;*
;* MACROS
;*
;***************************************************************************
;--- simple led macro
.macro led_on
sbi PORTD,led
.endm
.macro led_off
cbi PORTD,led
.endm
;--- send single char to console
.macro _send
ldi temp,@0
rcall putc
.endm
;--- send string to console
.macro _send_232_str
ldi zh,high(@0 * 2)
ldi zl,low(@0 * 2) ;Init Z-pointer
rcall ser_ram_str
.endm
;--- copy flash data to pocsag output buffer
.macro _flash2buff
ldi zh,high(@0 * 2)
ldi zl,low(@0 * 2) ;Init Z-pointer
rcall flash2buff
.endm
;--- skip next instruction
.macro skip
rjmp (pc + 2) ; skip, next instruction
.endm
;------delay two cycles in one instruction
.macro _nop_2
rjmp (pc + 1)
.endm
;--- some program equates and constants
.equ ram_begin = 0x60 ; start of ram on 2313
.equ max_str_len = 80 ; max len of string from console
.equ getc_to_val = 4 ; time before getc will timeout (in approx 2.5 second incs)
.equ eom_char = eot ; char to append to alpha messages (may not be necessary)
.equ clock = 7372800 ; cpu clock
.equ console_baud = 9600
.equ isr_divider = (0xffff - (clock/9600)) + 15
;--- ascii char codes
.equ ctrl_c = 0x03
.equ etx = 0x03
.equ eot = 0x04
.equ bel = 0x07 ; bell
.equ bs = 0x08 ; back space
.equ cr = 0x0d ; carriage return
.equ lf = 0x0a ; line feed
;.equ frame_sync = 0x7CD215D8 ; pocsag frame sync word (for reference)
;.equ idle = 0x7A89C197 ; pocsag idle word (for reference)
;-----------------------------------------------------------------
;--- port and pin defines
;--- portb
.equ spare_0 = 0
.equ cfg_0 = 1 ; unused at moment
.equ cfg_1 = 2 ; unused at moment
.equ cw_out = 3 ; tone output for cw generation
.equ poc_out = 4 ; encoded pocsac data out
.equ inp_1 = 5 ; send canned message 1
.equ inp_2 = 6 ; send canned message 2
.equ tx_inhibit = 7 ; x-mitter lockout
;--- portd
.equ ptt = 6 ; key radio
.equ led = 5 ; status
.equ cts_232 = 4 ; clear to send output, asserts while transmitting to indicate busy
.equ spare_1 = 3 ;
.equ spare_2 = 2 ;
.equ txd_232 = 1 ; O 232_txd
.equ rxd_232 = 0 ; I 232_rxd
;*****************************
;* Global Register Variables *
;*****************************
.def r0 = r00 ; used with lpm instruction
.def tic = r01 ; incs @ 9600 hz resets at 96 0-95
.def sec_01 = r02 ; incs @ 100 hz
.def u_data = r03 ; rs-232 data (rx)
.def EEaddr = r04 ; internal eeprom address buffer
.def EEdata = r05 ; internal eeprom data buffer for rd/wr
.def frame = r06 ; current pocsag frame 0-15
.def mant1hh = r07
.def mant1h = r08 ; used for ascii to bin conversion
.def mant1m = r09 ; also mapped to bin
.def mant1 = r10
.equ at_bin = 07 ; pointer location of bin registers
.def binhh = r07 ; msb
.def binh = r08 ; working registers to build pocsag word
.def binm = r09
.def bin = r10
.def mant2hh = r11
.def mant2h = r12 ; used for asc2bin routines
.def mant2m = r13 ; also mapped to pocbuff
.def mant2 = r14
.equ at_poc_buff = 11 ; pointer location of buffer regs
.def poc_buff_hh = r11 ; 32 bits of data to be clocked out by isr
.def poc_buff_h = r12
.def poc_buff_m = r13
.def poc_buff = r14
.def isr_save = r15 ; saves mcu status reg during isr
.def temp = r16 ; gp working reg
.def temp2 = r17 ; yet another working register
.def ii = r18 ; gp loop counter
.def flags = r19 ; various bit flags for isr
.def poc_flags = r20 ; various bit flags of message being sent
.def byte_cnt = r21 ; general purpose byte counter
.def bit_cnt = r22 ; gp bit counter
.def morse_rate = r23 ; dit length in .01 incs
.def poc_bit_cnt = r24 ; bit counter for isr x-mit routine 1-32
.def poc_baud_div = r25 ; divide isr 9600 tic to 2400,1200,512
.def poc_char_pnt = r26 ; pointer to next message char to process
.def poc_char = r27 ; current char being processed
.def yl = r28 ; used in flash2buff to point to destination
.def yh = r29 ;
.def zl = r30 ; used for indirect indexing
.def zh = r31 ; used for indirect indexing
;**************************
;- isr bit flags defined
;**************************
.equ p_baud_1200 = 0x00 ; pocsag baud rate for isr
.equ p_baud_2400 = 0x01 ; ditto, if neither bit is set, then baud = 512
.equ p_invert = 0x02 ; invert pocsag data before sending
.equ cw_tone = 0x03 ; turns on tone generation in isr
.equ uart_rx = 0x04 ; incoming char is ready
.equ debug = 0x05 ; if set, echo pocsag data to console
.equ poc_pre0 = 0x06 ; divide by 4 prescaler for pocsag 512 baud
.equ poc_pre1 = 0x07 ; ditto
;**************************
;- pocsag stored message bit flags defined
;**************************
.equ m_baud_1200 = 0x00
.equ m_baud_2400 = 0x01 ; if neither bit, then 512
.equ m_invert = 0x02 ; invert?
.equ m_spare = 0x03 ; not used
.equ m_fun_0 = 0x04 ; msg function
.equ m_fun_1 = 0x05 ; msg function
.equ m_type_num = 0x06 ; msg type numeric
.equ m_type_alpha = 0x07 ; msg type alpha
;-------------------------
;*********************
;* Interrupt Vectors *
;*********************
.CSEG
.org 0x00 ; reset
rjmp reset
.org INT0addr ; external int 0
reti
.org INT1addr ; external int 1
reti
.org OVF1addr ; overflow of 16 bit timer 1
reti
.org OVF0addr ; overflow of 8 bit timer 0 ; 9600hz system tic
rjmp t0int
.org URXCaddr ; reception of data by uart
rjmp uart_rx_isr
;--- timer 1 overflow interupt, we should hit the isr @ 9600 hz
;--- the isr shifts out the 32 bit pocsag word at the correct baud rate
;--- isr will also generats cw tone, and incs the sec_001 counter @ 100 hz
t0int: in isr_save,SREG ; save SREG
push temp
ldi temp,256 - ((clock/8) / 9600) + 1 ;(1 = approx overhead)
out TCNT0,temp ;
inc poc_baud_div ;
inc tic ; bump counter everytime through
ldi temp,96 ; divide by 96 to get our 10ms tic
eor temp,tic ;
brne no_roll_over ; no rollover
clr tic
inc sec_01 ; bump hunds of seconds (10ms)
no_roll_over: sbrs flags,cw_tone ; is tone enabled ?
rjmp sel_poc_baud ; no
sbrc tic,3 ; 1200 hz out
sbi portb,cw_out
sbrs tic,3
cbi portb,cw_out
rjmp tmr0isr_end ; skip pocsag generation
sel_poc_baud: sbrc flags,p_baud_1200 ; test baud rate bits
rjmp set_1200 ;
sbrc flags,p_baud_2400 ;
rjmp set_2400
set_512: mov temp,flags ; (9600*4) / ((3*19)+18)) = 512
andi temp,0b11000000 ; so, 1 in 4 times we count to 18
breq div18 ; other three times count to 19
div19: ldi temp,1
div18: subi temp, -18 ; add 18
cp poc_baud_div,temp ;
brne tmr0isr_end ; no match
ldi temp,0x40 ; matched
add flags,temp ; top two bits of flag register is used to divide by 4
rjmp period ; process bit
set_1200: cpi poc_baud_div,8 ; 1200 = 9600 / 8
breq period ; match
rjmp tmr0isr_end ; no match
set_2400: cpi poc_baud_div,4 ; 2400 = 960 /4
brne tmr0isr_end ; no match
period: clr poc_baud_div ; reset baud rate divisor
tst poc_bit_cnt ; test for zero bits
breq tmr0isr_end ; nothing to send
ldi temp,0x80 ; if invert flag is set, we invert the bit prior to sending
sbrc flags,p_invert ;
eor poc_buff_hh,temp
sbrs poc_buff_hh,7 ; copy hi bit to output pin
cbi portb,poc_out ;
sbrc poc_buff_hh,7 ; double test for no jitter
sbi portb,poc_out ;
rol poc_buff ; rotate next bit into position
rol poc_buff_m
rol poc_buff_h
rol poc_buff_hh ; msb
dec poc_bit_cnt ; dec number of bits left to send
tmr0isr_end: pop temp ;
out SREG,isr_save ; restore
reti
;--- rs-232 char reception isr, checks for errors and discards bad chars
uart_rx_isr: in isr_save,SREG ; store SREG
push temp
sbic USR, FE ; skip if framing error
rjmp uart_err ;
in temp, UDR ; get rx byte
sbic USR, OR ; skip if overrun error
rjmp uart_err ;
mov u_data,temp ; save actual data
sbr flags,(1<<uart_rx) ; set received data flag
rjmp uart_isr_end
uart_err: in temp, UDR ; read and discard byte to clear UDR
cbr flags,(1<<uart_rx) ; clear flag return
uart_isr_end: pop temp ; restore
out SREG,isr_save ; restore
reti
;------------------------------------------------------------------------
;--- start here on power up or external reset
;--- init ports, ints,
;--- zero all registers, maybe not necessary but a good idea while debugging
reset: ldi r16,0
ldi zl,0 ; beginning of registers
clr_reg: st z+,r16
cpi zl,0x1e ; don't zero z reg
brne clr_reg
;--- init stack pointer (somewhat important)
ldi temp,low(RAMEND) ; init stack
out spl,temp
;--- portb setup
ldi temp,(1 << cw_out)|(1 << poc_out)
out DDRB,temp
sbi PORTB,cfg_0 ; pull up
sbi PORTB,cfg_1 ; pull up
;--- portd setup
ldi temp,(1 << led)|(1 << cts_232)|(1 << txd_232)|(1 << ptt)
out DDRD,temp
;--- setup uart, 9600 baud, int on rx, no tx ints
ldi temp,((clock / console_baud) / 16) -1
out UBRR,temp ; Set baud rate generator
ldi temp, (1<<RXCIE)|(1<<RXEN)|(1<<TXEN) ; enable rxc interrupts
out UCR,temp ; enable UART tx & rx w/o interrupts
;--- set up tmr0
ldi temp,2 ; timer 0 prescale/8
out TCCR0,temp ;
ldi temp,0b00000010 ; enable Timer 0 interrupt
out TIMSK,temp
;--- global enable ints
sei ; enable global ints
ldi morse_rate,0x05 ; default morse wpm rate
_send_232_str _hello ; display sign on message
led_on ; flash the led
ldi temp,100
rcall del_hunds
led_off
rjmp cmd_top ; wait for command
error: _send_232_str _error
;----------------------------------------------
cmd_top: cbi PORTD,cts_232 ; enable comm
rcall crlf ; prompt
_send '.'
inp_loop: sbis PINB,inp_1 ; inp 1 or 2 down?
rjmp send_inp_1
sbis PINB,inp_2
rjmp send_inp_2
sbrs flags,uart_rx ; any console data?
rjmp inp_loop
rcall get_string
brcc pc+2 ; valid string?
rjmp cmd_top
ldi zl,ram_begin ; convert first char to upper case
ld temp,z
rcall to_upper
do_cmd: cpi temp,'D' ; set debug mode
brne pc+2
rjmp set_debug
cpi temp,'I' ; test inhibit line
brne pc+2 ; return status
rjmp check_inhibit
cpi temp,'M' ; send morse string
brne pc+2
rjmp send_morse
cpi temp,'R' ; get morse wpm
brne pc+2
rjmp set_m_rate
cpi temp,'G' ; get a message and store in eeprom
brne pc+2
rjmp get_eemsg
cpi temp,'S' ; send canned message from eeprom
brne pc+2
rjmp send_eemsg
cpi temp,'P' ; send pocsag message directly
breq send_con_str
rjmp cmd_top
;---------------------------------------------------------------------------------
;--- set and display debug mode
set_debug: lds temp,ram_begin+1 ; get arg
cpi temp,'0'
brne pc + 2
cbr flags, 1 << debug ; set appropriate flag
cpi temp,'1'
brne pc + 2
sbr flags, 1 << debug
_send_232_str _debug ; message
ldi temp,'0'
sbrc flags,debug
ldi temp,'1'
rcall putc ; send status
rjmp cmd_top
;--- test and return status of tx_inhibit line
check_inhibit: rcall crlf
ldi temp,'0'
sbic PINB,tx_inhibit
ldi temp,'1'
rcall putc
rjmp cmd_top
;--- send console string via morse
send_morse: sbi PORTD,cts_232
ldi ii,1
rcall pos_zl
mov xl,zl ; point to data
rcall key_radio
rcall send_cw_string
rcall unkey_radio
rjmp cmd_top
;--- set morse wpm rate
set_m_rate: ldi ii,1
rcall pos_zl
rcall asc2bin
mov morse_rate,bin
rjmp cmd_top
;--- send console string as pocsag directly
send_con_str: sbi PORTD,cts_232 ; disable comm
rcall count_param
cpi byte_cnt,6 ; check for minimum num of args
brsh pc + 2
rjmp error
rcall parse_msg ; parse out cap code and flags
rcall test_cap ; make sure cap code is within valid range
brcc pc +2
rjmp error
ldi ii,6
rcall pos_zl ; get pointer to message data
mov poc_char_pnt,zl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -