8×16 Microchip PIC LED message board. Approach №1.

This is the second article about this board.
The first part is here.

The code here is not actually a message board. It only demonstrates the principle of image rendering.
It may be usable for test purposes.

The image is hardcoded into the program memory. It is loaded from the program memory into the RAM and is transferred to the display in several cycles.
This scheme is good to check if the basic hardware is working – the PIC is started, shift registers are controlled correctly and so on.

Schematic diagram:
sch001

In the real device I used the cheapest transistors I could find.
In the real device I did not use resistors R11-R26 and especially R7-R10.

R11-R26 may make sense, because I really saw some flickering in unconnected rows that could be caused by unstable transistor’s condition when its base is connected only to high-impedance latch output. So, these resistors close column’s transistors by default..

But R7-R10 is demand of Proteus. It can’t calculate this scheme if you do not give him these resistors or if their value will be over 21k.
Actually, 21k is unstable too.

ASM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
 
        list            p=pic16f84a
        include         p16f84a.inc
        __config _hs_osc & _wdt_off & _pwrte_on & _cp_off
        errorlevel      -302    ;Eliminate bank warning
 
;****************  Label Definition  ********************
 
cnt500u 	equ     0c              ;500usec counter Address
cnt1m   	equ     0d              ;1msec counter Address
cnt100m 	equ     0e              ;100msec counter Address
cnt500m 	equ     0f              ;500msec counter Address
cnt1s   	equ     10              ;1sec counter Address
 
count    	equ    11		; number of bits that has been sent to the shift register
str      	equ    12 		; 
count2   	equ    13		; number of column shifts to display all message
pzsn      	equ    14		; here value is stored for initializing indirect addressing
count3    	equ    15		; number of one frame renders before column shift
 
;****************  Program Start  ***********************
        org     0               ;Reset Vector
        goto    init
        org     4               ;Interrupt Vector
        goto    init
 
;****************  Initial Process  *********************
        org     5
init    bsf     status,rp0      ;Change to Bank1 
        clrf    trisa           ;Set PORTA to Output mode
        clrf    trisb           ;Set PORTB to Output mode
        bcf     status,rp0      ;Change to Bank0
        movlw   h'00'           ;
        movwf   portb           ;
 
 
 
;***********  disposing the image of the first string in RAM ***************
;*********** here 53 colums of data + 7 empty (buffer) columns 
;000000000000000000000000000000000000000000000000000000000000
;011111011111001110011111011101000100111000010000000000000000
;000100010000010001000100001001000101000100010000000000000000
;000100010000010000000100001001100101000000010000000000000000
;000100011110001110000100001001010101001100010000000000000000
;000100010000000001000100001001001101000100010000000000000000
;000100010000010001000100001001000101000100000000000000000000
;000100011111001110000100011101000100111100010000000000000000
fst
 
    movlw     0x16 			; starting address
    movwf     fsr			; using indirect addressing
    movlw     b'00000000'
    movwf     indf			; 
 
    incf       fsr			; 0x17
    movlw      b'00000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'11111110'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'11111110'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10010010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10010010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10010010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'01001100'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10010010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10010010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10010010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'01100100'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'11111110'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'11111110'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'11111110'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00001000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00010000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00100000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'11111110'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'01111100'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10000010'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'11110100'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'10111110'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
;---------------  buffer ------------------------------------          
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
 
    incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
 
   incf       fsr
    movlw      b'00000000'
    movwf     indf                      ;
 
;  --------------  main program start --------------
; here we selecting initial address in RAM (pointer)
; where image of the string is stored (60 bytes)
; and sending to the screen 16 bytes that can be visible for 8x16 matrix
; then we increasing pointer by one and repeat this procedure
; 
; after 50 shifts all data will go through the screen.
 
        clrf    count
        movlw   b'00001110'  	        ; '14' is placed to count2
        movwf   count2  
        clrf    count3
        movlw   0x16			; initial RAM address for string image
        movwf   pzsn   			; value for indirect addressing
 
        movf     pzsn,0
        movwf    fsr
        movlw   b'00000000'		; select the 0-th row of the LED matrix
        movwf   porta
 
; collecting and sending data for row 0
egh0    btfsc  indf,0			; sending bit 0 to shift register
        call   dsend1			;
        btfss  indf,0			;
        call   dsend0			;
        incf   fsr,1			; next byte to render
        incf   count,1			; count number of bytes that been sended to register
        btfss  count,4			; all 16 bytes has been sent?
        goto   egh0				; no, send the 0-th bit of the next byte from FSR
        movf   pzsn,0			; reset indirect addressing to the beginning for the next row
        movwf  fsr				;
        clrf   count			; reset column (bytes) count for the next row
        call   oport			; show collected row on the screen
        movlw   b'00000001'		; switch matrix to the 1-st row
        movwf   porta			;
 
; collecting and sending data for row 1
egh1    btfsc  indf,1			; sending bit 1 to shift register
        call   dsend1			;
        btfss  indf,1			;
        call   dsend0			;
        incf   fsr,1			; next byte to render
        incf   count,1			; count number of bytes that been sended to register
        btfss  count,4			; all 16 bytes has been sent?
        goto   egh1				; no, send the 1-st bit of the next byte from FSR
        movf   pzsn,0			; reset indirect addressing to the beginning for the next row
        movwf  fsr				;
        clrf   count			; reset column (bytes) count for the next row
        call   oport			; show collected row on the screen
        movlw   b'00000010'		; switch matrix to the 2-nd row
        movwf   porta			;
 
 
; collecting and sending data for row 2
egh2    btfsc  indf,2
        call   dsend1
        btfss  indf,2
        call   dsend0
        incf   fsr,1
        incf   count,1
        btfss  count,4
        goto   egh2
        movf   pzsn,0
        movwf  fsr
        clrf   count
        call    oport
        movlw   b'00000011'
        movwf   porta
 
 
