PDA

View Full Version : 4 bit 7 segment display with two 74HC595



louislouis
- 18th February 2018, 09:17
Hello All,
I start to play with one of this cheap 4 digit 7 segment display. The display is driven by two 74HC595 which one is for segments and the other is for common cathodes (digits).
Here is the schematic:
8599

I writed a simple code using Darrel's interrupts. Code multiplexing the digits using TMR1 interrupt.
It works OK, but I think that code is not as elegant. It looks rough, because I'm not a skilled programmer.
Can someone explain to me a better way to do this task?

Here is my code:


'************************************************* ***************
'* Name : 4 bit 7 segment display *
'* Author : LouisLouis *
'* Notice : Copyright (c) 2018 *
'* : All Rights Reserved *
'* Date : 18. 2. 2018 *
'* Version : 1.0 *
'* Notes : *
'* MCU : PIC 12F1840 *
'************************************************* ***************

#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
__config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
#ENDCONFIG

DEFINE OSC 32 ; Use internal clock
OSCCON = %01110000
CLKRCON = 0

Include "modedefs.bas"
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts

TRISA = %000000
ANSELA = %0000
OPTION_REG.7=0 ; Enable internal pull-ups

LPIN var porta.2 ; Latch
DPIN var porta.4 ; Data
CPIN var porta.5 ; Clock

segment var byte
value var word
place var byte[4]
ones var word
tens var word
hundreds var word
thousands var word

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _DISP, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts
T1CON = $1

;---[simple counter 0 - to 9999]------------------------------------------------
Main:
for value = 0 to 9999
pause 100
next value
value = 0
GOTO Main

;---[TMR1 - interrupt handler]--------------------------------------------------
DISP:
T1CON.0 = 0 ; stop timer
TMR1H = %11111100
TMR1L = %00011111
T1CON.0 = 1 ; restart timer

;---[extract ones and show]-----------------------------------------------------
ones = value//10
lookup ones, [%11000000,%11111001,%10100100,%10110000,%10011001, %10010010,%10000010,%11111000,%10000000,%10010000],segment
LOW LPIN
Shiftout DPIN, CPIN, MSBFIRST,[segment,%0001]
high lpin

pause 4

;---[extract tens and show]-----------------------------------------------------
tens = value/10
tens = tens//10
lookup tens, [%11000000,%11111001,%10100100,%10110000,%10011001, %10010010,%10000010,%11111000,%10000000,%10010000],segment
LOW LPIN
Shiftout DPIN, CPIN, MSBFIRST,[segment,%0010]
high lpin

pause 4

;---[extract hundreds and show]-------------------------------------------------
hundreds = value/100
hundreds = hundreds//10
lookup hundreds, [%11000000,%11111001,%10100100,%10110000,%10011001, %10010010,%10000010,%11111000,%10000000,%10010000],segment
LOW LPIN
Shiftout DPIN, CPIN, MSBFIRST,[segment,%0100]
high lpin

pause 4

;---[extract thousands and show]------------------------------------------------
thousands = value/1000
place = %1000
lookup thousands, [%11000000,%11111001,%10100100,%10110000,%10011001, %10010010,%10000010,%11111000,%10000000,%10010000, %10001000],segment
LOW LPIN
Shiftout DPIN, CPIN, MSBFIRST,[segment,%1000]
high lpin

@ INT_RETURN

Art
- 18th February 2018, 14:23
It’s not bad except you don’t need 4 copies of the same lookup table. That should be a subroutine.
If possible, there should be four identical subroutines that you feed each digit to.

You’d normally do the display multiplex in the main program, and only use the interrupt to set a flag
that is being watched by the main program to know when a second, or whatever period ticks over.
The interrupt handler should be the smaller routine.

louislouis
- 18th February 2018, 19:29
It’s not bad except you don’t need 4 copies of the same lookup table. That should be a subroutine.
If possible, there should be four identical subroutines that you feed each digit to.

You’d normally do the display multiplex in the main program, and only use the interrupt to set a flag
that is being watched by the main program to know when a second, or whatever period ticks over.
The interrupt handler should be the smaller routine.

Hello Art,

something like this:



'************************************************* ***************
'* Name : 4 bit 7 segment display *
'* Author : LouisLouis *
'* Notice : Copyright (c) 2018 *
'* : All Rights Reserved *
'* Date : 18. 2. 2018 *
'* Version : 1.0 *
'* Notes : *
'* MCU : PIC 12F1840 *
'************************************************* ***************

#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
__config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
#ENDCONFIG

DEFINE OSC 32 ; Use internal clock
OSCCON = %01110000
CLKRCON = 0

Include "modedefs.bas"
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts

TRISA = %000000
ANSELA = %0000
OPTION_REG.7=0 ; Enable internal pull-ups

LPIN var porta.2 ; Latch
DPIN var porta.4 ; Data
CPIN var porta.5 ; Clock

segment var byte
value var word
place var byte[4]
ones var word
tens var word
hundreds var word
thousands var word

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _DISP, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts
T1CON = $1

;---[show HELO for 0,5sec.]-----------------------------------------------------
intro:
segment=12
gosub look
ones=segment
segment=11
gosub look
tens=segment
segment=10
gosub look
hundreds=segment
segment=13
gosub look
thousands=segment
pause 500

;---[simple counter 0 - to 9999]------------------------------------------------
Main:
for value = 0 to 9999
gosub setdisp
pause 10
next value
value = 0
GOTO Main

setdisp:
segment = value//10
gosub look
ones=segment ; extract ones

segment = value/10
segment = segment//10
gosub look
tens=segment ; extract tens

segment = value/100
segment = segment//10
gosub look
hundreds=segment ; extract hundreds

segment = value/1000
gosub look
thousands=segment ; extract thousands

;---[7 segment pattern 0123456789 and letters H E L O]--------------------------
look:
lookup segment, [%11000000,%11111001,%10100100,%10110000,%10011001, %10010010,%10000010,%11111000,%10000000,%10010000, %10000110,%11000111,%11000000,%10001001],segment
return
return

;---[TMR1 - interrupt handler]--------------------------------------------------
DISP:
T1CON.0 = 0 ; stop timer
TMR1H = %11111100
TMR1L = %00011111
T1CON.0 = 1 ; restart timer

;---[multiplex and show]--------------------------------------------------------
LOW LPIN
Shiftout DPIN, CPIN, MSBFIRST,[ones,%0001]
high lpin
pause 2
LOW LPIN
Shiftout DPIN, CPIN, MSBFIRST,[tens,%0010]
high lpin
pause 2
LOW LPIN
Shiftout DPIN, CPIN, MSBFIRST,[hundreds,%0100]
high lpin
pause 2
LOW LPIN
Shiftout DPIN, CPIN, MSBFIRST,[thousands,%1000]
high lpin
@ INT_RETURN


It is a bit slower, but now I can display digits and letters.
Otherwise, I don't think this is a more efficient and elegant code, it must be a better way.

mpgmike
- 18th February 2018, 22:18
At the bottom of look: you have RETURN listed twice.

You turn TMR1 Off (T1CON = 0) in your Disp: Interrupt Handler but I don't see where you turn it back on.

"segment = value/1000
gosub look
thousands=segment ; extract thousands"

Leads right into your look: Interrupt Handler. If that was to be a subroutine, you need that extra RETURN relocated to the end of that grouping.

louislouis
- 18th February 2018, 22:50
At the bottom of look: you have RETURN listed twice.

yes I forgot to delete one return, but it doesn't matter.


You turn TMR1 Off (T1CON = 0) in your Disp: Interrupt Handler but I don't see where you turn it back on.

Here: T1CON.0 = 1 ; restart timer


;---[TMR1 - interrupt handler]--------------------------------------------------
DISP:
T1CON.0 = 0 ; stop timer
TMR1H = %11111100
TMR1L = %00011111
T1CON.0 = 1 ; restart timer


Both codes which I posted works fine. I'm looking for more professional (easier, better, more skilled) example to do this.

Art
- 18th February 2018, 23:06
One of many ways to pull your counter value apart in BASIC is using DIG.
Copy the counter to another buffer so it stays safe.
This may be rough, and won't compile straight up.



destructobuffer = countervalue

FOR loopcounter = 0 TO 3
digitvalue = destructobuffer DIG 0
print digitvalue
shift out a digit
delay for digit (if you must)
destructobuffer = destructobuffer / 10
NEXT loopcounter

