Kört fast med multiplexing av 3st 7-segment display (PIC)

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Spket
Inlägg: 81
Blev medlem: 22 mars 2009, 02:19:50

Kört fast med multiplexing av 3st 7-segment display (PIC)

Inlägg av Spket »

Hej igen. Försöker lära mig och har kommit en bit. Nu är jag inne på det här med interrupts och har precis börjat använda mig av TMR0 för att multiplexa 3st 7-segment displayer. Tanken är att göra en räknare som räknar från 000 till 999 och sen börjar om helt enkelt.

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
Problemet jag har är att endast Digit 3 ändrar värde. Ökar jag prescaler till 256 kan jag ibland se att Digit 2 blir 1.

Är det Main loopen som är felaktig? Kör jag programmet i MPLAB SIM så fungerar det.
Användarvisningsbild
SeniorLemuren
Inlägg: 8332
Blev medlem: 26 maj 2009, 12:20:37
Ort: Kristinehamn

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av SeniorLemuren »

Kan det ha något med PORTB pull-up att göra? Den är disabled vad jag kan förstå.

Kod: Markera allt

movlw   b'11000011'      ; Ladda w
movwf   OPTION_REG      ; Flytta w till OPTION_REG
Edit. Tänkte lite fel på. Glöm det. :)
Användarvisningsbild
Icecap
Inlägg: 26610
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av Icecap »

Hela scanningen av displayen är i grunden fel! Du räknar upp värden samtidig som du scannar dom, inget bra!

Din ISR ser ganska OK ut men det du ska göra är att ha 3 minnesplatser som motsvarar var sin siffra. Ska det visas något på en viss siffra skriver du det i rätt minnesplats från mainloop'en, då ska ISR'n sköta resten per automatik.

Din ISR ska göra följande:
1: Spara alla temp-saker (gör du redan).
2: Stänga av PORTD (skicka ut 0x00) för att släcka displayen.
3: Stänga av PORTB. Dessa två lite onödiga punkter är viktiga för att undvika ghosting.
4: Välj rätt minnesplats för nästa siffra och skriv till PORTD. Dessa data är i "grafisk" form redan!
5: Välj rätt siffra på PORTB och slå på den.
6: Stega upp siffraräknaren och nolla den om den blir större än antalet siffror.
7: Återställ alla temp-saker (gör du redan).
Nu är din ISR "short & sharp" och gör det den ska.

I mainloop kan du sedan räkna upp värdet för att se siffrorna rulla på.

Du får göra en "skriv ut"-funktion som kan ta ett värde (16 bit) och omvandla till 3 tecken som sedan omvandlas till grafiska värden (Lookup) och sparas i scanningsminnet.

Har saxat lite från ett projekt som just scannade ett 3-siffrigt LED display. Det kan kanske finnas lite annat med som inte hör till, ISR'n hade en del annat att göra med menyval, auto-repeat på knappsats osv. Jag tror att jag har fått tagit bort det mesta av dessa onödiga saker men jag orkar inte lusläsa det hela... Projektet är ett antal år gammalt (från 2007) så det kan vara snyggare sätt att göra det hela på...

Kod: Markera allt

	org	0x070
w_temp			res	1	; variable used for context saving 
status_temp		res	1	; variable used for context saving
pclath_temp		res	1	; variable used for context saving
	org	0x020
Scan_Ctr		res	1	; Used to scan the display and such
ScanDigits		res	3	; Holds the digit pattern

; Here main is jumped to

ISR	org	0x004		; Interrupt vector location
	movwf	w_temp		; save off current W register contents
	movf	STATUS,W	; move status register into W register
	movwf	status_temp	; save off contents of STATUS register
	movf	PCLATH,W
	movwf	pclath_temp
	clrf	PCLATH		; Be sure that wer'e home alone
	banksel	PIR1