; collecting and sending data for row 3
egh3    btfsc  indf,3
        call   dsend1
        btfss  indf,3
        call   dsend0
        incf   fsr,1
        incf   count,1
        btfss  count,4
        goto   egh3
        movf   pzsn,0
        movwf  fsr
        clrf   count
        call   oport
        movlw   b'00000100'
        movwf   porta
 
 
 
; collecting and sending data for row 4
egh4    btfsc  indf,4
        call   dsend1
        btfss  indf,4
        call   dsend0
        incf   fsr,1
        incf   count,1
        btfss  count,4
        goto   egh4
        movf   pzsn,0
        movwf  fsr
        clrf   count
        call   oport
        movlw   b'00000101'
        movwf   porta
 
 
 
 
; collecting and sending data for row 5
egh5    btfsc  indf,5
        call   dsend1
        btfss  indf,5
        call   dsend0
        incf   fsr,1
        incf   count,1
        btfss  count,4
        goto   egh5
        movf   pzsn,0
        movwf  fsr
        clrf   count
 
        call    oport          
        movlw   b'00000110'
        movwf   porta
 
 
; collecting and sending data for row 6
egh6    btfsc  	indf,6
        call   	dsend1
        btfss  	indf,6
        call   	dsend0
        incf   	fsr,1
        incf   	count,1
        btfss  	count,4
        goto   	egh6
        movf   	pzsn,0
        movwf  	fsr
        clrf   	count
        call   	oport
        movlw   b'00000111'
        movwf   porta
 
 
; collecting and sending data for row 7
egh7    btfsc  	indf,7
        call   	dsend1
        btfss  	indf,7
        call   	dsend0
        incf   	fsr,1
        incf   	count,1
        btfss  	count,4
        goto   	egh7
        movf   	pzsn,0
        movwf  	fsr
        clrf   	count
        call   	oport
        movlw   b'00000000'
        movwf   porta
 
 
        incf   	count3
        btfss   count3,6     ; each frame should be displayed 64 times before shift
        goto    egh0 
        clrf    count3
 
 
        ; here the string is shifting to one column
        btfss  count2,6     ; check if count2 over 64. it means 64-14=50 column shifts
        incf   pzsn,1 	    ; if less the 50 shifts, change initial fsr value (shift by one column)
        btfsc  count2,6     ; if less then 50 shifts - do not go to the next word
        goto   stop 	    ; if 50 shifts has been done go to end
        incf count2 	    ; increase column shifts count
 
 
        goto   egh0		; render row 0
 
 
stop 	goto $
 
 
; I think this should control Output Enable pin of 4094 shift-register
oport   movlw   b'00000001'
        movwf   portb
        call    t1m
        movlw   b'00000000'
        movwf   portb 
 
        return
 
 
; sends one bit to the 4094 shift register
; portb 6 is DATA
; portb 7 is CLOCK
dsend1  movlw  b'00000000'
        movwf  portb
        nop
        movlw  b'01000000'
        movwf  portb
        nop
        movlw  b'11000000'
        movwf  portb
        nop
        movlw  b'01000000'
        movwf  portb
        return
 
dsend0  movlw  b'00000000'
        movwf  portb
        nop
        movlw  b'00000000'
        movwf  portb
        nop
        movlw  b'10000000'
        movwf  portb
        nop
        movlw  b'00000000'
        movwf  portb
        return
 
 
 
 
; These timers had been written by somebody else
;********************************************************
;          Timer  Subroutine for 10MHz clock
;********************************************************
 
;*************  1msec Timer Subroutine  *****************
t1m     movlw   d'2'            ;(1)       Set loop cnt1
        movwf   cnt1m           ;(1)       Save loop cnt1
tm1lp1  movlw   d'190'          ;(1)*2     Set loop cnt2  was 249
        movwf   cnt500u         ;(1)*2     Save loop cnt2
tm1lp2  nop                     ;(1)*249*2 Time adjust
        nop                     ;(1)*249*2 Time adjust
        decfsz  cnt500u,f       ;(1)*249*2 cnt500u-1=0 ?
        goto    tm1lp2          ;(2)*248*2 No, continue
        decfsz  cnt1m,f         ;(1)*2     cnt1m-1=0 ?
        goto    tm1lp1          ;(2)       No. Continue
        return                  ;(2)       Yes. Cnt end
                                ;Total 2501*0.4usec=1msec
 
;*************  100msec Timer Subroutine  ***************
t100m   movlw   d'100'          ;Set loop counter
        movwf   cnt100m         ;Save loop counter
tm2lp   call    t1m             ;1msec subroutine
        decfsz  cnt100m,f       ;cnt100m - 1 = 0 ?
        goto    tm2lp           ;No. Continue
        return                  ;Yes. Count end
 
 
;*************  500msec Timer Subroutine  ***************
t500m   movlw   d'5'            ;Set loop counter
        movwf   cnt500m         ;Save loop counter
tm3lp   call    t100m           ;100msec subroutine
        decfsz  cnt500m,f       ;cnt500m - 1 = 0 ?
        goto    tm3lp           ;No. Continue
        return                  ;Yes. Count end
 
;**************  1sec Timer Subroutine  *****************
t1s     movlw   d'2'            ;Set loop counter
        movwf   cnt1s           ;Save loop counter
tm4lp   call    t500m           ;500msec subroutine
        decfsz  cnt1s,f         ;cnt1s - 1 = 0 ?
        goto    tm4lp           ;No. Continue
        return                  ;Yes. Count end
 
 
 
        end

Downloads:
ASM file for PIC16F84.
HEX file for flashing into PIC16F84.
Project file for Proteus 8.4