⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 counter.asm

📁 PIC16F628A芯片制作的频率计
💻 ASM
📖 第 1 页 / 共 5 页
字号:
;**************************************************************************
; FILE:      C:\PIC\freq_counter\counter1.asm                             *
; CONTENTS:  Simple low-cost digital frequency meter using a PIC 16F628   *
; AUTHOR:    Wolfgang Buescher, DL4YHF                                    *
;            (based on a work by James Hutchby, MadLab, 1996)             *
; REVISIONS: (latest entry first)                                         *
; 2006-05-31 - Added the 'power-save' option which temporarily puts the   *
;              PIC to sleep (with only the watchdog-oscillator running)   *
; 2006-05-15 - New entry in the preconfigured frequency table for 4-MHz   *
;              IF filters (like "Miss Mosquita" [Moskita] by DK1HE)       *
; 2005-08-24 - Cured a bug in the COMMON ANODE decimal point setting .    *
;              (the "^0xFF" for the AND-mask was missing in macro 'conv') *
; 2005-03-21 - Added a few conditionals to use the same sourcecode        *
;              to drive a COMMON ANODE display ( DISPLAY_VARIANT_3 )      *
; 2004-03-14 - Fixed a range-switching bug around 8 MHz .                 *
;            - Support TWO different display variants now,                *
;              optimized for different board layouts, and different clock *
;              frequencies (4 MHz for variant 1,  20 MHz for variant 2).  *
; 2004-03-05 - Added the feature to add or subtract a frequency offset .  *
; 2004-02-18 - Migration to a PIC16F628 with 4 MHz crystal (el Cheapo)    *
;            - Changed the LED patterns '6' and '9' because they looked   *
;              like 'b' and 'q' in the old counter version .              *
;            - Added the auto-ranging feature                             *
;            - Stepped from 24-bit to 32-bit integer arithmetic, to be    *
;              able to count 50 MHz with 1-second gate time,              *
;              or (at least) adjust ANY result for the ANY prescaler      *
;              division ratio, which may give pretty large numbers .      *
;            - A PIC16F628 worked up to 63 MHz with this firmware .       *
;**************************************************************************

 list P=16F628
 #include <p16F628.inc>        ; processor specific definitions
 #define DEBUG 0         ; DEBUG=1 for simulation, DEBUG=0 for real hardware

; Selection of LED display control bits... since 2005, three different variants.
; Select ONE OF THESE in MPLAB under "Project".."Build Options".."Macro Definitions"!
;  DISP_VARIANT=1  :   first prototype, PIC on left side of display
;  DISP_VARIANT=2  :   second prototype, separated PIC and display board
;  DISP_VARIANT=3  :   similar as (2), but for COMMON CATHODE display
; Unfortunately it seems impossible to assign a NUMERIC VALUE to a macro 
;   in MPLAB (not in MPASM!) ....
#ifdef DISPLAY_VARIANT_1
  #define DISP_VARIANT 1    ; very first (old) prototype by DL4YHF
  #define COMMON_ANODE   0
  #define COMMON_CATHODE 1
#else
#ifdef DISPLAY_VARIANT_2
  #define DISP_VARIANT 2    ; 5 digits, new layout, COMMON CATHODE
  #define COMMON_ANODE   0
  #define COMMON_CATHODE 1
#else
#ifdef DISPLAY_VARIANT_3    ; added 2005-03-21 :
  #define DISP_VARIANT 3    ; similar as (2), but for COMMON ANODE display
  #define COMMON_ANODE   1
  #define COMMON_CATHODE 0
#else
  #define DISP_VARIANT 4
  #define COMMON_ANODE   0
  #define COMMON_CATHODE 1
  "Error, Must define DISPLAY_VARIANT_1, .._2, or .._3 under project options"
  ; With MPLAB: Project..Build Options..Project..MPASM..Macro Definitions..Add
#endif
#endif
#endif



;**************************************************************************
;                                                                         *
; Summary                                                                 *
;                                                                         *
;**************************************************************************

; The software functions as a frequency meter with an input signal
; range of 1 Hz to ~ 50 MHz and with an accuracy of +/- 1Hz
; if the oscillator crystal is properly trimmed .

