Você está na página 1de 54

SUMRIO

INDICE DE FIGURAS............................................................................................................................................... 9
INDICE DE TABELAS .............................................................................................................................................. 9
1.

INTRODUO ................................................................................................................................................. 10

2.

DESCRIO GERAL...................................................................................................................................... 11
2.1. A MEMRIA DE PROGRAMA E A MEMRIA RAM........................................................................... 13
2.2. A UNIDADE LGICA E ARITMTICA (ALU) E O ACUMULADOR OU W ..................................... 17
2.3. CONTADOR DE PROGRAMA E A PILHA ............................................................................................. 19
2.4. AS PORTAS DE E/S A E B ........................................................................................................................ 23
2.5. ESTADO DE ESCRITA DAS LINHAS DE E/S........................................................................................ 25
Funcionamento em entrada ................................................................................................................................ 27
Funcionamento em sada .................................................................................................................................... 27
Estado de sada da linha RA4 ............................................................................................................................. 28
Estado de sada das linhas RB4, RB5, RB6 e RB7.............................................................................................. 31
2.6. O REGISTRO CONTADOR TIMER0 ....................................................................................................... 32
2.7. PRESCALER .............................................................................................................................................. 36
2.8. INTERRUPES ....................................................................................................................................... 37
Tipos de eventos e bit's de habilitao................................................................................................................ 37
Vetor de Interrupo e Controle de Interrupo (Interrupt vector e Interrupt handler).................................... 38
Interrupt flag(sinalizador de interrupo).......................................................................................................... 39
Retorno de uma interrupt handler ...................................................................................................................... 39
2.9. FUNCIONAMENTO DO POWER DOWN MODE ......................................................................................... 39
A instruo SLEEP ............................................................................................................................................. 40
O "despertar" do PICmicro ................................................................................................................................ 40
2.10.
WATCH DOG TIMER ........................................................................................................................... 41
Ajuste do PRESCALER ao WDT......................................................................................................................... 42
Um exemplo simples de utilizao ...................................................................................................................... 42

BIBLIOGRAFIA....................................................................................................................................................... 45
APNDICE 1 - TABELA DOS CDIGOS DE INSTRUO DO PIC16F84 .................................................... 46
APNDICE 2 - CIRCUITO PARA O PROGRAMADOR DE PIC ..................................................................... 47
APNDICE 3 - CDIGO EM C PARA O PROGRAMADOR DE PIC.............................................................. 48

Indice de Figuras
FIGURA 1- ASPECTO FSICO DO PIC 16F84................................................................................................................... 11
FIGURA 2 - PINAGEM DO PIC 16 C 84 ......................................................................................................................... 13
FIGURA 3 - ARQUITETURA INTERNA DO PIC ................................................................................................................ 14
FIGURA 4 - A MEMRIA RAM .................................................................................................................................... 16
FIGURA 5 - O REGISTRADOR W E A UNIDADE LGICA E ARITMTICA ......................................................................... 18
FIGURA 6 - A PILHA E O CONTADOR DE PROGRAMA ..................................................................................................... 20
FIGURA 7 - PORTAS A E B............................................................................................................................................ 24
FIGURA 8 - ESTADO DAS LINHAS RA............................................................................................................................ 26
FIGURA 9 - A PORTA RA4............................................................................................................................................. 29
FIGURA 10 - O ESTADO DAS LINHAS RB0-RB3 ............................................................................................................ 30
FIGURA 11 - ESTADO DAS LINHAS RB4-7..................................................................................................................... 31
FIGURA 12 - O TIMER0 ................................................................................................................................................ 32
FIGURA 13 - FUNCIONAMENTO DO TIMER0 .................................................................................................................. 33
FIGURA 14 - CONFIGURAO DE FUNCIONAMENTO DE TIMER0 (A) ............................................................................. 34
FIGURA 15 - CONFIGURAO DE FUNCIONAMENTO DE TIMER0 (B) ............................................................................. 35
FIGURA 16 - SINAL EXTERNO E VALOR NO TIMER0 ...................................................................................................... 35
FIGURA 17 - PRESCALER .............................................................................................................................................. 36
FIGURA 18 ESQUEMA DO CIRCUITO ........................................................................................................................... 43

Indice de Tabelas
TABELA 1 - DIVISORES DO PRESCALER ........................................................................................................................ 37
TABELA 2 - DIVISORES PARA O WDT ............................................................................................................................ 42

1. INTRODUO
O PIC16F84A um microcontrolador pertencente famlia PIC 16FXX, fabricado pela
Microchip e foi escolhido para este curso pelo fato de ser o mais popular microcontrolador
usado hoje por estudantes e empresas. Os microcontroladores so computadores em um chip.
Contm basicamente uma Unidade Lgica e Aritmtica, portas de entrada e sada configurveis
por software bit a bit, Timers, barramentos de dados e endereos, memria RAM (registradores),
memria EEPROM para configuraes do usurio final e um bloco de memria FLASH para o
programa. So usados basicamente para sistemas embarcados como por exemplo automveis,
telefones mveis, mquinas computadorizadas, CLPs, msseis, brinquedos e outras muitas
aplicaes que envolvem sistemas de tempo real, medio, controle, sistemas ABS etc.
Neste tutorial daremos uma introduo de modo a esclarecer o funcionamento bsico
destes dispositivos.

PIC16F84A

pg. 10

2. DESCRIO GERAL
O PIC um circuito integrado produzido pela Microchip, Inc., que pertence da categoria
dos microcontroladores, ou seja um componente integrado, que em um nico dispositivo contm
todos os circuitos necessrios para realizar um completo sistema digital programvel.
Podemos ver na figura 1 o seu aspecto fsico.

Figura 1- Aspecto fsico do PIC 16f84

O PIC (neste caso um PIC16C(F)84) pode ser visto externamente como um circuito
integrado TTL ou CMOS normal, mas internamente dispe de todos os dispositivos tpicos de
um sistema microprocessado, ou seja:

Uma CPU (Central Processor Unit ou seja Unidade de Processamento Central) e sua
finalidade interpretar as instrues de programa.

Uma memria PROM (Programmable Read Only Memory ou Memria Programvel


Somente para Leitura) a qual ir memorizar de maneira permanente as instrues do
programa.

Uma memria RAM (Random Access Memory ou Memria de Accesso Aleatrio)


utilizada para memorizar as variveis utilizadas pelo programa.

Uma serie de LINHAS de I/O para controlar dispositivos externos ou receber pulsos de
sensores, chaves, etc.

PIC16F84A

pg. 11

Uma srie de dispositivos auxiliares ao funcionamento, ou seja gerador de clock, bus,


contador, etc.
A presena de todos estes dispositivos em um espao extremamente pequeno, d ao

projetista ampla gama de trabalho e enorme vantagem em usar um sistema microprocessado,


onde em pouco tempo e com poucos componentes externos podemos fazer o que seria oneroso
fazer com circuitos tradicionais.
O PIC esta disponvel em uma ampla gama de modelos para melhor adaptar-se as
exigncias de projetos especficos, diferenciando-se pelo nmero de linhas de I/O e pelo
contedo do dispositivo. Inicia-se com modelo pequeno identificado pela sigla PIC12Cxx
dotado de 8 pinos, at chegar a modelos maiores com sigla PIC17Cxx dotados de 40 pinos.
Uma descrio detalhada da tipologia do PIC disponvel no site da Microchip, onde
conseguimos encontrar grandes e variadas quantidades de informaes tcnicas, software de
apoio, exemplos de aplicao e atualizaes disponveis.
Para o nosso trabalho usaremos um modelo intermedirio de PIC o PIC16C(F)84. Com
este tipo intermedirio iremos fazer um um estudo de como trabalham os microprocessadores
desta arquitetura em particular.
Este dotado de 18 pinos sendo 13 disponveis para o I/O ou seja para serem ligados ao
nosso circuito e de algumas caractersticas que o tornam um circuito que pode bem exemplificar
nosso estudo.
Em particular o PIC16C(F)84 dispe de uma memria para armazenar o programa, do
tipo EEPROM ou seja Electrical Erasable Programmable Read Only Memory, que pode ser
rescrita quantas vezes quisermos e que ideal para o experimentador tornando fcil a coneco
para a programao on-board, ou seja podemos colocar o programa dentro do chip sem ter que
remov-lo do circuito de prova.
Podemos dar uma olhada no PIC16C84. Vejamos na figura 2 a reproduo da pinagem e
nomenclatura de seus respectivos pinos:.

PIC16F84A

pg. 12

Figura 2 - Pinagem do PIC 16 C 84

Como possvel ver, o PIC16C84 dotado de um total de 18 pinos dispostos em duas


fileiras paralela de 9 pinos cada uma (dual in line - DIL). Os pinos contrastados em azul
representam as linhas de I/O disponveis para a nossa aplicao, o pino em vermelho e o preto
so os pinos de alimentao, e os em verde so reservados ao funcionamento PIC (MCLR para o
reset e OSC1-2 para o clock).

2.1.

A MEMRIA DE PROGRAMA E A MEMRIA RAM

Na figura 3 v-se ilustrado o esquema de blocos simplificado da arquitetura interna do


PIC16F84 que nos ajudar a entender o que ser explicado. As partes evidenciadas em amarelo,
a componente que iremos analisar.
Iniciemos com a memria EEPROM e o REGISTER FILE.