mpgmike
- 19th February 2018, 07:07
Here: T1CON.0 = 1 ; restart timer


TMR1H = %11111100
TMR1L = %00011111
T1CON.0 = 1 ; restart timer


Most of the data sheets say that when you write to the TMRxH/L, you must declare the entire TxCON SFR. I personally have made a practice of using T1CON = %xxxxxxxx instead of isolating a single bit in the TxCON register after preloading the TMRx register. I actually had a bug that I couldn't figure out for the longest time. When I wrote to the entire Timer Register instead of just a single 1/0 bit, it started working. If it works now, you could leave it as is. If you have issues, try what I suggested here.

tumbleweed
- 19th February 2018, 10:35
Most of the data sheets say that when you write to the TMRxH/L, you must declare the entire TxCON SFRCould you point to an example of that?

richard
- 19th February 2018, 11:00
Could you point to an example of that?
me too
I have never had to do that and can find no mention of that short coming anywhere


anyways here is my take on the 7 seg display
if you have a chip with mssp why waste time and code space when the hardware can do it for you

I cheated a bit and did it in asm for speed and size gains
no nasty pauses , all gone
my displays are common anode so the data is inverted see comments


'************************************************* ***************
'* Name : 4 bit 7 segment display *
'* Author : RICHARD *
'* Notice : *
'* : *
'* Date : 18. 2. 2018 *
'* Version : 1.0 *
'* Notes : *
'* MCU : PIC 16F1825 @32MHZ *
'************************************************* ***************
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_ON & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_OFF & _LVP_OFF
#ENDCONFIG

goto overasm
asm
timer1 = TMR1L

seg_val
addwf PCL, F
retlw 0xc0;0B11000000 0
retlw 0xf9;0B11111001 1
retlw 0xa4;0B10100100 2
retlw 0xb0;0B10110000 3
retlw 0x99;0B10011001 4
retlw 0x92;0B10010010 5
retlw 0x82;0B10000010 6
retlw 0xf8;0B11111000 7
retlw 0x80;0B10000000 8
retlw 0x90;0B10010000 9
endasm

overasm:
DEFINE OSC 32 ; Use internal clock
ANSELC=0
SSP1CON1=$22
SSP1STAT=$40
OSCCON=$f0

INCLUDE "DT_INTS-14.bas" ; Base Interrupt System

TRISC = %11101010
LPIN var portc.4 ; Latch
DPIN var portc.2 ; Data SDO
CPIN var portc.0 ; Clock SCK
segment var byte
value var word
d_index var byte
buff var byte[5]
tmp var byte
d_pointer var byte
timer1 var word ext
timer1_reload con 1543 ;8mS
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _DISP, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
@ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts
T1CON = $1
d_index=0
;---[simple counter 0 - to 9999]------------------------------------------------
Main:
for value = 0 to 9999
arraywrite buff ,[dec4 value]
pause 100
next value
value = 0
GOTO Main
;---[TMR1 - interrupt handler]--------------------------------------------------
DISP:
asm
MOVE?CT 0, T1CON, TMR1ON ; 1 stop timer
MOVLW LOW(_timer1_reload) ; 1 Add TimerReload to the
ADDWF TMR1L,F ; 1 value in Timer1
BTFSC STATUS,C ; 1/2
INCF TMR1H,F ; 1
MOVLW HIGH(_timer1_reload) ; 1
ADDWF TMR1H,F ; 1
MOVE?CT 1, T1CON, TMR1ON ; 1 start timer
MOVE?CB high _buff, FSR0H ;load highbyte
MOVE?CB low _buff, FSR0L ;load low byte
MOVE?BA _d_index
ADDWF FSR0L,F
MOVLW 0X30
SUBWF INDF0,W
L?CALL seg_val
MOVE?AB _segment
MOVE?BB _d_index ,_tmp
BANKSEL _tmp
MOVLW 1
ADDWF _tmp,F
BANKSEL _d_pointer
CLRF _d_pointer
BSF STATUS ,C
N_BIT
BANKSEL _d_pointer
RLF _d_pointer,F
BCF STATUS ,C
BANKSEL _tmp
DECFSZ _tmp,F
GOTO N_BIT
MOVLW 1
BANKSEL _d_index
ADDWF _d_index,F
MOVLW 3
ANDWF _d_index,F
BANKSEL LATC
BCF LATC ,4
BANKSEL PIR1
BCF PIR1,3
BANKSEL _segment
COMF _segment,W ;COMMENT USED TO INVERT DATA FOR COMMON ANODE DISPLAY
BANKSEL SSP1BUF
movwf SSP1BUF
BANKSEL PIR1
BTFSs PIR1,3
GOTO $-1
BANKSEL _d_pointer
COMF _d_pointer,W ; ;COMMENT USED FOR COMMON ANODE DISPLAY
BANKSEL PIR1
BCF PIR1,3
BANKSEL SSP1BUF
movwf SSP1BUF
BANKSEL PIR1
BTFSs PIR1,3
GOTO $-1
BANKSEL LATC
BSF LATC ,4
BANKSEL 0
INT_RETURN
endasm

