⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rds decoder.asm

📁 An RDS decoder using the MC68hc05
💻 ASM
字号:
; ----------------------------------------------------
;
; RDS decoder -- pic code 
; by AHDL
;
; Config : PIC 16F84 / 4.332 / PUT enabled / XT
;
; TDA7330 demodulator
;
; (c) 2000 Andy Dewilde (xxx@xxx.xx)
; and      Lieven Hollevoet (picmicro@hollie.tk)
;   		
;
; Re-use and modification of this code is hereby 
; permitted, as long as the names and e-mail 
; addresses of both authors are mentioned in the new 
; version.
; ----------------------------------------------------

	
#include "P16F84.INC"

	LIST	p=PIC16F84
	

	__CONFIG	_CP_OFF & _PWRTE_ON & _WDT_OFF & _XT_OSC
	


; -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
; definitions
; -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

; *** PORTS ***
#DEFINE	rdsClock	0x00	; RB0 = rds clock, input
#DEFINE	rdsData		0x01	; RB1 = rds data, input
#DEFINE	TxD		0x02	; RB2 = transmit line


; *** MACROS ***
#DEFINE bank0		bcf STATUS, RP0
#DEFINE bank1		bsf STATUS, RP0

; *** CONSTANTS ***
#DEFINE dump		0x04

; *** REGISTERS ***
; used by rds routines
Reg1A		EQU	0x10
Reg1B		EQU	0x11
Reg2A		EQU	0x12
Reg2B		EQU	0x13
Reg3A		EQU	0x14
Reg3B		EQU	0x15
Reg4A		EQU	0x16
Reg4B		EQU	0x17

StoReg1		EQU	0x18
StoReg2		EQU	0x19
StoReg3		EQU	0x1A
StoReg4		EQU	0x1B
StoReg1X	EQU	0x1C
StoReg2X	EQU	0x1D
StoReg3X	EQU	0x1E
StoReg4X	EQU	0x1F

HiReg		EQU	0x20
LoReg		EQU	0x21

Loper		EQU	0x23
CountReg	EQU	0x24

DelayReg	EQU	0x25
Counter		EQU	0x2E

; used by serial routines
Locatie		EQU	0x26
LoopCount	EQU	0x27

TmrVal		EQU	0x28
TxChar		EQU	0x29

; used by the isr
W_Temp		EQU	0x2A
Status_Temp	EQU	0x2B

; used to store the PS information
; WARNING: DO NOT change these values,
; these locations are used in calcs!
Char0		EQU	0x30
Char1		EQU	0x31
Char2		EQU	0x32
Char3		EQU	0x33
Char4		EQU	0x34
Char5		EQU	0x35
Char6		EQU	0x36
Char7		EQU	0x37
Flags		EQU	0x38	; For PTY, TA (traffic announcement), TP (traffic programma)


; -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
; This is the begin of the main loop code
; -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
	ORG 0x00		; reset vector
	goto 	_main

	ORG 0X04		; interrupt vector
	goto 	_isr


; ---------------- _main ----------------------------------------
;
; Initialisation of the I/O ports and several variables that are 
; used throughout the program, also clears ram locations
; 
; ---------------------------------------------------------------
_main	
	bcf 	STATUS, RP0	; Set up I/O ports A & B
	clrf	PORTA		
	bsf	STATUS, RP0
	movlw	0x00
	movwf	TRISA		; A = unused (set all as output)

	bcf	STATUS, RP0	; PORTB is used as:
	clrf	PORTB		;   RB0 = rds clock, input 
	bsf	STATUS, RP0	;   RB1 = rds data, input
	movlw	0x03		;   RB2 = serial data, output
	movwf	TRISB		;   

	movlw	dump		; Determines after how many blocks a dump will be triggered
	movwf	LoopCount	

	clrwdt			; Change prescaler assignment (in case we use TMR0)
	bsf	STATUS, RP0	; Enable pull-up
	movlw	b'01010000'	; Enable TMR0
	movwf	OPTION_REG
 	bcf	STATUS, RP0

	bsf	PORTB, TxD	; pull TxD line high
	

	movlw	0x30		; Clear RAM locations for PS info
	movwf	FSR		; initialize pointer
_nloc	clrf	INDF		; clear INDF register
	incf	FSR, F		; increase pointer
	btfss	FSR, 3		; stop on 0x38
	goto	_nloc

	call	_send
; --------------------------------------------------------------------
; *************** Start the detection of RDS blocks ******************
; --------------------------------------------------------------------

