EmbeddedRelated.com
Forums

C18 ADC question

Started by Steve Nance August 27, 2008
I'm looking for some sample code that shows how to read an ADC over USB
using a 18F4550. I've looked at the MC sample code for the PICDEM FS USB
board, but it's just too tough to make sense of with all the functions it
has. I would like to find something simple if possible.

Thanks,
Steve

Hi Steve,
from what I understand getting a PIC to communicate directly over USB is very involved. You may be better off using an FTDI chip (http://www.ftdichip.com), then programming your PIC to communicate to that using RS232 style serial.

Gavin

--- On Thu, 8/14/08, Steve Nance wrote:
From: Steve Nance
Subject: [piclist] C18 ADC question
To: p...
Date: Thursday, August 14, 2008, 8:33 PM

I'm looking for some sample code that shows how to read an ADC over USB

using a 18F4550. I've looked at the MC sample code for the PICDEM FS USB

board, but it's just too tough to make sense of with all the functions it

has. I would like to find something simple if possible.

Thanks,

Steve
Hi,

USB is a tough nut to crack. But if you have some experience with
embedded C programming on PIC's then you could try the Microchips PICdem
Full Speed USB demo board. It comes with source and all you need to
build up your own USB app on a board. You will need to have Microchip
C18 in your environment to use it as it comes though. I've used this
board to play around with and it is pretty nifty.
The FTDI path is far, FAR easier however.

DLC

> Hi Steve,
> from what I understand getting a PIC to communicate directly over USB is
> very involved. You may be better off using an FTDI chip
> (http://www.ftdichip.com), then programming your PIC to communicate to
> that using RS232 style serial.
>
> Gavin
>
> --- On Thu, 8/14/08, Steve Nance wrote:
> From: Steve Nance
> Subject: [piclist] C18 ADC question
> To: p...
> Date: Thursday, August 14, 2008, 8:33 PM
>
> I'm looking for some sample code that shows how to read an ADC
> over USB
>
> using a 18F4550. I've looked at the MC sample code for the PICDEM FS USB
>
> board, but it's just too tough to make sense of with all the functions it
>
> has. I would like to find something simple if possible.
>
> Thanks,
>
> Steve
--
Dennis Clark
TTT Enterprises
Denis & Gavin,

Thanks for your responses. Actually I already have the USB link working and
can turn LEDs on/off from a C# program. That part is working. I just need to
configure the PIC for an ADC and pass the data back to the USB client.

I am using the PICDEM FS USB Demo board and have the Micro Chip Demo C code,
but it has so many features I don't know which settings I need to use just
for the ADC.

Steve

-----Original Message-----
From: p... [mailto:p...] On Behalf Of
Dennis Clark
Sent: Wednesday, August 27, 2008 2:45 PM
To: p...
Subject: Re: [piclist] C18 ADC question

Hi,

USB is a tough nut to crack. But if you have some experience with
embedded C programming on PIC's then you could try the Microchips PICdem
Full Speed USB demo board. It comes with source and all you need to
build up your own USB app on a board. You will need to have Microchip
C18 in your environment to use it as it comes though. I've used this
board to play around with and it is pretty nifty.
The FTDI path is far, FAR easier however.

DLC

> Hi Steve,
> from what I understand getting a PIC to communicate directly over USB is
> very involved. You may be better off using an FTDI chip
> (http://www.ftdichip.com), then programming your PIC to communicate to
> that using RS232 style serial.
>
> Gavin
>
> --- On Thu, 8/14/08, Steve Nance wrote:
> From: Steve Nance
> Subject: [piclist] C18 ADC question
> To: p...
> Date: Thursday, August 14, 2008, 8:33 PM
>
> I'm looking for some sample code that shows how to read an ADC
> over USB
>
> using a 18F4550. I've looked at the MC sample code for the PICDEM FS USB
>
> board, but it's just too tough to make sense of with all the functions it
>
> has. I would like to find something simple if possible.
>
> Thanks,
>
> Steve
>

--
Dennis Clark
TTT Enterprises

LIST PF242 ;directive to define processor
#include ;processor specific variable definitions
#include ;Math library macros
;OSCILLATOR=1Mhz, Baudrate$00
;WDT enabled with 380mS timeout !!!
;*****************************************************************************
; Config bits are defined in the P18F242.INC file.
; The PIC18F242 Data Sheet explains the functions of the config bits

;******************************************************************************
;Configuration bits
; The __CONFIG directive defines configuration data within the .ASM file.
; The labels following the directive configuration bits.
__CONFIG _CONFIG1H, _OSCS_OFF_1H & _RC_OSC_1H ;Oscillator switching=OFF. High Speed Oscillator enable=ON.
__CONFIG _CONFIG2L, _BOR_OFF_2L & _PWRT_ON_2L ;Brown Out Reset=OFF. Power-up Timer=ON.
__CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_32_2H ;Watch Dog Timer=ON with 380mS timeout
__CONFIG _CONFIG3H, _CCP2MX_OFF_3H ;Mux on CCP2=OFF.
__CONFIG _CONFIG4L, _STVR_OFF_4L & _LVP_OFF_4L & _DEBUG_OFF_4L ;Stack overflow reset=OFF. Low Voltage Programming(ISCP)=OFF. Background Debugger=OFF.
__CONFIG _CONFIG5L, _CP0_ON_5L & _CP1_ON_5L & _CP2_ON_5L & _CP3_ON_5L ;Code Protection=OFF.
__CONFIG _CONFIG5H, _CPB_ON_5H & _CPD_ON_5H ;Boot Block Code Protection=OFF. Data EEPROM Code Protection=OFF.
__CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L ;Program blocks 0:3 Write Protection=OFF.
__CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H ;EEPROM Write protection=OFF. Boot Block Write Protection=OFF. Configuration Register Write Protection=OFF.
__CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L ;Table Read Protection blocks 0:3=OFF.
__CONFIG _CONFIG7H, _EBTRB_OFF_7H ;Boot Block Table Read Protection=OFF.
;************************************************************************************************
;#DEFINE PROG_ORG 0X0000 ;Program origin, for use without bootloader. *
#DEFINE PROG_ORG 0X0600 ;For bootloader. Enable only the appropriate line *
;************************************************************************************************

;---------- Variable definitions --------

CBLOCK 0X100
BSRTMP,WREGTMP,STATUS_TMP
ANLOOPCNT
CH0BUFF,CH0BUFF1,CH0BUFF2 ;Infinite Impulse Response (IIR) filter output ch0
CH1BUFF,CH1BUFF1,CH1BUFF2 ;Infinite Impulse Response (IIR) filter output ch1
CH2BUFF,CH2BUFF1,CH2BUFF2 ;Infinite Impulse Response (IIR) filter output ch2
CH3BUFF,CH3BUFF1,CH3BUFF2 ;Infinite Impulse Response (IIR) filter output ch3
CH4BUFF,CH4BUFF1,CH4BUFF2 ;Infinite Impulse Response (IIR) filter output ch4

AN_ch0,AN_ch01,AN_ch1,AN_ch11 ;Filtered analog 16bit data outputs
AN_ch2,AN_ch21,AN_ch3,AN_ch31 ;
AN_ch4,AN_ch41 ;
ADC,ADC1 ;ADRES buffer
KVAL ;IIR filter value
FILTERTIMER ;FIR-filter stabilizing timer
TEMP0,TEMP1,TEMP2,TEMP3 ;temp variables
TEMP4,TEMP5,TEMP6,TEMP7

LIMLOW,LIMLOW1 ;LOW SETPOINT
LIMHIGH,LIMHIGH1 ;HIGH SETPOINT
LOWOFS,LOWOFS1 ;Offsetvalue for the LOWLIM data, will be 714d.
HIGHOFS,HIGHOFS1 ;Offsetvalue for the HIGHLIM data, will be 869d.
RADIO,RADIO1 ;Sensed radio battery voltage
SERVICE,SERVICE1 ;Sensed service battery voltage
Rhi,Rlo,Shi,Slo,DR,DS ;Input alarmflags:0=OFF , 1=ON
BP ;Beeper controlflag
RADIOBATT ;SET:use Radiobattery, CLEAR: use Servicebattery
RDISABLE ;Radio input disable flag
DRIFTBATT ;Drift battery: 1:Radiobattery, 0:Servicebattery
XTIMER ;Dual relay cross conduction timer
PORTIMER ;POR Beep & LED time
TESTH,TESTL ;Testswitch flags
BEEPTIMER,BEEPTIMER1 ;Beep inhibit timer (10min's)
PULSETOGGLE ;Pulser odd/even flag
BEEPDISABLE ;Beeper internal flag, inhibits beeper
MANUAL ;Flags Manual battery selected
TOGDEL ;Manual mode toggle delaytimer
BUTTTMR ;Alarm Reset button timer:
BUTTSTAT ;Progressive status of Alarm Reset button,
; ;0: normal, 1: 3sec's elapsed (RESET),
; ;2: 6sec's elapsed (MANUAL MODE)
PANEL ;PANEL BITS
ALLON ;Panel ovveride, turns all on
OUTH,OUTL ;16bit output shift register
BITCNT ;Panel bitcounter

;---
;--------------- MATH ROUTINE VARIABLES -------------------
AARGB0,AARGB1,AARGB2,AARGB3,AARGB4 ;Argument A
BARGB0,BARGB1,BARGB2,BARGB3,BARGB4 ;Argument B
REMB0,REMB1,REMB2,REMB3,REMB4 ;Remainder
DLOOPER,TEMPB0,TEMPB1,TEMPB2,SIGN ;Loopcounter,Misc.
SIGNMODE ;Mode selector, 1=signed, 0=unsigned
;-----------------------
ENDC

;******************************************************************************
;Reset vector
; This code will start executing when a reset occurs.
ORG PROG_ORG
GOTO START ;go to start of main code
;******************************************************************************
;High priority interrupt vector
ORG PROG_ORG+0x08
GOTO HIGHINT ;go to high priority interrupt routine
RETFIE
;******************************************************************************
;Low priority interrupt vector
ORG PROG_ORG+0x18
RETFIE
;*****************************************************************************
HIGHINT
;High priority interrupt routine
CALL MAIN ;DO MAIN PROGRAM
MOVLW 0X61 ;Reload timer
MOVWF TMR1H ;for 100mS @ 4Mhz (Hz)
MOVLW 0XA8
MOVWF TMR1L
BCF PIR1,TMR1IF ;CLEAR INTERRUPT FLAG
RETHINT RETFIE FAST ;PC,WREG,STATUS,BSR are pop'ed from HW stack.
;******************************************************************************

;*****************************************************
START ORG PROG_ORG+0X0100 ;start program code here
;*****************************************************
;*************** CLEAR ALL RAM LOCATIONS 0X000 to 0X2FF **************
MOVLB 0x01
LFSR FSR0,0X0000 ;select 0X00
NEXTB1 CLRF POSTINC0 ;clear location and increment pointer
CLRWDT
BTFSS FSR0H,2 ;3x255 bytes done?
BRA NEXTB1 ;No!
MOVLB 0x01 ;Yes! continue. Select 0X01
;*********************************************************************

BSF WDTCON,SWDTEN ;Enable WDT

;*************** SET UP DATA DIRECTION ON PORT A,B,C ****************************
MOVLW B'10000000' ;Right justified,5(4) analog input, internal Vref,Fosc/2
MOVFF WREG,ADCON1 ;
MOVLW 0X00 ;Fosc/2, ch0
MOVFF WREG,ADCON0 ;
BSF ADCON0,ADON ;ADC on
BSF ADCON0,GO ;Start conversion
;-------
CLRF PORTA ;clear output
MOVLW B'11111111' ;porta Inputs=7:0
MOVFF WREG,TRISA ;
;-------
CLRF PORTB ;clear output
MOVLW B'11010001' ;portb Inputs=7,6,4,0 Outputs=5,3,2,1
MOVFF WREG,TRISB ;
BCF PORTB,1 ;Relay off
;-------
CLRF PORTC ;clear output
MOVLW B'10111110' ;portc Inputs=7,5,4,3,2,1 Outputs=6,0
MOVFF WREG,TRISC ;
BCF PORTC,0 ;Relay off
;**************** SET UP TIMER1 FOR INTERRUPTS *********************************
MOVLW B'00000001' ;timer1 16bit, internal clock, no prescaler
MOVFF WREG,T1CON ;configure TIMER1
MOVLW 0X00
MOVFF WREG,TMR1H ;clear timer
MOVFF WREG,TMR1L
BSF PIE1,TMR1IE ;Enable Timer1 interrupt
BSF INTCON2,RBPU ;disable pullups on port
BCF RCON,IPEN ;Disable prioritized interrupts
;BSF INTCON,GIEH ;global enable
;BSF INTCON,GIEL ;global enable
;**********************************************************************************

;**************** SET UP USART ****************************************************
MOVLW 0X19 ;2400 baud @ 1Mhz
MOVFF WREG,SPBRG ;
MOVLW 0X24 ;8bit, BRGH=1
MOVFF WREG,TXSTA ;configure asynchronous transmitter
MOVLW 0X94 ;configure asynchronous receiver
MOVFF WREG,RCSTA ;
BCF TRISC,6 ;configure port pin for TXD
BSF TRISC,7 ;configure port pin for RXD
;**********************************************************************************

BEEPTIMER_RL EQU 0X2F ;Beeptimer reload value; 2B2F055..
BEEPTIMER_RH EQU 0X2B ;11055 x Intperiod of 162.8mS00sec0minutes.
XTIMERRL EQU 0X03 ;Dual relay cross conduction timer reload vlaue
TOGDELRL EQU 0X08 ;Manual mode toggle delay reload value
;------ Load the offsetvalues ------
MOVLW 0X5A;0XCA ;LOWOFS=(3.4848/5)*1024q4d=0X02CA
MOVFF WREG,LOWOFS
MOVLW 0X02
MOVFF WREG,LOWOFS1

MOVLW 0X65 ;HIGHOFS=(4.2420/5)*10249d=0X0365
MOVFF WREG,HIGHOFS
MOVLW 0X03
MOVFF WREG,HIGHOFS1
;-----------------------------------
MOVLW 0X80
MOVFF WREG,KVAL ;ADC filtervalue, low value=high filtering
MOVLW 0X08
MOVFF WREG,FILTERTIMER ;Initial samples before continuing the program

MOVLW 0X04
MOVFF WREG,PORTIMER ;1sec length of POR Beep & LED flash

MOVLW TOGDELRL
MOVFF WREG,TOGDEL ;1st Manual Toggle delay to avoid rollower
;------ These values will force the relayprocessor to initialize regardless of start-up status----
MOVLW 0X55
MOVFF WREG,DRIFTBATT
MOVLW 0X01
MOVFF WREG,XTIMER

SETF PANEL ;LEDs and Beeper on
CALL PANELOUT ;

BSF INTCON,GIEH ;global enable
BSF INTCON,GIEL ;global enable
;-------------------------

;********************************************************************************
MAINLOOP
CLRWDT ;Clear the watchdog timer (380mS timeout)

; CALL SCALELOW

BRA MAINLOOP
;******************************************************************************

;************************** INTERRUPT SERVICE HANDLER @ 10Hz ******************************************************
;---------- POR BEEP & LED FLASH ---
MAIN CLRWDT
TSTFSZ FILTERTIMER ;POR and filterstabilizing done?
BRA PORTST ;No! Do POR
BRA FIRSTAB ;Yes! Skip POR
PORTST TSTFSZ PORTIMER ;POR test timer done?
BRA NEXTPOR ;No! Continue test
BRA PORDONE ;POR test done
NEXTPOR DECF PORTIMER ;
BCF PORTB,1 ;Relays off
BCF PORTC,0 ;
SETF PANEL ;LEDs and Beeper on
CALL PANELOUT ;
RETURN ;Continue until POR timeout
PORDONE CLRF PANEL ;Panel off during filterstabilizing
CALL PANELOUT
;-----------------------------------

;---------- Filter stabilizing loop ----------------------------
FIRSTAB
;After a POR the FIR-filters needs to fill up their buffers to stabilize the outputs
CALL ADCACQ_ch0 ;Limit High
CALL ADCACQ_ch1 ;Limit Low
CALL ADCACQ_ch2 ;Servicebattery sense input
CALL ADCACQ_ch3 ;Radiobattery sense input
MOV16 AN_ch3,RADIO
MOV16 AN_ch1,LIMLOW
MOV16 AN_ch0,LIMHIGH
MOV16 AN_ch2,SERVICE
CALL HLTEST ;Inject test values into Analog Processor
TSTFSZ FILTERTIMER ;FIR-filter stabilized?
BRA NEXTFIR ;No! Continue to sample
BRA MAINSTART ;Filtered outputs should be stable now...
NEXTFIR DECF FILTERTIMER ;Continue stabilizing
RETURN ;No further processing until the filter has stabilized
;---------------------------
MAINSTART CALL RSTAT ;Processor Reset, Manual Mode Select
CALL SWITCHES ;Process external switches
CALL AN_PROC ;Analog processing
CALL PANELCONTROL ;Flash panel controls
CALL RELAY_PROC ;Control relays in crossconduction mode
CALL RINHIBIT ;Check if Radio input is externally inhibited
CALL PANELOUT ;Serial output clock to panel
RETURN

;******************************************************************************
;****************** RESET BUTTON ******************************
RSTAT
;The ALARM RESET button has multiple functions...
;Alarms are reset when button is pushed,
;After being depressed for 3-6sec's a Processor Reset is performed when the button is RELEASED.
;After being depressed for more than 6sec's manual mode is entered, toggeling between the
;two batteries, battery is selected when button is RELEASED.
BTFSS PORTB,0 ;Alarm Reset button depressed?
BRA RESTIME ;Yes!
CLRF BUTTTMR ;No!
CLRF ALLON
;Check if button was released when in Reset or Manual frame:
MOVLW 0X01
CPFSEQ BUTTSTAT ;Button released in Reset frame?
BRA RETRSTAT ;No!
CLRF PANEL ;Yes! Turn off LED's and Beeper
CALL PANELOUT ;
RESET ;Do processor RESET
BRA RETRSTAT ;
;
RESTIME INCF BUTTTMR
MOVLW 0X0A ;18d
CPFSGT BUTTTMR ;3sec's elapsed?
BRA RETRSTAT ;No!
MOVLW 0X01 ;Yes! status
MOVFF WREG,BUTTSTAT ;Set status
SETF ALLON ;Indicate that more than 3sec's has elapsed by start beeping
;-----------------------------------
MANTIME MOVLW 0X14 ;36d
CPFSGT BUTTTMR ;6sec's elapsed?
BRA RETRSTAT ;No!
MOVLW 0X02 ;Yes! status
MOVFF WREG,BUTTSTAT ;Set status
SETF MANUAL
CLRF ALLON
DECFSZ TOGDEL ;Toggle timeout?
BRA RETRSTAT ;No!
MOVLW TOGDELRL ;Yes! Reload
MOVFF WREG,TOGDEL ;
COMF RADIOBATT ;Select the other battery, with the use of the MANUAL flag.
RETRSTAT RETURN
;*****************************************************************

;****************** RADIO INHIBIT ******************************
RINHIBIT
;The Radio sense input can be disabled either by leaving that sense input floating,
;or by connecting it to Batt-. If the input is inhibited in this way there will be no
;Radiobattery visual or audiable indications on the panel.
;Sensed voltage values below 128d is defined as 'inhibit'. This is flagged in RDISABLE.
MOV16 RADIO,TEMP0 ;Get Radio voltage
MOVLW 0X00
MOVFF WREG,TEMP3 ;Compare High
MOVLW 0X80
MOVFF WREG,TEMP2 ;Compare Low
SUB16 TEMP0,TEMP2 ;Radio < 128d ?
BNC RDIS ;No!
SETF RDISABLE ;Yes! set disable flag
BRA RINHRET
RDIS CLRF RDISABLE ;Clear disable flag
BRA RINHRET
RINHRET RETURN
;*****************************************************************

;****************** HLTEST *************************
HLTEST
;Override ADC variables with testdata from the H-L test switches
BTFSS TESTH,0 ;SERVICE High test?
BRA TESTLCHK ;No!
MOV16 LIMHIGH,TEMP0 ;Yes! Inject a datavalue of HighLim+25%. Get LimHigh
BCF STATUS,C
RRC16 TEMP0 ;LimHigh/2
BCF STATUS,C
RRC16 TEMP0 ;LimHigh/4. TEMP0=LimHigh/4
MOV16 LIMHIGH,TEMP2 ;Get LimHigh
ADD16 TEMP2,TEMP0 ;TEMP0=SERVICE+(LimHigh/4)
MOV16 TEMP0,SERVICE ;Overwrite with testdata
TESTLCHK BTFSS TESTL,0 ;SERVICE Low test?
BRA RETTEST ;No! No test
MOV16 LIMLOW,TEMP0 ;Yes! Inject a datavalue of LowLim-25%. Get LimLow
BCF STATUS,C
RRC16 TEMP0 ;LimLow/2
BCF STATUS,C
RRC16 TEMP0 ;LimLow/4. TEMP0=LimLow/4
MOV16 LIMLOW,TEMP2 ;Get LowLimit
SUB16 TEMP0,TEMP2 ;TEMP0=SERVICE-(LimLow/4)
MOV16 TEMP0,SERVICE ;Overwrite with testdata
RETTEST RETURN
;***************************************************

;****************** PANEL CONTROL *******************************************
PANELCONTROL ; Interrupt driven routine
;Pulse LEDs and beeper if their ON-flag is set. Frequency is 2Hz.
;The beeper timeout timer is loaded by 'ALARM RESET', and this disables the
;beeper while the timer is running. At T=0 the beeper is re-enabled and pulses
;again, synchronous with the LEDs.
;If ALLON is set the whole panel is turned on, overriding the flags (Reset notify)
BTFSC ALLON,0 ; Whole panel on?
BRA LEDBEEPON ; Yes!
TFSZ16 BEEPTIMER ; Beeptimer=0?
BNZ DECPTIMER ; If not zero, go decrement
CLRF BEEPDISABLE ; Is zero, may beep if the controlflag is set
GOTO TOGGLE ;
DECPTIMER DEC16 BEEPTIMER ; Decrement the beeper timeout-timer
SETF BEEPDISABLE ; May not beep, even if the controlflag is set
TOGGLE COMF PULSETOGGLE ; Toggle odd/even flag
BTFSC DR,0 ; Drift Radio?
BRA DRON ; Yes!
BCF PANEL,3 ; No!
BRA DSCHK
DRON BSF PANEL,3
DSCHK BTFSC DS,0 ; Drift Service?
BRA DSON ; Yes!
BCF PANEL,6
BRA TGCHK
DSON BSF PANEL,6
TGCHK BTFSC PULSETOGGLE,0 ; Toggle=1?
GOTO SET_BEEPLED ; Yes!
BCF PANEL,2 ; Radiobattery Low alarm LED *OFF*
BCF PANEL,1 ; Radiobattery High alarm LED *OFF*
BCF PANEL,4 ; Servicebattery Low alarm LED *OFF*
BCF PANEL,5 ; Servicebattery High alarm LED *OFF*
BCF PANEL,0 ; Beeper audioalarm *OFF*
;We want to turn OFF the Drift LEDs to flash if manual mode is selected:
BTFSS MANUAL,0 ;Manual mode selected?
BRA RET_PC ;No!
BTFSC DR,0 ;Manual Drift Radio?
BCF PANEL,3 ;Yes! DR LED off
BTFSC DS,0 ;No! Manual Drift Service?
BCF PANEL,6 ;Yes! SR LED off
GOTO RET_PC
SET_BEEPLED BTFSC Rlo,0 ; No! Radio Low?
BSF PANEL,2 ; Yes!
BTFSC Rhi,0 ; No! Radio High?
BSF PANEL,1 ; Yes!
BTFSC Slo,0 ; No! Service Low?
BSF PANEL,4 ; Yes!
BTFSC Shi,0 ; No! Service High?
BSF PANEL,5 ; Yes!
BTFSC BP,0 ; No! Beeper ON?
BSF PANEL,0 ; Yes!
BTFSC BEEPDISABLE,0 ; No! Beeper disable?
BCF PANEL,0 ; Yes!
NOP ; No! At this point all alarm indicators are set
;We want to turn ON the Drift LEDs to flash if manual mode is selected:
BTFSS MANUAL,0 ;Manual mode selected?
BRA RET_PC ;No!
BTFSC DR,0 ;Manual Drift Radio?
BSF PANEL,3 ;Yes! DR LED on
BTFSC DS,0 ;No! Manual Drift Service?
BSF PANEL,6 ;Yes! SR LED on
BRA RET_PC
LEDBEEPON SETF PANEL
RET_PC NOP
RETURN
;*****************************************************************************
;********** ANALOG PROCESSING *******************************************************
AN_PROC
;If an input exceeds the high limit then set the corresponding alarmflag (Rhi),
;To clear the alarmflag the input must fall below the hysteresis boundry:
;(RADIOIN+(LIMHIGH/16)) < LIMHIGH. This gives about 6% hysteresis.
BTFSS RDISABLE,0 ;Radio input inhibited?
BRA RH_PROC ;No!
CLRF Rlo ;Yes! Clear Radiopanel
CLRF Rhi ;skip all Radio processing
BRA SH_PROC ;Drift is taken care of by DB_PROC
;---------- Radio Battery High Voltage Processing -------------
RH_PROC MOV16 RADIO,TEMP2
SUB16 LIMHIGH,TEMP2 ;RADIOIN > LIMHIGH ?
BNC RHNOLIM ;No!
RHILIM BRA SETRHAL ;Yes! Set Radio High Alarm
RHNOLIM MOV16 LIMHIGH,TEMP0 ;LIMHIGH -> TEMP0 for hysteresis processing
BCF STATUS,C
RRC16 TEMP0 ;LIMHIGH/2
BCF STATUS,C
RRC16 TEMP0 ;LIMHIGH/4
BCF STATUS,C
RRC16 TEMP0 ;LIMHIGH/8
BCF STATUS,C
RRC16 TEMP0 ;LIMHIGH/16
MOV16 LIMHIGH,TEMP2
SUB16 TEMP0,TEMP2 ;TEMP2=(LIMHIGH-(LIMHIGH/16))
SUB16 RADIO,TEMP2 ;(RADIOIN < (LIMHIGH-LIMHIGH/16)) ?
BC CLRRHAL ;Yes! Clear Radio High Alarm
BRA RHDONE ;
SETRHAL SETF Rhi ;Set Radio High Alarm
CLRF Rlo ;NEVER high&low at the same time
BRA RHDONE
CLRRHAL CLRF Rhi ;Clear Radio High Alarm
RHDONE BRA RL_PROC ;Do next module
;---------- End Radio Battery High Voltage Processing ----------

;---------- Radio Battery Low Voltage Processing -------------
RL_PROC MOV16 RADIO,TEMP2
SUB16 LIMLOW,TEMP2 ;RADIOIN < LIMLOW ?
BC RLNOLIM ;No!
RLILIM BRA SETRLAL ;Yes! Set Radio Low Alarm
RLNOLIM MOV16 LIMLOW,TEMP0 ;LIMLOW -> TEMP0 for hysteresis processing
BCF STATUS,C
RRC16 TEMP0 ;LIMLOW/2
BCF STATUS,C
RRC16 TEMP0 ;LIMLOW/4
BCF STATUS,C
RRC16 TEMP0 ;LIMLOW/8
BCF STATUS,C
RRC16 TEMP0 ;LIMLOW/16
MOV16 LIMLOW,TEMP2
ADD16 TEMP0,TEMP2 ;TEMP0=(LIMLOW+(LIMLOW/16))
SUB16 RADIO,TEMP2 ;(RADIOIN > (LIMLOW+LIMLOW/16)) ?
BNC CLRRLAL ;Yes! Clear Radio Low Alarm
BRA RLDONE ;
SETRLAL SETF Rlo ;Set Radio Low Alarm
CLRF Rhi ;NEVER high&low at the same time
BRA RLDONE
CLRRLAL CLRF Rlo ;Clear Radio Low Alarm
RLDONE BRA SH_PROC ;Do next module
;---------- End Radio Battery Low Voltage Processing ---------

;---------- Service Battery High Voltage Processing -------------
SH_PROC MOV16 SERVICE,TEMP2
SUB16 LIMHIGH,TEMP2 ;SERVICEIN > LIMHIGH ?
BNC SHNOLIM ;No!
SHILIM BRA SETSHAL ;Yes! Set Service High Alarm
SHNOLIM MOV16 LIMHIGH,TEMP0 ;LIMHIGH -> TEMP0 for hysteresis processing
BCF STATUS,C
RRC16 TEMP0 ;LIMHIGH/2
BCF STATUS,C
RRC16 TEMP0 ;LIMHIGH/4
BCF STATUS,C
RRC16 TEMP0 ;LIMHIGH/8
BCF STATUS,C
RRC16 TEMP0 ;LIMHIGH/16
MOV16 LIMHIGH,TEMP2
SUB16 TEMP0,TEMP2 ;TEMP2=(LIMHIGH-(LIMHIGH/16))
SUB16 SERVICE,TEMP2 ;(SERVICEIN < (LIMHIGH-LIMHIGH/16)) ?
BC CLRSHAL ;Yes! Clear Service High Alarm
BRA SHDONE ;
SETSHAL SETF Shi ;Set Service High Alarm
CLRF Slo ;NEVER high&low at the same time
BRA SHDONE
CLRSHAL CLRF Shi ;Clear Service High Alarm
SHDONE BRA SL_PROC ;Do next module
;---------- End Service Battery High Voltage Processing ----------

;---------- Service Battery Low Voltage Processing -------------
SL_PROC MOV16 SERVICE,TEMP2
SUB16 LIMLOW,TEMP2 ;SERVICEIN < LIMLOW ?
BC SLNOLIM ;No!
SLILIM BRA SETSLAL ;Yes! Set Service Low Alarm
SLNOLIM MOV16 LIMLOW,TEMP0 ;LIMLOW -> TEMP0 for hysteresis processing
BCF STATUS,C
RRC16 TEMP0 ;LIMLOW/2
BCF STATUS,C
RRC16 TEMP0 ;LIMLOW/4
BCF STATUS,C
RRC16 TEMP0 ;LIMLOW/8
BCF STATUS,C
RRC16 TEMP0 ;LIMLOW/16
MOV16 LIMLOW,TEMP2
ADD16 TEMP0,TEMP2 ;TEMP0=(LIMLOW+(LIMLOW/16))
SUB16 SERVICE,TEMP2 ;(SERVICEIN > (LIMLOW+LIMLOW/16)) ?
BNC CLRSLAL ;Yes! Clear Service Low Alarm
BRA SLDONE ;
SETSLAL SETF Slo ;Set Service Low Alarm
CLRF Shi ;NEVER high&low at the same time
BRA SLDONE
CLRSLAL CLRF Slo ;Clear Service Low Alarm
SLDONE BRA DB_PROC ;Do next module
;---------- End Service Battery Low Voltage Processing ---------

;---------- Drift and Beep processing ------------------------
DB_PROC
;If Radio input is inhibited then no LEDs or Beep for that input.
;Otherwise:
;Beeper flag (BP) ON: If any one of the 4 alarms is ON.
;Beeper flag (BP) OFF: All of the 4 alarms OFF. The BEEPDISABLE flag is also cleared here.
;Drift flags (DR/DS): Mutual exclusive...only one WILL be on at any given time.
;DS-ON,DR-OFF: Service alarms off.
;DR-ON,DS-OFF: Service alarm on.
;Relay switching has a cross-over delay of 0.5sec. This is done in a separate routine.
;In Automatic mode the battery selection is based on the Servicebattery voltage.
;In Manual mode either battery can be force selected.

;---------- AUTOMATIC MODE ---------------------
SAUTO
;---------- BEEPER -----------------
BTFSS RDISABLE,0 ;Radio input inhibited?
BRA ABRALCHK ;No! Include Radio in Audio alarm check
BRA ABNRADIO ;Yes! Set Beeper status, without Radio.
ABRALCHK MOVFF Rhi,WREG ;Get status both batteries...
IORWF Rlo,W
IORWF Shi,W
IORWF Slo,W
BRA ABSTATSET
ABNRADIO MOVFF Shi,WREG ;Get status only Servicebattery...
IORWF Slo,W
ABSTATSET BZ ANOALARMS ;Branch if no alarms
SETF BP ;One or more alarms, beeper on
BRA MODECHK
ANOALARMS CLRF BP ;No alarms, beeper off
CLR16 BEEPTIMER ;Clear the 30min reset timer as fault condition is cleared.
CLRF BEEPDISABLE
;-----------------------------------
MODECHK

BTFSS MANUAL,0 ;MANUAL MODE?
BRA ADLED ;No!
BRA SMANU ;Yes!

;---------- DRIFT LEDS -------------
ADLED MOVFF Shi,WREG
IORWF Slo,W
BZ ANOSALARMS ;Branch if no Service alarms
BTFSC RDISABLE,0 ;Radio input inhibited?
BRA ANODR ;Yes! No Drift Radio
SETF DR ;No! Service alarm: DR-ON,DS-OFF
ANODR CLRF DS
SETF RADIOBATT ;Use Radiobattery
BRA RETAN_PROC
ANOSALARMS SETF DS ;No Service alarm: DS-ON,DR-OFF
CLRF DR
CLRF RADIOBATT ;Use Servicebattery
BRA RETAN_PROC ;RETURN
;------------------
;
;
;---------- MANUAL MODE --------------------------
SMANU

;---------- DRIFT LEDS -------------
MDLED BTFSS RADIOBATT,0 ;Radiobattery temp-selected in manual mode?
BRA MNOSALARMS ;No!
BTFSC RDISABLE,0 ;Yes! Radio input inhibited?
BRA MNODR ;Yes! No Drift Radio
SETF DR ;No!
MNODR CLRF DS
BRA RETAN_PROC
MNOSALARMS SETF DS ;
CLRF DR
BRA RETAN_PROC ;RETURN
;------------------
RETAN_PROC RETURN
;************************************************************************************
;************** RELAY CONTROL **************************
RELAY_PROC
;Control the 2 relays to select the battery as indicated by the BATTERY flag.
;The relays are energized in a Make Before Break (MBB) fachion.
;The cross conduction time is 0.5 sec.
MOVFF RADIOBATT,WREG
SUBWF DRIFTBATT,W
BZ BATTSELCHK ;Branch if driftbatt and battselect are the same
BSF PORTB,1 ;They are not the same...
BSF PORTC,0 ;switch in both, one will be switched out later...
TSTFSZ XTIMER ;Cross conduction timing in progress?
BRA XCOUNT ;Yes! continue timing
BRA STRTXTIMER ;No! start timer
STRTXTIMER MOVLW XTIMERRL ;Relay cross conduction time reload value
MOVFF WREG,XTIMER
XCOUNT DECFSZ XTIMER ;Timed out?
BRA RETRELPROC ;No!
BATTSELCHK BTFSS RADIOBATT,0 ;Yes! Select Radiobattery?
BRA SSB ;No! Select Servicebattery
SRB BCF PORTC,0 ;Yes! Switch out Servicebattery
SETF DRIFTBATT ;Set variable to current driftbattery (Radiobattery)
BRA RETRELPROC ;Return
SSB BCF PORTB,1 ;Switch out Radiobattery
CLRF DRIFTBATT ;Set variable to current driftbattery (Servicebattery)
RETRELPROC RETURN
;*******************************************************
;********** SWITCHES **********************************************************************************
SWITCHES
;Check if ALARM RESET switch is pushed AND an alarm is active, if so disable beep and reload beeptimer.
;Also process the test switches:
;One switch simulates Service Low voltage, the other one simulates Service High voltage.
BTFSC Rlo,0 ; Radio Low?
BRA ARESETCHK ; Yes!
BTFSC Rhi,0 ; No! Radio High?
BRA ARESETCHK ; Yes!
BTFSC Slo,0 ; No! Service Low?
BRA ARESETCHK ; Yes!
BTFSC Shi,0 ; No! Service High?
BRA ARESETCHK ; Yes!
BRA ARESETDONE ; No! Leave without modifying timer or flag

ARESETCHK BTFSC PORTB,0 ; Alarm Reset depressed?
BRA ARESETDONE ; No!
AMODE SETF BEEPDISABLE ; Yes! Disable beeps
MMODE MOVLW BEEPTIMER_RL ; Reload beeptimer
MOVFF WREG,BEEPTIMER ; Low byte
MOVLW BEEPTIMER_RH
MOVFF WREG,BEEPTIMER1 ; High byte
;Now do the test switches:
ARESETDONE MOVFF PORTB,WREG
COMF WREG ;Switches are active low...
ANDLW B'11000000' ;Mask out the test switches
TEST BTFSS PORTB,7 ;Test High?
BRA TSTH ;Yes!
BTFSS PORTB,6 ;No! Test Low?
BRA TSTL ;Yes!
BRA NOTEST ;No! No test, clear all flags
TSTH SETF TESTH
BRA RETSWITCH
TSTL SETF TESTL
BRA RETSWITCH
NOTEST CLRF TESTH
CLRF TESTL
RETSWITCH RETURN
;*****************************************************************************************************
;********** TXTBYTE DEBUG ROUTINE *******************************************************************
TXBYTE CALL TXWait ; Ready to TX?
MOVFF WREG,TXREG ; Yes! Transmit data fron WREG
TXWait BTFSS PIR1,TXIF ; TX busy?
BRA TXWait ; Yes! Wait here while byte is transmitting
RETURN
;*****************************************************************************************************

;************************* ANALOG AQUSITION AND FILTERING **********************
ADCACQ_ch0
;Heavy filtering is required to remove all traces of noise. This is acomplished
;by using a Infinite Impulse Response (IIR) filter. The effect is roughly equal
;to a 232 sample averaging filter. The basic equation for the IIR filter is
;AVG=(((256-k)*AVG) + (k*NEW))/256. However this filter has feedback, and the
;rounding effects from the division causes a gain offset and a hysteresis at the
;output for the larger filter factors (low k-values). This is largely eliminated
;by usinig one fractional byte (remainder) from the division. The equation then
;becomes: AVG:F=(((256-k)*AVG:F)/256) + (k*NEW))/256
;the AVG with the fractional byte is only used for feedback into the filter, the
;actual filter output is truncated to AVG.
;Input:16bit data from ADC and 8bit filter factor.
;Output:16bit filtered data in ANAVG.
;Cycles:1262
MOVFF BSR,BSRTMP
MOVFF ADCON0,WREG ;
ANDLW B'11000111'
IORLW B'00000000' ;Select ch0
MOVFF WREG,ADCON0 ;
MOVLW 0X80
ACQ0WAIT DECFSZ WREG ;Wait here while the holding capacitor charges
BRA ACQ0WAIT
BSF ADCON0,GO ;start new conversion
ADC0WAIT BTFSC ADCON0,GO ;ADC done?
BRA ADC0WAIT ;No!
MOVFF ADRESL,ADC+B0 ;Yes! copy ADRES to variable
MOVFF ADRESH,ADC+B1
MOVFF KVAL,WREG ;To avoid a 16bit subtraction we do a 255-k
SUBLW 0XFF ;and then add 1 to the result.
INCF WREG ;Wreg is now (256-k)
MOVFF WREG,BARGB0 ;Multiply...
CLRF BARGB1 ;(256-k)*
MOV24 CH0BUFF,AARGB0 ;ANAVG:F, 16bit AVG plus 8bit fractional
CALL MUL2416SU ;=((256-k)*AVG:F)
MOV32 AARGB1,TEMP0 ;after truncation: ((256-k)*AVG:F)/256 -> TEMP
MOV16 ADC,BARGB0 ;Multiply ADC*
MOVFF KVAL,AARGB2 ;k
CLRF AARGB3 ;
CLRF AARGB0
CALL FXM1616S ;=(k*ADC)
ADD32 AARGB0,TEMP0 ;=(((256-k)*AVG:F)/256) + (k*ADC)
MOV32 TEMP0,AARGB0 ;Divide...
CLRF BARGB0 ;
MOVLW 0X01 ;by 100h
MOVFF WREG,BARGB1
CLRF BARGB2
CLRF BARGB3
CALL DIV32_32 ;AVG:F=(((256-k)*AVG:F)/256) + (k*ADC))/256
MOV16 AARGB0,CH0BUFF+1 ;Move 16bit integer to ANAVG and
MOVFF REMB3,CH0BUFF ;extend to 24bits by moving remainder to ANAVG LSD.
MOV16 CH0BUFF+1,AN_ch0 ;Filtered 16bit output.
CALL SCALEHIGH ;Scale to fit
MOVFF BSRTMP,BSR
RETURN
;*****************************************************************

;************************* ANALOG AQUSITION AND FILTERING **********************
ADCACQ_ch1
;Heavy filtering is required to remove all traces of noise. This is acomplished
;by using a Infinite Impulse Response (IIR) filter. The effect is roughly equal
;to a 232 sample averaging filter. The basic equation for the IIR filter is
;AVG=(((256-k)*AVG) + (k*NEW))/256. However this filter has feedback, and the
;rounding effects from the division causes a gain offset and a hysteresis at the
;output for the larger filter factors (low k-values). This is largely eliminated
;by usinig one fractional byte (remainder) from the division. The equation then
;becomes: AVG:F=(((256-k)*AVG:F)/256) + (k*NEW))/256
;the AVG with the fractional byte is only used for feedback into the filter, the
;actual filter output is truncated to AVG.
;Input:16bit data from ADC and 8bit filter factor.
;Output:16bit filtered data in ANAVG.
;Cycles:1262
MOVFF BSR,BSRTMP
MOVFF ADCON0,WREG ;
ANDLW B'11000111'
IORLW B'00001000' ;Select ch1
MOVFF WREG,ADCON0 ;
MOVLW 0X80
ACQ1WAIT DECFSZ WREG ;Wait here while the holding capacitor charges
BRA ACQ1WAIT
BSF ADCON0,GO ;start new conversion
ADC1WAIT BTFSC ADCON0,GO ;ADC done?
BRA ADC1WAIT ;No!
MOVFF ADRESL,ADC+B0 ;Yes! copy ADRES to variable
MOVFF ADRESH,ADC+B1
MOVFF KVAL,WREG ;To avoid a 16bit subtraction we do a 255-k
SUBLW 0XFF ;and then add 1 to the result.
INCF WREG ;Wreg is now (256-k)
MOVFF WREG,BARGB0 ;Multiply...
CLRF BARGB1 ;(256-k)*
MOV24 CH1BUFF,AARGB0 ;ANAVG:F, 16bit AVG plus 8bit fractional
CALL MUL2416SU ;=((256-k)*AVG:F)
MOV32 AARGB1,TEMP0 ;after truncation: ((256-k)*AVG:F)/256 -> TEMP
MOV16 ADC,BARGB0 ;Multiply ADC*
MOVFF KVAL,AARGB2 ;k
CLRF AARGB3 ;
CLRF AARGB0
CALL FXM1616S ;=(k*ADC)
ADD32 AARGB0,TEMP0 ;=(((256-k)*AVG:F)/256) + (k*ADC)
MOV32 TEMP0,AARGB0 ;Divide...
CLRF BARGB0 ;
MOVLW 0X01 ;by 100h
MOVFF WREG,BARGB1
CLRF BARGB2
CLRF BARGB3
CALL DIV32_32 ;AVG:F=(((256-k)*AVG:F)/256) + (k*ADC))/256
MOV16 AARGB0,CH1BUFF+1 ;Move 16bit integer to ANAVG and
MOVFF REMB3,CH1BUFF ;extend to 24bits by moving remainder to ANAVG LSD.
MOV16 CH1BUFF+1,AN_ch1 ;Filtered 16bit output.
CALL SCALELOW ;Scale to fit
MOVFF BSRTMP,BSR
RETURN
;*****************************************************************
;************************* ANALOG AQUSITION AND FILTERING **********************
ADCACQ_ch2
;Heavy filtering is required to remove all traces of noise. This is acomplished
;by using a Infinite Impulse Response (IIR) filter. The effect is roughly equal
;to a 232 sample averaging filter. The basic equation for the IIR filter is
;AVG=(((256-k)*AVG) + (k*NEW))/256. However this filter has feedback, and the
;rounding effects from the division causes a gain offset and a hysteresis at the
;output for the larger filter factors (low k-values). This is largely eliminated
;by usinig one fractional byte (remainder) from the division. The equation then
;becomes: AVG:F=(((256-k)*AVG:F)/256) + (k*NEW))/256
;the AVG with the fractional byte is only used for feedback into the filter, the
;actual filter output is truncated to AVG.
;Input:16bit data from ADC and 8bit filter factor.
;Output:16bit filtered data in ANAVG.
;Cycles:1262
MOVFF BSR,BSRTMP
MOVFF ADCON0,WREG ;
ANDLW B'11000111'
IORLW B'00010000' ;Select ch2
MOVFF WREG,ADCON0 ;
MOVLW 0X80
ACQ2WAIT DECFSZ WREG ;Wait here while the holding capacitor charges
BRA ACQ2WAIT
BSF ADCON0,GO ;start new conversion
ADC2WAIT BTFSC ADCON0,GO ;ADC done?
BRA ADC2WAIT ;No!
MOVFF ADRESL,ADC+B0 ;Yes! copy ADRES to variable
MOVFF ADRESH,ADC+B1
MOVFF KVAL,WREG ;To avoid a 16bit subtraction we do a 255-k
SUBLW 0XFF ;and then add 1 to the result.
INCF WREG ;Wreg is now (256-k)
MOVFF WREG,BARGB0 ;Multiply...
CLRF BARGB1 ;(256-k)*
MOV24 CH2BUFF,AARGB0 ;ANAVG:F, 16bit AVG plus 8bit fractional
CALL MUL2416SU ;=((256-k)*AVG:F)
MOV32 AARGB1,TEMP0 ;after truncation: ((256-k)*AVG:F)/256 -> TEMP
MOV16 ADC,BARGB0 ;Multiply ADC*
MOVFF KVAL,AARGB2 ;k
CLRF AARGB3 ;
CLRF AARGB0
CALL FXM1616S ;=(k*ADC)
ADD32 AARGB0,TEMP0 ;=(((256-k)*AVG:F)/256) + (k*ADC)
MOV32 TEMP0,AARGB0 ;Divide...
CLRF BARGB0 ;
MOVLW 0X01 ;by 100h
MOVFF WREG,BARGB1
CLRF BARGB2
CLRF BARGB3
CALL DIV32_32 ;AVG:F=(((256-k)*AVG:F)/256) + (k*ADC))/256
MOV16 AARGB0,CH2BUFF+1 ;Move 16bit integer to ANAVG and
MOVFF REMB3,CH2BUFF ;extend to 24bits by moving remainder to ANAVG LSD.
MOV16 CH2BUFF+1,AN_ch2 ;Filtered 16bit output.
;------------------ 12V-24V SELECT -------
;Read the position of the voltage select strap. If in 12V position (PORTC,1=H)
;then multiply Radio and Service datavalues by 2.
BTFSS PORTC,1 ;Strapped for 12V?
BRA CH2RET ;No!
MOV16 AN_ch2,TEMP0 ;Yes!
RLC16 TEMP0 ;Voltage X2
MOV16 TEMP0,AN_ch2 ;Overwrite with new data
;-----
CH2RET MOVFF BSRTMP,BSR
RETURN
;*****************************************************************
;************************* ANALOG AQUSITION AND FILTERING **********************
ADCACQ_ch3
;Heavy filtering is required to remove all traces of noise. This is acomplished
;by using a Infinite Impulse Response (IIR) filter. The effect is roughly equal
;to a 232 sample averaging filter. The basic equation for the IIR filter is
;AVG=(((256-k)*AVG) + (k*NEW))/256. However this filter has feedback, and the
;rounding effects from the division causes a gain offset and a hysteresis at the
;output for the larger filter factors (low k-values). This is largely eliminated
;by usinig one fractional byte (remainder) from the division. The equation then
;becomes: AVG:F=(((256-k)*AVG:F)/256) + (k*NEW))/256
;the AVG with the fractional byte is only used for feedback into the filter, the
;actual filter output is truncated to AVG.
;Input:16bit data from ADC and 8bit filter factor.
;Output:16bit filtered data in ANAVG.
;Cycles:1262
MOVFF BSR,BSRTMP
MOVFF ADCON0,WREG ;
ANDLW B'11000111'
IORLW B'00011000' ;Select ch3
MOVFF WREG,ADCON0 ;
MOVLW 0X80
ACQ3WAIT DECFSZ WREG ;Wait here while the holding capacitor charges
BRA ACQ3WAIT
BSF ADCON0,GO ;start new conversion
ADC3WAIT BTFSC ADCON0,GO ;ADC done?
BRA ADC3WAIT ;No!
MOVFF ADRESL,ADC+B0 ;Yes! copy ADRES to variable
MOVFF ADRESH,ADC+B1
MOVFF KVAL,WREG ;To avoid a 16bit subtraction we do a 255-k
SUBLW 0XFF ;and then add 1 to the result.
INCF WREG ;Wreg is now (256-k)
MOVFF WREG,BARGB0 ;Multiply...
CLRF BARGB1 ;(256-k)*
MOV24 CH3BUFF,AARGB0 ;ANAVG:F, 16bit AVG plus 8bit fractional
CALL MUL2416SU ;=((256-k)*AVG:F)
MOV32 AARGB1,TEMP0 ;after truncation: ((256-k)*AVG:F)/256 -> TEMP
MOV16 ADC,BARGB0 ;Multiply ADC*
MOVFF KVAL,AARGB2 ;k
CLRF AARGB3 ;
CLRF AARGB0
CALL FXM1616S ;=(k*ADC)
ADD32 AARGB0,TEMP0 ;=(((256-k)*AVG:F)/256) + (k*ADC)
MOV32 TEMP0,AARGB0 ;Divide...
CLRF BARGB0 ;
MOVLW 0X01 ;by 100h
MOVFF WREG,BARGB1
CLRF BARGB2
CLRF BARGB3
CALL DIV32_32 ;AVG:F=(((256-k)*AVG:F)/256) + (k*ADC))/256
MOV16 AARGB0,CH3BUFF+1 ;Move 16bit integer to ANAVG and
MOVFF REMB3,CH3BUFF ;extend to 24bits by moving remainder to ANAVG LSD.
MOV16 CH3BUFF+1,AN_ch3 ;Filtered 16bit output.
;------------------ 12V-24V SELECT -------
;Read the position of the voltage select strap. If in 12V position (PORTC,1=H)
;then multiply Radio and Service datavalues by 2.
BTFSS PORTC,1 ;Strapped for 12V?
BRA CH3RET ;No!
MOV16 AN_ch3,TEMP0 ;Yes!
RLC16 TEMP0 ;Voltage X2
MOV16 TEMP0,AN_ch3 ;Overwrite with new data
;-----
CH3RET MOVFF BSRTMP,BSR
RETURN
;*****************************************************************

