Need to drive 40 pins on variable change, is there a way to do it in elegant way?

# Thread: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

1. ## Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Hello.

I'm building a nixie clock, which does not uses any specific decoder ICs or multiplexer. Instead, all nixie digits are connected to individual MCU pins via transistors. It uses DS1302 as clock source. Time received from DS1302 is converted into single number in 24 hour format, for example, it time is 15:53, this number will read as 1553. Using DIG statement I'm extracting individual digits from it, so I have 4 variables, called T1-T4, which have data for individual number to be displayed on specific digit. The pin numbers to which nixies are connected are aliases in the following way - A0-A9 for numbers in 1st digit, B0-B9 for numbers in 2nd digit, C0-C9 and D0-D9 for 3rd and 4th digits correspondingly. So now, to display time, I need to run the following code:

IF T1=0 THEN A0=1
IF T1=1 THEN A1=1
IF T1=2 THEN A2=1
IF T1=3 THEN A3=1
IF T1=4 THEN A4=1

and so on, total, 40 lines (not shown is code for extinguishing all non-used numbers, but I'm doing it at same time for all digits)

So question is, is there a way to avoid all these if-then lines and do it somehow in more elegant way?

2. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Arrays?

Code:
```A_Vals var word(4) 'A0-A9, B0-B9, C0-C9, D0-D9 in each element;
T_Vals var byte(4) 'T1-T4
i var byte
Tx var byte
Xx var word

Begin:

for i = 0 to 3      ' Clear array.
A_Vals(i) = 0
T_Vals(i) = 0
next i

Start:

for i = 0 to 3  ' Scan 0-3 => T1-T4
Tx = T_Vals(i)   ' Get the value of Tx variable.
Xx = A_Vals(i)   ' Get the value of Ax value.
Xx[Tx]= 1        ' Change Ax value based on Tx value.
A_Vals(i)=Xx     ' Get the value back.
next i

goto start

END```

' A0 => A_Vals(0) bit.0-bit.9
' A4 => A_Vals(3) bit.0-bit.9
'.....

' you have to read them back from A_Vals, and assign your corresponding pins on its bits 0-9.
' For example,
' xx = A_Vals(0)
' A0 = ax.0(0)
' A9 = ax.0(8)
'...
' xx = A_Vals(3)
' B0 = ax.0(0)
' B9 = ax.0(8)

3. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

How about a lookup table, 5 bytes (40 bits) wide and 10 deep (0-9).

4. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Yes, table would be nice, but how to do with less iF-THEN ?

5. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Here is a routine I wrote for my 6 digit nixie clock using 2 each HV5530P high voltage shift registers. That's 64 bits.
I use a 16F1825 14 pin processor running @ 10 Mhz. I don't like to use all of that hardware....

HVCLK VAR LATC.0 '0-SHIFT REGISTER CLOCK
HVSTB VAR LATC.1 '0-SHIFT REGISTER STROBE
HVDAT VAR LATC.2 '0-SHIFT REGISTER DATA
' ************************************************** ******************
CLOCKIT: 'ENCODE OUTPUT SEQUENCE AND SEND TO SHIFT REGISTER W/COLLONS
' ************************************************** ******************
'------------------------ 64 BIT ENCODE SEQUENCE ------------------------
'9876543210,9876543210,cc,9876543210,9876543210,cc ,9876543210,9876543210
'10's HOURs,1's HOURs ,::,10's MIN's,1's MIN's ,::,10'S SEC's,1'S SEC's
'------------------------------------------------------------------------
JUNK = 7 'FIRST CLEAR THE OUTPUT ARRAY
WHILE JUNK < 255
OUTPUTS(JUNK) = 0
JUNK = JUNK - 1
WEND
JUNK = 0 'NEXT SET THE OUTPUT ARRAY
WHILE JUNK < 6 'CYCLE THRU ALL 6 DIGITS TO DISPLAY
PATDOG = 1 'FEED THE DOG
SELECT CASE JUNK
CASE 0 'UNIT SECONDS 'BIT POSITION
OUTPUTS.0((JUNK * 10) + (SECONDS DIG 0)) = 1 '0-9

CASE 1 'TEN'S OF SECONDS
OUTPUTS.0((JUNK * 10) + (SECONDS DIG 1)) = 1 '10-19
OUTPUTS.0((JUNK * 10) + 10) = MINSECCOL '20
OUTPUTS.0((JUNK * 10) + 11) = MINSECCOL '21

CASE 2 'UNIT MINUTES
OUTPUTS.0((JUNK * 10) + 2 + (MINUTES DIG 0)) = 1 '22-31

CASE 3 'TEN'S OF MINUTES
OUTPUTS.0((JUNK * 10) + 2 + (MINUTES DIG 1)) = 1 '32-41
OUTPUTS.0((JUNK * 10) + 12) = HOURMINCOL '42
OUTPUTS.0((JUNK * 10) + 13) = HOURMINCOL '43

CASE 4 'UNIT HOURS
OUTPUTS.0((JUNK * 10) + 4 + (HOURS DIG 0)) = 1 '44-53

CASE 5 'TEN'S OF HOURS
'DISPLAY 10'S OF HOURS IF THERE IS SOMETHING TO DISPLAY
IF HOURS DIG 1 <> 0 THEN 'IF THERE IS A DIGIT TO DISPLAY
OUTPUTS.0((JUNK * 10) + 4 + (HOURS DIG 1)) = 1 '54-63
ENDIF

END SELECT
JUNK = JUNK + 1
WEND
SHIFTOUT HVDAT,HVCLK,MSBFIRST,[OUTPUTS(7)\8,OUTPUTS(6)\8,OUTPUTS(5)\8,OUTPUTS(4)\ 8,OUTPUTS(3)\8,OUTPUTS(2)\8,OUTPUTS(1)\8,OUTPUTS(0 )\8]
PULSOUT HVSTB,PULSE
RETURN

6. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

I typically use DATA statements (simple with internal EEPROM) to map each 7 segment character in a byte value. 'A' segment is least significant digit, 'G' segment is bit 6. Bit 7 is unused. For example, the number 8 is %01111111 (all segments on), 1 is %00000011, etc. I then read the bit value and write it to a port or series of pins. If you store the digits in the corresponding memory location, you may simply READ [DIGIT VALUE + 1] to retrieve the segment code.

7. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Single Nixie tube need 10 pin from micro. It's not 7 segment display. And only 1 pin need to te activated at time.
So most of suggestion wont work.
Unfortunately you need 40 statements to set pins. eg
IF T1=0 THEN
A0=1
ELSE
A0=0
ENDIF
By time you write first post you could write 40 IF statements without any problem.
That way you probably get smallest program size.

8. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

If your ports and pins are consecutively mapped ie
Code:
```MAP
PORTC   PORTD   PORTE   PORTF   PORTG
0127456701234567012345670123456701234567
DIG0     DIG1      DIG0    DIG3```
just clear ports the set like this

;DIGO
PORTC.0[BIN VALUE OF DIGO]=1
;DIG1
PORTC.0[BIN VALUE OF DIG1+10]=1
;DIG2
PORTC.0[BIN VALUE OF DIG2+20]=1
;DIG3
PORTC.0[BIN VALUE OF DIG3+30]=1
Last edited by richard; - 16th January 2019 at 00:53. Reason: white space

9. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

I already wrote code with if-then-else, and it works fine, just wanted to make it more nice and tidy.

regarding port mapping, ports are 8 bit wide, but nixies are 10 bit, so that way won't work also....

10. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

regarding port mapping, ports are 8 bit wide, but nixies are 10 bit, so that way won't work also....
look again

11. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

If you are building a clock, the minutes digits never exceed 60 - you require 10 digits for the "ones" (0 - 9), but only 6 for the "tens" (0 - 5). So, it will be possible to map every possible minute on two ports or, in one word value. By writing in DATA statements the "ON" pattern for each possible minute, the DATA statements become a lookup table. For example at XX:34, the 70th DATA position (2 positions for each WORD value and allowing for "Zero" and 1 base offset ) contains the bit code (across two bytes) to turn on the 3 and the 4 on the relevant PORTs. Write the high byte to PORTB, the low to PORTA (or whatever). Of course some minutes - say 59 will be fully contained in the upper byte: 10000010_00000000 -because the two low order bits of the high byte are conscripted for the 9 and 0.

The Hours portion may be handled similarly. As before, you will use ten pins for the "ones" in the hours, but only - at most - three in the "tens" digit (0 - 1 - 2) . Place these values subsequent to the previous.

To retrieve the "minutes" value READ CURRENTMINUTE * 2 + 2, MIN_VAR. For hours, READ 122 + (CURRENTHOUR * 2), HOUR_VAR. The offset values are figures in my head and may require adjustment.

This method requires only two word variables - one for the minute value, one for the hour value and 144 - 168 EEPROM bytes. In truth, the values are easily calculated and it may be you determine only to calculate the bit value rather than store it.

12. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

amoque's suggestion makes good sense
my map would become [note can be any 4 consecutive ports][can start at any bit too]

;DIGO
PORTC.0[BIN VALUE OF DIGO]=1
;DIG1
PORTC.0[BIN VALUE OF DIG1+10]=1
;DIG2
PORTC.0[BIN VALUE OF DIG2+17]=1
;DIG3
PORTC.0[BIN VALUE OF DIG3+27]=1
Last edited by richard; - 16th January 2019 at 22:00.

13. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

If DIG0 is "ones" digit of minutes, and DIG1 is "tens" digit, then:

READ [MINUTEVALUE + 1], WORD WordVar
PORTC = WordVar.lowbyte
PORTD = WordVar.HighByte

In fact, you could then:

READ [HOURVALUE + 1], WORD Wordvar
PORTE = WordVar.lowbyte
PORTF = WordVar.HighByte

This would overwrite F.6..7, but if you aren't using them...
.
.
.

' BIT CODE OF "00", BIT CODE OF "01", BIT CODE OF "02"...
DATA %00000100_00000001, %00000100_00000010, %00000100_00000100,

Will set PORTC.0 and PORTD.2 HIGH (presumably turning on the "0" digit in both positions. It may be your transistors are active low and would therefore require the inverse bit values (%11111011_11111110). WARNING: I did NOT look up the specific syntax of the READ and DATA statements, you should verify these.
Last edited by Amoque; - 16th January 2019 at 23:34.

14. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

IF you do it my way, assuming HOUR,MINUTE are bcd byte values read from a rtc

Code:
```GOSUB SETDISPLAY
LATC=0
LATD=0
LATE=0
LATF=0
LATC.0[MINUTE&\$0F]=1
LATC.0[(MINUTE>>4)+10]=1
LATC.0[HOUR&\$0F)+17]=1
LATC.0[(HOUR>>4)+27]=1
RETURN```
thats it job done

15. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

It seems that nobody paid attention to my routine.

16. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

It seems that nobody paid attention to my routine.
i looked but failed to :-
1 understand how to feed the time from say two bcd encoded bytes into it
2 how it maps the resultant data onto the pins

perhaps you could explain more fully and develop the process a bit further

naming the var more meaningfully helps , i know when i'm deep in a pgm at the time its easy to see the big picture and keep track
but when i come back at a later time i wonder what was i doing here and why, i often wish i named things better with more comments

17. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Actually, for the number of digits:

Tens of hours n: 0 1 2 - 3 pins
Ones of hours: 0 1 2 3 4 5 6 7 8 9 - 10 pins
Tens of minutes: 0 1 2 3 4 5 - 6 pins
Ones of minutes: 0 1 2 3 4 5 6 7 8 9 - 10 pins
Single pin is needed for blinking middle dot.

So we have 3+10+6+10+1=30 pins. But I can't map them sequentially, due to pcb and other assembly restrictions. Currently say "4" in tens of minutes is PORTB.2, but "5" is PORTC.4 and so on

18. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Code:
```' These epins are just example pins.
' Pin number can be in any order; does not have to be in a sequence.
A0 var PORTA.0
A1 var PORTB.0
A2 var PORTC.0
A3 var PORTD.0
A4 var PORTE.0
A5 var PORTF.0
A6 var PORTA.0
A7 var PORTA.0
A8 var PORTA.0
A9 var PORTA.0

B0 var PORTA.0
B1 var PORTD.0
B2 var PORTC.0
B3 var PORTE.0
B4 var PORTG.0
B5 var PORTB.0
B6 var PORTB.0
B7 var PORTB.0
B8 var PORTB.0
B9 var PORTB.0

C0 var PORTB.0
C1 var PORTF.0
C2 var PORTD.0
C3 var PORTE.0
C4 var PORTC.0
C5 var PORTC.0
C6 var PORTC.0
C7 var PORTC.0
C8 var PORTC.0
C9 var PORTC.0

D0 var PORTE.0
D1 var PORTF.0
D2 var PORTH.0
D3 var PORTA.0
D4 var PORTB.0
D5 var PORTC.0
D6 var PORTD.0
D7 var PORTD.0
D8 var PORTD.0
D9 var PORTD.0

A_Vals var word(4) 'A0-A9, B0-B9, C0-C9, D0-D9 in each element;
T_Vals var byte(4) 'T1-T4
i var byte
Tx var byte
Xx var word

'===== These are your T Vals ========
'=== Use them in your code, and assign the values to them.
T1 var T_Vals(0)
T2 var T_Vals(1)
T3 var T_Vals(2)
T4 var T_Vals(3)

AVal var A_Vals(0)
BVal var A_Vals(1)
CVal var A_Vals(2)
DVal var A_Vals(3)

Begin:

for i = 0 to 3      ' Clear array.
A_Vals(i) = 0
T_Vals(i) = 0
next i

Start:

gosub GetPinValues

for i = 0 to 3  ' Scan 0-3 => T1-T4
Tx = T_Vals(i)   ' Get the value of Tx variable which can be 0...9
Xx = A_Vals(i)   ' Get the value of Ax value. We use bits from 0 to 9 inside Xx word.
Xx.0[Tx]= 1      ' Change Ax value based on Tx value. If TX = 0 then Xx.0[0] = 1, if Tx=9 then Xx.0[9] = 1 ... etc.
' Now here, something may be missing?!! Where do you make the pin = 0 after it gets to be = 1 ??

A_Vals(i)=Xx     ' Get the assigned bits to be masked on A_vals. Now your bit arrangement is in A_Vals(i).
next i

'Here, you now have all your corresponding bit values assigned into A_Vals(0-3).
gosub AssignPins

goto start

GetPinValues:
T1 = 1
T2 = 2
T3 = 3
T4 = 4

' or use  T_Vals() array....

Return

AssignPins:

A0 = AVal.0
A1 = AVal.1
A2 = AVal.2
A3 = AVal.3
A4 = AVal.4
A5 = AVal.5
A6 = AVal.6
A7 = AVal.7
A8 = AVal.8
A9 = AVal.9

B0 = bVal.0
B1 = bVal.1
B2 = bVal.2
B3 = bVal.3
B4 = bVal.4
B5 = bVal.5
B6 = bVal.6
B7 = bVal.7
B8 = bVal.8
B9 = bVal.9

C0 = cVal.0
C1 = cVal.1
C2 = cVal.2
C3 = cVal.3
C4 = cVal.4
C5 = cVal.5
C6 = cVal.6
C7 = cVal.7
C8 = cVal.8
C9 = cVal.9

D0 = DVal.0
D1 = DVal.1
D2 = DVal.2
D3 = DVal.3
D4 = DVal.4
D5 = DVal.5
D6 = DVal.6
D7 = DVal.7
D8 = DVal.8
D9 = DVal.9

return

END```

Use pins in any order;
Assign your T values before getting into scan routine.

Much cleaner, shorter, smaller and easier.

19. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Thanks, looks really promising, will give it try this weekend....

20. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Originally Posted by sayzer
Code:
```A6 var PORTA.0
A7 var PORTA.0
A8 var PORTA.0
A9 var PORTA.0```
Is this correct? same assignment port bit?

Ioannis

21. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Originally Posted by Ioannis
Is this correct? same assignment port bit?

Ioannis
It is just an example; I just wanted to show how the idea works.

22. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Originally Posted by sayzer
It seems that nobody paid attention to my routine.
I looked at it and, frankly, suggest that:

Code you write (and understand) is far more maintainable, and therefore "better" than code someone else writes that cannot be modified later. The difficulty in this specific case is that there are few options to IF THEN. You may look at SELECT CASE, but it will be only marginally different. Initially, I dismissed the topic because - it worked! It was only when I read Richard's comment "Look again" that I did so - and realized the inefficiency of reading, calculating, and setting each bit and digit individually that I thought about what I saw.

I maintain that code you understand is paramount. I made a suggestion for change because you can save a significant number of pins by dealing with HOURS and MINUTES as individual units (as I described) and, so long as you have EEPROM, you are perhaps able to save significant resources. It is also a possibility that the EEPROM map can be modified to enhance certain features. For example - you may, perhaps, define two sets of hour maps - on with the decimal lit and one without, then load alternates based on odd/ even seconds - thus, a "flashing" second indicator. When using matrix LEDs I find it handy to be able to redesign characters (via the map) without changing the code.

It will depend on your aim in this project. If you want only a Nixie Clock and have no intention of evolving your ability (in regard) and learning from it in the future, then any solution that "works" is good enough. You need not understand it or be comfortable modifying it. However, depending on future goals, starting with code you understand, having a flexible design, and continuing to revisit with a growing understanding become greater priorities.

As always, DIY is about solving your own priorities - and enjoying the satisfaction of doing it.

Amoque

23. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

The reason why I'm using separate pins for each digit can be seen in this short video:
And as you can guess, there are no PIC16 chips with 40 available IO ports at all

I've finished first revision of PCB, and DS1302 now is mapped on PORTA.5-7 ports now. And it does not works. While segments can be turn on/off without issues on PORTA, clock chip gives no response. The MCU used is PIC16F1519 and config looks like this:

Code:
```OSCCON = %01111010  'SET INTOSC TO 16MHZ
ANSELC=%00000000
ANSELB=%00000000
ANSELA=%00000000
ANSELE=%00000000

TRISC=%00000000 'set PORTS as output all
TRISD=%00000000
TRISB=%00000000
TRISA=%00111000 '3 ports are inputs, but changing them to outputs also does nothing
TRISE=%00000000

DEFINE OSC 16   'OSC SPEED```
I'm missing something?

24. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Originally Posted by CuriousOne
....

Code:
```OSCCON = %01111010  'SET INTOSC TO 16MHZ
ANSELC=%00000000
ANSELB=%00000000
ANSELA=%00000000
ANSELE=%00000000

TRISC=%00000000 'set PORTS as output all
TRISD=%00000000
TRISB=%00000000
TRISA=%00111000 '3 ports are inputs, but changing them to outputs also does nothing
TRISE=%00000000

DEFINE OSC 16   'OSC SPEED```
I'm missing something?

Attachment 8862
Where is the config?
In addition to OSCCON for intosc setting, Config fuse also needs to be configured for internal OSC.

25. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Well chip works fine, and I can light up any digits via any pins in software.

here is config used in above code

Code:
```;----[16F1519 Hardware Configuration]-------------------------------------------
#IF __PROCESSOR__ = "16F1519"
#DEFINE MCU_FOUND 1
#CONFIG
cfg1 = _FOSC_INTOSC           ; INTOSC oscillator: I/O function on CLKIN pin
cfg1&= _WDTE_OFF              ; WDT disabled
cfg1&= _PWRTE_OFF             ; PWRT disabled
cfg1&= _MCLRE_ON              ; MCLR/VPP pin function is MCLR
cfg1&= _CP_OFF                ; Program memory code protection is disabled
cfg1&= _BOREN_OFF             ; Brown-out Reset disabled
cfg1&= _CLKOUTEN_OFF          ; CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
cfg1&= _IESO_OFF              ; Internal/External Switchover mode is disabled
cfg1&= _FCMEN_OFF             ; Fail-Safe Clock Monitor is disabled
__CONFIG _CONFIG1, cfg1

cfg2 = _WRT_OFF               ; Write protection off
cfg2&= _VCAPEN_OFF            ; VCAP pin function disabled
cfg2&= _STVREN_ON             ; Stack Overflow or Underflow will cause a Reset
cfg2&= _BORV_LO               ; Brown-out Reset Voltage (Vbor), low trip point selected.
cfg2&= _LPBOR_OFF             ; Low-Power BOR is disabled
cfg2&= _LVP_OFF               ; High-voltage on MCLR/VPP must be used for programming
__CONFIG _CONFIG2, cfg2

#ENDCONFIG

#ENDIF

;----[Verify Configs have been specified for Selected Processor]----------------
;       Note: Only include this routine once, after all #CONFIG blocks
#IFNDEF MCU_FOUND
#ERROR "No CONFIGs found for [" + __PROCESSOR__ +"]"
#ENDIF```

26. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

CuriousOne
Sorry to go off topic, but how did you menage to create that turn on?
It look amazing...

27. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

If you can " light up any digits via any pins in software", it is unlikely to be the configuration. More likely in my mind the I2C routines to retrieve clock data. Can you get Hour and Minute values to display on LCD or via the serial comms provided in PB? If you don't have any of the cheap TTL to Serial modules available on Ebay or Amazon for a few bucks, they are (with a serial cable) a worthwhile investment. A 4x20 LCD can also be very helpful in providing some troubleshooting output, if you haven't anything else.

Presuming you have serial, this should (configure the serial com screen (in PB) to match):

'-----DEBUG (SERIAL) SETUP----------------------------------------
DEFINE DEBUG_REG PORTB
DEFINE DEBUG_BIT 5
DEFINE DEBUG_BAUD 2400
DEFINE DEBUG_MODE 0

Should get you some output and a way to demonstrate you are getting output from the clock. You can read up on all the formatting codes, but start with "TEST", 13, then start adding variables when you're sure you've got it going.

Once you know you can output to serial... Here are some routines I use with the DS series clocks. I use the DS1337 - its supposed to be high accuracy, but I just found them in battery backed-up modules for cheap and... no fiddling with crystals, or wires.

Code:
```'-----I2C SET-UP-------------------------------------------------
SDA  VAR PORTB.1
SCL  VAR PORTB.4

'-----CLOCK SET-UP------------------------------------------------
REG_TIM CON \$00
REG_AL1 CON \$07		' Not implemented
REG_AL2 CON \$0B		' Not implemented
REG_SPC CON\$0E
REG_STS CON \$0F

'-----TIME/ CLOCK VARIABLES----------------------------------------
REG_VAL VAR Byte[7]  	' Seconds, minutes, hours, day of week, date, month, year

'-----SET INITIAL TIME-----------------------------------------------
'FOR FUNCTION TEST, JUST SET EACH REGISTER TO ITS POSITION - LP[0] = 0 SECONDS, LP[1] = 1 MINUTE, LP[2] = 2 HOUR...

FOR LP = 0 TO 6        ' For each register
REG_VAL[LP] = LP     ' Set value to address
NEXT LP                ' Loop
GOSUB CLK_WRITE

'+++++MAIN LOOP+++++++++++++++++++++++++++++++++++++++++++++++++++
MAIN:
PAUSE 500                          ' Pause
GOTO MAIN

END

'-----READ TIME, CONVERT FROM BCD TO DECIMAL, DISPLAY--------------------------------------------------------------------
I2CRead SDA, SCL, RTC_ADD, REG_TIM, [REG_VAL[0], REG_VAL[1], REG_VAL[2], REG_VAL[3], REG_VAL[4], REG_VAL[5], REG_VAL[6]]
FOR LP = 0 TO 6			        ' For each register
D0 = (REG_VAL[LP] >> 4) * 10	' Decode 10's digit
D1 = REG_VAL[LP] & %0001111	' Blank 10's, get 1's
REG_VAL[LP] = D0 + D1 	        ' Write Decimal value to register
NEXT LP				                ' Next register

DEBUG "TIME:[", dec1 REG_VAL[3], "]  ", dec2 REG_VAL[5], "/", dec2 REG_VAL[4], "/", dec2 REG_VAL[6], "  ", dec2 REG_VAL[2], ":", dec2 REG_VAL[1], ":",  DEC2 REG_VAL[0], 13
RETURN

CLK_WRITE:
'-----CONVERT TO BCD VALUES, WRITE TO CLOCK REGISTERS ----------------------------------------------------------------------
FOR LP = 0 TO 6			        ' For each register
D0 = REG_VAL[LP] / 10		        ' Get decimal 10's digit
D1 = REG_VAL[LP] // 10 		' Get decimal 1's
REG_VAL[LP] = (D0 << 4) + D1	' Shift BCD 10's in, add 1's
NEXT LP				                ' Next register

I2CWrite SDA, SCL, RTC_ADD, REG_TIM, [REG_VAL[0], REG_VAL[1], REG_VAL[2], REG_VAL[3], REG_VAL[4], REG_VAL[5], REG_VAL[6]]
RETURN```
I don't know how much help this is, you didn't really give enough info to go beyond what you say already works, but if you I2C routines look different, then maybe your issue is there. If you're looking for some way to troubleshoot, then maybe the LCD or serial stuff will get you started... just not sure how to help.
Last edited by Amoque; - 28th January 2019 at 00:49.

28. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

The animated turn on/off is created via a hardware trick, which we were using in times, when SN74141 was not widely available (~30 years ago). It requires 2 transistors per each digit, so this clock uses 60 pcs of MPSA42 transistors just to do this I'm planning to put this clock on instructables, so all details, including schematics and PCB will be available there.

For the code (I'm using one from PBP examples). Initially, I had test setup assembled on breadboard. DS1302 module was connected to PORTC.1-2-3 and worked fine. I had MAX7219 connected and code worked as it should. However, when moving to PCB, to ease process of PCB design, I had to move DS1302 to PORTA. So now it does not works. The reason might be that I've messed up with wiring, but I wanted to be sure to ask, whenever there might be some specific additional configs needed for PORTA.

29. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Do you have pull up resistors on I2C lines?
Also post code for reading RTC, so we can help. This way is hard to guess what is wrong.
All address for used for I2C should be byte or word, for proper function off i2CREAD/WRITE.
I2C command uses variables size to send proper no of bits for addresses(8 or 16 bits).
Last edited by pedja089; - 28th January 2019 at 07:33.

30. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Here is complete code, but a lot of "water" in it

Code:
```;----[16F1519 Hardware Configuration]-------------------------------------------
#IF __PROCESSOR__ = "16F1519"
#DEFINE MCU_FOUND 1
#CONFIG
cfg1 = _FOSC_INTOSC           ; INTOSC oscillator: I/O function on CLKIN pin
cfg1&= _WDTE_OFF              ; WDT disabled
cfg1&= _PWRTE_OFF             ; PWRT disabled
cfg1&= _MCLRE_ON              ; MCLR/VPP pin function is MCLR
cfg1&= _CP_OFF                ; Program memory code protection is disabled
cfg1&= _BOREN_OFF             ; Brown-out Reset disabled
cfg1&= _CLKOUTEN_OFF          ; CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
cfg1&= _IESO_OFF              ; Internal/External Switchover mode is disabled
cfg1&= _FCMEN_OFF             ; Fail-Safe Clock Monitor is disabled
__CONFIG _CONFIG1, cfg1

cfg2 = _WRT_OFF               ; Write protection off
cfg2&= _VCAPEN_OFF            ; VCAP pin function disabled
cfg2&= _STVREN_ON             ; Stack Overflow or Underflow will cause a Reset
cfg2&= _BORV_LO               ; Brown-out Reset Voltage (Vbor), low trip point selected.
cfg2&= _LPBOR_OFF             ; Low-Power BOR is disabled
cfg2&= _LVP_OFF               ; High-voltage on MCLR/VPP must be used for programming
__CONFIG _CONFIG2, cfg2

#ENDCONFIG

#ENDIF

;----[Verify Configs have been specified for Selected Processor]----------------
;       Note: Only include this routine once, after all #CONFIG blocks
#IFNDEF MCU_FOUND
#ERROR "No CONFIGs found for [" + __PROCESSOR__ +"]"
#ENDIF

'nixie led clock electronics direct drive

include "modedefs.bas"
OSCCON = %01111010  'SET INTOSC TO 16MHZ
ANSELC=%00000000
ANSELB=%00000000
ANSELA=%00000000
ANSELE=%00000000

TRISC=%00000000 'set PORTC as output all
TRISD=%00000000 'set PORTD as output all
TRISB=%00000000 'set PORTD as output all
TRISA=%00111000
TRISE=%00000000

DEFINE OSC 16   'OSC SPEED

X VAR WORD ' TEMP VARIABLE
X=200

'TENS HOURS PINS

A0 VAR PORTD.7
A1 VAR PORTD.6
A2 VAR PORTD.5

'ONES HOURS PINS

B0 VAR PORTB.2
B1 VAR PORTB.3
B2 VAR PORTB.5
B3 VAR PORTB.4
B4 VAR PORTD.4
B5 VAR PORTA.0
B6 VAR PORTA.1
B7 VAR PORTA.2
B8 VAR PORTE.0
B9 VAR PORTB.1

DOT VAR PORTE.1

'TENS OF MINUTES

C0 VAR PORTC.7
C1 VAR PORTB.0
C2 VAR PORTE.2
C3 VAR PORTA.7
C4 VAR PORTC.0
C5 VAR PORTC.1

'ONES OF MINUTES

D0 var PORTD.3
D1 VAR PORTC.4
D2 VAR PORTC.5
D3 VAR PORTC.6
D4 VAR PORTC.2
D5 VAR PORTC.3
D6 VAR PORTD.0
D7 var PORTD.1
D8 VAR PORTA.6
D9 var PORTD.2

'DS 1302 pins

RST  Var PORTA.5
IO   Var PORTA.4
SCLK Var PORTA.3

' DS1302 Allocate variables
rtcyear    Var byte
rtcday     Var byte
rtcmonth   Var byte
rtcdate    Var byte
rtchr      Var byte
rtcmin     Var byte
rtcsec     Var byte
rtccontrol Var byte

'my time variables

saatebi var word
cutebi var word
DRO var word

T1 VAR WORD 'VARIABLES FOR TIME DIGITS
T2 VAR WORD
T3 VAR WORD
T4 VAR WORD

' MTAVARI KODI AQ

' Set initial time to 8:00:00AM 07/16/99
rtcyear = \$99
rtcday = \$06
rtcmonth = \$07
rtcdate = \$16
rtchr = \$23
rtcmin = \$48
rtcsec = 0
Gosub settime   ' Set the time

mtavari:
'high dot
gosub gettime
't1=2
't2=3
't3=4
't4=5
gosub display
'pause 100
'low dot
'pause 100
goto mtavari

DISPLAY: 'DECODE VALUES AND DISPLAY THEM

'tens hours

IF T1=0 THEN
HIGH A0
ELSE
LOW A0
ENDIF

IF T1=1 THEN
HIGH A1
ELSE
LOW A1
ENDIF

IF T1=2 THEN
HIGH A2
ELSE
LOW A2
ENDIF

'ONES HOURS

IF T2=0 THEN
HIGH B0
ELSE
LOW B0
ENDIF

IF T2=1 THEN
HIGH B1
ELSE
LOW B1
ENDIF

IF T2=2 THEN
HIGH B2
ELSE
LOW B2
ENDIF

IF T2=3 THEN
HIGH B3
ELSE
LOW B3
ENDIF

IF T2=4 THEN
HIGH B4
ELSE
LOW B4
ENDIF

IF T2=5 THEN
HIGH B5
ELSE
LOW B5
ENDIF

IF T2=6 THEN
HIGH B6
ELSE
LOW B6
ENDIF

IF T2=7 THEN
HIGH B7
ELSE
LOW B7
ENDIF

IF T2=8 THEN
HIGH B8
ELSE
LOW B8
ENDIF

IF T2=9 THEN
HIGH B9
ELSE
LOW B9
ENDIF

'tens of minutes

IF T3=0 THEN
HIGH C0
ELSE
LOW C0
ENDIF

IF T3=1 THEN
HIGH C1
ELSE
LOW C1
ENDIF

IF T3=2 THEN
HIGH C2
ELSE
LOW C2
ENDIF

IF T3=3 THEN
HIGH C3
ELSE
LOW C3
ENDIF

IF T3=4 THEN
HIGH C4
ELSE
LOW C4
ENDIF

IF T3=5 THEN
HIGH C5
ELSE
LOW C5
ENDIF

'ONES OF MINUTES

IF T4=0 THEN
HIGH D0
ELSE
LOW D0
ENDIF

IF T4=1 THEN
HIGH D1
ELSE
LOW D1
ENDIF

IF T4=2 THEN
HIGH D2
ELSE
LOW D2
ENDIF

IF T4=3 THEN
HIGH D3
ELSE
LOW D3
ENDIF

IF T4=4 THEN
HIGH D4
ELSE
LOW D4
ENDIF

IF T4=5 THEN
HIGH D5
ELSE
LOW D5
ENDIF

IF T4=6 THEN
HIGH D6
ELSE
LOW D6
ENDIF

IF T4=7 THEN
HIGH D7
ELSE
LOW D7
ENDIF

IF T4=8 THEN
HIGH D8
ELSE
LOW D8
ENDIF

IF T4=9 THEN
HIGH D9
ELSE
LOW D9
ENDIF
'ended
return

' Subroutine to write time to RTC
settime:
RST = 1         ' Ready for transfer

' Enable write
Shiftout IO, SCLK, LSBFIRST, [\$8e, 0]
RST = 0         ' Reset RTC
RST = 1         ' Ready for transfer

' Write all 8 RTC registers in burst mode
Shiftout IO, SCLK, LSBFIRST, [\$be, rtcsec, rtcmin, rtchr, rtcdate, rtcmonth, rtcday, rtcyear, 0]
RST = 0         ' Reset RTC
Return

' Subroutine to read time from RTC
gettime:
RST = 1         ' Ready for transfer
Shiftout IO, SCLK, LSBFIRST, [\$bf] ' Read all 8 RTC registers in burst mode
Shiftin IO, SCLK, LSBPRE, [rtcsec, rtcmin, rtchr, rtcdate, rtcmonth, rtcday, rtcyear, rtccontrol]
RST = 0         ' Reset RTC

saatebi =( rtchr >> 4 * 10 ) + ( rtchr // 16 )    'GET TIME VALUES INTO 4 DIGIT VARIABLE
cutebi =( rtcmin >> 4 * 10 ) + ( rtcmin // 16 )
DRO=SAATEBI*100+CUTEBI

'DECODE TIME INTO SEGMENT VARIABLES

T1=DRO DIG 1
T2=DRO DIG 2
T3=DRO DIG 3
T4=DRO DIG 4

'T4=rtcsec //16     'test

Return

:SEGTEST  'test all segments
HIGH A0
PAUSE X
LOW A0
HIGH A1
PAUSE X
LOW A1
HIGH A2
PAUSE X
LOW A2
HIGH B0
PAUSE X
LOW B0
HIGH B1
PAUSE X
LOW B1
HIGH B2
PAUSE X
LOW B2
HIGH B3
PAUSE X
LOW B3
HIGH B4
PAUSE X
LOW B4
HIGH B5
PAUSE X
LOW B5
HIGH B6
PAUSE X
LOW B6
HIGH B7
PAUSE X
LOW B7
HIGH B8
PAUSE X
LOW B8
HIGH B9
PAUSE X
LOW B9
HIGH C0
PAUSE X
LOW C0
HIGH C1
PAUSE X
LOW C1
HIGH C2
PAUSE X
LOW C2
HIGH C3
PAUSE X
LOW C3
high c4
pause x
low c4
high c5
pause x
low c5
high d0
pause x
low d0
high d1
pause x
low d1
high d2
pause x
low d2
high d3
pause x
low d3
high d4
pause x
low d4
high d5
pause x
low d5
high d6
pause x
low d6
high d7
pause x
low d7
high d8
pause x
low d8
high d9
pause x
low d9
high dot
pause x
low dot
RETURN```

31. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

I din't look at datasheet, so I assume that RTC is I2C.
RST is input, so it wont never go high. And your clock isn't selected.
Things like this:
RST = 0 ' Reset RTC
RST = 1 ' Ready for transfer
Can make a lot of problem. Depending on how long are your traces, etc it can fail. Look up about RMW issue on PIC.
You can try to add pauses, or slow down PIC clock. and try to use HIGH and LOW, this is little slower and it will set pin to output.
Also try to put LED on 3 pin used by RTC, and drive them with HIGH LOW, to see if they work.

32. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

It appears to be config issue. When using PORTC for DS1302, all works correctly. When try to use PORTA, even on breadboard it does not works.

33. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

fixed configs, it now works on breadboard. later will try with nixies.

34. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Can you tell what was issue. Because I still don't see it...

35. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

When copying code, I was missing this during initialisation:

Low RST ' Reset RTC
Low SCLK

after I added it, it now works, but now I have another issue - DIG does not converts time properly. The code for that I'm using is as follows:

Code:
```gettime:
RST = 1         ' Ready for transfer
Shiftout IO, SCLK, LSBFIRST, [\$bf] ' Read all 8 RTC registers in burst mode
Shiftin IO, SCLK, LSBPRE, [rtcsec, rtcmin, rtchr, rtcdate, rtcmonth, rtcday, rtcyear, rtccontrol]
RST = 0         ' Reset RTC

saatebi =( rtchr >> 4 * 10 ) + ( rtchr // 16 )    'GET TIME VALUES INTO 4 DIGIT VARIABLE
cutebi =( rtcmin >> 4 * 10 ) + ( rtcmin // 16 )
DRO=SAATEBI*100+CUTEBI

'DECODE TIME INTO SEGMENT VARIABLES

T1=DRO dig 1
T2=DRO DIG 2
T3=DRO DIG 3
T4=DRO DIG 4

Return```

36. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

This works, but only for ones of hours and ones for minutes. Does not works for tens of hours and tens for minutes. But the problem is, that I've copied this code from somewhere, and have no clue how it works...

t1=rtchr >> 4 * 10
t2=rtchr // 16
T3=rtcmin >> 4 * 10
T4=rtcmin // 16

37. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

Oh, need to read manual removed * 10 and all works fine.

38. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

I use similar code, but it's faster, and take less space.
t1=rtchr >> 4
t2=rtchr & %00001111
T3=rtcmin >> 4
T4=rtcmin & %00001111
It is always faster to do logic, than math.

39. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

I'm facing another problem

statement like WRITE 1, variable or READ 1, variable give "symbol not previously defined" error, but I have variable defined and it can be used with other statements without an issues.

40. ## Re: Need to drive 40 pins on variable change, is there a way to do it in elegant way?

you need a chip that has some eeprom to use read/write