; Signal pulses are counted over a fixed time interval of 1/4 second to
; 1 second (gate time). High frequency pulses are counted over 1/4 s 
; to make the meter more responsive with no loss of displayed accuracy.

; Pulses are counted using Timer 0 of the PIC,
; which is set to increment on rising edges on the TMR0 pin. The 8-bit
; hardware register is extended by software into a 32-bit pulse counter.
; If timer 0 rolls over (msb 1 -> 0) between successive polls then the
; high two bytes of the pulse counter are incremented.

; Timer 0 is unable to count more than one pulse per instruction cycle
; (per 4 clock cycles) so the prescaler is used at frequencies above
; 1MHz (4MHz clock / 4) and also to ensure that pulses are not lost
; between polls of timer 0 (which would happen if more than 128 pulses were
; received). Fortunately the prescaler is an asynchronous counter
; which works up to a few ten MHz (sometimes as far as 60 MHz) .

; Timing is based on a software loop of known execution period . The loop
; time is 50 or 20 us which gives integer counts to time 1 s  and 1/4 s .
; During this timing loop, the multiplexed LED display is updated .

; The frequency in binary is converted to decimal using a powers-of-ten
; lookup table. The binary powers of ten are repeatedly subtracted from
; the frequency to determine the individual decimal digits. The decimal
; digits are stored at the 8 bytes at 'digits'. Leading zeroes are then
; suppressed and the 4 (or 5) significant digits are converted to LED data
; for the 7-segment displays using a lookup table.

; The signal frequency is displayed on four (or five) 7-segment displays. 
; The displays are multiplexed which means that only one display is enabled 
; at any one time. The variable 'disp_index' contains the index of the currently
; enabled display. Each display is enabled in turn at a sufficient frequency
; that no flicker is discernable. A prescaler ('disp_timer') is used
; to set the multiplexing frequency to a few hundred Hz.

; The display shows the signal frequency in KHz or MHz, according to the
; following table:

; --------------------------
; | Frequency | Display    |
; --------------------------
; | < 1Hz     |       0    |
; | 1Hz       |   0.001[0] |  Note: kHz-dot is flashing (blinking)
; | 10Hz      |   0.010[0] |
; | 100Hz     |   0.100[0] |
; | 1.000KHz  |   1.000[0] |
; | 10.00KHz  |   10.00[0] |
; | 100.0KHz  |   100.0[0] |
; | 1.000MHz  |   1.000[0] |  Note: MHz-dot is steady (not blinking)
; | 10.00MHz  |   10.00[0] |
; --------------------------

; If there is no signal at all, a single zero is displayed in the 4th(!) digit.
; Overflows are not displayed because they cannot be detected !


;**************************************************************************
;                                                                         *
; PIC config definitions                                                  *
;                                                                         *
;**************************************************************************


; '__CONFIG' directive is used to embed configuration data within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.
; Since 2006-05-28, the watchdog must be ENABLE in the config word
;       because of its wakeup-from-sleep function (see 'Sleep100ms') .
; EX(16F84:)     __CONFIG   _CP_OFF & _WDT_ON & _PWRTE_ON & _RC_OSC
#if (DISP_VARIANT==1)  ; display variant 1 : clocked with 4 MHz (low power, "XT" )
   __CONFIG   _CP_OFF & _WDT_ON & _PWRTE_ON & _XT_OSC & _LVP_OFF & _BODEN_OFF & _MCLRE_OFF
#else                  ; display variants 2+3 : clocked with 20 MHz (needs "HS" oscillator)
   __CONFIG   _CP_OFF & _WDT_ON & _PWRTE_ON & _HS_OSC & _LVP_OFF & _BODEN_OFF & _MCLRE_OFF
#endif



; '__IDLOCS' directive may be used to set the 4 * 4(?!?) ID Location Bits .
; These shall be placed in the HEX file at addresses 0x2000...0x2003 .
   __IDLOCS H'1234'


; (definitions of "file" registers removed.  They are defined in a header file!)



;**************************************************************************
;                                                                         *
; Port assignments                                                        *
;                                                                         *
;**************************************************************************

PORT_A_IO      equ  b'0000'        ; port A I/O mode (all output)
PORT_B_IO      equ  b'00000000'    ; port B I/O mode (all output)

LEDS_PORT      equ  PORTB          ; 7-segment LEDs port

