; t1_test1.asm - 1st test for 3niti alpha simu1 (Oct 2009 - Nov 2011)
; this code is PUBLIC DOMAIN, created bt Alexander A. Shabarshin <ashabarshin@gmail.com>

	processor pic16f870
	radix dec
	include "p16f870.inc"
	__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC
	include "shaos-p16.inc"

; PORTA - outputs to choose column (A0...A4) and direct LED (A5)
; PORTB - inputs for rows of switches (B0...B5) and I2C (B6,B7)
; PORTC - outputs for rows of LEDs (C0...C5) and RS232 (C6,C7)

bsize	EQU	27 ; -13...+13

; Variables

; Global vars 0x70...0x7F (all banks)

cnt1	EQU	0x75
cnt2	EQU	0x76
tmp0	EQU	0x77
tmp1	EQU	0x78
tmp2	EQU	0x79
tmpA	EQU	0x7A
tmpB	EQU	0x7B
tmpC	EQU	0x7C
mask	EQU	0x7D
count	EQU	0x7E

; Reset vector
	ORG 00h
	goto Start

; Interrupt vector
	ORG 04h
	retfie

Start:

; Configure all I/O pins as digital
	_bank1
	_movlr 0x06,ADCON1

; Set direction of ports
	_bank1
	_movlr b'00000000',TRISA
	_movlr b'00111111',TRISB
	_movlr b'11000000',TRISC

; Initialize output ports
	_bank0
	_movlr b'11111111',PORTA
	_movlr b'11111111',PORTB
	_movlr b'11111111',PORTC

; Setup interrupts
	_bank1
	clrf	INTCON ; disable all interrupts and clear all flags
	bcf	OPTION_REG,NOT_RBPU ; enable pull-ups
	bsf	OPTION_REG,INTEDG ; interrupt on rising edge
;	bsf	INTCON,INTE ; enable RB0 port change interrupt
;	bsf	INTCON,GIE ; enable interrupts

; Clear watch dog
	_bank0
	clrwdt

	goto	Main

; Ternary inversion (negation) of W (used tmp1,tmp2)
tri_neg: ; 14 cycles with call
	movwf	tmp1
	andlw	b'01010101'
	movwf	tmp2
	movf	tmp1,W
	andlw	b'10101010'
	movwf	tmp1
	bcf	STATUS,C
	rlf	tmp2,F
	rrf	tmp1,W
	iorwf	tmp2,W
	return
; P.S. it also works with inverted binary representation

Main:

; Test program to send state of ternary switches to ternary LEDs
loop:
	movlw	b'11111110' ; initial zero at bit 0
	movwf	mask ; save it as a mask
	movlw	5
	movwf	count ; set counter for 5 iterations
loop0:
	movf	mask,w
	movwf	PORTA ; send mask to the port A (to choose 3 switches/LEDs)
	_delay1 10,cnt1 ; wait
	movf	PORTB,w ; read byte from the port B (from the next 3 ternary switches)
	call	tri_neg ; ternary invertion (it's not a bug, it's a feature ;)
	movwf	PORTC ; send it to the port C (to the next 3 ternary LEDs)
	_delay1	0,cnt1 ; long wait
	movlw	b'11111111'
	movwf	PORTC ; clear the port C to avoid ghost lights...
	bsf	STATUS,C ; C = 1
	rlf	mask,f ; shift single zero in the mask to the left
	decfsz	count,f ; decrement counter and check if it's not a zero
	goto	loop0 ; next iteration
	goto	loop ; after 5 iterations start all over again...

	END