;***************** LOWLIM SCALE *********************************************************
SCALELOW
;The setpoint inputs have an original range of 0-5V. This must be scaled
;(multiplied and offset) to match the required input voltage range.
;The total input voltage range is 23-33V. For better resolution this is divided into two
;non-overlapping ranges: Low range is defined as 23-28V, and high range is defined as 28-33V.
;The input voltage is fed to the voltage divider consisting of 56K-10K, and this gives
;us a divided voltage range of 3.4848-5.0000V. The low range is 3.4848-4.2420V, and the
;high range is 4.2420-5.0000V. The division factor is calculated as 33V in / 5V out = 0.1515.
;From this follows that the new Limit data must be calculated according to the equations
;LIMLOWN=3.4848+((LIMLOW*5)/33), and LIMHIGHN=4.2420+((LIMHIGH*5)/33)
;The binary offsetvalues is; (3.4848/5)*1024q4, and (4.2420/5)*10249.
MOV16 AN_ch1,TEMP0 ;GET Low set VOLTAGE
;Reverse pot direction
MOVLW 0X03
MOVFF WREG,TEMP3
MOVLW 0XFF
MOVFF WREG,TEMP2
SUB16 TEMP0,TEMP2
MOVFF TEMP3,WREG
ANDLW 0X03
MOVFF WREG,TEMP3
MOV16 TEMP2,TEMP0
;---------------------
RLC16 TEMP0 ;X2
RLC16 TEMP0 ;X4
ADD16 AN_ch1,TEMP0 ;X5. TEMP=AN_ch1*5
MOV16 TEMP0,AARGB0 ;
MOVLW 0X0F ;0033d
MOVFF WREG,BARGB0
MOVLW 0X00
MOVFF WREG,BARGB1
CALL SDIV16_16 ;(AN_ch1*5)/33 -> AARGB
MOV16 AARGB0,TEMP0 ;
ADD16 LOWOFS,TEMP0 ;Ofset + ((AN_ch1*5)/33) -> TEMP
MOV16 TEMP0,AN_ch1 ;Overwrite with scaled value
RETURN
;******************************************************************************
;***************** HIGHLIM SCALE ********************************************************
SCALEHIGH
;The setpoint inputs have an original range of 0-5V. This must be scaled
;(multiplied and offset) to match the required input voltage range.
;The total input voltage range is 23-33V. For better resolution this is divided into two
;non-overlapping ranges: Low range is defined as 23-28V, and high range is defined as 28-33V.
;The input voltage is fed to the voltage divider consisting of 56K-10K, and this gives
;us a divided voltage range of 3.4848-5.0000V. The low range is 3.4848-4.2420V, and the
;high range is 4.2420-5.0000V. The division factor is calculated as 33V in / 5V out = 0.1515.
;From this follows that the new Limit data must be calculated according to the equations
;LIMLOWN=3.4848+((LIMLOW*5)/33), and LIMHIGHN=4.2420+((LIMHIGH*5)/33)
;The binary offsetvalues is; (3.4848/5)*1024q4, and (4.2420/5)*10249.
MOV16 AN_ch0,TEMP0 ;GET High set VOLTAGE
RLC16 TEMP0 ;X2
RLC16 TEMP0 ;X4
ADD16 AN_ch0,TEMP0 ;X5. TEMP=AN_ch0*5
MOV16 TEMP0,AARGB0 ;
MOVLW 0X21 ;033d
MOVFF WREG,BARGB0
MOVLW 0X00
MOVFF WREG,BARGB1
CALL SDIV16_16 ;(AN_ch0*5)/33 -> AARGB
MOV16 AARGB0,TEMP0 ;
ADD16 HIGHOFS,TEMP0 ;Ofset + ((AN_ch0*5)/33) -> TEMP
MOV16 TEMP0,AN_ch0 ;Overwrite with scaled value
RETURN
;******************************************************************************
;**********************************************************************************************
; PIC18
; 24x16 Bit Signed or Unsigned Fixed Point Multiply 24 x 16 -> 40 ,by Eirik Karlsen 29.12.03
;
; Input:24 bit signed or unsigned fixed point multiplicand in AARGB2, AARGB1, AARGB0
; 16 bit signed or unsigned fixed point multiplier in BARGB1, BARGB0
;
; Use: CALL MUL2416SU
;
; Output: 40 bit signed or unsigned fixed point product in AARGB4, AARGB3, AARGB2, AARGB1, AARGB0
;
; Input and output is right justified and ARGB0 is LSB
;
; AARGB4,AARGB3,AARGB2,AARGB1,AARGB0,BARGB1,BARGB0,TEMP3,TEMP2,TEMP1,TEMP0,SIGNMODE
;
; Result: AARG <-- AARG * BARG
;
; Timing: 99 clks
;
;
MUL2416SU
MOVFF BSR,BSRTMP ;Store bank
MOVLB BANK1
MOVFF AARGB0,TEMP0 ;Store AARGB, each byte is moved to TEMP3 for processing.
MOVFF AARGB1,TEMP1
MOVFF AARGB2,TEMP2
CLRF AARGB3 ;Clear high order bytes
CLRF AARGB4 ;
SETF SIGNMODE ;Set Signed operation mode
CLRF SIGNMODE ;Clear SIGNMODE here and the routine will operate unsigned.
MOVFF BARGB0,WREG ;Multiply B0*A
MULWF AARGB0 ;B0*A0
MOVFF PRODH,AARGB1 ;
MOVFF PRODL,AARGB0 ;->A1,A0
MOVFF TEMP1,TEMP3 ;Get A1
MULWF TEMP3 ;B0*A1
MOVFF PRODL,WREG ;
ADDWF AARGB1 ;Add to partial sum
MOVFF PRODH,AARGB2 ;
MOVFF BARGB0,WREG ;
MOVFF TEMP2,TEMP3 ;A2
MULWF TEMP3 ;B0*A2
MOVFF PRODL,WREG ;
ADDWFC AARGB2 ;Propagate carry from previous addition
MOVFF PRODH,WREG ;
ADDWFC AARGB3 ;Done B0*A ->A3,A0
MOVFF BARGB1,WREG ;Multiply B1*A
MOVFF TEMP0,TEMP3 ;Get A0
MULWF TEMP3 ;B1*A0
MOVFF PRODL,WREG ;
ADDWF AARGB1 ;B1 additions are shifted 1 byte to MSB
MOVFF PRODH,WREG ;
ADDWFC AARGB2 ;
CLRF WREG ;
ADDWFC AARGB3 ;Propagate carry from previous additions
ADDWFC AARGB4 ;Done A+256*(B1*A0)->A4,A0
MOVFF BARGB1,WREG ;
MOVFF TEMP1,TEMP3 ;Get A1
MULWF TEMP3 ;B1*A1
MOVFF PRODL,WREG ;
ADDWF AARGB2 ;
MOVFF PRODH,WREG ;
ADDWFC AARGB3 ;
CLRF WREG ;
ADDWFC AARGB4 ;Done B1*A1
MOVFF BARGB1,WREG ;
MOVFF TEMP2,TEMP3 ;Get A2
MULWF TEMP3 ;B1*A2
MOVFF PRODL,WREG ;
ADDWFC AARGB3 ;
MOVFF PRODH,WREG ;
ADDWFC AARGB4 ;Done B1*A2
BTFSS SIGNMODE,0 ;Operatin in signed mode?
BRA M2416SURET ;No!
BTFSS BARGB1,7 ;Yes! B negative?
GOTO TSIGN2416 ;No!
MOVFF TEMP0,WREG ;
SUBWF AARGB2,F ;
MOVFF TEMP1,WREG ;
SUBWFB AARGB3,F ;
MOVFF TEMP2,WREG ;
SUBWFB AARGB4,F ;
TSIGN2416 BTFSS TEMP2,7 ;A negative?
BRA M2416SURET ;No!
MOVFF BARGB0,WREG ;
SUBWF AARGB3,F ;
MOVFF BARGB1,WREG ;
SUBWFB AARGB4,F ;
MOVFF BSRTMP,BSR ;Restore bank
M2416SURET RETURN ;
;**********************************************************************************************

;************** 16x16 Bit Signed Fixed Point Multiply 16 x 16 -> 32 ***************************
;
; Input: 16 bit signed fixed point multiplicand in AARGB3, AARGB2 (NOTE! AARGB2 is LSB )
; 16 bit signed fixed point multiplier in BARGB1, BARGB0 (NOTE! BARGB0 is LSB )
;
; Use: CALL FXM1616S
;
; Output: 32 bit signed fixed point product in AARGB3,AARGB2,AARGB1,AARGB0
; NOTE! AARGB3 is MSB and AARGB0 is LSB !!
;
; Result: AARG <-- AARG * BARG
;
; Max Timing: 39 clks
;
; Min Timing: 31 clks
;
; PM: 38 DM: 8
;
FXM1616S
MOVFF BSR,BSRTMP ;Store bank
MOVLB BANK1
MOVFF AARGB3,TEMPB0
MOVFF AARGB2,TEMPB1
MOVFF AARGB2,WREG
MULWF BARGB0
MOVFF PRODH,AARGB1

MOVFF PRODL,AARGB0
MOVFF AARGB3,WREG
MULWF BARGB1
MOVFF PRODH,AARGB3
MOVFF PRODL,AARGB2

MULWF BARGB0
MOVFF PRODL,WREG
ADDWF AARGB1,F
MOVFF PRODH,WREG
ADDWFC AARGB2,F

