;SerialLogger.ASM G4JNT Sept 2011 ;Serial Port Logger new redesigned version to replace HF-08 ; All timings based on 3.2768MHz Xtal (819.2kHz clock) ;RS232 polarity determined by lnk on B5 list P=16F819 include "P16F819.INC" errorlevel 2 __config 0x3F61 ;11 1111 0110 0101 PUT On, WDT Off, XT Osc, BOR On, LVP Off, RA5 = CLR __idlocs 0xA100 #define SerIn PORTB , 7 ;Data IN from PC #define SerOut PORTB , 6 ;Data OUT to PC #define PolarityLink PORTB , 5 ;1 = TTL logic, 0 = RS232 #define LED PORTB , 4 #define SendIt Flags, 0 #define SingleChannel Flags, 1 BAUDCONST = d'11' ;(Fclock / Baud - 18) / 6 ;Timing intervals, in units of 40ms (Fclock / 32768) T1 = d'2' ;80ms T2 = d'25' ;1s T3 = d'125' ;5s T4 = d'250' ;10s T5 = d'500' ;20s T6 = d'1500' ;1 min T7 = d'3000' ;2 mins T8 = d'7500' ;5 mins org 0x2100 ;===================================== org 0 nop goto StartUp ;jump to main code ;===================================== org 4 ; Interrupt Handler bcf INTCON, TMR0IF ;Timer interrupt every 40ms (25Hz) movwf Wreg ;Save W swapf STATUS , W ; nb. movwf does not affect any STATUS bits movwf SaveSts ;Save STATUS, without affecting it ; bcf INTCON, RBIF bcf LED movf IntCountHi, W ;Maintain separate count at 40Hz to allow faster sampling intervals iorwf IntCountLo, W ;test if both zero first, to force an initial reading btfss STATUS, Z goto NotThisTime bsf LED ;20ms flash every read bsf SendIt ;Set the flag so main routine can send the data, straddling several interrupts if necessary ;....... NotThisTime incf IntCountLo ;Maintain separate count at 40Hz to allow faster sampling intervals btfsc STATUS, Z incf IntCountHi movf RptCountHi, W subwf IntCountHi, W ;W = HI(IntCountHi - Threshold) btfss STATUS, C ;if -ve, C=0, no further action goto OutTmrInt ;Need to subtract as rate may have been changed ; using RS232 updating movf RptCountLo, W subwf IntCountLo, W btfss STATUS, Z ;If LO(IntCountHi - Threshold) >=0, reset the goto OutTmrInt ; counter, and trigger a reading next interrupt clrf IntCountLo clrf IntCountHi OutTmrInt incf IntCounter ;Now do the independent seconds count movlw d'25' subwf IntCounter, W ;W = Counter - 25 btfsc STATUS, C ;if +Ve / zero, (C=1) reset to zero clrf IntCounter ;Counts 0 - 24, rolls over at 1 second intervals movf IntCounter, W ;Test if zero btfss STATUS, Z goto NoSecondsUpdate incf SecondsLo btfsc STATUS, Z incf SecondsMe btfsc STATUS, Z incf SecondsHi ;24 bit count rolls over every ~ 194 days NoSecondsUpdate swapf SaveSts , W ;Restore STATUS movwf STATUS swapf Wreg ;Restore W swapf Wreg , W ;Can't use movf as it affects Z bit retfie ;===================================== StartUp bcf STATUS, RP1 bsf STATUS, RP0 ;ram page 1 movlw b'00000110' ;Internal input, Prescalar /128, pull-ups movwf OPTION_REG movlw b'00011111' ;All analogue inputs movwf PORTA movlw b'10101111' ;B0-3 Link inputs, B7 serial data movwf PORTB ; movlw 0x85 ;AN0,1,2,4,5, Ext Ref+ on AN3 movwf ADCON1 ; right justified result bcf STATUS , RP0 movlw 7 movwf PCLATH ;All tables in page 7 clrf Flags clrf IntCountHi clrf IntCountLo clrf SecondsLo clrf SecondsMe clrf SecondsHi clrf IntCounter bsf LED movlw d'100' call DelayNms bcf LED movlw d'250' call DelayNms bsf LED movlw d'100' call DelayNms bcf LED movlw d'250' call DelayNms call ReadLinks call IntroMsg bsf INTCON, TMR0IE ;50Hz interrupt timer bsf INTCON, GIE ; bsf INTCON, RBIE ;PortB change int enable, ready for R232 input MainLoop btfss SendIt goto MainLoop call DoTime call BinToBCD call SendLongNumber movlw 9 call SendByte movlw "*" call SendByte movlw 9 ;Use TAB delimiter call SendByte movlw 0 call ReadAD ;result in A1/0 clrf A2 call BinToBCD call SendNumber btfsc SingleChannel goto SkipHigherChannels movlw 9 call SendByte movlw 1 call ReadAD ;result in A1/0 clrf A2 call BinToBCD call SendNumber movlw 9 call SendByte movlw 4 ;CH3 & CH2 input swapped on PCB, and CH3 is A/D CH4, coz CH3 is reference call ReadAD ;result in A1/0 clrf A2 call BinToBCD call SendNumber movlw 9 call SendByte movlw 2 call ReadAD ;result in A1/0 clrf A2 call BinToBCD call SendNumber SkipHigherChannels movlw 0x0D call SendByte movlw 0x0A call SendByte bcf SendIt call ReadLinks goto MainLoop ;================================ ReadLinks comf PORTB, W ;Read links, convert to interrupt count threshold andlw 0x07 ;Invert data so link installed = 1 call RateTableHi movwf RptCountHi comf PORTB, W andlw 0x07 call RateTableLo movwf RptCountLo btfss PORTB, 3 ;Link installed, uses A/D channel 0 only bsf SingleChannel btfsc PORTB, 3 bcf SingleChannel return ;------------------------------------------------- ReadAD ;Returns with scaled reading in A0/A1 movwf Temp rlf Temp rlf Temp rlf Temp, W andlw b'00111000 iorlw b'01000001' ;AD On, Channel in bits 3-5 movwf ADCON0 call HalfBaudDelay ;Give it some acquisition time bsf ADCON0, GO TestAdDone btfsc ADCON0, GO goto TestAdDone ;Loop until Chan 0 conversion is done bsf STATUS, RP0 movf ADRESL, W bcf STATUS, RP0 movwf A0 movf ADRESH, W movwf A1 bcf STATUS, C ;Multiply by 4 to give reading in mV based on 4.096V reference rlf A0 rlf A1 bcf STATUS, C rlf A0 rlf A1 return ;-------------------------------------------------- DoTime movf SecondsLo, W movwf A0 movf SecondsMe, W movwf A1 movf SecondsHi, W movwf A2 return ;------------------------------- Delay5ms movlw 5 DelayNms ;callable delay of approx N ms based on 1MHz clock movwf DelCount2 DelmsLoop2 movlw d'100' ;Inner loop 10 * 240 movwf DelCount DelmsLoop goto $+1 goto $+1 goto $+1 nop decfsz DelCount goto DelmsLoop decfsz DelCount2 goto DelmsLoop2 return ;-------------------------------- SendLongNumber swapf BCDHi, W andlw 0x0F addlw 0x30 call SendByte movf BCDHi, W andlw 0x0F addlw 0x30 call SendByte SendNumber swapf BCDMe, W andlw 0x0F addlw 0x30 call SendByte movf BCDMe, W andlw 0x0F addlw 0x30 call SendByte swapf BCDLo, W andlw 0x0F addlw 0x30 call SendByte movf BCDLo, W andlw 0x0F addlw 0x30 call SendByte return ;-------------------------------- HexToChar ;Convert 4 bit nibble to single Ascii character andlw 0x0F ;Mask off any high order stuff addlw 0x30 movwf Temp2 sublw 0x39 ;W = "9" - W, if -ve, A-F, C = 0 so add 7 movf Temp2, W ;Recover data, doesn't affect Carry btfss STATUS , C addlw 7 return ;-------------------------------------------- BinToBCD ;Takes in A2/A1/A0, calculates packed BCD equivalent clrf BCDVi ;Result in BCDVi/Hi/Me/Lo clrf BCDHi ;Also uses BcdCounter, BcdTemp Destroys A clrf BCDMe ; may be able to reuse Q registers in some cases clrf BCDLo ;Approx 1235 clocks movlw d'24' movwf BcdCounter BcdLoop rlf A0 rlf A1 rlf A2 rlf BCDLo rlf BCDMe rlf BCDHi rlf BCDVi decfsz BcdCounter ;Need a final shift only, so loop count here goto BCDgo goto BCDone ;.......... BCDgo movf BCDVi , W addlw 3 movwf BcdTemp btfsc BcdTemp , 3 movwf BCDVi ;If BCDVi >= 5, add 3 and store back movf BCDVi , W addlw 0x30 movwf BcdTemp btfsc BcdTemp , 7 movwf BCDVi ;Adjust BCDVi if > 80 movf BCDHi , W addlw 3 movwf BcdTemp btfsc BcdTemp , 3 movwf BCDHi movf BCDHi , W addlw 0x30 movwf BcdTemp btfsc BcdTemp , 7 movwf BCDHi movf BCDMe , W ;Repeating for middle then low digits addlw 3 movwf BcdTemp btfsc BcdTemp , 3 movwf BCDMe movf BCDMe , W addlw 0x30 movwf BcdTemp btfsc BcdTemp , 7 movwf BCDMe movf BCDLo , W ; addlw 3 movwf BcdTemp btfsc BcdTemp , 3 movwf BCDLo movf BCDLo , W addlw 0x30 movwf BcdTemp btfsc BcdTemp , 7 movwf BCDLo goto BcdLoop ;........... BCDone return ;-------------------------------------------- Multiply16 ;16 bit * 16 bit multiplication, more efficient method clrf Q0 clrf Q1 ;A and B 16 bit clrf Q2 clrf Q3 ;Up to 328 clock cycles max movlw d'16' movwf Counter MultLoop bcf STATUS , C rrf A1 ;Working bit into carry rrf A0 ;Repeatedly adds shifted version of B btfss STATUS , C ; into Q depending on working bit of A goto NoMult movf B0 , W ;get shifted BLo value addwf Q2 ; and add into accumulator if 1 in btfss STATUS , C ; appropriate bit in Avalue goto MulAdd1 movlw 1 addwf Q3 MulAdd1 movf B1 , W addwf Q3 NoMult ;Need to rotate in carry from final addition rrf Q3 ;C already zero if we've jumped in here rrf Q2 rrf Q1 rrf Q0 decfsz Counter goto MultLoop return ;Q3/2/1/0 = A * B A kept, B destroyed ;------------------------------------------------------------------ Div2N ;Divide Q0/1/2/3 by 2^N movwf BcdCounter iorlw 0 ;Test the value btfsc STATUS, Z return ;If zero do nothing DivLoop bcf STATUS, C rrf Q3 rrf Q2 rrf Q1 rrf Q0 decfsz BcdCounter goto DivLoop return ;------------------------------------------------------------ Divide32x16 ;[32bit] A / [16 bit] B = [32 bit] Quotient, movlw d'32' ; remainder [16 bit] in R movwf Counter clrf R0 clrf R1 Divide16Loop bcf STATUS, C rlf A0 rlf A1 rlf A2 rlf A3 rlf R0 rlf R1 ;Rotate A through Remainder movf R0, W ;Make backup of original R0/1 movwf Temp movf R1, W movwf Temp2 movf B0, W subwf R0 btfsc STATUS, C goto NotDiv16Ovf decf R1 comf R1, W ;if borrowed, R1 will go to 0xFF btfsc STATUS, Z ; so test for 0xFF by complementing it to zero (in W) goto RestoreR NotDiv16Ovf ;R0/1 contains the result of the subtraction movf B1, W ; irrespective of any overflow or not. subwf R1 btfsc STATUS, C goto DivdPassThru ;With C=1, result was sucessful RestoreR movf Temp, W ;If overflow, have to recover original R1/0 movwf R0 ; from the backup movf Temp2, W movwf R1 ;Otherwise, leave R as it stands bcf STATUS, C ;C=0 to be shifted into Q DivdPassThru rlf Q0 ;Use the carry bit from the subtraction rlf Q1 ; to build up Q rlf Q2 rlf Q3 decfsz Counter goto Divide16Loop return ;------------------------------------ SendByte ;Enter with data in W, send it to PC movwf Temp ;Uses Temp, Counter, [DelCount] bcf INTCON, GIE ;Inhibit all interrupts to avoid ; corrupting sent data. btfss PolarityLink goto SendAs232 bcf SerOut ;TTL / Logic polarity call HalfBaudDelay call HalfBaudDelay movlw 8 movwf Counter SendDatLoopX rrf Temp ;bit into C btfsc STATUS , C bsf SerOut btfss STATUS , C bcf SerOut call HalfBaudDelay call HalfBaudDelay decfsz Counter goto SendDatLoopX ;loop 8 + 2 * HalfBaudDelay long bsf SerOut ;stop bit bsf INTCON, GIE ;restore interrupts call HalfBaudDelay call HalfBaudDelay return ;...................... SendAs232 ;RS232 polarity bsf SerOut call HalfBaudDelay call HalfBaudDelay movlw 8 movwf Counter SendDatLoopY rrf Temp ;bit into C btfsc STATUS , C bcf SerOut btfss STATUS , C bsf SerOut call HalfBaudDelay call HalfBaudDelay decfsz Counter goto SendDatLoopY bcf SerOut ;stop bit bsf INTCON, GIE ;restore interrupts call HalfBaudDelay call HalfBaudDelay return ;-------------------------------------- HalfBaudDelay movlw BAUDCONST ; movwf DelCount ;baud period delay LoopBit ;Total Delay = 3.N + 5 clocks decfsz DelCount goto LoopBit return ;------------------------------------------- GetEE8 ;New EE routines needed as banks 2/3 used bsf STATUS, RP1 ;Address (0 - 63) in W, result in W bcf STATUS, RP0 ;Bank 2 movwf EEADR bsf STATUS, RP0 ;Bank 3 bcf EECON1, EEPGD ;Point to Data memory bsf EECON1, RD ;EE Read bcf STATUS, RP0 ;Bank2 movf EEDATA, w bcf STATUS, RP1 ;Reset to Bank 0 return ;-------------------------------- EEWrite8 ;Writes data in W to address in EEAddress bsf STATUS, RP1 ; bcf STATUS, RP0 ;Bank 2 movwf EEDATA ; bcf STATUS, RP1 ;Bank 0 movf EEAddress, w bsf STATUS, RP1 ;Bank2 movwf EEADR bsf STATUS, RP0 ;Bank 3 bcf EECON1, EEPGD ; bsf EECON1, WREN ; ; bcf INTCON, GIE movlw 0x55 movwf EECON2 movlw 0xAA movwf EECON2 bsf EECON1, WR EEWaitW btfsc EECON1, WR ;WR is cleared in hardware when write is complete goto EEWaitW bcf EECON1, WREN bcf STATUS, RP0 ;Back to Bank 0 bcf STATUS, RP1 ; bsf INTCON, GIE ;restore Interrupts return ;--------------------------- IntroMsg movlw 0x0D call SendByte movlw 0x0A call SendByte movlw "S" call SendByte movlw "e" call SendByte movlw "r" call SendByte movlw "i" call SendByte movlw "a" call SendByte movlw "l" call SendByte movlw " " call SendByte movlw "P" call SendByte movlw "o" call SendByte movlw "r" call SendByte movlw "t" call SendByte movlw " " call SendByte movlw "D" call SendByte movlw "a" call SendByte movlw "t" call SendByte movlw "a" call SendByte movlw " " call SendByte movlw "L" call SendByte movlw "o" call SendByte movlw "g" call SendByte movlw "g" call SendByte movlw "e" call SendByte movlw "r" call SendByte movlw " " call SendByte movlw " " call SendByte movlw " " call SendByte movlw "G" call SendByte movlw "4" call SendByte movlw "J" call SendByte movlw "N" call SendByte movlw "T" call SendByte movlw " " call SendByte movlw " " call SendByte movlw "V" call SendByte movlw "e" call SendByte movlw "r" call SendByte movlw " " call SendByte movlw "1" call SendByte movlw "." call SendByte movlw "0" call SendByte movlw " " call SendByte movlw "S" call SendByte movlw "e" call SendByte movlw "p" call SendByte movlw "t" call SendByte movlw " " call SendByte movlw "2" call SendByte movlw "0" call SendByte movlw "1" call SendByte movlw "1" call SendByte movlw 0x0D call SendByte movlw 0x0A call SendByte return ;--------------------------- org 0x700 RateTableHi andlw 0x07 addwf PCL dt HIGH(T1),HIGH(T2),HIGH(T3),HIGH(T4),HIGH(T5),HIGH(T6),HIGH(T7),HIGH(T8) ;.................. RateTableLo andlw 0x07 addwf PCL dt LOW(T1),LOW(T2),LOW(T3),LOW(T4),LOW(T5),LOW(T6),LOW(T7),LOW(T8), ;==================================== cblock 0x20 Temp, Temp2 Wreg, SaveSts Counter, DelCount, DelCount2 Flags EEAddress, EEContents BCDVi, BCDHi, BCDMe, BCDLo, DPoint BcdTemp, BcdCounter IntCountHi, IntCountLo RptCountHi, RptCountLo IntCounter, SecondsLo, SecondsMe, SecondsHi A0, A1, A2, A3 ;Input to maths rountines B0, B1 Q0, Q1, Q2, Q3 ;Result from Multiplication, and Division quotient R0, R1 ;Divisior remainder Rho0, Rho1 endc end