This chapter contains a number of projects by other authors.
The only way to understand how to program is to study lots of programs. This includes reading other peoples programs so you can pick up different hints and tricks.

Clicking on the following will take you down the page:


Note: The instructions in your program should be in small lettering as shown in "Flickering Candle."
The terms used in the following programs, such as $+2, ds, are covered in the: Library of Routines (see left index).

This program flashes a LED. It's the simplest program you can get.

; list directive to define processor
		list      p=12f629            
		; processor specific variable definitions

__CONFIG   _cp_off & _mclre_off & _wdt_off & _intrc_osc_noclkout 
                  & _boden_off & _cpd_off &_pwrte_off

	ORG	0000H
	MOVLW 	07H	
	MOVWF 	CMCON		; TURN-OFF analog comparator 
	BSF	STATUS,RP0	; select bank 1
	CALL	3FFH		; Load cal value
	BCF	LED_IO		; set as output
	BCF	STATUS,RP0	; select bank 0
	GOTO	$+2
	GOTO	$+2
	GOTO	Delay_0
	GOTO	$+1	;delay 2 cycles
	GOTO	$+1	;delay 2 cycles
	GOTO	$+1	;delay 2 cycles
	RETURN		;4 cycles (including call)

This program comes from:
It simulates a candle and is powered by 3 "AAA" cells. The flickering looks so real, all visitors think it is a real candle inside a large jar.

Here is the program:

;	Candle Simulation
;	6/04 Luhan Monat
;	Simulate flicker of candle using incandescent lamp
	device	PIC12F675,intrc_osc,pwrte_on,wdt_off

	org	20h  ;This is file 20h  - first General Purpose File

del1	ds	1
del2	ds	1
pcnt	ds	1
temp	ds	1
lev1	ds	1
lev2	ds	1
level	ds	1
rbuf	ds	5 	;five files have been allocated 

LAMP	=	gp.5

	org	0
	goto	start	;the program will start at location 0005
	org	4          ;this is the Return From Interrupt location

start	bsf	RP0  	 ;the start of the program 
	movlw	0
	movwf	GP
	movlw	127	;this is decimal 127
	movwf	OSCCAL
	bcf	RP0
	bsf	rbuf,0	;seed random number
	movlw	127
	movwf	lev1	;initial light level
	movwf	lev2

; Main Loop
; Create hi and low power levels
; Switch between levels
candle	movf	lev1,w
	movwf	level
	call	power	;do lev1 power
	call	rando
	andlw	7
	btfss	z	;test the zero bit of the working register
	goto	:run	;skip 7 out of 8
	call	rmid	;generate new hi and low levels
	movwf	lev1
	sublw	0
	movwf	lev2
:run	movf	lev2,w	;do lev2 power
	movwf	level
	call	power
	goto	candle
; PWM power control

power	movlw	100	;set flicker rate: higher=slower
	movwf	pcnt	;set loop count
:p1	movf	level,w	;get target level
	movwf	del1	;set 1st delay
	sublw	0	;
	movwf	del2	;set 2nd delay
	bsf	LAMP	;power on
:p3	nop
	decfsz	del1	;do 1st delay
	goto	:p3
	bcf	LAMP	;power off
:p4	nop
	decfsz	del2	;second delay
	goto	:p4
	decfsz	pcnt
	goto	:p1

; find sum of 4 random numbers
; skews results around 127

rmid	call	rando
	andlw	3fh
	movwf	temp
	call	rando
	andlw	3fh
	addwf	temp
	call	rando
	andlw	3fh
	addwf	temp
	call	rando
	andlw	3fh
	addwf	temp,w
	ret		;return

; Pseudo Rando Number
; "Chop Suey Machine"

rando	movf	rbuf,w
	addwf	rbuf+1,w
	movwf	rbuf+1
	addwf	rbuf+2,w
	movwf	rbuf+2
	addwf	rbuf+3,w
	movwf	rbuf+3
	addwf	rbuf+4,w
	movwf	rbuf+4
	bcf	c	;clear the carry bit of rbuf+4
	rlf	rbuf+4
	btfsc	c
	bsf	rbuf+4,0
	movf	rbuf+4,w
	addwf	rbuf


The program comes from:
The three LEDs are mounted on the end of a ruler and the LEDs produce a pattern when it is waved in the air. The circuit is powered by 3 button cells. The circuit turns off after 20 seconds and the switch needs to be reset to start the effect.


;	Swish Stick Program
;	8/04 Luhan Monat

	device	pic12f675,intrc_osc,mclre_on,wdt_off

	org	20h
count	ds	2
sumyel	ds	1
sumgrn	ds	1
sumred	ds	1
del0	ds	1
del1	ds	1
del2	ds	1
prn	ds	3

YEL	=	gp.2
RED	=	gp.1
GRN	=	gp.0

	org	0

	goto	start
start	bsf	RP0
	movlw	001000b		;float mclr?
	movwf	gp
	movlw	104
	movwf	OSCCAL
	bcf	RP0
	movlw	7
	movwf	CMCON		;no comparators
	movlw	111
	movwf	prn
	bsf	GP,3		;raise mclr?

	clrf	count
	movlw	20
	movwf	count+1
:nxt	movlw	1
	call	msecs		;basic loop timing
	call	pseudo
	bcf	RED
	bcf	YEL
	bcf	GRN
	btfsc	prn,0
	bsf	RED
	btfsc	PRN,1
	bsf	YEL
	btfsc	PRN,2
	bsf	GRN
	decfsz	count
	goto	:nxt
	decfsz	count+1
	goto	:nxt
	bcf	RED
	bcf	GRN
	bcf	YEL
:hang	sleep			
	goto	:hang

; pseudo random number generator

pseudo	movf	prn,w
	addwf	prn+1
	movf	prn+1,w
	addwf	prn+2
	bcf	c
	rrf	prn+2
	btfsc	c
	bsf	prn+2,7
	movf	prn+2,w
	addwf	prn

; milliseconds at 4 MHz

msecs	movwf	del1
:2	movlw	250
	movwf	del0
:3	clrwdt
	decfsz	del0
	goto	:3
	decfsz	del1
	goto	:2



by: Rickard Gunée

The program comes from:


This project describes a PIC10F200-based electronic dice. The reason I made this was that I had a small corner left over when ordering a panel with a couple of other PCBs and thought I would rather use the corner for something interesting than leave it unused, so I made a dice project. The PCB is quite small, so it is hard to etch it yourself.

Even though this is a very simple project, it requires some surface mount soldering skills, proper tools, and a steady hand as it is built with surface mount components only. But it might be a good start if you have experience with through-hole soldering and want to try surface mount.

The complete project


The standard solution for a power supply is to use a 7805 but I could not find any 7805 in a sot-23 or smaller outline so I used an LP2985 that is available in a 5-pin sot-23 with 5v/150mA output. I use a 100nF cap on both input and output side of the regulator to get rid of noise etc. I'm using a standard 9v battery to supply the circuit.

The PIC controlling the dice is a PIC10F20X, but it is also possible to use a PIC10F22X (that is what is sold in my web shop as it is almost the same price so I use the 10F222 to get fewer chips in stock as other projects use the 10F222).
Both are microcontrollers with very small RAM and ROM, 16byte/256words of RAM/ROM but there are versions with up to 24byes/512words.
The 10F22X series also has an ADC but that is not needed in this project. Two of the six pins are used for power supply, there is one reset (or input only) pin and three IO-pins. The switch is connected to the input pin.
The three IO-pins are used to drive a 2x2 matrix configuration of the seven LEDs. Some of the the LEDs are connected in series and lit in three sets of two on opposite sides in series and one single LED in the center. The 2x2 matrix configuration is created with three pins by putting the LEDs in opposite directions so when the common line is "0" some LEDs are lit and when the common is "1" other LEDs are lit. This leads to only two sets of LEDs can be lit at one time, either the LEDs in the corners or the ones in the middle. When scanning at 100Hz between the different LEDs it looks like they are all lit at the same time thanks to the persistence of vision effect.
There are 3 resistors in series with the LEDs as the system runs on 5v and the LEDs have a voltage drop of about 2v each. One nice feature of the PIC10F-series is the current consumption, especially in sleep mode. This removes the need for an on/off switch as the dice only uses 0.4uA in standby, so it can be in standby for many years without using up the battery.


The software is very simple, not very good looking and not very optimized but the 16 bytes of RAM and 256 words of ROM are more than enough so there is no need for optimizations (except for the optimizations that are fun to do). It has a main loop that lights some of the LEDs in one pass and the other LEDs in a second pass. The state engine has four states IDLE, WAIT, ROLL and SHOW.
When in the idle state the PIC is set to sleep state and is woken up on pin change (when the switch is pushed). In the wait state, a roll pattern is shown and a counter is generating a random number based on how long the user pushes the button (not a very good random generator but if the button is pushed longer than the mechanically shortest possible time it is quite ok). In the ROLL state the roll animation is shown for two additional seconds just to make it more exciting. Finally in the SHOW state the result is shown for 3.5sec before going back to IDLE, unless the button is pushed and it starts another roll.

Before "taking on" the PIC10Fxxx" the cost of these chip is higher than the PIC12F629 as the PIC12F629's are sold in larger quantities and thus the costs are less.
This project is only shown as "an idea." Using a
PIC12F629 will save multiplexing the display and produce a brighter output. Also, using a 9v battery and regulator is very wasteful. The supply can be 3 button cells, with no wasted "excess voltage."

The dice is built with seven LEDs placed like this:                  

This is the software for a dice based on PIC10F2XX  

;* PIC10F2XX-based mini dice (C) Rickard Gunee 2007                           

	list r = dec              
	__config   _cp_off & _wdt_off & _IOFSCS_4MHz & _MCLRE_off 
;	udata
;temp0	res	1
;temp1	res	1

VDA0		equ	1
VDA1		equ	2

sndbit		equ	0
lpl		equ	1
rpl		equ	2
scrpart		equ	3
close		equ	4
serve		equ	6
screen		equ	7

temp0		equ	0x10
temp1		equ	0x11
temp2		equ	0x12
digit		equ	0x13
state		equ	0x14
time_l		equ	0x15
time_h		equ	0x16
number		equ	0x17

S_IDLE		equ	0x00
S_WAIT		equ	0x01
S_ROLL		equ	0x02
S_SHOW		equ	0x03

;rst     	code     0x00       		;Reset Vector
	movwf 	OSCCAL
  	goto    	Start             	;Jump to Start code

; Table with digits and graphics for roll. Note that order of numbers doesn't matter
; because they are shown randomly so the table has been rolled to make roll table
; and digit table overlap thus saving one byte in the table, a lot of memory left
; so it is just to show off. 

digits	andlw	7
	addwf	PCL,F
	retlw	B'1001'	;4
	retlw	B'0001'	;5
	retlw	B'1011'	;6
	retlw	B'0100'	;1
	retlw	B'1000'	;2
	retlw	B'0000'	;3 \
	retlw	B'0101'	;/
	retlw	B'0110'	;-

; big delay loop to create a delay of about w*3cc

bigdelay		movwf	temp1
bigdelay_l0	movlw	0xFF
		movwf	temp0
bigdelay_l1	decfsz	temp0,F
		goto	bigdelay_l1
		decfsz	temp1,F
		goto	bigdelay_l0
		retlw	0

; Initialize ports etc

Start	movlw 	B'1000'	; set leds as outputs and switch as input
	tris 	GPIO
	clrf 	ADCON0	; disable ADC on PIC10F22X
	movlw 	B'00000000'
	clrf	time_l	;clear time
	clrf	time_h

;display phase 1
	movfw	digit	;for a given digit
	call	digits	;get on/off values for the four LED sets
	movwf	temp2	;store in temp2 for phase 2
	andlw	B'0011'	;mask out lower 2 bits
	movwf	GPIO	;output to LEDs (also sets common to low)

	movlw	3
	call	bigdelay	;wait for 1/200 second

;display phase 2
	rrf	temp2,F		;shift down upper two bits
	rrf	temp2,W
	xorlw	B'0100'		;set common line bit to high
	movwf	GPIO		;output to LEDs

	movlw	3
	call	bigdelay		;wait for 1/200 second

;handle timer

	incf	time_l,f	;increase timer low byte
	skpnz		;if overflow
	incf	time_h,f	;then increase timer high byte

;handle main state machine

	movfw	state		;switch on state
	andlw	0x03		;prevent illegal jump to be safe
	addwf	PCL,F		;jump to state jump (one of 4 lines below)
	goto	state_idle
	goto	state_wait
	goto	state_roll
				;"fallthrough" to show state below

;- Show state, shows the result

	movlw	S_WAIT
	btfss	GPIO,3		;if button is pressed
	movwf	state		;set state to WAIT to make another roll
	movfw	time_h		;check if time = 512 main loop cycles
	xorlw	0x2
	goto	main		;if not get back to main and keep waiting
	clrf	state		;otherwise: set idle state
	clrf	GPIO		;turn of leds
	sleep			;go to sleep

; this is the state where the system wakes up
	btfsc	GPIO,3		;if button was not pressed
	sleep			;then power down
	movlw	S_WAIT
	movwf	state		;otherwise set state to wait
	goto	main

;- Wait for button to be released and decrease number
;- to get user pressing time to generate a random value

	movlw	S_ROLL
	btfss	GPIO,3		;if button is released
	goto	state_wait_j0
	movwf	state		;set state to roll
	clrf	time_l		;and clear time
	clrf	time_h

	decfsz	number,F		;decrease number
	goto	state_wait_j1
	movlw	6		;restart at 6 if zero
	movwf	number		;resulting in a "random" number of 0..5
	goto	spin		;show spin effect

;- Roll state, this is just to get some tension, rolling for a couple of extra seconds

	movfw	time_h
	xorlw	0x1		;check if time = 256 main loop cycles
	goto	spin;		;if not get show spin effect before getting
				;back to main and keep waiting

	movlw	S_SHOW		;otherwise, set state = show
	movwf	state
	clrf	time_l		;clear time
	clrf	time_h
	decf	number,w		;set digit to number-1 (result of roll)
	movwf	digit
	goto	main		;go back to main and start showing result

;- Spin effect, shows a rolling sequence of \/-

spin	movfw	time_l		;get low part of time
	andlw	0x1F		;check lower 4 bits
	skpz			;if nonzero
	goto	main		;then continue

		;the following is done every 16 display cycles

	incf	digit,w		;else increase digit
	andlw	0x03		;keep below upper limit
	skpnz			;and check for zero
	movlw	0x01		;additional increase if zero
	xorlw	0x04		;keep above lower limit
	movwf	digit		;store back to digit
	goto	main		;get back to main loop



This program produces random noise with an output frequency of approx 50kHz. This is only a "partial program" to show the concept of
The algorithm for generating the noise signal is quite simple. The process begins by setting up a 15 bit shift register, with the initial value of all 15 bits set as 1's. The register is right shifted, and the lowest bit is transferred to the output register GPO. The lowest and second lowest bits are Exclusive OR'ed, and the result shifted into the highest bit position. The cycle is repeated, with each cycle producing a bit in a pseudo-random bit sequence. The pseudo-random bit sequence repeats each 32,767 cycles.
The output frequency can be decreased by adding delays to the program loop, using an external clock, or using the internal clock/counter/prescaler.

;Pseudo Random Noise
;microprocessor to suit your requirements	

HIGH BYTE	equ	007	; define high byte of shift register 
LOW_BYTE	equ	008	; define low byte of shift register

LOAD_OPTION	movlw 	 0xDF	; zero bit 5 of option register to
		option		 ; disable timer 0 clock source

LOAD TRIS	movlw	0x08	; define GPIO 0-2, 4 & 5 as outputs
		tris	GPIO	; 3 as input (or as needed)

INIT REGS		movlw	0xff
		movwf	HIGH BYTE  ;Initialize all bits of registers to 1
		movwf	LOW_BYTE

GEN PRBS	bcf	HIGH BYTE,7  ;set shift-in value to 0
		rrf	HIGH BYTE,1  ;shift high byte right
		rrf	LOW BYTE,1  ;shift low byte right, 
				      ;shift out bit is carry bit in status
		movfw	STATUS         ;load status register
		andlw	0x01 	     ;isolate carry bit
		movfw	GPIO	     ;output new prbs value

	xorwf	LOW BYTE,0  ; value for high bit of register
	andlw	0x01	      ;isolate shift-in value, sets zero flag if zero
	btfss	STATUS,Z       ;if shift-in bit is zero, skip next
	bsf	HIGH BYTE,6  ;set high bit to 1
	goto	GEN_PRBS



The Quiz Controller circuit:

; written by: John Morton		
; for PIC12F675			
; clock frequency: Int. 4 MHz		
; ***************************************

; Program Description: Quiz controller for 3 players, including reset button 
;  for the quiz master

	list		P=12F675		
	include		inc:\pic\

; Declarations:

temp	equ	20h
Post16	equ	21h

	org	0	; first instruction to be executed
	goto	Start	;
	org	4	; interrupt service routine
	goto	isr	;

; Subroutines: 

Init	bsf	STATUS, RP0	; go to Bank 1
	call	3FFh		; call calibration address
	movwf	OSCCAL		; move w. reg into OSCCAL

	movlw	b'011110'		; GP5: Buzzer, GP3: Reset button
	movwf	TRISIO		;  GP1,2,4: LEDs/Buttons (inputs
				;  to start with), GP0: LED enable
	movlw	b'010110'		; GP1,2,4 have weak pull-ups 
	movwf	WPU		;   enabled

	movlw	b'00000111'	; pull-ups enabled, TMR0 presc.	
	movwf	OPTION_REG	;  by maximum (256)
	clrf	PIE1		; turn off peripheral interrupts
	movlw	b'010110'		; enable GPIO change interrupt
	movwf	IOC		;  on GP1, GP2 and GP4 only
	clrf	VRCON		; turn off comparator V. ref.
	clrf	ANSEL		; make GP0:3 digital I/O pins
	bcf	STATUS, RP0	; back to Bank 0
	clrf	GPIO		; reset input/output port
	movlw	b'00001000'	; enable GPIO change interrupt
	movwf	INTCON		;  only
	movlw	b'00000111'	; turn off comparator
	movwf	CMCON		;
	clrf	T1CON		; turn off TMR1
	clrf	ADCON0		; turn off A to D converter

	movlw	d'16'		; set up postscaler
	movwf	Post16		;	
	retfie			; return, enabling interrupts

; Interrupt Service Routine
isr	btfss	INTCON, 0		; check GPIO change int. flag
	goto	Timer		; TMR0 interrupt occurred?
				; GPIO interrupt occurred?
	bcf	INTCON, 0		; reset interrupt flag	
	comf	GPIO, w		; store state of GPIO
	andlw	b'010110'		; mask all except buttons
	movwf	temp			;
	btfsc	STATUS, Z	; are any buttons actually pressed?
	retfie			; false alarm	
	bsf	STATUS, RP0	; to Bank 1
	movlw	b'001000'		; make GP1,2,4 outputs 
	movwf	TRISIO		; 
	bcf	STATUS, RP0	; move to Bank 0	
	movfw	temp		; move temp back into GPIO,
	addlw	b'100001'		;  set GP5 and GP0 (turns on 
	movwf	GPIO		;  buzzer and enables LEDs)
	movlw	b'00100000'	; enable TMR0 interrupt, disables 
	movwf	INTCON		;  the GPIO change interrupt
	retfie			; return, enabling GIE

Timer	bcf	INTCON, 2		; reset TMR0 interrupt flag
	decfsz	Post16, f		; is this the 16th TMR0 interrupt
	retfie			;
	bcf	GPIO, 5		; turn off buzzer
	clrf	INTCON		; turn off all interrupts 
	sleep			; go into low power mode

; Program Start

Start	call	Init		; initialisation routine

Loop	goto	Loop		; keep looping



The following circuit shows how to connect resistors to a keyboard for a 1-wire communication to a micro. The line is taken to the ADC of the micro. When a  key is pressed it produces a unique resistance and this is interpreted by a sub-routine.

The interesting feature of this circuit is the function of the two transistors. They are designed to reduce the voltage of the power supply so that the LEDs do not illuminate when one or more of the output lines are made "input."
Suppose all drive lines are made input.
You can see a red LED and orange LED are connected directly across the power rails in two of the branches. These LEDs would illuminate if the supply was higher than 1.7v + 2.3v = 4v.
The two transistors are designed to drop the rail voltage.
To work out the rail voltage we note the 3k3, 2k7 and 2k2 are voltage dividers. The voltage across the 3k3 will be 5 / 8.2 x 3.3 = 2v
The voltage on the base of the BC182 will be 5v - 2.6v = 2.4v
This means the supply voltage for the LEDs will be 2.4v  This means any output taken LOW will deliver slightly less than 2.4v for any LED connected between the drive-line and Vref1.
The BC 213 drops 5 / 8.2 x 2.2 = 1.3v
A drive line supplying voltage to the orange and green LEDs will have slightly less than 3.7v available.
The different base resistor shave been chosen to produce approx the same current though each of the LEDs.
The chip can only drive some of the LEDs at the same time and this is covered in some of our other articles.