2 THINGS AT ONCE


Home


 
PIC12F629 Data Sheet (.pdf  4,926KB)
Instruction Set for PIC12F629
blank12F629.asm template

PIC12F629.inc

See more projects using micros:
Elektor,EPE,Silicon Chip

Notepad2.zip     Notepad2.exe 
Library of Sub-routines "Cut and Paste
"
Library of routines:   A-E   E-P    P-Z 
 

 

A micro executes a program one instruction at a time and each instruction takes 1 microsecond. The instructions can create all sorts of effects but basically the micro is doing one thing at a time.
A program can perform a small task and output a result, then perform another task and output a result very soon after the first, so they appear to be happening at the same time.
This can be called a form of multi-tasking or multiplexing and in this way large displays can be illuminated, although only a few of the pixels are being driven at any one time.
But sometimes you want to actually carry out 2 tasks AT THE SAME TIME and sometimes this cannot be done by jumping from one task to the other and back again.
For instance, you may want to time the length of a game, while the player is playing.
There is no way to multiplex these two requirements, but the PIC chip has a feature called a TIMER. This is a file or register that is used exclusively for counting pulses (cycles). These pulses can come from an external source via one of the input pins or the file can be connected to the clock inside the chip.
The timer register is actually to files and they can be connected together to create a file 16 bits long. We call the result timer1.  It is made up of tmrL for the low 8 bits and tmrH for the high 8 bits.
Then we connect the input of timer1 to the clock in the micro so that it increments each time the clock advances.
Timer1 will increment in the background while the program is being executed. We have an instruction reset timer1, so that timing will commence immediately after the instruction is executed. We also have 2 instructions to load the timer1 with a value so that it will "roll-over" at a desired instant.
We can also instruct the micro to jump to a certain location "0004" each time timer1 rolls over from FFFFh to 0000h. Timer1 gets incremented and that means if you are going to load it with a value, it has to be the number of uS (counts) up to FFFFh.
Location "0004" is called the Interrupt Service location or Interrupt Service Register and at that location you can place an instruction to go to a sub-routine: isr - Interrupt Service Routine that outputs a value to a port, turns off a port-line or perform any task at all. You can also reload timer1 with a value so that the Interrupt occurs again after a desired interval.
The instructions at ISR should be kept very short so they do not interfere with the running of the main program.
What happens is this:
The micro executes the main program and all the sub-routines and when timer1 rolls-over, the micro marks the next instruction and goes to location 0004.
It carries out the instructions at 0004. At 0004 you can place an instruction to go to isr.  At isr the micro comes to an instruction retfi (return from interrupt). This is the instruction that is placed at the end of the routine and tells the micro to go back the location it marked and continue. This location the micro came from can be in the middle of sub-routine or the middle of a delay routine. It does not matter, the micro will continue with the program.
The maximum length of time for timer1 is 65,536uS or about 0.06 seconds. This can be increased by adding a prescaler of 8:1 making the maximum time approx .52seconds.
The full details of how to set up timer1 to create a 20 second time-delay is shown below.
There are a number of bits in files that must be set and since this is quite complex, the best approach is to copy and past the instructions and add further code to Main and sub-routines.
Start by making sure the instructions below work, then add a few instructions at a time, while checking that everything still works.
Adding an interrupt feature like this is complex and only add a few instructions at a time.

The following program contains the instructions needed to set up Timer1. Some of the instructions are in SetUp and some are in Main.
The micro then goes to a loop in main consisting of nop's and executes these until 20 seconds has elapsed.
The instruction just before the nops in main (
bsf PIE1,0) start the timer incrementing each time the clock ticks over while it is carrying out the instructions in the program. 
The micro executes a program in Main and gets interrupted 39 times and goes to 0004 and isr where it decrements a file and when the file is zero, it executes a set of instructions at isr such as flashing a LED on a display.
You can turn the timer off and turn it on at any time.
 
	
;*******************************
;;Interrupt Routine.asm
;  1-11-2010 
;*******************************

	;for  16F628 microcontroller 
	

	__Config 	_cp_off & _lvp_off & _pwrte_on 
		& _wdt_off & _intRC_osc_noclkout & _mclre_off

	;for 12F629 microcontroller 
			
	 __CONFIG   _MCLRE_OFF & _CP_OFF 
		& _WDT_OFF & _INTRC_OSC_NOCLKOUT 
			

;****************************************************************
; variables - names and files
;****************************************************************


		;Files start at 20h 
 
_20Secs		equ 20h	;file for counting up to 20 seconds

;****************************************************************
;Equates
;****************************************************************
status		equ	0x03
cmcon		equ	0x1F
rp1		equ	0x06
rp0		equ	0x05

z		equ	0x02


;****************************************************************
;Beginning of program
;****************************************************************


Start	org	0x00	;program starts at location 000
	goto	SetUp
	nop		
	nop		;NOPs to get past reset vector address
	org	4
	goto	isr	

SetUp	bsf	status,rp0		
	movlw	b'10000000'; 
	movwf	OPTION_REG	; x000 0000 x=1 = weak pull-ups disabled
	bcf	status,rp0		;select programming area - bank0 	
	movlw	b'00000000'	;6,7=0 disables all interrupts  
	movwf 	INTCON		;until we want timing to commence.	
	movlw	07h		;Turn comparators off 
	movwf	cmcon		
	movlw	.39
	movwf	_20Secs
	goto 	Main					

	
;interrupt service routine		

isr	nop		
	bsf	status,rp0 	;Bank 1				
	bsf	PIE1,0	;,0 1=enables TMR1 interrupt
	bcf	status,rp0	;bank 0 		
	bcf	PIR1,0	;clear TMR1 overflow flag
	bsf	INTCON,7	;This instruction is needed HERE!!!	
	bsf	INTCON,6	;1=enable all peripheral interrupts	
	decfsz	_20Secs,f	;creates 20Sec delay for each game.
	retfie		
	bcf	PIE1,0	;,0 0=disables TMR1 interrupt
	bcf	INTCON,6	;0=disable all peripheral interrupts		
	nop		;put instructions here such as to produce a 
	nop		;digit on a display to show 20 seconds
	nop		;has elapsed.
	goto	SetUp
			
				
;*************************************
;* Main 			*
;*************************************
			
Main			;at the instruction bsf	PIE1,0 timer1 starts 
			;incrementing and the micro goes to 
			;0004 and isr to decrement_20Secs file
			;39 times  39 x .53sec = 20 seconds. 
			

;
;The following instructions start Timer1 to count 39 loops of .53 seconds
;to produce a total delay of 20 seconds. This is done on the background while the 
;main program is being executed: 
;
		
	bsf	status,rp0 	;Bank 1			
	movlw	b'10000000'	; 
	movwf	OPTION_REG	; x000 0000 x=1= weak pull-ups disabled 
	bcf	status,rp0	;bank 0 		
				
	movlw	b'11000000'	;b'11000000'
	movwf 	INTCON		;,0  1=RB port change interrupt flag
				;,1  1=RB0 interrupt occurred
	;bcf	INTCON,2	;1=TMR0 overflowed. Clear overflow flag 
	;bcf	INTCON,3	;1=enable RB port change interrupt
	;bcf	INTCON,4	;1=enable RB external interrupt		
	;bsf	INTCON,5	;1=enable TMR0 overflow (interrupt)
	;bcf	INTCON,6	;1=enable all peripheral interrupts
	;bsf	INTCON,7	;1=enable all unmasked interrupts
				
	movlw	b'00110101'	;b'00110001'			
	movwf	T1CON		;,7  not used
				;,6 0=Timer1 is ON
				;,5,4  11=8 prescale (max) 01=1:2
				;,3 bit ignored
				;,2 This MUST BE SET!!!!!!
				;,1 0=int clock 
				;,0 1=enable timer1 
							
	bcf	PIR1,0		;clear TMR1 overflow flag		
	clrf	TMR1L		;clear the Timer1 low register
	clrf	TMR1H		;clear the Timer1 high register
				;Timer0 is not used 		
				; will go to isr when overflow in TMR1
				;0.52 sec when prescaler=1:8  524,288uS	
		
	bsf	status,rp0 	;Bank 1	(Must use Bank1)	
	bsf	PIE1,0		;,0 1=enables TMR1 interrupt	
	bcf	status,rp0	;bank 0 				
							
