PIC16F628A Test Setup.
Fig. 1
Click here for larger image.


Microchip PIC16F628 Assembly Code Programs Tutorial

by Lewis Loflin


In this section we will explore how to use the Microchip PIC mostly the 16F628A. While the previous section on the PIC18F2550 was written in C, here I'll use only assembly language.

On issues with TMR0, PORTB pullups, and interrupts the PIC16F628A is similar to the PIC16F84A.

This is built on earlier sections. See the following

PIC16F628A Digikey $2.74, Mouser $3.07, and $2 ea. Ebay. For pin connections and specs see image pic16f84a_pic16f628a.jpg. The PIC6F628A is a major upgrade to the PIC16F84A and more complex. For the novice is harder to learn.

Related YouTube Video: Home Built PIC Dev. Board.

Why assembly? It's produces fast and efficient coding over C for basic functions related to electronics control. This enables one to really access the powerful features of the PIC. As a RISC processor it has only 35 instructions to learn. They operate at the register and bit levels.

These were developed using MPLAB v8.92.

The projects concentrate on using the PIC16F628A that has the following features:

And so much more. While 2048 bytes may not sound like much, most of the demos used more than 75 bytes! That includes operating a bipolar stepper motor and reading an external analog to digital converter, which the 16F628A lacks. The 12F683 has 4 ADC channels, but only six IO pins. (8 pins total.)

PICs utilize the Harvard architecture in which instructions and data operate on separate sources, which simplifies timing and microcircuit design. While they can be programmed in circuit, I used a separate programmer and a ZIP socket in my home built development board.

External Crystal or Internal RC Oscillator?

The PIC16F628A has an internal 4 mHz. and 38kHz. oscillators meaning no need for an external crystal. But there some issues to discuss. Oscillator base or Fosc is divided by 4 to create the execution clock cycle. Most commands use 1 clock cycle, branches use 2 clock cycles.

A 16 megahertz crystal is divided by 4 to 4mHz. The cycle time is 0.250 uSecs or 250 nano seconds. For a 4mHz crystal, 1 uSec.

There is a choice for a 4mHz internal oscillator, 38kHz internal oscillator, or faster 16mHz, etc. external crystal, etc.

With the __CONFIG line one has the following choices:

Use _HS_OSC for a 16 mHz ext crystal.

Use _XT_OSC for 4 mHz ext crystal. Page 95 in spec sheet.

Use _FOSC_INTOSCIO for Internal 4 mHz osc and no ext reset, MCLR pin RA5 is input only.

But to use 4mHz or the internal 38KhZ oscillator the PCON register (power control register bank 1, 8Fh) bit 3 must be set 1 = 4mHz, or 0 = 38 kHz.

Note PCON bit 3 can be cahnged under software control to switch to low-power operation.

This defaults to 38kHz and was fit to figure out. Most PIC spec sheets are poorly written for the novice. 38kHz is used for low power applications.

Software Delay Loops

The program below covers software delay loops. Whether using internal or external Fosc some tuning is desired. Note the following two short code snippets.

The first is a simple toggle LED function using XORWF that loads the W register with 2, then XORs W with PORTB bit 1 (RB1). This toggles the state of the LED on RB1 with every cycle, 2 cycles creates a complete square wave.

Each cycle or iteration jumps to the 1mSec. delay routine. 1,000 iterations creates a 500Hz square wave measured on a frequency country. This assumes a 4mHz Fosc clock frequency that when divided by 4 is 1uSec.


main

	movlw 0x02
	xorwf PORTB, f
	call delay1ms
	goto $-3

goto main

;**************************	;Delay routine.
; Calculating a 1mSec delay. 4mHz is divided by 4
; At 4mHz / 4 = 1uSec. ;  1uSec. * 1000 = 1 mSec.
; GOTO uses 2 cycles, DECFSZ 1 cycle = 3 cycles or 3uSec.
; 3 * ~83 * 4 = ~ 1000uSec. or 1mSec.
; Adjust CNT2 for 500 Hz on RB1 LED.

; For 16mhz CNT1 = 0x07, CNT2 = 0xBC.