Timer0_Int
	btfss	INTCON,T0IF	; Is it Timer0?
	goto	ISR_Exit	; Jump if not
	bcf	INTCON,T0IF	; Clear interript request flag
	clrf	PORTB		; Shut off LED's
	movf	PORTA,W		; Get PORTA into W
	andlw	b'11111000'	; Mask out Column-bits
	movwf	PORTA		; Shut off column drivers
	incf	Scan_Ctr,F	 ; Increment scan-counter
	movf	Scan_Ctr,W	; Read Scan_Ctr
	sublw	d'3'-1		; Is Scan_Ctr >= 3?
	btfss	STATUS,C	; Skip next if not
	clrf	Scan_Ctr	; Else clear Scan_Ctr
	movf	Scan_Ctr,W	; Read Scan_Ctr
	addlw	ScanDigits	; Offset with ones position
	movwf	FSR		; Set it in index register
	movf	INDF,W		; Read the appropriate data
	movwf	PORTB		; Send out pattern on PORTB
	movf	Scan_Ctr,W	; Read value
	addwf	Scan_Ctr,W	; Make it double
	addwf	PCL,F		; Make an indexed jump
	movlw	b'00000001'	; Index #0
	goto	ISR_Scan01
	movlw	b'00000010'	; Index #1
	goto	ISR_Scan01
	movlw	b'00000100'	; Index #2
;	goto	ISR_Scan01 ; Not really needed, just here for clarity
ISR_Scan01
ISR_Exit
	movf	pclath_temp,W	; Read copy of PCLATH
	movwf	PCLATH		; Restore to pre-ISR content
	movf	status_temp,W	; Retrieve copy of STATUS register
	movwf	STATUS		; Restore pre-isr STATUS register contents
	swapf	w_temp,F
	swapf	w_temp,W	; Restore pre-isr W register contents
	retfie			; Return from interrupt

Digits ; Returns "graphic" value for a given character to write
	andlw	h'1F'
	bsf	PCLATH,2	; Set correct bank bits
	bcf	INTCON,GIE
	call	DigitTabel
	bcf	PCLATH,2
	bsf	INTCON,GIE
	return

	org	h'400'
DigitTabel
	addwf	PCL,F
	retlw	b'00111111'	;00 '0' gFEDCBA
	retlw	b'00000110'	;01 '1' gfedCBa
	retlw	b'01011011'	;02 '2' GfEDcBA
	retlw	b'01001111'	;03 '3' GfeDCBA
	retlw	b'01100110'	;04 '4' GFedCBa
	retlw	b'01101101'	;05 '5' GFeDCbA
	retlw	b'01111101'	;06 '6' GFEDCbA
	retlw	b'00000111'	;07 '7' gfedCBA
	retlw	b'01111111'	;08 '8' GFEDCBA
	retlw	b'01101111'	;09 '9' GFeDCBA
	retlw	b'01110111'	;10 'A' GFEdCBA
	retlw	b'01111100'	;11 'b' GFEDCba
	retlw	b'00111001'	;12 'C' gFEDcbA
	retlw	b'01011110'	;13 'd' GfEDCBa
	retlw	b'01111001'	;14 'E' GFEDcbA
	retlw	b'01110001'	;15 'F' GFEdcbA
	retlw	b'01110110'	;16 'H' GFEdCBa
	retlw	b'01110100'	;17 'h' GFEdCba
	retlw	b'00011110'	;18 'J' gfEDCBa
	retlw	b'00111000'	;19 'L' gFEDcba
	retlw	b'01010100'	;20 'n' GfEdCba
	retlw	b'01011100'	;21 'o' GfEDCba
	retlw	b'01110011'	;22 'P' GFEdcBA
	retlw	b'01010000'	;23 'r' GfEdcba
	retlw	b'00111110'	;24 'U' gFEDCBa
	retlw	b'01101110'	;25 'Y' GFeDCBa
	retlw	b'01000000'	;26 '-' Gfedcba
	retlw	b'00001000'	;27 '_' gfeDcba
	retlw	b'00000001'	;28 '¯' gfedcbA
	retlw	b'01001000'	;29 '=' GfeDcba
	retlw	b'01011101'	;30 'ö' GfEDCbA
	retlw	b'00000000'	;31 ' ' gfedcba