Main2	nop		;the micro will loop around these nop's until 20 seconds 
	nop		;has expired.
	nop
                nop		
	goto	Main2

	End	
	

The PIC micro can sometimes do 2 things at the same time, such as produce
3Hz and 23Hz on pins GP4 and GP5 but the instructions can be very long and complex.
The following is a program to produce 3Hz and 23Hz:

	
;*******************************
;;3Hz and 23Hz.asm 
;*******************************
;Producing 3Hz at GP4 and 23Hz at GP5 at the same time.
				
				
				
cycle 
 
	movlw    30h
	xorwf    gpio,1    ;to toggle GP4 GP5 (say ON)
	movlw    .7
	movwf    loops
	call     delay
	call     delay
	call     delay
	movlw    10h
	xorwf    gpio,1    ;to toggle GP4 3.5 times
	decfsz   loops,1
	goto     $-6
	call     delay
	call     delay
	movlw    20h
	xorwf    gpio,1    ;to toggle GP5 for 23Hz (off)
	call     delay
	movlw    10h
	xorwf    gpio,1    ;to toggle GP4 4 times
	movlw    .7
	movwf    loops
	call     delay
	call     delay
	call     delay
	movlw    10h
	xorwf    gpio,1    ;to toggle GP4 7.5 times
	decfsz   loops,1
	goto     $-6
	call     delay
	movlw    20h
	xorwf    gpio,1    ;to toggle GP5 (ON)
	call     delay
	call     delay
	movlw    10h
	xorwf    gpio,1    ;to toggle GP4 8 times
	movlw    .7
	movwf    loops
	call     delay
	call     delay
	call     delay
	movlw    30h
	xorwf    gpio,1    ;to toggle GP4 11.5 times GP5 (off)
	decfsz   loops,1
	goto     $-6
	movlw    .7
	movwf    loops
	call     delay
	call     delay
	call     delay
	movlw    10h
	xorwf    gpio,1    ;to toggle GP4 15 times
	decfsz   loops,1
	goto     $-6
	call     delay
	call     delay
	movlw    20h
	xorwf    gpio,1    ;to toggle GP5 (ON)
	call     delay
	movlw    10h
	xorwf    gpio,1    ;to toggle GP4 15.5 times
	movlw    .7
	movwf    loops
	call     delay
	call     delay
	call     delay
	movlw    10h
	xorwf    gpio,1    ;to toggle GP4 19 times
	decfsz   loops,1
	goto     $-6
	call     delay
	movlw    20h
	xorwf    gpio,1    ;to toggle GP5 (off)
	call     delay
	call     delay
	movlw    10h
	xorwf    gpio,1    ;to toggle GP4 19.5 times
	movlw    .6
	movwf    loops
	call     delay
	call     delay
	call     delay
	movlw    30h
	xorwf    gpio,1    ;to toggle GP4  22.5 times
	decfsz   loops,1
	goto     $-6              
	call     delay
	call     delay
	call     delay
	goto     cycle where GP4 = 23 times and GP5 (ON)



delay    ;7246uS

	movlw    .8
	movwf    fileA
	movlw    .225
	movwf    fileB
	nop
	decfsz   fileB,1
	goto      $-2
	decfsz   fileA,1
	goto      $-4
	retlw    00

