Teletron.asm

;Apell 2012 04 24,
;Ekholm 20120509

;ver 2/EUF		eepromskrivning
;ver.3/UCZ 20120511   eepromskrivning vidare
;ver.4/EUF/UCZ 20120514 fixat eepromskrivningens buggar 
;ver.5/UCZ 20120515  fixat toggling mellan 100Hz och 1kHz stegning
;ver.6/UCZ 20120517  sänkt klockfrekvensen till 32kHz för att reducera störningar från processorn

;Program för att styra en en Teletron TE704C mottagare via en pulsgivare, VFO-ratt, för att ersätta tumhjulen.
;Programmet skrivet i MPLAB IDE v8.83... hämtas gratis hos microchip.com
;
;eftersom processorn endast har 25 I/O portar så har "10Hz" funktionen slopats.. sparar 4 bitar.
;då räcker portarna till precis!  Övriga önskemål av extra funktioner hindras effektivt av detta!!
;Alltså skall vi styra 6 siffror BCD  00.010.0 ... 29.999.9 kHz Lägsta frekvens 10kHz.
;när vfo-ratten stått still i 10 sekunder...sparas den frekvensen i eepromminnet, och kommer tillbaka vid nästa power on
;
;Att mottagaren inte är specad för mellanvågsbandet hanteras inte just nu!... den funkar där oxo!
;man ville förhindra rundradiomottagning på jobbet! Flera dämpkretsar i radion!

;Processorn jobbar med intern klocka 8MHz, alla faciliteter avstängda... vi ska bara räkna register upp och ner
;och skyffla data mellan register och utportar.