; ----- _block1 -----------------------------------------------------
; 
; FUNCTION: searches for an A-datablock in the incoming datastream
;	using the 'bit-slip'(tm) method. It shift all the previous
; 	bits and inserts the newly read bit as LSB
;	Then it calculates the syndrome and checks for block A
;	This subroutine actually synchronizes the algorithm 
;	with the incoming bitstream
;
; USES:		_getBit
;
; FALLS INTO: 	_block2
;
; --------------------------------------------------------------------
_block1				; Search for syndrome A (using the bit-slip(tm) method)
	call	_getBit		; wait for new databit, get syndrome
	movlw	0xF6		; syndrome A?
	xorwf	HiReg, W	;    check 8 MSB's
	btfss	STATUS, Z
	goto	_block1		; again
	clrw
	xorwf	LoReg, W	;    check the LSB's
	btfss	STATUS, Z
	goto	_block1		; again
	movf	StoReg1, W	; store *** block 1 data ***
	movwf	Reg1A
	movf	StoReg2, W
	movwf	Reg1B


; ----- _block2 -----------------------------------------------------
; 
; FUNCTION: reads the next 26 incoming bits and checks the syndrome
;
; USES:		_get26Bits, interrupt service routine, _syndrome, _block1
;
; FALLS INTO: 	_block3
;
; -------------------------------------------------------------------
_block2
	call	_get26Bits	; read the next 26 bits
	
	movlw	0xF5		; syndrome B?
	xorwf	HiReg, W
	btfss	STATUS, Z
	goto	_block1		; again
	clrw
	xorwf 	LoReg, W
	btfss	STATUS, Z
	goto	_block1		; again
	movf	StoReg1, W	; store *block 2 data*
	movwf	Reg2A
	movf	StoReg2, W
	movwf	Reg2B


; ----- _block3 -----------------------------------------------------
; 
; FUNCTION: reads the next 26 incoming bits and checks the syndrome
;		this routine handles blocks of type C and C'
;
; USES:		_get26Bits, interrupt service routine, _syndrome, _block1
;
; FALLS INTO: 	_block4
;
; -------------------------------------------------------------------
_block3
	call	_get26Bits	; read the next 26 bits

	movlw	0x97		; syndrome C?
	xorwf	HiReg, W
	btfsc	STATUS, Z
	goto	_block3_lo
	movlw	0xF3		; syndrome C'?
	xorwf	HiReg, W
	btfss	STATUS, Z
	goto	_block1		; again

_block3_lo
	clrw
	xorwf	LoReg, W
	btfss	STATUS, Z
	goto	_block1		; again
	movf	StoReg1, W	; store *block 3 data*
	movwf	Reg3A
	movf	StoReg2, W
	movwf	Reg3B


; ----- _block4 -----------------------------------------------------
; 
; FUNCTION: reads the next 26 incoming bits and checks the syndrome
;
; USES:		interrupt service routine, _syndrome, _block1
;
; FALLS INTO: 	_getps
;
; -------------------------------------------------------------------
_block4
	call	_get26Bits	; read the next 26 bits
	
	movlw	0x96		; syndrome D?
	xorwf	HiReg, W
	btfss	STATUS, Z
	goto 	_block1		; again
	clrw
	xorwf	LoReg, W
	btfss	STATUS, Z
	goto	_block1		; again
	movf	StoReg1, W	; store *block 4 data*
	movwf	Reg4A
	movf	StoReg2, W
	movwf	Reg4B

; --------------------------------------------------------------------
; *************** Process the data & extract info   ******************
; --------------------------------------------------------------------

; ----- _getdata ----------------------------------------------------
; 
; FUNCTION: 	Extract the PS/PTY/TP/TA from the group data (group 0A/0B)
;
; USES:		_block1
;
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_getdata				
	movf	Reg2A, W
	andlw	0xF0		; Check for group 0A/B
	xorlw	0x00		
	btfss	STATUS, Z
	goto	_block1		; start all over again

				; REG4A & REG4B now contain 2 chars of PS
	movf	Reg2B, W	; read char position
	andlw	0x03		; mask bits
	movwf	Locatie		; save position
	rlf	Locatie, F	; x 2
	movlw	0x30		; calculate mempos
	addwf	Locatie, W
	movwf	FSR		; write char using indirect adressing
	movf	Reg4A, W
	movwf	INDF
	incf	FSR, F
	movf	Reg4B, W
	movwf	INDF

	
	movlw	0x38		; Now get TP(1)/PTY(5)/TA(1) code (Block B, bit 10-4)
	movwf	FSR
	rlf	Reg2B, F	; ! Reg2B & REG2A are changed here (to save clock ticks)
	rlf	Reg2A, F
	rlf	Reg2B, F
	rlf	Reg2A, F
	rlf	Reg2B, F	
	rlf	Reg2A, F
	rlf	Reg2B, F
	rlf	Reg2A, W

	movwf	INDF

	decfsz	LoopCount, F	; decrease loop counter, if 0 => dump
	goto	_block1
	movlw	dump
	movwf	LoopCount
	call	_dump
	goto 	_block1
	