ENABLE_PORT    equ  PORTA          ; display enable port
  ; Bitmasks to control the digit outputs have been moved to enable_table .
  ; YHF: Note that 'display #0' is the MOST SIGNIFICANT digit !


#define IOP_PROG_MODE  PORTA,5   ; digital input signal, LOW enters programming mode
  



;**************************************************************************
;                                                                         *
; Constants and timings                                                   *
;                                                                         *
;**************************************************************************

; processor clock frequency in Hz (4MHz)
#if (DISP_VARIANT==1)  ; display variant 1 : clocked with 4 MHz (low power consumption)
CLOCK     equ  .4000000
#else                  ; display variants 2+3 : clocked with 20 MHz (higher resolution)
CLOCK     equ  .20000000
#endif

; microseconds per timing loop
#if (DISP_VARIANT==1)  ; display variant 1 : clocked with 4 MHz
  ; 20 microseconds is impossible with 4-MHz-Crystal, so use 50 us instead ! 
  ; Make sure all gate times can be divided by this interval without remainder :
  ; 1   second / 50 us = 20000  (ok)
  ; 1/4 second / 50 us =  5000  (ok)
  ; 1/8 second / 50 us =  2500  (ok)
TIME      equ  .50
#else                  ; display variants 2+3 : clocked with 20 MHz
  ; 20 microseconds is impossible with 4-MHz-Crystal, so use 50 us instead ! 
  ; Make sure all gate times can be divided by this interval without remainder :
  ; 1   second / 20 us = 50000  (ok)
  ; 1/4 second / 20 us = 12500  (ok)
  ; 1/8 second / 50 us =  6250  (ok)
TIME      equ  .20
#endif ; variant 1 or 2+3 ?


; Clock cycles per timing loop.  See subroutine count_pulses .
;  Usually CYCLES=200 (for 4 MHz crystal,  50 usec - loop)  
;              or 400 (for 20 MHz crystal, 20 usec - loop)
CYCLES    equ  TIME*CLOCK/.1000000

GATE_TIME_LOOPS equ  CLOCK/CYCLES       ; number of gate-time loops for ONE SECOND gate time

LAMPTEST_LOOPS  equ  CLOCK/(.2*CYCLES)  ; number of loops for a 0.5 SECOND lamp test after power-on

PROGMODE_LOOPS  equ  CLOCK/(.10*CYCLES) ; number of delay loops for display in PROGRAMMING MODE (0.1 sec)

; Configuration of power-saving mode :
#if( DEBUG )
PSAVE_DELAY_TIME equ .10  ; number of 0.25-sec-intervals before turning off (shorter for debugging)
#else
PSAVE_DELAY_TIME equ .60  ; number of 0.25-sec-intervals before turning off (some dozen seconds)
#endif
PSAVE_FLASHUP_TIME equ .14 ; number of 0.7(!)-second-intervals between two flashes in power-saving mode
PSAVE_MAX_DIFF   equ .10  ; maximum frequency difference (range-dependent, see below)
     ; Unit: N times "frequency-resolution", see frequency-range table .
     ; Example: PSAVE_MAX_DIFF=10 means 10*4Hz in Range 1 (1..3.4 MHz) .


; Menu Indices ... must match the jump table PMDisplay + PMExecute !
MI_QUIT   equ  0     ; exit from menu
MI_PSAVE  equ  1     ; turn "power save"-option on and off
MI_ADD    equ  2     ; save frequency offset to ADD it from now on
MI_SUB    equ  3     ; save frequency offset to SUBTRACT it from now on
MI_ZERO   equ  4     ; set the frequency offset to ZERO and leave menu
MI_STD_IF equ  5     ; jump into the STANDARD INTERMEDIATE FREQUENCY table..
MI_INDEX_MAX  equ 5  ; normal menu indices up to MI_INDEX_MAX .
MI_IF_1   equ  6     ; show the 1st standard IF
MI_IF_2   equ  7     ; show the 2nd standard IF
MI_IF_3   equ  8     ; show the 3rd standard IF
MI_IF_4   equ  9     ; show the 4th standard IF
MI_IF_5   equ  0x0A  ; show the 4th standard IF
MI_IF_QT  equ  0x0B  ; exit standard IF menu without changing anything
MI_IF_SUBMENU_MAX equ 0x0A

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -