You are on page 1of 47

3 channel IR remote control

This project is a 3-channel IR remote control with 3 output


relay and easy to build.
Feature :

CPU PIC12F629 at 4MHz crystal for Tx/Rx


3 channel output relay
The Tx use sleep mode for saving battery power
Use Phillips RC5 protocal
distance more than 7 m.
Easy circuit to build and assembly
small components

Basic RC5 protocal


The RC5 is probably the most used by hobbyists, probably because the wide availability of
cheap remote controls and
easy to understand.
Feature :

2 start bit always "1"


1 toggle bit but this project not use and always "0"
5 bit address and 6 bit command length
Bi-phase coding (aka Manchester coding)
Carrier frequency of 36kHz 25-50% duty cycle
Bit time period about 1.67 ms
Developt by Philips

The protocol uses bi-phase modulation (or Manchester code) of


a 36kHz IR carrier frequency. All bits are of equal length of about 1.67 ms as follows figure.

Figure 1. RC5 Modulation

Figure 3. Bi-Phase coding

In figure 2,the first two pulses are the start pulses, and are both logical "1". (St1 and St2)
The 3d bit is a toggle bit. This bit is inverted every time a key is released and pressed again.
But this project not use this bit
and always "0" (Ctrl)
The next 5 bits represent the IR device address, which is sent with MSB first. (S0-S4)
The next 6 bits is command and sent with MSB first too.(C0-C5)
Note that a RC5 frame consists of a total of 14 bits so the total
time is about 23 mS

RC5 detecting
When the detect subroutine is called, it first waits for a start bit. The length of the low part of
the first start bit is measured. If the low pulse of first start bit is longer than 1.020 ms or less
then 800 uS the routine returns indicating error or no
command received.

Figure 4. Synchronizing and Sampling of the Data

The measurement of the start bit is used to calculate two reference times, ref1 and ref2, which
are used when sampling the data line. The program uses the edge in the middle of
every bit to synchronize the timing. 3/4 bit length after this
edge, the line is sampled. This is in the middle of the first half
of the next bit (see Figure 4).The state for each bit is stored and the routine waits for the
middle edge.

Tx schematic

The TX use 8 pin PIC devices, here is PIC12F629 run at 4 MHz


crystal. Actualy, this device has 4MHz RC internal oscillator but
not suitible for use with the project that need cirtical time as
remote control.The 36KHz carrier and information bit generated by IC1.For saving power
when use with battery powered we
need to use this device in sleep mode when any keys not
pressed and draw current <1 mA at 4MHz, 5.5V .

Example how to wake-up from sleep mode when key pressed.


main :

SLEEP
BTFSS
GOTO
BTFSS
GOTO
BTFSS
GOTO
GOTO

CH1
Do_CH1
CH2
Do_CH2
CH3
Do_CH3
main

Rx schematic

The IR was recieved from Tx will demodulated by IC2 that is IR receiver Modules for
Remote Control Systems.In this project I
use TSOP4836 from Vishay Semiconductors that is one of TSOP48XX series. After IR
demodulated it was decoded the protocal by IC1 then turn on/off appropiate channel.The out
out of IC1 is toggle every time when Tx send the same command to Rx.You may be change
the output drive circuit for
suitible with your load.The pin 3 of IC1 must pull-up to vcc with
R10K becuase it is not has weak-up internal pull-up.

RC5 Basics

Introduction
The RC5 protocol was developed by Philips as consumer IR (infrared) remote control
communication protocol for consumer electronics.
Data Format
The RC5 code is 14 bits long. Each code includes 2 start bits, 1 toggle bit, a 5 bit address (or
system) and a 6 bit command. This allows for 32 systems (like TV, CD, video, etc.) and 64
commands per system.

The two start bit indicate the start of the RC5 frame.
Note:
After some time 64 commands per system didn't seem to be enough though, so an extra
command bit was added to allow 128 commands. To maintain backward compatibility with
the standard RC5, the format itself was left unchanged. The second start bit (S2) was replaced
by C6. The resulting format is called Extended RC5.
The toggle bit T changes each time a new command is transmitted. It allows detection if the
same key is pressed twice. Since a code is being sent as long as the key is pressed, a short
release of the button and again pressing it again would otherwise not be recognized.

The address bits A5..A0 specifies the system (or device) the command shall be sent to, e.g.
TV, CD, Video, etc.
Finally, the command bits specify the command to be performed.
Modulation
RC5 uses Manchester coding. Manchester coding has a transition in the middle of a bit.
A logical 1 is coded as a 0 in the first half of the bit and a 1 in the second half of the bit.
A logical 0 is coded as a 1 in the first half of the bit and a 0 in the second half of the bit.

Important hint:
Most of the IR-Receivers (e.g. the SFH5110 or TSOP1736) have an inverted output! So a
logical 1 at the output of the IR-Receiver will be represented by a 1 in the first half of the bit
and a 0 in the second half, a logical 0 will be represented by 0 in the first half of the bit and a
1 in the second half.
RC5 Example
In the example below an example of an RC5 code which shows how the information is coded.
In this example the toggle bit is 0, the address is also 0 and the command is 9, i.e. key '9' has
been pressed.

Hardware

As IR-Receiver I used a SFH5110-36 which is a IR-Receiver for Remote Control Systems.


Also other IR-Receivers like, a SFH506-36 or TSOP1736 will work. Important is that the IR-

Receiver is designed for a carrier frequency of 36kHz (which is the carrier frequency used by
RC5).
The interface to the PIC microcontroller is very simple, the output of the IR-Receiver just
needs to be connected to an "interrupt on-change" pin. I used a PIC16F886 where port B has
"interrupt on-change" capability, so I connected it to port pin RB1. Further I also added a
pull-up resistor (according to the datasheet this is optional).

Software

The RC5 software driver is written in C language and currently is compatible to CCS C
compiler and Microchip C18 compiler.
Decoding
The decoding happens in the interrupt service routine of the "on-change" interrupt of port B,
i.e. every time the logic level on the pin changes the decoding is done. As time base for the
decoding a free running hardware timer of the microcontroller is used, so the timer can also be
used for other things. In my demo application, I used timer 0 of the PIC which is configured
to increment every 25.6us. The resolution of 25.6us provides enough accuracy for decoding
the RC5 signal (a half bit is 889us long). Timer 0 is a 8 bit timer, with a timer increment every

25.6us an overflow will occur every 25.6us * 256 = 6553us. Since the bit length is 1778us
which is (much) smaller than the timer overflow time this configuration is ok for decoding the
RC5 signal.
RC5 Driver Configuration
To use the RC5 driver in your projects, the following things need to be configured.
First of all, the pin where the IR-Receiver is connect needs to be specified via the #define
RC5_DATA_PIN. In the demo I used RB1. I.e. PIN_B1 needs to be replaced by the pin
where the IR-Receiver is connected to. Important is that the pin which shall be used has "onchange" interrupt capability!
#define RC5_DATA_PIN
connected to RB1 */

PIN_B1

/* IR sensor (SFH5110-36)

Since a hardware timer is required as time base for decoding the RC5 signal, the driver needs
to know how often the timer is incremented per millisecond. In my example timer 0 is used
which is configured to increment every 25.6us, hence it will increment 1000us/25.6us = 39
times per 1ms (1000us).
#define RC5_TICKS_PER_MS
(1000/26)
25.6us, */
/* i.e. around 39 ticks per millisecond */

/* timer increments every

The driver also needs to know which timer is used or to be more precise how to get the
current timer value. To achieve this, the macro RC5_GetTimer() needs to be defined. This
macro shall return the current timer value. In the demo I used timer 0, hence it is configured
to "get_timer0()" which is a CCS built in function which returns the timer 0 register value.
#define RC5_GetTimer()
decoding */

get_timer0()

/* timer0 shall be used for RC5

Since the RC5 driver is no properly configured, we have to include the RC5 driver itself.
#include "rc5.h"

/* RC5 driver include */

Now we need to add the interrupt handler which calls the RC5 decoding function of the RC5
driver. The decoding function is RC5_InterruptHandler().
/**************************************************************************
***/
/* Interrupt_RB
*/
/*
*/
/* Port B change interrupt service routine.
*/
/* Used to decode RC5 IR signal.
*/
/**************************************************************************
***/
#INT_RB
void Interrupt_RB(void)

{
RC5_InterruptHandler();
clear_interrupt(INT_RB);
}

And finally, we need to configure the timer 0 which will be the time base for the RC5
decoding function and enable the "on-change" interrupt.
/* FOSC/4 is timer source */
/* FOSC = 20MHz => 5MHz, i.e. timer increment every t = 1/(FOSC/4) = 200ns
*/
/* with prescaler of 128 timer will increment every 25.6us */
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
/* configure port B interrupt on change */
set_tris_b(0xFF);
/* all pins on port B are input */
input_b();
/* read port B to clear mismatch condition
*/
clear_interrupt(INT_RB);
/* clear port B interrupt flag */
enable_interrupts(INT_RB1);
/* enable RB1 interrupt on change */
/* global interrupt enable */
enable_interrupts(GLOBAL);