;	retlw	b'0'	; '' gfedcba
; A0A
;F   B
;5   1
; G6G
;E   C
;4   2
; D3D DP7

Sign_0		equ	d'00'
Sign_1		equ	d'01'
Sign_2		equ	d'02'
Sign_3		equ	d'03'
Sign_4		equ	d'04'
Sign_5		equ	d'05'
Sign_6		equ	d'06'
Sign_7		equ	d'07'
Sign_8		equ	d'08'
Sign_9		equ	d'09'
Sign_A		equ	d'10'
Sign_b		equ	d'11'
Sign_C		equ	d'12'
Sign_d		equ	d'13'
Sign_E		equ	d'14'
Sign_F		equ	d'15'
Sign_H		equ	d'16'
Sign_h		equ	d'17'
Sign_J		equ	d'18'
Sign_L		equ	d'19'
Sign_n		equ	d'20'
Sign_o		equ	d'21'
Sign_P		equ	d'22'
Sign_r		equ	d'23'
Sign_U		equ	d'24'
Sign_Y		equ	d'25'
Sign_Dash	equ	d'26'
Sign_Underscore	equ	d'27'
Sign_Overscore	equ	d'28'
Sign_Equal	equ	d'29'
Sign_oe		equ	d'30'
Sign_Blank	equ	d'31'
Spket
Inlägg: 81
Blev medlem: 22 mars 2009, 02:19:50

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av Spket »

Tack så mycket för svaret! Fanns mycket nyttig information där som jag ska ta till mig. Tyvärr är klockan lite för mycket just nu för att jag ska ha orken att sätta mig och skriva lite men ska definitivt ta till mig det i morgon.

Trevligt helg!
Spket
Inlägg: 81
Blev medlem: 22 mars 2009, 02:19:50

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av Spket »

Icecap skrev:

Du får göra en "skriv ut"-funktion som kan ta ett värde (16 bit) och omvandla till 3 tecken som sedan omvandlas till grafiska värden (Lookup) och sparas i scanningsminnet.
Den här raden förbryllar mig lite. Jag är som sagt helt färsk när det kommer till programmering. Läste lite Visual Basic, C++ å Java i gymnasiet med det är nästan 10 år sedan.

Skulle du kunna utveckla lite vad du menar?
sodjan
EF Sponsor
Inlägg: 43231
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av sodjan »

> en räknare som räknar från 000 till 999

Alltså behövsa det en 16-bitars variabel som "räknare",
en enskild byte räcker inte till. *Eller* så kör man med
tre inidividuella register för 100, 10 resp ental (så som
du föreslog), båda fungerar och vilket man väljer är mer
upp till vad det ska användas till.

Sedan, när du har själva uppräkningen klar, så kan du kolla
på hur det ska visas på displayerna. Varje värde från de tre
siffrorna behöver översättas till motsvarande 7-seg kod för att
visa rätt siffra på displayen.

Hur det hela ska struktureras är lite svårt att säga. Det hänger mycket
ihop med hur kopplingen är mellan själva uppräkningen och visningen.
Ofta är det ju så att det inte har någonting alls med varandra att göra.
Räknaren kanske räknar händelser på en I/O pinne, men visningen måste
ju pågå hela tiden utan avbrott oavsett om det räknar eller inte. D.v.s att
även om det är samma siffror hela tiden så måste multiplexningen av
displayerna fortgå.

Så bäst är att separera uppräkningen från visningen.
Användarvisningsbild
4kTRB
Inlägg: 20287
Blev medlem: 16 augusti 2009, 19:04:48

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av 4kTRB »

