基于PIC16F1517与BCD4511的0-9999计数显示程序调试求助
Let's walk through the issues causing your jumpy display and erratic counting, then fix them one by one. Most of the problems stem from incorrect BCD logic, display timing, and interrupt configuration—easy fixes once we spot them!
1. Critical TMR0 Interrupt Issues
Your TMR0 interrupt is missing two key steps that cause unstable triggering:
- No initial TMR0 reload value: The PIC16F1517's TMR0 is an 8-bit counter that overflows from
0xFFto0x00. Without loading an initial value, your interrupt frequency will be inconsistent, and it will fire extremely fast (e.g., ~1.5kHz with 4MHz INTOSC and 1:256 prescaler), making the display look like it's jumping. - Uncleared interrupt flag before enabling interrupts: If
TMR0IFwas set accidentally, enablingTMR0IEwill trigger an immediate interrupt, causing unexpected behavior.
Fix:
Add a TMR0 initial value calculation (example for ~10ms interrupt with 4MHz INTOSC) and reload it every interrupt:
; Add these register definitions at the top W_TEMP EQU 0x70 STATUS_TEMP EQU 0x71 TMR0_INIT EQU 0xD9 ; Calculated for ~10ms interrupt (4MHz FOSC, 1:256 prescaler) ; In your settings section, initialize TMR0 BANKSEL TMR0 MOVLW TMR0_INIT MOVWF TMR0 ; Update your interrupt service routine (ISR) to save context and reload TMR0 interupt: ; Save registers to avoid corrupting main program state MOVWF W_TEMP SWAPF STATUS, W MOVWF STATUS_TEMP BCF STATUS, RP0 ; Switch to bank 0 BCF STATUS, RP1 ; Reload TMR0 first to keep interrupt timing consistent MOVLW TMR0_INIT MOVWF TMR0 BCF INTCON, 2 ; Clear TMR0IF ; Your existing counter logic here incf WSKP,f call check call display ; Restore registers SWAPF STATUS_TEMP, W MOVWF STATUS SWAPF W_TEMP, F SWAPF W_TEMP, W retfie
2. Broken BCD Counting Logic
Your check function has incorrect BCD correction logic—you're checking for 0x60 (6 in the tens place) instead of detecting when a BCD digit exceeds 9. This causes wrong increments and resets at the wrong values.
Fix: Replace the check function with this correct BCD increment logic
check: ; Handle low byte (units + tens) MOVFW WSKP ANDLW 0x0F ; Check units digit SUBLW 0x09 BTFSC STATUS, C ; If units <=9, skip correction goto CHECK_TENS MOVLW 0x06 ADDWF WSKP, f ; Correct units digit (add 6 to skip non-BCD values) CHECK_TENS: MOVFW WSKP ANDLW 0xF0 ; Check tens digit SUBLW 0x90 BTFSC STATUS, C ; If tens <=9, skip carry to high byte goto CHECK_HIGH_BYTE CLRF WSKP ; Tens digit overflowed, reset low byte INCF WSKL, f ; Carry to high byte (hundreds + thousands) ; Handle high byte (hundreds + thousands) CHECK_HIGH_BYTE: MOVFW WSKL ANDLW 0x0F ; Check hundreds digit SUBLW 0x09 BTFSC STATUS, C ; If hundreds <=9, skip correction goto CHECK_THOUSANDS MOVLW 0x06 ADDWF WSKL, f ; Correct hundreds digit CHECK_THOUSANDS: MOVFW WSKL ANDLW 0xF0 ; Check thousands digit SUBLW 0x90 BTFSC STATUS, C ; If thousands <=9, skip reset goto CHECK_DONE CLRF WSKP ; Reset low byte CLRF WSKL ; Reset high byte (count wraps from 9999 to 0) CHECK_DONE: RETURN
3. Display Timing & Latch Order Errors
Your display function has the wrong order for latching data to your BCD4511 circuit. You're latching first, then sending data—this means you're locking in old data instead of the new value. You also need a short delay to ensure the display stabilizes between digit switches.
Fix: Rewrite the display function with correct timing
display: BCF BI ; Disable display first to prevent flicker during data switch ; Update low byte (units + tens) MOVFW WSKP MOVWF PORTD ; Send data to PORTD first BSF LEL ; Latch low byte data BCF LEL ; Hold latch state ; Update high byte (hundreds + thousands) MOVFW WSKL MOVWF PORTD ; Send high byte data BSF LEH ; Latch high byte data BCF LEH ; Hold latch state BSF BI ; Re-enable display ; Short delay to stabilize display (adjust value as needed) MOVLW 0x08 call SHORT_DELAY RETURN SHORT_DELAY: DECFSZ WREG, f goto SHORT_DELAY RETURN
4. Button Debouncing & Main Loop Logic
Your START loop uses a typo (tmfsc instead of btfsc) and lacks button debouncing. Without debouncing, the RB0 press can trigger multiple times, leading to unexpected interrupt enabling.
Fix: Correct the button check and add debouncing
START: BTFSC PORTB, 0 ; Wait for RB0 press (assuming active low) goto START ; Debounce delay to ignore switch bounce MOVLW 0xFF call SHORT_DELAY BTFSC PORTB, 0 ; Confirm button is still pressed goto START ; Enable interrupts (clear flag first to avoid immediate trigger) BANKSEL INTCON BCF INTCON, 2 ; Clear TMR0IF BSF INTCON, 7 ; Enable GIE BSF INTCON, 5 ; Enable TMR0IE MAIN_LOOP: goto MAIN_LOOP ; Stay in main loop after enabling interrupts
Final Notes
- Double-check your hardware connections: Ensure the BCD4511's
LEpins are connected to RC4/RC5,BIto RC2, and that PORTD is connected to the BCD inputs of each 4511. - The prescaler setting in
OPTION_REG(1:256) gives a slow enough interrupt for visible counting, but you can adjustTMR0_INITto make the count faster or slower.
内容的提问来源于stack exchange,提问作者stackingnauledge