RC5 Decoder Demo Application


Here a full demo application showing the RC5 driver usage. A full CCS C project and
Microchip C18 project can be downloaded in the Download section below.
The following explainations are done based on the CCS C project, but are very simialr for the
C18 compiler.
/*** FILEHEADER
****************************************************************
*
*
FILENAME:
rc5demo.c
*
DATE:
26.07.2011
*
AUTHOR:
Christian Stadler
*
*
DESCRIPTION: RC5 demo which shows usage of RC decoder driver.
*
***************************************************************************
***/
/* make compiler case sensitive */
#pragma case
#include
#include "types.h"
/* --- RC5 driver configuration --- */
#define RC5_DATA_PIN
PIN_B1
/* IR sensor (SFH5110-36)
connected to RB1 */
#define RC5_TICKS_PER_MS
(1000/26)
/* timer increments every
25.6us, */
/* i.e. around 39 ticks per millisecond */
#define RC5_GetTimer()
get_timer0() /* timer0 shall be used for RC5
decoding */
#include "rc5.h"
/* RC5 driver include */
/* --- macros to switch on/off LED --- */
#define Led_On()
output_high(PIN_A0)
#define Led_Off()
output_low(PIN_A0)

/**************************************************************************
***/
/* Interrupt_RB
*/
/*
*/
/* Port B change interrupt service routine.
*/
/* Used to decode RC5 IR signal.
*/
/**************************************************************************
***/
#INT_RB
void Interrupt_RB(void)
{
Led_On();
RC5_InterruptHandler();
clear_interrupt(INT_RB);
Led_Off();
}
/**************************************************************************
***/
/* main
*/
/*
*/
/* Configures timer0 as time base for RC5 decoding and enables port B
*/
/* interrupt on change.
*/
/* Main loop checks if a RC5 code has been received and writes the code
*/
/* to the RS232 interface.
*/
/**************************************************************************
***/
/* NOTE: Currently it only works if PIC is reset after programming? */
void main()
{
uint16 rc5code;
/* FOSC/4 is timer source */
/* FOSC = 20MHz => 5MHz, i.e. timer increment every t = 1/(FOSC/4) = 200ns
*/
/* with prescaler of 128 timer will increment every 25.6us */
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
/* configure port B interrupt on change */
set_tris_b(0xFF);
/* all pins on port B are input */
input_b();
/* read port B to clear mismatch condition
*/
clear_interrupt(INT_RB);
/* clear port B interrupt flag */
enable_interrupts(INT_RB1);
/* enable RB1 interrupt on change */
/* global interrupt enable */
enable_interrupts(GLOBAL);
printf("**** RC5 Demo started! **** \n\r");
while(TRUE)
{
/* check if new data is available */
if (RC5_CodeReady())
{
/* get code */
rc5code = RC5_GetCode();

printf("RC5 Code=0x%04LX DevAddr=0x%02X Toggle=%d Cmd=0x%02X\n\r",


rc5code,
RC5_GetDeviceAddr(rc5code),
RC5_GetToggleBit(rc5code),
RC5_GetCmd(rc5code));
}
/* this function increments the RC5 timeout timer */
/* NOTE: Decoding will also work without calling this function, but */
/*
it could happen that RC5 codes are sometimes not getting */
/*
recognized because of decoding state machine stucks due */
/*
to erroneous RC5 signal. */
RC5_TimeoutIncrement();
}
}

Chapter 1

Chapter 2

Chapter 3
P1

P2 P3

Disassembler

Soldering and using a prototype PC board


PIC12F629 Data Sheet (.pdf 4,926KB)
PIC12c508A Data Sheet (.pdf 1,600KB)
Instruction Set for PIC12F629
blank12F629.asm template
Notepad2.zip Notepad2.exe
PIC12F629.asm Chip as a "D" flip flop
Library of Sub-routines "Cut and Paste"
Library of routines: A-E E-P P-Z
PIC12F629 Project: 2-Digit Counter
PIC12F629 Project: 20 LED Display-1
10 Projects using the PIC12F629
12 FREE PIC Books Simply download the books via Rapidshare.
Lots of PIC micro information on this website.

You may be asking "Why do I use a PIC chip?" The answer is simple. There is nothing else.
Let me fill you in. I have been developing a range of modules similar to the talking modules
and music chips in greeting cards. But these "sound" cards are so prosaic. The tunes are
frightful and the speech is quite unfunny.
For a person like me, who has never bought a card in his life, it is unusual to be designing
electronic cards.
Possibly because most of the cards on the market "fall between two stools," I have decided to
design something that is a pleasure to give.
I don't like gaudy, over-designed images or wording that doesn't fit the occasion. For that
reason the cards I have designed are simple and uncluttered.
But more important, they contain an electronics module that delivers a concept that has never
been produced.
For a few extra dollars you get a card that contains a gift that can keep the recipient happy for
the afternoon.
Some of the ideas for the modules include a Reaction Timer, a "sky writer that produces
words in the air, a 20 second timer, a game of NIM and a decision-maker.

All the circuits are designed around an 8-pin microcontroller - the PIC12F629.
At first glance this chip seems to be too expensive, at about 60 cents, and I was steered in
the direction of the ATMIL TTtiny11. But it was soon realised this chip was going out of
production and the ATtiny12 was heading the same way. The next chip in the range was
ATtiny13 but the cost was higher than the PIC chip and I would have to transport my code as
well as suffer a slightly reduced output drive current.
Then MicroChip came to the rescue with a special chip for production-runs. Not only was it
cheaper but it had additional features above the PIC12F629. The only reductions on the '629
are 2-stack (instead of 8), fewer registers and in different locations (that's why you use the
"equ" statement), and no EEPROM (so data is lost when the chip is turned off). But the plusvalues include an Analogue to Digital Converter and a precision voltage reference.
I also tried all the other manufacturers and nothing similar in price was available.
So, the decision is made and the supply is guaranteed for quantities of 100,000.
If you are thinking of designing anything for the mass-market, email me before starting
anything so you don't waste time searching in the wrong direction as there are chips that are
not available to the consumer market.
Before reading this article, go to ICP article. It shows how to solder a surface-mount or
through-hole PIC12F629 to a PC board with a programming socket that will accept In-Circuit
Programming. Use the kit on the ICP page to write your first program. The article also shows
how to use the PICkit-2 USB programmer.

In a nutshell, the simplest PIC chip is the PIC12C508. The


PIC12C509 has twice the memory but both are only
programmable ONCE. This type of chip is now HISTORY. We
don't use them any more.
The replacement is the PIC12F629. If you want analogue inputs,
the chip to use is the PIC12F675,
None of these chip has a low-voltage programming feature.
For low-voltage in-circuit serial programming use PIC16F628.
The PIC12F629 comes in:

8-pin
(through
hole)
8/PDIP

8-pin SMD
(surface mount)
PIC12F629-I/SN
8/SOIC package

SOIC = SOP = SMD IC = 050 (1.27mm) spacing.


SOIC - pins are bent slightly at PC board
SOP - pins are flat when touching PC board

Before we start:
Although the PIC12F629 is an up-grade of the PIC12C508 and '509, the program from a
PIC12C508 cannot be transferred directly to a PIC12F629 as there are a number of
differences between the two chips. The following items cover some of the differences.

1. The CALL Instruction


The CALL instruction for a PIC12C508,9 only works to the first 256 locations.
The CALL instruction for a PIC12F629 accesses ALL MEMORY.

2. The STACK
The PIC12C508A has only a 2-CALL stack.
The PIC12F629 has an 8-CALL stack. (8-level stack).

3. The In/Out Port