Jag kodade i JavaScript nyligen, en liknande uppgift.

Principen jag använder är att ha en bild för varje siffra lagrad och byter sedan bilder
beroende på vad räknaren innehåller. Du kan säker använda samma teknik fast ha
en uppsättning bitmönster för varje led-siffra lagrat i minnet.

Funktionen nedan anropas varje gång ett avbrott sker, tex en timer som tickar. ledCounter är satt till noll
vid start och sedan beroende på vad den räknats upp till så sätts de tre displayerna
till rätt värde. Hoppas du greppar principen?

Här avslutas det hela när det räknat till 100.

Kod: Markera allt

	function setLedDisplay() {
		ledCounter++;
		var x = y = z = 0;
		if (ledCounter < 10) {
			z = 0; y = 0; x = ledCounter ;
		}
		if (ledCounter >= 10) {
			z = 0; y = parseInt(ledCounter / 10); x = ledCounter - y * 10;
		}
		if (ledCounter >= 100) {
			z = 1; y = 0; x = 0;
		}
		document.getElementById("C").setAttribute("src", imgLed[z].src);
		document.getElementById("B").setAttribute("src", imgLed[y].src);
		document.getElementById("A").setAttribute("src", imgLed[x].src);
	}
Spket
Inlägg: 81
Blev medlem: 22 mars 2009, 02:19:50

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av Spket »

Hur skapar man en 16-bitars variabel? Är det som Icecap gjort genom
ScanDigits res 3?

Står 'res' för reserve? Dvs att man reserverar 3 bytes för ScanDigits?

"res can be used to reserve data storage. In non-relocatable code, label is assumed to be a program memory address.
Address locations are defined in words for PIC12/16 MCUs, and bytes for PIC18 MCUs."
http://ww1.microchip.com/downloads/en/d ... 33014j.pdf - MICROCHIPS ASSEMBLER/LINKER/LIBRARIAN USER’S GUIDE s.107

Så om jag t.ex. skapar en 16-bitars variabel Number
Number res 2

Då innehåller den 2 bytes eller 16 bitar. Men instruktionerna påverkar bara 8bitar? Eller tänker jag helt snett nu?
Säg att jag vill flytta värdet i den höga byten till w. Ser instruktionen ut så här då?
movf Number+1,w ; Flytta den höga byten av Number till w

Är instruktionen för den låga byten som vanligt?
movf Number,w
Användarvisningsbild
4kTRB
Inlägg: 20287
Blev medlem: 16 augusti 2009, 19:04:48

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av 4kTRB »

Kom på att det blir lite effektivare med omvänd ordning...

Kod: Markera allt

   function setLedDisplay() {
      ledCounter++;
      var x = y = z = 0;
      if (ledCounter >= 100) {
         z = 1; y = 0; x = 0;
      avsluta;
      }
      if (ledCounter >= 10) {
         z = 0; y = parseInt(ledCounter / 10); x = ledCounter - y * 10;
      }
      if (ledCounter < 10) {
         z = 0; y = 0; x = ledCounter ;
      }
      document.getElementById("C").setAttribute("src", imgLed[z].src);
      document.getElementById("B").setAttribute("src", imgLed[y].src);
      document.getElementById("A").setAttribute("src", imgLed[x].src);
   }
Kaggen
Inlägg: 432
Blev medlem: 29 januari 2005, 03:06:02

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av Kaggen »

> Hur skapar man en 16-bitars variabel? Är det som Icecap gjort genom
> ScanDigits res 3?

Det är 3 bytes = 24 bit inte 16. Men i Icecaps fall används dom som separata bytes, 1 per digit.

> Så om jag t.ex. skapar en 16-bitars variabel Number
> Number res 2

Japp! res reserverar bara det antal bytes du anger i RAM minne. Om du reserverar 4 bytes och använder dom som ett 32-bitars tal eller 4 tecken sträng eller 4 st 8-bitars tal struntar assemblern i. Det beror på hur du skriver din kod.