CLRF WREG
ADDWFC AARGB3,F
MOVFF TEMPB1,WREG
MULWF BARGB1
MOVFF PRODL,WREG

ADDWF AARGB1,F
MOVFF PRODH,WREG
ADDWFC AARGB2,F
CLRF WREG
ADDWFC AARGB3,F

BTFSS BARGB1,7
GOTO TSIGN1616A
MOVFF TEMPB1,WREG
SUBWF AARGB2,F
MOVFF TEMPB0,WREG

SUBWFB AARGB3,F
TSIGN1616A BTFSS TEMPB0,7
BRA RET1616
MOVFF BARGB0,WREG
SUBWF AARGB2,F
MOVFF BARGB1,WREG
SUBWFB AARGB3,F

RET1616 MOVFF BSRTMP,BSR
RETURN
;**********************************************************************************************
;**********************************************************************************************
; Signed divide 16 bits by 16 bits: 16 bit quotient, 16 bit remainder.
; AARGB1,0 / BARGB1,0 -> AARGB1,0 remainder in REMB1,0
; Uses DLOOPER
; 402 cycles max
;
SDIV16_16
MOVFF BSR,BSRTMP ;Store bank
MOVLB BANK1
CLRF SIGN ;ASSUME POSITIVE
CLRF REMB0
CLRF REMB1
BTFSS BARGB1,MSB ; if MSB set go & negate BARG to bring it positive
GOTO D1616ANEG
BCF STATUS,C
CLRF WREG
COMF BARGB0
COMF BARGB1
INCF BARGB0
ADDWFC BARGB1
SETF SIGN ;NEGATIVE
D1616ANEG BTFSS AARGB1,MSB ; if MSB set go & negate AARG to bring it positive
GOTO D1616POS
BCF STATUS,C
CLRF WREG
COMF AARGB0
COMF AARGB1
INCF AARGB0
ADDWFC AARGB1
SETF SIGN ;NEGATIVE
D1616POS MOVLW .16 ;16 bits.At this point both AARGB and BAARGB are positive
MOVFF WREG,DLOOPER
D16LOOP RLCF AARGB0
RLCF AARGB1
RLCF REMB0
RLCF REMB1
MOVFF BARGB1,WREG
SUBWF REMB1,W
BTFSS STATUS,Z
BRA check16sgn
MOVFF BARGB0,WREG
SUBWF REMB0,W
check16sgn BTFSS STATUS,C
BRA check16cnt
MOVFF BARGB0,WREG ;subtract least significant byte
SUBWF REMB0,F
MOVFF BARGB1,WREG ;2nd byte
SUBWFB REMB1,F
BSF STATUS,C
check16cnt DECFSZ DLOOPER
BRA D16LOOP
RLCF AARGB0
RLCF AARGB1 ;Division is done.
BTFSS SIGN,BIT7 ;NEGATIVE?
BRA D1616 ;NO!
BCF STATUS,C ;NEGATE QUOTIENT
CLRF WREG
COMF AARGB0
COMF AARGB1
INCF AARGB0
ADDWFC AARGB1
BCF STATUS,C ;AND REMAINDER...
CLRF WREG
COMF BARGB0
COMF BARGB1
INCF BARGB0
ADDWFC BARGB1
D1616 MOVFF BSRTMP,BSR
RETURN
;**********************************************************************************************

;**********************************************************************************************
; Unsigned divide 32 bits by 32 bits: 32 bit quotient, 32 bit remainder.
; AARGB3,2,1,0 / BARGB3,2,1,0 -> AARGB3,2,1,0 remainder in REMB3,2,1,0
; Uses DLOOPER
; 1365 cycles max
;
DIV32_32
MOVFF BSR,BSRTMP ;Store bank
MOVLB BANK1
CLRF REMB0
CLRF REMB1
CLRF REMB2
CLRF REMB3
MOVLW .32 ;32 bits
MOVFF WREG,DLOOPER
D32LOOP RLCF AARGB0
RLCF AARGB1
RLCF AARGB2
RLCF AARGB3
RLCF REMB0
RLCF REMB1
RLCF REMB2
RLCF REMB3
MOVFF BARGB3,WREG
SUBWF REMB3,W
BTFSS STATUS,Z
BRA check32sgn
MOVFF BARGB2,WREG
SUBWF REMB2,W
BTFSS STATUS,Z
BRA check32sgn
MOVFF BARGB1,WREG
SUBWF REMB1,W
BTFSS STATUS,Z
BRA check32sgn
MOVFF BARGB0,WREG
SUBWF REMB0,W
check32sgn BTFSS STATUS,C
BRA check32cnt
MOVFF BARGB0,WREG ;subtract least significant byte
SUBWF REMB0,F
MOVFF BARGB1,WREG ;2nd byte
SUBWFB REMB1,F
MOVFF BARGB2,WREG ;3rd byte
SUBWFB REMB2,F
MOVFF BARGB3,WREG ;4th byte
SUBWFB REMB3,F
BSF STATUS,C
check32cnt DECFSZ DLOOPER
BRA D32LOOP
RLCF AARGB0
RLCF AARGB1
RLCF AARGB2
RLCF AARGB3
MOVFF BSRTMP,BSR
RETURN
;**********************************************************************************************

;************************* PANELOUT **********************
PANELOUT
;Clock out the bits in PANEL to the shift register in the panel pcb.
;Bit assignment:
;b0-*Beep*
;b1-*Radio High*
;b2-*Radio Low*
;b3-*Drift Radio*
;b4-*Service Low*
;b5-*Service High*
;b6-*Drift Service*
;b7-NC
MOVFF BSR,BSRTMP
MOVLB BANK1
;First rearrange the bits....
CLRF OUTL ;Clear 16bit shiftregister
CLRF OUTH ;prior to loading new data
BCF STATUS,C
MOVFF PANEL,WREG
DO7 RLCF WREG
BC PANELb7 ;Excamine bit7
BRA DO6
PANELb7 BSF OUTH,7 ;Move to 16bit register
DO6 RLCF WREG
BC PANELb6 ;Excamine bit6
BRA DO5
PANELb6 BSF OUTH,6 ;Move to 16bit register
DO5 RLCF WREG
BC PANELb5 ;Excamine bit5
BRA DO4
PANELb5 BSF OUTL,5 ;Move to 16bit register
DO4 RLCF WREG
BC PANELb4 ;Excamine bit4
BRA DO3
PANELb4 BSF OUTL,7 ;Move to 16bit register
DO3 RLCF WREG
BC PANELb3 ;Excamine bit3
BRA DO2
PANELb3 BSF OUTL,6 ;Move to 16bit register
DO2 RLCF WREG
BC PANELb2 ;Excamine bit2
BRA DO1
PANELb2 BSF OUTL,4 ;Move to 16bit register
DO1 RLCF WREG
BC PANELb1 ;Excamine bit1
BRA DO0
PANELb1 BSF OUTL,3 ;Move to 16bit register
DO0 RLCF WREG
BC PANELb0 ;Excamine bit0
BRA OUT
PANELb0 BSF OUTL,0 ;Move to 16bit register
;-----------------------------------
OUT MOVLW 0X08 ;8+2 (10) bits will be shifted
MOVFF WREG,BITCNT ;Initiate bitcounter
MOVFF OUTH,WREG ;Get High databyte
BCF PORTB,5 ;Set clock low
BCF PORTB,2 ;Set strobe low
;First transfer the 2 MSB bits...
RLCF WREG ;Get bit
BC BIT10ONE ;Branch if set
BCF PORTB,3 ;Output low data
BRA CLOCK10 ;Clock out
BIT10ONE BSF PORTB,3 ;Output high data
CLOCK10 BSF PORTB,5 ;Clock high
BCF PORTB,5 ;Completed transfer of bit10.
RLCF WREG ;Get bit
BC BIT09ONE ;Branch if set
BCF PORTB,3 ;Output low data
BRA CLOCK09 ;Clock out
BIT09ONE BSF PORTB,3 ;Output high data
CLOCK09 BSF PORTB,5 ;Clock high
BCF PORTB,5 ;Completed transfer of bit09.
;Next transfer the 8 LSB bits...
MOVFF OUTL,WREG ;Get Low databyte
NEXTBIT RLCF WREG ;Get bit
BC BITONE ;Branch if set
BCF PORTB,3 ;Output low data
BRA CLOCK ;Clock out
BITONE BSF PORTB,3 ;Output high data
CLOCK BSF PORTB,5 ;Clock high
BCF PORTB,5 ;Completed transfer of one bit.
BCF STATUS,C ;Clear carry for bit 9 and bit 10
DECFSZ BITCNT ;Clockec out 8 bits?
BRA NEXTBIT ;No!
BSF PORTB,2 ;Yes! Strobe to output latch
BCF PORTB,2 ;10 bits transmitted
PANELOUTRET MOVFF BSRTMP,BSR
RETURN
;******************************************************