PIC16F84A

pg. 13

Figura 3 - Arquitetura interna do PIC

A EEPROM uma memria especial, apagvel eltricamente, utilizada no PIC para


memorizar o programa a ser executado.
A sua capacidade de memorizao de 1024 locaes as quais podero conter somente
um opcode de 14 bits ou seja uma instruo bsica do PIC. Um programa mais complexo que
podemos realizar no poder ter mais do que 1024 instrues.
Os endereos reservados para EEPROM comeam em 0000H e vo at 03FFH. O PIC
pode somente executar instrues memorizadas nestas locaes. No se pode de maneira
nenhuma ler, escrever ou cancelar dados nesses endereos.
Par escrever, ler e cancelar estas locaes necessrio um dispositivo externo
chamadoprogramador. Um exemplo de programador o

PICSTART-16+ produto da

Microchip ou pode ser outro qualquer disponvel no comrcio.


A primeira locao de memria, o endereo 0000H, deve conter a primeira instruo que
o PIC devera executar aps o reset e por isso denominada Reset Vector.
O REGISTER FILE uma parte da locao de memria

RAM denominada

REGISTRO. Diferente da memria EEPROM destinada a conter o programa, a rea de memria


RAM destinada s variveis do programa e portanto voltil. Podemos escrever, ler, ou
PIC16F84A

pg. 14

modificar tranqilamente qualquer endereo do REGISTER FILE no nosso programa a qualquer


momento em que for necessrio.
A nica limitao consiste de que alguns desses registros desenvolvem funes especiais
pelo PIC e no podem ser utilizados para outra coisa a no ser para aquilo a qual eles esto
reservados. Estes registros encontram-se nas locaes base da rea de memria RAM .
A locao de memria presente no REGISTER FILE so endereadas diretamente em um
espao de memria que vai de 00H a 4fH um total de 68 bytes, denominada pagina 0. um
segundo espao de endereamento denominado pagina 1 vai de 80H a 4fH. Para acessar esse
segundo espao necessrio recorrer a dois bits auxiliares RP0 e RP1 segundo a modalidade que
iremos explicar mais adiante.
As primeiras 12 locaes da pagina 0 (de 00H a 0BH) e da pagina 1 (de 80H a 8BH) so
aquelas reservadas as funes especiais para o funcionamento do PIC e, como j dito, no podem
ser utilizadas para outra coisa.
As 36 locaes na pagina 0 podem ser endereadas de 0CH a 4FH e podemos aqui
utilizar este espao livremente pelo nosso programa para salvar variveis, contadores, etc.
Na figura 4 est mapeado o espao da RAM, com seus endereos ou registros especiais e
gerais.

PIC16F84A

pg. 15

Figura 4 - A memria RAM

Os registros especiais do PIC sero utilizados com muita freqncia nos programas.
Por exemplo, podemos usar os registros especiais TRISA e TRISB, para definir qual
linha de I/O ser entrada e qual ser sada. O mesmo estado lgico da linha de I/O depende do
valor de dois registros PORTA e PORTB.
Alguns registros reportaro o estado de funcionamento do dispositivo interno do PIC ou o
resultado de operaes aritmticas e lgicas.
PIC16F84A

pg. 16

necessrio conhecer portanto exatamente qual funo desenvolve, cada um dos


registros especiais e qual efeito se obtm ao manipular seus contedos.
Para facilitar as operaes de seus registros especiais, podemos incluir no programa, com
a diretiva INCLUDE, o arquivo PIC16F84.INC, fornecido pela Microchip. A Microchip inseriu
uma lista de nomes que identificam univocamente qualquer registro especial e a qual esta
associado o endereo correspondente na rea do REGISTER FILE.
Se, por exemplo, quisermos definir todas as linhas do PORTB do PIC como de sada,
agindo sobre o TRISB, podemos escolher e referenciar diretamente o registro com o seu
endereo:
movlw B'00000000'
movwf 06H
ou ento, referenciar o mesmo registro com o seu nome simblico:
movlw B'00000000'
movwf TRISB
Tendo que ter a certeza de ter inserido a diretiva INCLUDE "PIC16C84.INC" no nosso
cdigo. Com a diretiva INCLUDE

2.2.

A UNIDADE LGICA E ARITMTICA (ALU) E O ACUMULADOR OU W

Iremos agora ilustrar outros dois componentes fundamentais na arquitetura do PIC, a


ALU e o registro W ou acumulador. Podemos v-los destacados na figura 5.

PIC16F84A

pg. 17

Figura 5 - O Registrador W e a Unidade Lgica e Aritmtica

A ALU (siglas de Arithmetic and Logic Unit ou seja unidade aritmtica e lgica) a
componente mais complexa do PIC por conter todos os circuitos destinados a desenvolver as
funes de clculo e manipulao de dados durante a execuo de um programa.
A ALU uma componente presente em todos os microprocessadores e dessa depende
diretamente a capacidade de clculo do micro em si.
A ALU do PIC16F84 est preparada para operar com 8 bits, ou seja valor numrico no
maior do que 255. Existem processadores com ALU de 16, 32, 64 bits e mais. A famlia Intel
80386, 486 e Pentium por exemplo dispe de uma ALU de 32 bits. A capacidade de clculo
presente nesses micros notavelmente superior em detrimento da complexidade dos circuitos
internos de suporte e consequentemente do espao ocupado.
PIC16F84A

pg. 18

Diretamente acima da ALU temos o registro W denominado por outros fabricantes de


acumulador. Este registro consiste de uma locao de memria destinada a conter um s valor
de 8 bits.
A diferena entre o registro W e outras locaes de memria consiste no fato de que, ao
referenciar o registro W, a ALU no necessita de nenhum endereo fsico, sendo acessado
diretamente.
Faamos um exemplo pratico. Suponhamos querer colocar na locao de memria 0CH
do REGISTER FILE o valor 01H. Procurando entre as instrues do PIC veremos rpido que
no existe uma nica instruo capaz de efetuar esta operao mas deveremos necessariamente
recorrer ao acumulador e usar duas instrues em seqncia. Vejamos porque:
Como dissemos anteriormente, o opcode de uma instruo no pode exceder aos 14 bits e
assim teremos:
8 bits para especificar o valor que queremos colocar na locao de memria,
7 bits para especificar em qual locao de memria queremos inserir o nosso valor,
6 bits para especificar qual instruo queremos usar.
teremos um total de 8 + 7 + 6 = 21 bits.
Devemos ento recorrer a duas instrues, ou seja:
movlw
movwf

01H
0CH

A primeira colocar no registro W o valor 01H com a instruo MOV e Literal para W e
depois "moveremos" para locao 0CH com a instruo MOV e W para F.

2.3.

CONTADOR DE PROGRAMA E A PILHA

Analisaremos agora o funcionamento do Program Counter e do Stack dois


componentes importantes para a compreenso da instruo de salto e chamada a subrotina.
Vemos estes componentes destacados na figura 6.

PIC16F84A

pg. 19

Figura 6 - A pilha e o contador de programa

Como visto, o PIC16F84 inicia a execuo do programa a partir do Reset Vector ou seja
da locao de memria 0000H. Depois de ter executado esta instruo passa para a prxima
instruo memorizada na locao 0001H e assim por diante. Se no existisse instruo capaz de
influenciar a execuo progressiva do programa, o PIC chegaria at o final na ltima instruo
memorizada na ltima locao e no saberia mais como continuar.
Sabemos obviamente que no bem assim e qualquer sistema a microprocessador ou
linguagem de programao dispe de instruo de desvio, ou seja instrues capaz de modificar
o fluxo de execuo do programa.

PIC16F84A

pg. 20

Uma destas instrues o goto (do ingls go to, v para). Quando o PIC encontra um
goto no segue mais a instruo imediatamente aps, mas desvia-se diretamente para a locao
de memria especificada na instruo.
Faamos um exemplo :

Point1

ORG 00H
movlw 10
goto Point1

No reset o PIC seguir a instruo movlw 10 memorizada na locao 0000H que colocar
no acumulador o valor decimal 10. Depois ento passar a executar a prxima goto Point1. Esta
instruo determinar um desvio incondicionado para locao de memria especificada pelo
label Point1 ou seja de novo para locao 0000H.
O programa no far outra coisa se no a de executar um ciclo infinito seguindo
continuamente as instrues especificadas.
Durante este ciclo, para determinar qual a prxima instruo a ser seguida, o PIC utiliza
um registro especial denominado Program Counter ou seja contador de programa. Este ter
sempre o endereo da prxima instruo a ser executada. No reset este estar sempre zerado,
determinando o inicio da execuo no endereo 0000H, e cada instruo ter um incremento de
um para poder passar para prxima instruo.
A instruo goto permite a colocao de um novo valor no Program Counter e
consequentemente desvia-a a uma locao qualquer da rea de programa do PIC.
Uma outra instruo muito interessante o call ou seja a chamada a subrotina. Esta
instruo funciona de maneira muito similar ao goto com a nica diferena que, a primeira,
desvia para uma locao de memria especificada e continua a execuo do programa, enquanto
o call desviar o programa para uma subrotina especificada, executar a mesma, e retornar a
execuo da instruo imediatamente aps a chamada call, o valor imediatamente aps a
chamada call ser armazenado em uma rea particular da memria denominada Stack.
Vejamos melhor com um exemplo:
ORG
Point1
movlw
PIC16F84A