mpgmike
- 19th February 2018, 16:48
OK, looked through a K50 and 16F1619 Data Sheet for that note or catch phrase indicating a full write to TxCON is recommended after writing to the TMRxH/L registers and cannot find it. It might be for an older processor, or maybe I read it on a forum somewhere and now it's that propagating myth. Sorry.

louislouis
- 19th February 2018, 19:52
anyways here is my take on the 7 seg display
if you have a chip with mssp why waste time and code space when the hardware can do it for you

I cheated a bit and did it in asm for speed and size gains
no nasty pauses , all gone
my displays are common anode so the data is inverted see comments

Hello Richard, thanks for response. Your code is probably for 4 digit 7 segment display where the segments is driven via 74HC595 shift register, and the common anodes via transistors directly from MCU or for multiplexing a bare display whitout driver right?

Look at mi first post, my display is driven by two 74HC595 shift register, one for segments, and the second for digits (like common anodes/cathodes).

To send data I used:


SHIFTOUT DPIN, CPIN, MSBFIRST,[ones,%0001] ;(segment pattern, digit position)


Now I tring to find more elegant way to extract ones, tens, hundreds and thousands like my previous solution:


setdisp:
segment = value//10
gosub look
ones=segment ; extract ones

segment = value/10
segment = segment//10
gosub look
tens=segment ; extract tens

segment = value/100
segment = segment//10
gosub look
hundreds=segment ; extract hundreds

segment = value/1000
gosub look
thousands=segment ; extract thousands


Can you help me with it?

richard
- 19th February 2018, 20:21
Your code is probably for 4 digit 7 segment display where the segments is driven via 74HC595 shift register, and the common anodes via transistors directly from MCU or for multiplexing a bare display whitout driver right

wrong , my code is for your circuit but using a different pic chip . I don't have a 12f1840 on hand but I cannot see any reason for it not to work on that chip . if you use the right pins.:)
your code is for common anode mine common cathode the commented lines can be changed to suit


COMF _segment,W for common Anode becomes MOVF _segment,W
COMF _d_pointer,W for common Anode becomes MOVF _d_pointer,W
ie the current is reversed in the display

richard
- 19th February 2018, 20:37
here is a 12f1822 version
with full hex [upper and lower case] space and - sign also
note comments for common anode/cathode



'************************************************* ***************
'* Name : 4 bit 7 segment display *
'* Author : RICHARD *
'* Notice : *
'* : *
'* Date : 18. 2. 2018 *
'* Version : 1.0 *
'* Notes : *
'* MCU : PIC 12F1822 @32MHZ *
'************************************************* ***************
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
__config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
#ENDCONFIG

goto overasm
ASM
timer1 = TMR1L
seg_val
CHK?RP _TM_TMP
MOVWF _TM_TMP
SUBLW 0x21
btfsc STATUS, C
retlw 0 ;" "
MOVF _TM_TMP,W
SUBLW 0x2f
btfsc STATUS, C
retlw 64 ;"-"
MOVF _TM_TMP,W
MOVLW 0X40
SUBWF _TM_TMP,W
btfsC STATUS, C
GOTO TM_ALPHA
MOVF _TM_TMP,W
ANDLW 0X0F
GOTO TM_LU
TM_ALPHA
ANDLW 0xdf ;ucase
SUBLW 6
btfsS STATUS, C
retlw 0 ;ERROR
MOVLW 0X37
SUBWF _TM_TMP,W
ANDLW 0xdf ;ucase
TM_LU
BRW
retlw 0X3F ;0
retlw 6
retlw 0X5B
retlw 0X4F
retlw 0X66
retlw 0X6D
retlw 0X7D
retlw 7
retlw 0X7F
retlw 0X67 ;9
retlw 0X77 ;A
retlw 0X7C ;b
retlw 0X39 ;C
retlw 0X5E ;d
retlw 0X79 ;E
retlw 0X71 ;F
endasm



overasm:

DEFINE OSC 32 ; Use internal clock
ANSELA=0
SSP1CON1=$22
SSP1STAT=$40
OSCCON=$70

INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
"
TRISA = %11111000
@LPORT=LATA
LPIN CON 2 ;var LATC.4 ; Latch
DPIN var porta.0 ; Data SDO
CPIN var porta.1 ; Clock SCK

segment var byte
value var word
d_index var byte
buff var byte[5]
tmp var byte
TM_TMP var byte
d_pointer var byte
timer1 var word ext
timer1_reload con 1543 ;8mS

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _DISP, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts
T1CON = $1
d_index=0
;---[simple counter 0 - to ffff]------------------------------------------------
Main:
for value = 0 to 65535
arraywrite buff ,[HEX4 value,0]

pause 100
next value
value = 0
GOTO Main

;---[TMR1 - interrupt handler]--------------------------------------------------
DISP:

asm
MOVE?CT 0, T1CON, TMR1ON ; 1 stop timer
MOVLW LOW(_timer1_reload) ; 1 Add TimerReload to the
ADDWF TMR1L,F ; 1 value in Timer1
BTFSC STATUS,C ; 1/2
INCF TMR1H,F ; 1
MOVLW HIGH(_timer1_reload) ; 1
ADDWF TMR1H,F ; 1
MOVE?CT 1, T1CON, TMR1ON ; 1 start timer
MOVE?CB high _buff, FSR0H ;load highbyte
MOVE?CB low _buff, FSR0L ;load low byte
MOVE?BA _d_index
ADDWF FSR0L,F
MOVF INDF0,W
L?CALL seg_val
MOVE?AB _segment
MOVE?BB _d_index ,_tmp
BANKSEL _tmp
MOVLW 1
ADDWF _tmp,F
BANKSEL _d_pointer
CLRF _d_pointer
BSF STATUS ,C
N_BIT
BANKSEL _d_pointer
RLF _d_pointer,F
BCF STATUS ,C
BANKSEL _tmp
DECFSZ _tmp,F
GOTO N_BIT
MOVLW 1
BANKSEL _d_index
ADDWF _d_index,F
MOVLW 3
ANDWF _d_index,F
BANKSEL LPORT
BCF LPORT ,_LPIN
BANKSEL PIR1
BCF PIR1,3
BANKSEL _segment
MOVF _segment,W
;COMF _segment,W ;COMMENT USED TO INVERT DATA FOR COMMON ANODE DISPLAY
BANKSEL SSP1BUF
movwf SSP1BUF
BANKSEL PIR1
BTFSs PIR1,3
GOTO $-1
BANKSEL _d_pointer
COMF _d_pointer,W
;MOVF _d_pointer,W ;COMMENT USED FOR COMMON ANODE DISPLAY
BANKSEL PIR1
BCF PIR1,3
BANKSEL SSP1BUF
movwf SSP1BUF
BANKSEL PIR1
BTFSs PIR1,3
GOTO $-1
BANKSEL LPORT
BSF LPORT ,_LPIN
BANKSEL 0
INT_RETURN
endasm

louislouis
- 19th February 2018, 22:41
here is a 12f1822 version
with full hex [upper and lower case] space and - sign also
note comments for common anode/cathode

Thanks Richard, that code works, but that is a way more difficult understand to me because ASM and so on.
A few things I've noticed when I tried the code:
- your code is a way shorter in MCU memory like mine, which is good
- multiplex is a bit slower I see some flickers
- if I put in to the "value" variable mumber "1234" the display shows "4321"
of course I changed this line
arraywrite buff ,[HEX4 value,0]
to
arraywrite buff ,[DEC4 value,0]

Anyway, it is a good example how the skilled programmer thinks, and how a beginner thinks.

richard
- 19th February 2018, 22:52
multiplex is a bit slower I see some flickers

the refresh rate is 8mS to speed it up to 4mS change timer1_reload to 33543



if I put in to the "value" variable mumber "1234" the display shows "4321" sic

the digit scan direction can be reversed easily and would result in even smaller code

the difference with this method is that the mcu can now do other tasks and not spend all its time being just a display controller

richard
- 19th February 2018, 23:02
digit order reversed,scan 4mS
and I moved the lookup out of the isr into the foreground (reduce isr overhead)






'************************************************* ***************
'* Name : 4 bit 7 segment display *
'* Author : RICHARD *
'* Notice : *
'* : *
'* Date : 18. 2. 2018 *
'* Version : 1.0 *
'* Notes : *
'* MCU : PIC 12F1822 @32MHZ *
'************************************************* ***************
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
__config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
#ENDCONFIG

goto overasm
ASM

seg_val
CHK?RP _TM_TMP
MOVWF _TM_TMP
SUBLW 0x21
btfsc STATUS, C
retlw 0 ;" "
MOVF _TM_TMP,W
SUBLW 0x2f
btfsc STATUS, C
retlw 64 ;"-"
MOVF _TM_TMP,W
MOVLW 0X40
SUBWF _TM_TMP,W
btfsC STATUS, C
GOTO TM_ALPHA
MOVF _TM_TMP,W
ANDLW 0X0F
GOTO TM_LU
TM_ALPHA
ANDLW 0xdf ;ucase
SUBLW 6
btfsS STATUS, C
retlw 0 ;ERROR
MOVLW 0X37
SUBWF _TM_TMP,W
ANDLW 0xdf ;ucase
TM_LU
BRW
retlw 0X3F ;0
retlw 6
retlw 0X5B
retlw 0X4F
retlw 0X66
retlw 0X6D
retlw 0X7D
retlw 7
retlw 0X7F
retlw 0X67 ;9
retlw 0X77 ;A
retlw 0X7C ;b
retlw 0X39 ;C
retlw 0X5E ;d
retlw 0X79 ;E
retlw 0X71 ;F
endasm



overasm:

DEFINE OSC 32 ; Use internal clock
ANSELA=0
SSP1CON1=$22
SSP1STAT=$40
OSCCON=$70

INCLUDE "DT_INTS-14.bas" ; Base Interrupt System

TRISA = %11111000
@LPORT=LATA
LPIN CON 2 ;var LATa.2 ; Latch
DPIN var porta.0 ; Data SDO
CPIN var porta.1 ; Clock SCK

segment var byte
value var word
d_index var byte
buff var byte[5]
seg_buff var byte[4]
seg_cnt var byte
seg_dat var byte
tmp var byte
TM_TMP var byte
d_pointer var byte

timer1_reload con 33543 ;4mS

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _DISP, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts
T1CON = $1
d_index=0
;---[simple counter 0 - to ffff]------------------------------------------------
Main:
for value = 0 to 65535
arraywrite buff ,[HEX4 value,0]
gosub load_seg
pause 100
next value
value = 0
GOTO Main

load_seg :
for seg_cnt=0 to 3
seg_dat= buff[seg_cnt]
asm
MOVE?BA _seg_dat
L?CALL seg_val
MOVE?AB _seg_dat
endasm
seg_buff[seg_cnt]= seg_dat
next
return




;---[TMR1 - interrupt handler]--------------------------------------------------
DISP:

asm
MOVE?CT 0, T1CON, TMR1ON ; 1 stop timer
MOVLW LOW(_timer1_reload) ; 1 Add TimerReload to the
ADDWF TMR1L,F ; 1 value in Timer1
BTFSC STATUS,C ; 1/2
INCF TMR1H,F ; 1
MOVLW HIGH(_timer1_reload) ; 1
ADDWF TMR1H,F ; 1
MOVE?CT 1, T1CON, TMR1ON ; 1 start timer
MOVE?CB high _seg_buff, FSR0H ;load highbyte
MOVE?CB low _seg_buff, FSR0L ;load low byte
MOVE?BA _d_index
ADDWF FSR0L,F
MOVF INDF0,W
;L?CALL seg_val
MOVE?AB _segment
MOVE?BB _d_index ,_tmp
BANKSEL _tmp
MOVLW 1
ADDWF _tmp,F
MOVLW 16
BANKSEL _d_pointer
movwf _d_pointer
BcF STATUS ,C
N_BIT
BANKSEL _d_pointer
RRF _d_pointer,F
BANKSEL _tmp
DECFSZ _tmp,F
GOTO N_BIT
MOVLW 1
BANKSEL _d_index
ADDWF _d_index,F
MOVLW 3
ANDWF _d_index,F
BANKSEL LPORT
BCF LPORT ,_LPIN
BANKSEL PIR1
BCF PIR1,3
BANKSEL _segment
MOVF _segment,W ;COMMENT USED TO INVERT DATA FOR COMMON cathode DISPLAY
;COMF _segment,W ;COMMENT USED TO INVERT DATA FOR COMMON ANODE DISPLAY
BANKSEL SSP1BUF
movwf SSP1BUF
BANKSEL PIR1
BTFSs PIR1,3
GOTO $-1
BANKSEL _d_pointer
COMF _d_pointer,W ;COMMENT USED FOR COMMON cathode DISPLAY
;MOVF _d_pointer,W ;COMMENT USED FOR COMMON ANODE DISPLAY
BANKSEL PIR1
BCF PIR1,3
BANKSEL SSP1BUF
movwf SSP1BUF
BANKSEL PIR1
BTFSs PIR1,3
GOTO $-1
BANKSEL LPORT
BSF LPORT ,_LPIN
BANKSEL 0
INT_RETURN
endasm

louislouis
- 19th February 2018, 23:25
the difference with this method is that the mcu can now do other tasks and not spend all its time being just a display controller

Yes that's great, now the MCU has a way more time to do other tasks which I write using my poor skills in picbasic.
Probably this piece of your code will be used in my future projects with that type of 7 segment displays.
Thanks.

richard
- 19th February 2018, 23:42
One further improvement is to ditch dt_ints

it adds unnecessary bloat for this app


'************************************************* ***************
'* Name : 4 bit 7 segment display *
'* Author : RICHARD *
'* Notice : *
'* : *
'* Date : 18. 2. 2018 *
'* Version : 1.0 *
'* Notes : *
'* MCU : PIC 12F1822 @32MHZ *
'************************************************* ***************
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON
__config _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_19 & _LVP_OFF
#ENDCONFIG

goto overasm
ASM

seg_val
CHK?RP _TM_TMP
MOVWF _TM_TMP
SUBLW 0x21
btfsc STATUS, C
retlw 0 ;" "
MOVF _TM_TMP,W
SUBLW 0x2f
btfsc STATUS, C
retlw 64 ;"-"
MOVF _TM_TMP,W
MOVLW 0X40
SUBWF _TM_TMP,W
btfsC STATUS, C
GOTO TM_ALPHA
MOVF _TM_TMP,W
ANDLW 0X0F
GOTO TM_LU
TM_ALPHA
ANDLW 0xdf ;ucase
SUBLW 6
btfsS STATUS, C
retlw 0 ;ERROR
MOVLW 0X37
SUBWF _TM_TMP,W
ANDLW 0xdf ;ucase
TM_LU
BRW
retlw 0X3F ;0
retlw 6
retlw 0X5B
retlw 0X4F
retlw 0X66
retlw 0X6D
retlw 0X7D
retlw 7
retlw 0X7F
retlw 0X67 ;9
retlw 0X77 ;A
retlw 0X7C ;b
retlw 0X39 ;C
retlw 0X5E ;d
retlw 0X79 ;E
retlw 0X71 ;F
endasm



overasm:

DEFINE OSC 32 ; Use internal clock
ANSELA=0
SSP1CON1=$22
SSP1STAT=$40
OSCCON=$70
DEFINE INTHAND _DISP


TRISA = %11111000
@LPORT=LATA
LPIN CON 2 ;var LATa.2 ; Latch
DPIN var porta.0 ; Data SDO
CPIN var porta.1 ; Clock SCK

segment var byte
value var word
d_index var byte
buff var byte[5]
seg_buff var byte[4]
seg_cnt var byte
seg_dat var byte
tmp var byte
TM_TMP var byte
d_pointer var byte

timer1_reload con 33543 ;4mS


PIR1.0=0
INTCON=$C0
PIE1.0=1


