Så här ser min krets ut http://forumbilder.se/show.asp?iid=993A6804
Knappen används inte i den här koden
Kristallen är på 4MHz
Anoderna är kopplade till RD0-RD6
De gemensamma Cathoderna är kopplade via NPN-transistorer till RB7,RB6 och RB5
De tre displayerna ska användas så här:
Digit 1 visar hundratal
Digit 2 visar tiotal
Digit 3 visar ental
Till dessa har jag skapat 3st register som kallas Count_h (hundratal) , Count_t (tiotal) och Count_s (ental).
Count_s jämförs hela tiden med XORLW b'1010' för att titta om Count_s blev 10. Då skall Count_s nollställas och Count_t ökas med 1. Likadant med Count_t. Count_h nollställs när den uppnår värdet 10.
Interrupten jag har använder sig av Timer0. Den skall helt enkelt byta vilken Display som ska visas samt att visa vilken siffra (Count_s, Count_t, Count_h) i den displayen som ska visas. Till detta har jag en(ett?) TABLE som jag hämtar rätt värde för att sedan flytta det till PORTD.
För att den ska veta vilken display som ska visas har jag Count.
Count = 1 -> Visa Digit 3
Count = 2 -> Visa Digit 2
Count = 3 -> Visa Digit 1
Count = 4 -> Rensa Count (clrf Count)
Kod: Markera allt
;**********************************************************************
; This file is a basic code template for assembly code generation *
; on the PIC16F877A. This file contains the basic code *
; building blocks to build upon. *
; *
; Refer to the MPASM User's Guide for additional information on *
; features of the assembler (Document DS33014). *
; *
; Refer to the respective PIC data sheet for additional *
; information on the instruction set. *
; *
;**********************************************************************
; *
; Filename: xxx.asm *
; Date: *
; File Version: *
; *
; Author: *
; Company: *
; *
; *
;**********************************************************************
; *
; Files Required: P16F877A.INC *
; *
;**********************************************************************
; *
; Notes: *
; *
;**********************************************************************
list p=16f877A ; list directive to define processor
#include <p16f877A.inc> ; processor specific variable definitions
__CONFIG _CP_OFF & _LVP_OFF & _BODEN_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC
#define J 0x20
#define K 0x21
#define Display 0x22
#define Count 0x23
#define W_Temp 0x24
#define STATUS_Temp 0x25
#define d1 0x26
#define d2 0x27
#define Count_h 0x28
#define Count_t 0x29
#define Count_s 0x30
#define Number 0x31
org 0
goto Start
org 4
goto Do_Interrupt
;=====================================
;========== LOOKUP TABLE =============
;=====================================
Lookup:
ADDWF PCL ; Jump to entry spec'd by w.
RETLW 0x3F ; 0
RETLW 0x06 ; 1
RETLW 0x5B ; 2
RETLW 0x4F ; 3
RETLW 0x66 ; 4
RETLW 0x6D ; 5
RETLW 0x7C ; 6
RETLW 0x07 ; 7
RETLW 0x7F ; 8
RETLW 0x67 ; 9
;=====================================
;====== INITIALIZE PROGRAM ===========
;=====================================
Start: ;Initierar de första instruktionerna
bsf STATUS,RP0 ; Väljer Bank1
clrf TRISD ; Gör alla portar på PORTD till output
movlw b'00011111' ; Gör RB5,6,7 outout. RB0-4 input
movwf TRISB
movlw b'11000011' ; Ladda w
movwf OPTION_REG ; Flytta w till OPTION_REG
bcf STATUS,RP0 ; Tillbaka till Bank0
clrf PORTD ; Släcka alla lysdioder i början
clrf PORTB ; Stäng av PORTB
clrf Count
clrf Count_s
clrf Count_t
clrf Count_h
clrf Display
clrf Number
movlw 0x06 ; Ladda w med 6
movwf TMR0 ; Flytta w till TMR0
bsf INTCON,GIE ; Möjliggör interrupt
bsf INTCON,TMR0IE ; Möjliggör TMR0 interrupt
;movlw 0x7F
;movwf PORTD
;bsf INTCON,INTE ; Möjliggör interrupt genom flankändring på RB0/INT pinnen
;=====================================
;======== MAIN PROGRAM LOOP =========
;=====================================
Main:
call OndelayLoop ; Dröj en stund
movf Count_s,w ; Flytta Count_s till W
xorlw 0x0a ; Blev det 10? Jämnför Count_s med 1010
btfsc STATUS,Z ; Blev STATUS,Z 1? I så fall gå till nästa instruktion. Annars hoppa över den
call Increase_tens ; Ropa på Increase_tens
movf Count_t,w ; Flytta Count_t till W
xorlw 0x0a ; Gör samma sak med Count_t
btfsc STATUS,Z ; Blev STATUS,Z 1? I så fall gå till nästa instruktion. Annars hoppa över den
call Increase_hundreds ; Ropa på Increase_hundreds
movf Count_h,w
xorlw 0x0a
btfsc STATUS,Z ; Blev STATUS,Z 1? I så fall gå till nästa instruktion. Annars hoppa över den
clrf Count_h ; Rensar Count_h om STATUS,Z blev 1 i föregående instruktion.
incf Count_s,f ; Öka Count_s med 1
goto Main ; Gå tillbaka till Main
Increase_tens:
incf Count_t,f ; Öka Count_t med 1
clrf Count_s ; Rensa Count_s
return ; Gå tillbaka
Increase_hundreds:
incf Count_h,f ; Öka Count_h med 1
clrf Count_t ; Rensa Count_t
return
;=====================================
;===== INTERRUPT SERVICE ROUTINE =====
;=====================================
Do_Interrupt: ; Interrupt rutin
movwf W_Temp ; Spara det som fanns i W i W_temp
movf STATUS,w ; Flytta det som finns i Status till W
movwf STATUS_Temp ; Och spara det i STATUS_Temp
movlw 0x06 ; Ladda w med 6
movwf TMR0 ; Flytta w till TMR0
incf Count,f ; Öka Count med 1 varje gång TMR0 Interrupten aktiveras.
clrf PORTD ; Stäng av alla segment i 7segment display.
clrf PORTB ; Stäng av alla Common Cathode
movf Count,w ; Flytta Count till w
xorlw 0x03 ; Blev Count b'011'?
btfsc STATUS,Z
call Digit1 ; Ja? -> Gå till Digit1
movf Count,w ; Flytta Count till w
xorlw 0x02 ; Blev count b'010'?
btfsc STATUS,Z
call Digit2 ; Ja? -> Gå till Digit2
movf Count,w ; Flytta Count till w
xorlw 0x01 ; Blev count b'001'
btfsc STATUS,Z
call Digit3 ; Ja? -> Gå till Digit3
btfsc Count,2 ; Blev count b'100'?
clrf Count ; Ja? -> rensa Count
movf STATUS_Temp,w ; Få tillbaka värdet från STATUS_Temp till W
movwf STATUS ; Flytta W till STATUS-registret
swapf W_Temp,f ; Få tillbaka värdet från W_temp till W utan att påverka statusregistret
swapf W_Temp,w
bcf INTCON,TMR0IF ; Återställ TMR0IF så att en ny interrupt blir möjlig
retfie ; Gå tillbaka
;=====================================
;=========== DELAY LOOP ==============
;=====================================
OndelayLoop:
decfsz J,f ; Waste time.
goto OndelayLoop ; The Inner loop takes 3 instructions per loop * 256 loopss = 768 instructions
; decfsz K,f ; The outer loop takes and additional 3 instructions per lap * 256 loops
; goto OndelayLoop ; (768+3) * 256 = 197376 instructions / 1M instructions per second = 0.197 sec.
; call it a two-tenths of a second.
return
;=====================================
;====== DIGIT DISPLAY CHOOSER ========
;=====================================
Digit1:
movlw 0x80 ; b'1000 0000' till w
movwf PORTB ; Aktivera PORTB,7 (Digit 1 på 7 segment display)
movf Count_h,w ; Flytta värdet i Count_h till w
andlw b'00001111' ; Ta bort de 4 högsta bitarna
call Lookup ; Kolla vilken siffra som ska visas
movwf Display ; Flytta w till Display (Kanske är ett onödigt steg men det kan väll inte skada?
movf Display,w ; Flytta Display till W
movwf PORTD ; Och visa den i PORTD
return
Digit2:
movlw 0x40 ; b'0100 0000' till w
movwf PORTB ; Aktivera PORTB,6 (Digit 2 på 7 segment display)
movf Count_t,w ; Flytta värdet i Count_t till w
andlw b'00001111' ; Ta bort de 4 högsta bitarna
call Lookup ; Kolla vilen siffra som ska visas
movwf Display ; Flytta w till Display (Kanske är ett onödigt steg men det kan väll inte skada?
movf Display,w
movwf PORTD ; Och visa den i PORTD
return
Digit3:
movlw 0x20 ; b'0010 0000' till w
movwf PORTB ; Aktivera PORTB,5 (Digit 3 på 7 segment display)
movf Count_s,w ; Flytta värdet i Count_s till w
andlw b'00001111' ; Ta bort de 4 högsta bitarna
call Lookup ; Kolla vilen siffra som ska visas
movwf Display ; Flytta w till Display (Kanske är ett onödigt steg men det kan väll inte skada?
movf Display,w
movwf PORTD ; Och visa den i PORTD
return
end ; Avslutar programmet
Är det Main loopen som är felaktig? Kör jag programmet i MPLAB SIM så fungerar det.