Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

dual 7-segment hex display controller

Status
Not open for further replies.

Ambient

New Member
dual 7-segment hex decoder

Finally got all the kinks worked out. Thanks for the help guys. I provided the Eagle CAD PCB and schematic files, just share your results if you make any improvements please. I minimized the top layer traces because I make single sided boards. Enjoy!

This project is simply a hex decoder for one byte input.

Code:
;Dual 7-segment hex display driver.
;Sean LeBlanc, 02/04/08
;NOTES:
;PORTC,0 pin is free to use as I/O.  PCB design has solder pad or switch option.
;This pin is also AN4, so ADC is available (comment out ADC off code).

	List	p=16f690
	include	P16F690.INC
	
	__CONFIG	_CP_OFF & _CPD_OFF & _BOR_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO & _MCLRE_OFF & _FCMEN_OFF & _IESO_OFF; & _INTRC_OSC_NOCLKOUT
	errorlevel  -302
	;-----------------------VARIABLE REGISTER DEFINITIONS---------------------------
w_temp		EQU	0x40		; variable used for context saving
status_temp	EQU	0x41		; variable used for context saving
pclath_temp	EQU	0x22		; variable used for context saving
Digit1		EQU	0x43
Digit2		EQU 0x44
temp		EQU	0x45

	org		0x0000
  	goto	Initialize
;***************************Interrupt_Routine**************************
	org		0x0004			; interrupt vector location
	movwf	w_temp
	movf	STATUS,W		; move status register into W register
	movwf	status_temp		; save of contents of STATUS register
	movf	PCLATH,W		; move pclath register into W register
	movwf	pclath_temp		; save of contents of PCLATH register
	bcf		PIR1,TMR2IF		;check which display is off (pin high)
	btfsc	PORTB,h'05'
	goto	Display1
	btfsc	PORTB,h'04'
	goto	Display2
STATUS_RESTORE
	movf	pclath_temp,W	; retrieve copy of PCLATH register
	movwf	PCLATH			; restore pre-isr PCLATH register contents	
	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
;***************************INITIALIZATION*****************************
Initialize
	banksel	ADCON0			;BANK 0
	movlw	b'00000000'
	movwf	ADCON0			;ADC off
	movlw	b'01001100'
	movwf	T2CON			;TMR2 PreS 1:1, TMR2 PostS 1:10
	banksel OSCCON			;BANK 1
	movlw	b'01000001'
	movwf	OSCCON			;sets oscillator to 1MHz
	bsf		PIE1,TMR2IE		;enable Timer2 interrupt
	movlw	b'00111111'
	movwf	TRISA			;PORTA I/O setup
	movlw	b'11000000'
	movwf	TRISB			;PORTB: RB4-5 outputs for Display select lines, 6 and 7 input
	movlw	b'00000001'
	movwf	TRISC			;PORTC: LED output pins
	movlw	b'11011000'
	banksel	ANSEL			;BANK 2
	clrf	ANSEL			;analog disable ANS0-ANS7
	clrf	ANSELH			;analog disable ANS8-ANS11
	banksel	INTCON			;BANK 0
	bsf		INTCON,PEIE
	bsf		INTCON,GIE
	bsf		PORTB,h'05'
	bcf		PORTB,h'04'
main
	nop
	nop
	goto	$-1				;idle loop
Display1
	movf	PORTB,W
	andlw	b'11000000'
	iorwf	PORTA,W
	movwf	temp
	swapf	temp,W
	andlw	h'0F'			;Most Significant Nibble
	call	Table
	movwf	Digit1	
	bsf		PORTB,h'04'		;disable display 2
	movf	Digit1,W
	movwf	PORTC
	bcf		PORTB,h'05'		;enable display 1
	goto	STATUS_RESTORE	
Display2
	movf	temp,W
	andlw	h'0F'			;Least Significant Nibble
	call	Table
	movwf	Digit2
	bsf		PORTB,h'05'		;disable display 1
	movf	Digit2,W
	movwf	PORTC
	bcf		PORTB,h'04'		;enable display 2
	goto	STATUS_RESTORE
Table
	andlw	b'00001111'
	addwf	PCL,F
	;PORTC    76543210
	;Segment  abcdefgh, active low, Common Anode setup
	retlw	b'00000010'	;0
	retlw	b'10011110'	;1
	retlw	b'00100100'	;2
	retlw	b'00001100'	;3
	retlw	b'10011000'	;4
	retlw	b'01001000'	;5
	retlw	b'01000000'	;6
	retlw	b'00011110'	;7
	retlw	b'00000000'	;8
	retlw	b'00011000'	;9
	retlw	b'00010000'	;A
	retlw	b'11000000'	;B
	retlw	b'01100010'	;C
	retlw	b'10000100'	;D
	retlw	b'01100000'	;E
	retlw	b'01110000'	;F
	END