> Då innehåller den 2 bytes eller 16 bitar. Men instruktionerna påverkar bara 8bitar? Eller tänker jag helt snett nu?

Du tänker rätt. Om du använder en 8-bitars uC så kan du i de flesta fall bara hantera 8 bitar åt gången. W är ett 8-bitars register. För att hantera större tal använder man overflow, carry m.fl flaggor i STATUS registret. Dvs om W innehåller 255 och du adderar 1 så kommer W att innehålla noll efter additionen. Dock sätts C-flaggan i STATUS registret som talar om att du har wrappat runt W. Detta gör att du kan bittesta C-flaggan efter en addition och avgöra om du måste öka höga byten, i ett 16-bitars tal t.ex, med ett.

För att konvertera en 16-bitars variabel till tre ascii siffror kan du modifiera koden i nedanstående länk:
http://www.piclist.com/techref/microchi ... 3a2-ng.htm

EDIT nedanstående länk är nog bättre än den förra.
http://www.piclist.com/techref/microchi ... b3a-ng.htm
sodjan
EF Sponsor
Inlägg: 43231
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av sodjan »

> Hur skapar man en 16-bitars variabel? Är det som Icecap gjort genom
> ScanDigits res 3?

Nja, det reserverar ett minnesytrymme 3 bytes stort och med en symbol
"ScanDigits" som pekar på första/lägsta adressen. Hur du senare använder
dessa struntar RES helt i.

> Står 'res' för reserve?

RES gör (surprice!) exakt det som dokumentationen säger! :-)
Fråga gärna på det som eventuellt är otydligt i dokumentationen.

Skillnaden mellan RES och EQU (som användes i din kod) är bl.a att
med RES så *reserveras* fysiskt minne, med EQU så ger man bara en
symbol ett värde, den kan betyda vad som helst och behöver inte ha
någonting alls med minne att göra.

> movf Number+1,w ; Flytta den höga byten av Number till w
> movf Number,w

Ja, det där ser väl OK ut. Och som du har förstått så finns det inga
instruktioner som direkt räknar upp 16 bitar, man får göra det en byte
i taget, i princip på samma sätt som när du räknar ihop två tal mellan
11 och 99 "på papper". Först högra delen och sedan vänstra delen inkl
eventuellt carry/minnessiffra ifall den första delen gav "overflow".
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av jesse »

Man behöver lära sig metoderna för hur man arbetar med 16-bitars tal i assembler för en 8-bitars microprocessor. Det kan skilja sig lite åt beroende på processortyp, men generellt fungerar det likadant. Som Sodjan säger t.ex. vid addition så adderar man först de låga byten, sedan adderar man de höga byten inklusive 'carry'. I assembler finns det en särskild adderingsinstruktion som tar med carry.

För PIC finns bra guide här för 16-bitars operationer:
16 Bit Operations on PIC Chips

Testa att skriva lite kod och kör i simulator så du får en uppfattning om hur det fungerar.

Å andra sidan - om du bara ska räkna upp tre siffror från 000-999 så behöver du ju inget 16-bitars tal. Då låter du siffrorna enklast vara var sin separat byte i minnet. Men normalt sett, så brukar ju man använda talet till något annat också - inte bara visa siffrorna. T.ex att man läst in ett analogt värde (spänning). Då är det normala att man 'internt' i processorn har ett 16-bitars tal, och som omvandlas till tre separata siffror först i den rutin som ska sätta siffrorna. Det är ju skillnad på talet 745 och tecknen '7', '4' och '5'.

talet 745 kan du räkna med hur du vill (addition, multiplikation etc.) på vanligt sätt, Tecknen "745" är ju bara att likna vid en textsträng.
Spket
Inlägg: 81
Blev medlem: 22 mars 2009, 02:19:50

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av Spket »

Hej igen!