delay1ms
	; 4 mhz crystal
	movlw d'4'
	movwf CNT1
	movlw d'83' ; adjust for 500Hz test
	movwf CNT2
	decfsz CNT2, f
	goto $-1 ; count 82 * 3
	decfsz CNT1, f
	goto $-5 
	return


;*********************************************  
; Filename: 16F628A_PWM.asm 
; Uses PIC16F628A
; Date: 13 Nov. 2013      
; Author:  Lewis Loflin
; http://www.bristolwatch.com
; http://www.bristolwatch.com/PIC16F628A/a7.htm
; Delay routines based on 4 mHz Fosc / 4 = 1uSec.
; LED1 on RB1 blinks 1Hz, PWM LED on RB3 off to bright to off.
; PWM output PORTB, 3 
;*******************************************

list      p=16f628A           ; list directive to define processor
#include <p16F628A.inc>      ; processor specific variable definitions
errorlevel  -302              ; suppress message 302 from list file

__CONFIG _CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC 
; single line do not press return on keyboard.


; Use  _FOSC_INTOSCIO  for
; Internal 4 mHz osc and no ext reset, MCLR pin RA5 is input only.
; Internal RC OSC PCON bit 3 must be set
; 1 = 4mHz, 0 = 38 kHZ

; Use _HS_OSC for a 16 mHz ext crystal.
; Use _XT_OSC for 4 mHz ext crystal. Page 95 in spec sheet. 