; --------------------------------------------------------------------
; ************************* Subroutines ******************************
; --------------------------------------------------------------------

; ----- _getBit -----------------------------------------------------
; 
; FUNCTION: used to sync the algortihm with the incoming bitstream
;
; USES:		_shuffle, _syndrome
;
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_getBit
	btfss	PORTB, rdsClock	
	goto 	_getBit		; wait for RDCL to go high
	call	_shuffle	; shuffle new bit into stack
	call	_syndrome	; get syndrome
	return


; ----- _get26Bits --------------------------------------------------
; 
; FUNCTION: 	read next 26 bits from the incoming bitstream
;
; USES:		_syndrome
;
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_get26Bits
	movlw	0x1A		; read 26 bits
	movwf	Loper		; save value in Loper
	movlw	0x90		; enable interrupt (INT/RB0)
	movwf	INTCON		

_get26Lus
	movf	Loper, F	; just to check if Loper = zero
	btfss	STATUS, Z	
	goto 	_get26Lus
	movlw	0x00		; Now, the 26 bits are read, disable interrupts
	movwf	INTCON
	call 	_syndrome
	return

	
; ----- _shuffle ----------------------------------------------------
; 
; FUNCTION: shuffle the working registers containing the incoming data
;
; USES:		nothing
;
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_shuffle
	bcf	STATUS, C
	btfsc	PORTB, rdsData	; incoming bit
	bsf	STATUS,	C
	rlf	StoReg4, F	; shuffle
	rlf	StoReg3, F
	rlf	StoReg2, F
	rlf	StoReg1, F
	return


; ----- _syndrome ---------------------------------------------------
; 
; FUNCTION: determine the syndrome, using the data from the working
;		registers and the check-matrix in program memory
;
; USES:		_matrixHi, _matrixLo, _delay
;
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_syndrome			; Multiply the 26 bits by the 26x10
	movlw 	0x1A		; check-matrix H to produce a 10-bit
	movwf 	CountReg	; syndrome...
	clrf 	HiReg		; Hireg/Loreg will eventually contain
	clrf 	LoReg		; the syndrome
	movf 	StoReg4, W
	movwf 	StoReg4X
	movf 	StoReg3, W
	movwf 	StoReg3X
	movf 	StoReg2, W
	movwf 	StoReg2X
	movf 	StoReg1, W
	movwf 	StoReg1X
_loops
	rlf 	StoReg4X, F	; shuffle stack by 1 bit
	rlf 	StoReg3X, F
	rlf 	StoReg2X, F
	rlf 	StoReg1X, F
	btfss 	STATUS, C	; was it a `1'?
	goto 	_loopx		; for a `0'
	movf 	CountReg, W
	call 	_matrixHi	; get appropriate row from matrix
	xorwf 	HiReg, F	; and exclusive OR it
	movf 	CountReg, W
	call 	_matrixLo	; do same for last 2 bits of matrix row
	xorwf 	LoReg, F
	decfsz 	CountReg, F
	goto 	_loops		; repeat this 26 times, in less than 842uS
	return
