; This is for reading voltge from ADC input and transmitting as ASCII string of characters
; Started 19/02/2017
; Modified to disable USART receive after recognising station ID (18/03/17)
;******************************************************************************************
;
;******************************************************************************************
;
; OSC : Internal OSC 4 MHz
;
;******************************************************************************************
LIST P=PIC12F1840,ST=OFF,R=DEC
INCLUDE "P12F1840.inc"
__CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_HI & _LVP_OFF
;*******************************************************************************
; Constants
;*******************************************************************************
Station_ID equ 'D' ;Station identification character for this station
RAM_START equ 0x20
; The periods are timed with timer1 which is set to run at the internal clock
; rate (4 Mhz) of Fosc/4 or 1.0MHz which is equal to a 1 uS period.
;DELAY_6MS equ D'2993' ;Value to give delay of 6 mS
RX_Timer equ D'200'
;*******************************************************************************
; Pin Assignments
;*******************************************************************************
;
; PIC signals
;
#DEFINE TX_Data PORTA, 0 ;
#DEFINE RX_Data PORTA, 1 ;
;
#DEFINE AN2 PORTA, 2 ; Analogue input
; #DEFINE Button PORTA, 3 ; Push button to trigger read (Not used)
; I/O pin use
; RA0 TX (Pin 7) (To pin 4 on programmer connection)
; RA1 RX (Pin 6) (To pin 5 on programmer connection)
; RA2 Analogue input (Pin 5)
; RA3 Trigger button (Pin 4) NOTE THIS PIN CAN ONLY BE USED AS AN INPUT.
; (This is VPP for programming This could be connected to pin 3 or 5 of the header to program the chip on header.)
; RA4 (AN3) Not used (Pin 3)
; RA5 (Pin 2)
; Define GENERAL PURPOSE RAM AREA (80 bytes maximum)
;*******************************************************************************
; File Register Variables
;*******************************************************************************
cblock RAM_START
param1: 1 ; parameter 1 (Used in delay cycles routine)
param2: 1 ; parameter 2 (Used in delay cycles routine)
Temp_1: 1 ;Used in 2 second delay
tmpData: 1 ; Used in output_hexbyte routine
; delay counters
Del_Count: 1
ADC_Temp_L: 1
ADC_Temp_H: 1
; byte counter
bytcnt: 1
ESEVN: 1 ; 10 000,000 (digit 8)
ESIX: 1 ; 1000,000s (digit 7 )
EFIVE: 1 ; 100,000s digit 6 store
EFOUR: 1 ; 10,000s digit 5 store
ETHREE: 1 ; 1000s digit 4 store
ETWO: 1 ; 100s digit 3 store
EONE: 1 ; 10s digit 2 store
EZERO: 1 ; 1's digit 1 store
COUNT: 1
BCD1: 1 ; overrange
BCD2: 1 ; MS decimal value
BCD3: 1 ;
BCD4: 1 ; decimal value
BCD5: 1 ; ls decimal value
BIN1: 1 ; LS binary value
BIN2: 1 ;
BIN3: 1 ;
BIN4: 1 ; MS binary value
TEMP: 1
RX_Count: 1
endc
;*******************************************************************************
; Common RAM (0x70 to 0x7F)
;*******************************************************************************
TX_temp EQU 0x70 ;Temporary storage for character to be transmitted.
RX_Temp EQU 0x71 ;Temporary storage for received character.
BS_Temp EQU 0x72 ;Temporary storage for "W" during bank select
;*******************************************************************************
; Define Macro Takes 2 uS
;*******************************************************************************
SELBANK MACRO #BANK_NO
MOVLB #BANK_NO ;1 cycle - 1 uS
ENDM
; *****************************
ORG 0h
GOTO START
ORG 4h
GOTO START
START
; *****************************
; Initialized Segment
; *****************************
; Initialise OSC (4MHz, IntOSC)
SELBANK 1 ; SET BANK1
MOVLW B'11101010'
MOVWF OSCCON
BCF INTCON,GIE
; Initialise I/O port
SELBANK 1 ; SET BANK1
MOVLW B'00001110' ; Bits 0, 4, 5 output Bit 1, 2, 3 input.
MOVWF TRISA
;Set pullup on PORTA,3
BCF OPTION_REG,NOT_WPUEN
SELBANK 4 ; SET BANK 4
MOVLW B'00001000'
MOVWF WPUA
SELBANK 3 ; SET BANK 3
MOVLW B'00000100'
MOVWF ANSELA ; Set bit 2 as analogue, set the rest to digital
SELBANK 2 ; SET BANK2
; Initialized Comparitor.
MOVLW B'00000000' ; Comparator disabled.
MOVWF CM1CON0 ;In bank 2
SELBANK 0 ; SET BANK0
CLRF PORTA ;Set all outputs low
; Initialized EUSART
SELBANK 3 ; SET BANK 3
MOVLW B'00000000'
MOVWF BAUDCON
BSF TXSTA,BRGH ; Set baud rate high bit
BSF TXSTA,TXEN ;enable transmission
MOVLW 0x19 ; Decimal 25 for 9600 baud rate
MOVWF SPBRGL
MOVLW 0x00
MOVWF SPBRGH
BSF RCSTA,SPEN ;enable serial port
BSF RCSTA,CREN ;enable receive
SELBANK 0 ; SET BANK0
; Initialized Timer 1
SELBANK 0 ; SET BANK0
MOVLW B'00010100' ;Clock source FOSC, 1:2 prescale, Dedicated Timer1 oscillator circuit disabled,
;Do not synchronize external clock input, Timer off
MOVWF T1CON ;With 4 Mhz clock timer will increment every 500 nS
MOVLW 0x00 ;All bits clear (Gate control not used.)
MOVWF T1GCON
; Initialized ADC
SELBANK 1 ; SET BANK1
MOVLW 0x09 ; Channel 2, ADON (Bit 0)
MOVWF ADCON0
MOVLW B'11010011' ; Bit 7 Result right justified. ADCS 101 /16 (Bits 6 & 4 set ). ADPREF bits 0 & 1 set (FVR module.)
MOVWF ADCON1
SELBANK 2 ; SET BANK2
MOVLW B'10000011' ;Bit 7 enable. Bits 0,1 4.096V ref
MOVWF FVRCON
SELBANK 0 ; SET BANK0
; *****************************
; Program main
; *****************************
; Main loop
; CALL Delay_2_Sec
MAIN:
Wait_Rx_Chr: ;Wait for a received character
SELBANK 3
BSF RCSTA,CREN ;enable receive
SELBANK 0
bcf PORTA,5 ; TEST switch off LED
BCF PORTA,4 ;TEST switch off LED
CALL SerialReceive
; CALL SerialTransmit ;Echo character as a test
; MOVF RX_Temp,W
; BCF PORTA,5 ;TEST switch off LED
XORLW '#' ;Wait for # character.
BTFSS STATUS,Z
GOTO Wait_Rx_Chr ; Not # character
MOVLW RX_Timer ; Number of 10 mS to wait for station ID character
MOVWF RX_Count
Test_DAV:
btfsc PIR1,RCIF ;check if data received
GOTO Read_Data
CALL Delay_10mS
DECFSZ RX_Count
GOTO Test_DAV
GOTO Wait_Rx_Chr
Read_Data:
; bsf PORTA, 4 ; led ON test ONLY
SELBANK 3 ; SET BANK 3
movf RCREG,W ;get received data into W
BCF RCSTA,CREN ;disable receive
; MOVWF RX_Temp
SELBANK 0 ; SET BANK 0
; MOVF RX_Temp,W
; CALL SerialTransmit ;Echo character as a test
XORLW Station_ID
BTFSS STATUS,Z
GOTO Wait_Rx_Chr ; Not this station
CALL Read_ADC
CALL Output_Decimal ;Output in decimal
MOVLW 0x0D ;C/R
CALL SerialTransmit
MOVLW 0x0A ;L/F
CALL SerialTransmit
; CALL Delay_2_Sec
CALL Delay_100mS
CALL Delay_100mS
CALL Delay_100mS
GOTO Wait_Rx_Chr
; --------------------------------------------------------------------------------------
; *****************************
; Subroutines
; *****************************
;*****************************************************************************
;
; Function : SerialTransmit
; This function sends the byte in W over the RS232 port. The
; function will wait until previous data has been sent
;
; Input: Byte in W
;
; Output:
;
;*****************************************************************************
SerialTransmit:
; MOVWF TX_temp
btfss PIR1,TXIF ;check that buffer is empty
goto $-1
SELBANK 3 ; SET BANK 3
; MOVF TX_temp,W
movwf TXREG ;transmit byte
SELBANK 0 ; SET BANK 0
return
;*****************************************************************************
SerialReceive:
;Start of test code
; CALL Toggle_bit5
; SELBANK 3 ; SET BANK 3
; BTFSC RCSTA,1 ;test for OVERRUN error
; BSF PORTA,4
; SELBANK 0 ; SET BANK 0
;End of test code
btfss PIR1,RCIF ;check if data received
goto SerialReceive ;wait until new data
SELBANK 3 ; SET BANK 3
movf RCREG,W ;get received data into W
; MOVWF RX_Temp
SELBANK 0 ; SET BANK 0
; MOVF RX_Temp,W
return
;*****************************************************************************
;*Read ADC
;* Result in ADC_TempL & ADC_Temp_H
;*
;*****************************************************************************
;
Read_ADC:
SELBANK 1 ; SET BANK 1
MOVLW 0x09 ; Channel 2, ADON (Bit 0)
MOVWF ADCON0
NOP ;For short delay
NOP
NOP
NOP
NOP
BSF ADCON0,ADGO ;Start conversion
ADC_Tst:
BTFSC ADCON0,ADGO
GOTO ADC_Tst
MOVFW ADRESH
SELBANK 0 ; SET BANK 0
MOVWF ADC_Temp_H
SELBANK 1 ; SET BANK 1
MOVFW ADRESL
SELBANK 0 ; SET BANK 0
MOVWF ADC_Temp_L
; Rotate left 4 bits
RLF ADC_Temp_L
RLF ADC_Temp_H
RLF ADC_Temp_L
RLF ADC_Temp_H
RLF ADC_Temp_L
RLF ADC_Temp_H
RLF ADC_Temp_L
RLF ADC_Temp_H
MOVLW 0xF0
ANDWF ADC_Temp_L ; Clear bits 0 to 3 that could have been set by uncleared carry bit
RETURN
; -----------------------------------------------------------------------------
Delay_10mS: ;Need to set param to (10000 - 14)/2 = 9986/2 = 4993 = 0x1381
MOVLW 0x13
MOVWF param2
MOVLW 0x81
MOVWF param1
GOTO delay_cycles
Delay_100mS:
MOVLW 0xC3
MOVWF param2
MOVLW 0x49
MOVWF param1
GOTO delay_cycles
Delay_2_Sec:
MOVLW D'20'
MOVWF Temp_1
D2_Loop:
CALL Delay_100mS
DECFSZ Temp_1
GOTO D2_Loop
RETURN
;*******************************************************************************
; Function: delay_cycles
; Description: Delay a specified number of instruction cycles including
; interrupt cycles. The function call overhead adds between
; 13 and 16 cycles of delay on top of the specified value.
; With 4 Mhz system clock and 1:2 prescale
;Delay will be param * 2 uS + (13 * 1uS) + 0 to 3 uS
; = param * 2 uS + (13 to16.0 uS) (Use 14 uS for calculation.)
; So param = No. of uS/2 - 7
; Parameters: param1 - least significant byte of 16 bit cycle delay
; param2 - most significant byte of 16 bit cycle delay
; Returns: None
;*******************************************************************************
delay_cycles:
comf param1,F ; negate the delay by complementing the (1 uS) (1 cycle)
comf param2,F ; low and high bytes (1 uS) (1 cycle)
bcf T1CON,TMR1ON ; stop timer 1 (1 uS) (1 cycle)
movf param1,W ; move the low byte of the delay into (1 uS) (1 cycle)
movwf TMR1L ; timer 1 (1 uS) (1 cycle)
movf param2,W ; move the high byte of the delay into (1 uS) (1 cycle)
movwf TMR1H ; timer 1 (1 uS) (1 cycle)
bcf PIR1,TMR1IF ; clear the timer 1 rollover flag (1 uS) (1 cycle)
bsf T1CON,TMR1ON ; turn on timer 1 (1 uS) (1 cycle)
tmr1_check:
btfss PIR1,TMR1IF ; wait for the timer 1 rollover flag to 1 uS while looping (2 uS) (2 cycle) on exit
goto tmr1_check ; trigger
return ; (2 uS) (2 cycle)
;**********************************************************************************
; Subroutine BCD (to convert 28-bit binary to 8-digit BCD)
; Binary value is in BIN1, BIN2, BIN3 & BIN4. BIN1 is LSB, BIN4 is MSB
; Result in BCD is in BCD1, BCD2, BCD3, BCD4 & BCD5. BCD1 is for overrange,
; BCD2 is MSB, BCD5 is LSB
;**********************************************************************************
BIN_BCD:
bcf STATUS,C ; clear carry bit
movlw D'32'
movwf COUNT ; 32 in count
clrf BCD1 ; set BCD registers to 0
clrf BCD2
clrf BCD3
clrf BCD4
clrf BCD5
LOOPBCD:
rlf BIN1,f ; LSB shift left binary registers
rlf BIN2,f
rlf BIN3,f
rlf BIN4,f ; MSB
rlf BCD5,f ; LSB shift left BCD registers
rlf BCD4,f
rlf BCD3,f
rlf BCD2,f
rlf BCD1,f ; MSB
decfsz COUNT,f ; reduce count value return when 0
goto DECADJ ; continue decimal adjust
; result in BCD1-5. (BCD1 overrange, BCD2 MS byte)
swapf BCD2,w ; get ms nibble
andlw 0x0F
iorlw 0x30 ; convert to ASCII
movwf ESEVN ; ms digit
movf BCD2,w ; get 2nd ms nibble
andlw 0x0F
iorlw 0x30 ; convert to ASCII
movwf ESIX
swapf BCD3,w ; get next nibble
andlw 0x0F
iorlw 0x30 ; convert to ASCII
movwf EFIVE ; ms digit
movf BCD3,w ; get next nibble
andlw 0x0F
iorlw 0x30 ; convert to ASCII
movwf EFOUR
swapf BCD4,w ; get ms nibble
andlw 0x0F
iorlw 0x30 ; convert to ASCII
movwf ETHREE ; ms digit
movf BCD4,w ; get 2nd ms nibble
andlw 0x0F
iorlw 0x30 ; convert to ASCII
movwf ETWO
swapf BCD5,w ; get ms nibble
andlw 0x0F
iorlw 0x30 ; convert to ASCII
movwf EONE ; ms digit
movf BCD5,w ; get 2nd ms nibble
andlw 0x0F
iorlw 0x30 ; convert to ASCII
movwf EZERO
return ; completed decimal to BCD operation
; subroutine decimal adjust
DECADJ movlw BCD5 ; BCD LSB address
movwf FSR1L ; pointer for BCD5
CLRF FSR1H
call ADJBCD ; subroutine to adjust BCD
movlw BCD4
movwf FSR1L
CLRF FSR1H
call ADJBCD
movlw BCD3
movwf FSR1L
CLRF FSR1H
call ADJBCD
movlw BCD2
movwf FSR1L
CLRF FSR1H
call ADJBCD
movlw BCD1
movwf FSR1L
CLRF FSR1H
call ADJBCD
goto LOOPBCD
; subroutine adjust BCD
ADJBCD movlw 0x03 ; w has 03
addwf INDF1,w ; add 03 to BCDx register (x is 1-5)
movwf TEMP ; store w
btfsc TEMP,3 ; test if >7
movwf INDF1 ; save as LS digit
movlw 0x30 ; 3 for MSbyte
addwf INDF1,w ; add 30 to BCDx register
movwf TEMP ; store w
btfsc TEMP,7 ; test if >7
movwf INDF1 ; save as MS digit
return ; end subroutine
;**********************************************************************************
;
;
Output_Decimal:
CLRF BIN4 ;Clear top 3 bytes (Not used.)
CLRF BIN3
CLRF BIN2
MOVF ADC_Temp_H,W ;ADC high byte
MOVWF BIN2
MOVF ADC_Temp_L,W ;ADC low byte
MOVWF BIN1
CALL BIN_BCD
Output_Reading:
MOVF EFOUR, W
CALL SerialTransmit
MOVF ETHREE, W
CALL SerialTransmit
MOVLW '.'
CALL SerialTransmit
MOVF ETWO, W
CALL SerialTransmit
MOVF EONE, W
CALL SerialTransmit
MOVF EZERO, W
CALL SerialTransmit
MOVLW ' '
CALL SerialTransmit
MOVLW 'V'
CALL SerialTransmit
MOVLW 'o'
CALL SerialTransmit
MOVLW 'l'
CALL SerialTransmit
MOVLW 't'
CALL SerialTransmit
MOVLW 's'
CALL SerialTransmit
MOVLW ' '
CALL SerialTransmit
RETURN
;Toggle_bit5: ;Used for testing
; MOVWF BS_Temp
; MOVLW b'00100000'
; XORWF PORTA,f ;Toggle bit 5
; MOVFW BS_Temp
; RETURN
end