This can be simplified by using timer1 to produce the 3Hz and 23Hz while the Main program is performing another task. 

	
;************************************************************************************
;;Interrupt Routine.asm
;Original code written by:  Mosaic Trinidad,W.I.   BSc, Industrial Eng. 







;  1-11-2010
;***********************************************************************************

	;for  PIC12F629 and 16F628 microcontrollers	
		list p=12f629,
		
		__CONFIG _WDT_OFF &_INTRC_OSC_NOCLKOUT
		&_BODEN_ON &_CP_OFF &_PWRTE_ON

W_TEMP		Equ	0x20
STATUS_TEMP	Equ	0x21
Timebase3	Equ	0x22
Timebase23	Equ	0x23

	org 	000 	;reset vector
	goto 	start 	;go to beginning of program

	org  0x004 ;interrupt vector location
	goto isr   ;go to interrupt service routine
	org	0020
;context save - save the value in w and status file
isr	movwf 	W_TEMP 		;copy W to temp register, could be in either bank
	swapf 	STATUS,W 	;swap status to be saved into W
	bcf 	STATUS,RP0 	;change to bank 0 regardless of current bank
	movwf 	STATUS_TEMP 	;save status to bank 0 register

	bcf 	PIR1,0      	; clr Timer1 Int flag
	movlw 	63h		;Timer1 must be loaded with 65536-14493 = 51043
				;refer to converter below to obtain the
				;hex value for tmrL and tmrH = c763	
	movwf 	tmr1L
	movlw 	c7h
	movwf 	tmr1H
;do time base ticks
	incf 	Timebase3,f
	incf 	Timebase23,f
	movlw 	.3 		; test for 1/3 of 69Hz (23Hz)
	subwf 	Timebase23,w
	btfsc	status,z
	goto 	Next_timebase
	clrf 	Timebase23
	movlw 	b'00100000'
	xorwf 	GPIO,f 		;toggle GP5 at 23Hz
Next_timebase;
	movlw 	.23 		;test for 1/23 of 69Hz (3hz)
	subwf 	Timebase3,w
	btfsc	status,z
	goto 	ISRDONE
	clrf 	Timebase3
	movlw 	b'00010000'
	xorwf 	GPIO,f		;toggle GP4 at 3Hz

ISRDONE; restore context
	swapf 	STATUS_TEMP,W	;swap STATUS_TEMP into W, bank to original state
	movwf 	STATUS 		;move W into STATUS register
	swapf 	W_TEMP,F 	;swap W_TEMP
	swapf 	W_TEMP,W 	;swap W_TEMP into W
	retfie			;return to Main from interrupt
	

start
	clrf 	GPIO 		;Init GPIO
	movlw 	07h 		;Set GP<2:0> to
	movwf 	CMCON 		;digital IO
	bsf 	STATUS,RP0 	;Bank 1
	movlw 	b'00001111' 	;Sets inputs and outputs
	movwf 	TRISIO 		;
	bcf 	STATUS,RP0 	;Bank 0

;Setup Tmr1 interrupt

; 1000,000/69 = 14493 ticks required for interrupt for a 69Hz base.
; 65536-14493 = 51043 => preload this into TMR1L/H for 14493 ticks for interrupt.
	movlw 	63h
	movwf 	tmr1L
	movlw 	c7h
	movwf 	tmr1H
	bsf	status,rp0 	;Bank 1	(Must use Bank1)	
	bsf	PIE1,0		;,0 1=enables TMR1 interrupt	
	bcf	status,rp0		;bank 0 				
	bsf 	INTCON,6 		;peripheral interrupt enable
	bsf 	INTCON,7 		;generate interrupt enable.
	movlw 	b'00000101' 	;timer1 setup bits, with 1:1 prescale
	movwf 	T1CON		;start timer1 running on a 1,000,000 ticks/sec
				;filling TMR1L, TMR1H (65536)before interrupt occurs
	goto	Main

Main	nop
	goto Main	;loop until interrupt occurs

	END
 

1/11/10