Tack för era svar. Jag har äntligen lyckats få ihop det.
Jag använde mig av den här. Jag förstår inte riktigt mattematiken bakom med additionerna m.m. Men jag förstår vad den gör i alla fall. Fick modifiera den lite så att den passa mig.
Kaggen skrev:> EDIT nedanstående länk är nog bättre än den förra.
http://www.piclist.com/techref/microchi ... b3a-ng.htm
Har även läst mer ur databladet till både PIC16f877a och MPLAB IDE (som jag länkade ovan). Förstått mig på så smått det här med bytes osv.

Så här ser skönheten ut
http://forumbilder.se/show.asp?iid=68E75CA6 Klicka här för en lite större bild
Bild
Trassel, jag vet. Den blåa lysdioden används för att se om strömmen är på.

Här är i alla fall koden om någon önskar att se den. Många kommentarer.. men det är för att jag ska repetera in allt och försöka lära mig så jag slipper sitta å titta på ett papper med instruktionerna hela tiden

Kod: Markera allt

; Multiplexa 3st 7-segment leddisplay.
; Räkna från 000 till 999 och börja om.


	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

cblock 0x20
	J				; 20
	K				; 21
	Display			; 22	
	W_Temp			; 23
	STATUS_Temp		; 24
	Hund			; 25
	Tens			; 26
	Ones			; 27
	Number:2		; 28-29
	PCLATH_Temp		; 30
endc
	org	0
	goto	Start

	org 4
	goto	ISR

;=====================================
;===== INTERRUPT SERVICE ROUTINE =====
;=====================================

ISR:
	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
	movf	PCLATH,w		; Flytta PCLATH till w
	movwf	PCLATH_Temp		; Spara det i PCLATH_Temp
	clrf	PCLATH			; Rensa PCLATH

Timer0_Int:	
	btfss	INTCON,TMR0IF	; Va det en TMR0 interrupt?
	goto	ISR_Exit		; Nej, gå till ISR_Exit
	bcf		INTCON,TMR0IF	; Möjliggör en ny interrupt

	clrf	PORTD
	clrf	PORTB			; Undvik ghosting

	incf	Display,f

	movf	Display,w
	xorlw	0x01			; Blev Display == 1?
	btfsc	STATUS,Z
	goto	Digit1			; Ja! Tänd första siffran

	movf	Display,w
	xorlw	0x02			; Blev Display == 2?
	btfsc	STATUS,Z
	goto	Digit2			; Ja! Tänd andra siffran

	movf	Display,w
	xorlw	0x03			; Blev Display == 3?
	btfsc	STATUS,Z
	goto	Digit3			; Ja! Tänd tredje siffran

Digit1:
	movf	Hund,w
	call	Lookup
	movwf	PORTD
	bsf		PORTB,7
	goto	ISR_Exit

Digit2:
	movf	Tens,w
	call	Lookup
	movwf	PORTD
	bsf		PORTB,6
	goto	ISR_Exit

Digit3:
	clrf	Display			; Rensa Display så att vi börjar om med Digit1 efter denna.
	movf	Ones,w
	call	Lookup
	movwf	PORTD
	bsf		PORTB,5
	goto	ISR_Exit

ISR_Exit
	movf	PCLATH_Temp,w
	movwf	PCLATH
	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

	retfie
	
	

;=====================================
;====== 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	Ones			; Börja med allt på 0
	clrf	Tens
	clrf	Hund
	clrf	Number
	clrf	Number+1
	clrf	Display

	clrf	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
	bcf		STATUS,Z		; Nollställ Zero
	incf	Number,f		; Öka Byte 1 i Number med 1
	btfsc	STATUS,Z		; Blev Number > 256? 
	incf	Number+1,f		; Ja, öka Byte 2 i Number med 1
	call	bin2dec999