_loopx				; this is trap for `0', no exclusive OR
	movlw 	0x03		; just padding to avoid reading the
	call 	_delay		; same bit twice
	decfsz 	CountReg, F
	goto 	_loops
	return


; ----- _delay ------------------------------------------------------
; 
; FUNCTION: causes a delay :-)
;
; USES:		the present value of the W register
;
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_delay				; delay
	movwf 	DelayReg
_del
	decfsz 	DelayReg, F
	goto 	_del
	return


; ----- _MatrixHi ---------------------------------------------------
; (info on the checkmatrix extracted from Wireless World, '89)
;
; FUNCTION: contains the 8 upper-most bytes of the checkmatrix
;
; USES:		the present value of W register
;
; RETURNS:	the requested data from the checkmatrix
;
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_matrixHi			
	addwf 	PCL, F		
	nop			; nop needed because adding to PC causes 2 cycles
	retlw 	0xC6		
	retlw 	0xE3
	retlw 	0xA9
	retlw 	0x3D
	retlw 	0x7B
	retlw 	0xF7
	retlw 	0x80
	retlw 	0x6E
	retlw 	0xDD
	retlw 	0xD5
	retlw 	0xC4
	retlw 	0xE7
	retlw 	0xA1
	retlw 	0x2D
	retlw 	0x5B
	retlw 	0xB7
	retlw 	0x00
	retlw 	0x00
	retlw 	0x01
	retlw 	0x02
	retlw 	0x04
	retlw 	0x08
	retlw 	0x10
	retlw 	0x20
	retlw	0x40
	retlw 	0x80


; ----- _MatrixLo ---------------------------------------------------
; (info on the checkmatrix extracted from Wireless World, '89)
;
; FUNCTION: contains the 2 lower-most bytes of the checkmatrix
;
; USES:		the present value of W register
;
; RETURNS:	the requested data from the checkmatrix
;
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_matrixLo			
	addwf 	PCL, F
	nop			; needed because adding 1 to PC jumps 2 steps
	retlw 	0xC0
	retlw 	0xC0
	retlw 	0xC0
	retlw 	0xC0
	retlw 	0x80
	retlw 	0x00
	retlw 	0x40
	retlw 	0xC0
	retlw 	0x80
	retlw 	0x40
	retlw 	0xC0
	retlw 	0xC0
	retlw 	0xC0
	retlw 	0xC0
	retlw 	0x80
	retlw 	0x00
	retlw 	0x40
	retlw 	0x80
	retlw 	0x00
	retlw 	0x00
	retlw 	0x00
	retlw 	0x00
	retlw 	0x00
	retlw 	0x00
	retlw 	0x00
	retlw 	0x00


; ----- _dump -------------------------------------------------------
; 
; FUNCTION: 	Dumps the memory contents of locations 30h - 37h
;		to the serial port
;
; USES:		nothing
;
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_dump
	movf	Char0, W	
	call	_send
	movf	Char1, W
	call	_send
	movf	Char2, W
	call	_send
	movf	Char3, W
	call	_send
	movf	Char4, W
	call	_send
	movf	Char5, W
	call	_send
	movf	Char6, W
	call	_send
	movf	Char7, W
	call	_send
	movf	Flags, W
	call	_send
	return

; ----- _send ------------------------------------------------------
;
; FUNCTION:	Transmits the byte that is in W register 9600, 8N1
;
; USES:		_sendDelay 
;
; FALLS INTO: 	_sendDelay
; ----------------------------------
_send	
	movwf	TxChar
	movlw	8
	movwf	Counter

	
	bcf	PORTB, TxD	; send the startbit
	call 	_sendDelay	; delay
_loop	
	bcf	STATUS, C
	rrf	TxChar, F
	btfss	STATUS, C
	goto	_zendNul
	bsf	PORTB, TxD
	goto	_wait

_zendNul
	bcf	PORTB, TxD

_wait
	call	_sendDelay
	decfsz	Counter, F
	goto	_loop
_eos	bsf	PORTB, TxD	; send the stopbit
	
	; hier geen return, er is nog een senddelay nodig voor stopbit !

; ---------------------
; Serial send delay
; ---------------------
_sendDelay
	movlw	d'33'
	movwf	DelayReg
_serlus
	decfsz	DelayReg, F
	goto	_serlus	
	return


; ----- _isr -------------------------------------------------------
; 
; FUNCTION: 	Takes care of interrupt calls.
;		
;	In case of a RB0/INT change interrupt -> reads the next bit
;	
; USES:		_shuffle
; 
; FALLS INTO: 	nothing
;
; -------------------------------------------------------------------
_isr	; Interrupt service routine
_push
	movwf	W_Temp          ; save W
        swapf	STATUS, W       ; save status
        movwf	Status_Temp     ; without changing flags

	call 	_shuffle	; it was the bit-read routine
	decf	Loper, F
	bcf	INTCON, INTF

_pop
	swapf 	Status_Temp, W  ; get original status back
	movwf 	STATUS          ; into status register
	swapf	Status_Temp, F  ; old no flags trick again
	swapf 	Status_Temp, W  ; to restore W
	
	retfie                  ; finished

	END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -