; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ; Panteltje swr ; copyright Jan Panteltje 2008-always ; integer math copyright Microchip, some other routines copyright others, my part is GPL. ; ; ; This is a SWR and power meter with output on a 4 line x 20 char LCD, and RS232 interface. ; It also has a 24 hour clock. ; Uses a PIC 16F690, and the PIC's internal 8MHz oscillator, and seems quite accurate, ; CHANGES ; ; 0.1 ; First release ; 0.5: ; Added swtch fro remote, off, rx, tx ; Divider for volts: 1k to ground, 18k and 1k in series (exact value 1 / 20.46, thisis 1 / 20.5) so 1023 steps ADC is 102.3V. ; That way a 12V battery will read 13.4 V for example. ; Decouple all analog input pins with 100nF to ground at the chip. ; The soft has a serial 19200 Baud, 8 bits no parity interface, and accepts the following commands: ; D enters debug mode, continuously prints adc steps for forward, reflected, power, and flags2 ; d exits debug mode. ; h prints help. ; Ctlr PnnnENTER sets PWM output value, LCD backlight, range 0 to 100, stored in EEPROM. ; p prints PWM setting. ; v prints version number. ; X transceiver power on. ; x transceiver power off. ; Y transmitter on. ; y transmitter off. ; removed command_end_status label. ; The math is done in integer. ; CODE IS FOR GPASM, may work on MPLAB too. ; Calculations are for a Vref = Vsupply of 5.0V, use LM317 for example. TRUE equ 1 FALSE equ 0 MSB equ 7 SIGNED equ FALSE ; Set This To 'TRUE' if the routines ; ; for Multiplication & Division needs ; ; to be assembled as Signed Integer ; ; Routines. If 'FALSE' the above two ; ; routines ( D_mpy & D_div ) use ; ; unsigned arithmetic. ; for commands with numeric arguments. #define COMMAND_OFF D'0' #define COMMAND_PRINT_VERSION D'1' #define COMMAND_SET_PWM D'2' #define COMMAND_PRINT_PWM D'3' #define COMMAND_PRINT_HELP D'4' #define COMMAND_POWER_OFF D'6' #define COMMAND_POWER_ON D'7' #define COMMAND_TX_OFF D'8' #define COMMAND_TX_ON D'9' ; mode for main #define MODE_OFF D'0' #define MODE_PRINT_VERSION D'1' #define MODE_SET_PWM D'2' #define MODE_PRINT_PWM D'3' #define MODE_PRINT_HELP D'4' #define MODE_READ_ADC D'5' #define MODE_POWER_OFF D'6' #define MODE_POWER_ON D'7' #define MODE_TX_OFF D'8' #define MODE_TX_ON D'9' ; ** NOTE: ** ; define config fuses ; IF YOU WANT TO RUN VERIFY, BETTER HAVE COPY PROTECTION OFF ;-) ; Internal OSC, pin 3 (RA4,AN3,T1G,OSC2,CLKOUT) available for IO. __CONFIG _FCMEN_OFF & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_OFF & _WDT_OFF & _INTOSCIO ; when !MRCLRE is asserted in INTOSC or RC mode, the internal clock oscillator is disabled. ; include PIC register definitions. PROCESSOR p16f690 include Dev_Freq EQU D'8000000' ; Device Frequency is 8 MHz LCD_INIT_DELAY EQU (HIGH ((( Dev_Freq / 4 ) * D'46' / D'10000' ) / 3 ) ) + 1 ; IO pin bit assignment PORTA, PORTB, PORTC ; RA and RB have change interrupt ; PORTA 6 bit wide ; PORTB 4 bit wide ; PORTC 8 bit wide ; define register file variables ; start at 0x20 hex, 32 dec, total 256 bytes ; 0x20 - 0x7f in bank 0 ; 32 - 127 ; 0x70 - 0x7f in each bank the same ; 112 - 127 ; 0xa0 - 0xef in bank 1 ; 160 - 239 ; 0x120 - 0x16f in bank 2 ; 288 - 376 ;offset equ D'32' delay_count1 equ D'33' ; 1ms delay old_minutes equ D'34' flags3 equ D'35' tx_timeout equ D'37' flags1 equ D'38' temp1 equ D'39' count equ D'40' temp_l equ D'41' temp_h equ D'42' temp equ D'43' ; temp for binary to BCD bin equ D'44' ; bin+1 for 16 bits equ D'45' bcd equ D'46' R0 equ D'47' ; BCD digit 5 right justified R1 equ D'48' ; BCD digit 4 and 3 R2 equ D'49' ; BCD digit 2 and 1 ii equ D'50' timer1_reload_l equ D'51' ; saved in EEPROM clock calibration old_seconds equ D'52' data_byte_cnt equ D'53' int_fsr_save equ D'54' portc_shadow equ D'55' command equ D'56' digit_in equ D'57' digit_cnt equ D'58' temp3 equ D'59' value equ D'60' flags2 equ D'61' ; saved in EEPROM swr_alert equ D'62' pwm_pulse_width equ D'63' analog_select equ D'64' minutes equ D'65' seconds_5 equ D'66' seconds equ D'67' MSD equ D'68' ; Temporary register, Holds Most Significant Digit of BIN to BCD conversion LSD equ D'69' ; Temporary register, Holds Least Significant Digit of BIN to BCD conversion TEMP equ D'70' ; Temporary register CHAR equ D'71' ; Temporary register, Holds value to send to LCD module. delay_count2 equ D'72' fsr_save equ D'101' fsr_save2 equ D'102' mode equ D'103' ad_h equ D'104' ad_l equ D'105' ; SAME IN ALL BANKS 112 - 127 hours equ D'112' eeprom_address equ D'113' eeprom_data equ D'114' ACCaLO equ D'115' ACCaHI equ D'116' ACCbLO equ D'117' ACCbHI equ D'118' ACCcLO equ D'119' ACCcHI equ D'120' ACCdLO equ D'121' ACCdHI equ D'122' sign equ D'123' s_pclath equ D'124' s_fsr equ D'125' temp_w equ D'126' temp_s equ D'127' ; define flags1 ONE_MINUTE_FLAG equ D'0' PRINT_DOT_FLAG equ D'1' SAVE_SETTINGS_FLAG equ D'2' FIRST_ZERO_SUPPRESSED_FLAG equ D'3' DIVIDE_BY_TEN_FLAG equ D'4' EEPROM_WRITE_ERROR_FLAG equ D'5' DEBUG_FLAG equ D'6' ONE_SECOND_FLAG equ D'7' ; define flags2 ; define flags3 RX_ON_FLAG equ D'0' TX_ON_FLAG equ D'1' FLASH_FLAG equ D'2' ; page macros call_0 macro subroutine_name clrf PCLATH ; Next call will go to page 0 call subroutine_name endm call_1 macro subroutine_name bsf PCLATH, 3 ; Next call or jump will go to page 1 CALL subroutine_name ; Jump to function that starts in this page endm ; macros to save and restore W and status register in interrupt. save_w_stat macro movwf temp_w swapf STATUS,W clrf STATUS ; extra force bank 0 clears IRP, RP1, RP0 movwf temp_s movfw PCLATH movwf s_pclath movfw FSR movwf s_fsr endm restore_w_stat macro movfw s_fsr movwf FSR movfw s_pclath movwf PCLATH swapf temp_s,W movwf STATUS swapf temp_w,F swapf temp_w,W endm ; code start org 0 goto main_init org 4 ; interrupt entry point ; 8 MHz internal OSC ; OPTION_REG is 0xff at power up! ; do interrupt processing here save_w_stat ; save W and status clrf PCLATH ; interrupts routines only call subroutines in page 0 banksel 0 ; what interrupt? ; test for timer 1 interrupt test_timer1_interrupt: ; banksel PIR1 ; bank 0 btfss PIR1, TMR1IF goto test_rx_interrupt ; decrement seconds / 5, if 0 reload 5, decrement seconds. bcf flags1, ONE_SECOND_FLAG decfsz seconds_5 goto in_5 bsf flags1, ONE_SECOND_FLAG movlw D'5' movwf seconds_5 ; increment seconds incf seconds ; test 60 seconds movlw D'60' subwf seconds, w btfss STATUS, Z goto in_5 one_minute: clrf seconds incf minutes bsf flags1, ONE_MINUTE_FLAG ; to be checked and cleared in main ; test 60 minutes movlw D'60' subwf minutes, w btfss STATUS, Z goto in_5 clrf minutes incf hours ; test 24 hours movlw D'24' subwf hours, w btfss STATUS, Z goto in_5 clrf hours in_5: ; reload 65535 - 50000 makes 5Hz = 200mS ; Calibrate clock speed here ; banksel TMR1H ; bank 0 65535 - 50000 = 15535 reload (upcounter int on overflow), makes 60 175 movlw D'60' movwf TMR1H ; movlw D'175' movfw timer1_reload_l movwf TMR1L ; banksel T1CON ; in bank 0 bsf T1CON, T1CKPS1 ; 11 = 1:8 prescaler bsf T1CON, T1CKPS0 ; ; banksel 0 ; goto int_end test_rx_interrupt: banksel PIR1 btfss PIR1, RCIF ; test if serial port interrupt goto int_end ; read rx status ; test framing error banksel RCSTA btfss RCSTA, FERR goto test_overrun ; framing error goto reset_rx_circuit test_overrun: btfss RCSTA, OERR goto get_rx_char ; overrun error reset_rx_circuit: ; clear error flags bcf RCSTA, FERR bcf RCSTA, OERR ; restart rx bcf RCSTA, CREN bsf RCSTA, CREN get_rx_char: ; have serial char in RCREG ; TEST echo for TEST ; movfw RCREG ; call tx_w ; force immediate response to serial input movfw seconds movwf old_seconds incf old_seconds ; CR movlw D'13' subwf RCREG, W btfsc STATUS, Z goto cr_command ; help movlw 'h' subwf RCREG, W btfsc STATUS, Z goto print_help_command ; pwm movlw D'16' ; ctrl P subwf RCREG, W btfsc STATUS, Z goto set_pwm_command movlw 'p' subwf RCREG, W btfsc STATUS, Z goto print_pwm_command ; version movlw 'v' subwf RCREG, W btfsc STATUS, Z goto print_version_command ; transceiver power movlw 'X' subwf RCREG, W btfsc STATUS, Z goto transceiver_power_on_command movlw 'x' subwf RCREG, W btfsc STATUS, Z goto transceiver_power_off_command ; tx movlw 'Y' subwf RCREG, W btfsc STATUS, Z goto transmitter_on_command movlw 'y' subwf RCREG, W btfsc STATUS, Z goto transmitter_off_command ; digits movlw '0' subwf RCREG, W btfsc STATUS, Z goto process_digits_command movlw '1' subwf RCREG, W btfsc STATUS, Z goto process_digits_command movlw '2' subwf RCREG, W btfsc STATUS, Z goto process_digits_command movlw '3' subwf RCREG, W btfsc STATUS, Z goto process_digits_command movlw '4' subwf RCREG, W btfsc STATUS, Z goto process_digits_command movlw '5' subwf RCREG, W btfsc STATUS, Z goto process_digits_command movlw '6' subwf RCREG, W btfsc STATUS, Z goto process_digits_command movlw '7' subwf RCREG, W btfsc STATUS, Z goto process_digits_command movlw '8' subwf RCREG, W btfsc STATUS, Z goto process_digits_command movlw '9' subwf RCREG, W btfsc STATUS, Z goto process_digits_command goto int_end cr_command: ; If zero digits were entered, do nothing movlw COMMAND_SET_PWM subwf command, W btfsc STATUS, Z goto end_set_pwm_command movlw COMMAND_OFF subwf digit_cnt, W btfsc STATUS, Z ; if zero digits do nothing goto int_end ; these commands have no numeric argument debug_on_command: banksel 0 bsf flags1, DEBUG_FLAG goto int_end_clr debug_off_command: banksel 0 bcf flags1, DEBUG_FLAG goto int_end_clr transceiver_power_on_command: movlw COMMAND_POWER_ON movwf command movlw MODE_POWER_ON movwf mode goto int_end_clr transceiver_power_off_command: movlw COMMAND_POWER_OFF movwf command movlw MODE_POWER_OFF movwf mode goto int_end_clr transmitter_on_command: movlw COMMAND_TX_ON movwf command movlw MODE_TX_ON movwf mode goto int_end_clr transmitter_off_command: movlw COMMAND_TX_OFF movwf command movlw MODE_TX_OFF movwf mode goto int_end_clr print_pwm_command: movlw COMMAND_PRINT_PWM movwf command movlw MODE_PRINT_PWM movwf mode goto int_end_clr print_help_command: movlw COMMAND_PRINT_HELP movwf command movlw MODE_PRINT_HELP movwf mode goto int_end_clr print_version_command: movlw COMMAND_PRINT_VERSION movwf command movlw MODE_PRINT_VERSION movwf mode goto int_end_clr ; these commands have a numeric argument set_pwm_command: movlw COMMAND_SET_PWM movwf command goto command_end ; final processing of commands with numeric arguments, we have the number in 'value' now. end_set_pwm_command: movfw value movwf pwm_pulse_width movlw MODE_SET_PWM movwf mode call save_settings ; bsf flags1, SAVE_SETTINGS_FLAG goto command_end process_digits_command: movlw D'48' subwf RCREG, W ; digit now in W movwf digit_in ; value = value * 10 ; value += RCREG movfw value ; W = original value ; look, I know about rlf, but we have 4096 words available. addwf value ; value * 2 addwf value ; value * 3 addwf value ; value * 4 addwf value ; value * 5 addwf value ; value * 6 addwf value ; value * 7 addwf value ; value * 8 addwf value ; value * 9 addwf value ; value * 10 movfw digit_in ; input digit in W addwf value ; add W to value incf digit_cnt goto int_end ; end of interrupt routines command_end: ; reset the value, so we can continue with nnnENTER banksel 0 clrf value clrf digit_cnt goto int_end int_end_clr: ; for non numeric commands, no digits expected. banksel 0 clrf command int_end: banksel 0 ; OLD IF COMPARATOR movf CMCON, W ; read CMCON to end mismatch because of comparator output change ; INTCON: GIE PEIE T0IE INTE RABIE T0IF INTF RABIF bcf INTCON, GIE ; bcf INTCON, PEIE bcf INTCON, T0IE bcf INTCON, INTE bcf INTCON, RABIE bcf INTCON, T0IF ; timer 0 overflow interrupt flag bcf INTCON, INTF ; GP2/INT bcf INTCON, RABIF ; port change interrupt flag bit ; PIR1 -- ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR1IF bcf PIR1, ADIF bcf PIR1, RCIF bcf PIR1, TXIF bcf PIR1, SSPIF bcf PIR1, CCP1IF bcf PIR1, TMR2IF bcf PIR1, TMR1IF ; PIR2 OSFIF C2IF C1IF EEIF -- -- -- -- bcf PIR2, OSFIF bcf PIR2, C2IF bcf PIR2, C1IF bcf PIR2, EEIF restore_w_stat ; get back W and status retfie main_init: ; set internal OSC speed, the output on pin 3 (OSC2) is this clock / 4. ; SELECT BANK banksel OSCCON ; clrf OSCCON ; all zero ; bcf OSCCON, 7 ; bit 7 not implemented bsf OSCCON, 6 ; bit 6 osc speed 111=8 MHz, 110=4MHz (default), 101=2MHz, 100=1MHz, 011=500kHz, 010=250kHz, 001=125kHz, 000=32kHz (LFINTOSC) bsf OSCCON, 5 ; bit 5 osc speed bsf OSCCON, 4 ; bit 4 osc speed bcf OSCCON, 3 ; bit 3, HTS 0 = internal OSC, 1 = external ; bcf OSCCON, 2 ; bit 2, HTS HFINTOSC status, 1 = stable ; bcf OSCCON, 1 ; bit 1, LTS LFINTOSC status, 1 = stable bcf OSCCON, 0 ; bit 0, SCS 0 = clock source defined by FOSC<2:0> of the CONFIG register, 1 = internal osc used for system clock ; initialize IO output latches banksel 0 ; load settings from eeprom 0 banksel 0 ; GPIO bank 0, address 0x05 clrf PORTA ; init all output latches to zero clrf PORTB clrf PORTC clrf portc_shadow ; portb init (4 to 7) banksel 0 ; banksel TRISB ; MOVLW 00h ; Set RB<7:4> as outputs ; MOVWF TRISB ; banksel 0 ; init async serial out ;12.1.1.6 Asynchronous Transmission Set-up: ;1. Initialize the SPBRGH, SPBRG register pair and ; the BRGH and BRG16 bits to achieve the desired ; baud rate (see Section 12.3 "EUSART Baud ; Rate Generator (BRG)"). ;2. Enable the asynchronous serial port by clearing ; the SYNC bit and setting the SPEN bit. ;3. If 9-bit transmission is desired, set the TX9 con- ; trol bit. A set ninth data bit will indicate that the 8 ; Least Significant data bits are an address when ; the receiver is set for address detection. ;4. Enable the transmission by setting the TXEN ; control bit. This will cause the TXIF interrupt bit ; to be set. ;5. If interrupts are desired, set the TXIE interrupt ; enable bit. An interrupt will occur immediately ; provided that the GIE and PEIE bits of the ; INTCON register are also set. ;6. If 9-bit transmission is selected, the ninth bit ; should be loaded into the TX9D data bit. ;7. Load 8-bit data into the TXREG register. This ; will start the transmission. ; 8 bit async ; SYNC = 0, BRG16 = 0, BRGH=1, at 8MHz: 19231 Baud, 0.16% for SPBRG=25 ; banksel TRISB ; bcf TRISB, TRISB7 ; pin 10 (RB7,TX,CK) output banksel SPBRG movlw D'25' movwf SPBRG ; default 8 bit mode, SPBRGH not used ; banksel SPBRGH banksel BAUDCTL bcf BAUDCTL, BRG16 banksel TXSTA bsf TXSTA, BRGH bcf TXSTA, SYNC banksel RCSTA bsf RCSTA, SPEN banksel TXSTA bsf TXSTA, TXEN ;12.1.2.8 Asynchronous Reception Set-up: ;1. Initialize the SPBRGH, SPBRG register pair and ; the BRGH and BRG16 bits to achieve the ; desired baud rate (see Section 12.3 "EUSART ; Baud Rate Generator (BRG)"). ;2. Enable the serial port by setting the SPEN bit. ; The SYNC bit must be clear for asynchronous ; operation. ;3. If interrupts are desired, set the RCIE interrupt ; enable bit and set the GIE and PEIE bits of the ; INTCON register. ;4. If 9-bit reception is desired, set the RX9 bit. ;5. Enable reception by setting the CREN bit. ;6. The RCIF interrupt flag bit will be set when a ; character is transferred from the receive shift ; register to the receive buffer. An interrupt will be ; generated if the RCIE interrupt enable bit was ; also set. ;7. Read the RCSTA register to get the error flags ; and, if 9-bit data reception is enabled, the ninth ; data bit. ;8. Get the received 8 Least Significant data bits ; from the receive buffer by reading the RCREG ; register. ;9. If an overrun occurred, clear the OERR flag by ; clearing the CREN receiver enable bit. banksel RCSTA bsf RCSTA, CREN ; SYNC and SPEN already done. banksel 0 ; Load 5 Hz ticck movlw D'5' movwf seconds_5 ; clock to 00:00 clrf seconds clrf minutes clrf hours ; init PWM call_1 pwm_init clrf PCLATH ;This code block configures the ADC ;for polling, Vdd reference, Frc clock ;and AN0 input. ; ;Conversion start & polling for completion ; are included. ; BANKSEL ADCON1 ; MOVLW B'00100000' ; not used, :32, ; bit 7 not used, zero ; bit 6 clock speed ; bit 5 clock speed ; bit 4 clock speed ; bit 3 not used ; bit 2 not used ; bit 1 not used ; bit 0 not used MOVWF ADCON1 ; ADC channels #define U_BAT D'3' #define ANA8 D'8' ; not used #define ANA9 D'9' ; not used #define ANA10 D'10' ; not used ; on PORTA POWER_OUT equ 5 ; RA5, pin 2 active low MODE_SWITCH3 equ 2 ; RA2, pin 17, active low, pullup used ; force receiver on MODE_SWITCH4 equ 1 ; RA1, pin 18, active low, pullup used ; force receiver on plus tx LOW_BATT equ 0 ; RA0, pin 6 active low ; on PORTB TX_OUT equ 6 ; RB6, pin 11 active high ; on PORTC ; IO used: ; IC3 IC4 ; Port pin pullup I/O pu act signal I/O pu act signal IC4 modifications ; ; RA5 2 * out SWR beeper out !PWR ; RA4 3 * ana V batt ana V batt ; RA3 4 in Vpp (n.c.) in Vpp (n.c) ; RA2 17 * ana I batt in * S3 no ana ; RA1 18 * out LCD R/W in * S4 ; RA0 19 * out LCD E out !low batt ; RB7 10 * out TXD out TXD (n.c.) ; RB6 11 * out !SWR alert LED out TX ; RB5 12 * in RXD in RXD ; RB4 13 * ana TX power ana n.c. ; RC7 9 ana reflected ana n.c. ; RC6 8 ana forward ana n.c. ; RC5 5 out PWM out PWM (n.c.) ; RC4 6 out LCD RS out n.c. ; RC3 7 out/I LCD D7 out n.c ; RC2 14 out LCD D6 out n.c. ; RC1 15 out LCD D5 out n.c. ; RC0 16 out LCD D4 out n.c. ; WAS ; 1 = input, 0 = output banksel TRISA movlw B'011110' movwf TRISA banksel TRISB movlw B'00110000' movwf TRISB banksel TRISC movlw B'11000000' movwf TRISC ; pullups porta banksel WPUA movlw B'00000110' ; select which port c pins are analog inputs ; Analog inputs: BANKSEL ANSEL ; default is 1111 1111 bcf ANSEL, 0 ; ASN 0 bcf ANSEL, 1 ; ASN 1 bcf ANSEL, 2 ; ASN 2 ; modified, was I batt bsf ANSEL, 3 ; ASN 3 ; U battery bcf ANSEL, 4 ; ASN 4 bcf ANSEL, 5 ; ASN 5 bcf ANSEL, 6 ; ASN 6 bcf ANSEL, 7 ; ASN 7 BANKSEL ANSELH ; default is 1111 bsf ANSELH, 0 ; ASN 8 ; forward in bsf ANSELH, 1 ; ASN 9 ; refected in bsf ANSELH, 2 ; ASN 10 ; power in bcf ANSELH, 3 ; ASN 11 UART RX ; only lower 4 bits used ; right justify analog result BANKSEL ADCON0 clrf ADCON0 bsf ADCON0, ADFM ; ADFM right justified bcf ADCON0, VCFG ; Vdd reference ; select an analog channel for the ADC bcf ADCON0, 5 ; 1 1010= AN10 bsf ADCON0, 4 ; 0 bcf ADCON0, 3 ; 1 bsf ADCON0, 2 ; 0 ; bit 1 is A/D conversion status bit ; start the ADC bsf ADCON0, ADON ; AD on ; OPTION_REG bank 1, address 0x81 ; !GPPU INTEDG T0CS T0SE PSA PS2 PS1 PS0 ; serial com init ; OPTION_REG: RABPU INTEDG T0CS T0SE PSA PS2 PS1 PS0 banksel OPTION_REG ; PSA: 1= prescaler to WDT, 0 = prescaler to TIMER0 movlw B'00000001' ; prescaler 1 ; movlw B'00001111' ; watchdog prescaler 128 movwf OPTION_REG ; bsf OPTION_REG, NOT_GPPU ; no pullups ; watchdog prescaler 128 111 bit<2-0> ; bsf OPTION_REG, PS2 ; bsf OPTION_REG, PS1 ; bsf OPTION_REG, PS0 ; Watchdog prescaler 128 ; from pdf page 84 ; BANKSEL TMR0 ; ; CLRWDT ;Clear WDT ; CLRF TMR0 ;Clear TMR0 and prescaler ; BANKSEL OPTION_REG ; ; BSF OPTION_REG, PSA ;Select WDT ; CLRWDT ; ; MOVLW b'11111000' ;Mask prescaler ; ANDWF OPTION_REG, W ; bits ; IORLW b'00000111' ;Set WDT prescaler 1:128 ;; IORLW b'00000101' ;Set WDT prescaler ; MOVWF OPTION_REG ; to 1:32 ; serial in interrupt enable banksel PIE1 clrf PIE1 bsf PIE1, RCIE ; USART receive interrupt enable ; bsf PIE1, ADIE ; AD converter interrupt enable (12F675 only) bsf PIE1, TMR1IE ; timer 1 overflow interrupt enable ; bsf PIE1, CMIE ; comparator interrupt enable ; PIE2: OSFIE C2IE C1IE EEIE -- -- -- -- banksel PIE2 bcf PIE2, EEIE ; EEPROM write complete interrupt enable ; flags to zero banksel 0 clrf flags1 ; clrf flags2 ; set by load_settings clrf flags3 ; OPTION_REG bank 1, address 0x81 ; !GPPU INTEDG T0CS T0SE PSA PS2 PS1 PS0 banksel OPTION_REG movlw B'00000001' ; prescaler 1 movwf OPTION_REG ; bsf OPTION_REG, NOT_RABPU ; disable pullups on port A and port B ; timer 1 :4 clock = 2MHz, :8 prescaler=250000 Hz, :50000 reload=5Hz interrupt ; T1CON: T1GINV TMR1GE T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON banksel T1CON bcf T1CON, T1GINV ; non invert bcf T1CON, TMR1GE ; no gate enable bsf T1CON, T1CKPS1 ; 11 = 1:8 prescaler bsf T1CON, T1CKPS0 ; bcf T1CON, T1OSCEN ; no external clock bcf T1CON, NOT_T1SYNC ; no sync bcf T1CON, TMR1CS ; select :4 internal osc = 2MHz bsf T1CON, TMR1ON ; timer 1 on ; set timer 1 reload 0, and clear TMR1IF as on page 88 pdf banksel TMR1H ; 50000 reload clrf TMR1H banksel TMR1L movwf TMR1L ; reset timer 1 interrupt flag banksel PIR1 bcf PIR1, TMR1IF banksel 0 ; enable gobal and peripheral interrupt banksel INTCON clrf INTCON bsf INTCON, PEIE ; peripheral interrupts enable ; bsf INTCON, T0IE ; timer 0 overflow interrupt enable ; bsf INTCON, INTE ; GP2/INT interrupt enable ; bsf INTCON, GPIE ; port change interrupt enable bsf INTCON, GIE ; global interrupt enable ; banksel WDTCON ; configure watchdog timer ; WDTCON: -- -- -- WDTPS3 WDTPS2 WDTPS1 WDTPS0 SWDTEN ; movlw B'00011111' ; software enable watchdog timer, : 65535 prescaler 31kHz osc, second prescaler : 128, 268 seconds ; movwf WDTCON main: banksel 0 ; load settings from eeprom 0 banksel 0 call load_settings ; adjust pwm, wait for correct reload moment here? banksel 0 movfw pwm_pulse_width banksel CCPR1L movwf CCPR1L ; force calc of Ah movfw minutes movwf old_minutes ; gets mysteriously set? banksel 0 bcf flags1, DEBUG_FLAG banksel 0 ; intial states, power is active low, TX is active high. ; power off bsf PORTA, POWER_OUT ; TX off bcf PORTB, TX_OUT ; low battery indicator off bsf PORTA, LOW_BATT ; clrf mode main_loop: banksel 0 ; call_1 test1 ; clrf PCLATH ; update the display once a second. wait_for_seconds_change: banksel 0 wait_one_second_flag: movfw seconds subwf old_seconds, w btfss STATUS, Z goto seconds_changed ; same second ; btfss flags1, DEBUG_FLAG goto wait_for_seconds_change ; while waiting for seconds to change if debug we print the ADC steps ; debug mode, print ADC steps for all analog inputs, and flags2 banksel 0 movlw U_BAT call ad_pri movlw ANA10 call ad_pri movlw ANA8 call ad_pri movlw ANA9 call ad_pri movfw flags2 call print_w_ascii_dec call tx_crlf goto wait_for_seconds_change seconds_changed: movfw seconds movwf old_seconds ; flash flag toggle btfss flags3, FLASH_FLAG goto set_flash_flag bcf flags3, FLASH_FLAG goto test_mode_switch set_flash_flag: bsf flags3, FLASH_FLAG test_mode_switch: ; modes ; force receiver on MODE_SWITCH3 low, RS232 ignored, receiver on. ; force receiver on plus tx MODE_SWITCH4 low, RS232 ignored, receiver and transmitter on. ; *It is guaranteed* the rotary switch will pass through 1 -> 2 -> 3 -> 4, same for 4 -> 3 -> 2 -> 1, position 2 is hardwired for power off, break before make. ; we need to stay in the process 'mode' loop, so a low battery alert and low battery switch off will still work in manual mode. ; test_switch1 test_switch3: btfsc PORTA, MODE_SWITCH3 ; receiver on? goto test_switch4 ; force tx off, could be coming from switch position 4. bcf PORTB, TX_OUT bcf flags3, TX_ON_FLAG ; receiver on movlw MODE_POWER_ON movwf mode goto test_print_version ; process 'mode'. test_switch4: btfsc PORTA, MODE_SWITCH4 ; receiver and transmitter on? goto test_print_version ; process 'mode' ; receiver plus tx on movlw MODE_TX_ON movwf mode ; goto test_print_version ; process 'mode', battery check will overrule. test_print_version: movlw MODE_PRINT_VERSION subwf mode, w btfss STATUS, Z goto test_print_help ; print version call_1 print_id clrf PCLATH goto main_end test_print_help movlw MODE_PRINT_HELP subwf mode, w btfss STATUS, Z goto test_adjust_pwm ; print help call_1 help_pri clrf PCLATH goto main_end test_adjust_pwm: banksel 0 movlw MODE_SET_PWM subwf mode, w btfss STATUS, Z goto test_print_pwm ; adjust pwm, wait for correct reload moment here? movfw pwm_pulse_width banksel CCPR1L movwf CCPR1L goto main_end test_print_pwm: banksel 0 movlw MODE_PRINT_PWM subwf mode, w btfss STATUS, Z goto test_power_on movfw pwm_pulse_width call print_w_ascii_dec call tx_crlf goto main_end test_power_on: movlw MODE_POWER_ON subwf mode, w btfss STATUS, Z goto test_power_off set_rx_off: bcf PORTA, POWER_OUT ; active low bsf flags3, RX_ON_FLAG goto main_end test_power_off: movlw MODE_POWER_OFF subwf mode, w btfss STATUS, Z goto test_low_battery set_rx_on: bsf PORTA, POWER_OUT bcf flags3, RX_ON_FLAG ; active low goto main_end test_low_battery: ; can only test voltage, and can only transmit, if power is on, RX_ON_FLAG is set. btfss flags3, RX_ON_FLAG goto main_end ; no more to do ; read voltage movlw U_BAT ; battery voltage movwf analog_select call_1 read_adc clrf PCLATH banksel 0 ; test if voltage < 10V, if so disable transmit mode, set orange LED on. movlw D'100' ; test if voltage is < 10 V subwf ad_l, w btfsc STATUS, C ; if voltage < 10V set current to zero. goto test_ten_seven ; voltage >= 10V ; low battery LED on bcf PORTA, LOW_BATT ; low battery LED on (red). ; stop tx bcf PORTB, TX_OUT ; active high bcf flags3, TX_ON_FLAG ; power off transceiver bsf PORTA, POWER_OUT ; active low bcf flags3, RX_ON_FLAG ; clear mode goto main_end ; clears mode ; test if voltage < 10.7 volt, if so flash orange LED 1x per second (toggle if passing here). test_ten_seven: movlw D'107' ; test if voltage is < 10.7 V subwf ad_l, w btfsc STATUS, C goto flash_led_off ; if voltage >= 10.7 do nothing ; battery not OK, between 10.7 and 10.0 ; flash the LED btfss flags3, FLASH_FLAG goto flash_led_off ; if flash flag low, LED off ; flash LED on bcf PORTA, LOW_BATT ; low battery LED on goto test_tx_on flash_led_off: bsf PORTA, LOW_BATT ; low battery LED off goto test_tx_on test_tx_on: movlw MODE_TX_ON subwf mode, w btfss STATUS, Z goto test_tx_off set_tx_on: bsf PORTB, TX_OUT bsf flags3, TX_ON_FLAG goto main_end test_tx_off: movlw MODE_TX_OFF subwf mode, w btfss STATUS, Z goto main_loop ; IF NOT FOUND, ONLY CLEAR mode if something found. set_tx_off: bcf PORTB, TX_OUT bcf flags3, TX_ON_FLAG goto main_end main_end: banksel 0 clrf mode goto main_loop ; ***************** subroutines ******************** ; send byte in W tx_digit_in_w: addlw '0' ; zero tx_w: banksel TXREG ; is in bank 0 movwf TXREG ; call wait_tx_empty ; inline ; banksel 0 ; make sure we have a timeout ; movlw D'255' ; movwf tx_timeout banksel TXSTA ; is in bank 1 test_tx_empty: ; banksel 0 ; decfsz tx_timeout, 1 ; goto test_txsta ; goto tx_has_timed_out ;test_txsta: btfss TXSTA, TRMT goto test_tx_empty ;tx_has_timed_out: banksel 0 return print_w_ascii_dec: ; prints register W in ASCII decimal banksel 0 bsf flags1, FIRST_ZERO_SUPPRESSED_FLAG movwf temp1 clrf count ; number of hundreds found loop_hundreds: movlw D'100' subwf temp1 btfss STATUS, C ; if no carry flag, no more hundreds, go count tenth goto count10 ; substraction failed incf count goto loop_hundreds count10: movlw D'0' subwf count, W btfsc STATUS, Z goto suppress_first_zero bcf flags1, FIRST_ZERO_SUPPRESSED_FLAG movfw count call tx_digit_in_w ; print hundreds suppress_first_zero: movlw D'100' ; restore temp1 from one substract to many addwf temp1 clrf count ; number of tenth found loop_tenth: movlw D'10' subwf temp1 btfss STATUS, C ; if no carry flag no more tenth, only units left goto count1 incf count goto loop_tenth count1: movlw D'0' subwf count, W btfss STATUS, Z goto print_tenth ; tenth not zero ; tenth zero ; test if zero supression was active in hundreds (first digit) btfsc flags1, FIRST_ZERO_SUPPRESSED_FLAG goto print_units ; if first digit was not zero, print this zero print_tenth: movfw count call tx_digit_in_w ; print tenth print_units: movlw D'10' ; restore temp1 from 1 substract to many addwf temp1 ; units movfw temp1 call tx_digit_in_w ; print units banksel 0 return print_16_ascii_dec: ; prints 16 bit value in registers bin (high byte) and bin+1 (low byte) in ASCII decimal banksel 0 call_1 b2bcd clrf PCLATH ; suppress leading zeros bsf flags1, FIRST_ZERO_SUPPRESSED_FLAG movfw bcd call print_bcd_in_w_decimal_2_digits movfw bcd+1 call print_bcd_in_w_decimal_2_digits btfss flags1, DIVIDE_BY_TEN_FLAG goto pri_16_no_dot ; force dot printing just before last digit bsf flags1, PRINT_DOT_FLAG bcf flags1, DIVIDE_BY_TEN_FLAG pri_16_no_dot: movfw bcd+2 call print_bcd_in_w_decimal_2_digits bcf flags1, PRINT_DOT_FLAG ; if the zero suppress flag is still set we had zero, so print zero btfss flags1, FIRST_ZERO_SUPPRESSED_FLAG return movlw D'0' call tx_digit_in_w return print_bcd_in_w_decimal_2_digits: banksel 0 ; high digit first movwf temp ; save w swapf temp, w andlw 0x0f ; test if zero btfss STATUS, Z ; if not zero print it goto print_high_nibble test_lead_zero: ; test if leading zero suppress flag set btfsc flags1, FIRST_ZERO_SUPPRESSED_FLAG goto low_nibble print_high_nibble: bcf flags1, FIRST_ZERO_SUPPRESSED_FLAG call tx_digit_in_w low_nibble: ; test if we need to print a dot here banksel 0 btfss flags1, PRINT_DOT_FLAG goto no_dot movlw '.' call tx_w no_dot: banksel 0 ; low digit second movfw temp ; get w andlw 0x0f ; test if zero btfss STATUS, Z ; if not zero print it goto print_low_nibble ; test if leading zero suppress flag is set btfsc flags1, FIRST_ZERO_SUPPRESSED_FLAG ; return if no zero print return print_low_nibble bcf flags1, FIRST_ZERO_SUPPRESSED_FLAG call tx_digit_in_w return tx_crlf: movlw D'13' call tx_w ; CR movlw D'10' ; LF call tx_w return eeprom_write: banksel INTCON bcf INTCON, GIE ; disable interrupts BANKSEL EEADR ; MOVF eeprom_address, W ; MOVWF EEADR ; Data Memory Address to write MOVF eeprom_data, W ; MOVWF EEDAT ; Data Memory Value to write BANKSEL EECON1 ; BCF EECON1, EEPGD ; Point to DATA memory BSF EECON1, WREN ; Enable writes BCF INTCON, GIE ; Disable INTs. BTFSC INTCON, GIE ; SEE AN576 GOTO $-2 MOVLW 0x55 ; MOVWF EECON2 ; Write 55h MOVLW 0xAA ; MOVWF EECON2 ; Write AAh BSF EECON1, WR ; Set WR bit to begin write BSF INTCON, GIE ; Enable INTs. eeprom_poll_write_complete_loop: banksel EECON1 btfsc EECON1, WR goto eeprom_poll_write_complete_loop BCF EECON1, WREN ; Disable writes eeprom_verify: ; data at EEDADR against eeprom_data banksel 0 call eeprom_read ; EEDATA in w banksel 0 bcf flags1, EEPROM_WRITE_ERROR_FLAG movfw eeprom_data banksel EEDATA subwf EEDATA, W ; compare to requested btfss STATUS, Z ; skip if no error goto eeprom_write_error banksel 0 return eeprom_write_error: call eeprom_report banksel 0 bsf flags1, EEPROM_WRITE_ERROR_FLAG return eeprom_report: ; eeprom write result banksel 0 movlw 'E' call tx_w movlw 'E' call tx_w movlw 'P' call tx_w ; address=nnn movlw 'a' call tx_w movlw '=' call tx_w movfw eeprom_address call print_w_ascii_dec movlw ' ' call tx_w ; original=nnn movlw 'o' call tx_w movlw 'r' call tx_w movlw 'g' call tx_w movlw '=' call tx_w movfw eeprom_data call print_w_ascii_dec movlw ' ' call tx_w ; read=nnn movlw 'r' call tx_w movlw 'd' call tx_w movlw '=' call tx_w ; read eeprom call eeprom_read banksel 0 call print_w_ascii_dec call tx_crlf return eeprom_read: ; address in eeprom_address, returns data in W banksel 0 movfw eeprom_address banksel EEADR movwf EEADR banksel EECON1 bcf EECON1, EEPGD ; access data memory bsf EECON1, RD banksel EEDATA movfw EEDATA ; return data in w return save_settings: banksel 0 movlw D'1' ; clock_calibration movwf eeprom_address ; 1 movfw timer1_reload_l movwf eeprom_data call eeprom_write banksel 0 incf eeprom_address ; 2 movfw pwm_pulse_width movwf eeprom_data call eeprom_write banksel 0 incf eeprom_address ; 3 movfw swr_alert movwf eeprom_data call eeprom_write incf eeprom_address ; 4 movfw flags2 movwf eeprom_data call eeprom_write banksel 0 return load_settings: ; this will load settings from EEPROM. ; To see if any value was actually programmed in EEPROM, first EEPROM address 255 is read. ; if EEPROM address 255 reads 255, then nothing was programmed, defaults are then written to EEPROM, ; and the value 123 is written to EEPROM address 255 as a marker that it is programmed. banksel 0 movlw D'255' movwf eeprom_address ; 255 call eeprom_read ; returns data in w banksel 0 xorlw D'123' ; test for programmed btfsc STATUS, Z goto eeprom_is_programmed ; program default values in eeprom banksel 0 movlw D'175' movwf timer1_reload_l movlw D'128' movwf pwm_pulse_width movlw D'19' movwf swr_alert clrf flags2 call save_settings ; mark writtem banksel 0 movlw D'123' movwf eeprom_data movlw D'255' movwf eeprom_address call eeprom_write banksel 0 return eeprom_is_programmed: banksel 0 movlw D'1' ; clock calibration movwf eeprom_address ; 1 call eeprom_read ; returns data in w banksel 0 movwf timer1_reload_l incf eeprom_address ; 2 call eeprom_read banksel 0 movwf pwm_pulse_width incf eeprom_address ; 3 call eeprom_read banksel 0 movwf swr_alert incf eeprom_address ; 4 call eeprom_read banksel 0 movwf flags2 banksel 0 return neg_A comf ACCaLO, F ; negate ACCa ( -ACCa -> ACCa ) incf ACCaLO, F btfsc STATUS, Z decf ACCaHI, F comf ACCaHI, F retlw 0 ; Double Precision Subtraction ( ACCb - ACCa -> ACCb ) D_sub ; call neg_A ; At first negate ACCa; Then add ; inline comf ACCaLO, F ; negate ACCa ( -ACCa -> ACCa ) incf ACCaLO, F btfsc STATUS, Z decf ACCaHI, F comf ACCaHI, F ; Double Precision Addition ( ACCb + ACCa -> ACCb ) D_add movf ACCaLO, W addwf ACCbLO, F ; add lsb btfsc STATUS, C ; add in carry incf ACCbHI, F movf ACCaHI, W addwf ACCbHI, F ; add msb retlw 0 ; division macro ; divMac MACRO LOCAL NOCHK LOCAL NOGO ; bcf STATUS, C rlf ACCdLO, F rlf ACCdHI, F rlf ACCcLO, F rlf ACCcHI, F movf ACCaHI, W subwf ACCcHI, W ;check if a>c btfss STATUS, Z goto NOCHK movf ACCaLO, W subwf ACCcLO, W ;if msb equal then check lsb NOCHK btfss STATUS,C ;carry set if c>a goto NOGO movf ACCaLO, W ;c-a into c subwf ACCcLO, F btfss STATUS, C decf ACCcHI, F movf ACCaHI, W subwf ACCcHI, F bsf STATUS, C ;shift a 1 into b (result) NOGO rlf ACCbLO, F rlf ACCbHI, F ; ENDM ; Double Precision Divide ( 16/16 -> 16 ) ; ; ( ACCb/ACCa -> ACCb with remainder in ACCc ) : 16 bit output ; with Quotiont in ACCb (ACCbHI,ACCbLO) and Remainder in ACCc (ACCcHI,ACCcLO). ; ; NOTE : Before calling this routine, the user should make sure that ; the Numerator(ACCb) is greater than Denominator(ACCa). If ; the case is not true, the user should scale either Numerator ; or Denominator or both such that Numerator is greater than ; the Denominator. setup movlw .16 ; for 16 shifts movwf temp movf ACCbHI, W ; move ACCb to ACCd movwf ACCdHI movf ACCbLO, W movwf ACCdLO clrf ACCbHI clrf ACCbLO retlw 0 ; D_divF ; IF SIGNED CALL S_SIGN ENDIF ; call setup clrf ACCcHI clrf ACCcLO ; ; use the divMac macro 16 times ; divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac divMac ; IF SIGNED btfss sign,MSB ; check sign if negative retlw 0 goto neg_B ; negate ACCa ( -ACCa -> ACCa ) ELSE retlw 0 ENDIF ; Assemble this section only if Signed Arithmetic Needed IF SIGNED ; S_SIGN movf ACCaHI,W xorwf ACCbHI,W movwf sign btfss ACCbHI,MSB ; if MSB set go & negate ACCb goto chek_A ; comf ACCbLO ; negate ACCb incf ACCbLO btfsc STATUS,Z decf ACCbHI comf ACCbHI ; chek_A btfss ACCaHI,MSB ; if MSB set go & negate ACCa retlw 0 goto neg_A ; ENDIF ; Double Precision Multiply ( 16x16 -> 32 ) ; ( ACCb*ACCa -> ACCb,ACCc ) : 32 bit output with high word ; in ACCb ( ACCbHI,ACCbLO ) and low word in ACCc ( ACCcHI,ACCcLO ). D_mpyS ;results in ACCb(16 msb's) and ACCc(16 lsb's) ; IF SIGNED CALL S_SIGN ENDIF ; call setup mloop rrf ACCdHI, F ;rotate d right rrf ACCdLO, F btfsc STATUS,C ;need to add? call D_add rrf ACCbHI, F rrf ACCbLO, F rrf ACCcHI, F rrf ACCcLO, F decfsz temp, F ;loop until all bits checked goto mloop ; IF SIGNED btfss sign,MSB retlw 0 comf ACCcLO, F ; negate ACCa ( -ACCa -> ACCa ) incf ACCcLO, F btfsc STATUS,Z decf ACCcHI, F comf ACCcHI, F btfsc STATUS,Z neg_B comf ACCbLO, F ; negate ACCb incf ACCbLO, F btfsc STATUS,Z decf ACCbHI, F comf ACCbHI, F retlw 0 ELSE retlw 0 ENDIF ad_pri: ; prints ADC channel in W followed by a space movwf analog_select call_1 read_adc clrf PCLATH movfw ad_h movwf bin movfw ad_l movwf bin+1 call print_16_ascii_dec banksel 0 movlw ' ' call tx_w return ; PAGE 1 org D'2048' ; Convert 32-bit binary number at into a bcd number ; at . Uses Mike Keitz's procedure for handling bcd ; adjust; Modified Microchip AN526 for 32-bits. b2bcd: bcf STATUS, C movlw D'16' ; 32 for 32-bits movwf ii ; make cycle counter clrf bcd ; clear result area clrf bcd+1 clrf bcd+2 ; clrf bcd+3 ; clrf bcd+4 b2bcd2: movlw bcd ; make pointer movwf FSR movlw 3 ; was 5 movwf count ; Mike's routine: b2bcd3: movlw 0x33 addwf INDF, f ; add to both nybbles btfsc INDF, 3 ; test if low result > 7 andlw 0xf0 ; low result >7 so take the 3 out btfsc INDF, 7 ; test if high result > 7 andlw 0x0f ; high result > 7 so ok subwf INDF, f ; any results <= 7, subtract back incf FSR, f ; point to next decfsz count goto b2bcd3 ; rlf bin+3,f ; get another bit ; rlf bin+2,f rlf bin+1,f rlf bin+0,f ; rlf bcd+4,f ; put it into bcd ; rlf bcd+3,f rlf bcd+2,f rlf bcd+1,f rlf bcd+0,f decfsz ii,f ; all done? goto b2bcd2 ; no, loop movlw 0 movwf bcd return delay10us: ; delays W * 10 us movlw D'60' ; 10 us movwf delay_count1 delay_loop1: nop nop nop nop nop nop nop nop nop nop decf delay_count1,f btfss STATUS, Z goto delay_loop1 return delay_1ms: ; movlw D'100' ; 100 x 10 us = 1 ms movwf delay_count2 delay_loop2: call delay10us decf delay_count2,f btfss STATUS, Z goto delay_loop2 return read_adc: ; value for AD channel analog_select to ad_h and ad_l banksel 0 movfw analog_select ; TRISC or other ports must be set for input if used for ADC ; ANSEL and ANSELH must have bits set for analog input ; select an analog channel for the ADC ; set bit<5-2> in ADCONO for the selected input number ; mask out lowest 4 bits andlw D'15' movwf temp3 ; to position ; RLF: carry to LSB, MSB to carry ; clear carry bcf STATUS, C ; x 2 rlf temp3, 1 ; clear carry bcf STATUS, C rlf temp3, 1 ; x 4 ; to ADCON0 movfw temp3 BANKSEL ADCON0 clrf ADCON0 movwf ADCON0 bsf ADCON0, ADFM ; ADFM right justified bit 7 bcf ADCON0, VCFG ; Vdd reference bit 6 ; bit 1 is A/D conversion status bit ; start the ADC bsf ADCON0, ADON ; AD on bit 0 ; sample time delay ; movlw D'255' movlw D'100' movwf delay_count1 adc_sample_delay: decfsz delay_count1, F goto adc_sample_delay ; set ADCON0 GO / !DONE bit to start the conversion BSF ADCON0, GO ; Start conversion bit 1 BTFSC ADCON0, GO ; Is conversion done? GOTO $-1 ; No, test again BANKSEL ADRESH MOVF ADRESH, W ; Read upper 2 bits banksel 0 MOVWF ad_h ; store in GPR space BANKSEL ADRESL MOVF ADRESL, W ; Read lower 8 bits banksel 0 MOVWF ad_l ; Store in GPR space return pwm_init: banksel TMR2 clrf TMR2 banksel PR2 ; movlw d'249' ; PWM Period movlw 0x65 ; 8MHz 1x prescaler 8 bits resolution movwf PR2 ; init 50 % duty cycle banksel 0 movlw D'50' ; Load Duty cycle into CCPR1L, seems 0 (0V) to - 102 (+5V). movwf pwm_pulse_width banksel CCPR1L movwf CCPR1L ; CCP1CON: P1M1 P1M0 DC1B1 DC1B0 CCP1M3 CCP1M2 CCP1M1 CCP1M0 movlw b'00001100' banksel CCP1CON movwf CCP1CON ; Setup PWM mode ; set prescaler 1x banksel T2CON clrf T2CON bcf T2CON, T2CKPS0 ; 00 = /1, 01 = /4, 1x = /16 bcf T2CON, T2CKPS1 ; timer 2 on bsf T2CON, TMR2ON banksel 0 return help_pri: banksel 0 movlw HIGH help_menu movwf temp_h movlw LOW help_menu movwf temp_l text_pri_loop: banksel 0 MOVF temp_h, W banksel EEADR ; MOVWF EEADRH ; MS Byte of Program Address to read banksel 0 MOVF temp_l, W banksel EEADR MOVWF EEADR ; LS Byte of Program Address to read BANKSEL EECON1 BSF EECON1, EEPGD ; Point to PROGRAM memory BSF EECON1, RD ; EE Read NOP ; First instruction after BSF EECON1,RD executes normally NOP ; Any instructions here are ignored as program memory is read in second cycle after BSF EECON1,RD BANKSEL EEDAT MOVF EEDAT, W ; W = LS Byte of Program Memory banksel 0 movwf temp ; save in temp banksel EEDATH MOVF EEDATH, W ; W = MS Byte of Program EEDAT banksel 0 movwf temp1 ; have data, high byte in temp1, low byte in temp ; print_temp1 ; bit 7 temp now holds the lower bit of the second character rlf temp1 ; shift temp1 to left, making free bit 0 rlf temp ; bit 7 temp to carry btfss STATUS, C goto was_zero bsf temp1, 0 ; set bit 0 temp if carry goto as_is was_zero: bcf temp1, 0 as_is: ; test for end of string movfw temp1 andlw D'127' xorlw 0 btfsc STATUS, Z return ; print low part andlw D'127' call_0 tx_w bsf PCLATH, 3 ; high part banksel EEDAT movfw EEDAT banksel 0 ; test for end of string xorlw 0 andlw D'127' btfsc STATUS, Z return ; print high part call_0 tx_w bsf PCLATH, 3 ; get next byte incf temp_l movlw D'0' subwf temp_l, W btfss STATUS, Z goto text_pri_loop incf temp_h goto text_pri_loop help_menu: ; DO NOT FOLD THIS LINE!!!!! ; help menu, unfortunately gputils (gpasm) does not understand '\ at the end of a line for continuation, like in C. ; \n will empty buffer in Linux / Unix, do not use \n\r at the end, \0 writes zero and is string termination, so always end with \r\n\0. DA "RS232 commands:\n\rD enters debug mode, continuously prints adc steps for U_BAT, ANA10, ANA8, ANA9, and flags2.\n\rd exits debug mode.\n\rh prints help.\n\rCtrl PnnnENTER sets PWM output value, range 0 to 100, stored in EEPROM.\n\rp prints PWM setting.\n\rv prints version number.\r\nX transceiver power on.\n\rx transceiver power off.\n\rY transmitter on.\n\ry transmitter off.\r\n\0" print_id: banksel 0 movlw HIGH id_text movwf temp_h movlw LOW id_text movwf temp_l goto text_pri_loop id_text: ; Set version here DA "Panteltje pwtx-0.5.1\r\n\0" end