Halloween Pumpkin

This is essentially a flashing LED project. However, the reason to build it was to demonstrate two techniques: generating pseudorandom numbers and using PWM for adjusting the LED brightness. The LEDs imitate the candle flame with the center LED lighting constantly. The battery lasts for several hours during the Halloween hight. The unit is intended to be put on a ground in one's garden.

Hardware

The unit is assembled within a plastic pumpkin toy purchased in Walgreens. Actually, the toy had a handle and a motor used for a different purpose, but we needed just a pumpkin case from it. The PCB is mounted on a triple AAA batteries holder available from Radioshack. The round perf-board can also be found in Radioshack. The parts are connected by using the point-to-point method. The transistor is used to control the brightness of LEDs and is in turn controlled by a PWM signal generated by the PIC. The LEDs brightness is changing randomly, as well as the ON/OFF states of each LED and the state update time. The transistor can be replaced with a less powerful MOSFET, say 2N7000. The device is supposed to be used in darkness, so no ultra bright LEDs are used. The maximum drawing current is limited by choosing decent current limiting resistors and does not exceed 45mA. The average current consumption is about 30mA.

Schematic Daylight demo Night demo
clip
AVI ~1.3Mb
clip
AVI ~0.8Mb

The PIC runs at 2MHz frequency provided by internal oscillator. The PWM frequency for controlling the LED brightness is about 122Hz. The brightness is adjusted every 0.26sec provided by timer TMR1 with a 1:2 pre-scaler. The construction should be clear from the photos. When the pumpkin hull is closed, the plastic plate on the right photo below goes into a niche in the hull and locks there, so the entire construction is stable. There is no need in a power switch. Just put the batteries whenever you need it and let it go.

Construction Top view Back view

Software

The software implements two pseudorandom number generators. One of them generates 4-bit sequences which are used to setup time intervals for updating LEDs. The sequence numeric value is multiplied by 10msec to form a variable delay. The other generator generates 7-bit sequences which are used to light the LEDs. This generator is also used to modify the LEDs brightness by adjusting the PWM duty cycle. The duty cycle is modified every 100msec provided by timer TMR1 overflow interrupts.

The generator produce periodic sequences with periods 15 and 127, respectively. Their implementation mimics the Fibonacci LFSR (Linear Feedback Shift Register), see an article in Wikipedia for definitions. The polynomials representing the LFSRs are x4 + x3 + 1 and x7 + x6 + 1. Both polynomials are known to be primitive in GF(24) and GF(27), respectively, which guarantees the longest possible periods for the pseudorandom numbers. Run the supplied C code to convince yourself that this is indeed the case.

The main loop is pretty straightforward. The 4-bit and 7-bit pseudorandom sequences are stored in variables seq4 and seq7, respectively. We first display the old state by OR-ing these sequences together and forwarding the result to PORTC. The OR-ing is done to increase the number of LEDs on to increase the brightness. This affects the period of non-repeating sequences, of course, but it works quite well. Since PORTC in PIC16F684 has only 6 bits, and bit 5 is used to generate PWM, the two top bits of the 7-bit pseudorandom sequence are displayed by using pins 5 and 4 of PORTA. For this purpose we shift the sequence one bit to the right before forwarding it to PORTA.

loop
	movf	seq4, w		; delay 0.1sec * seq4
	movwf	cnt
	call	delay
	decfsz	cnt, f
	 goto	$-2	

	movf	seq4, w		; light the LEDs
	iorwf	seq7, w
	movwf	PORTC
	movwf	cnt
	rrf	cnt, f
	movf	cnt, w
	movwf	PORTA
	
	bcf	STATUS, C	; update seq4
	rlf	seq4, f		; LFSR implementation of primitive
	movlw	1		; polynomial x^4 + x^3 + 1
	btfsc	seq4, 3
	 xorwf	seq4, f	
	btfsc	seq4, 4
	 xorwf	seq4, f
	movlw	0x0F
	andwf	seq4, f

	bcf	STATUS, C	; update seq7
	rlf	seq7, f		; x^7 + x^6 + 1
	movlw	1
	btfsc	seq7, 6
	 xorwf	seq7, f	
	btfsc	seq7, 7
	 xorwf	seq7, f
	movlw	0x7F
	andwf	seq7, f

  	goto 	loop		; endless loop

The interrupt service routine (ISR) first saves the current state (STATUS and WREG registers) and then uses seq7 to setup the LED brightness. Note that 0 < seq7 < 128, so most of the time seq7 is quite a small number. If we use this number directly to setup the PWM duty cycle, the LEDs will be to dim most of the time. To improve the situation we first multiply this number by 3 (by adding it with itself) and then complement. The steps of this approach were figured out experimentally.

 ORG 4				; ISR
	movwf	w_save		; save W reg
	swapf	STATUS, w	; save stat reg without
	movwf	stat_save	; changing flags

	movf	seq7, w		; compute the complement of
	addwf	seq7, w		; seq7*3 to noticeably dim the LEDs
	addwf	seq7, w
	xorlw	0xFF
	movwf	CCPR1L		; setup PWM duty cycle
	bcf	PIR1, TMR1IF	; clear TMR1 interrupt flag

	swapf	stat_save, w	; get orig flags in STATUS
	movwf	STATUS
	swapf	w_save, f	; restore the original W		
	swapf	w_save, w
	retfie

Downloads


Last modified:Mon, Jan 23, 2023.

01874