PIC16F628A light generator

Find out how to setup your programmer's software and how to solve many common problems.

Moderator: phalanx

Post Reply
Posts: 1
Joined: Fri Jun 24, 2016 2:54 am

PIC16F628A light generator

Post by Hobby1958 » Fri Jun 24, 2016 3:17 am

Hi all,

As an old man (58) i am new to ASM PIC programming. I studied a lot of tutorials and program PIC in some simulators (Oshonsoft is great) on my PC. It makes fun.
I started a project for my model railroad. It is a kind of generator to put random lights on.
In my program the LED's goes on after a delay, but not random. I have used normal sequence. See te ASM file. A lot of ideas are not yet implemented like the jumpers JP1-4 but the most important is how to get it random.
How can you make the RB0-7 logic 1 in a random sequence with delay.
I hope there is a genius who can help me.

Code: Select all

; Old man is learning
; Version 1.0 June 2016 
; Rev All LED's lightsup after delay but not random 
; (needs  help....)
; Learning project based on internet tutorials
; My idea is as follows
; A kind of generator that can be used in model railroad etc like random lights 
; SW1 start the program 
; The jumpers change settings like 
; JP1 and JP2 not set makes 8 random output signal 
; JP1 set JP2 not set makes 7 random output signals
; JP1 not set JP2 set makes 6 random ouput signals
; JP1 and JP2 set makes 5 random output signals
; JP3 and JP4 not set speed random on and off are the same
; JP3 set and JP4 not set speed random on is faster as speed random off
; JP3 not set and JP4 set speed random 0ff is faster as speed random on
; JP3 and JP4 set random on / off is adjustable by trimpot and cap  On RA0 one side trimpot 50k otherside and middle are connected wit cap 100nf 
; other side cap is connected to GND
LIST	p=16F628a				;tell assembler what chip we are using
	include "P16F628a.inc"	;include the defaults for the chip
	__config 0x3f18			;sets the configuration settings (oscillator type etc.)

	cblock 	0x20 					;start of general purpose registers
		count						;used in table read routine
		count1 						;used in delay routine
		count2 						;used in delay routine
		counta 						;used in delay routine 
		countb						;used in delay routine 
		countc						;used in delay routine 
		countd						;used in delay routine 
		speed						;used in delay routine 

LEDPORT	Equ	PORTB					;set constant LEDPORT 	= 'PORTB'
LEDTRIS	Equ	TRISB					;set constant LEDTRIS 	= 'TRISB' register'
SWPORT	Equ	PORTA					;set constant SWPORT 	= 'PORTA'
SWTRIS	Equ	TRISA					;set constant SWTRIS 	= 'TRISA' register'

									;set constants for the switches

SW1		Equ	1						;set constant SW1 = 0 this is the start switch and is located on PORTA1
JP1		Equ	2						;set constant for jumper JP1 = 5 this will be PORTA2
JP2		Equ	3						;set constant for jumper JP2 = 3 this will be PORTA3
JP3		Equ 	5						;set constant for jumper JP3 = 5 this will be PORTA5
JP4		Equ	6						;set constant for jumper JP4 = 6 this will be PORTA6

									;and for the LED's

LED0	Equ	0						;set constant LED0 = 0
LED1	Equ	1						;set constant LED1 = 1
LED2	Equ	2						;set constant LED2 = 2
LED3	Equ	3						;set constant LED3 = 3
LED4	Equ	4						;set constant LED4 = 4
LED5	Equ	5						;set constant LED5 = 5
LED6	Equ	6						;set constant LED6 = 6
LED7	Equ	7						;set constant LED7 = 7

	org	0x0000					;org sets the origin, 0x0000 for the 16F628,
								;this is where the program starts running	

	movlw	0x07					;move h 07 to W
	movwf	CMCON				;move W to register file CMCON turn comparators off (make it like a 16F84)

   	bsf 	STATUS,		RP0			;bit set (1) registerfile STATUS RP0 select bank 1
   	movlw 	b'00000000'			;move b 0 to W
   	movwf 	LEDTRIS				;move W to register file LEDTRIS (= TRISB) all output
	movlw 	b'11111111'			;move b 111111110 to W
  	movwf 	SWTRIS				;move W to registerfile SWTRIS (= TRISA) all input
	bcf	STATUS,		RP0			;bit clear (0) registerfile STATUS RPO select bank 0
	clrf	LEDPORT					;clear registerfile LEDPORT (= PORTB) set all outputs low (0) all LED's off
	clrf	SWPORT					;clear registerfile SWPORT (= PORTA) set all outputs low (0)
	movlw	d'250'				;move d 250 to W
	movwf	speed				;move W to registerfile speed (set initial speed)


	btfsc	SWPORT,	SW1				;bit test registerfile SWPORT SW1 (= PORTA1) check if switch is on, if 0 skip next
	call	TableOn					;and call the associated table1
	call	TableOff
	btfsc	SWPORT,	JP1				;not used yet bit test registerfile SWPORT JP1 (= PORTA2) check if jumper is set on, if 0 skip next
	call	TableOn					
	btfsc	SWPORT,	JP2				;not used yet bit test registerfile SWPORT JP2 (= PORTA3) check if jumper is set on, if 0 skip next
	call	TableOn
	btfsc	SWPORT,	JP3				;not used yet bit test registerfile SWPORT JP3 (= PORTA5) check if jumper is set on, if 0 skip next
	call	TableOn
	btfsc	SWPORT,	JP4				;not used yet bit test registerfile SWPORT JP4 (= PORTA6) check if jumper is set on, if 0 skip next
	call	TableOn
	goto	Read

		call	Del50
		call	Del50
		bsf 	LEDPORT, LED1
		call	Del50
		call	Del50
		bsf 	LEDPORT, LED3
		call	Del50
		call	Del50
		bsf 	LEDPORT, LED5
		call	Del50
		call	Del50
		bsf 	LEDPORT, LED7
		goto Read


		call	Del50
		call	Del50
		bcf 	LEDPORT, LED1
		call	Del50
		call	Del50
		bcf 	LEDPORT, LED3
		call	Del50
		call	Del50
		bcf 	LEDPORT, LED5
		call	Del50
		call	Del50
		bcf 	LEDPORT, LED7
		goto Read

	movlw	0xC7				;delay 
	movwf	counta
	movlw	0x01
	movwf	countb

	decfsz	counta, f
	goto	$+2
	decfsz	countb, f
	goto	Delay_0

	decfsz	count1	,f
	goto	d1
	retlw	0x00

							;use separate delay routines