The IN/OUT port on a PIC12F629 is file 05h. This port corresponds to pins 7, 6, 5, 4, 3, and 2
for GP0, GP1, GP2, GP3 GP4 and GP5.
Remember: GPIO,3 (GP3) (pin 4) is an INPUT-ONLY pin.
When writing a program, use GPIO,0 GPIO,1 GPIO,2 GPIO,3 GPIO,4 GPIO,5 in your
program and the compiler will do the rest. (GPIO = General Purpose Input/Output).
For instance, If you want to SET (make HIGH) pin 7, you must do two things:
1. Make sure GPIO,0 is an OUTPUT bit by making the corresponding bit in the TRISIO
register "0." This is done via the following instructions: Remember: "0" = output, "1" = input
bsf
status, rp0
;bank 1
movlw b'xxxxxxx0' ;(x= don't care = does not matter)
movwf TRISIO
;the lowest bit will be an OUTPUT
bcf
status, rp0 ;bank 0
2. Make the lowest bit of the output port = 1 (HIGH). This is done via the following instruction:
bsf

GPIO,0

Do not set more than one bit at a time in the GPIO (in/out) port. In other words, do not create
two instructions such as:
bsf
bsf

GPIO,0
GPIO,2

If you need to clear or set two or more output lines, perform the operation via a single
instruction, thus:
movlw b'xxxxx1x1'
movwf GPIO
You need to know the state of all the outputs and include this in the value you are going to
load into GPIO via movlw b'xxxxxxxx' etc.
As can be seen from the above, the six lower bits of file 05 are connected to 6 pins of the chip

to connect the microprocessor to the outside world. This file is like all the other files (from
20h to 5F - 64 files) as it can be operated-upon (incremented, decremented, shifted left or
right, plus the other operations). The only difference is the contents of file 05 can be exported
to the outside world and the outside world can influence the file. When any of the bits of file
05 are configured as "out," the value of the bit will make the corresponding pin of the chip
either HIGH or LOW. When it is "set" (=1), the pin will be HIGH. When it is "clear" (=0), the
pin will be LOW.

READING AN INPUT LINE


When any of the bits of file 05 are configured as "input," (this is done via the TRISIO
instruction) the HIGH or LOW on the pin of the chip (this HIGH or LOW will be created by
something in the outside world making the line HIGH or LOW) will be read by the micro as a
HIGH or LOW, (when the file is read via an instruction such as btfss GPIO,1 or btfsc GPIO,1 bit test1 in file 05h, skip if set or bit test1 file 05h, skip if clear).
This "reading process" can also be done when the contents of file 05 (GPIO) is moved to W.
The instruction to do this is movf 05h,0 This instruction tells the micro to move the in/out port
to the working register. The working register is called "W" and has the destination "0" - a file
has the destination "1." The contents can also be shifted, incremented, plus other
instructions.
Here are some instructions to read the input bit:
In most cases, the first bit (or line) to use in a program is pin 4 as this line is INPUT ONLY. It
corresponds to GPIO,3.
Using the instructions from above, we have GPIO,3 as an INPUT and all other lines are
OUTPUT.
We are looking for a HIGH on the input line.
To read the bit, use the following instructions:
btfsc GPIO,3 ;This will test the input bit and if it is LOW, the micro goes to movlw xx
GOTO PhaseA ;This instruction takes the micro to a new sub-routine
movlw xx
If you don't know the state of some of the bits (or don't want to alter them - by mistake), you
can use the XOR instruction.
For example, to turn ON bits 0, 1 and 2, the instructions can be:
bsf GPIO,0 b'00000001'
bsf GPIO,1 b'00000010'
bsf GPIO,2 b'00000100'
But this will result in only the third instruction being carried out. We mentioned above, not to
use multiple bit-setting as it will fail to work.
The answer is to use the XOR instruction
Combine the 3 instructions to get: b'00000111'
movlw 07h
xorwf GPIO
Only the three lowest outputs will go HIGH.
To turn OFF the three lowest outputs, repeat the same instructions:
movlw 07h
xorwf GPIO
Only the three lowest outputs will go LOW.
Actually, the bits will TOGGLE.
The in/out port (file 05h for PIC12F629) is shown in RED in the following map. It is called
GPIO:

Voltage on an Input line


Most input lines are classified as TTL and the voltage must be above 2v (for 5v rail) for the
chip to detect a HIGH. GP2 is Schmitt Trigger input a it TMR0 clock input. This line requires
2.5v to detect a HIGH and 1.75v to detect a LOW. The TTL input have a very small gap
between HIGH and LOW and to make sure the input line detects correctly, the input voltage
must be much higher or much lower than the detection-point.

4. Reading the Input Port


