;================================================== ; 18/01/2013 ; Заголовок к программе трехсегментного ампер/вольтметра ; с внешним пепеключателем режима измерения. ;======== ОПРЕДЕЛЕНИЯ ===================== ; ; 27/05/2017 ; modified for 99.9v using R2 = 310K, Mike McLaren, K8LH ; ; ; НАЗНАЧЕНИЯ ДЛЯ ПОРТОВ: RA0-вход АЦП; RA3-вход с переключателя ; все остальные - выходы, подтяжки выключены. ; При назначении порта RC2 как вход - точка гасится ; Результат АЦП - 2-байтный ; #define SW_SENSE PORTA,3 ; вход переключателя рода работ #define DIGIT_1 PORTC,4 ; катод старшего разряда индикатора #define DIGIT_2 PORTC,3 ; катод среднего разряда индикатора #define DIGIT_3 PORTC,2 ; катод младшего разряда индикатора ; ;============ ПЕРЕМЕННЫЕ ========================================= ; cblock 0x020 TEMP ; TEMPorary register COUNTER ; общий счетчик COUNT ; счетчики задержек COUNT1 ; ; CCOUNTER ; счетчик прерываний ; D1 ; Разряды индикатора D2 D3 ; ; регистры для двоично-десятичного преобразования ; DL ; число для преборазования bin2bcd DH ADD_L ; накопитель суммы ADD_H LED0 ; результат преобразования LED1 LED2 LED3 LED4 ; INDEX ; указатель для индикации ; WREG_TEMP ; storage for WREG during interrupt STATUS_TEMP ; storage for STATUS during interrupt PCLATH_TEMP ; storage for PCLATH during interrupt FSR_TEMP ; storage for FSR during interrupt ; FLAGS ; флаги общие endc #define mode FLAGS,0 ; ,бит режима работы U=1, I=0 ;------------------------------------------------------------ ; ОПРЕДЕЛЕНЯ ДЛЯ ИНДИКАЦИИ ;------------------------------------------------------------ ; Соответствие сегментам: PORTA '--ABiCGi'; PORTC '--F123ED' ; #define coma PORTC,2 ; бит включения запятой ; ;======================= ;**** М А К Р О С Ы **** ;======================= ;------------------------------------------------------------ Bank0 MACRO ; macro to select data RAM bank 0 bcf STATUS,RP0 ENDM Bank1 MACRO ; macro to select data RAM bank 1 bsf STATUS,RP0 ENDM ;------------------------------------------------------------ ; ; 25/06/2013_v3.3 ; Рабочая программа вольт/амперметра ; V.3.3.Добавлена индикация перегрузки по напряжению. ; V.3.2.Возобновлена засветка индикатора в 2 приема в связи с высоким ; потреблением зеленого индикатора. ; V.3.1.Изменена коррекция значения тока 1:1. ; Добавлено ограничение значения тока до 9,9В (перегрузка -,--) ; V.1.2.Добавлена фильтрация результата измерения. ; V.1.1.Откорректирован диапазон по току ; list p=16f676, st=off __CONFIG _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_OFF & _PWRTE_OFF & _MCLRE_OFF & _BODEN_OFF ERRORLEVEL -302,-306 include ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; reset vector ~ ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ org 0x000 v_reset clrf PCLATH ; select program memory page 0 goto SETUP ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; interrupt vector ~ ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ org 0x004 ; ; interrupt every 100 * 16-usec clock 'ticks' (~1600-usecs) for ; an approximate ~100-Hz display refresh rate ; v_int movwf WREG_TEMP ; save WREG swapf STATUS,W ; store STATUS in WREG clrf STATUS ; select file register bank0 movwf STATUS_TEMP ; save STATUS value movf PCLATH,W ; store PCLATH in WREG movwf PCLATH_TEMP ; save PCLATH value clrf PCLATH ; select program memory page0 movf FSR,W ; store FSR in WREG movwf FSR_TEMP ; save FSR value TMR0int movlw d'256'-d'101'+2 ; approx 100*16-usecs plus one addwf TMR0,F ; due to clearing the prescaler call DISPLAY ; вызов п/п индикации bcf INTCON,T0IF ; EndInt movf FSR_TEMP,W ; get saved FSR value movwf FSR ; restore FSR movf PCLATH_TEMP,W ; get saved PCLATH value movwf PCLATH ; restore PCLATH swapf STATUS_TEMP,W ; get saved STATUS value movwf STATUS ; restore STATUS swapf WREG_TEMP,F ; prepare WREG to be restored swapf WREG_TEMP,W ; restore WREG without affecting STATUS retfie ; return from interrupt ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; LED Segment Tables ~ ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LEDTABLE_A addwf PCL,F ; --AB-CG- on PORTA retlw b'00110100' ; 0 --AB-C-- retlw b'00010100' ; 1 ---B-C-- retlw b'00110010' ; 2 --AB--G- retlw b'00110110' ; 3 --AB-CG- retlw b'00010110' ; 4 ---B-CG- retlw b'00100110' ; 5 --A--CG- retlw b'00100110' ; 6 --A--CG- retlw b'00110100' ; 7 --AB-C-- retlw b'00110110' ; 8 --AB-CG- retlw b'00110110' ; 9 --AB-CG- retlw b'00000010' ;'-' ------G- LEDTABLE_C addwf PCL,F ; --F---ED on PORTB retlw b'00100011' ; 0 --F---ED retlw b'00000000' ; 1 -------- retlw b'00000011' ; 2 ------ED retlw b'00000001' ; 3 -------D retlw b'00100000' ; 4 --F----- retlw b'00100001' ; 5 --F----D retlw b'00100011' ; 6 --F---ED retlw b'00000000' ; 7 -------- retlw b'00100011' ; 8 --F---ED retlw b'00100001' ; 9 --F----D retlw b'00000000' ;'-' -------- ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; main setup ~ ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SETUP CLRF PORTA ; очистка портов |b0 CLRF PORTC ; |b0 movlw b'00000111' ; |b0 movwf CMCON ; компаратор выключен |b0 Bank1 ; |b1 call 3FFh ; get factory calibration value |b1 movwf OSCCAL ; calibrate internal oscillator |b1 movlw b'11000011' ; TMR0 prescale 16 |b1 movwf OPTION_REG ; for 16-usec TMR0 'ticks' |b1 movlw b'00000001' ; вход AN0 - аналоговый |b1 movwf ANSEL ; |b1 movlw b'00001001' ; RA0, RA3 - inputs |b1 movwf TRISA ; |b1 movlw b'00000100' ; RC2 - input (точка выключена) |b1 movwf TRISC ; |b1 movlw b'01010000' ; частота преобразования Fosc/16 |b1 movwf ADCON1 ; |b1 clrf PIE1 ; clear peripheral int enables |b1 Bank0 ; |b0 movlw b'10000001' ; вход RA0-аналоговый, АЦП включен movwf ADCON0 ; |b0 clrf INTCON ; все прерывания запрещены |b0 ; movlw 0x20 ; |b0 movwf FSR ; |b0 initram clrf INDF ; clear RAM from 0x20..0x3F |b0 incf FSR,F ; bump indirect address pointer |b0 btfss FSR,6 ; done (0x40)? yes, skip, else |b0 goto initram ; branch (clear another byte) |b0 ; clrf TMR0 ; |b0 bsf INTCON,T0IE ; enable TMR0 interrupts |b0 bsf INTCON,GIE ; enable global interrupts |b0 ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; main loop ~ ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MAIN: measure call AD_CONVERTION ; АЦП-преобразование. Рез. в DH/DL ; ; прибавляем D к ADD ; bcf STATUS,C ; movf DL,W ; addwf ADD_L,F ; btfsc STATUS,C ; incf DH,F ; movf DH,W ; addwf ADD_H,F ; ; ; после 8 измерений сумма результатов делится на 8 для усреднения ; incf CCOUNTER,F ; btfsc CCOUNTER,3 ; счетчик измерений = 8? goto calc_result ; да, произвести расчет ; ; пауза между измерениями для исключения перемигивания ; младшего разряда ; call PAU50 ; пауза 40мс goto measure ; ; ; делим сумму на 8, результат заносим в DH/DL ; calc_result bcf STATUS,C ; rrf ADD_H,F ; rrf ADD_L,F ; bcf STATUS,C ; rrf ADD_H,F ; rrf ADD_L,F ; bcf STATUS,C ; rrf ADD_H,W ; movwf DH ; rrf ADD_L,W ; movwf DL ; ; ; очищаем регистры ; clrf CCOUNTER ; clrf ADD_L ; clrf ADD_H ; ; ; переходим к пересчету результата конкретного вида измерения ; btfss SW_SENSE ; режим измерения напряжения? goto CURRENT ; нет ; да VOLTAGE: bsf mode ; voltage mode (1 decimal place) |00 goto calc_current ; 99.9v version (R2 = 310K) |00 ; ; для получения диапазона 0-51,2 делим результат на 2 ; bcf STATUS,C ; |00 rrf DH,F ; |00 rrf DL,F ; |00 ; ; производим обработку значения, которое не должно быть больше 500 ; то есть DH=1, DL=244 (01F4) ; calc_voltage movf DH,F ; skpnz ; goto do_BCD ; DH=0, не обрабатываем результат movf DL,W ; sublw .244 ; 244-DL > 0? skpnc ; goto do_BCD ; DL<=244, не обрабатываем результат movlw .10 ; записываем ссылку на черточки в movwf D1 ; movwf D2 ; movwf D3 ; goto MAIN ; ; CURRENT: bcf mode ; ; ; отсекаем значения тока меньше 1 единицы ; movf DH,f ; skpz ; goto calc_current ; decfsz DL,w ; goto calc_current ; clrf DL ; ; ; производим обработку значения, которое не должно быть больше 999 ; то есть DH=3, DL=231 (03E7) ; calc_current movf DH,w ; sublw b'00000011' ; skpz ; проверяем DH на равество "3" goto do_BCD ; DH<3, не обрабатываем результат movf DL,w ; sublw .231 ; 231-DL > 0? skpnc ; goto do_BCD ; DL<=231, не обрабатываем результат movlw .10 ; записываем ссылку на черточки в movwf D1 movwf D2 movwf D3 goto MAIN ; do_BCD call BIN2BCD ; movf LED0,w ; movwf D3 ; movf LED1,w ; movwf D2 ; movf LED2,w ; movwf D1 ; goto MAIN ; ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; subroutines ~ ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ; display subroutine for Common Anode displays ; DISPLAY movlw b'00100011' ; anodes K1(RC4),K2(RC3),K3(RC2) off movwf PORTC ; segments D(RC0),E(RC1),F(RC5) off movlw b'00110110' ; movwf PORTA ; segments G(RA1),C(RA2),B(RA4),A(RA5) off movlw TRISC ; movwf FSR ; setup indirect access to TRISC movlw b'00000100' ; K3/DP pin (RC2) off (hi-z) |b0 movwf INDF ; trisc = '00000100' RC2 input |b0 ; ; select and display digit 1, 2, or 3 based on INDEX 0..5 ; movf INDEX,W ; LEDIndex -> W |b0 sublw .5 ; in range, 0 <= index <= 5? |b0 skpc ; yes, skip, else |b0 clrf INDEX ; reset index to 0 |b0 btfsc INDEX,2 ; index 4 or 5? no, skip, else |b0 goto sel_MSD ; display digit 1 |b0 btfsc INDEX,1 ; index 2 or 3? no, skip, else |b0 goto sel_CSD ; display digit 2 |b0 sel_LSD movlw b'00000000' ; K3/DP (RC2) pin 'output' |b0 movwf INDF ; trisc = '00000000' RC2 output |b0 movlw b'00100111' ; PORTC shadow | 1< 1..6 retlw 0 ; ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ~ ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAU100 movlw .130 ; movwf COUNT ; goto loopH ; PAU50 ; movlw .65 ; 50ms movlw .52 ; 40ms ; movlw .39 ; 30ms movwf COUNT ; ; goto loopH ; loopH: decfsz COUNT,F ; goto loopL ; return ; loopL: clrf COUNT1 ; loop: decfsz COUNT1,F ; goto loop ; goto loopH ; ;/=============================================\ ; П/П ПРЕОБРАЗОВАНИЯ ДВУХБАЙТОВОГО ЧИСЛА ; В ПЯТИ-РАЗРЯДНОЕ ДВОИЧНО-ДЕСЯТИЧНОЕ ЧИСЛО ; вход - DL, DH; выход - LED0-LED4 ; >use: COUNT,TEMP ;\=============================================/ BIN2BCD bcf STATUS,C ; clear the carry bit movlw .16 ; movwf COUNT ; clrf LED2 ; clrf LED1 ; clrf LED0 ; loop16 rlf DL,F ; rlf DH,F ; rlf LED0,F ; rlf LED1,F ; rlf LED2,F ; decfsz COUNT,F ; goto adjDEC ; movf LED2,W ; разнос тетрад по байтам andlw 0x0F ; movwf LED4 ; LED4 - MSD swapf LED1,W ; andlw 0x0F ; movwf LED3 ; LED3 movf LED1,W ; andlw 0x0F ; movwf LED2 ; LED2 swapf LED0,W ; andlw 0x0F ; movwf LED1 ; LED1 movf LED0,W ; andlw 0x0F ; movwf LED0 ; LED0 - LSD return ; adjDEC movlw LED0 movwf FSR call adjBCD movlw LED1 movwf FSR call adjBCD movlw LED2 movwf FSR call adjBCD movlw LED3 movwf FSR call adjBCD goto loop16 adjBCD movlw 3 addwf 0,W movwf TEMP btfsc TEMP,3 ; test if result > 7 movwf 0 movlw 30 addwf 0,W movwf TEMP btfsc TEMP,7 ; test if result > 7 movwf 0 ; save as MSD retlw 0 ;============================================================== ;============================================================== ;ПП АЦП. Результат помещается в WREG ;use: TEMP AD_CONVERTION ; clrf TEMP ;пауза на время заряда С АЦП (100us) ;p_adc: decfsz TEMP,f ; goto p_adc bsf ADCON0,GO_DONE ;запускаем АЦП loopAD btfsc ADCON0,GO_DONE ;ожидаем окончания goto loopAD ;преобразования movf ADRESH,w ;результат записываем в DH/DL movwf DH Bank1 movf ADRESL,w Bank0 movwf DL return ;============================================================== ;============================================================== ;============================================================== ;============================================================== END