;+++++++++++++++++++PORTC Pinout+++++++++++++++
;++++++++++++++++		  _a_		+++++++++++
;++++++++++++++++		 |   |		+++++++++++
;++++++++++++++++		f|_g_|b		+++++++++++
;++++++++++++++++		 |   |		+++++++++++
;++++++++++++++++		e|   |c		+++++++++++
;++++++++++++++++	  h	  -d-		+++++++++++
;++++++++++++++++++++++++++++++++++++++++++++++

Edited: changed some code around to make more usable on other PIC's
Edited 2/05/08: updated pcb design. I had the input header on the pcb upside down, so the bits were reversed. fixed now.
 

Attachments

  • 7_Segment_Module.zip
    32.6 KB · Views: 432
Last edited:
Everything is inside your ISR :rolleyes:

Why do you multiplex your two digits separately on every interrupt?

You can combine the two digits multiplexing coding into one & can place in the main routine.you can call a small delay in between digit separating.
You can check the inputs (byte) on every interrupt.That method is more sensitive.
 
Last edited:
I prefer putting the multiplex display routine in the ISR. At least, you don't have to worry when to switch the displays, the timer interrupt will do for you. This is why there are multiple interrupt source in the microcontroller.
 
You can certainly modify the code to do that, but I did it this way to make the code easier to put into a different program. Lots of our projects use a hex display, so I made the code easier to place into a new program. All you would need to do is modify the input source to an internal register, and you have 8 pins free for whatever else your project does.
 
Ah. I will be adding it to a larger assembly, pretty much like a trainer board. I guess that would be a complete project.
 
Nice job! We did something similar around September last year. It was kind of a callaborative or group effort of sorts;

erics-4477-ic-png.14391


There were two versions of the software. The v1 software used a loop with delay code in Main and the v2 software used interrupts like your example. I've attached both versions for anyone who may be interested and I have listed the ISR code (below) from the ISR version for you to compare or study.

Kind regards, Mike

Code:
;
ISR     movwf   W_ISR           ; save W-reg                      |B?
        swapf   STATUS,W        ; doesn't change STATUS bits      |B?
        movwf   S_ISR           ; save STATUS reg                 |B?
        clrf    STATUS          ; bank 0                          |B0
        movf    PCLATH,W        ; get PCLATH                      |B0
        movwf   P_ISR           ; save PCLATH                     |B0
        clrf    PCLATH          ; ISR is in bank 0                |B0
;
;  update left or right display on alternating interrupt cycles
;
        swapf   PORTA,W         ; W = hi nybble in b3..b0 bits    |B0
        btfss   DigSel,7        ; left digit? yes, skip, else     |B0
        movf    PORTA,W         ; W = lo nybble in b3..b0 bits    |B0
        andlw   b'00001111'     ; mask off upper 4 bits           |B0
        call    SegData         ; get segment data in W           |B0
        iorwf   DigSel,W        ; add digit select bit in b7      |B0
        movwf   PORTB           ; display new digit               |B0
        movlw   b'10000000'     ; mask for digit select bit       |B0
        xorwf   DigSel,F        ; toggle b7 digit select bit      |B0
;
        bcf     PIR1,TMR2IF     ; clear TMR2 interrupt flag bit   |B0
        movf    P_ISR,W         ;                                 |B0
        movwf   PCLATH          ; restore PCLATH                  |B0
        swapf   S_ISR,W         ;                                 |B0
        movwf   STATUS          ; restore STATUS                  |B0
        swapf   W_ISR,F         ; don't screw up STATUS           |B0
        swapf   W_ISR,W         ; restore W-reg                   |B0
        retfie                  ; return from interrupt           |B0
 

Attachments

  • Forum 4477 IC v2.asm
    8.3 KB · Views: 231
  • Forum 4477 IC v1.asm
    8.8 KB · Views: 212
Last edited:
Sean,

Here's one way you might streamline your ISR code a bit (below, eliminates about 13 instructions).

Is there a more convenient way to see your schematic and board layout?

I also don't see you setting the PR2 register. What is your Timer 2 periodic interrupt rate?

Mike