;-------------------------- counters	
;*****[ Data Storage Reg's ]*****
	; Assign each reg. from Bank 0 RAM area.
	; total 96 bytes from 0x20 - 0x7F
	CBLOCK  0x20 
	B0
	B1
	B2
	temp1
	temp2
	CNT1
	CNT2
	CNT3
	CNT4
	ENDC ; Conclude Bank 0 RAM assignments.


	ORG     0x000             ; processor reset vector
	goto    setup             ; go to beginning of program

setup ; init PIC16F628A

;************************************************************
	; PWM calculator www.micro-examples.com
	; 4 mHz. clock.
	; PR2 = %11111001 'Timer2 Module Period Register - Bank 1
	; rest bank 0
	; T2CON = %00000101  
	; P52, Bits 6-3 postscaler, 0000 = 1:1
	; Bit 2 TMR2ON, 1 = ON, 0 = OFF
	; Bits 1-0 prescaler value 01 = 1:4
	; CCPR1L = %0  ' duty cycle 0-255
	; CCP1CON = %00001100  'CCP1 control register 
	; Bits 3-0 CCP mode select, 110x =  PWM active high
	; Bits 5-4 PWM LSB
	; Bits 7-6 unused
	
	; Set for 1,000 Hz.
	BANKSEL 1 ; Bank 1
	MOVLW B'11111001'
	MOVWF PR2
	BANKSEL 0 ; Back Bank 0
	MOVLW B'00000101'
	MOVWF T2CON
	MOVLW 0 ; duty cycle
	MOVWF  CCPR1L ; duty cycle 0-255
	MOVLW B'00001100'
	MOVWF CCP1CON  
	
;*************************************************************
	; Setup TRIS DDR register and PCON register, PORTB pull ups.
	BANKSEL OPTION_REG          ; Switch to Bank 1.
	MOVLW b'111111' ; input
	MOVWF TRISA ;
	MOVLW B'11110001'
	MOVWF TRISB 
	; Setup PCON bit 3, 
	; 1 = 4mHz, 0 = 48kHz
	MOVLW b'00001000'
	MOVWF PCON
	
	; pull ups
	BCF OPTION_REG, 7 ; turn on PU, 1 = off, 0 = on
	; pull ups disabled if pin is output.
	; No WPU individual pins as in PIC12F683
	
;*************************************************************
	; Voltage refernce moodule test.
	; Make sure +5V supply VDD is accurate.
	; VREF control VRCON 9Fh,  P69
	; Check TRISA bit = 1
	; 1. VREF=ON, RA2 out, high range, <3:0> = 0, VOUT = 1.25V
	; 2. VREF=ON, RA2 out, low range, <3:0> = 15, VOUT max = 3.125V
	movlw b'11101111' ; measure 3.125V on RA2
	movwf VRCON
	; bit 7 VREN, 1 = on, 0 = off 
	; bit 6 VROE, 1 = ouput RA2, 0 = no output
	; bit 5 VRR,
	; 1 = low range VREF = (VR<3:0> / 24) * VDD
	; 0 = high range VREF = 1/4 * VDD + (VR<3:0>/ 32) * VDD
	; bit 4 XX
	; bits 3-0 = 0-15
	
	BANKSEL PORTB  ; Switch to Bank 0.
	MOVLW   0x07  ; comp off
	MOVWF   CMCON  
	CLRF    PORTB  	   

	goto main

main
; remaining code goes here

; Demo 1
; 1mSec. delay calibrate.
; Freq. counter attached to LED1 on RB1.
; Should measure 500Hz. Adjust CNT2 value
; if needed for 500Hz on LED1.
; 1 cycle generated every 2 interations.
; Uncomment following to measure freq. 

;	movlw 0x02
;	xorwf PORTB, f
;	call delay1ms
;	goto $-3



; Demo 2
; CCPR1L is 8-bit PWM duty cycle reg. 0-255.
; RB3 is PWM output to LED2 to GRD.
; LED2 on pin RB3 goes from off to bright in steps.
; Clear PWM register CCPR1L, LED2 = OFF
; Flip state of LED1 RB1 with XORWF
; W = 50, call delay Wx10ms = 500mSec. 
; 2 loops = 1 Hz. rate on LED1 RB1
; Every loop 20 ADDed to CCPR1L reg.
; LED2 gets brighter
; Every 1Hz 40 is ADDed to PWM CCPR1L
; Check STATUS bit C
; Exit loop if C = 1, C = 0 back aa
; Repeat until STATUS C bit = 1.
	clrf 	CCPR1L
aa	movlw 0x02
	xorwf PORTB, f
	movwf d'50' 
	call Wx10ms ; LED ON 0.5 sec.
	movlw d'20'
	addwf CCPR1L, f
	btfss STATUS, C ; check carry
	goto aa

; CCPR1L is 8-bit PWM duty cycle reg. 0-255.	
; RB3 is PWM output to LED2 to GRD.
; LED2 on pin RB3 goes from bright to off in steps.
; PWM register CCPR1L = 255, LED2 on RB3 is bright
; Flip state of LED1 RB1 with XORWF
; W = 50, call delay Wx10ms = 500mSec. 
; 2 loops = 1 Hz. rate on LED1 on RB1
; Every loop 20 SUBed from PWM CCPR1L reg.
; LED2 get dimmer
; Every 1Hz 40 is SUBed from PWM CCPR1L
; Check STATUS bit C for borrow
; Exit loop if C = 0, C = 1 back  bb
; Repeat until STATUS C bit = 0.
	movlw d'255'
	movwf CCPR1L
bb	movlw 0x02
	xorwf PORTB, f
	movwf d'50' 
	call Wx10ms ; LED ON 0.5 sec.
	movlw d'20'
	subwf CCPR1L, f
	btfsc STATUS, C ; check borrow
	goto bb	
	
	goto	main 

;**************************	;Delay routine.
; Calculating a 1mSec delay. 4mHz is divided by 4
; At 4mHz / 4 = 1uSec. ;  1uSec. * 1000 = 1 mSec.
; GOTO uses 2 cycles, DECFSZ 1 cycle = 3 cycles or 3uSec.
; 3 * ~83 * 4 = ~ 1000uSec. or 1mSec.

delay1ms
	; 4 mhz crystal
	movlw d'4'
	movwf CNT1
	movlw d'83' ; adjust for 500Hz test
	movwf CNT2
	decfsz CNT2, f
	goto $-1 ; count 82 * 3
	decfsz CNT1, f
	goto $-5 
	return


delay10ms
	movlw d'10'
	goto $+2
Wx1ms	; W * 1mSec.
	movwf CNT3
	call delay1ms
	decfsz CNT3, f
	goto $-2
	return


Wx10ms	; W * 10mSec.
	movwf CNT4
	call delay10ms
	decfsz CNT4, f
	goto $-2
	return

	END  ; directive 'end of program'



See How I got into Electronics

Bristolwatch.com banner.

Web site Copyright Lewis Loflin, All rights reserved.
If using this material on another site, please provide a link back to my site.