T1CON = $1
d_index=0
;---[simple counter 0 - to ffff]------------------------------------------------
Main:
for value = 0 to 65535
arraywrite buff ,[HEX4 value,0]
gosub load_seg
pause 100
next value
value = 0
GOTO Main

load_seg :
for seg_cnt=0 to 3
seg_dat= buff[seg_cnt]
asm
MOVE?BA _seg_dat
L?CALL seg_val
MOVE?AB _seg_dat
endasm
seg_buff[seg_cnt]= seg_dat
next
return




;---[TMR1 - interrupt handler]--------------------------------------------------
DISP:

asm
MOVE?CT 0, T1CON, TMR1ON ; 1 stop timer
MOVLW LOW(_timer1_reload) ; 1 Add TimerReload to the
ADDWF TMR1L,F ; 1 value in Timer1
BTFSC STATUS,C ; 1/2
INCF TMR1H,F ; 1
MOVLW HIGH(_timer1_reload) ; 1
ADDWF TMR1H,F ; 1
MOVE?CT 1, T1CON, TMR1ON ; 1 start timer
MOVE?CB high _seg_buff, FSR0H ;load highbyte
MOVE?CB low _seg_buff, FSR0L ;load low byte
MOVE?BA _d_index
ADDWF FSR0L,F
MOVF INDF0,W
;L?CALL seg_val
MOVE?AB _segment
MOVE?BB _d_index ,_tmp
BANKSEL _tmp
INCF _tmp,F
MOVLW 16
BANKSEL _d_pointer
movwf _d_pointer
BcF STATUS ,C
N_BIT
BANKSEL _d_pointer
RRF _d_pointer,F
BANKSEL _tmp
DECFSZ _tmp,F
GOTO N_BIT
BANKSEL _d_index
INCF _d_index,F
MOVLW 3
ANDWF _d_index,F
BANKSEL LPORT
BCF LPORT ,_LPIN
BANKSEL PIR1
BCF PIR1,3
BANKSEL _segment
MOVF _segment,W ;COMMENT USED TO INVERT DATA FOR COMMON cathode DISPLAY
;COMF _segment,W ;COMMENT USED TO INVERT DATA FOR COMMON ANODE DISPLAY
BANKSEL SSP1BUF
movwf SSP1BUF
BANKSEL PIR1
BTFSs PIR1,3
GOTO $-1
BANKSEL _d_pointer
COMF _d_pointer,W ;COMMENT USED FOR COMMON cathode DISPLAY
;MOVF _d_pointer,W ;COMMENT USED FOR COMMON ANODE DISPLAY
BANKSEL PIR1
BCF PIR1,3
BANKSEL SSP1BUF
movwf SSP1BUF
BANKSEL PIR1
BTFSs PIR1,3
GOTO $-1
BANKSEL LPORT
BSF LPORT ,_LPIN
BANKSEL PIR1
BCF PIR1 ,0
RETFIE
endasm

richard
- 20th February 2018, 01:19
Final version after a bit of a clean up

lester
- 20th February 2018, 11:06
Published in the WiKI

http://www.picbasic.co.uk/forum/content.php?r=553-4-bit-7-segment-display-with-two-74HC595 (http://www.picbasic.co.uk/forum/content.php?r=553-4-bit-7-segment-display-with-two-74HC595)

richard
- 20th February 2018, 23:17
Published in the WiKI
lester
the two small code windows are blank in the wiki article , i'm sure that was not the intention

might also add that a decimal point can be lit in the appropriate display using

Main:
for value = 0 to 65535
arraywrite buff ,[HEX4 value]
gosub load_seg
seg_buff[2]=seg_buff[2]|128 ; place a dp in digit 2
pause 100
next value
value = 0
GOTO Main

lester
- 21st February 2018, 05:08
Thank you Richard, the editor went a little funky and added some crazy formatting, causing the blank code boxes. Its fixed now.

Thank you for your generous contribution.

louislouis
- 21st February 2018, 09:15
Thank you Richard, the editor went a little funky and added some crazy formatting, causing the blank code boxes. Its fixed now.

Thank you for your generous contribution.

there are still something wrong, because missing "%" character in the codes published on wiki

Orig. code:
TRISA = %111000

Code on wiki:
TRISA = 111000

lester
- 21st February 2018, 15:41
OK thanks for that

I think the % is displayed correctly now.