To read the individual pins of the input port of a PIC12F629, use one of the following
instructions. (GPIO,3 (GP3) (pin 4) is an INPUT-ONLY pin and this pin is the first to use.
If the input pin is normally low and goes HIGH when a signal is sent to the micro, use one of
the following:
btfsc 05h,0 (This the same as: btfsc GPIO,0)
btfsc 05h,1
btfsc 05h,2
btfsc 05h,3 - this is pin 4 - GPIO,3 - use first in your program
btfsc 05h,4

btfsc 05h,5
The next instruction will be:
goto task1 - input has been detected
It may be difficult to read the same input bit further down a program.
This is solved by setting and clearing the bit, thus:
bsf
bcf
nop
bsf
bcf

status, rp0
TRISIO,0
TRISIO,0
status, rp0

;Bank 1

;bank 0

5. The General Purpose Files - called GPR's (General Purpose Registers)


The General Purpose Files are the files you use in your program for sub-routines such as
delays, comparison, incrementing, decrementing, etc. A program can start by loading a value
into GPIO and outputting it to the outside world (such as a LED). A value (called a literal) is
loaded into a file (a General Purpose File) and decremented until it is zero. This allows the
LED to be viewed.
In the diagram above, you can see the 25 General Purpose Files in a PIC12C508/9 do not
match up with the 64 files in a PIC12F629.
This means any program written for a '508 will not work in a PIC12F629.
The solution is to add 20h to the files that have been used in a '508 program to move them so
they align with the PIC12F629 files.
The following table shows the result:

Old
'508
file:

for '629
Change
to:

07h

27h

08h

28h

09h

29h

0Ah

2Ah

0Bh

2Bh

0Ch

2Ch

0Dh

2Dh

0Eh

2Eh

0Fh

2Fh

10h

30h

11h

31h

12h

32h

13h

33h

14h

34h

15h

35h

16h

36h

17h

37h

18h

38h

19h

39h

1Ah

3Ah

1Bh

3Bh

1Ch

3Ch

1Dh

3Dh

1Eh

3Eh

1Fh

3Fh

6. Incrementing a File
When incrementing a file such as:
incf 2Ah,1
The result is placed in the file and the working register "W" is not affected.
With the instruction:
incf 2Ah,0
only the working register "W" contains the result. In other words, the file is
NOT INCREMENTED!!!
With the instruction:
incf 2Ah
the assembler assumes ",1" and increments the file. But it is best to always include the
directive.
In the above, W=0 and f=1 where W is the working register and f is the file being
incremented.

7. Current of an Output Line


The maximum current of an output line is 25mA. In the following diagram, no current-limiting
resistors have been included and the current through the red LED will be more than 25mA as
the voltage across the LED is 1.7v and theoretically the current will be as high as the battery
can deliver. The chip will provide some current-limiting but the flow will be higher than 25mA
and the chip may be damaged.

Two 47R resistors are needed as shown in the schematic below:

8. Driving a LOAD
The output current of each line of a microcontroller is very small. It is only 25mA. The only two
items that can be driven directly from an output are a LED and a mini piezo diaphragm.
The following diagram shows how these items can be connected (interfaced).

For a current greater than 25mA, a transistor will be needed. A transistor will be able to
deliver about 500mA to 1Amp. This is assuming the transistor has a gain of 20 - 40 and this
about the capability of a transistor - called a small-signal transistor.
For larger currents, a MOSFET will be needed. These devices will deliver 20 amps or more to
a load.
There are two ways to describe the requirement of "driving a load."
You can say you want to "drive the transistor as an amplifier" or "drive the transistor as a
switch."
When a transistor is used in an analogue situation, there is a big difference between these

two statements.
In an audio amplifier, when the transistor is amplifying the signal, the output is a faithful
reproduction of the input, but with a larger amplitude. Or the shape of the signal will be
identical but with a larger current capability.
But if the transistor in an audio amplifier is driven as a switch, the output will rise very high as
soon as the input waveform starts to rise. In most audio cases this will create distortion.
But with a microcontroller we are dealing with a digital circuit and the output is either 0v or rail
volts (5v).
Any transistor connected to the microcontroller can only have two states. When the output is
zero, the transistor is turned off. This is called CUTOFF. When the output is high, the
transistor is turned ON fully. This is called SATURATION.
These two states are called SWITCHING STATES. When a transistor is in either of these two
states, it dissipates the least amount of heat. When a transistor is CUTOFF it is obvious that
the heat dissipation is low as it is zero.
When a transistor is SATURATED, it has the lowest voltage across it and although the
current flow is the highest, the heat dissipated is the lowest as the heat loss is multiplication
of current and voltage.
Suppose we want to drive a wailing siren from a microcontroller. If the microcontroller delivers
the varying tone to the speaker, we say the transistor is acting as an amplifier. It is acting as a
DIGITAL AMPLIFIER. It is being switched ON and OFF at different rates and the result is a
wailing sound.
When we refer to the transistor as a SWITCH, we often require it to turn on a device for a
long period of time - such as a relay or LED.

9. GP3 - pin 4

Driving a LOAD

GP3 is an INPUT Only and cannot be used to drive a load.


The only drive-lines for PIC12f series are:
GP 0 - pin 7
GP 1 - pin 6
GP 2 - pin 5
GP 4 - pin 3
GP 5 - pin 2

10. 100n across the micro


Don't forget the 100n across the power rails. Place it near the micro. It stops the micro
starting-up half-way through the program! Without the capacitor, the micro can start anywhere
down the program and create all sorts of unusual effects.

SOME APPLICATIONS:
Although the PIC12F629 is the simplest device in the PIC range, it can can carry out
operations such as monitoring and controlling:

Battery Monitoring and Voltage Detection

Watchdog Timing

Circuit Resetting

Voltage Detecting
There are many specially-designed chips for these applications, but they must be purchased
in large quantities. To keep your inventory down, you can use a PIC chip with a few external
components to perform the operation. All you have to do is design the circuit (the detection

section) and program the chip.

READING A PIC CHIP


If you have a PIC12C508/9 chip and want to get the program and convert it to suit a
PIC12F629, you will need to fit it into the socket of our Multi Chip Programmer and read it via
ICProg.
To do this you will need to pick PIC12C508 from the list of microprocessors from the "drop
down" menu. You will also need disasm.dll or the Disassembler link above.
For disasm.dll, use the "lightening" symbol to import the code from the chip. It will appear in
the frame on the screen. Use the "A" button (next to the "H" button) to see the disassembled
program.
You can then copy and save the program in Notepad. Only chips that are not Code
Protected, can be read. We only have some information on reading chips that are Code
Protected: Cracking a PIC Chip
If you have the .hex file, you can get the assembly file via disasm.zip as explained above.
Once you have the assembly file, you can change the files as shown above.

SOME PROGRAMMING TRICKS:


The author has found problems with some instructions.
The PIC12F629 does not like setting a bit on the in/out port and then setting or clearing
another bit in the next instruction.
The problem instructions are something like this:
bsf 05,2
bsf 05,4
The micro does not set the second bit when it is executing the program. The answer is to
work out the value in file 05 before the two instructions, add the value of the bits and place
the value in the in/out port via the following two instructions:
movlw xxh
movwf 05h
Alternatively, a meaningless instruction can be inserted between the two "bsf" instructions.
This MAY work but is not as guaranteed as the method above.
bsf 05,2
nop
bsf 05,4
Each new program or modification MUST be saved with a new name as either MPASM or
IC_Prog will not detect the changes and you will get the old program burnt into the chip and
wonder why the changes did not fix the problem!

USING A SIMULATOR AND DEBUGGER


To help developers get a program to work successfully, a number of programming tools have
been created. Two of these are a SIMULATOR and a DE-BUGGER. These are software
programs and a simulator runs your program and lets you know if it will work. It seems to be
the answer to a dream. But a simulator has many limitations. It assumes any hardware
devices connected to the program are "ideal devices."
For example, it will assume a switch has no "contact bounce" and is pressed and released
very quickly. This does not happen in real life, so your program must be re-tested in actuality.
Also, any output to LEDs etc assume the items are connected around the correct way. You
will still have to test the actual circuit and make sure the current is within the limits of the
micro.
A de-bugger is also another piece of software that tries to locate a fault in your code.
It has a "single step mode" in which it shows the contents of each register after an operation.
Sometimes these program will assist but let me assure you that they can also lead you "down

the garden path" and in the wrong direction.


I have used them and concluded that they create more frustration than assistance.
The best method is to start with a small number of instructions and make sure the program
works. Add a few more instructions and re-test the program. Re-name the file each time you
add instructions and slowly build up the program. This is the best way to avoid frustration.
We have provided explanations and helpful advice in our Library of routines: A-E E-P PZ
and provided a number of programs for you to analyse and use. The main thing is not to use
an instruction unless you know exactly what it does. Do not try any "clever" programming,
with exotic instructions as the result can be completely different to what you expect.
The first thing to do create a subroutine called a delay. Call it "_200mS" for 200milliseconds
delay.
_200mS
AA

movlw
0C8h ; equal to 200
movwf
fileB
decfsz fileA,1
goto
AA
decfsz fileB,1
goto
AA
retlw
00

Create a routine to turn a LED "on" and "off" using the delay.
such as:
On_Off

bsf
call
bcf
call
goto

gpio,0
_200mS
gpio,0
_200mS
On_Off

; put a LED on pin 7 with a 470R resistor.

If you want to see if the micro has advanced down a program to a particular location, put:
goto On_Off and the LED will blink.

SOME CIRCUIT TRICKS:


The author has found the PIC12F629 chip must be fitted to a circuit when the voltage on the
rail is ZERO. If a voltage is present, some of the files in the chip will get corrupted and the
program will not run correctly. For example, some of the outputs will not go HIGH when
required. The remedy is to turn off the project and wait for the electrolytics to discharge. You
can also remove and replace the chip if you find it is performing incorrectly.
The addition of a 10k resistor across the power rails will discharge the electrolytics to zero
and help solve this problem. Also, the addition of a 100n (very close to the chip rails) will
provide stability for the chip and allow the internal oscillator to work correctly and prevent
outside spikes from upsetting the chip.

THE PIC12F629 - some preliminary points:


The PIC12F629 is an 8 pin chip that can be re-programmed up to 1,000 times.
It is an up-grade of the PIC12C508 and '509 as it can be re-programmed.
(The PIC12F629 does not have analogue inputs - the PIC12F675 has 4 analogue inputs.)
For more details on PIC chips, see our Chip Data Ebook.
Here is a list of the chips we suggest for the beginner to microcontroller programming.
Start with the 8-pin 12F629 if you have only 1 to 5 items to "drive" (GP3 is input only). Or use
the PIC16F628A if you want to drive up to 15 items (RA5 is input only).

Device

No
Code I/O ADC ADC
of
Type
Space Pins Pins
pins

PIC12C508(A) 8

OTP 512

PIC12C509(A) 8

OTP 1024

PIC12F629

Flash 1024

PIC12F675

Flash 1024

We
use
these:
Data

Data

Smallest chip
1st choice

10-bit Data

Lots of projects The


smallest,
for this chip
simplest,
and latest
8-pin
2nd choice
PIC16F628A 18 Flash 2048 16
Data
microcontr
oller chip
in the PIC
series is the PIC12F629. It has 8 pins, will accept over 1022 lines of code and can be reprogrammed over 1,000 times. It has 6 in/out lines (GP3 is input only) and will deliver about
25mA on each output.
Programs and projects written for the PIC12C508 and '509 can be converted to PIC12F629
by using our blank12F629.asm template.
The only items that have to be converted are:
(a) The config values. ( __config) The configuration values that turn things on or off, such as
the watchdog timer, internal oscillator, plus others, to suit the PIC12F629.
(b) The GPIO values.
GPIO for PIC12C508A is location 06h
GPIO for PIC12F629 is location 05h
To convert a PIC12C508 assembly program to 12F629, the in/out instructions (such as 06,0
06,1 etc) are converted to GPIO,0 GPIO,1 etc.
In one of our articles we explained how to produce a program in a PIC16F84A and when the
project is working perfectly, the program can be burnt into a PIC12C508A. This was
necessary as the PIC12C508A was One-Time Programmable device. The GPIO's for
PIC12C508A are in location 06h. This is Port B for a PIC16F84A or 06h. (Port A for a
PIC16F84A is 05h).
If you use the PIC12F629, you do not have to create your program in a PIC16F84A as the
PIC12F629 can be programmed up to 1,000 times.
(c) The TRISIO for a PIC12F629 is address 85h in bank 1. Use the instruction TRISIO when
programming a PIC12F629. For a PIC12C508, the instruction is TRIS. It has no address.
PIC16F84(A)

18

Flash 1024

13

Data

IDENTIFYING THE PINS


The pinout of the PIC12F629 is the same as the PIC12C508A and all projects using a '508A
can be converted to PIC12F629 by fitting a PIC12F629 and turning the project on.
All you have to do is burn the '508A program into the PIC12F629 before fitting it.
Only a few lines of the program and a few instructions are different for the PIC12F629 - these
are the setting-up instructions and the location of the GPIO file. The differences have been
discussed above.

Many of the pins have a dual function and the first thing to do is decide on the function of
each pin. In most cases you will want to use the oscillator inside the chip and this will allow
you to use all the 6 in/out lines.
The functions for the chip will be simplified to:

The setting-up of the pins, plus the other functions of the chip, is done via an instruction
called "__CONFIG." - Note the double under-bar: __
This instruction also determines a number of other things for the chip, such as code
protection, and watchdog timer.
During experimenting, turn Code Protection OFF and Watchdog Timer OFF.
This will allow you to read a chip. Before marketing the final design, the code protection is
turned on and the chip is "protected." If the watchdog timer is turned off, you will not have to
include instructions in your program to keep resetting the timer. This is a complex thing to do
and will be discussed later. Keep things simple for the moment.

MCLR
Pin 4 can be configured as an "Input line" (GP3) or "Master Clear."
To configure Pin 4 as MCLR (also written as /MCLR or /MCLRE ) the configuration bit
setting is: _MCLRE_ON
When this pin is configured as /MCLRE, the pin resets the chip when it is taken LOW.
To configure Pin 4 as GP3, the configuration bit setting is: _MCLRE_OFF
This instruction tells the PIC to use its internal MCLR circuitry (to keep /MCLRE high), and
leaves pin 4 free as an Input line. Note: MCLR pin (GP3) is INPUT ONLY.

OSCILLATOR CALIBRATION VALUE


Calibration of the oscillator is only necessary when you need precise timing, as for serial
communication. In most cases you will not have to worry about this.
The oscillation calibration value can be changed from the value supplied in the chip by
adding the following instructions to the end of your program, (BEFORE the "end" instruction

of the program).

;****************************************************************
;* OSCCAL calibration value
*
;****************************************************************
org
0x3ff
retlw 0x20
END

During the programming of the chip, the above instruction will cause the burner to go to
location 3FF and insert the value 20h as well as the instruction "return with the value 20h in
W."
To create the maximum frequency, use: 3fh
Centre frequency = 20h
Minimum frequency = 00h
During the running of the program (when the chip is in the project), this value is put into the
OSCCAL location, to adjust the frequency of the internal oscillator.
To get the micro to do this, the following instructions are added to your program:

;****************************************************************
;* Calibrating the internal oscillator
*
;****************************************************************
bsf
status,rp0
call
3ffh
movwf OSCCAL
bcf
status,rp0

;bank 1
;get the calibration value
;calibrate
;bank 0

The location of the oscillator calibration register is 90h. This is in Bank 1 and is identified in
your program by writing: "OSCCAL" It is a 6-bit register, with values from 00h to 3fh.

P2 P3

;-----------------------------------------------------; PROJECT : 3 CHANNEL TX IR REMOTE


; CRYSTAL 4 MHz

; MPLAB : 7.11 , Assembly


; RC5 FORMAT @38KHz , 35% DUTY CYCLE
; ADDRESS = 0X0B 0000 1011 you may change
; CH1 = 0X01
; CH2 = 0X02
; CH3 = 0X03
; NOT USE TOGGLE ALWAY = 0
; WWW.SIXCA.COM
; 4-JULY 2005
;
; FREE TO USE FOR PERSONAL OR EVEN COMERCIAL PRODUCT
;-----------------------------------------------------list P=12F629
#include <P12F629.INC>
__config _WDT_OFF & _XT_OSC & _CP_ON & _CPD_ON & _BODEN_OFF &
_MCLRE_OFF & _PWRTE_ON
#DEFINE
#DEFINE
#DEFINE
#DEFINE
#DEFINE
#DEFINE
#DEFINE
#DEFINE

CH1
GPIO,0
; CONNECT WITH TX SWITCH CHANNEL 1
CH2
GPIO,1
; CONNECT WITH TX SWITCH CHANNEL 2
CH3
GPIO,3
; CONNECT WITH TX SWITCH CHANNEL 3
IR GPIO,2
; CONNECT WITH IR LED WITH TRANSISTOR DRIVES
TOG_BIT TOGGLE,0 ; TOGLE BIT NOT USE FOR THIS PROJECT
CH1_CMD 0X01 ; CHANNEL 1 COMMAND
CH2_CMD 0X02 ; CHANNEL 2 COMMAND
CH3_CMD 0X03 ; CHANNEL 3 COMMAND

CNT1 EQU
CNT2 EQU
CNT3 EQU
CNT4 EQU
TOGGLE
CMD EQU

20H
21H
22H
23H
EQU
25H

ORG

000

24H
; IR COMMAND BUFFER

BCF IR
;BSF STATUS,RP0
;CALL 0X3FF
;MOVWF
OSCCAL
;BCF STATUS,RP0
CALL DEBOUNCE
;
MOVLW 0X07
MOVWF CMCON ; MAKE ALL GPIO TO DIGITAL I/O
BSF STATUS,RP0
BCF OPTION_REG,7
; ENABLE WEAK PULL-UP
BCF WPU,2
; DISABLE WEAK PULL-UP FOR GPIO2
MOVLW B'00001011'
; GPIO<0,1,3> = INPUT , GPIO 2 = OUTPUT
MOVWF TRISIO
BSF IOCB,IOCB0
BSF IOCB,IOCB1

BSF
BSF
BCF
BCF
BCF

IOCB,IOCB3
INTCON,GPIE
STATUS,RP0
INTCON,GIE
TOG_BIT

;-----------------------------------; MAIN LOOP


MAIN: SLEEP ; GOTO SLEEP MODE(I a sleepy! and need to save my energy)
BTFSS CH1
GOTO DO_CH1
BTFSS CH2
GOTO DO_CH2
BTFSS CH3
GOTO DO_CH3
GOTO MAIN
;-----------------------------------DO_CH1:
CALL DEBOUNCE
BTFSC CH1
GOTO MAIN
MOVLW CH1_CMD
; LOAD COMMANE FOR CHANNEL 1
MOVWF CMD
CALL SEND_RC5
;
BTFSS CH1
GOTO $-1 ; WAIT FOR SWITCH RELEASED
;
CALL DEBOUNCE
; DELAY AFTER SWITCH RELEASED
GOTO MAIN
;-----------------------------------DO_CH2:
CALL DEBOUNCE
BTFSC CH2
GOTO MAIN
MOVLW CH2_CMD
; LOAD COMMANE FOR CHANNEL 1
MOVWF CMD
CALL SEND_RC5
;
BTFSS CH2
GOTO $-1 ; WAIT FOR SWITCH RELEASED
;
CALL DEBOUNCE
; DELAY AFTER SWITCH RELEASED
GOTO MAIN
;
;-----------------------------------DO_CH3:
CALL DEBOUNCE
BTFSC CH3
GOTO MAIN
MOVLW CH3_CMD
; LOAD COMMANE FOR CHANNEL 1
MOVWF CMD
CALL SEND_RC5
;
BTFSS CH3
GOTO $-1 ; WAIT FOR SWITCH RELEASED
;

CALL DEBOUNCE
; DELAY AFTER SWITCH RELEASED
GOTO MAIN
;
;======================================
; SEND LOGIC 0
;======================================
LOGIC0:
MOVLW .32
; 1
MOVWF CNT1
; 1
;
LOG0_1:
BSF IR
; 1 MAKE IR HIGH 35% Duty cycle = 9 uS
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
;
;===================================
BCF IR
; 1 MAKE IR LOW 17 uS
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
NOP
; 1
;
DECFSZ
CNT1,F
; 1/2
GOTO LOG0_1
; 2
26 uS
;
CALL DELAY_OFF
RETURN
; 2
;
;======================================
; SEND LOGIC 1
;======================================
LOGIC1:
CALL DELAY_OFF ; DELAY 899 uS
MOVLW .32
; 1
MOVWF CNT1
; 1
;
LOG1_1:
BSF IR
; 1 MAKE IR HIGH 35% Duty cycle = 9 uS
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
;
;===================================
BCF IR
; 1 MAKE IR LOW 17 uS
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
NOP
; 1
;
DECFSZ
CNT1,F
; 1/2
GOTO LOG1_1
; 2

;
RETURN
; 2
;
;======================================
; DELAY FOR NO CARRAIR
; DELAY ABOUT 835 uS
;======================================
DELAY_OFF:
MOVLW 5
; 1
MOVWF CNT3
; 1
MOVLW .54
; 1
MOVWF CNT4
; 1
DECFSZ
CNT4,F
; 1/2
GOTO $-1
; 2
DECFSZ
CNT3,F
; 1/2
GOTO $-5
; 2
RETURN
; 2
;======================================
; SEND RC5 TO REMOTE
; INPUT : CMD (6 BIT IR COMMAND)
;======================================
SEND_RC5:
; SEND 2 START BIT
CALL LOGIC1
CALL LOGIC1
; SEND TOGGLE BIT
BTFSS TOG_BIT
GOTO $+3
CALL LOGIC1
GOTO $+2
CALL LOGIC0
; SEND ADDRESS 5 BIT FIX AT 01011 (0X0B) IT MAY BE CHANGED BY
YOU
CALL LOGIC0
; 0 MSB FIRST BIT 4
CALL LOGIC1
; 1
CALL LOGIC0
; 0
CALL LOGIC1
; 1
CALL LOGIC1
; 1 LSB BIT 0
;
; SEND COMMAND 6 BIT(00HH LLLL) MSB FIRST
BCF STATUS,C
RLF CMD,F ; AFTER FIRST ROTAGE 0HHL LLL0
RLF CMD,F ; AFTER SECOND ROTAGE HHLL LL00
;
MOVLW 6
MOVWF CNT2
;
RLF CMD,F
; SEND MSB FIRST
BTFSS STATUS,C
GOTO $+3
CALL LOGIC1
GOTO $+2
;
CALL LOGIC0

DECFSZ
GOTO $-7
;
RETLW 0
;

CNT2,F

;======================================
; DEBOUNCE SWITCH
; DELAY 15 mS
;======================================
DEBOUNCE:
MOVLW .1
; 1
MOVWF CNT1
; 1
DEL_1:
MOVLW .20
MOVWF CNT2
; 1
DEL_2:
CLRF CNT3
; 1
DEL_3:
DECFSZ
CNT3,F
; 1/2
GOTO DEL_3
; 2
DECFSZ
CNT2,F
; 1/2
GOTO DEL_2
; 2
DECFSZ
CNT1,F
; 1/2
GOTO DEL_1
; 2
RETLW 0
; 2
END

P1

P2 P3

Disassembler

Soldering and using a prototype PC board


PIC12F629 Data Sheet (.pdf 4,926KB)
INSTRUCTION SET for PIC12F629
blank12F629.asm template
Library of Sub-routines "Cut and Paste"
Library of routines: A-E E-P P-Z

WRITING A PROGRAM
Before starting to write a program, there are a number of things you need to know about
laying it out.
Let's start:
Anything you write on the page is interpreted by an ASSEMBLER. The assembler will convert
anything it understands to MACHINE CODE. Any comments you write on the page are placed
after the ";" symbol.
A program is written in a set of columns. Anything in the first column is called a LABEL. If you
leave more than 2 spaces, the next item is interpreted as an INSTRUCTION and the next
column contains your comments ( ";" is needed before any comments).
Start by giving a name to the program, and revision number plus date.
the ;************************************ simply creates a separator.
The next line identifies the type of microcontroller.
#include <p12f629.inc> The assembler will need to have this file in the same directory as the
assembler program so it can identify some of the words you have used in your program.
See: <p12f629.inc>
The next line is the configuration code. It tells the assembler if you want the Code Protection
ON or OFF, and other things such as Watchdog Timer, and Internal 4MHz RC Oscillator. The
configuration line starts with double underbar "__"

NAMING THE FILES


One of the first things you will need to do is "list" or "name" or "equate" the files. This is the
process of matching each file to a number, so the compiler can compile your program.
The PIC12F629 has 64 general purpose registers or files, starting at 20h (this is two-oh-hex)
and is actually 32 files from the start:
(1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10h,11h,12h,13h,14h,15h,16h,17h,18h,1h,1A,1B,1C,1D,1E,1F)
20h.
The 64 files are:
20h,21h,22h,23h,24h,25h,26h,27h,28h,29h,2Ah,2Bh,2Ch,2Dh,2Eh,2Fh,30h,31h,32h,33h,34h
35h,36h,37h,38h,39h,40h,41h,42h,43h,44h,45h,46h,47h,48h,49h,4Ah,4Bh,4Ch,4Dh,4Eh,4Fh,
50h,51h,52h,53h,54h,55h,56h,57h,58h,59h,5Ah,5Bh,5Ch,5Dh,5Eh,5Fh.
These can be used to store values during the running of the program.
For instance, file 20h can be one of the files in the delay routine. We can call it delay1.
The next file can be delay2.
The next file is part of a tone routine, we will call it tone1
The next file is tone2.
These files are called "Variables" and are placed at the beginning of the program.
Each name such as delay1 has to be assigned to a file.
For instance, delay1 will be file 20h
delay2 will be file 21h etc.
This process is called "equates." You are equating a name to a file.
;**********************************************************************
;Equates
;**********************************************************************
delay1 equ 20h
delay2 equ 21h
tone1 equ 22h
tone2 equ 23h

Instead of writing the word "equ" for each file, there is a short-cut:
It is called "CBLOCK" - for "naming a block for the named constants."
The first line of the short-cut is: cblock and then a number that refers to the beginning of the
files for the block. The number: 0x20 is the same as saying 20h. The following cblock is the
same as the above.
The short-cut ends: "endc"
**********************************************************************
;Variables
;**********************************************************************
cblock 0x20 ;20h is the first file of the General Purpose Registers
delay1
delay2
tone1
tone2
endc

Another method of defining our files allows 2 or more files with the same name. For instance,
the following allows 3 flag files. These are identified as "flags," "flags+1," "flags+2," in your
program. rand is identified as "rand" and "rand+1" in your program. You can also identify
similar names for files on the same line, such as: temp1, temp2. In the following, 13 files
have been identified and will be given the file numbers: 20h, 21h, 22h, 23h, 24h, 25h, 26h,
27h, 28h, 29h, 2Ah, 2Bh, 2Ch. To give a name such as "flags" more than one file, it is written
flags:3 or flags:4 etc. It can also be written flags1, flags2, flags3, etc.
;**********************************************************************
;File Register usage
;**********************************************************************
cblock 0x20
count
; counter
flags:3
; various flags
rand:2
; random number
sensor
; sensor reading
servo1, servo2 ; servo positions
speed1, speed2 ; motor speeds
temp1, temp2 ; timers
endc

The next statement is called START. It is the beginning of the program.


The program starts with the statement ORG 000 or ORG 0x000. Or you can make the
ORIGIN of your program 0x004 or 0x34.
This tells the assemble to put the first instruction in the program at location 000 in the program
memory, or at location 4 or at location 34hex. This is called a DIRECTIVE and is information
for the assembler. The first instruction in our example is "goto SetUp" The sub-routine at
SetUp, sets the port bits as IN or OUT. The port is actually a file and has the name GPIO (for
General Purpose In Out) and is file 05. All files have 8 bits but only the lowest 6 bits of file 05
are used. These are called GPIO,0 GPIO,1 GPIO,2 GPIO,3 GPIO,4 GPIO,5

These can be called "lines" and any or all of them can be configured as input, but only
GPIO,0 GPIO,1 GPIO,2 GPIO,4 GPIO,5 can be used at output as GPIO,3 (GP3) (pin 4)
is an INPUT-ONLY pin. To get a pin to "work," two things must be done. Firstly the micro
must be told if the pin is to be an input or output and them it must be made HIGH or LOW if it
is an output pin. Any pin can be changed at any time during the running of a program but it is
normal to set up the pins in Set-Up if they are not going to be altered. We discuss setting up
the "lines" a little further down the article.
Set-Up is placed at the 7th program location. There is a reason for this. Location 04 is where
the microcontroller will return when it is "interrupted." For instance, it may be asleep, and is
waiting for one of the inputs to change state. The microcontroller can be programmed to go to
location 04 after an interrupt and the instructions at 04 will be carried out. We will leave three
lines for three instructions, at 04, 05, 06. Location 07 is now available for your program.

At the end of SetUp, the microcontroller goes to Main.


Main is always located at the end of your program and all the subroutines are placed before
Main, in alphabetical order. This allows you to easily find each sub-routine.
Any tables are placed before the sub-routines.
Here is how the program is laid out:
;**********************************************************************
; SPINNING SIGN Colin Mitchell rev 2 19-9-2007
;**********************************************************************
list
p=12f629
#include <p12f629.inc>
; Set configuration register for:
; Code protection off
; Code protection DATA off
; Brown-out detect off
; MCLR disabled (use pins for InOut)
; Watch Dog timer disabled
; Power on reset delay enabled
; Enable Internal Clock Osc, (all pins for InOut)
;
__CONFIG _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_OFF
& _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
;**********************************************************************
;Variables
;**********************************************************************
cblock 0x20 ;20h is the first file of the General Purpose Registers
delay1
delay2
tone1
tone2
endc
;**********************************************************************
;Start
;**********************************************************************

ORG 0x000
goto SetUp

; processor reset vector


; go to "setting up the port as In-Out etc"

ORG
nop
nop
nop

; processor goes here after interrupt


; nop = no operation = 1 cycle

0x004

SetUp
instruction goes here
instruction goes here
goto Main
;**********************************************************************
;Tables
;***********************************************************************

;**********************************************************************
;Sub-routines
;***********************************************************************

Main
instruction goes here
instruction goes here
end

SETTING UP THE "LINES':


The "lines" are the input/out pins or "lines."
These are called GPIO,0 GPIO,1 GPIO,2 GPIO,3 GPIO,4 GPIO,5
Any or all of them can be configured as input, but only GPIO,0 GPIO,1 GPIO,2 GPIO,4
GPIO,5 can be used at output as GPIO,3 (GP3) (pin 4) is an INPUT-ONLY pin.
The first thing to do is work out which pins are needed to be input and output. An input pin will
be given the value "1" for Input and "0" for output. Two instructions are needed, are are
highlighted:
bsf
STATUS,rp0
movlw b'00110111'
movwf TRISIO
bcf
status,rp0
These instructions must be placed between two instructions: bsf STATUS,rp0 and
bcf status,rp0 so your instructions are placed in the chip at a special location. These
instructions are placed in a file (or register) called the TRISIO file.
The movlw b'00110111' instruction is a binary number that directly represents each line
you want to make input or output. The chip has only 6 lines so the instruction is really:
movlw b'xx110111' as the two highest bits do not have a corresponding line. They can be
0 or 1 as they have no effect.
The lowest line is called "line 0" or "bit 0" or "GPIO,0" and to make it an input we place a '1'
as follows: b'xx - - - - - 1' To make it an output: b'xx - - - - - 0' We have already said GPIO,3
is INPUT-ONLY so the instruction starts: b'xx - - 1 - - -' Once you have worked out if each
line is to be input or output, the next decision is to make an output line HIGH or LOW.
(If you make an input line high or low, it does not have any effect on the line. It will only
function at detecting the voltage applied to it from the outside world.)

To make an output line HIGH, one or two instructions are needed, depending how it is done.
To make any or all the lines HIGH, this can be done with two instructions. This is called "Byte
Setting" as the whole byte is acted on in a single operation:
movlw
movwf

b'00110111'
GPIO

If you want to make a line HIGH, you can use "Bit Setting:"
bsf

GPIO,0

You cannot set more than one bit at a time, the micro does not like the following:
bsf
bsf

GPIO,0
GPIO,2

;This makes the lowest line go HIGH

To set more than one line at a time, read: The In/Out Port.

;blink12F629.asm
;This program will blink a LED connected to pin 7
;17-9-2007

list p=12F629

;microcontroller identity
; 0x033 or 33h = hex value
include "p12f629.inc"

__CONFIG _MCLRE_OFF & _CP_OFF & _WDT_OFF &


_INTRC_OSC_NOCLKOUT
;**********************************************************************
;Variables
;*************************************************************************

fileA
fileB
fileC

equ 20h
equ 21h
equ 22h
equ 23h
equ 24h
equ 25h

;this is the first available file

equ 26h
equ 27h
equ 28h

;delay file A
;delay file B
;delay file C
; bits on GPIO

pin7
pin6
pin5
pin4

equ 0
equ 1
equ 2
equ 3

;GP0 output to LED


;GP1
;GP2
;GP3

pin3
pin2

equ 4
equ 5

Start

org
nop
nop
nop
nop
nop
nop
nop

;GP4
;GP5

0x0000

;program starts at location 000


;"org" = tells the assembler to start at this address.

;NOPs to get past interrupt address

SetUp bsf
STATUS,rp0
movlw b'10000110'
movwf OPTION_REG
movlw b'00110111'
movwf TRISIO
movlw 0x07
movwf CMCON

;Bank 1
;Turn off T0CKI, prescaler for TMR0 = 1:128
;Set GP0 (pin 7) as output
;turn comparator off
; comparator off =111
;calibrating the internal oscillator

Del
DelX

Main

call
0x3ff
movwf OSCCAL
bcf
status,rp0
clrf
GPIO
goto
Main

;get the calibration value


;calibrate oscillator
;bank 0
;Clear GPIO of junk. This is file 05.

movlw
movwf
decfsz
goto
decfsz
goto
decfsz
goto
retlw

40h
fileC
fileA,1
DelX
fileB,1
DelX
fileC,1
DelX
00

;Delay 0.5 sec

bsf
call
bcf
call
goto

GPIO,pin7
Del
GPIO,pin7
Del
Main

;turn on LED

; ,1 denotes the result of the decrement


; is placed in the file

;turn off LED

;OSCCAL calibration value


org
0x3ff
retlw 0x20
END

THE TEMPLATE LAYOUT:


The template above consists of 6 different areas:
The first area contains the CONFIGURATION values.
The second area contains the "equates" or "variables."
The third area contains the SET UP instructions
The fourth area contains all the sub-routines. These are placed in alphabetical order, so you
can easily find them when the program gets lengthy.
The fifth area contains the MAIN routine.
The last area sets the calibration value for the oscillator and the "end" instruction.
The micro will commence at location 000 and execute the Set Up instructions.
It will then go to Main.
In "Main" it will find instructions to "call" sub-routines and return. In this way it will constantly
loop "Main" and use sub-routines as required.
If you keep to this form of layout, you will be able to follow programs written by others and be
able to come back to your own programs and easily modify them.

Delay Routine
There are two ways to write a Delay Routine (and other routines). The program above uses
instructions found in List of Instructions for PIC12F629. The following Delay Routine uses
"$+2" to advance the micro down the program:

Del

movlw
movwf
DelX decfsz
goto
decfsz
goto
decfsz
goto
retlw

40h
fileC
fileA,1
DelX
fileB,1
DelX
fileC,1
DelX
00

Del

40h
fileC
fileA,1
$+2
fileB,1
$+2
fileC,1
DelX
00

movlw
movwf
DelX decfsz
goto
decfsz
goto
decfsz
goto
retlw

;Delay 0.5 sec


; ,1 denotes the result of the decrement
; is placed in the file

$+2 sends the micro to: goto $+2 below


$+2 sends the micro to: goto DelX

The Delay Routine above can be written with only one Label.

;Delay 0.5 sec

Del

movlw
movwf
decfsz
goto
decfsz
goto
decfsz
goto
retlw

40h
fileC
fileA,1
$+2
fileB,1
$+2
fileC,1
$-5
00

$+2 sends the micro to: goto $+2 below


$+2 sends the micro to: goto goto $-5
$-5 sends the micro to: decfsz fileA,1

Creating 4 micro-second delay:

;Delay 4 micro-seconds
nop
nop
nop
nop

;1 uS
;1 uS
;1 uS
;1 uS

----------------------- ----------------------------------------------------------------goto $+1


goto $+1

;2 uS, $+1 sends the micro to the next instruction


;2 uS, $+1 sends the micro to the next instruction

SLEEP
To put the micro to sleep, a number of things must be done. This routine allows the micro to
go to SLEEP when it comes to the SLEEP instruction. The micro wakes up from sleep when it
detects a change on GPIO,5 (pin 2). Pin 2 must have a pull-up resistor for the following
program to work and a push-switch to create the change on the pin. The pull-up resistor can
be external (about 47k) and a push switch to take the pin low to take the micro out of SLEEP.
Or, to turn on the weak internal 47k pull-up resistor, place the following instructions in SetUp:
bsf
bcf
bsf
bsf
bcf

STATUS,RP0
; Sel Bank 1
OPTION_REG,NOT_GPPU
; enable weak pull-up
WPU, 5
; enable wpu on GPIO 5 only
IOC, 5
; enable Int-On-Change GPIO 5
STATUS,RP0
; Sel Bank 0

In a sub-routine, place the following instruction:


goto sleep

; goto sleep.

The following sub-routine is suitable to create a sleep condition:

Sleep movf

GPIO,W

; Read GPIO clears Int-On-Change flag. Must read


; into W not back to F as it reads port not the output
; latch which may result in output data being
; inadvertently altered.

bcf
INTCON,GPIF
bsf
STATUS,RP0
movlw 0xFF
movwf TRISIO
sleep
nop
movlw b'11101000'
movwf TRISIO
bcf
STATUS,RP0
movf GPIO,W
bcf
INTCON,GPIF

; Sel bank 1
; Setup W for TRISIO all input
; Write to TRISIO. Reduce power in sleep mode
; Go to sleep
;
; Wake from sleep and set
; TRISIO for input and output for your project
; Sel Bank 0
; Read GPIO register
; and clear GPIF flag in interrupt register

CREATING A MACRO
Suppose you want to create an instruction the assemble does not understand, such as:

movlf 0A0h,sensor

In the instruction above you want to move the value A0h into file 26h (by referring to the list
above:
count
flags:3
rand:2
sensor

; counter
; various flags
; random number
; sensor reading

count will be allotted file 20h, flags will be allotted file 21h, flags+1 will be give 22h, flags+2
will be give file 23h, rand will be 24h, rand+1 will be 25h and sensor will be 26h.
But the assembler does not have an instruction of the above. It requires two instructions:

movlw
movwf

0A0h
sensor

Creating your own instructions for the assembler is called a "macro."


To tell the assembler how to handle an instruction in which the value 0Ah (called a "constant"
or "literal") is to be moved to file 26h (the "sensor" file), a macro can be written to allow any
"literal" to be written to any "file:"

movlf

macro
movlw
movwf

n,f
n
f

; move literal to file

endm

When the assembler sees the instruction: movlf it looks to see if a macro has been
produced. The instructions in the macro are then added to the program (called the "source").
The macro is written with a label in the first column. The word "macro" is then written to tell
the assembler the next instructions are "macro instructions." On the same line we write the
parameters that will be used in the macro. The macro ends with "endm."

START HERE
If you will want to burn a chip and make sure it works in a test circuit. To help you, we have
written a simple program, called "blink12F629.asm". This will blink a LED on Pin 7.
The circuit for this is:

Click .asm and .hex for blink12F629.asm files.

;blink12F629.asm
;This program will blink a LED connected to pin 7
;17-12-2005

list p=12F629

;microcontroller identity
; 0x033 or 33h = hex value
include "p12f629.inc"

__CONFIG _MCLRE_OFF & _CP_OFF & _WDT_OFF &


_INTRC_OSC_NOCLKOUT
;Internal osc.

equ 20h
equ 21h

; globals
;this is the first available file

equ 22h
equ 23h
equ 24h
equ 25h
fileA
fileB
fileC

equ 26h
equ 27h
equ 28h

;delay file A
;delay file B
;delay file C
; bits on GPIO

pin7
pin6
pin5
pin4
pin3
pin2

equ 0
equ 1
equ 2
equ 3
equ 4
equ 5

Start

org
nop
nop
nop
nop
nop
nop
nop

;GP0 output to LED


;GP1
;GP2
;GP3
;GP4
;GP5

0x0000

;program starts at location 000


;"org" = tells the assembler to go to this address.

;NOPs to get past interrupt address

SetUp bsf
STATUS,rp0
movlw b'10000110'
movwf OPTION_REG
movlw b'00110111'
movwf TRISIO
movlw 0x07
movwf CMCON

;Bank 1
;Turn off T0CKI, prescaler for TMR0 = 1:128
;Set GP0 (pin 7) as output
;turn comparator off
; comparator off =111
;calibrating the internal oscillator

Del
DelX

call
0x3ff
movwf OSCCAL
bcf
status,rp0
clrf
GPIO
goto
Main

;get the calibration value


;calibrate oscillator
;bank 0
;Clear GPIO of junk. This is file 05.

movlw
movwf
decfsz
goto
decfsz
goto
decfsz

;Delay 0.5 sec

40h
fileC
fileA,1
DelX
fileB,1
DelX
fileC,1

; ,1 denotes the result of the decrement


; is placed in the file

Main

goto
retlw

DelX
00

bsf
call
bcf
call
goto

GPIO,pin7
Del
GPIO,pin7
Del
Main

;turn on LED
;turn off LED

;OSCCAL calibration value

org
0x3ff
retlw 0x20
END

YOUR FIRST PROGRAM:


We are now ready to start writing a program.
You will need the INSTRUCTION SET for the PIC12F629
Below is the blank12F629.asm template:
The instructions for your program are arranged in three columns.
The first column contains the "labels." They identify the address of the first instruction for a
sub-routine.
The second column contains the "instructions" - called the mnemonics. The "half-computer"
"half-English" instructions that both computer and micro understands.
The third column contains the "comments." It must have a ";" before each line so that they are
not assembled - so they don't appear in the final .hex file!
Click .asm and .hex for "blank12F629.asm" files. The .asm file is used by your compiler
(MPASM) to produce a .hex file for your ICProg burner program.

;blank12F629.asmm
;Template for PIC12F629 microcontroller 17-12-2005
;CONFIG defines internal oscillator, code-protection OFF, pin 4 is GP3,
; watchdog timer OFF.
list p=12F629

;microcontroller identity

; 0x033 or 33h = hex value


include "p12f629.inc"
__CONFIG _MCLRE_OFF & _CP_OFF & _WDT_OFF &
_INTRC_OSC_NOCLKOUT
;Internal osc.

equ 20h
equ 21h
equ 22h
equ 23h
equ 24h
equ 25h
fileA
fileB
fileC

equ 26h
equ 27h
equ 28h

; globals
;this is the first available file

;delay file A
;delay file B
;delay file C
; bits on GPIO

pin7
pin6
pin5
pin4
pin3
pin2

equ 0
equ 1
equ 2
equ 3
equ 4
equ 5

;GP0
;GP1
;GP2
;GP3
;GP4
;GP5

;***************************************************
;* Start of program *
;***************************************************

Start

org
nop
nop
nop
nop
nop
nop

0x0000

SetUp call
0x3ff
bsf
STATUS,rp0
movwf OSCCAL
movlw b'10000110'
movwf OPTION_REG
movlw b'00001000'
movwf TRISIO
bcf
status,rp0

;program starts at location 000


;"org" = tells the assembler to go to this address.

;NOPs to get past reset vector address

;get the calibration value


;Bank 1
;calibrate oscillator
;Turn off T0CKI, prescaler for TMR0 = 1:128
;Set GP0's as output, GP3 = input.
;bank 0

clrf
goto

Del_1 movlw
movwf
DelX decfsz
goto
decfsz
goto
decfsz
goto
retlw
Main

GPIO
Main

40h
fileC
fileA,1
DelX
fileB,1
DelX
fileC,1
DelX
00

;Clear GPIO of junk

;Delay_1 0.5sec
; ,1 denotes the result of the decrement
; is placed in the file

your instruction goes here


your instruction goes here
your instruction goes here
call Del_1
your instruction goes here
your instruction goes here
your instruction goes here
goto Main

;OSCCAL calibration value


org
0x3ff
retlw 0x20
END

BURNING YOUR PROGRAM


The first program you will burn will be "blink12F629.asm"
Open Notepad.exe or Unzip Notepad.zip in our Programming folder on the left-side of the
screen and load it with the blink12F629.asm file by sliding it into Notepad. It will then show in
Notepad.
You can now make any changes to the program.
Save the result in a folder called PIC12F629Pgms (programs).
To burn blink12F629.asm into a PIC12F629, you will need to assemble the .asm file in
MPASM to create a .hex file. To do this, place MPASM in a folder (or unzip MPASM.zip in the
folder) and create a shortcut to desktop.
Click on MPASM on your desktop and it will open.
Locate blink12F629.asm in PIC12F629Pgms folder and load it into MPASM.
Use:
Radix: Default, Warning Level: Default, Hex Output: Default, Generated Files: Error File and
List file, Do not tick: Case Sensitive, Macro Expansion: Default, Processor PIC12F629, Tab
Size: 8, Tick: Save settings on exit.
Click: Assemble.
Your blink12F629.hex file will be put into the same folder.
To burn a PIC12F629, you will need the Multi Chip Programmer. Make sure the programmer

is the latest version with 628 on the underside of the PCB.


Connect it to your computer via the serial cable supplied in the kit and the green LED will
illuminate.
Install IC Prog on your desktop or unzip IC Prog.zip
Click on the folder on the top left-hand side and locate Expt-1.hex
Make sure you have selected PIC12F629 before loading the .hex file.
The configuration settings will be automatically set according to the configuration value
supplied in the program - or you can change anything before burning the new program.
Fit a chip into the programmer and click on the "lightening" icon.
The programmer will now burn the program into the chip. The LEDs on the Multi-Chip
Programmer will show the action taking place.
When the chip is "burnt," place it in the socket on the project and the LED will flash.
This might seem a lot of work to create a simple effect, but the same amount of work will
produce a compete project - it's just the size of the program will be different.

WRITING YOUR PROGRAM


Writing a program consists of creating small routines called sub-routines.
The basic layout of a program has already been shown above.
It is now a matter of creating subroutines that perform a function.
When these are executed at high-speed, the program performs a task.
The most interesting subroutines carry out an operation that appears to have "intelligence."
These type of subroutines can be found in a game, where the player is pitted against the
computer.
The basics behind an "intelligent" sub-routine is simple. You simply provide an answer for ALL
the possible combinations.
When this sub-routine is executed in the program, it creates the illusion of intelligence.
This type of sub-routine is interesting and challenging to create.
There are a number of very common games played with matches and marbles or markers,
that can be converted to a program.
Once you master the technique of writing a sub-routine that solves a problem, all other
routines will be easy to create.

HERE ARE SOME PROGRAMMING HINTS:


Before we start, the PIC12F629 has only 5 output lines and this prevents it from directly
driving a 7-digit display. We have designed a project called 2-Digit Counter that shows how to
expand the outputs to drive the displays.
1. Indirect Addressing
One of the things you may want to do is access a list of values from a table.
A number of files can be addressed by a sub-routine and the information can be moved into
each file or read from each file. The files must be a group.
Suppose we have 8 files and need to read the contents and output it to a display.
The files are: 21h, 22h, 23h, 24h, 25h, 26h, 27h, and 28h.
There are two special files that allow a sub-routine to be created to look at the 8 files and read
the contents.
They are: INDF and FSR
The INDF file is not a real file. It is like a Robot Arm. It reaches down the list of files and picks
up the contents or delivers the contents of a file to the programmer. The file it reaches is
determined by the value in FSR.
FSR is loaded with the address of the file you wish to read or write.
This arrangement has an advantage. By loading FSR with a value, you can reach a file and
by incrementing FSR, you can reach the next file etc.
If you load a value into INDF, you will actually load the value into the file pointed to by FSR.
If you read INDF, you will actually read the contents of the file pointed to by FSR.
You can consecutively read 8, 10 or 20 files or clear 20 files or load into 20 or more files with
a simple looping sub-routine. It's a very powerful feature.
The following instructions put a value of 8Fh into file 21h.

MOVLW 21h
MOVWF 04
MOVLW 8Fh
MOVWF 00

;Load W with start of 8 files


;Load 21h into FSR
;Put 8F into W
;Put 8Fh into file 21h

The animation below shows how the information passes to the files:

Using INDF and FSR


The following instructions put a value of 8Fh into files 21h, 22h, 23h, 24h, 25h, 26h, 27h and
28h.
MOVLW 08
MOVWF 20h
MOVLW 21h
MOVWF 04
MOVLW 8Fh
Loop1 MOVWF 00
INCF 04
DECFSZ 20h
GOTO Loop1
RETLW 00

;8 loops of the program


;File 20h is the decrementing file
;Load W with start of 8 files
;Load 21h into FSR
;Put 8F into W
;Put 8Fh into file 21h
;Increment FSR to make INDF go to next file

The following instructions read files 21h, 22h and 23h, and outputs to GPIO.
MOVLW 03
MOVWF 20h
MOVLW 21h
MOVWF 04
Loop1 MOVF 00,0
MOVWF GPIO
CALL Delay
INCF 04

;3 loops of the program


;File 20h is the decrementing file
;Load W with start of 3 files
;Load 21h into FSR
;Copy file 21h (or next file) into W
;Move W to output GPIO
;Show value on set of 3 LEDs

DECFSZ 20h
GOTO Loop1
RETLW 00

;Increment FSR to make INDF go to next file

P1

P2 P3

You might also like