;End of program

END
Eirik,

Thanks, I'll see if I can make some sense of the code. It's been many years
since I've done any assembler, but looks familiar.

I guess I should have mentioned I was using the C18 compiler.

Steve

From: p... [mailto:p...] On Behalf Of
Eirik Karlsen
Sent: Wednesday, August 27, 2008 5:23 PM
To: p...
Subject: Re: [piclist] C18 ADC question

Steve,
attached is source (assembly) for a sort of battery monitor I made a few
years ago.
There is code for reading and filtering 4 analog inputs. The ADC routines
and the port config
should get you going.

Steve Nance wrote:

Denis & Gavin,

Thanks for your responses. Actually I already have the USB link working and
can turn LEDs on/off from a C# program. That part is working. I just need to

configure the PIC for an ADC and pass the data back to the USB client.

I am using the PICDEM FS USB Demo board and have the Micro Chip Demo C code,

but it has so many features I don't know which settings I need to use just
for the ADC.

Steve

--
*******************************************
VISIT MY HOME PAGE:

LAST UPDATED: 23/08/2003
*******************************************
Regards
Eirik Karlsen
Steve,

Can't you just use the A/D macros in the library? Just a couple and you
should have the A/D working. I'm used to using the Hitec C compiler, and
separate functions for doing A/D, I2C, etc, but these look convenient. Look
up the examples in your C18 directory.

Alan KM6VV

_____

From: p... [mailto:p...] On Behalf Of
Steve Nance
Sent: Wednesday, August 27, 2008 4:59 PM
To: p...
Subject: RE: [piclist] C18 ADC question

Eirik,

Thanks, I'll see if I can make some sense of the code. It's been many years
since I've done any assembler, but looks familiar.

I guess I should have mentioned I was using the C18 compiler.

Steve
Anyone know where I can get a Serial UART routine, written in 'C', that's
suitable for a 12F675?

Steve