00H
10
pg. 21

call Point2
goto Point1
Point2
movlw
return

11

Neste caso o PIC, aps ter executado movlw 10 passa a executar o call Point2. Antes de
desviar memoriza no Stack o endereo 0002H, ou seja a prxima locao ao call. Passa ento a
executar a instruo movlw 11, memorizada em correspondncia ao label Point2. E neste ponto
encontra uma nova instruo: o return que, como podemos deduzir de seu nome, permite o
"RETORNO", ou seja retorne a execuo da instruo imediatamente aps o call.
Esta operao denominada de: "chamada a subrotina", ou seja uma interrupo
momentnea do fluxo normal do programa para "chamar" a execuo de uma srie de instrues,
para depois retornar a execuo normal do programa.
Para poder retornar para onde havia interrompido, o PIC utiliza o ltimo valor
armazenado no Stack e o coloca de novo no Program Counter.
A palavra stack em ingls significa "pilha" e por esse fato possvel empilhar um
endereo sobre o outro para ser recuperado quando necessrio. Este tipo de memorizao era
antes denominado de LIFO do ingls Last In First Out, em que o ltimo elemento
armazenado(last in) deve necessariamente ser o primeiro a sair (last out).
Graas ao Stack possvel efetuar vrios calls, (na verdade at 8, que o tamanho da
pilha) um dentro do outro e manter sempre o retorno ao fluxo do programa quando se encontra
uma instruo return.
Vejamos um outro exemplo:
ORG

00H

Point1
movlw
10
call Point2
goto Point1
Point2
movlw
11
call Point3
return
Point3
PIC16F84A

pg. 22

movlw
return

12

No exemplo acima a rotina principal Point1 promove a chamada do primeiro call para
subrotina Point2, a subrotina Point2 chama outra subrotina no caso Point3, este ltimo por sua
vez, encontra um returm e retorna para Point2 que encontra o outro return e retorna para a
execuo da rotina Point1 que no caso a principal.
Os endereos a serem memorizados no stack so dois e quando vir a encontrar um
segundo call procurar pelo return correspondente ao primeiro e assim por diante. Se diz ento
que o call "nidificate" ( aninhado) ou seja um dentro do outro.
O PIC16F84 dispe de um stack de 8 nveis, ou seja um Stack que consegue armazenar
no mximo 8 chamadas subrotina.
importante assegurar-se, durante a formulao de um programa que, se tenha sempre
uma instruo returm em correspondncia a um call para evitar o perigo de desalinhamento do
stack que em execuo pode gerar erros que dificilmente encontraramos.

2.4.

AS PORTAS DE E/S A e B

O PIC16C84 dispes de um total de 13 linhas de I/O organizadas em duas portas


denominadas de PORTA A e PORTA B. A PORTA A dispe de 5 linhas configurveis tanto
em entrada como em sada. A PORTA B dispe de 8 linhas tambm configurveis seja em
entrada ou em sada Ver Figura 7.

PIC16F84A

pg. 23

Figura 7 - Portas A e B

A subdiviso da linha em duas portas diferentes devido ao tipo de arquitetura interna do


PIC16C84 que prev um controle de dados de no mximo 8 bits.
Para o controle da linha de I/O do programa, o PIC dispe de dois registros internos que
controlam as portas e so chamados de TRISA e PORTA para a porta A e TRISB e PORTB
para a porta B.
Os registros TRIS A e B , determinaro o funcionamento em entrada ou em sada da
mesma linha, e o registro PORT A e B determinaro o status da linha em sada ou reportaro o
status da linha em entrada.
Todos os bits contidos nos registros mencionados correspondem univocamente a uma
linha de I/O.
PIC16F84A

pg. 24