Code:
        org     0x0004          ; interrupt vector location
 
        movwf   w_temp          ;
        movf    STATUS,W        ; move status register into W register
        movwf   status_temp     ; save of contents of STATUS register
        movf    PCLATH,W        ; move pclath register into W register
        movwf   pclath_temp     ; save of contents of PCLATH register
        bcf     PIR1,TMR2IF     ; clear timer 2 interrupt flag bit
[COLOR=blue]
        movlw   b'11111110'     ; image for all segments off
        [/COLOR][COLOR=blue]movwf   PORTC           ; turn off display
        movlw   b'00110000'     ; digit select bit mask
        xorwf   PORTB,F         ; toggle digit select bits
        movf    PORTB,W         ; get fresh input reading
        andlw   b'11000000'     ;
        iorwf   PORTA,W         ;
        movwf   temp            ; W = b3..b0 bits in b3..b0
        btfss   PORTB,4         ; correct nybble? yes, skip, else
        swapf   temp,W          ; W = b7..b4 bits in b3..b0
        andlw   b'00001111'     ; mask off upper nybble
        call    Table           ; get segment data
        movwf   PORTC           ; update display
[/COLOR]
        movf    pclath_temp,W   ; retrieve copy of PCLATH register
        movwf   PCLATH          ; restore pre-isr PCLATH register contents    
        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
 
Last edited:
Sean (Ambient),

You may want to consider using the 70..7F 'common' RAM area for your ISR context variables and consider clearing the STATUS register after saving it to force Bank 0 (and IRP = 0). I've been using the 'swapf STATUS' instruction in my ISR code for years and I'm sure there's a reason why (grin) so please check out the interrupt section in the '690 Data Sheet.

Also, while your Table routine fits very nicely within a 256 byte boundary now that may not always be the case as you add or remove code in the program. You can always move it around and force it to fit within some 256 byte boundary but it might bite some other unsuspecting soul using your fine example and so it might be worth the extra few instructions to make the table "256 byte boundary tolerant" (please disregard the actual table portion below as it is completely backwards from your table)...

Mike

Code:
SegData
        movwf   temp            ; save 0..F index temporarily     |B0
        movlw   high SegTable   ;                                 |B0
        movwf   PCLATH          ;                                 |B0
        movlw   low  SegTable   ;                                 |B0
        addwf   temp,W          ;                                 |B0
        skpnc                   ;                                 |B0
        incf    PCLATH,F        ;                                 |B0
        movwf   PCL             ;                                 |B0

SegTable
        dt      b'00111111'     ; "0"   -|-|F|E|D|C|B|A
        dt      b'00000110'     ; "1"   -|-|-|-|-|C|B|-
        dt      b'01011011'     ; "2"   -|G|-|E|D|-|B|A
        dt      b'01001111'     ; "3"   -|G|-|-|D|C|B|A
        dt      b'01100110'     ; "4"   -|G|F|-|-|C|B|-
        dt      b'01101101'     ; "5"   -|G|F|-|D|C|-|A
        dt      b'01111101'     ; "6"   -|G|F|E|D|C|-|A
        dt      b'00000111'     ; "7"   -|-|-|-|-|C|B|A
        dt      b'01111111'     ; "8"   -|G|F|E|D|C|B|A
        dt      b'01101111'     ; "9"   -|G|F|-|D|C|B|A
        dt      b'01110111'     ; "A"   -|G|F|E|-|C|B|A
        dt      b'01111100'     ; "b"   -|G|F|E|D|C|-|-
        dt      b'00111001'     ; "C"   -|-|F|E|D|-|-|A
        dt      b'01011110'     ; "d"   -|G|-|E|D|C|B|-
        dt      b'01111001'     ; "E"   -|G|F|E|D|-|-|A
        dt      b'01110001'     ; "F"   -|G|F|E|-|-|-|A
 
Sorry for not replying sooner. I have been really busy with my hexapod project and work.

I set TMR2 with:
movlw b'01001100'
movwf T2CON ;TMR2 PreS 1:1, TMR2 PostS 1:10

I will have to look at the improved code you posted, Mike. Thanks!
 
Sean (Ambient),

The code I posted isn't really better or improved, it's just different and perhaps a little tighter. Your code is great...

So you're relying on the PR2 value of 255 (h'FF') on POR/BOR? What's the interrupt rate then? Something like 10 milliseconds?
 
Last edited:
Should be around 98Hz Interrupt rate. This is my math: 1MHz/4/255/10 = 98.03Hz. There are not too many instructions, so that will not affect it much. I have measured 100Hz on my analog scope, so it is operating properly.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top