Del50						;
	movlw	0x32				;move 0x32 to W = decimaal 50
 	movwf	count2			;move W to registerfile 'count2' 
	movlw	0xc7				;move 0xc7 to W = decimaal 199
	movwf	countc			;move W to registerfile 'countc' 
	movlw	0xc1				;move 0x01 to W = decimaal 1
	movwf	countd			;move W to registerfile 'countd'

Delay_1						;
	decfsz	countc, f			;decrement registerfile 'countc' write back in f skip next if '0'
	goto	$+2				        ;goto
	decfsz	countd, f			;decrement registerfile 'countd' write back in f skip next if '0'
	goto	Delay_1				

	decfsz	count2	,f		;decrement registerfile 'count2' write back in f skip next if '0'
	goto	d3				        ;goto 'd3'
	retlw 	0x00


User avatar
Non-SFE Guru
Posts: 1980
Joined: Sun Nov 30, 2003 8:57 am
Location: Candia, NH

Re: PIC16F628A light generator

Post by phalanx » Tue Jul 05, 2016 6:59 am

Hi Hobby1958,

Sorry for the long delay in replying. Random Number Generators (RNG) are often a topic of discussion with microcontrollers. Without external hardware, the best you will muster is a pseudo random number which should be fine for your purposes. A linear feedback shift register is one method of generating pseudo-random numbers. I lifted this code from meikled on the Microchip forums because it is simple and works well:

Code: Select all

; Pseudo random number generator, using linear shift register feedback
 Random8                           ; seed (non-zero) is in rand    
         movf    rand,w            ; W = R (use to accumulate XOR)
         movwf   tr8               ; T = R (holds shifted result)
         rlf     tr8,f
         rlf     tr8,f             ; T(7) = R(5)
         xorwf   tr8,w             ; W(7) = W(7)^R(5) (= R(7)^R(5))
         rlf     tr8,f             ; T(7) = R(4)
         xorwf   tr8,w             ; W(7) = W(7)^R(4) (= R(7)^R(5)^R(4))
         rlf     tr8,f             ; T(7) = R(3)
         xorwf   tr8,w             ; W(7) = W(7)^R(3) (= R(7)^R(5)^R(4)^R(3))
         addlw   b'10000000'       ; carry = W(7) = R(7)^R(5)^R(4)^R(3)
         rlf     rand,f            ; rotate carry (xor'ed result) into rand
         return                    ; to generate next pseudo-random number in sequence
Basically you seed the algorithm by putting a value in "rand" and it will generate pseudo-random numbers every time you run it. If you use the same "rand" value every time you start the program, you will get the same sequence of numbers out of the algorithm. There are tricks you can use to improve the randomness of the seed value. One that I like to do is turn on the watch dog timer along with Timer1. Timer1's TMR1H and TMR1L are not reset to 0x00h after a reset so what I do is allow a watch dog timeout to reset the PIC after it is first turned on. The watch dog's timer has variation in it so the amount that Timer1 has incremented will be unique after every power up. I then use the TMR1L value to seed the random algorithm. You can check the status register to see if the last reset was due to the watch dog and then disable it if you no longer need it.

After you have your random number, you need to make use of it to control the timing of your lights. Algorithmically there are lots of things you could do. You could check the random number and if it falls into a specific range, you get a specific delay. You could wait until you have gotten a specified amount of random number within a specific range before taking action. There are lots of ways to implement it but they will all have to be tuned to provide the response you are looking for in your application.

I hope that gets you moving in the right direction!


Post Reply