Por exemplo o bit 0 do registro PORTA e do registo TRIS A correspondem a linha RA0
, o bit 1 a linha RA1 e assim por diante.
Se o bit 0 do registro TRISA for colocado em zero, a linha RA0 estar configurada como
linha de sada, por isso o valor a que ir ao bit 0 do registro PORTA determinar o estado
lgico de tal linha (0 = 0volts, 1 = 5 volts).
Se o bit 0 de registro TRISA for colocado a um, a linha RA0 ser configurada como
linha de entrada, e se um dado for colocado a linha 0 da porta A este valor estar disponvel no
endereo da porta A (0 = 0volts, 1 = 5 volts).
Faamos um exemplo prtico: imaginemos querer conectar um led sobre a RB0 e uma
chave sobre a linha RB4, o cdigo a se escrever ser o seguinte:
movlw 00010000B
tris B
onde aqui ser colocado a 0 o bit 0(linha RB0 em escrita(sada), e a 1 o bit 4 (linha RB4) em
entrada. recorde-se de tal propsito que na notao binria do assembler o bit mais a direita
corresponde ao bit menos significativo por isso o bit 0.
Para acender o led devemos escrever o seguinte cdigo:
bsf

PORTB,0

Para apaga-lo:
bcf

PORTB,0

Para ler-mos o estado da chave conectada a linha RB4, o cdigo ser:


btfss PORTB,4
goto SwitchAMassa
goto SwitchAPositivo
2.5.

ESTADO DE ESCRITA DAS LINHAS DE E/S

Por ser o PIC mais malevel s diversas exigncias de utilizao, a Microchip tem
implementado diversas tipologia de status de escrita para a linha de I/O. Tendo ento dois grupos
de pinos aos quais o comportamento ligeiramente diferenciado do outro grupo. Conhecendo
melhor o funcionamento dos diversos status de escrita podemos desfrutar melhor das
caractersticas e otimizar melhor o nosso projeto.
PIC16F84A

pg. 25

Estado de escrita das linhas RA0, RA1, RA2 e RA3


Iniciaremos com grupo das linhas RA0, RA1, RA2 e RA3 no qual representamos, na
figura seguinte, o esquema do estado de escrita extrado do data sheet da Microchip:

Figura 8 - Estado das linhas RA

Como dito anteriormente, a configurao de uma linha como entrada ou sada depende
do estado do bit no registro TRIS(TRISA para o PORTA e TRISB para o PORTB).
Tomaremos como exemplo a linha RA0 e analisaremos o funcionamento do estado de
sada seja quando a mesma funciona em entrada ou quando em sada.

PIC16F84A

pg. 26

Funcionamento em entrada
Para configurar a linha RA0 em entrada, devemos colocar em 1 o bit 0 do registro
TRISA com a instruo:
bsf

TRISA,0

Esta instruo determinara uma comutao a 1 do estado lgico do flip-flop do D-latch


indicado no bloco com o nome TRIS latch. Para outra linha de I/O existe um destes flip-flop e o
estado lgico em que se trava depende extritamente do estado lgico do relativo bit no registro
TRIS(ou melhor dizendo todos o bit's do registro TRIS so fisicamente implementados com um
TRIS latch).
A sada Q do TRIS latch conectada a entrada de uma porta lgica do tipo OR. Isto
significa que, independente do valor presente a outra entrada, a sada da porta OR estar sempre
em 1 enquanto uma de suas entradas vale 1(veja na tabela verdade). E nesta condio o
transistor P no conduz e mantm a linha RA0 desconetada do positivo da alimentao.
Do mesmo modo a sada negativa Q do TRIS latch conectada a entrada de uma porta
AND onde a sada desta estar sempre em 0 enquanto uma de suas entradas vale 0 (veja tabela
verdade). E nesta condio o transistor N no conduz mantendo a linha RA0 desconectada da
massa. O estado lgico da linha RA0 depender exclusivamente do circuito externo a que o
conectarmos.
Aplicando 0 ou 5 volts ao pino RA0, ser possvel lermos o estado presente no circuito
externo entrada do bloco representado por TTl input buffer e do latch de entrada.
Funcionamento em sada
Para configurar a linha de RA0 em sada, devemos colocar em 0 o bit 0 do registro
TRISA com a instruo:
bcf

TRISA,0
Esta determina a comutao para 0 da sada Q do TRIS latch ( e para 1 a sada Q

negativa). E neste estado o valor da sada da porta OR e AND depende exclusivamente do estado
de sada do Q negativo do Data Latch. Como para o TRIS latch, em que o Data Latch depende
do estado de um bit em um registro, particularmente do registro PORTA. A sua sada negativa
PIC16F84A

pg. 27

ser enviada para entrada das duas portas lgicas OR e AND e que esto diretamente sobre a
base do transistor P e N.
Se colocar-mos em 0 o bit 0 do registro PORTA com a instruo:
bcf

PORTA,0

obteremos a conduo do transistor N e portanto ir a 0 a linha RA0. Se ao invs colocarmos


em 1 o bit 0 com a instruo:
bsf

PORTA,0

obteremos a conduo do transistor P e portanto ira a +5 volts a linha RA0. Nesta condio ser
sempre possvel rever o valor enviado sobre a linha atravs do circuito de entrada.
Estado de sada da linha RA4
Analisaremos agora o funcionamento do estado de sada da linha RA4 que diferente de
todas as outras linhas de I/O enquanto compartilha o mesmo pino do PIC16c84 com o TOCKI .
Na figura seguinte est descrito o esquema de blocos do estado de sada extrado do data
sheet Microchip:

PIC16F84A

pg. 28

Figura 9 - a porta RA4

A lgica de comutao substancialmente idntica ao grupo das linha RA0 a 3 com


exceo da ausncia da porta OR e do transistor P, ou seja de todos os circuitos que permitem a
ligao ao positivo, da linha RA4. Isto significa em termos prticos, que quando a linha RA4 esta
programada em sada poder assumir um nvel que depender do circuito externo pois na
realidade no est conectada ao positivo e sim desconectada. Este tipo de circuito de sada
chama-se "coletor aberto" e til para aplicaes em que necessrio compartilhar uma mesma
ligao com mais pinos de sada ou que se tenha a necessidade de colocar em alta impedncia
uma linha de sada e podendo assim reprogram-la como linha de entrada.
Se quisermos tornar seguro que a linha RA4 v a 1 devemos conectar externamente um
resistor de pull-up, ou seja um resistor conectado ao positivo da alimentao.
Veremos em seguida a utilizao da linha indicada no esquema acima TMR0 clock input.
PIC16F84A

pg. 29

Estado de sada das linhas RB0, RB1, RB2 e RB3


Para este grupo de linhas a lgica de comutao permanece invarivel. Estas dispe de
um circuito a mais, o weak pull-up ativvel quando a linha for programada em entrada.
A entrada de fato, como explicado anteriormente, a linha vem completamente desligada
do PIC. O estado da linha depende ento exclusivamente do circuito externo. Se o circuito do
tipo de coletor aberto ou simplesmente constitudo de uma simples chave que, quando
pressionada, conecta a massa a linha de I\O, necessrio inserir um resistor de pull-up vinda do
positivo para tornar seguro quando a chave for solta o nvel voltar a uma condio lgica 1
estvel sobre a linha de entrada. O circuito de weak pull-up permite evitar o uso do resistor de
pull-up e possvel de ser ativado agindo sobre o bit RBPU do registro OPTION.
Na figura seguinte est representado o esquema de blocos do estado de sada extrado do
data sheet Microchip:

Figura 10 - O estado das linhas RB0-RB3

Alm disso a linha RB0 sozinha, apresenta uma caracterstica muito particular. Esta ,
quando for configurada como linha de entrada, pode gerar, em correspondncia a uma troca de
estado lgico, uma interrupt, ou seja uma interrupo imediata do programa em execuo e uma
PIC16F84A

pg. 30

chamada a uma subrotina especial denominada interrupt handler. Mas disso falaremos em
seguida.
Estado de sada das linhas RB4, RB5, RB6 e RB7
O circuito de comutao deste grupo de linhas idntico ao grupo RB0 a 3. Esta linha
dispe tambm de um circuito de weak pull-up. E mais, com respeito a linha RB0 - 3 tem a
vantagem de poder revelar variaes de estado sobre qualquer linha e gerar uma interrupo.
Na figura seguinte esta reproduzido o esquema de blocos do estado de sada extrado do
data sheet Micrchip.

Figura 11 - Estado das linhas RB4-7

PIC16F84A

pg. 31

2.6.

O REGISTRO CONTADOR TIMER0

Figura 12 - O Timer0

O registro TMR0 (figura 12) um contador, ou seja um registro particular, na qual, seu
contedo v-se incrementado com cadncia regular e programada diretamente pelo hardware do
PIC. Na prtica, a diferena de outro registro, que o TMR0 no mantm inalterado o valor que
memorizado, mas o incrementa continuamente, se por exemplo escrevermos nele o valor 10
com a instruo:
PIC16F84A

pg. 32

movlw
10
movwf
TMR0
Aps um tempo par de quatro ciclos de maquina, o contedo do registro comea a ser
incrementado em +1 ou seja 11, 12, 13 e assim por diante com a cadncia constante e
independente da execuo do resto do programa.
Se por exemplo, aps ter colocado um valor no registro TMR0, executar-mos um loop
infinito
Loop

movlw
movwf

10
TMR0

goto loop
o registro TMR0 ser incrementado pelo hardware interno do PIC durante a execuo do loop.
Uma vez atingido o valor 255 o registro TMR0 ser zerado automaticamente retornando
ento a contagem, mas no do valor originalmente imposto mas do zero.
A freqncia diretamente proporcional a freqncia de clock aplicada ao chip e pode ser
modificada programando-se oportunamente os seus bits de configurao.
Na figura 13 est representada a cadeia de blocos internos do PIC que determina o
funcionamento do registro TMR0.

Figura 13 - funcionamento do Timer0

O bloco Fosc/4 e T0CKI representados em azul representam as duas possveis fontes de


sinal para o contador TMR0.
PIC16F84A

pg. 33

Fosc/4 um sinal gerado internamente no PIC pelo circuito de clock e par na freqncia
de clock dividida por quatro.
T0CKI um sinal gerado de um eventual circuito externo e aplicado ao pino T0CKI
correspondente ao pino 3 no PIC 16C84.
O blocos T0CS e PSA descritos em verde so dois comutadores de sinal na qual esto
representando um dos dois tipos de sinal de entrada com base no valor dos bits TOCS e PSA do
registro OPTION.
O bloco PRESCALER um divisor programvel e que seu funcionamento ser
explicado mais adiante.
Vejamos na prtica como possvel agir sobre este bloco para obter diferentes
modalidades de contagem pelo registro TMR0.
Iniciaremos programando o bit T0CS em 0 e PSA em 1. A configurao de
funcionamento que obteremos a representada na figura 14 abaixo:

Figura 14 - Configurao de funcionamento de Timer0 (a)

A parte em vermelho mostra-nos o percurso que efetua o sinal antes de chegar ao


contador TMR0.
Como j havamos dito anteriormente, a freqncia Fosc/4 par e de um quarto da
freqncia de colck. Utilizando-se um cristal de quartzo de 4Mhz teremos uma freqncia par de
1 MHz. Tal freqncia ser enviada diretamente ao registro TMR0 sem haver nenhuma
modificao. A cadncia de contagem que se obtm ento par e de 1 milho de incrementos por
segundo do valor presente no TMR0.
PIC16F84A

pg. 34

Imaginemos agora modificar o status do bit T0CS de 0 para 1 a configurao que


obteremos seguinte:

Figura 15 - Configurao de funcionamento de Timer0 (b)

Desta vez ser o sinal aplicado ao pino TOCKI do PIC a ser enviado diretamente ao
contador TMR0 determinando a freqncia de contagem. Aplicando-se por exemplo a este pino
uma freqncia par de 100Hz obteremos uma de contagem par de cem encrementos por segundo.
A presena da porta lgica XOR(exclusive OR) na entrada TOCKI do PIC permite
determinar o caminho do bit TOSE do registro OPTION se o contador TMR0 deve ser
incrementado na decida do pulso(TOSE=1) ou na subida do pulso(TOSE=0) do sinal externo
aplicado.
Na figura seguinte est representada a correspondncia entre a cadncia do sinal externo e
o valor que assume o contador TMR0 :

Figura 16 - Sinal externo e valor no Timer0

PIC16F84A

pg. 35

2.7.

PRESCALER

O ltimo bloco a ser analisado para poder utilizar completamente o registro TMR0 o
PRESCALER.
Se configurarmos o bit PSA do registro OPTION em 0 enviamos ao registro TMR0 o
sinal de sada do PRESCALER como visvel na figura abaixo:

Figura 17 - Prescaler

O PRESCALER consiste na prtica de um divisor programvel de 8 bits utilizado no caso


pela freqncia de contagem enviada ao contador TMR0 que demasiada alta para nossos
propsitos.
Havamos visto que utilizando um cristal de 4Mhz obtnhamos uma freqncia de
contagem par de 1 Mhz que para muitas aplicaes poder ser muito elevada.
Com o uso do PRESCALER podemos dividir interiormente a freqncia Fosc/4
configurando desta forma os bits PS0, PS1, PS2 do registro OPTION segundo a tabela abaixo:
PS
2
0
0
0
0
1
1
1
1

PS
1
0
0
1
1
0
0
1
1

PIC16F84A

PS
0
0
1
0
1
0
1
0
1

Divisor

Freqncia de sada do prescaler (Hz)

2
4
8
16
32
64
128
256

500.000
250.000
125.000
62.500
31.250
15.625
7.813
3.906
pg. 36

Tabela 1 - divisores do prescaler

2.8.

INTERRUPES

A interrupo uma tcnica particular do PIC que permite interceptar eventos externos ao
programa em execuo, interrompe momentaneamente a operao do programa em andamento,
controla o evento com uma subrotina apropriada e retorna para a execuo do programa.
Para fazer um pargrafo mais ou menos explicativo, podemos dizer que a interrupo
para o PIC, se no, o que para ns representaria uma chamada telefnica.
Para receber-mos um telefonema no precisamos nos preocupar em ficar levantando
continuamente o monofone do gancho para ver se tem algum querendo falar com ns, mas
podemos tranqilamente aguardar pelo toque da campainha quando algum nos chama. Quando
ento apenas levantamos o monofone do gancho e interrompemos momentaneamente o sistema
de chamada, respondemos ao telefone e uma vez terminada a conversao, retornamos o
monofone no gancho ou seja, do ponto onde havamos interrompido.
Transportando o termo deste pargrafo ao PIC veremos que::

O nosso telefone corresponde ao programa em execuo;

a chamada de algum corresponde ao evento de controle;

o monofone corresponde a requisio de interrupo;

a nossa reposta ao telefone corresponde a subrotina de controle da interrupo.


evidente que assim como extremamente mais eficaz se ter uma campainha conectada

ao telefone extremamente mais eficaz controlar nosso evento com uma interrupo ao invs de
diretamente pelo programa.
Tipos de eventos e bit's de habilitao
O PIC16C84 est preparado para controlar interrupes ao final de quatro eventos
diferentes, vejamos quais so:
1. A troca de estado sobre a linha RB0 (External interrupt RB0/INT pin).
PIC16F84A

pg. 37

2. Ao final da contagem do registro TMR0 (TMR0 overflow interrupt).


3. A troca de estado sobre uma das linhas de RB4 a RB7 (PORTB change interrupts).
4. Ao final da escrita sobre um endereo da EEPROM (EEPROM write complete interrupt).
A interrupo de qualquer um destes eventos pode ser conseguido habilitando ou
desabilitando independentemente uns dos outros, agindo sobre os seguintes bit's do registro
INTCON:

INTE (bit 4) se este bit estiver em 1 habilitara a interrupo de troca de estado sobre a
linha RB0

T0IE (bit 5) se este bit estiver em 1 habilitara a interrupo de final de contagem do


registro TMR0

RBIE (bit 3) se este bit estiver em 1 habilitara a interrupo de troca de estado sobre uma
das linhas de RB4 a RB7

EEIE (bit 6) se este bit estiver em 1 habilitara a interrupo de final de escrita sobre um
endereo da EEPROM
Existe um outro bit de habilitao geral de interrupo que deve ser setado antes destes ou

seja o bit GIE (Global Interrupt Enable bit) e este o bit 7 do registro INTCON.
Vetor de Interrupo e Controle de Interrupo (Interrupt vector e Interrupt handler)
Qualquer que seja o evento habilitado, ao se manifestar, o PIC interrompe a execuo do
programa em andamento, memoriza automaticamente no STACK o valor corrente do
PROGRAM COUNTER e pula para a instruo presente no endereo de memria 0004H
denominada Interrupt vector(vetor de interrupo).
Deste ponto em diante devemos colocar a nossa subrotina de controle denominada
Interrupt Handler (controle de interrupo).
Pode-se habilitar mais interrupes e, a primeira providncia da interrupt handler a de
verificar qual o evento habilitado fez gerar a interrupo e a execuo da parte do programa
relativo
Este controle pode ser efetuado utilizando a Interrupt flag.

PIC16F84A

pg. 38

Interrupt flag(sinalizador de interrupo)


Dado que qualquer interrupo gera uma chamada do endereo 04H, no registro
INTCON esta presente o flag que indica qual o evento que gerou a interrupo vejamos:

INTF (bit 1) Se vale 1 a interrupo um estado gerado na troca de estado sobre a linha
RB0.

T0IF (bit 2) Se vale 1 a interrupo um estado gerado no termino da contagem do timer


TMR0.

RBIF (bit 0) Se vale 1 a interrupo um estado gerado da troca de estado de uma das
linhas de RB4 a RB7.
Como se pode ver a interrupo de final de escrita na EEPROM no tem previsto nenhum

flag de sinalizao para que a interrup handler deva considerar que a interrupo um estado
gerado deste evento quando todos os trs flags supra citados iro a 0.
Importante: Uma vez conhecido qual o flag esta ativo, a interrupt handler deve zera-lo,
ou ento no mais gerara interrupo correspondente.
Retorno de uma interrupt handler
Quando for gerada uma interrupo o PIC desabilita automaticamente o bit GIE(global
Interrupt Enable) do registro INTECON de modo a desabilitar todas as interrupes restantes.
Para poder retornar ao programa principal e reinicializar em 1este bit deve-se utilizar a instruo
:
RETFIE

2.9.

FUNCIONAMENTO DO Power Down mode

O Power Down Mode e Sleep Mode um estado particular de funcionamento do


PICmicro utilizado para reduzir o consumo de corrente no momento em que o PICmicro no
utilizado e aguarda um evento externo.
Se pegarmos como exemplo um controle remoto para TV veremos que na maior parte do
tempo o PICmicro permanece aguardando que algum pressione uma tecla. Apenas quando

PIC16F84A

pg. 39

pressionamos o PICmicro efetua uma breve transmisso e se coloca de novo a espera de um novo
pressionar de tecla.
O tempo de utilizao efetivo da CPU do PICmicro ento limitado a poucos
milisegundos necessrios para efetuar a transmisso ao passo que para outros no preciso
nenhuma elaborao particular.
Para evitar o consumo intil frente a limitada energia da bateria possvel desligar boa
parte do circuito de funcionamento do PICmicro e reaviv-lo somente quando um evento externo
ocorrer.
Vejamos como.
A instruo SLEEP
A instruo SLEEP ser utilizada para colocar o PICmicro em Power Down Mode e
reduzir consequentemente a corrente absorvida que passar de cerca dos 2mA(a 5 volts com
clock de 4Mhz) para cerca dos 2uA, ou seja 1000 vezes menos !
Para entrar em Power Down Mode basta inserir-mos esta instruo em um ponto qualquer
do nosso programa:
SLEEP
Qualquer instruo presente depois de SLLEP no ser executada pelo PICmicro que
terminar neste ponto sua execuo, desligar todos os circuitos internos, menos aqueles
necessrios a manter o estado da linha de I/O (estado lgico alto, baixo ou de alta impedncia)
para informar a condio de "reaviv-lo" o qual veremos em seguida.
Para reduzir o consumo de corrente neste estado, no devemos fazer obviamente um
circuito que conectado a linha de escrita do PIC consuma corrente excessiva. O melhor circuito
que podemos projetar aquele que absorver o mnimo de corrente na condio de Power Down.
Um outro truque recomendado pela Microchip conectar ao positivo (Vdd) ou ao negativo(vss)
da alimentao todas a linhas em alta impedncia no utilizadas, como a linha RA4/T0CKI (pin
3).
O "despertar" do PICmicro
Para despertar o PICmicro do seu sono podemos utilizar diversas tcnicas:
PIC16F84A

pg. 40

1. Reset do PICmicro colocando em 0 o pino MCLR (pino 4)


2. Timeout do timer do Watchdog (se habilitado)
3. Verificao de uma situao de interrupo (interrupo do pino RB0/INT, troca de
estado sobre a porta B, trmino da operao de escrita na EEPROM)
No caso 1 e 2 o PICmicro ser resetado e a execuo comear da posio 0.
No caso 3 o PICmicro se comporta como no atendimento de uma interrupo ir para a
primeira interrup handler e ento retornar para execuo aps a instruo SLLEP. Para que o
PICmicro possa retornar de uma interrupo devemos habilitar o flag do registro INTCON.

2.10. WATCH DOG TIMER


Analisaremos agora o funcionamento do Watch Dog Timer (que traduzindo em
Portugus significa Co de Guarda) e sua finalidade a de melhorar o funcionamento do nosso
circuito baseado no PICmicro.
O Watch Dog Timer na prtica um oscilador interno do PICmicro, mas completamente
independente do resto do circuito, cuja finalidade informar eventuais bloqueios da CPU do
micro e resetar o PICmicro para poder retornar a execuo normal do Programa.
Para poder informar um eventual bloqueio da CPU durante a execuo do programa
principal, ser colocada dentro deste, uma instruo especial, ou seja:
CLRWDT (CLear Watch Dog Timer), a qual zerara em intervalos regulares o Watch Dog
Timer e assim no permitindo o mesmo, terminar sua contagem. Se a CPU no executa esta
instruo antes de terminar a contagem ser entendido como um bloqueio de programa por
motivo qualquer, e ser efetuado o Reset da CPU.
O perodo mnimo para que a CPU seja resetada de cerca de 18ms (isso dependera da
temperatura e da tenso de alimentao). Porem possvel programar o PRESCALER do Watch
Dog Timer para obter um tempo de retardo maior com cerca de 2 a 3 segundos.
Para habilitar o Watch Dog Timer devemos habilitar na fase de programao o flag
WDTE do byte de configurao. O meio de ativao deste flag depende do programador que
esteja sendo usado.

PIC16F84A

pg. 41

Ajuste do PRESCALER ao WDT


Agindo sobre o bit PSA do registro OPTION_REG possvel ajustar o prescaler do
Watch Dog Timer para obtermos tempo de retardo maiores. O bit PSA ser setado em um com a
instruo:
BSF OPTION_REG,PSA
Caso contrrio o prescaler estar ligado ao TIMER 0. Obviamente ajustando o prescaler
ao WTD no ser possvel ajust-lo completamente para TIMER 0 e vice-versa.
Intervindo sobre o valor do bit PS0, PS1 e PS2 do mesmo registro OPTION_REG
podemos obter diversos intervalos de retardo. A setagem correta dever ser feita tendo em conta
o mximo retardo que podemos obter dentro do nosso programa entre a execuo de duas
instrues CLRWD sucessivas.
Na tabela seguinte esta representada a correspondncia entre os valores destes bit's e os
intervalos que obteremos.
PS2
0
0
0
0
1
1
1
1

PS1
0
0
1
1
0
0
1
1

PS0
0
1
0
1
0
1
0
1

Divisor
1
2
4
8
16
32
64
128

Perodo de retardo do WDT


18ms
36ms
72ms
144ms
288ms
576ms
1.152s
2.304s

Tabela 2 - Divisores para o wdt

Um exemplo simples de utilizao


Iremos agora dar um exemplo prtico de utilizao do PIC visto num circuito
extremamente simples, com o intuito de piscar uma seqncia de 8 Leds sinalizadores.
Utilizaremos um programador de PIC desenvolvido no Laboratrio de Eletrnica desta
Universidade e um circuito montado em prottipo.
Esquema do programador pode ser visto abaixo:

PIC16F84A

pg. 42

Figura 18 Esquema do circuito

O circuito acima dever ser ligado porta paralela do PC e executar o programa em C


denominado NOPPP que consta do apndice 2.
O programa dever ser compilado pelo aplicativo Mpasmwin.exe, fornecido
gratuitamente pela Microchip em seu site.
Uma vez gravado o PIC deve ser retirado do programador e inserido no circuito de
aplicao que nada mais do que um PIC com 8 leds ligados porta B.
programa pode ser visto abaixo:

; arquivo DEMO.ASM
; Cdigo assembler para o microcontrolador PIC16F84
; Dever piscar leds em um padro rotativo
; Com oscilador de 75 KHz devero piscar a cada 1/2 segundo.
;configurao da CPU
;
( um 16F84, com oscildor a RC
;
watchdog timer desligado, power-up timer ligado)

PIC16F84A

pg. 43

processor 16f84
include
<p16f84.inc>
__config _RC_OSC & _WDT_OFF & _PWRTE_ON
; declarao de 2 variveis na memria
J
K

equ
equ

H'1F'
H'1E'

; J = address hex 1F
; K = address hex 1E

; Programa
org

; comea no endereo 0

; Setar porta B como sada e inicializ-la


bsf status,rp0 ;estamos no banco um
movlw
B'00000000'
; w := 00000000 em binrio
movwf
TRISB
; port B ctrl register := w
bcf status,rp0 ;estamos no banco zero
movlw
B'00000001'
; w := 00000001 binary
movwf
PORTB
; port B := w
; rotaciona os bits
mloop:

rlf

PORTB,f

; gasta algum tempo


movlw
D'50'
; w := 50 decimal
movwf
J
; J := w
jloop:
movwf
K
; K := w
kloop:
decfsz
K,f ; K = K-1, pula a prxima se zero
goto
kloop
decfsz
J,f ; J = J-1, pula se zero
goto jloop
; faz tudo de novo
goto

mloop

end

PIC16F84A

pg. 44

Bibliografia
Manual 1998 Microchip Tecnologic Inc
http:// microchip.com.br

PIC16F84A

pg. 45

Apndice 1 - Tabela dos cdigos de instruo do PIC16F84


Operador, Minemnico
ADDWF
ANDWF
CLRF
CLRW
COMF
DECF
DCFSZ
INCF
INCFSZ
IORWF
MOVF
MOVWF
NOP
RLF
RRF
SUBWF
SWAPF
XORWF

PIC16F84A

Descrio
f,d Add W and f
f,d And Wwith f
f
Clear f
Clear W
f,d Complement f
f,d Decrement f
f,d Decrement f, Skip if 0
f,d Increment f
f,d Increment f, Skip if 0
f,d Incluse Or W with f
f,d Move f
f
Move w to f
No Operetion
f,d Rotate Left f Through Carry
f,d Rotate Right f Through Carry
f,d Subtract W from f
f,d Swap nibbles in f
f,d Exclusive OR W with f

pg. 46

Apndice 2 - Circuito para o programador de PIC

PIC16F84A

pg. 47

Apndice 3 - Cdigo em C para o programador de PIC

// NOPPP.C (Revised) - M. Covington 1997, 1998


// Software for the "No-Parts Pic Programmer"
// Inspired by David Tait's TOPIC; compatible therewith.
// This is Microsoft C.
// Be sure to compile for 8088 (not 286 or 386) for maximum portability.
// Command line arguments:
//
None.
// Environment variable:
//
PPLPT=n where n=1, 2, or 3
#include
#include
#include
#include
#include

specifies which LPT port to use.

<stdio.h>
<conio.h>
<stdlib.h>
<ctype.h>
<string.h>

typedef unsigned int word;


typedef unsigned char byte, bit;
// *********************************************************************
// GLOBAL STATUS VARIABLES
// *********************************************************************
int LPT = 0,
PORT = 0;
#define
#define
#define
int

PIC16C84
PIC16F84
PIC16F83
DEVICE =

// which LPT port we're using (1..3)


// its port address
1
2
3
0;

// which PIC we're programming

#define PROGRAM 1
#define VERIFY 0

// desired action in main programming loop

char

FNAME[255];

// name of file currently loaded

char

CHOICE = 0;

// user's most recent menu choice

// *********************************************************************
// I/O UTILITIES
// *********************************************************************
#define KBUFSIZE 256
char buf[KBUFSIZE];

// keyboard input buffer

char* cleanctrl(char *s) {


int i=0;
while (s[i] >= ' ') i++;
s[i] = 0;
return s;

// truncates string at first ctrl char,


// cleaning up ^M or ^J left behind by fgets

PIC16F84A

pg. 48

}
char* getstring() {
fgets(buf,KBUFSIZE-1,stdin);
cleanctrl(buf);
return buf;
}

// read string

int getint()

// read integer

{ return atoi(getstring()); };

char getchoice(char *s) {


// read menu choice
// prints prompt, then reads letters, uppercasing,
// until a letter that is in s is found
printf("\n\nYour choice (%s): ",s);
do {
CHOICE = _getch();
CHOICE = toupper(CHOICE);
// toupper evals arg twice, so arg can't be _getch()
}
while ((CHOICE == ',') || (strchr(s,CHOICE) == NULL));
printf("%c\n",CHOICE);
return CHOICE;
}
void clearscreen() {
__asm {
mov ax,0f00h
int 010h
mov ah,0
int 010h
}
}
void waitkey() {
while (_kbhit()) { _getch(); };
puts("\nPress space bar to continue...");
_getch();
while (_kbhit()) { _getch(); };
}
void errmsg(char *s) {
puts(s);
waitkey();
}
// *********************************************************************
// TIMING
// *********************************************************************
#define IODELAY (_inp(0x61))
void
//
//
//
//

// allow time for timer to respond

delay(int k) {
Delay at least k microseconds, possibly a good bit more.
k must be less than 27304.
Minimum delay on a 25-MHz 386 is about 100 microseconds;
on a 133-MHz Pentium, about 18 microseconds.

// Uses system timer 2.


// When running in a DOS box under OS/2, set HW_TIMER ON in DOS settings.
PIC16F84A

pg. 49

unsigned int w;
unsigned char lo,hi;
_outp(0x61, (_inp(0x61) & 0xFD) | 1); // spkr off, tmr 2 gate on
w = (unsigned int)(k*1.2);
_outp(0x43, 0xB0);
// tmr 2 mode 0 2-byte load
IODELAY;
_outp(0x42, (unsigned char)w);
// low byte
IODELAY;
_outp(0x42, (unsigned char)(w>>8)); // high byte
IODELAY;
do {
_outp(0x43,0x80);
// latch timer count
IODELAY;
lo = _inp(0x42);
// discard low byte
IODELAY;
hi = _inp(0x42);
// get high byte
IODELAY;
}
while ((hi & 0x80) == 0);
// wait for a 1 there, signifying rollover
return;
}
// *********************************************************************
// PARALLEL PORT HARDWARE INTERFACE
// *********************************************************************
//
//
//
//
//
//

Uses two-wire serial data communication through printer port.


Pin 1, STROBE, is serial clock;
Pin 14, AUTOFD, is serial data out to PIC;
Pin 11, BUSY,
is serial data in from PIC;
Pin 17, SLCTIN, is low when writing, high to provide pull-up when reading;
Pin 2, D0,
is lowered to apply Vpp.

// SLCTIN and BUSY are tied together for pull-up and for hardware detection.
// (In current versions this is done through diodes or gates.)
//
//
//
//

SLCTIN is an open-collector output with pull-up.


If it is pulled down, some printer ports will latch it down.
Accordingly, it and all the other control bits are asserted
every time they are needed.

byte BITS = 0x0F;


word portaddr(int n) {
return(*(word far *)(0x00000408+2*n-2));
}

// base address of port LPTn

// Procedures to set and clear the data lines


void datawritable() {
BITS |= 0x0A; _outp(PORT+2,BITS);
}
void datareadable() {
BITS &= ~0x0A; _outp(PORT+2,BITS);
}
void datadown()
void dataup()
PIC16F84A

// SLCTIN, AUTOFD down


// SLCTIN, AUTOFD up

{ BITS |= 0x02; _outp(PORT+2, BITS); } // AUTOFD down


{ BITS &= ~0x02; _outp(PORT+2, BITS); } // AUTOFD up
pg. 50

void clockdown()
void clockup()

{ BITS |= 0x01; _outp(PORT+2, BITS); } // STROBE down


{ BITS &= ~0x01; _outp(PORT+2, BITS); } // STROBE up

void vppon() {
BITS &= ~0x04;
_outp(PORT+2, BITS);
_outp(PORT,
0
);
}

// INIT down, D0 down

void vppoff() {
BITS |= 0x04;
_outp(PORT+2, BITS);
_outp(PORT,
1
);
}

// INIT up,

bit

datain()

D0 up

{ return(((~(byte)_inp(PORT+1)) & 0x80) >> 7); }

void allpinslow() {
vppoff();
//datawritable();
//datadown();
//clockdown();
BITS = 0x0F;
_outp(PORT+2, BITS);
}
bit
detecthardware() {
together.
datawritable(); // SLCTIN down
dataup();
// AUTOFD up
delay(10);
if (datain() == 1) return(0);
datareadable(); // SLCTIN up
dataup();
// AUTOFD up
delay(10);
if (datain() == 0) return(0);
return(1);
}

// True if BUSY and SLCTIN are tied

// *********************************************************************
// PIC COMMUNICATION ROUTINES
// *********************************************************************
void sendbit(bit b) {
if (b) dataup(); else datadown();
clockup();
delay(1);
clockdown();
edge
delay(1);
datadown();
}

// Sends out 1 bit to PIC

bit recvbit() {
bit b;
clockup();
delay(1);
clockdown();
b = datain();
delay(1);
PIC16F84A

// Receives a bit from PIC

// tset1
// data is clocked into PIC on this
// thld1
// idle with data line low

// tdly3
// data is ready just before this
// thld1
pg. 51

return b;
}
void sendcmd(byte b) {
int i;
datawritable();
delay(2);
for (i=6; i>0; i--) {
sendbit((bit)(b & 1));
b = b >> 1;
}
delay(2);
}

// Sends 6-bit command from bottom of b

void senddata(word w) {
int i;
datawritable();
delay(2);
sendbit(0);
for (i=14; i>0; i--) {
sendbit((bit)(w & 1));
w = w >> 1;
}
sendbit(0);
delay(2);
}

// Sends 14-bit word from bottom of w

word recvdata() {
int i;
bit b;
word w = 0;
datareadable();
delay(2);
recvbit();
for (i=0; i<14; i++) {
b = recvbit();
w = w | ((word)b << i);
}
recvbit();
delay(2);
return w;
}

// Receives 14-bit word, lsb first

// thld0

// tdly2

// thld0
// one garbage bit
// 14 data bits
// one garbage bit
// tdly2

// SLCTIN up for pull-up


// thld0
// one garbage bit
// 14 data bits
// another garbage bit;
// tdly2

// *********************************************************************
// PIC PROGRAMMING ALGORITHMS
// *********************************************************************
// PIC MEMORY MAP
// The PIC16F84 has four programmable memory areas
// (plus data RAM, which is not programmable).
// Config memory is only 1 byte, but is treated like the others.
#define
#define
#define
#define

PBASE
IBASE
CBASE
DBASE

#define PSIZEMAX
#define ISIZEMAX
PIC16F84A

0
0x2000
0x2007
0x2100

// Base address of each memory

1024
4

// Max size of each memory


pg. 52

#define CSIZEMAX
#define DSIZEMAX

1
64

word
word
word
word

PSIZE
ISIZE
CSIZE
DSIZE

=
=
=
=

word
word
word
word

PMEM[PSIZEMAX];
IMEM[ISIZEMAX];
CMEM[CSIZEMAX];
DMEM[DSIZEMAX];

// Arrays representing the memories

word
word
word
word

PUSED
CUSED
IUSED
DUSED

=
=
=
=

// Number of valid words in array

#define
word
#define
#define

PMASK
CMASK
IMASK
DMASK

0x3fff
= 0x001f;
0x3fff
0x00ff

word

DEFAULTCONFIG

PSIZEMAX;
ISIZEMAX;
CSIZEMAX;
DSIZEMAX;

0;
0;
0;
0;

0x1B;

void cleararrays () {
PUSED =
IUSED =
CUSED =
DUSED = 0;
}

// Actual size, can be set lower


// for particular CPUs

// Which bits are used in each word


// (CMASK depends on processor)

// Initialization for config word


// Mark the memory arrays as empty

bit

stuffarray (word address,


// Stuff data into a memory array.
word array[],
// Returns true if successful.
word base,
word size,
word *used,
word data[],
int count) {
int i;
if (address-base+count-1 > size) {
printf("Invalid address: %04XH\n",address+count-1);
return 0;
}
for (i=0; i<count; i++) {
array[i+address-base] = data[i];
if (*used < address-base+count) *used = address-base+count;
}
return 1;

}
// PIC PROGRAMMING COMMANDS
byte LOADCONFIG
byte LOADPROGRAM
byte READPROGRAM
byte INCREMENTADDRESS
byte BEGINPROGRAMMING
byte LOADDATA
byte READDATA
PIC16F84A

=
=
=
=
=
=
=

0;
2;
4;
6;
8;
3;
5;
pg. 53

byte ERASEPROGRAM
byte ERASEDATA

= 9;
= 11;

// PROGRAMMING PROCEDURES
void vppreset() {
vppoff();
datawritable();
datadown();
clockdown();
delay(25000);
vppon();
delay(25000);
}

// reset PIC, apply Vpp

void progcycle(byte cmd, word arg) {


// send a command and an argument,
sendcmd(cmd);
// then program EPROM accordingly
senddata(arg);
sendcmd(BEGINPROGRAMMING);
delay(20000); // PIC errata sheet says 10ms is typical, not guaranteed
}
bit programall(
// Program a memory from appropriate array.
// Returns true if successful.
int mode,
// program or verify
word mask,
// to throw away irrelevant bits
byte writecommand,
// command to write this memory
byte readcommand,
// command to read this memory,
word array[],
// which memory array we're using
word base,
// its base address
word used) {
// number of valid words in array
word i,w;
switch(mode) {
case PROGRAM: puts("programming..."); break;
case VERIFY: puts("verifying..."); break;
}
for (i=0; i<used; i++) {
printf("%04X\b\b\b\b",i+base);
// display addr and backspace
if (mode==PROGRAM)
progcycle(writecommand,(array[i] & mask));
sendcmd(readcommand);
w = (recvdata() & mask);
if (w != (array[i] & mask)) {
printf("Failed at %04X: Expecting %04X, found %04X.\n",
i+base, (array[i] & mask), w);
return 0;
}
sendcmd(INCREMENTADDRESS);
}
return 1;
}
// *********************************************************************
// HEX FILE LOADER
// *********************************************************************
// This is for Intel INHX8M (8-bit merged) hex files only.
// These files use two bytes for each word (low, then high).
PIC16F84A

pg. 54

// All addresses are doubled, i.e., 0x2001 is encoded as 0x4002,


// so that addresses increment at the same rate as the byte count.
bit validhexline(char *s) {
byte cksum = 0;
int bytecount;
int i, b;
if (s[0] != ':') return(0);
sscanf(s+1,"%2x",&bytecount);
if (bytecount > 32) return(0);
cksum = bytecount;
i = 3;
bytecount = bytecount+3;
while (bytecount>0) {
bytecount--;
sscanf(s+i,"%2x",&b);
cksum = cksum+b;
i = i+2;
}
sscanf(s+i,"%2x",&b);
cksum = -cksum;
if (cksum == b) return 1;
return 0;
}

// Gross syntax and checksum check.


// For all HEX formats, not just 8M.
// Initial colon
// Valid byte count

// Compute checksum

// Test checksum

void loadhexfile(FILE *f) {


// Loads a hex file into memory arrays
char s[256];
word i,lo,hi;
word linetype = 0;
// 0 for data, 1 for end of file
word wordcount;
// number of 16 bit words on this line
word address;
// address where they begin
word data[8];
// 16 bytes = 8 words max. per line of hex
cleararrays();
while((!feof(f)) && (linetype != 1)) {
fgets(s,255,f);
cleanctrl(s);
if (!validhexline(s)) {
// Syntax check
s[40] = 0;
// Truncate invalid line for display
if (s[0] != ':') {
printf("Invalid line (skipped): '%s'...\n",s);
continue;
}
else {
printf("Unable to decode line: '%s'...\n",s);
goto bailout;
}
}
sscanf(s+1,"%2x",&wordcount);
wordcount = wordcount/2;
sscanf(s+3,"%4x",&address);
address = address/2;
sscanf(s+7,"%2x",&linetype);

// Parse the line - Intel Hex8M


// (double bytes, addresses doubled)

if (linetype==1) goto finished;


for (i=0; i<wordcount; i++) {
PIC16F84A

// Grab the data


pg. 55

sscanf(s+(9+4*i),"%2x%2x",&lo,&hi);
data[i] = (hi << 8) | lo;
}
// Place in appropriate array
if (address >= DBASE) {
if (!stuffarray(address,DMEM,DBASE,DSIZE,&DUSED,data,wordcount))
goto bailout;
}
else if (address >= CBASE) {
if (!stuffarray(address,CMEM,CBASE,CSIZE,&CUSED,data,wordcount))
goto bailout;
}
else if (address >= IBASE) {
if (!stuffarray(address,IMEM,IBASE,ISIZE,&IUSED,data,wordcount))
goto bailout;
}
else {
if (!stuffarray(address,PMEM,PBASE,PSIZE,&PUSED,data,wordcount))
goto bailout;
}
} // while
finished:
printf("Program memory loaded:
printf("Configuration loaded:
printf("ID memory loaded:
printf("Data memory loaded:
return;

%5d
%5d
%5d
%5d

word(s)\n",PUSED);
word(s)\n",CUSED);
word(s)\n",IUSED);
byte(s)\n",DUSED);

bailout:
cleararrays();
errmsg("Unable to load file.");
FNAME[0] = 0;
return;
}
// *********************************************************************
// USER INTERFACE
// *********************************************************************
void banner() {
clearscreen();
puts("---------------------------------");
puts("NOPPP - \"No-Parts\" PIC Programmer");
puts("Michael A. Covington");
puts("Version of " __DATE__ " " __TIME__);
puts("---------------------------------");
if (LPT > 0) printf("Using LPT%d on %03XH\n",LPT,PORT);
puts("---------------------------------");
switch (DEVICE) {
case PIC16C84: printf("PIC16C84"); break;
case PIC16F84: printf("PIC16F84"); break;
case PIC16F83: printf("PIC16F83"); break;
default:
printf("
");
}
printf("
%s\n",FNAME);
puts("---------------------------------\n");
}
PIC16F84A

pg. 56

void selectport() {
char c;
c = (getenv("PPLPT"))[0];
if ((c >= '1') && (c <= '3')) {
CHOICE = c;
}
else {
banner();
printf("Which LPT port? ");
getchoice("1,2,3");
}
LPT = CHOICE - '0';
PORT = portaddr(LPT);
banner();
puts("Apply power to NOPPP now, but");
errmsg("do not put a PIC in the socket.");
if (!detecthardware()) {
banner();
puts("Caution: NOPPP hardware not found!\n\n");
puts("With some versions of the circuit and some");
puts("parallel ports, this may be normal.\n");
puts("If you are sure you have chosen the correct");
puts("parallel port, press space bar to proceed.");
puts("To cancel program, press Ctrl-C.");
errmsg(" ");
}
}
void troubleshoot() {
banner();
puts("Ensure NOPPP is powered up now,");
errmsg("with no PIC in the socket.");
allpinslow();
banner();
puts("TEST 1\n");
puts("Connect negative voltmeter lead to pin 5");
puts("of PIC socket and check the following voltages:\n");
puts(" Socket pin 4
< 0.8 V");
puts(" Socket pin 12
< 0.8 V");
puts(" Socket pin 13
< 0.8 V");
puts(" Socket pin 14
4.75 to 5.25 V");
puts(" Junction of");
puts("
D1, D2, and R1
< 0.8 V");
errmsg(" ");
vppon();
clockup();
dataup();
banner();
puts("TEST 2\n");
puts("With negative voltmeter lead still");
puts("connected to pin 5 in the PIC socket,");
puts("check the following voltages:\n");
puts(" Socket pin 4
12.0 - 14.0 V");
puts(" Socket pin 12
> 4.0 V");
puts(" Socket pin 13
> 4.0 V");
PIC16F84A

pg. 57

puts(" Junction of");


puts("
D1, D2, and R1
errmsg(" ");

< 0.8 V");

vppoff();
clockdown();
datareadable(); // AUTOFD, SLCTIN high
banner();
puts("TEST 3\n");
puts("With negative voltmeter lead still");
puts("connected to pin 5 in the PIC socket,");
puts("verify that pin 13 > 4.0 V.\n");
puts("Next, insert a 470-ohm resistor into the socket");
puts("connecting pin 13 to pin 5 and verify that");
puts("pin 13 drops to < 0.7 V with the resistor in place.");
errmsg(" ");
allpinslow();
datawritable(); // SLCTIN down
dataup();
// AUTOFD up
banner();
puts("TEST 4\n");
puts("With negative voltmeter lead still");
puts("connected to pin 5 in the PIC socket,");
puts("verify that the junction of D1, D2, and R1");
puts("is < 0.8 V.");
errmsg(" ");
allpinslow();
datareadable(); // SLCTIN up
dataup();
// AUTOFD up
banner();
puts("TEST 5\n");
puts("With negative voltmeter lead still");
puts("connected to pin 5 in the PIC socket,");
puts("verify that the junction of D1, D2, and R1");
puts("is now > 4 V.\n");
puts("This completes the test sequence.");
errmsg(" ");
allpinslow();
exit(0);
}
void load() {
FILE *f;
banner();
printf("File to load: ");
strcpy(FNAME,getstring());
f = fopen(FNAME,"rt");
if (f == NULL) {
errmsg("Unable to open file.");
FNAME[0] = 0;
return;
}
loadhexfile(f);
fclose(f);
errmsg("Loading complete.");
PIC16F84A

pg. 58

if (CUSED == 0) {
banner();
puts("Caution: HEX file did not contain a configuration word.\n");
puts("The following settings will be used:\n");
puts(" RC oscillator");
puts(" Watchdog timer disabled");
puts(" Power-up timer enabled");
puts(" Code not read-protected\n");
errmsg("You can specify other settings in the assembler.");
}
else if (CMEM[0] != (CMEM[0] & CMASK)) {
banner();
puts("Caution: Configuration word appears to contain invalid bits.\n");
puts("Your program may have been assembled for a different");
puts("type of PIC. Check device selection carefully.");
errmsg("");
}
}
void selectdevice() {
banner();
puts("Devices supported:\n");
puts(" C
PIC16C84");
puts(" F
PIC16F84");
puts(" 3
PIC16F83\n\n");
puts(" T
Test the NOPPP circuit\n");
getchoice("C,F,3,T");
switch(CHOICE) {
case 'C':
DEVICE = PIC16C84;
PSIZE = 1024;
CMASK = 0x001F;
DEFAULTCONFIG = 0x001B;
break;
case 'F':
DEVICE = PIC16F84;
PSIZE = 1024;
CMASK = 0x3FF3;
DEFAULTCONFIG = 0x3FF3;
break;
case '3':
DEVICE = PIC16F83;
PSIZE = 512;
CMASK = 0x3FF3;
DEFAULTCONFIG = 0x3FF3;
break;
case 'T':
troubleshoot();
}
}
void erase() {
int i;
vppreset();
printf("Erasing ID and configuration, ");
sendcmd(LOADCONFIG);
senddata(0x3FFF);
for (i=7; i>0; i--) sendcmd(INCREMENTADDRESS);
sendcmd(1);
PIC16F84A

pg. 59

sendcmd(7);
sendcmd(BEGINPROGRAMMING);
delay(20000);
sendcmd(1);
sendcmd(7);
printf("program, ");
progcycle(ERASEPROGRAM,0x3FFF);
printf("data...");
progcycle(ERASEDATA,0x3FFF);
allpinslow();
puts("Done.");
waitkey();

// is the data word necessary?


// is the data word necessary?

}
void program(int mode) {
word i;
banner();
if (PUSED+IUSED+CUSED+DUSED == 0) {
printf("Load a file first.\n");
goto finish;
}
vppreset();
printf("Program memory: ");
if (!programall(mode,PMASK,LOADPROGRAM,READPROGRAM,PMEM,PBASE,PUSED))
goto finish;
sendcmd(LOADCONFIG);
senddata(DEFAULTCONFIG);

// from here on we're in config/ID memory


// loadconfig requires an arg, here it is

printf("ID memory: ");


if (!programall(mode,IMASK,LOADPROGRAM,READPROGRAM,IMEM,IBASE,IUSED))
goto finish;
for (i=0; i < CBASE-IBASE-IUSED; i++)
sendcmd(INCREMENTADDRESS);
// get to config memory
printf("Configuration memory: ");
if (!programall(mode,CMASK,LOADPROGRAM,READPROGRAM,CMEM,CBASE,CUSED))
goto finish;
vppreset();

// Reset address counter in PIC to 0

printf("Data memory: ");


if (!programall(mode,DMASK,LOADDATA,READDATA,DMEM,DBASE,DUSED))
goto finish;
puts("Programming complete.\n\n");
puts("For production-grade work, you should now verify");
puts("the PIC at the maximum and minimum values of Vcc.");
finish:
allpinslow();
waitkey();
}

PIC16F84A

pg. 60

void queryexit() {
banner();
allpinslow();
puts("Are you sure you want to exit?");
getchoice("Y,N");
if (CHOICE == 'Y') {
banner();
errmsg("Remove PIC from socket now.");
exit(0);
}
}
void menu() {
allpinslow(); // Clean up after aberrant routines if any
banner();
puts(" L Load HEX file");
puts(" S Select type of PIC");
puts(" E Erase PIC");
puts(" P Program PIC");
puts(" V Verify PIC\n");
puts(" X Exit program");
getchoice("L,S,E,P,V,X");
switch(CHOICE) {
case 'L': load(); break;
case 'S': selectdevice(); break;
case 'E': erase(); break;
case 'P': program(PROGRAM); break;
case 'V': program(VERIFY); break;
case 'X': queryexit();
}
}
main() {
FNAME[0] = 0;

// no file is presently loaded

selectport();
allpinslow();
selectdevice(); // mandatory
banner();
errmsg("You may insert the PIC in the socket now.");
while(1) menu();
return 0;
}

PIC16F84A

pg. 61