; Kolla om Number > 999
	movlw	0x03
	xorwf	Number+1,w		; Är den höga byten i Number == 3?
	btfss	STATUS,Z
	goto	Main			; Nej, gå till main
	movlw	0xE7			
	xorwf	Number,w		; Ja! Är den låga byten i Number == 231?
	btfss	STATUS,Z
	goto	Main			; Nej, gå till main
	clrf	Number			; Ja! Då är det totala värdet i Number 999
	clrf	Number+1		; Börja då om på 000
	goto	Main	
	
	
	

;=====================================
;========= Binary to Decimal =========
;=====================================

bin2dec999
	bcf	INTCON,GIE				; Omöjliggör interrupt medans vi konverterar talen
		movf	Number+1, w		; Flytta den höga byten till W
		addlw	d'241'			; Addera W med 241
		addwf	Number+1, w		; Addera den höga byten med W spara
								; nya värdet i W

		movwf	Hund      		; b_2 = 2a_2 - 15
								; Flytta W till Hund
		addwf	Hund, w			; Addera W och Hund. Spara i W
		addwf	Hund, w			; Addera W och Hund. Spara i W
		addlw	d'253'			; Addera W med 253
		movwf	Tens			; Flytta W till Tens
		swapf	Number, w		; Byt de högsta 4 bitarna med de 4 lägsta
								; bitarna i Number. t.ex. 1001 0110 blir
								; 0110 1001
		andlw	0x0F			; Logisk AND. W AND 15 (00001111)
		addwf	Tens, f			; Addera W och Tens. Spara i Tens
		addwf	Tens, f   		; Addera W och Tens. Spara i Tens
 								; (b_1 = 6a_2 + 2a_1 - 48)

		addwf	Number+1, w		; Addera den höga byten i Number och W
		sublw	d'251'			; Subtrahera W från 251
		movwf	Ones			; Flytta W till Ones
		addwf	Ones, f			; Addera W och Ones. Spara i Ones 
		addwf	Ones, f			; Addera W och Ones. Spara i Ones 
		addwf	Ones, f			; Addera W och Ones. Spara i Ones 
		movf	Number, w		; Flytta den låga byten i Number till W
		andlw	0x0F			; Logisk AND. W AND 15 (00001111)
        addwf	Ones, f			; Addera W och Ones. Spara i Ones
								; b_0 = a_0 - 4(a_2 + a_1) - 20
	
		movlw	d'10'			; W = 10
bin2dec999a                     ;9 cycles max
		addwf	Ones, f			; Addera W och Ones. Spara i Ones
		decf	Tens, f			; Minska Tens med 1. Spara i Tens
		skpc					; BTFSS STATUS,C	Hoppa över nästa
								; instruktion om STATUS,C = 1
		goto	bin2dec999a

bin2dec999b                     ;6 cycles max
		addwf	Tens, f			; Addera W och Tens. Spara i Tens
		decf	Hund, f			; Minska Hund med 1. Spara i Hund
		skpc					; BTFSS STATUS,C	Hoppa över nästa
								; instruktion om STATUS,C = 1					
		goto	bin2dec999b

bin2dec999c                     ;3 cycles max
		addwf	Hund, f			; Addera W och Hund. Spara i Hund
		skpc					; BTFSS STATUS,C	Hoppa över nästa
								; instruktion om STATUS,C = 1
		goto	bin2dec999c

	bsf	INTCON,GIE

		return


;=====================================
;========== 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


;=====================================
;=========== 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

end
sodjan
EF Sponsor
Inlägg: 43231
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av sodjan »

> Förstått mig på så smått det här med bytes osv.

Ja, det är ju svårt att hitta något mer grundläggande! :-)
Har du inte dessa saker "på plats" så blir mycket väldigt svårt...
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Kört fast med multiplexing av 3st 7-segment display (PIC

Inlägg av jesse »

snyggt! :bravo:

Jag är för dålig på att tolka PIC assembler, så jag ska inte kommentera koden.
Skriv svar