;*****[ Data Storage Reg's ]*****

		

        CBLOCK  0x20        	; Tilldela registerna olika namn från adressen 0x20
            enctempnew
			enctempold          ; Olika register till delayfunktionerna
            encod             
			Hz100
			kHz1
			kHz10
			kHz100
			MHz1
			MHz10
			xPORTA
			xPORTB
			xPORTC
			Flags
								
			VARVREG1			;Varvräknare för PROM-uppdateringar
			VARVREG2			;
			VARVREG3

			ENDC

						;tilldela enskilda bitar egna namn, lättare att läsa
#define 	encx   		PORTA,0    ; Encoder inputs
#define 	ency   		PORTA,1
#define		quick		PORTE,3		;snabbräknarknappen
#define		sparat		Flags,0		;flagga som sätts när frekvensen sparats
#define		enkHzstep	Flags,1		;flagga för 1kHz stegning
#define		enkHzflag	Flags,2		;flankflagga vid toggling 100Hz/1kHz




;**********************************************************************************

;Här talar vi om för assemblerprogrammet vilken processor vi har och vilka adresser
;som vi ska starta ifrån

	list    p=18f2520			;direktiv till assemblern om vilken process. som valts

	#include <p18f2520.inc>  	; processor specific variable definitions
	errorlevel  -302        	; Ignore error message when storing to Bank 1.
	  
	
;	__CONFIG _MCLRE_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _INT_OSC & _WRT_ENABLE_ON & _LVP_OFF & _CPD_OFF
;bitarna ställs i MPLAB manuellt! intern oscillator, MCLRE off, allt off! jag reder inte ut alla optionerna...
	org     0	     			;adress vid power on eller reset här startar programkörningen
	goto    init    			;gå till initiering av kretsen vid power on... längst ner i programmet.


;**********************************************************************************
;Och här kommer själva programkoden...

;En smart code från Alvaro för att läsa av en encoder!
;genom att läsa in förändringen och sen skifta bitarna höger/vänster
;och ta hjälp av "carry-flaggan" kan det konstateras åt vilket håll
;pulsgivaren vrides!


;Alvaro Deibe Diaz [adeibe at CDF.UDC.ES] says: 

; Encoder read

main
		call	skrivtimer			;kör timern och spara om tiden är mogen
		call	toggla				;kolla om stegningen skall togglas??

        clrf    enctempnew  		; cleara ett tempregister
        btfsc   encx       			; and get encoder inputs
        bsf     enctempnew,0   		; in bit 0...
        btfsc   ency
        bsf     enctempnew,1   		; ...and 1
		movf	enctempnew,w		;kolla om det är någon förändring på inkommande encodersignal??
		subwf	enctempold,w
		btfsc	STATUS,Z
		goto	main				;om inte...hoppa till main
		movf	enctempnew,w		;förändring har skett...skriv nya värdet i tempregistret "old"... för att kunna kolla nästa gång
		movwf	enctempold			;om pulsgivaren har snurrats
;
; Here starts the hard work			;nu vet vi att någon har fingrat på pulsgivaren.. men åt vilket håll??
        movf    enctempnew,W   		; encod <- (actual state) xor (previous one)
        xorwf   encod,F    			; (only bits 0 and 1 affected)
									;här kommer det smarta... rotera via "carry-flaggan"
        rrcf    enctempnew,F   		; XOR results, reordered, get
        rlcf    encod,F    			; into encod, in bits 0 and 1.
        rrcf    enctempnew,F   		; This bits are the motion indicators
        rlcf    encod,F
;
;At this point you have a new read of the encoder. Bits 2 and 3 of 'encod'
;have the information about the direction of movement of the encoder. If you
;have to translate this information into a variable, then you can do
;something like this:
;
	    btfsc   encod,2    			; Direction 'X' motion
        goto	countup				;hoppa till räkna upp
        btfsc   encod,3    			; ...or 'Y'
        goto 	countdown			;hoppa till räkna ner
		goto	main
;
;Bits 4,5 and 6,7 of 'encod' have the previous reads.


;***************************************************************************************************
toggla							;att toggla mellan 100Hz och 1kHz stegning varannan gång QUICK knappen tryckes
		btfsc	quick			;när quickknappen släppes reset flankflaggan
		goto	jmp15
		bcf		enkHzflag
		return
jmp15
		btfsc	enkHzflag		;kolla om flankflaggan är satt
		return					;då blir det return
		btfss	enkHzstep
		goto	jmp16
		bcf		enkHzstep
		bsf		enkHzflag
		return
jmp16	bsf		enkHzstep
		bsf		enkHzflag
		return


;************************************************************************************************
									;Att räkna upp är enkelt... men kolla därefter om registret blev "10"
									;då skall nästa siffra räknas upp!	vi räknar bara 0,1,2...9 BCD! i varje register								


countup
		btfsc	quick				;kolla om det skall snabbräknas, tryckknappen QUICK är TILL	
		goto	snabb

		btfsc	enkHzstep			;val mellan 100Hz eller 1kHz stegning
		goto	enkHzu

		incf	Hz100,f				;öka 100Hz med 1
		movlw	.10					;kolla om det blev "10". ladda in "10"
		subwf	Hz100,w				;minska registret med 10 och kolla om det blev "0" = Z
		btfss	STATUS,Z
		goto	display				;om inte "10" gå till displayvisning... bara denna siffran ändrade sig

enkHzu								;toggling mellan 100Hz/1kHz stegning
		clrf	Hz100				;om lika med "10" sätt Hz till "0"
		incf	kHz1,f				;öka 1kHz siffran istället
		movlw	.10
		subwf	kHz1,w				;kolla om "10"
		btfss	STATUS,Z
		goto 	display
									;och lika för alla siffrorna
		clrf	kHz1				
		incf	kHz10,f				;10kHz
		movlw	.10
		subwf	kHz10,w				
		btfss	STATUS,Z
		goto 	display

		clrf	kHz10			
snabb	btfsc	quick				;nollställ de lägsta siffrorna vid snabbscrollning
		call	clearas
		incf	kHz100,f			;hoppa hit direkt vid snabbräkning
		movlw	.10
		subwf	kHz100,w			;100kHz
		btfss	STATUS,Z
		goto 	display

		clrf	kHz100			
		incf	MHz1,f				;1MHz
		movlw	.10
		subwf	MHz1,w				
		btfss	STATUS,Z
		goto 	display

		clrf	MHz1				
		incf	MHz10,f				;10MHz	
		movlw	.10
		subwf	MHz10,w				
		btfss	STATUS,Z
		goto 	display
		
		goto	display

;*************************************************************************************************
									;Att räkna ner är inte lika enkelt när vi skall hålla oss till siffrorna 0...9 i BCD format

countdown
		btfsc	quick				;kolla om det skall snabbräknas
		goto	jmpq				;hoppa då till 100kHz siffran direkt
		
		btfsc	enkHzstep			;val mellan 100Hz eller 1kHz stegning
		goto	enkHzd

		movf    Hz100, w            ;kolla först om det är "0" i Hz100, då är det nästa siffra som skall räknas ner
  		btfsc   STATUS, Z 			;genom att ladda i filen i w så sätts Z om det är noll
   		goto	jmp1				;det är "0" hoppa till nästa siffra
  		decf   	Hz100, f			;inte "0" då stegar vi ner ett hack
		goto	display				;det blir bara denna siffra som skall räknas ner...gå direkt till visning
jmp1
		movlw	.9					;skriv in "9" i föregående siffra...den var ju "0" innan
		movwf	Hz100
enkHzd
		btfsc	enkHzstep
		clrf	Hz100				;toggling mellan 100Hz/1kHz stegning
		movf	kHz1,w				;kolla så det inte är "0"
		btfsc	STATUS,Z
		goto	jmp2
		decf   	kHz1, f          	;  1kHz
		goto	display

jmp2
		movlw	.9
		movwf	kHz1
		movf	kHz10,w				
		btfsc	STATUS,Z
		goto	jmp3
		decf   	kHz10, f          	;  10kHz
		goto	display

jmp3		
		movlw	.9
		movwf	kHz10
jmpq	btfsc	quick				;nollställ de lägsta siffrorna vid snabbscrollning
		call	clearas
		
		movf	kHz100,w			;hoppa hit om det skall snabbräknas
		btfsc	STATUS,Z
		goto	jmp4
		decf   	kHz100, f          	;100kHz
		goto	display

jmp4		
		movlw	.9
		movwf	kHz100
		movf	MHz1,w
		btfsc	STATUS,Z
		goto	jmp5
		decf   	MHz1, f          	; 1Mhz
		goto	display

jmp5		
		movlw	.9
		movwf	MHz1
		movf	MHz10,w
		btfsc	STATUS,Z
		goto	jmp6
		decf   	MHz10, f          	;  10MHz
		goto	display

jmp6	clrf	MHz10
		goto	display

clearas
		clrf	Hz100
		clrf	kHz1
		clrf	kHz10
		return

;****************************************************************************************************
;kolla om det är under 10kHz!! Mottagaren funkar inte där!

lågkoll
		movlw	.0					;genom att kolla om alla BCD är "0"
		subwf	MHz10,w				;kan det fastställas om frekvensen
		btfss	STATUS,Z			;är under 10kHz
		return
		movlw	.0
		subwf	MHz1,w
		btfss	STATUS,Z
		return
		movlw	.0
		subwf	kHz100,w
		btfss	STATUS,Z
		return
		movlw	.0
		subwf	kHz10,w
		btfss	STATUS,Z
		return						;inte under 10kHz...tebaks

									;det blev under 10kHz	
		movlw	.9					;skriv in 29.999.9kHz
		movwf	Hz100
		movwf	kHz1
		movwf	kHz10
		movwf	kHz100
		movwf	MHz1
		movlw	.2
		movwf	MHz10
		
		return

;********************************************************************************************************

;kolla om det är över 29.999.9 kHz.. då skriver vi in 10kHz

högkoll
		movlw	.3				;det är över 29.999.9...alltså 30.XXX.XXX
		subwf	MHz10,w			;det räcker att kolla om 10MHz är "3"
		btfss	STATUS,Z
		return					;inte över...tebaks

cleara	clrf	Hz100			;över...då rensar vi alla siffror
		clrf	kHz1
		clrf	kHz10
		clrf	kHz100
		clrf	MHz1
		clrf	MHz10
		movlw	.1				;och skriver in 10kHz
		movwf	kHz10
		return
		

;******************************************************************************************************
									;Nu är det dax att flytta ut resultaten till mottagaren och displayen
									;för att det inte skall bli flimmer så sorterar vi upp alla bitarna till
									;sina rätta platser i temporära register.
									;därefter kopieras dessa register ut till verkligheten

display
		call	lågkoll				;kolla först om värdet är under eller över tillåtet
		call	högkoll				;att vi håller oss inom mottagaren specifikationer
 
		clrf	xPORTA				;flytta över varje bit till sin plats i utporten
		btfsc	MHz10,0				;först i ett tempregister, sen ut till porten
		bsf		xPORTA,2			;enklast är att rensa registret först
		btfsc	MHz10,1				;och sen skriva in i respektive bit en "1" om det skall vara en.
		bsf		xPORTA,3			;10MHz

		btfsc	MHz1,0
		bsf		xPORTA,4
		btfsc	MHz1,1				;1MHz
		bsf		xPORTA,5
		btfsc	MHz1,2
		bsf		xPORTA,6
		btfsc	MHz1,3
		bsf		xPORTA,7

		clrf	xPORTB
		btfsc	kHz10,0
		bsf		xPORTB,0
		btfsc	kHz10,1				;10kHz
		bsf		xPORTB,1
		btfsc	kHz10,2
		bsf		xPORTB,2
		btfsc	kHz10,3
		bsf		xPORTB,3

		btfsc	kHz100,0
		bsf		xPORTB,4
		btfsc	kHz100,1
		bsf		xPORTB,5			;100kHz
		btfsc	kHz100,2
		bsf		xPORTB,6
		btfsc	kHz100,3
		bsf		xPORTB,7
  
		clrf	xPORTC
		btfsc	Hz100,0
		bsf		xPORTC,0
		btfsc	Hz100,1
		bsf		xPORTC,1			;100Hz
		btfsc	Hz100,2
		bsf		xPORTC,2
		btfsc	Hz100,3
		bsf		xPORTC,3

		btfsc	kHz1,0
		bsf		xPORTC,4
		btfsc	kHz1,1
		bsf		xPORTC,5			;1kHz
		btfsc	kHz1,2
		bsf		xPORTC,6
		btfsc	kHz1,3
		bsf		xPORTC,7

		movf	xPORTA,w			;och här flyttas det ut till verkligheten!
		movwf	PORTA
		movf	xPORTB,w
		movwf	PORTB
		movf	xPORTC,w
		movwf	PORTC
		
		clrf	VARVREG1			;nollställ skrivtimern till eepromskrivningen
		clrf	VARVREG2			;pulsgivaren är fingrad...
		movlw	.10					;ger ca 10 sek fördröjning av dataskrivningen till eeprommet
		movwf	VARVREG3
		bcf		sparat				;frekvensen är ändrad från tidigare sparade...tillåt ny arkivering i eeprom
		goto	main

;***************************************************************************************
									;Timer som fördröjer skrivningen till minnet ca 10 sekunder
									;efter det man slutat att vrida på vfo-ratten
								
skrivtimer							;med VARVREG3=10 så ca 10 sek fördröjning		;
		decfsz	VARVREG1,f			;Minska inre loop med 1
		return						;Om INTE =0 gör ett varv till
;		decfsz	VARVREG2,f			;Minska yttre loop med 1... vid 32kHz klocka slopas denna!
;		return						;Gör ett varv till
		decfsz	VARVREG3,f
		return
		call	spara				;här har den yttre räknaren blivit "0" spara i eeprom!!
		return
;*******************************************************************************************
;                      Write Byte to EEPROM... rutin som anropas vid varje byte skrivning
;
; Input: Adress och data måste ligga i EEADR och EEDATA när rutinen anropas

WriteEEPROM:   
		banksel	EECON1      
		bcf		EECON1,EEPGD
		bcf		EECON1,CFGS
		bsf		EECON1,WREN			; start the write (must follow this sequence exactly!)
		bcf		INTCON,GIE
		movlw	55h
		movwf	EECON2  			; Write 55h
		movlw	0AAh
		movwf	EECON2  			; Write AAh
		bsf		EECON1,WR 			; Set WR bit starta skrivningen
		bsf		INTCON,GIE			; write now in progress
jmpee	btfss	PIR2,EEIF			;vänta tills interruptflaggan kommer...skrivningen färdig
		goto	jmpee
		bcf		EECON1,WREN			;stäng skrivmöjligheten
		bcf		PIR2,EEIF			;reset interruptflaggan
		banksel 0
		
		return 
;----------------------------------------------------------------------
;                   Read Byte from EEPROM
;Adressen måste finnas i EEADR när rutinen anropas
;datat ligger i w när rutinen lämnas
; Input:  W=address 
; Output: W=Byte
;
ReadEEPROM:
		banksel	EECON1
wait_read:
		btfsc	EECON1,RD			; wait for end of previous read  
		goto	wait_read			;
		bcf		EECON1,EEPGD
		bcf		EECON1,CFGS
		bsf		EECON1,RD			;initiate READ
		movf	EEDATA,W			;transfer Byte to W
		banksel	0
		RETURN 

;----------------------------------------------------------------------
									;frekvensen sparas 10 sekunder efter det att vfo-ratten slutat att vridas
;Skriv från resp. "siffra" till EEPROM
	
spara
		btfsc	sparat				;kolla om samma frekvens redan är sparad! Spärrflaggan är satt
		return						;den är redan sparad...tebaks

		movlw	.0					;spara undan 100Hz
		movwf	EEADR				;först rätt adress
		movf	Hz100,w
		movwf	EEDATA				;och sen rätt data
		call	WriteEEPROM			;skickas till eepromskrivningen

		movlw	.1					;spara undan 1kHz
		movwf	EEADR
		movf	kHz1,w
		movwf	EEDATA
		call	WriteEEPROM
	
		movlw	.2					;spara undan 10kHz
		movwf	EEADR
		movf	kHz10,w
		movwf	EEDATA
		call	WriteEEPROM

		movlw	.3					;spara undan 100kHz
		movwf	EEADR
		movf	kHz100,w
		movwf	EEDATA
		call	WriteEEPROM

		movlw	.4					;spara undan 1MHz
		movwf	EEADR
		movf	MHz1,w
		movwf	EEDATA
		call	WriteEEPROM

		movlw	.5					;spara undan 10MHz
		movwf	EEADR
		movf	MHz10,w
		movwf	EEDATA
		call	WriteEEPROM

;		clrf	PORTC				;släcker porten som kvitto på att skrivningen är färdig...för testningen
		bsf		sparat				;sätt flaggan frekvensen sparad.... resetas när pulsgivaren vrides

		return						;skrivningen är färdigt...tebaks

;********************************************************************************************
								;detta anropas vid power on och läser in senast sparade frekvensen
läseeprom

		movlw	.0				;Promadr 0 till w
		movwf	EEADR			; 
		call	ReadEEPROM
		movwf	Hz100			;läsningen finns i w bara att pytsa ut i rätt file

		movlw	.1				;Promadr 1 till w
		movwf	EEADR			; 
		call	ReadEEPROM
		movwf	kHz1			;läsningen finns i w bara att pytsa ut i rätt file

		movlw	.2				;Promadr 2 till w
		movwf	EEADR			; 
		call	ReadEEPROM
		movwf	kHz10			;läsningen finns i w bara att pytsa ut i rätt file

		movlw	.3				;Promadr 3 till w
		movwf	EEADR			; 
		call	ReadEEPROM
		movwf	kHz100			;läsningen finns i w bara att pytsa ut i rätt file

		movlw	.4				;Promadr 4 till w
		movwf	EEADR			; 
		call	ReadEEPROM
		movwf	MHz1			;läsningen finns i w bara att pytsa ut i rätt file

		movlw	.5				;Promadr 5 till w
		movwf	EEADR			; 
		call	ReadEEPROM		;hämta från eeprommet
		movwf	MHz10			;

		movlw	0FFH			;nytt chip kan ha FF i minnena
		subwf	MHz1,w			;kollar bara en siffra...
		btfsc	STATUS,Z
		call	cleara			;i så fall rensa och skriv in 10kHz
		call	display			;pytsa ut värdena på displayen
		
		return
;****************************************************************************************

init						;initiering av kretsen vid power on

		
	clrf	PORTA			;rensa först alla portar
	clrf	PORTB			;så inte siffrorna fladdrar till vid power on
	clrf	PORTC
	clrf	PORTE
	clrf	LATA
	clrf	LATB

	movlw	0fh
	movwf	ADCON1			;gör analogmodulen till vanliga I/O
	movlw	07h
	movwf	CMCON			;gör komparatormodulen till vanliga I/O

	movlw	b'10001111'
	movwf   OSCCON			;(sätt 8MHz klocka) klockan reducerad till 32kHz!

	movlw 	b'00000011'		;fixa till två ingångar till pulsgivaren RA0 + RA1
	movwf	TRISA			;1=Input   0=output
	clrf	TRISB			;alla övriga portar göres till utgångar
	clrf	TRISC
							;ingången RE3 är alltid en ingång...behöver ej sättas

	clrf	Hz100			;säkerställ att registren är rena vi använder bara 4 av 8 bitar i varje register
	clrf	kHz1
	clrf	kHz10
	clrf	kHz100
	clrf	MHz1
	clrf	MHz10
	clrf	Flags

	call	läseeprom		;läs in från minnet till frekvensen vid start upp
	movlw	.5
	movwf	VARVREG3		;förställ timern för skrivintervallerna

	goto    main   			;gå till huvudprogrammet
	
	end				