Escolar Documentos
Profissional Documentos
Cultura Documentos
Apostila Programacao PIC16 Exsto
Apostila Programacao PIC16 Exsto
Tecnologia
Exsto Tecnologia
Microcontroladores PIC16F877A 3
ÍNDICE PÁGINA
Introdução .............................................................................................................................................. 6
1 CONCEITOS BÁSICOS ................................................................................................................ 7
1.1 Sistema Computacional .......................................................................................................... 7
1.1.1 Memórias........................................................................................................................... 8
1.1.2 Memória de programa ...................................................................................................... 8
1.1.3 Memória de Dados ............................................................................................................ 9
1.1.4 Barramentos ...................................................................................................................... 9
1.1.5 Dispositivos de entrada e saída ....................................................................................... 10
1.1.6 Periféricos ........................................................................................................................ 13
1.1.7 CPU .................................................................................................................................. 14
1.2 Arquitetura Computacional................................................................................................... 17
1.2.1 Arquitetura von-Neumann .............................................................................................. 17
1.2.2 Arquitetura Harvard ........................................................................................................ 18
2 O MICROCONTROLADOR PIC16F877A ................................................................................. 20
2.1 A Microchip .......................................................................................................................... 20
2.2 Microcontroladores PIC ........................................................................................................ 20
2.3 A Arquitetura do PIC16F877A ............................................................................................. 21
2.4 Geração de clock................................................................................................................... 22
2.4.1 Modos LP,XT e HS ............................................................................................................ 23
2.4.2 Modos RC......................................................................................................................... 25
2.4.3 Modo INTOSC .................................................................................................................. 26
2.4.4 Comparação entre os modos de oscilador ...................................................................... 26
2.4.5 Clock e execução das instruções ..................................................................................... 26
2.5 Memórias .............................................................................................................................. 27
2.5.1 Memória de programa .................................................................................................... 27
2.5.2 Memória de dados .......................................................................................................... 28
2.6 RESET .................................................................................................................................. 31
2.6.1 POR – Power-On Reset .................................................................................................... 31
2.6.2 PWRT – Power-up Timer ................................................................................................. 31
2.6.3 OST – Oscillator Start-up Timer ....................................................................................... 31
2.6.4 BOR – Brown-out Reset ................................................................................................... 31
2.6.5 Seqüência de inicialização ............................................................................................... 32
2.6.6 Identificação de Reset pelo Software .............................................................................. 32
2.7 Watch-Dog Timer ................................................................................................................. 33
2.8 Modo de baixo consumo – Modo SLEEP............................................................................. 33
Exsto Tecnologia
Microcontroladores PIC16F877A 4
Exsto Tecnologia
Microcontroladores PIC16F877A 5
Exsto Tecnologia
Microcontroladores PIC16F877A 6
Introdução
Está apostila tem o objetivo de servir como livro texto para um curso de microcontroladores PIC16.
Esse conteúdo foi preparado para ser usado em disciplinas de microcontrolador/microprocessadores
em cursos técnicos ou superiores na área de tecnologia.
O capítulo 4 apresenta algumas aplicações avançadas de programação, com displays LCD, teclados
matriciais e, principalmente, interrupções.
No último capítulo são apresentados alguns dos principais periféricos do PIC16F877A, também
encontrados em outros microcontroladores da família PIC16. Destes, são fundamentais os timers e
comunicação serial. Os demais poderão ser sacrificadas ou resumidas, caso a carga horária não
suporte a totalidade do conteúdo, apesar de ser recomendado dar uma maior atenção ao conversor
analógico para digital.
Exsto Tecnologia
Microcontroladores PIC16F877A 7
1 CONCEITOS BÁSICOS
Inicialmente será apresentado o conceito de microcontroladores de forma genérica, que
posteriormente será estendido ao PIC16F877A e pode ser aplicado a qualquer outro
microcontrolador.
É importante este embasamento teórico não somente para garantir um melhor aproveitamento no
estudo do PIC 16F877A como também para tornar o leitor apto a entender o funcionamento de
outros microcontroladores, tanto da linha PIC como de outros fabricantes. Esses conhecimentos
também são importantes na escolha do microcontrolador a ser utilizado em um projeto, pois permite
estabelecer as bases conceituais para a comparação de suas características.
Uma boa analogia é imaginar o hardware como um instrumento musical e o software como uma
partitura. Um piano por si só não faz nada, é necessária uma música que possa ser executada a fim
de se obter algum resultado. Da mesma forma que a música contida na partitura, um programa será
composto por um conjunto limitado de símbolos (no caso da partitura são as notas musicais e no
caso do programa são as instruções) que podem ser organizados de diversas formas diferentes,
obtendo-se diferentes resultados.
Como exemplo de sistema computacional, o primeiro que nos vem em mente é o computador
pessoal (PC), hoje tão difundido. Contudo, existem vários equipamentos, tão ou mais comuns que os
PC´s, que são sistemas computacionais. Por exemplo, os vídeo-games, os mini-games, as
calculadoras, palm-top´s, etc. Além disso, temos os microcontroladores, que são o objetivo desse
nosso estudo, que estão presentes nas mais diversas aplicações.
Exsto Tecnologia
Microcontroladores PIC16F877A 8
Memória
Dados Programa
Controle
(CPU) Barramento de
Dados
Dispositivos de
Entrada e saída e “Mundo
periféricos Externo”
1.1.1 Memórias
Memórias são dispositivos que armazenam informações. No caso de um sistema computacional, essa
informação, assim como a memória, pode ser dividida em dois tipos: de programa e de dados.
Existem também Registros (bytes de memória) com funções especiais que trabalham junto ao
processador (CPU).
Existem endereços de memória de programa existem alguns com finalidade específica, chamados
vetores, que são endereços para onde o programa desvia quando ocorrem determinados eventos.
Temos o vetor de reset, que é o endereço pelo qual o programa começa a ser executado e o vetor de
interrupções, que é para onde o programa desvia quando ocorreu um pedido de interrupção
(trataremos desse conceito mais adiante).
De uma forma geral, a memória de programa é uma memória não volátil. O tipo dessa memória pode
ser:
Exsto Tecnologia
Microcontroladores PIC16F877A 9
• Flash: é uma memória eletricamente apagável (EEPROM – Electricaly Eresable Read Only
Memory) com tempos de acesso para leitura rápido. Oferece uma grande flexibilidade,
pois geralmente é possível reprogramar um equipamento sem troca de componentes.
Alguns microcontroladores disponibilizam também memórias EEPROM para armazenar dados que
não devem ser perdidos com a falta de energia.
1.1.4 Barramentos
As várias partes de um sistema computacional (CPU, memórias, dispositivos de entrada e saída) são
ligadas entre si através de barramentos, ou vias, que são ligações físicas de comunicação paralela
entre os componentes. São eles:
• Barramento de dados: pelo qual os dispositivos de I/O e memórias trocam dados com o
processador
• Barramento de endereços: permite ao processador “endereçar” qual dispositivo será
acessado
• Barramento de controle: indica se o acesso é de leitura ou escrita, se é feito a posição de
memória ou a I/O.
• Barramento de programa: por onde o processador recebe as instruções que compõe o
programa.
O tamanho do barramento de dados limita o tamanho de dados que trafegam pelo sistema. Por isso
é comum classificar os sistemas computacionais pelo tamanho de seu barramento; temos então
sistemas de 8 bits, 16 bits, 32bits, etc. Os microcontroladores são em sua maioria de 8 bits, apesar de
existirem alguns modelos de 16 bits.
Todos os dispositivos de um sistema computacional fazem uso do barramento de dados para trafegar
informações. Para que o sistema funcione corretamente podemos apresentar o processo de forma
simplificada assim: o processador (que coordena o processo) escreve no barramento de endereços o
endereço do dispositivo a ser acessado. Através do barramento de controle ele informa ao
dispositivo se o acesso é de leitura ou escrita (a definição de leitura ou escrita de dispositivos sempre
é feita pelo ponto de vista do processador). No caso de um aceso de leitura o dispositivo escreve no
Exsto Tecnologia
Microcontroladores PIC16F877A 10
Como dispositivos de um sistema computacional usam o mesmo barramento de dados para trafegar
informações é preciso que, quando um dispositivo estiver escrevendo no barramento (portanto
aplicando níveis de tensão ao barramento) os demais dispositivos não causem conflito de dados. De
fato, todos os dispositivos presentes em um sistema computacional são capazes de ficar em estado
de “alta impedância” enquanto não forem acessados para leitura.
A função dos portais de saída é transferir ao “mundo externo” um dado que esteja presente no
barramento de dados. Para isso são utilizados latches, pois permitem o “carregar” dados somente
quando são acionados, retendo esses dados independente de haverem alterações em suas entradas.
A seleção dos dispositivos de I/O a partir do barramento de endereços é feita por decodificadores
ligados ao barramento de endereços e seu acionamento é feita através do barramento de controle.
Exemplo 1.1
A figura 1.2, abaixo, mostra um exemplo de utilização de buffers e latches como portais de entrada e
saída, respectivamente.
Ambos os portais estão ligados ao barramento de dados. Cada portal possui um decodificador (DEC),
que apresenta nível alto na saída quando o valor do barramento de endereços é o endereço do portal.
Os sinais RD (read – ler), WR (write – escrever) e IORQ (I/O request – requisição de I/O) constituem o
barramento de controle.
Exsto Tecnologia
Microcontroladores PIC16F877A 11
Para realizar uma operação de escrita do portal , o processador inicialmente coloca os dados a serem
escritos no barramento de dados e o endereço do portal no barramento de endereço.O decodificador
decodifica o endereço do portal de escrita e coloca em sua saída nível lógico 0. Então são acionados
os sinais WR e IORQ. Nesse instante temos ‘1’ nas três entradas da porta AND que aciona o terminal E
do latch, que faz com ele carregue os dados presentes no barramento na saída.
A função do microcontrolador, como o próprio nome diz, é controlar processos e circuitos. Para
otimizar essa função, seus portais de entrada e saída são tratados como registros de funções
especiais, ou seja, são lidos e escritos como se fossem simples bytes de memória. Em sistemas como
microprocessadores geralmente o tratamento é diferente, havendo instruções específicas para
acesso aos portais e outras implicações, que diminuem a eficiência do código gerado quando se
trabalha intensamente com entrada e saída.
Exsto Tecnologia
Microcontroladores PIC16F877A 12
OPERAÇÃO DE ESCRITA OU SAÍDA DE DADOS: ao acionar o controle WR PORT, o latch de saída (Data
Latch) armazena a informação complementar do barramento de dados em sua saída complementar
Q “barra”. Vamos admitir que o registro de direção de dados (TRIS Latch) foi carregado inicialmente
com o valor ‘0’. O registro de direção de dados é habilitado através do controle WR TRIS e a
informação de direção fica armazenada em sua saída. Para Q=0 e Q ”barra”=1 na saída do registro de
direção, o pino I/O estará configurado como saída e tem-se a transferência da informação Q ”barra”
do latch de saída para o driver do pino I/O conforme o arranjo das portas lógicas. Se este último Q
”barra” =0 o transistor “N” será cortado e “P” será ativado permitindo que a tensão Vdd apareça no
pino I/O como nível lógico 1 que era a informação original do barramento de dados. Se Q “barra” =1
o transistor “P” será cortado e “N” estará ativo. A tensão no pino I/O cai para o nível Vss indicando
nível lógico 0.
Exsto Tecnologia
Microcontroladores PIC16F877A 13
Caso seja feita uma operação de escrita em um terminal configurado como entrada, o dado escrito
será armazenado no latch de dados, mas não será transferido para o terminal, pois o driver está
desativado. Por outro lado, se for realizada uma operação de leitura em um terminal configurado
como saída, o valor lido será o dado presente no terminal, que é o mesmo escrito no latch de dados
anteriormente.
1.1.6 Periféricos
Além dos portais de I/O e as memórias, podemos ter muitos outros tipos de dispositivos ligados ao
barramento de dados. Esses dispositivos nada mais são do que circuitos destinados a realizar funções
especiais. Esses dispositivos periféricos são particularmente importantes nos microcontroladores.
Como periféricos mais comuns podemos citar os temporizadores e contadores (Timers), os módulos
de comunicação serial, conversores AD e DA, módulos de CCP (Captura, comparação e PWM), drivers
de LCD, comparadores analógicos, etc.
Exsto Tecnologia
Microcontroladores PIC16F877A 14
O modo de acesso aos periféricos é semelhante ao de acesso aos portais de I/O. Eles muitas vezes
possuem vários registros de parâmetros que podem ser configurados, e um ou mais registros de
entrada e saída de dados.
Quando estivermos tratando dos periféricos do PIC16F877A mostraremos como trabalhar com eles
e, apesar de cada microcontrolador apresentar um conjunto de periféricos diferentes, seu
funcionamento é muito semelhante.
1.1.7 CPU
A CPU (Central Processing Unit – Unidade Central de Processamento) ou processador é parte
principal de um sistema computacional. É comum se referir à CPU dos microcontroladores como core
(núcleo). Sua função é executar as instruções do programa e processar dados. Para tanto ela controla
todas as demais partes do sistema e envia ou recebe dados dessas partes. Ela também é capaz de
interpretar e colocar em execução as instruções que compõe o programa e realizar operações lógicas
e aritméticas.
Os nomes de cada bloco estão em inglês no diagrama para facilitar a identificação desses blocos nos
manuais de microcontroladores e microprocessadores, que comumente são escritos nessa língua. Os
blocos pontilhados podem ou não estar presentes. As vias em amarelo representam o barramento de
dados interno do processador, que é ligado ao barramento de dados do sistema. As vias em verde
são outras vias de dados e sinais de controle.
Exsto Tecnologia
Microcontroladores PIC16F877A 15
Esse bloco é composto por um decodificador e um contador. Tal decodificador pode ser visto como
um livro de receitas culinárias. No livro, cada página contém uma receita e dentro de cada receita há
os passos para sua execução. De modo análogo, cada instrução do processador é como o endereço
de uma “página” onde está a seqüências de acionamento dos sinais de controles (internos e externos
ao processador) que permitem a execução da instrução. O contador existente é responsável por
fazer com que os passos para a execução de uma instrução sejam executados em seqüência. Cada
modelo de processador possui um conjunto, ou set, de instruções que pode executar.
O programa armazenado na memória é uma seqüência de instruções. Podemos então supor que
para endereçar corretamente essas instruções deveria haver um contador. Ele existe e é chamado
Contador de Programa ou PC (Program Counter). A cada instrução iniciada o PC é incrementado.
Portanto ele aponta a próxima instrução, isto é, contém o endereço da próxima instrução a ser
executada. A saída desse contador é ligada a um registro (Program Addressing) que é carregado ao
final de cada instrução com o endereço da próxima instrução. A saída do registro Program Addressing
está ligada ao barramento de endereços da memória de programa.
Quando a CPU é resetada, o PC é automaticamente carregado com o valor do vetor de reset. Durante
a execução do programa, um valor pode ser carregado no PC. Isso ocorre para desviar o fluxo do
programa. Existem instruções que realizam essa alteração de fluxo, que pode ser de dois tipos:
desvio ou chamada.
Quando ocorre um desvio o conteúdo do PC é alterado para que ele passe a executar o programa a
partir de outro ponto.
Na execução de uma chamada o fluxo do programa também é desviado para um determinado ponto
para executar um trecho do programa, mas nesse caso ele deve retornar ao ponto do programa onde
ocorreu o desvio (mais precisamente à primeira instrução após a instrução de chamada). Isso
permite executar uma sub-rotina, conceito que será discutido quando tratarmos do software.
Em uma chamada o endereço de retorno deve ser armazenado em algum lugar, caso contrário não
seria possível retornar ao ponto onde a chamada ocorreu. Esse lugar é chamado de pilha (stack). O
nome pilha se deve a seu funcionamento, que é semelhante a uma pilha de pratos: como pode haver
várias chamadas consecutivas sem que haja retorno, os endereços de retorno são armazenados “uns
sobre os outros”. Quando ocorre uma instrução de retorno (que é o que faz o programa retornar da
chamada), o programa volta para o último endereço guardado, e assim sucessivamente até que a
pilha esteja vazia. A pilha é então uma porção de memória onde podem ser armazenados os
endereços de retorno.
Exsto Tecnologia
Microcontroladores PIC16F877A 16
Para indicar a próxima posição livre na pilha existe um registro (na verdade um contador) chamado
ponteiro da pilha (Stack Pointer) que aponta o topo. Esse registro é incrementado cada vez que um
novo endereço de retorno é armazenado na pilha e decrementado quando ocorre um retorno.
Uma vez determinado o endereço, seu conteúdo é lido e armazenado em um registro chamado
registro de instrução (Instruction Register). Desse registro, parte da instrução vai para o
decodificador de instruções e parte pode ir para a ALU e/ou parte para o registro de endereçamento
de dados (Data Addressing). Para entender o porque disso, devemos ter em mente que uma
instrução nada mais é que uma palavra binária. Parte dela, que é efetivamente a instrução, indica ao
decodificador de instruções qual a seqüência de ações deve ser executada (qual a “página” do
decodificador de instruções). O restante constitui os operandos da instrução, ou seja, os dados a
serem processados. Esses dados podem ser constantes ou endereços de dados variáveis na memória
RAM. Conforme sua natureza e a instrução a ser executada eles tem um destino ou outro.
A unidade lógico-aritmética ou ALU (Aritmetic and Lógic Unit) é o circuito responsável pelos cálculos
em um processador. Como próprio nome diz, ela é responsável pela realização de operações lógicas,
(E, OU, OU-exclusivo, deslocamentos, rotações, complemento), e aritméticas (incremento,
decremento, adição, subtração, multiplicação, e divisão). Os processos de divisão e multiplicação são
feitos com a ALU utilizando seqüências somas e subtrações, o que efetivamente o que a ALU é capaz
de fazer.
A ALU trabalha juntamente com dois registros especiais: o Acumulador (Accumulator) e o registro de
estado de operações aritméticas (Status). É comum se referir ao acumulador simplesmente como
Acc ou, no caso dos PICs, como W (Worker – Trabalhador ). O acumulador quase sempre está
envolvido nas operações realizadas pela ALU. Ele pode ser um dos operandos, pode ser onde se
armazena o resultado ou pode ser as duas coisas. Há também microcontroladores onde qualquer
transferência de dados entre dois endereços da RAM passa pelo acumulador.
Quanto ao registro de status, sua função é indicar resultados notáveis das operações matemáticas.
Esses resultados são indicados por flags, que são bits desse registro. Através da análise dos flags é
possível saber, dentre outras coisas, se uma operação resultou em zero; se houve estouro da
capacidade de armazenamento (overflow), que acontece quando um resultado é maior que o
máximo valor possível de ser representado pelo sistema; se o resultado de uma operação aritimética
é negativo ou positivo. Existe uma interação do registro status com o decodificador de instruções,
pois através da análise de seus flags é possível realizar instruções de testes.
Para acessar a memória de dados e os periféricos existe um registro, que em nosso sistema é
chamado de endereçamento de dados (Data Addressing) que pode receber valores de duas formas.
A primeira é diretamente de parte da instrução. Nesse caso se está fazendo referência a endereços
da RAM conhecidos e fixos, pois são carregados valores constantes existentes no programa. Esse
modo é chamado endereçamento direto.
Em muitos casos é necessário fazer referências a endereços variáveis. Isso é feito carregando o
registro de endereçamento com dados provenientes de um outro registro, o registro de
endereçamento indireto (Indirect Addressig). Como qualquer outro registro, ele pode ser carregado
com um valor, constante ou proveniente de uma variável, pode ser incrementado, decrementado ou
participar que qualquer operação lógico-aritmética. Sua função é semelhante a dos ponteiros em
linguagens de alto nível.
Exsto Tecnologia
Microcontroladores PIC16F877A 17
Todo o sistema computacional trabalha sincronizado com um mesmo sinal de clock. Devemos
lembrar que esse clock é o que faz o decodificador de instruções passar de uma instrução para a
outra, e tudo o mais deve estar sincronizado com ele, senão haveria o caos. Para gerar esse sinal de
clock é necessário um oscilador. Nos microcontroladores esse oscilador já faz parte do componente
Independente da forma como o clock é gerado, esse sinal é aplicado a CPU e aos periféricos. É
comum que a freqüência do clock dos periféricos seja menor que a da CPU. Para tanto são utilizados
divisores de freqüência
Outro ponto importante é o reset. Além do reset que ocorre quando o sistema é ligado, chamado de
Power-on reset, os microcontroladores apresentam várias outras fontes de reset. Esses resets são
proteções do sistema.
Exsto Tecnologia
Microcontroladores PIC16F877A 18
Vale lembrar aqui que uma instrução é como uma operação matemática, isto é, composta de
operadores, que indicam o que será feito, e operandos, que são os parâmetros envolvidos na
operação.Desta forma, o processo de execução de cada instrução é dividido em dois momentos: a
leitura da instrução e a leitura dos operandos (fetch) e a execução da instrução propriamente dita.
Nota-se que dessa forma o processador está parte do tempo ocupado com a leitura da memória de
programa e, conseqüentemente não fica executando o firmware o tempo todo. Outra característica
da arquitetura von-Neumann é que, visto que os operandos das instruções são geralmente do
mesmo tamanho do barramento de dados, quanto mais complexa a instrução maior será a
quantidade de endereços ocupados por ela na memória. Isto quer dizer que por exemplo, para um
barramento de 8 vias, uma instrução de 16 bits é buscada e executada em duas partes de 8 bits. Por
outro lado, como a complexidade da instrução não tem limite a não ser o espaço ocupado, podemos
ter um set de instruções tão complexo quanto se queira.
Podemos concluir que arquitetura von-Neumann consome muito tempo de processamento com a
leitura da instrução e dos operandos. Conclui-se também que instruções diferentes ocupam
quantidades diferentes de memória e são executadas em tempos diferentes.
Memória
Programa Dados
CPU
Barramento de I/O
Dados
A principal vantagem dessa arquitetura é que a leitura de instruções e de alguns tipos de operandos
pode ser feita ao mesmo tempo em que a execução das instruções (tempo Tcy). Isso significa que o
sistema fica todo o tempo executando instruções, o que acarreta um significativo ganho de
velocidade. Enquanto uma instrução está sendo executada, a seguinte está sendo lida. Esse processo
é conhecido como pipelining (canalização) e é ilustrado pela figura 1.6 abaixo.
Exsto Tecnologia
Microcontroladores PIC16F877A 19
Programa Dados
Barramento de
I/O
Programa Barramento de
Dados
Pode-se notar então que os tempos de execução e de leitura estão atrelados e são os menores
possíveis. Isso acarreta em as instruções não poderem executar uma grande seqüência de ações, ou
seja, não existem instruções complexas. Por isso, os PIC´s são considerados processadores RISC
(Reduced Instruction Set CPU – CPU com Set de Instruções Reduzido). O número de instruções é
reduzido, o que não significa que não se possa executar programas complexos, mas sim que
seqüências complexas de ações devem ser construídas por seqüências de instruções básicas.
Exsto Tecnologia
Microcontroladores PIC16F877A 20
2 O MICROCONTROLADOR PIC16F877A
2.1 A Microchip
O fabricante dos microcontroladores PIC é a empresa americana Microchip. Atualmente ela é um dos
maiores fabricante mundiais de microcontroladores de 8, 16 e 32 bits, além de possuir uma ampla
linha de memórias e componentes analógicos.
A Microchip trabalha com uma política de suporte ao cliente muito eficiente, que provavelmente é
uma das causas de seu sucesso. Em seu site (www.microchip.com) existe uma grande quantidade de
informação disponível. Além dos manuais dos componentes, existem muitas notas de aplicação
(Application Notes) e projetos de referência, que são de grande ajuda para a formação da base de
conhecimentos do estudante de microcontroladores PIC.
• 8 bits
o Família PIC10
o Família PIC12
o Família PIC14 e PIC17
o Família PIC16
o Família PIC18
• 16 bits:
o Famílias PIC24F e PIC24H
o Familias dsPIC30F e dsPIC33F
• 32 bits
Exsto Tecnologia
Microcontroladores PIC16F877A 21
o PIC32
o
Os componentes diferem entre si basicamente em:
Também são dignos de nota os periféricos, localizados na parte inferior do diagrama, que estão
ligados ao barramento de dados.
Exsto Tecnologia
Microcontroladores PIC16F877A 22
Os microcontroladores PIC possuem um circuito de oscilação interna, isto é, são capazes de gerar seu
próprio clock (ou sinal de relógio) com acréscimo de poucos (ou nenhum) componentes externos.
Existem sete modos diferentes de clock, e cada componente da família utiliza alguns deles. O modo
de clock para cada aplicação é selecionado no momento da gravação do microcontrolador e não
pode ser alterado pelo programa. São eles:
Exsto Tecnologia
Microcontroladores PIC16F877A 23
Obs.: resistores, indutores, capacitores e cristais podem ser combinados formando circuitos
osciladores em freqüências determinadas. Mais detalhes sobre os conceitos, funcionamento e
projeto desse tipo de circuito podem ser encontrados em livros de eletrônica com capítulos sobre
osciladores.
Os modos LP, XT e HS utilizam um cristal ou ressonador cerâmico para estabilizar o clock. A diferença
está na faixa de freqüência de cada modo e no consumo de energia associado a cada freqüência.
O modo LP refere-se a cristal/ressonador cerâmico de baixa freqüência. Esse modo trabalha com
freqüências de oscilação de até 200 kHz e nele conseguimos o menor consumo dos três modos em
questão.
O modo XT abrange as freqüências de 200 kHz até 4 MHz e apresenta um consumo médio.
Cada faixa de freqüência possui um ganho do circuito oscilador, que é ajustado de forma diferente
para cada modo. É recomendado que se use o modo adequado para cada freqüência, caso contrário
pode ocorrer mau funcionamento do oscilador.
Além do cristal ou do ressonador, nos modos LP, XT e HS, devem existir capacitores ligados dos
terminais do cristal terra, conforme mostra a figura 2.2.
Os valores desses capacitores C1 e C2 são os indicados nas tabelas Capacitor Selection for Crystal
Oscillator que se encontra nos manuais de cada PIC na seção que trata de configurações do oscilador.
Para o PIC16F877A os valores são os apresentados na tabela 2.2. O valor de RF representa o ajuste
interno do oscilador para cada modo (XT, LP e HS). O resistor RS pode ser necessário para alguns
tipos de corte de cristal, mas geralmente não é usado. O Comando SLEEP desativa o oscilador no
modo de baixo consumo, do qual trataremos mais adiante.
Exsto Tecnologia
Microcontroladores PIC16F877A 24
Exsto Tecnologia
Microcontroladores PIC16F877A 25
Também é possível aplicar sinais de clock gerados externamente, bastando para isso selecionar o
modo relativo a faixa de sinal utilizado. Nesse caso o sinal deve ser aplicado ao pino OSC1/CLKIN e o
pino OSC2/CLKOUT deve permanecer em aberto.
2.4.2 Modos RC
Também é possível trabalhar com osciladores RC (Resistor/Capacitor). Para isso é utilizada a
montagem da figura 2.4 e selecionado o modo de oscilador como RC.
O resistor REXT deve estar entre 3kΩ e 100kΩ e o capacitor CEXT deve ser superior a 20pF. O circuito
pode funcionar sem capacitor CEXT, mas nessa situação ele se torna muito suscetível a variações
drásticas de freqüência devido a capacitâncias externas (do próprio lay-out, por exemplo). Além
disso, a variação da freqüência é maior para resistores maiores e capacitores menores.
Exsto Tecnologia
Microcontroladores PIC16F877A 26
No modo RC com saída de clock o terminal OSC2/CLKOUT apresenta a freqüência do oscilador divida
por quatro, que pode ser utilizado como fonte de clock para outros pontos do circuito. Já no modo
sem saída de clock, esse terminal pode ser utilizado como I/O.
Nesse modo, o sinal de clock é obtido de forma semelhante ao funcionamento do modo RC, porém o
“resistor” e “capacitor” são implementados na própria pastilha do componente. Devido a isso temos
geralmente uma ou duas freqüências de clock fixas.
Tipicamente o oscilador interno é menos preciso que o oscilador a cristal é mais preciso que o
oscilador RC, com tolerâncias entre +/- 1 e 10 %.
Em cada um dos ciclos Q é realizada uma etapa da instrução, conforme mostrado na tabela 2.2.
Graficamente esse processo é apresentado na figura 2.5.
Ciclo Ação
Q1 Ciclo de decodificação da instrução
Q2 Ciclo de leitura de dados
Q3 Ciclo de processamento
Q4 Ciclo de escrita de dados
Tabela 1.2 – Ciclos de execução das instruções
Exsto Tecnologia
Microcontroladores PIC16F877A 27
Alguns periféricos e algumas funções do PIC não são sincronizados nem com o clock do oscilador
nem com o clock de periféricos, mas com os ciclos Q.
2.5 Memórias
2.5.1 Memória de programa
O PIC16F877A possui 8K-palavras de memória de programa. Já que se trata de um processador RISC,
o tamanho das palavras da memória de programa é maior que o barramento de dados. Assim, apesar
de ser um microcontrolador de 8 bits, a memória de programa é composta por palavras de 14 bits.
Cada palavra, isto é, cada endereço de memória de programa guarda uma instrução. Dessa forma,
um programa de 500 instruções ocupará 500 bytes.
O vetor de reset é o endereço 0000h. Como vimos, isso significa que o programa deve ser escrito a
partir desse endereço. O vetor de interrupção, para todas as interrupções é o 0004h.
Na estrutura das instruções de chamada e desvio da família 16F o espaço reservado para endereço é
de 11 bits. Portanto é possível endereçar diretamente 2048 endereços de memória. Sendo que o
PIC16F877A tem 8k endereços de memória de programa, essa memória é dividida em unidades que
chamaremos de páginas. Dentro de uma mesma página é possível realizar saltos e desvios para
qualquer ponto. Mas se um salto ou desvio vai de uma página para outra é necessário fazer um
ajuste prévio dos dois bits mais significativos do SFR PCLATH, conforme mostrado na tabela abaixo.
PCLATH
Página
Bit 4 Bit 3
0 0 0
1 0 1
2 1 0
3 1 1
Tabela 2.3 – Páginas de memória de programa
Exsto Tecnologia
Microcontroladores PIC16F877A 28
No PIC16F877A existem 368 bytes de memória RAM de dados. Ela é composta por registros de
funções especiais (SFR – Special Function Registers) e a RAM de uso geral (GPR – General Purpose
RAM). Os SFR são responsáveis pelo controle da CPU e dos periféricos, além de conterem os registros
dos portais. Na RAM de uso geral é onde o programa armazenará suas variáveis.
A memória RAM pode ser acessada de duas formas: por acesso direto e por acesso indireto. Acesso
direto ocorre quando o endereço acessado faz parte da própria instrução (é um dos operandos). Já o
acesso indireto é feito através de duas variáveis, uma contendo o endereço a ser acessado e a outra
Exsto Tecnologia
Microcontroladores PIC16F877A 29
se comportando como o byte acessado. Este último modo de endereçamento pode ser muito útil em
algumas situações e será estudado mais adiante.
Para acesso direto, a RAM é dividida em 4 bancos. Isso ocorre porque a capacidade de máxima de
acesso de memória dos microcontroladores PIC é de 512 bytes. Portanto, são necessários 9 bits para
compor os endereços. Como cada instrução tem apenas 14 bits, e esses bits devem ser divididos
entre operadores e operandos, não há espaço para um endereço de 9 bits. Na verdade, as instruções
armazenam apenas 7 bits do endereço a ser acessado. Os dois bits restantes fazem parte do registro
de função especial STATUS e são chamados RP1 e RP0. Já que dois bits podem gerar 4 combinações,
existe essa divisão em 4 bancos. Para acessar um registro em um banco diferente do banco atual, é
necessário ajustar previamente RP1 e RP0. Na prática utilizamos o máximo possível endereços do
banco 0, e mudamos para os demais bancos quando necessário, retornando novamente ao banco 0.
A divisão de bancos é feita conforme a tabela 1.3.
Os registros de funções especiais têm seus nomes e os nomes de seus bits já definidos em um
arquivo. Existe um arquivo desses para cada PIC e a forma de incluí-lo no programa será mostrado
mais adiante. Podemos então tratar os SFR pelo seus nomes, não havendo a preocupação com o
endereço que eles ocupam. Também não é necessário saber qual bit de um registro tem
determinada função, apenas o nome do mesmo. Na apresentação desses registros será seguida a
convenção abaixo, que a mesma utilizada no manual dos componentes.
No anexo B encontra-se o mapa de memória do PIC16F628A. Pode-se observar os nomes dos SFR e
as regiões de uso geral. Note que apesar de ser possível acessar 512 bytes, foram implementados
apenas 224 bytes. As posições não implementadas estão em cinza na figura. Note ainda que os
últimos 16 endereços de todos os bancos acessam os mesmos bytes no banco 0.
Exsto Tecnologia
Microcontroladores PIC16F877A 30
A figura 1.7 trás o mapeamento de memória RAM do PIC16F877A com os nomes dos registros de
função especial e as áreas de uso geral (GPR). As regiões em cinza correspondem a endereços para os
quais não há memória implementada. No manual do PIC16F877A existe um detalhamento maior dos
bits que compõe os SPR´s. A função de vários desses registros será explicada no decorrer do curso.
Exsto Tecnologia
Microcontroladores PIC16F877A 31
2.6 RESET
O PIC possui várias fontes de reset (reinicialização), que são:
O reset por MCLR é acionado quando ao terminal MCLR (pino 4) é aplicado nível lógico baixo. MCLR é
o terminal de Reset do componente, sendo um terminal baixo ativo, isto é, o reset ocorre em ‘0’.
Além disso, o terminal de MCLR possui internamente um filtro para evitar que ruídos possam causar
reset acidental.
O modo como os registros se comportam em cada reset é variado. Para saber quais são os “valores
iniciais” de cada registro, deve ser consultada a tabela de situações iniciais dos registros, presente no
manual de cada PIC.
O BOR ocorre quando a alimentação atinge aproximadamente 4V por mais de 100µs (quedas por
tempo intervalos menores que esse são ignorados pois podem se tratar de ruídos na alimentação),
em situações como as mostradas na figura2.8.
Exsto Tecnologia
Microcontroladores PIC16F877A 32
Essa informação pode ser útil, permitindo que providências sejam tomadas em situações específicas
de problema.
Exsto Tecnologia
Microcontroladores PIC16F877A 33
Essa funcionalidade é muito útil, pois, na grande maioria das situações práticas, é melhor que o
sistema reinicie do que fique inoperante. Desenvolvendo o código adequadamente é possível fazer
com que o reset sequer tenha efeitos perceptíveis para o sistema.
• Qualquer reset;
• Estouro do Watch-Dog (se este estiver habilitado);
• Qualquer periférico que estiver com sua respectiva interrupção habilitada (incluso INT e
interrupção por mudança no Portal B).
Exsto Tecnologia
Microcontroladores PIC16F877A 34
Quando da ocorrência de algum reset, o programa recomeça sua execução no vetor de reset
(0000h). Se, porém, ocorrer um estouro do Watch-Dog ou a chamada de alguma interrupção o
programa continua sua execução a partir do endereço imediatamente posterior a instrução SLEEP
que ativou o modo de baixo consumo. E ainda, se o controle geral de interrupções estiver habilitado,
o programa recomeça pelo vetor de interrupções (0004h) se desperto por interrupção. Assim, se
desejamos que uma interrupção simplesmente “acorde” o microcontrolador, devemos desabilitar
globalmente as interrupções.
Deve-se ter atenção ao fato de que no modo SLEEP o oscilador está desligado. Dessa forma não
podem ser utilizadas interrupções dos timer’s para a saída do modo, se estes timer’s utilizarem como
fonte de clock o oscilador interno, nem demais periféricos cujo funcionamento se baseie no oscilador
principal do sistema.
A figura abaixo apresenta a pinagem do PIC 16F877A. Para facilitar a escrita, toda documentação da
Microchip quando se refere a um terminal não utiliza a notação bit N do portal X, e sim RX N. Por
exemplo, o bit 2 do portal A é representado por RA2, o bit 7 do portal C por RC7, e assim por diante.
Exsto Tecnologia
Microcontroladores PIC16F877A 35
Exsto Tecnologia
Microcontroladores PIC16F877A 36
Os níveis de tensão de entrada e saída para o PIC são apresentados na tabela abaixo. Os valores são
considerndo que a alimentação é de 5,0 V. O buffer de entrada de cada pino pode ser do tipo TTL
simples ou Schmitt Trigger. Para saber qual o tipo de buffer deve-se consultar a parte do manual de
cada componente relativo aos portais de I/O.
Um cuidado que deve ser tomado, independente do tipo de oscilador escolhido, é fazer com que os
componentes externos do circuito oscilador fiquem bem próximo uns dos outros e todos bem
próximos ao microcontrolador. Além disso, quando for confeccionada uma placa de circuito impresso
deve-se minimizar as indutâncias e capacitâncias parasitas. Isso é feito aumentando a espessura das
trilhas, diminuindo seu comprimento e posicionando trilhas excessivamente próximas umas das
outras. Esses cuidados são fundamentais quando se trabalha com freqüências altas.
2.10 Gravação
A gravação do microcontrolador PIC pode ser realizada sem que o componente seja retirado da placa
(gravação in-circuit). Essa gravação é feita de forma serial utilizando somente dois pinos: PB7/PGD
para envio de dados e RB6/PGC para clock.
Além dos pinos RB7 e RB6 é necessário que o pino MCLR/VPP receba uma tensão de 13VDC +/- 0,5V
durante o processo de gravação. Também é necessário que o microcontrolador esteja devidamente
alimentado, portanto VDD e VSS devem estar devidamente conectados.
Exsto Tecnologia
Microcontroladores PIC16F877A 37
Como criar uma lógica complexa de programação usando apenas códigos numéricos seria um
trabalho muito desgastante e o resultado muito confuso foi criada uma linguagem simbólica
que associa nomes, denominados mnemônicos, aos opcodes; por conveniência esses nomes
fazem referência a ação realiza, como poderá ser observado brevemente.
Para assembler é o programa responsável por “traduzir” o código mnemônico (entendido pelo ser
humano) para um código numérico composto de opcodes (entendido pelo core do
microcontrolador).
Antes de estudar as instruções deve-se definir alguns termos que serão utilizados na descrição das
instruções e na apresentação de sua sintaxe:
Exsto Tecnologia
Microcontroladores PIC16F877A 38
microcontrolador a cada instrução. Esses bits são tipicamente chamados de flags (Bandeiras).
Através deles podemos saber de resultados de operações da ALU (se uma subtração resultou em
zero, se uma soma causou “overflow”, etc), a situação do RESET, além do controle bancos de
memória.
• Manipulação de byte
• Manipulação e bit
• Matemáticas
• Lógicas
Exsto Tecnologia
Microcontroladores PIC16F877A 39
No anexo A existe uma tabela resumo de todas as instruções. Recomenda-se tirar uma cópia desta
pagina e tela sempre à mão para consulta rápida.
CLRW
Sintaxe CLRW
Operadores Nenhum
Operação (W) 00h
Flags Afetados Z
Ciclos 1
Exemplo CLRW
Alterações nas Flags: Como a instrução resultou em um registro se tornar 0, o bit Z é setado
indicando esse evento.
CLRF
Sintaxe CLRF f
Operadores 0 ≤ f ≤ 127
Operação (f) 00h
Flags Afetados Z
Ciclos 1
Exemplo CLRF TEST
Alterações nas Flags: Como a instrução resultou em um registro se tornar 0, o bit Z é setado
indicando esse evento.
MOVLW
Sintaxe MOVLW k
Operadores 0 ≤ k ≤ 255
Operação (W) k
Flags Afetados Nenhum
Ciclos 1
Exemplo MOVLW 35h
Exsto Tecnologia
Microcontroladores PIC16F877A 40
MOVF
Sintaxe MOVF f, d
0 ≤ f ≤ 127
Operadores d=0:W
d = 1 : registro f
Operação (d) (f)
Flags Afetados Z
Ciclos 1
Exemplo MOVF TEST,0
Alterações nas Flags:
Z = 0: o valor movido, é diferente de zero.
Z = 1: o valor movido, é 0.
MOVWF
Sintaxe MOVWF f
Operadores 0 ≤ f ≤ 127
Operação (f) W
Flags Afetados Nenhum
Ciclos 1
Exemplo MOVWF TEST
BCF
Sintaxe BCF f, b
0 ≤ f ≤ 127
Operadores
0≤b≤7
Operação f[b] 0
Flags Afetados Nenhum
Ciclos 1
Exemplo BCF CONTROLE,5
Exsto Tecnologia
Microcontroladores PIC16F877A 41
BSF
Sintaxe BSF f, b
0 ≤ f ≤ 127
Operadores
0≤b≤7
Operação f[b] 1
Flags Afetados Nenhum
Ciclos 1
Exemplo BSF CONTROLE,7
2.11.3 Matemáticas
ADDLW
Sintaxe ADDLW k
Operadores 0 ≤ k ≤ 255
Operação (W) (W) + k
Flags Afetados C, DC, Z
Ciclos 1
Exemplo ADDLW 35h
Alterações nas Flags:
ADDWF
Exsto Tecnologia
Microcontroladores PIC16F877A 42
Sintaxe ADDWF f, d
0 ≤ f ≤ 127
Operadores d=0:W
d = 1 : registro f
Operação (d) (W) + (f)
Flags Afetados C, DC,Z
Ciclos 1
Exemplo ADDWF TEST,0
Alterações nas Flags:
DECF
Decrementa o valor contido no registro f. O resultado é armazenado no destino: d=0 para W ou d=1
para o registro designado por f.
INCF
Incrementa o valor contido no registro f. O resultado é armazenado no destino: d=0 para W ou d=1
para o registro designado por f.
Exsto Tecnologia
Microcontroladores PIC16F877A 43
SUBLW
Sintaxe SUBLW k
Operadores 0 ≤ k ≤ 255
Operação (W) k - (W)
Flags Afetados C, DC, Z
Ciclos 1
Exemplo SUBLW 23h
Alterações nas Flags:
ATENÇÃO: nessa operação os bits C e DC tem significado inverso ao que seria esperado, isto é,
quando ocorre um borrow ("estouro para menos"), os bits C e DC ficam em zero, ao contrário que
quando ocorre um Carry ("estouro para mais"), quando C e DC ficam em 1.
SUBWF
ATENÇÃO: nessa operação os bits C e DC têm significado inverso ao que seria esperado, isto é,
quando ocorre um borrow ("estouro para menos"), os bits C e DC ficam em zero, ao contrário que
quando ocorre um Carry ("estouro para mais"), quando C e DC ficam em 1.
Exsto Tecnologia
Microcontroladores PIC16F877A 44
2.11.4 Lógicas
Assim como as instruções matemáticas, as instruções lógicas realizam operações lógicas básicas
fazendo uso da ALU.
ANDLW
Realiza uma operação lógica "E" entre o valor contido em W e a constante k. O resultado é
armazenado em W.
Sintaxe ANDLW k
Operadores 0 ≤ k ≤ 255
Operação (W) (W) E k
Flags Afetados Z
Ciclos 1
Exemplo ANDLW 0Fh
Alterações nas Flags:
ANDWF
Realiza a operação "E" entre o valor contido em W o valor contido no registro f. O resultado é
armazenado no destino: 0 para W ou 1 para o registro designado por f.
Sintaxe ANDWF f, d
0 ≤ f ≤ 127
Operadores d=0:W
d = 1 : registro f
Operação (d) (W) E (f)
Flags Afetados Z
Ciclos 1
Exemplo ANDWF TEST,1
Alterações nas Flags:
Exsto Tecnologia
Microcontroladores PIC16F877A 45
COMF
IORLW
Realiza uma operação "OU" bit a bit entre o valor contido em W e a constante k. O resultado é
armazenado em W.
Sintaxe IORLW k
Operadores 0 ≤ k ≤ 255
Operação (W) (W) OU (f)
Flags Afetados Z
Ciclos 1
Exemplo IORLW TEST
Alterações nas Flags:
IORWF
Realiza a operação "OU" bit a bit entre o valor contido em W com o valor do registro indicado por f.
O resultado é armazenado no destino: d=0 para W ou d=1 para o registro designado por f.
Exsto Tecnologia
Microcontroladores PIC16F877A 46
RLF
O valor contido em f é rotacionado para a esquerda através do bit de Carry (bit C do registro
STATUS). O resultado é armazenado no destino: d=0 para W ou d=1 para o registro designado por f. A
operação de rotação a esquerda consiste no deslocamento sucessivo de bits de sua posição inicial
para a posição consecutiva de modo que o último bit do registro f vá para C e o bit que estava em C
vá para o primeiro bit do registro f.
C Registro f
RRF
O valor contido em f é rotacionado para a direita através do bit de Carry (bit C do registro STATUS). O
resultado é armazenado no destino: 0 para W ou 1 para o registro designado por f. A operação de
rotação a direita consiste no deslocamento sucessivo de bits de sua posição inicial para a posição
consecutiva de modo que o primeiro bit do registro f vá para C e o bit que estava em C vá para o
último bit do registro f.
C Registro f
Exsto Tecnologia
Microcontroladores PIC16F877A 47
SWAPF
O nibble (conjuntos de 4 bits) mais significativo e o menos significativo do registro f são trocados. Ou
seja, os bits de 7 a 4 vão para as posições de 3 a 0 e os bits de 3 a 0 vão para as posições de 7 a 4. A
figura abaixo ilustra esse processo. O resultado é armazenado no destino: d=0 para W ou d=1 para o
registro designado por f.
XORLW
Realiza uma operação "OU exclusivo" entre o valor contido em W e a constante de oito bits k. O
resultado é armazenado em W.
Sintaxe XORLW k
Operadores 0 ≤ k ≤ 255
Operação (W) (W) XOU (f)
Flags Afetados Z
Ciclos 1
Exemplo XORLW OFh
Alterações nas Flags:
Z = 1: o resultado da operação "OU exclusivo" é 0 (um valor "OU-exclusivo" consigo mesmo é igual a
zero).
XORWF
Realiza a operação "OU exclusivo" entre o valor contido em W com o valor do registro indicado por f.
O resultado é armazenado no destino: d=0 para W ou d=1 para o registro designado por f.
Sintaxe XORWF f, d
0 ≤ f ≤ 127
Operadores
d= 0 → W
Exsto Tecnologia
Microcontroladores PIC16F877A 48
d=1 → registro f
Operação (d) ← (W) XOU (f)
Flags Afetados Z
Ciclos 1
Exemplo XORWF TEST,0
Alterações nas Flags:
Z = 1: o resultado da operação "OU exclusivo" é 0 (um valor "OU-exclusivo" consigo mesmo é igual a
zero).
2.11.5 Testes
BTFSC
Testa o bit b do registro f : se o bit for '1' a próxima instrução é executada; se o bit for '0' a próxima
instrução não é executada, em seu lugar é executada uma instrução NOP, seguindo o programa na
segunda instrução após a BTFSC.
Sintaxe BTFSC f, b
0 ≤ f ≤ 127
Operadores
0≤ b≤7
Operação se f[b]=0 salta a próxima instrução
Flags Afetados nenhum
se o bit não estiver em 1;
Ciclos se o bit estiver em 1.
BTFSC STATUS,Z
Exemplo GOTO ZERO
BTFSS
Testa o bit b do registro f : se o bit for '0' a próxima instrução é executada; se o bit for '1' a próxima
instrução não é executada, em seu lugar é executada uma instrução NOP, seguindo o programa na
segunda instrução após a BTFSS.
Sintaxe BTFSS f, b
0 ≤ f ≤ 127
Operadores
0≤ b≤7
Operação se f[b]=1 salta a próxima instrução
Flags Afetados Nenhum
se o bit não estiver em 1;
Ciclos
se o bit estiver em 1.
BTFSS STATUS,Z
Exemplo
GOTO NO_ZERO
DECFSZ
Decrementa o valor contido no registro f. O resultado é armazenado no destino: d=0 para W ou d=1
para o registro designado por f. Se o resultado for diferente de 0 a próxima instrução é executada; se
o resultado for 0 a próxima instrução não é executada, em seu lugar é executada uma instrução NOP,
seguindo o programa na segunda instrução após a DECFSZ.
Exsto Tecnologia
Microcontroladores PIC16F877A 49
Incrementa o valor contido no registro f. O resultado é armazenado no destino: d=0 para W ou d=1
para o registro designado por f. Se o resultado for diferente de 0 a próxima instrução é executada; se
o resultado for 0 a próxima não é executada, em seu lugar é executada uma instrução NOP e o
seguindo o programa na segunda instrução após a INCFSZ.
Sintaxe CALL k
Operadores 0 ≤ k ≤ 2047
TOS PC+1
Operação PC[10:0] k
PC[12:11] (PCLATCH[4:3])
Flags Afetados Nenhum
Ciclos 2
Exemplo CALL TX_SERIAL
Exsto Tecnologia
Microcontroladores PIC16F877A 50
GOTO
Realiza um desvio incondicional para endereço k. O endereço de 11 bits é carregado no PC, fazendo a
seqüência do programa ser transferida para o endereço indicado por k. Os bits superiores do PC são
carregados de PCLATH. Ver tópico "Desvio X Chamada" para mais informações.
Sintaxe GOTO k
Operadores 0 ≤ k ≤ 2047
PC[10:0] k
Operação
PC[12:11] (PCLATCH[4:3])
Flags Afetados Nenhum
Ciclos 2
Exemplo GOTO INICIO
RETURN
Sintaxe RETURN
Operadores Nenhum
Operação PC TOS
Flags Afetados Nenhum
Ciclos 2
Exemplo RETURN
RETLW
Realiza o retorno de uma sub-rotina com o W contendo a constante de oito bits k . W passa a conter
k e o endereço de retorno salvo na pilha quando da ocorrência da interrupção é carregado no PC.
Sintaxe RETLW k
Operadores 0 ≤k ≤ 255
PC TOS
Operação
(W) k
Flags Afetados nenhum
Ciclos 2
Exemplo RETLW 69h
Exsto Tecnologia
Microcontroladores PIC16F877A 51
RETFIE
Sintaxe RETFIE
Operadores nenhum
PC TOS
Operação
GIE 1
Flags Afetados nenhum
Ciclos 2
Exemplo RETFIE
2.11.7 Controle
NOP
Sintaxe NOP
Operadores Nenhum
Operação Nenhuma
Flags Afetados Nenhum
Ciclos 1
Exemplo NOP
CLRWDT
Sintaxe CLRWDT
Operadores nenhum
WDT 00h
WDT prescaler 0
Operação
NOT_TO 1
NOT_PD 1
Flags Afetados NOT_TO, NOT_PD
Ciclos 1
Exemplo CLRWDT
Alterações nos Flags:
NOT_PD = 1: indica que não houve queda de energia.
NOT_TO = 1: indica que não houve time-out.
Exsto Tecnologia
Microcontroladores PIC16F877A 52
SLEEP
O Processador entra no modo SLEEP, desativando oscilador. O bit NOT_PD é zerado; O bit NOT_TO é
setado. O timer do Watchdog e seu prescaler são zerados.
Sintaxe SLEEP
Operadores nenhum
WDT 00h
WDT prescaler 0
Operação
NOT_TO 1
NOT_PD 0
Flags Afetados NOT_TO, NOT_PD
Ciclos 1
Exemplo SLEEP
Alterações nos Flags:
NOT_PD=0 e NOT_TO=1 indicam que o microcontrolador está em modo SLEEP.
Como já foi visto, a principal característica de um sistema computacional é permitir que um mesmo
hardware execute diferentes funções pela mudança de seu software.
Então, para programar um sistema computacional deve-se criar uma seqüência lógica de comandos
que possam ser traduzidos em uma determinada linguagem de programação, para que o sistema
possa entender o que deve ser feito. Linguagem de programação é uma forma de escrever um
programa. Cada linguagem possui sua sintaxe, suas regras de escritas, suas instruções. Exemplos de
linguagem de programação são Assembly, C/C++, Pascal, Basic, Cobol. A seqüência lógica de ações é
o que chamamos de algoritmo.
A apresentação de um algoritmo pode ser feita de forma escrita, o que é chamado português
estruturado ou “portugol”, ou de forma gráfica, utilizando fluxogramas. O fluxograma, por se tratar
de uma ferramenta gráfica, deixa bem clara a seqüência de ações realizadas pelo programa. Contudo
não apresenta muitos detalhes de implementação.
Exsto Tecnologia
Microcontroladores PIC16F877A 53
interpretação universal de fluxograma, foi desenvolvido um conjunto específico para trabalho com
programação de microcontroladores para esse curso. Suas principais características são possuir
símbolos diferentes para entrada e saída de dados e possuir um símbolo de Atraso, devido à
importância desse conceito para sistemas microcontrolados.
Quanto às linguagens de programação, elas são classificadas em “níveis”, sendo as de nível mais alto
as próximas da linguagem humana e as de baixo nível as próximas à linguagem de máquina, que o
que o microcontrolador/processador efetivamente entende. O Assembly do PIC é uma linguagem de
baixo nível.
Exsto Tecnologia
Microcontroladores PIC16F877A 54
;=============================================================
; <Nome da empresa>
; <Nome do projeto/programa>
Cabeçalho
;=============================================================
; Versão:
; <numero> <descrição da versão>
; <descrição da finalidade e operação do programa>
; Cristal <freqüência> - Ti = <tempo de instrução>
;
; <autor>
Configuraçõe
; <e-mail do autor>
;=============================================================
#include<P16F877A.INC> ; microcontrolador a ser utilizado
__CONFIG <opções> ; configurações do programa
; *** Variáveis
CBLOCK 20h
Definições de
hardware e
Software
<variáveis>
ENDC
; *** Software
org 0000H ; vetor de reset
Programa
Início do
GOTO INICIO ; inicio do programa principal
Tratamento de
; <aqui deve estar o salvamento de contexto>
Interrupção
; <aqui devem ser inseridas as rotinas de tratamento
; de interrupções, quando houverem >
RETFIE
; *** Rotina principal
INICIO:
< aqui fica a inicialização>
Principal
PRINCIPAL:
Rotina
<nome da subrotina>:
Sub-rotinas
RETURN
END ; FIM DO CÓDIGO
Exsto Tecnologia
Microcontroladores PIC16F877A 55
Como pude ser observado, várias partes da estrutura do programa não constituem código executável
propriamente dito, mas comentários e outras informações. Isso é feito visando documentar
adequadamente o projeto, permitindo realizar melhor o entendimento e a manutenção do software,
além de seu desenvolvimento.
Cabeçalho
O cabeçalho contém informações sobre o programa, como objetivo, autor, revisões e seus motivos,
dentre outras. Sua finalidade e documentar um resumo do programa, quem é o responsável pela sua
implementação e outras observações que permitam estabelecer a finalidade e o contexto para os
quais aquele código foi desenvolvido.
Assim como no cabeçalho, em muitas outras partes do texto são feitos comentário e explicações
sobre o que está sendo realizado. Esse procedimento é extremamente recomendado, pois, como
logo será percebido, o código em Assembly muitas vezes não deixa claro o que está sendo feito. É
comum que um programador, ao retomar um programa com o qual não trabalhou por algumas
semanas, não se lembre mais do motivo de ter feito certas partes do código. Quando é necessária
alguma manutenção em um programa, por pessoas que não o desenvolveram, e não há comentários,
o trabalho se torna virtualmente impossível.
Configurações
Podemos fazer definições de hardware utilizando a diretiva #DEFINE para tornar o programa mais
claro. A idéia é atribuir nomes aos pinos e/ou aos portais, segundo sua função. Dessa forma, na
escrita do programa, não é necessário lembrar qual função está associada a cada pino, apenas a
função. Por exemplo, suponhamos que existe um LED no pino RB2, isto é, no bit 2 do PORTB. É mais
cômodo nos referirmos a ele simplesmente por LED, não sendo preciso lembrar onde realmente está
o LED. Além disso, se por algum motivo for preciso mudar o LED para o pino RB6, basta alterar
somente a definição, e não todo local onde se faça referências ao LED.
...
CBLOCK 20h
ENTRADA ; ARMAZENA OS VALORES DE ENTRADA
CONT ; CONTADOR PARA TEMPORIZAÇÃO
...
ENDC
...
#DEFINE LED PORTB,2 ; o LED está em RB2
...
Exsto Tecnologia
Microcontroladores PIC16F877A 56
É aqui que o programa que vai ser gravado no microcontrolador realmente começa. A diretiva ORG
indica que o programa vai ser escrito a partir do vetor de reset (0000h). Como logo em seguida
temos o vetor de interrupção, caso esta esteja sendo utilizada, é necessário fazer um desvio para a
rotina principal do programa.
Tratamento de interrupção
A partir do vetor de interrupção (0004h) é colocado o código para tratar das interrupções, quando
estas forem utilizadas, conforme será discutido no futuro.
Rotina principal
Sub-rotinas
As sub-rotinas devem ser devidamente identificadas com seus cabeçalhos, informando sua função e
seus parâmetros de entrada e saída. Ao utilizar sub-rotinas bem feitas e documentadas reduzimos o
tempo de desenvolvimento, pois passamos a simplesmente organizar a rotinas já desenvolvidas, cujo
funcionamento é totalmente descrito pelo cabeçalho, não sendo necessário refazer a rotina nem
mesmo perder tempo estudando-a.
O problema a ser resolvido, que geralmente é um problema complexo, deve ser dividido em blocos
de problemas mais simples, e assim sucessivamente até que os sub-problemas atinjam uma
simplicidade tal que possam ser resolvidos com o uso de estruturas básicas. Para resolver qualquer
tipo de problema, independente de sua complexidade, existe apenas três tipos de estruturas: a
atribuição de valores, as estrutura de decisão e as estruturas de repetição.
É importante que um programa estruturado seja modular. Isto quer dizer que deve ser composto por
partes independentes do todo, que resolvam problemas específicos. Essas partes são chamadas sub-
rotinas. Harmoniosamente organizadas, as sub-rotinas nos permitem solucionar o problema, que é o
objetivo do software.
A divisão do programa em módulos acarreta uma série de vantagens. Como cada função trata de um
problema específico, fica fácil identificar onde está ocorrendo algum problema e também soluciona-
Exsto Tecnologia
Microcontroladores PIC16F877A 57
lo. Além disso, uma função pode facilmente ser “levada” para outro programa onde a mesma
solução se faça necessária, reduzindo assim o tempo de desenvolvimento. E ainda, um programa
modular é mais facilmente compreendido quando lido.
Exsto Tecnologia
Microcontroladores PIC16F877A 58
3 PROGRAMANDO O PIC16F877A
3.1 Diretivas
Diretivas podem ser vistas como instruções dadas ao montador, e não ao microcontrolador. Elas são
reconhecidas ou interpretadas pelo processador e realizam várias funções na criação do programa.
Trataremos aqui de algumas diretivas principais, que serão utilizadas na grande maioria dos
programas.
ORG e END
A diretiva ORG indica ao compilador que o código que se segue será alojado a partir da posição de
memória indicada por <endereço>. Sempre é necessária uma diretiva ORG para indicar o começo do
programa, conforme mostrado no exemplo.
Sintaxe END
org 0000h ; inicio do programa
INICIO:
Exemplo ... ; corpo do programa
end ; fim do programa
A diretiva END indica o fim do programa. Todo código escrito deve ser finalizado com END. Qualquer
código escrito após END será ignorado pelo compilador.
#INCLUDE
Exsto Tecnologia
Microcontroladores PIC16F877A 59
A diretiva #INCLUDE permite incluir arquivos no código fonte principal. Esses arquivos podem ser
arquivos de definições dos microcontroladores (cada microcontrolador tem seu arquivo de
definições, que deve ser incluído no início do programa) ou “bibliotecas”, que são conjuntos de
funções e/ou macros já prontas. No exemplo dado, temos esses dois casos
#DEFINE e EQU
Essas duas diretivas têm função semelhante, que é estabelecer uma substituição de texto. Em ambos
os casos, elas informam ao compilador que <nome> deve ser substituído por <texto> quando o
programa for compilado. A diferença fundamental entre elas é que #DEFINE aceita textos compostos
por virgulas, pontos, espaços, etc, enquanto EQU aceita apenas uma seqüência simples de
caracteres.
Ambas as diretivas pode ser utilizadas para declarar variáveis. Como veremos, declarar uma variável
nada mais é que dar um nome a um endereço de memória, que é a mesma coisa que declarar uma
constante. A diferença entre constante e variável está somente no tratamento dado no programa.
Apesar disso, vamos estabelecer o critério de utilizar EQU para definição de variáveis e #DEFINE para
definição de constantes.
Veremos na próxima diretiva que existe um jeito mais eficiente de declarar variáveis.
CBLOCK e ENDC
CBLOCK <valor_inicial>
<nome_1>
<nome_2>
Sintaxe ...
<nome_N>
ENDC
CBLOCK 20h ;endereço inicial da RAM geral
TESTE
MEDIDAS
Exemplo VALOR
...
ENDC
A diretiva CBLOCK permite criar um bloco de constantes consecutivas. É especificado um valor inicial,
que será o valor atribuído ao primeiro nome do bloco de constantes, a partir dele, cada nome recebe
Exsto Tecnologia
Microcontroladores PIC16F877A 60
um valor em ordem crescente a partir do valor inicial. No exemplo dado, o valor inicial é 20h, o que
resulta em TESTE = 20h, MEDIDAS = 21h e VALOR = 22h.
Essa diretiva é muito útil para a definição de variáveis, pois nos permite estabelecer o endereço onde
começa a RAM de uso geral e simplesmente dar o nomes as variáveis, sem preocupação com o
endereço individual de cada variável. Contudo, deve-se estar atento para que o número de variáveis
não seja tão grande que extrapole os endereços do banco.
BANKSEL
Essas duas diretivas são utilizadas quando é necessário realizar mudanças de bancos de RAM de
dados. BANKSEL realiza automaticamente a alteração dos valores de RP0 e RP1 para acessar
<endereço_de_memória> diretamente. BANKISEL realiza a alteração de IRP para realizar acesso
indireto.
A vantagem de se utilizar essas diretivas é que não é preciso saber em qual banco está o registro
acessado, apenas que ele não está no banco corrente. Como elas geram código para alterar os bits
em questão, sua utilização deve ser cuidadosa.
No exemplo acima da diretiva BANKSEL são declaradas duas variáveis, MEDIDA e TESTE, nos
endereços 20h (banco 0) e A0h (banco 1), respectivamente. Considerando a formação de endereços
por 7 bits essas duas variáveis correspondem ao mesmo valor de operando na instrução, no entanto
se encontram em bancos diferentes. Para a manipulação de dados entre elas é necessário o ajuste de
banco, que é feito atribuído os valores corretos a RP0 e RP1. A diretiva BANKSEL realiza essa ação. No
exemplo, o valor contido em MEDIDA é carregado em W, a diretiva BANKSEL realiza o ajuste de
banco para acessar a variável TESTE, ou seja, realiza a mudança de banco para o banco 1, o valor
contido em W é transferido para TESTE e a diretiva BANKSEL é novamente utilizada, agora para fazer
o ajuste para o banco de MEDIDA, isto é, para o banco 0.
__CONFIG
A diretiva __CONFIG (existem dois ‘_’ (dois caracteres underline) antes de CONFIG) permite
estabelecer a configuração dos “fusíveis” utilizada pelo programa. Fusíveis ou fuses são como são
Exsto Tecnologia
Microcontroladores PIC16F877A 61
chamados os bits de configuração das diversas características especiais, das quais trataremos mais
adiante. As várias opções, que na verdade são constantes, são associadas pelo símbolo &, que realiza
uma operação E entre os valores dessas constantes.
Para cada PIC existem várias opções, que podem ser encontradas no arquivo de definições. A tabela
4.1 contém as opções de configuração para os PIC 16F628 e 16F628A
3.2 Variáveis
Os dados a serem manipulados pelo microcontrolador são armazenados na memória RAM de uso
geral. É nessa região da memória onde são declaradas as variáveis do programa. Quando se trabalha
em Assembly no PIC somente dois tipos de variável existem diretamente. O primeiro é o byte, que
pode ser encarado como o tipo caracter (8 bits). Byte aceita valores de 0 a 255 se considerarmos
valores não sinalizados ou de –128 a 127 se considerarmos valores sinalizados (notação
complemento 2).
A outra possibilidade é o tipo lógico. Nesse caso, como a variável pode assumir somente dois valores,
verdadeiro (‘1’ ou true) ou falso (‘0’ ou false), são utilizados individualmente bits de bytes
pertencentes a RAM. É comum se referir a esses bits como flags (bandeiras).
As variáveis a serem usadas em um programa devem ser declaradas, isto é, deve-se informar ao
sistema que elas existem antes de usá-las, para que lhes seja destinado um espaço de memória.
Exsto Tecnologia
Microcontroladores PIC16F877A 62
Para declarar variáveis de tipo lógico, ou flags, primeiramente declara-se um endereço que irá conter
os flags. Em seguida utiliza-se a diretiva #DEFINE para declarar o flag dentro do byte de flags,
conforme a sintaxe abaixo.
Sendo que o campo <bit> pode conter valores de 0 a 7, sendo 0 o bit menos significativo do byte e 7
o mais significativo. Abaixo pode ser observado um exemplo de declaração de variáveis lógicas.
Uma boa dica de programação é usar sempre nomes de variáveis e flags que deixem clara sua
função, facilitando a compreensão do código. Pode-se ainda obedecer a regra de sempre iniciar o
nome de variáveis lógicas com “F_”, para indicar que se trata de um flag e não de um byte.
3.3 Sub-rotinas
Para a implementação de programas modulares é de fundamental importância o conceito de sub-
rotinas. Uma sub-rotina é definida como um trecho de código que realiza uma ação específica, assim
como uma função matemática. Ela pode ou não ter parâmetros de entrada (operandos de uma
função matemática) e parâmetros de saída (resultados). O conceito de sub-rotina admite ainda que
ela será “chamada” pelo programa, isto é, ela será executada e depois retornará ao ponto onde foi
chamada.
Em Assembly, uma sub-rotina inicia-se no Label (ou rótulo) que dá lhe o nome pelo qual ela será
“chamada” pelo programa e termina sempre com uma instrução RETURN. A instrução RETURN é
necessária para que o programa retorne ao ponto onde a sub-rotina foi chamada. As sub-rotinas
seguirão a forma geral abaixo.
<nome da subrotina>:
; Descrição da função da sub-rotina (1)
; Entrada: < parâmetros de entrada> (2)
; Saída: < parâmetros de saída > (3)
RETURN
Exemplo 4.1
Por exemplo, o código abaixo soma o valor de duas variáveis e salva esse valor em W.
ADD_FUNCTION:
; soma dois números (1)
; entrada: NUMERO_1 (2)
; NUMERO_2 (2)
Exsto Tecnologia
Microcontroladores PIC16F877A 63
; saída: W (3)
RETURN
Exemplo 4.2
Para a implementação da sub-rotina de soma suposta no exemplo anterior podemos utilizar o código
abaixo. Simule-o para observar seu funcionamento.
CBLOCK 20h
NUMERO_1
NUMERO_2
SOMA
ENDC
ORG 0000H
MOVLW 32h
MOVWF NUMERO_1 ; NUMERO_1 <- 32h
MOVLW 04h
MOVWF NUMERO_2 ; NUMERO_2 <- AUX
CALL ADD_FUNCTION ; chama a função
MOVWF SOMA ; SUM <- resultado contido em W
GOTO $
Exsto Tecnologia
Microcontroladores PIC16F877A 64
END
Pode-se notar que abaixo do nome da sub-rotina foram introduzidas algumas linhas de comentários
que especificam (1) o que faz a sub-rotina, (2) quais são os parâmetros de entrada e (3) quais são os
parâmetros de saída. É extremamente recomendado que se siga esse procedimento para garantir
maior facilidade de compreensão e melhor documentação do software.
Porém para a grande maioria das aplicações não é de grande utilidade um programa que seja
executado sempre na mesma seqüência. Por isso o programa deve ser capaz de mudar seu próprio
fluxo. Nas chamadas de sub-rotinas e tratamento de interrupções ele deve ser capaz de interromper
sua seqüência normal, executar um código armazenado em outra região da memória e retornar ao
ponto onde a seqüência foi interrompida. Numa estrutura de decisão ele deve ser capaz de executar
o bloco verdadeiro ou o bloco falso. E ainda, numa estrutura de repetição ele deve ser capaz de
realizar a mesma seqüência N vezes, dependendo das condições da estrutura.
O desvio, que no PIC é realizado pela execução da instrução GOTO, consiste em alterar o valor do PC,
fazendo com ele contenha o endereço onde está o código que se deseja executar. Dessa maneira a
seqüência do código é desviada para aquele endereço e de lá segue seqüencialmente, até encontrar
uma outro desvio ou uma chamada.
A chamada, que no PIC é realizada pela execução da instrução CALL, é semelhante ao desvio, porém
fundamentalmente diferente. A chamada também altera o valor do PC, causando um desvio na
seqüência do programa para um determinado endereço, porém antes de realizar essa alteração ela
“salva” o valor do PC (próximo endereço depois do CALL), que será seu endereço de retorno, numa
região de memória chamada pilha. Isso é feito porque o conceito de chamada é de que uma parte do
código, gravada em uma diferente região da memória, deve ser executada e depois o fluxo retorna o
ponto em que a chamada foi originada. Portanto uma instrução de chamada sempre exigirá uma
instrução de retorno, que no PIC é a instrução RETURN. A chamada em Assembly funciona então
como a chamada de funções numa linguagem de médio ou alto nível, porém temos que nos
preocupar com o retorno dessa função. Uma função em Assembly sempre terminará com uma
instrução de retorno (RETURN ou RETLW). O que o RETURN faz é recuperar o valor salvo na pilha
pela última instrução CALL executada e carrega-lo no PC, fazendo com que o fluxo do programa volte
ao ponto onde foi executada a chamada.
Exsto Tecnologia
Microcontroladores PIC16F877A 65
A pilha do PIC possui somente oito níveis, isto é, pode armazenar somente oito endereços de
retorno. Ela trabalha de forma circular, assim, já tendo 8 endereços armazenados, o nono substitui o
primeiro e assim por diante. Em uma analogia com uma pilha de pratos, o nono prato tomará o lugar
do primeiro que está em baixo. Portanto deve-se tomar cuidado para não se fazer mais de 8
chamadas consecutivas (incluindo a interrupção!), senão perde-se os endereços de retorno das
primeiras chamadas, fazendo com que o programa perca completamente sua seqüência lógica.
A figura 4.1 ilustra o a seqüência do programa dentro da memória, quando temos uma chamada, um
0000h
CALL A
GOTO B
RETURN
CALL C
RETURN
desvio, depois mais uma chamada, o retorno da segunda chamada e o retorno da primeira.
No programa existirão labels com duas finalidades: indicar o início de sub-rotinas e indicar pontos de
desvio. Para desvios curtos (poucas instruções acima ou abaixo do ponto atual) é possível utilizar a
construção:
GOTO $ +/- k
Onde k é um valor constante e $ indica o endereço atual. Sendo assim, para realizar um salto
a 3 instrução abaixo soma-se 3 ao endereço atual. Para saltar para a instrução anterior, subtrai-se 1
do endereço atual. Esses procedimentos são apresentados abaixo.
Exsto Tecnologia
Microcontroladores PIC16F877A 66
3.4 Atribuição
A estrutura mais simples existente em algoritmo ou fluxograma é a atribuição, que nada mais é que o
modo pelo qual se atribui valor a uma variável. Em outras palavras, trata-se de mover o valor de uma
origem, sendo essa uma constante ou uma variável, para uma variável de destino. Tanto nos
fluxogramas como no português estruturado essa operação será caracterizada pelo símbolo “”,
sendo que o destino encontra-se na ponta da seta e a origem na extremidade oposta a ponta. Abaixo
são apresentados alguns exemplos.
X Soma;
X Soma;
Orientadas a bytes:
MOVLW k : W k
MOVF f, 1 : f f
CLRF f : f 0
CLRW : W 0
Orientadas a bit:
Devido ao reduzido número de instrução no Assembly do PIC não existem instruções que permitam
mover o conteúdo de uma variável diretamente para outra ou uma constante diretamente para uma
variável (exceto quando a constante for zero). Para mover uma constante para uma variável utiliza-se
a seqüência abaixo.
Exsto Tecnologia
Microcontroladores PIC16F877A 67
MOVLW k ; W k
MOVWF f ; f W
Uma instrução de saída é uma atribuição que tem como destino o registro de um portal. Do mesmo
modo, uma instrução de entrada é uma atribuição que tem como origem o registro de um portal.
Exemplos são apresentados abaixo.
Para saída de dados é possível ainda trabalhar alterando somente um bit de um portal, sendo essa
alteração refletida em um único terminal de saída. Para isso utilizam-se as instruções de atribuição
orientadas a bit (BCF e BSF), como pode ser visto abaixo. Também é possível realizar entradas em
nível de bit, procedimento esse que será tratado mais adiante.
Na figura 4.2 são apresentados os símbolos de entrada (a) e saída (b) para fluxogramas.
(a)
(b)
Figura 4.2 – Símbolos de (a) entrada e (b) saída em fluxogramas
As representações em português estruturadas são as palavras Escreva para saída de dados e Leia
para a entrada de dados.
Exsto Tecnologia
Microcontroladores PIC16F877A 68
• Se
• Se-Senão
• Se-Senão-Se
• Caso
No Assembly do PIC, as estruturas de decisão são implementadas através de instruções que realizam
teste e desvios, que são:
Incrementa <registro> e salta a próxima instrução se o resultado for ‘0’ (255 + 1 = 0 e ‘vai um’ para
STATUS,C).
Juntamente com as instruções citadas acima, geralmente se utilizam instruções de desvio para os
endereços do código que tratam de cada situação. O exemplo abaixo mostra como isso acontece:
LOOP:
...
DECFSZ CONTADOR,F ; desvia para LOOP se o contador
GOTO LOOP ; não vale ‘0’
Os procedimentos acima descritos podem ser utilizados para o teste de bits em portais, realizando
assim decisão e entrada de dados ao mesmo tempo. Dessa forma consegue-se maior agilidade no
software. O exemplo abaixo realiza uma decisão a partir de um bit de entrada; neste caso o bit em
questão foi definido com o nome SENSOR_1.
Exsto Tecnologia
Microcontroladores PIC16F877A 69
3.7 Condições
As decisões que devem ser tomadas em um programa muitas vezes são baseadas na comparação
numérica entre dois valores, isso é, se esses valores são iguais ou não, qual é o maior, etc. No set de
instruções da linha PIC 16Xxxx não existe nenhuma instrução de comparação. Então para realizar
comparação se faz necessário utilizar instruções de teste associada a manipulações matemáticas.
Assim, antes de tratar propriamente das estruturas de decisões, deve-se saber como reconhecer
essas condições.
Condições A = B e A != B
Uma forma simples de saber se dois valores são iguais é subtraindo um do outro: se o resultado for
zero os dois valores são iguais; qualquer outro resultado significa que os valores são diferentes. Em
Assembly realiza-se a subtração e estuda-se o bit Z do registro STATUS, conforme pode ser
observado no exemplo abaixo.
Simule esse exemplo, alterando o valor da variável MEDIDA para 25h e outros valores e observado o
que ocorre.
CBLOCK 20H
MEDIDA
ENDC
ORG 0000H
END
E ainda, para testar se uma variável é igual a zero, pode-se utilizar a instrução MOVF, tendo como
destino o próprio registro. Nesse caso o valor da variável é movido para ela mesma, não sofrendo
qualquer alteração. Porém, se a variável for igual a zero o bit Z de STATUS será afetado, assumindo
valor igual a 1.
Pode haver a necessidade de saber qual de dois valores é o maior, sendo eles diferentes entre si.
Para tanto, novamente subtrai-se um valor pelo outro e então analisa-se o bit de Carry (Transporte)
que é o bit C do registro STATUS.
Exsto Tecnologia
Microcontroladores PIC16F877A 70
O Borrow pode ser percebido pela análise do bit C do STATUS. É importante notar que na subtração
esse bit trabalha com lógica inversa à adição. Assim:
Resultado normal inclui 0. Dessa forma, se fazendo A – B resulta em C = 1 conclui-se que A >= B (ou
que B <= A).
O trecho de código abaixo chama a sub-rotina “AJUSTE” se MEDIDA for maior que MAX. Simule seu
funcionamento para diferentes valores de MEDIDA e MAX.
#INCLUDE<P16F877A.INC>
CBLOCK 20H
MAX
MEDIDA
ENDC
ORG 0000H
REPETE:
MOVFW MAX ; W <-- MAX
SUBWF MEDIDA,W ; W <-- MEDIDA - W
BTFSC STATUS,C ; Se (MEDIDA >= MAX) então
CALL AJUSTE ; AJUSTE é chamado
GOTO REPETE ; senão desvia para REPETE
; ...
AJUSTE:
NOP ; \
NOP ; > corpo da sub-rotina
NOP ; /
END
Finalmente, para testar se um valor é somente menor ou maior que outro, e não igual, testa-se na
mesma operação o bit Z de STATUS. O código abaixo exemplifica essa operação:
CBLOCK 20H
MEDIDA
ENDC
ORG 0000H
Exsto Tecnologia
Microcontroladores PIC16F877A 71
IGUAL:
GOTO $ ; se MEDIDA == 05h, para aqui
MENOR:
GOTO $ ; se MEDIDA < 05h, para aqui
MAIOR:
GOTO $ ; se MEDIDA > 05h, para aqui
END
Z C Condição
0 0 A<B
0 1 A>B
1 0 impossível
1 1 A=B
3.8 Se
A estrutura de decisão Se funciona da seguinte forma: se a condição for verdadeira, o
Bloco_verdadeiro é executado; senão, programa continua o fluxo normalmente a partir de Fim_Se.
Em outras palavras, o código contido no Bloco_verdadeiro é executado somente se a condição for
verdadeira.
Se (<condição>) então V
<Condição>
[Bloco_verdadeiro]
F Bloco
Fim_Se
A implementação dessa estrutura pode ser feita com uma instrução de teste e salto seguida por uma
chamada de função. Essa chamada contem o Bloco_verdadeiro. É conveniente a utilização de uma
chamada de função, pois o programa retorna ao ponto onde foi chamado e continua o programa da
próxima linha, isto é, do mesmo ponto de onde continuaria se a condição fosse falsa. Esse
procedimento é exemplificado abaixo.
Exsto Tecnologia
Microcontroladores PIC16F877A 72
Se por algum motivo não for interessante a utilização de uma chamada, devemos fazer o teste
inverso, de forma a desviar quando a condição for falsa. Esse desvio deve ser para o ponto que
também será o destino do termino do bloco verdade. O trecho de código abaixo realiza o mesmo
que o código anterior, porém sem a utilização de chamada.
3.9 Se senão
A estrutura Se-Senão é uma derivação da estrutura Se onde, além de um bloco a ser executado
somente quando a condição for verdadeira (o Bloco_verdadeiro), existe um bloco a ser executado
somente quando a condição for falsa (o Bloco_falso). Sua representação é ilustrada abaixo.
Se (<condição>) então F V
<Condição>
[Bloco_verdadeiro]
Bloco Bloco
Senão Falso Verdadeiro
[Bloco_falso]
Fim_Se
Essa estrutura é implementada em Assembly por uma instrução de teste e salto seguida de dois
desvios, conforme o trecho abaixo.
CBLOCK 20H
CANAL
TST1
ENDC
ORG 0000H
MOVFW CANAL
SUBLW 35h
SKPNZ ; instrução especial = BTFSC STATUS,Z
GOTO BL_VERDADE ; se (CHANNEL) = 35h
GOTO BL_FALSO ; senão
BL_VERDADE: ; Bloco Verdadeiro
MOVLW 03h
MOVWF TST1
GOTO FIM_SE ; vai para o “Fim_Se”
BL_FALSO: ; Bloco Falso
MOVLW 08h
MOVWF TST1
; vai para o “Fim_Se”
Exsto Tecnologia
Microcontroladores PIC16F877A 73
END
CBLOCK 20H
CANAL
TST1
ENDC
ORG 0000H
MOVFW CANAL
SUBLW 35h
SKPNZ ; instrução especial = BTFSC STATUS,Z
GOTO BL_VERDADE ; se (CHANNEL) = 35h
; Bloco Falso vem aqui
MOVLW 08h
MOVWF TST1
GOTO FIM_SE ; vai para o “Fim_Se”
END
A diferença entre esses dois códigos é que no segundo, as instruções do bloco falso vêm logo em
seguida ao desvio BL_VERDADE sem que seja necessário colocar outro desvio para a as instruções a
serem executadas em caso de a condição da estrutura de decisão ser falsa.
3.10 Se senão se
Uma outra possibilidade de construção utilizando-se a estrutura Se-Senão é a chamada estrutura Se-
Senão-Se, que é simplesmente a implementação onde o bloco falso de uma estrutura Se-Senão é
composto por outra estrutura Se-Senão. Esta forma pode ser utilizada em cascata, possibilitando a
verificação de quantas possibilidades forem necessárias no programa. Abaixo é apresentada a forma
geral dessa estrutura. Deve-se notar que todos os “FIM_SE” da estrutura levam na verdade a um
mesmo ponto. E ainda, pode haver ou não um Bloco Falso, que será executado caso nenhuma das
condições seja satisfeitas.
Exsto Tecnologia
Microcontroladores PIC16F877A 74
V F
Condição 1
Bloco
Verdadeiro V F
Condição 2
Bloco
Verdadeiro V F
Condição 3
Bloco Bloco
Verdadeiro Falso
Exsto Tecnologia
Microcontroladores PIC16F877A 75
CBLOCK 20h
TEMP
UMIDADE
ENDC
ORG 0000H
END
3.11 Caso
A estrutura Caso (Case ou Switch) é uma estrutura de admite múltiplas condições de igualdade, com
um bloco verdade para cada condição. Existe também a possibilidade de um bloco de exceção para
tratar os casos que não se enquadram em nenhuma condição. Dessa forma temos:
Exsto Tecnologia
Microcontroladores PIC16F877A 76
Caso <Variável> de
...
Senão: [Bloco_exceção]
Fim_caso
Usando essa estrutura em Assembly pode-se construir tabelas, que são de grande utilidade em
muitos casos. Elas são de grande ajuda no trabalho com displays de segmentos e na linearização de
medidas analógicas provenientes de sensores não lineares. Uma tabela de software comporta-se
como uma tabela no papel, onde a partir de um valor de entrada obtemos um valor de saída
associado a ele. Como exemplo podemos implementar uma tabela que retorne uma letra do alfabeto
a partir do valor de sua posição ou uma tabela que retorne o quadrado do valor de entrada.
Para construção de tabelas é utilizada a instrução RETLW (Retorna com uma constante em W).
Primeiramente é feito um desvio por software, somando-se o valor de uma variável ao Registro PCL
(bits menos significativos do PC (Program Counter)). Dessa forma a próxima instrução a ser
executada é a n-ésima instrução após a soma, sendo n o valor contido na variável.
Algumas regras devem ser observadas na construção de tabelas. Primeiramente deve-se estar atento
ao banco onde se encontra a tabela. É recomendado que se faça uma tabela no início de um bloco de
256 endereços (0000h, 0100h, 0200h, etc.), pois caso a operação de soma com o PCL der overflow,
isto é, resultar em um valor maior que 256 o PCLATH não será incrementado automaticamente, o
que limita o tamanho da tabela em 256 valores. Além disso, um overflow em PCL causado por uma
instrução de soma não ocasiona automaticamente o incremento de PCH (bits mais significativos do
PC). Dessa forma não se pode fazer tabelas com comprimento maior que 256 itens sem um
tratamento especial, supondo que nesse caso a tabela comece no primeiro endereço de cada bloco
de 256 endereços.
A linha
soma um valor n com o PC, o que resulta em a próxima instrução executada ser n-ésima após a
soma. Ou seja, a instrução a ser executada está no n-ésimo endereço a partir do endereço seguinte a
instrução ADDWF. Esse processo é chamado desvio por software.
Exsto Tecnologia
Microcontroladores PIC16F877A 77
A rotina abaixo, que converte valores em BCD para a palavra de ativação dos respectivos caracteres e
um display de LED´s ligado a um portal. A sub-rotina chamada é SEGMENTOS; dentro dela é feito um
desvio para o label TABLE e o retorno é realizado por uma das instruções RETLW. O endereço de
TABLE é tal que o primeiro valor da tabela ocupa a posição 700h. Admite-se que a variável NUMERO
não contém valores maiores que 9. O registro PCLATH é carregado com 07h porque esse é o valor da
parte mais significativa das linhas tabela (como pode ser observado a direita) e o endereço para onde
se desvia é dado pelo par PCLATH e PCL
SEGMENTOS:
MOVFW NUMERO ; move o número a ser convertido para W
GOTO TABELA ; desvia para a tabela
; . . .
ORG 06FDH ; o código abaixo começa no endereço 6FDh
TABELA:
MOVLW 07H ; ajusta os bits mais significativos (06FDh)
MOVWF PCLATH ; de PCH (06FEh)
ADDWF PCL,F ; (PCL) (PCL) + (W) (06FFh)
; ABCDEFG
RETLW 01110111B ;0 1111110 (0700h)
RETLW 00000110B ;1 0110000 (0701h)
RETLW 10110011B ;2 1101101 (0702h)
RETLW 10010111B ;3 1111001 (0703h)
RETLW 11000110B ;4 0110011 (0704h)
RETLW 11010101B ;5 1011011 (0705h)
RETLW 11110101B ;6 1011111 (0706h)
RETLW 00000111B ;7 1110000 (0707h)
RETLW 11110111B ;8 1111111 (0708h)
RETLW 11010111B ;9 1111011 (0709h)
RETLW 11100111B ;A 1110111 (070Ah)
RETLW 11110100B ;B 0011111 (070Bh)
RETLW 01110001B ;C 1001110 (070Ch)
RETLW 10110110B ;D 0111101 (070Dh)
RETLW 11110001B ;E 1001111 (070Eh)
RETLW 11100001B ;F 1000111 (070Fh)
Na grande maioria dos casos, os programas para microcontroladores ficam repetindo a mesma
seqüência de instruções indefinidamente ou, pelo menos, checando entradas indefinidamente.
Como pode ser observado nos programas desenvolvidos até o momento, todo programa tem como
“núcleo” uma estrutura de repetição infinita, chamado normalmente de laço principal, loop principal
ou main loop.
Existem três tipos de estruturas de descisão: Faça-Enquanto, Enquanto e Para. Essa estruturas de
repetição são implementadas em linguagens de médio e alto nível por comando como While, Do-
While e For, respectivamente.
Exsto Tecnologia
Microcontroladores PIC16F877A 78
3.12.1 Faça-Enquanto
Faça-Enquanto (Do-While): estrutura de repetição que executa um bloco enquanto uma
determinada condição é verdadeira. A apresentação dessa estrutura em português estruturado e
fluxograma segue abaixo.
Faça
[Bloco] Bloco
Enquanto (<Condição>) V
Cond?
LOOP: ;
INCF CONTROL,W ; \
MOVWF PORTB ; > Bloco
CALL MEDIDA ; /
MOVFW MED
SUBLW 40h ; (W) 40h – (W)
BTFSC STATUS,C ; se((MED) < 40h) então sai do loop
GOTO LOOP ; senão retorna ao inicio loop
3.12.2 Enquanto
Enquanto (While): estrutura de repetição semelhante a condição Faça-Enquanto, porém difere em
um ponto muito importante: enquanto um Faça-Enquanto executa o bloco primeiro e testa a
condição depois a estrutura Enquanto testa a condição primeiro e executa o bloco depois. Essa
diferença pode mudar totalmente a lógica do programa. A apresentação da estrutura abaixo deixa
clara essa diferença.
Enquanto (<Condição>)
[Bloco] F V
Cond? Bloco
Fim_Enquanto
Exsto Tecnologia
Microcontroladores PIC16F877A 79
LOOP:
CALL MEDIDA ; realiza uma medida
SUBLW 40h ; (W) 40h – (W)
BTFSS STATUS,C ; só “sai”quando (MED) < 40h
GOTO CONTINUA ; sai do loop
;
INCF CONTROL,W ; \
MOVWF PORTB ; > Bloco
MOVFW MED ; /
GOTO LOOP
CONTINUA:
. . .
3.12.3 Para
Para (For): estrutura de repetição que tem uma característica que a torna diferente da estruturas de
repetição até agora estudadas: nas estruturas Enquanto e Faça-Enquanto a condição da estrutura é
uma condição aleatória, isto é, ela não depende da estrutura de repetição; isso significa que o
número de vezes que o bloco é repetido não é conhecido a priori. Na estrutura Para a condição está
intimamente ligada a estrutura e seu estado é alterado por esta. De fato, a estrutura Para serve para
que blocos de código sejam repetidos um número de vezes conhecido, o que implica na existência de
uma variável contadora associada à estrutura.
Deve-se notar então que para essa estrutura a variável contadora não deve ter seu valor alterado
pelo bloco de instruções, somente pela estrutura de repetição em si.
[Bloco]
Fim_Para
<contador> <valor inicial>
Bloco
Passo
V F
<contador> = <valor final> ?
A estrutura funciona da seguinte maneira: (1) primeiramente a variável contadora recebe o valor
inicial. (2) O programa entra no loop propriamente dito, o bloco é executado e (3) a instrução que
dará o passo à contagem das vezes que o loop é executada. (4) Em seguida é testado se a variável
Exsto Tecnologia
Microcontroladores PIC16F877A 80
contadora atingiu o valor final. Se o atingiu, o programa sai do loop e segue; senão o processo é
repetido novamente a partir do ponto (2).
O passo é como a variável contadora varia a cada execução do loop. Apesar de poder assumir
qualquer forma (por exemplo, a cada execução do loop o contador pode ser elevado ao quadrado)
normalmente o passo é ou um incremento (contador contador + 1) ou um decremento (contador
contador - 1).
Pelo exposto acima, o bloco contido na estrutura será repetido N vezes, N dado por:
Ou
Para a implementação de uma estrutura Para em Assembly são usadas as instruções DECFSZ e
INCFSZ:
Para o caso de INCFSZ, o valor do contador será igual a zero quando for somado 1 ao valor 255.
Se INCFSZ for usado, o valor final obrigatoriamente será 256, então o valor inicial deve ser calculado
subtraindo a quantidade de vezes que o loop deve ser executado de 256. Por exemplo, para N = 12, o
valor inicial deve ser 256 - 12 = 244. Quando é usada a instrução DECFSZ o valor final
obrigatoriamente será 0. Dessa forma, o valor inicial será o número de vezes que o bloco deve se
repetir. A contagem nesse caso é regressiva, isto é, o passo é de decremento. O código abaixo
apresenta um loop que será repetido 123 vezes.
. . .
MOVLW .123 ; o “.” (ponto) indica que o valor é decimal
MOVWF CONT ; (1) (CONT) 123
LOOP: ; (2) o bloco será executado 123 vezes
CALL TX_SERIAL ; bloco a ser repetido
DECFSZ CONT,F ;(3)e(4) CONT <-CONT-1, se (CONT=0) salta
GOTO LOOP ; senão volta para LOOP
. . .
Exsto Tecnologia
Microcontroladores PIC16F877A 81
Porém muitas vezes não se deseja que uma instrução seja executada imediatamente após outra. Em
muitas situações necessitamos de gerar atrasos na execução normal do programa. Por exemplo, em
muitos casos onde um usuário interage com o microcontrolador, é necessário esperar o usuário; em
muitas situações também é preciso respeitar a temporização de outros componentes, não tão
rápidos quanto o microcontrolador. Esses atrasos são conseguidos com as chamadas sub-rotinas de
atraso, ou de delay (atraso, em inglês), como é mais comum chamá-las.
Existem basicamente dois modos de se conseguir “delay”. Um seria utilizando o Timer incorporado
ao microcontrolador, trabalhando então com temporização por interrupção, a qual será tratada
mais adiante. Outra forma é criando estruturas de repetição nas quais possamos “perder” o tempo
necessário, que é a temporização por software.
Ainda considerando o PIC trabalhando a 1 MIPS (1 Milhão de Instruções Por Segundo) quando é
necessário um atraso de 10µs basta executarmos 10 vezes uma instrução qualquer. Porém, aplicando
o mesmo raciocínio para um atraso de 3s é necessário repetir a mesma instrução 3.000.000 vezes, o
que ocupa 3.000.000 endereços da memória de programa! Como pode ser notada, na maior parte
das vezes não podemos criar delays com a simples seqüência do número de instruções necessário. O
que se faz é a criar estruturas de repetição que executem um ou algumas instruções o número de
vezes necessário para nos dar o atraso desejado. Repetir um bloco de 4 instruções 50 vezes equivale
(do ponto de vista do tempo gasto) a executar 200 instruções. Deve-se tomar cuidado, porém, com o
fato de que a estrutura de repetição também demora um tempo para ser executada. Para atrasos
precisos devemos considerar o tempo de execução das estruturas, principalmente quando temos
laços de repetição dentro de outros laços de repetição.
O núcleo de uma rotina de delay é estrutura de repetição Para responsável por repetir um bloco de
instruções um determinado número de vezes. Observemos o trecho de código abaixo. Os
comentários em cada linha indicam quantos ciclos de máquina são executados em cada instrução
(Devemos lembrar que instruções de desvio e instruções de teste, quanto a condição testada é
verdadeira, gastam 2 ciclos de máquina).
MOVLW n ; 1
MOVWF CONT1 ; 1
LOOP1:
NOP ; 1
DECFSZ CONT1,F ; 1 normalmente, 2 quando CONT1 == 0 | Bloco
GOTO LOOP1 ; 2
No código acima, “n” será substituído por uma constante que, como veremos mais a seguir, dará o
tempo de execução do código. O “bloco“ é será repetido até que CONT1, que é decrementado a cada
execução, resulte em 0. Ou seja, o bloco será repetido “n” vezes. Como a execução do bloco leva 4
ciclos de máquina, o tempo total gasto na repetição do bloco é 4 x n. Já o tempo total de execução
da rotina do trecho de código deve levar em consideração o tempo gasto para carregar a variável
CONT1, que é de 2 ciclos de máquina. Portanto, podemos concluir que o tempo total de execução
desse trecho de código é dado pela equação (1) , sendo TCY o tempo do ciclo de máquina do
microcontrolador (que estamos considerando como sendo de 1µs):
Exsto Tecnologia
Microcontroladores PIC16F877A 82
T = ( 4 × n + 2) × TCY (1)
DELAY:
; rotina de atraso
; entrada: nulo
; saída: nulo
MOVLW n ; 1
MOVWF CONT1 ; 1
LOOP1:
NOP ; 1 \
DECFSZ CONT1,F ; 1 normalmente, 2 quando CONT1 == 0 | Bloco
GOTO LOOP1 ; 2 /
RETURN
T = ( 4 × n + 6) × TCY (2)
Para determinar o valor da constante “n” basta isolá-la na equação (2) e obtemos a equação (3),
lembrando sempre que “n” é um valor inteiro entre 1 e 255.
n = 0,25 T − 6 (3)
TCY
Devemos atentar para duas limitações dessa sub-rotina. A primeira é que não é possível obter um
valor de n inteiro para qualquer valor de T. Por exemplo, para T = 31µs temos n = 6,25. Nesse caso,
se adotarmos n = 6 obtemos um tempo de 30µs. Nessa situações, porém, a diferença entre o valor
desejado e o valor obtido será sempre pequena, e podemos completar o tempo necessário com a
simples adição de um instrução NOP
Outra limitação é que o valor máximo de n é 255, o que nos leva a um tempo máximo de 1,026 ms.
Para obter tempos maiores que esse o procedimento é considerar todo o código da rotina como
sendo um bloco, e inseri-lo dentro de outro loop. Observe como isso é feito na sub-rotina baixo.
DELAY_MAIOR:
; rotina de atraso para tempos maiores que 1 ms
; entrada: nulo
; saída: nulo
MOVLW m ; 1
MOVWF CONT2 ; 1
LOOP2:
; --- --- --- --- --- --- --- --- --- --- ---
MOVLW n ; 1
MOVWF CONT1 ; 1
LOOP1:
Exsto Tecnologia
Microcontroladores PIC16F877A 83
NOP ; 1 \
DECFSZ CONT1,F ; 1 normalmente, 2 quando CONT1 == 0 | Bloco
GOTO LOOP1 ; 2 /
; --- --- --- --- --- --- --- --- --- --- ---
DECFSZ CONT2,F ; 1 normalmente, 2 quando CONT2 == 0
GOTO LOOP2 ; 2
RETURN
O tempo total gasto para essa rotina é determinado pela equação (4). A equação (5) permite calcular
o valor de “m” arbitrando-se o valor de “n”.
T −6
TCY (5)
m=
4n + 5
Com essa rotina é possível se obter tempos de até 261,381 ms. Para tempos ainda maiores, basta
usar o mesmo raciocínio: considerar a sub-rotina um bloco e colocá-la dentro de outro loop.
Exsto Tecnologia
Microcontroladores PIC16F877A 84
4 RECURSOS AVANÇADOS
4.1 Display de cristal Líquido
Grande parte das aplicações com microcontroladores necessitam de uma interface homem-máquina,
para que os usuários possam passar informações ao sistema e/ou receber informações dele. Para
que informações do sistema sejam passadas ao usuário pode-se utilizar uma serie de recursos,
porém muitos deles não são nada maleáveis e alguns pouco amigáveis. Por exemplo, um modo
bastante simples de se ter informações do sistema é através de um painel com LED´s, cada um
indicando uma determinada situação. Embora em muitas aplicações só isso seja suficiente, em
muitas outras, principalmente quando a quantidade e variedade de informações são grande, esse
método se torna insuficiente. Outro método também muito utilizado e que, porém, aceita uma
grande variedade e quantidade de informações é o Display de Cristal Líquido (LCD – Liquid Cristal
Display).
Existe uma grande variedade de LCD’s no mercado. Existem displays gráficos e displays que aceitam
somente caracteres, esses últimos chamados displays alfanuméricos. Esses podem ter diferentes
quantidades de linha e colunas. LCD’s alfanuméricos tem uma determinada “inteligência”, isto é,
possuem circuitos que controlam o display propriamente dito, e fazer com que algo seja escrito no
LCD é somente o trabalho de comunica-se com esses circuitos.
Para a comunicação com o display são necessários 8 bits como via de dados (podendo também ser
configurado para trabalhar com 4 bits), um bit EN (Enable - Habilitação) e um bit RS (seleção entre
dados e comandos). O display reconhece dois tipos de informação na via de dados: comandos e
dados. Os comandos, que são reconhecidos quando RS = 0, são instruções para o display (limpar a
tela, ir para a segunda linha, ir para a décima coluna, etc... ); os dados são caracteres a serem escritos
no display, e são indicados por RS = 1. A 4 bits da via de dados são ligados aos bits 4 a 7 do LCD.
Exsto Tecnologia
Microcontroladores PIC16F877A 85
Os endereços de cada posição no display são dados pela tabela abaixo. Para que um caracter seja
escrito em uma determinada posição, envia-se o valor dessa posição como comando e em seguida
envia-se o caracter a ser escrito.
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
A figura 7.1 apresenta o circuito básico LCD.
Exsto Tecnologia
Microcontroladores PIC16F877A 86
A tabela seguinte apresenta a função de cada um dos pinos do display e em como eles estão ligados
ao PIC.
Comando:
Exsto Tecnologia
Microcontroladores PIC16F877A 87
Dados:
Enquanto EN estiver em ‘0’ (‘Falso’) qualquer mudança em RS ou na via de dados é ignorada pelo
display.
Além dessas duas sub-rotinas básicas, deve-se criar também uma sub-rotina de inicialização do
display, pois esse também necessita ser configurado. Essa sub-rotina será chamada logo após a
inicialização do microcontrolador. Somente para a inicialização deve-se utilizar um atraso de 5ms na
rotina de envio de comando. Uma seqüência de inicialização básica é apresentada abaixo.
4.2 Teclado
Uma forma muito comum de usuário de um sistema microcontrolado passar informações ao sistema
é através de teclas. Em muitas aplicações o número teclas existentes pode ser bastante grande.
Nesses casos, a leitura dessas teclas simplesmente conectando-as aos terminais do microcontrolador
incorre na utilização de muitos terminais. Nessa aplicação é apresentado um sistema de varredura
que permite fazer um uso otimizado dos terminais do microcontrolador de foram a reduzir o número
de terminais utilizados.
Para essa experiência será feito uso do teclado do kit. Esse módulo funciona implementando um
sistema de varredura que nos permite realizar a leitura de um número de teclas N utilizando menos
de N entradas. Isso é importante quando existe uma grande quantidade de teclas a serem lidas e não
se dispõe tanta entrada.
Para o caso da placa de teclado existem 16 teclas e seus estados são lidos com apenas 4 saídas e 4
entrada, num total de 8 terminais. A varredura funciona da seguinte maneira: o teclado é organizado
de forma a ter 4 colunas e 4 linhas, conforme a figura abaixo. Cada linha é ligada a uma entrada, e
cada coluna a uma saída. Existem resistores de pull-up nas entradas de forma que enquanto uma
tecla não for pressionada, a entrada ficando em aberto tem nível lógico alto. Começando a
varredura, é forçado “0” na coluna 0 (C0), “1” nas coluna 1 (C1), 2 (C2) e 3 (C3) e são lidas as quatro
linhas (L0, L1, L2 e L3). Em seguida coloca-se “1” em C0 e C2 e “0” em C1 e lêem-se as linhas, e assim
Exsto Tecnologia
Microcontroladores PIC16F877A 88
sucessivamente.. Nos momentos em que é feita a leitura das linhas podemos determinar se uma
tecla está pressionada e qual é essa tecla da seguinte maneira: admitindo que a tecla está ligada a
coluna que está em zero no momento a linha ligada a ela estará em também. As linhas que contém
teclas que não estão pressionadas estarão em “1”, devido aos resistores de pull-up. Seguindo esse
raciocínio podemos gerar a seguinte tabela:
C3 C2 C1 C0 L3 L2 L1 L0 Tecla
1 1 1 0 1 1 1 0 1
1 1 0 1 1 1 1 0 2
1 0 1 1 1 1 1 0 3
0 1 1 1 1 1 1 0 A
1 1 1 0 1 1 0 1 4
1 1 0 1 1 1 0 1 5
1 0 1 1 1 1 0 1 6
0 1 1 1 1 1 0 1 B
1 1 1 0 1 0 1 1 7
1 1 0 1 1 0 1 1 8
1 0 1 1 1 0 1 1 9
0 1 1 1 1 0 1 1 C
1 1 1 0 0 1 1 1 */F
1 1 0 1 0 1 1 1 0
1 0 1 1 0 1 1 1 #/E
0 1 1 1 0 1 1 1 D
Tabela 7.3 – Funcionamento do LCD
Exsto Tecnologia
Microcontroladores PIC16F877A 89
No programa que utilizar leitura de teclado deve-se ativar os resistores de pull-up do portal B. Caso
contrário, o teclado não funcionará corretamente. Isso é feito zerando o bit NOT_RBPU do registro
OPTION_REG, assim
4.3 Interrupções
Interrupções são poderosos recursos presentes nos sistemas computacionais, que permitem
desenvolver códigos mais elaborados e profissionais, garantindo tratamento imediato a eventos de
maior prioridade.
Uma interrupção faz exatamente isso: interrompe a execução normal do programa para executar
tarefas de maior prioridade no momento. Ela pode ser chamada por determinados eventos, parando
a execução normal no momento em que ocorre o evento, executando o código armazenado em uma
posição de memória vinculada a interrupção e depois retornam a execução normal do programa. As
interrupções podem ser vistas como chamadas de sub-rotinas realizadas pelo hardware.
Observe que a distância entre o vetor de inicialização (0000h) e o vetor de reset (0004h) é de apenas
4 endereços. Dessa forma quando as interrupções estão desabilitadas o PC passa por 0004h
normalmente durante a execução de um programa. Quando se faz necessário o uso de interrupções,
as rotinas de tratamento de interrupção são colocadas a partir do vetor de reset 0004h. No intervalo
entre o vetor de inicialização e o vetor de reset é colocado um desvio para um endereço após as
rotinas de interrupção a partir do qual o programa realmente começa.
Quando ocorre um pedido de interrupção para a CPU do PIC16F877A, o programa é desviado para
um endereço pré-estabelecido, o vetor de reset (0004h). Desse endereço em diante é feito o
tratamento de interrupção, isto é, são executadas as rotinas que se deseja associar ao evento
causador da interrupção.
Exsto Tecnologia
Microcontroladores PIC16F877A 90
• Interrupção do timer 0;
• Interrupção do timer 1;
• Interrupção do timer 2;
• Interrupção externa (RB0/INT);
• Interrupção por mudança de estado (bits 4 a 7 do portal B);
• Interrupção de transmissão serial;
• Interrupção de recepção serial;
• Interrupção do módulo comparador analógico;
• Interrupção do módulo CCP1;
• Interrupção do módulo CCP2;
• Interrupção da memória EEPROM;
• Interrupção do conversor analógico para digital;
• Interrupção da porta paralela escrava;
• Interrupção da comunicação SPI;
• Interrupção por colisão no barramento I2C.
A cada interrupção são associados dois bits, para seu controle, sendo que um é o bit de habilitação,
alterado somente pelo programa, e o outro é o flag indicador de interrupção, que é setado quando
ocorre a interrupção em questão. Esse último bit pode, porém, ser alterado também pelo programa.
A Figura 2.9 mostra a lógica como se relacionam as interrupções. Existem mais dois bits envolvidos
no trabalho com interrupção, PEIE e GIE. PEIE habilita as interrupções dos periféricos. GIE, por sua
vez, realiza a habilitação global. Como pode ser notado, se GIE estiver em ‘0’ todas interrupções
estão desabilitadas; se GIE estiver em ‘1’ as interrupções que estiverem habilitadas gerarão pedidos
de interrupção à CPU.
Exsto Tecnologia
Microcontroladores PIC16F877A 91
Atenção: Os flags das interrupções são setados quando ocorre um evento que geraria a interrupção,
mesmo que essa interrupção não esteja habilitada.
As interrupções externas, isto é, que são causadas diretamente por eventos externos ao
microcontrolador, são a interrupção INT em RB0 e a interrupção por mudança de estado do portal B.
As demais interrupções são internas, ou seja, causadas pelos periféricos para indicar determinados
eventos (chegada de dado pelo portal serial, "estouro" de timer, etc).
Quando ocorre uma interrupção o endereço chamado é (sempre) o vetor de interrupção (0004h).
Conseqüentemente, a rotina de tratamento de interrupção deve obrigatoriamente começar nesse
endereço.
Para a determinar qual interrupção ocorreu testa-se os bits de flags de todas as interrupções ativas.
Pela ordem em que esses bits são testados pode-se atribuir a prioridade à interrupção, sendo que as
interrupções testadas em primeiro lugar têm prioridade maior.
Um outro cuidado que deve ser tomado quando se trabalha com interrupções é não executar
rotinas muito grandes. Isso porque o tratamento de interrupção deve tomar medidas emergenciais.
Nada que não seja estritamente necessário deve ser trabalhado na interrupção, e isso principalmente
porque podem ocorrer várias interrupções em seguida, e só se pode tratar uma por vez. Quando
uma interrupção é chamada, a habilitação das demais fica desativada, e só é reativada após a
execução do RETFIE. Se outra interrupção ocorrer nesse intervalo de tempo, ela é tratada após
RETFIE. Deve-se notar que o que ativa a chamada de interrupção é a existência de um flag setado de
uma interrupção habilitada. Assim, depois de tratar uma determinada interrupção deve-se zerar o
flag associado a ela. Caso contrário, o programa fica travado, pois cada vez que há o retorno de
interrupção (instrução RETFIE), a interrupção é chamada novamente.
Exsto Tecnologia
Microcontroladores PIC16F877A 92
3 a 3,75 ciclos de máquina se for uma interrupção externa. Esses tempos devem ser considerados
em aplicações onde a precisão de tempo é importante.
O próximo passo é habilitar as interrupções a serem utilizadas, e isso pode ser feito em dois
momentos. Pode-se determinar que uma interrupção esteja ativa durante toda a execução do
programa, e nesse caso sua habilitação deve ser feita na inicialização. Por outro lado, em algumas
situações deseja-se que a interrupção seja ativada somente a partir de um dado momento ou ainda
que seja ativada e posteriormente desativada. Nessa situação basta habilitar, ou desabilitar, a
interrupção no momento oportuno.
Como para cada interrupção existe um flag que indica sua ocorrência, para se determinar qual
interrupção basta testar os flags das interrupções habilitadas e tratar a que ocorreu. Somente uma
interrupção pode ser tratada por vez e enquanto uma interrupção é tratada (intervalo que vai desde
sua chamada até o retorno realizado pela interrupção RETFIE) não ocorre outra chamada. Isso
porque quando uma interrupção é chamada, automaticamente GIE é zerado, só sendo setado
novamente pela instrução RETFIE. Os pedidos de interrupção que porventura ocorram nesse
intervalo não são descartados, visto que quando GIE volta a ‘1’ e existe algum flag de interrupção
habilitada também em ‘1’ imediatamente o processo de tratamento de interrupção recomeça e será
repetido até que todas as interrupções pendentes sejam tratadas.
Os bits de habilitação das interrupções e respectivos flags, além de GIE e PEIE encontram-se em
quatro registros, apresentados abaixo.
Exsto Tecnologia
Microcontroladores PIC16F877A 93
o 0 = interrupções desabilitadas
PEIE: Habilitação das interrupções de periféricos
o 1 = interrupções de periféricos habilitadas
o 0 = interrupções de periféricos desabilitadas
T0IE: Interrupção do timer 0 (por overflow)
o 1 = interrupção habilitada
o 0 = interrupção desabilitada
INTE: Interrupção RB0/INT
o 1 = interrupção habilitada
o 0 = interrupção desabilitada
RBIE: Interrupção por mudança de estado no portal B
o 1 = interrupção habilitada
o 0 = interrupção desabilitada
T0IF: flag da interrupção do timer 0
o 1 = ocorreu overflow de timer 0
o 0 = não ocorreu overflow de timer 0
INTF: flag da interrupção INT
o 1 = ocorreu interrupção externa
o 0 = não ocorreu interrupção externa
RBIF: flag da interrupção por mudança de estado no portal B
o 1 = pelo menos um dos bits RB4~RB7 mudou
o 0 = nenhum dos bits RB4~RB7 mudou
PIE1 (Banco 1)
Exsto Tecnologia
Microcontroladores PIC16F877A 94
o 1 = interrupção habilitada
o 0 = interrupção desabilitada
PIR1 (Banco 0)
PIE2 (Banco 1)
Exsto Tecnologia
Microcontroladores PIC16F877A 95
Exsto Tecnologia
Microcontroladores PIC16F877A 96
; \
; > tratamento das interrupções
; /
MOVFW INT_STATUS ; \
MOVWF STATUS ; > recupera STATUS
MOVFW INT_FSR ; \
MOVWF FSR ; > recupera FSR
MOVFW INT_W ; recupera W
A interrupção ocorre na mudança de estado lógico no terminal PORTB,0. Isto significa que não é um
determinado estado lógico (‘0’ ou ‘1’) que causa a chamada da interrupção; o flag que indica a
interrupção INT (o bit INTF do registro INTCON) não é uma “cópia” do estado de RB0. A interrupção
pode ser configurada para “disparar” na transição de subida (0 para 1) ou decida (1 para 0). Isso é
feito configurando o bit INTEDG de OPTION_REG conforme mostrado abaixo.
A habilitação da interrupção INT é feita setando o bit INTE de INTCON. O bit de habilitação global das
interrupções, GIE de INTCON, também deve ser setado. Da mesma forma que a interrupção por
mudança de estado, INT pode tirar o processador do modo SLEEP.
Exsto Tecnologia
Microcontroladores PIC16F877A 97
se executar a rotina de leitura do teclado, identificando a tecla lida e retornando as colunas a nível
lógico baixo.
Esse funcionamento é bastante útil em sistema que ficam muito tempo ociosos. Nesses casos é
possível colocar o microcontrolador em modo de baixo consumo e “acorda-lo” somente quando uma
tecla for pressionada, num processo parecido ao utilizado em celulares.
Exsto Tecnologia
Microcontroladores PIC16F877A 98
5 PERIFÉRICOS DO PIC16F877A
5.1 Timers
Um dos periféricos mais comuns em qualquer linha de microcontroladores é Timer/Couter –
Temporizador/ Contador.
Trata-se de nada mais, nada a menos, que um componente contador dentro do microcontrolador. Se
atuar fazendo contagem de eventos externos, aleatórios, é dito no modo contador (Counter). Se o
evento que causa a contagem for um sinal periódico de freqüência conhecida, gerado dentro ou fora
do microcontrolador, é dito no modo temporizador (timer).
O PIC16F877A possui três timer´s: timer 0, Timer 1 e Timer 2. A operação dos três é bastante
semelhante, bastando estudar apenas um (no caso o Timer 1) para se estar habilitado a trabalhar
com os outros dois.
5.1.1 Timer 1
O Timer 1 é um temporizador/contador (timer/counter) de 16 bits. O sinal de clock pode ser
selecionado como interno ou externo. Caso seja usada a fonte de clock interna, o sinal será o do
clock de periféricos, que corresponde à freqüência do oscilador dividida por 4. No caso kit, que utiliza
um cristal de 4MHz, trata-se de um sinal com período de 1 microssegundo. Já no caso de sinal de
clock externo, o sinal deve ser aplicado ao terminal RC0. Quando se utiliza fonte de clock externo é
possível selecionar em qual transição (subida ou descida) o timer incrementa. Existem ainda uma
interrupção no overflow do timer e uma pré-escala programável que permite dividir a freqüência do
sinal de clock até por 8.
A figura 9.1 apresenta o diagrama elétrico simplificado do timer 1. O contador propriamente dito é
composto pelo par de registros TMR1H e TMR1L. Quando ocorre o overflow desse timer o flag
TMR1IF é setado, podendo ocasionar uma interrupção. Para economia de energia o timer pode ser
desabilitado através do bit TMR1ON, que inibe os pulsos de clock para o timer. O sinal de clock, caso
seja externo, pode ser sincronizado ou não com o clock interno; essa escolha é feita através do bit
T1SYNC. A pré-escala permite dividir a freqüência do sinal de clock por 1, 2, 4 ou 8. Através do bit
TMR1CS seleciona-se se a fonte de clock é interna ou externa. Sendo externo, o clock pode ser
gerado por qualquer circuito conectado a RC0 ou por um oscilador próprio do timer, que é ativado
por T1OSCEN. Esse oscilador permite colocar um cristal (tipicamente de 32.768 Hz) entre RC0 e RC1,
e que pode operar quando o microcontrolador estiver em SLEEP, ou seja, com o oscilador principal
desligado.
Exsto Tecnologia
Microcontroladores PIC16F877A 99
A pré-escala do timer 1 permite a seleção de 4 fatores de divisão, através do bits T1CKPS1 e T1CKPS0,
conforme mostrado na tabela 9.1.
Valor
Taxa de divisão
T1CKPS1 T1CKPS0
0 0 1:1
0 1 1:2
1 0 1:4
1 1 1:8
Tabela 9.1 – Pré-escala do timer 1
Exsto Tecnologia
Microcontroladores PIC16F877A 100
Há também o bit TMR1ON, que permite desligar todo o timer 1 quando este não for usado,
reduzindo assim o consumo de energia. Ele também pode ser utilizado para parar o timer em
algumas situações que trataremos mais adiante.
temporizador
contador
o síncrono
o assíncrono
No modo temporizador, o sinal de clock utilizado é o clock de periférico (TMR1CS = ‘0’). Nesse caso,
seu funcionamento é bem semelhante ao do timer 0, porém realizando contagens de 0000h á FFFFh
(16 bits), além da pré-escala.
O modo contador, por sua vez, utiliza como fonte de clock o sinal aplicado ao terminal RB6. O timer é
incrementado a cada transição de subida nesse pino. Podemos trabalhar no modo síncrono ou
assíncrono. A seleção de modo é feita pelo bit T1SYNC, sendo que ‘0’ indica modo síncrono e ‘1’
modo assíncrono.
No modo síncrono o sinal de clock é amostrado duas vezes a cada ciclo de instrução. Se a taxa de
divisão do pré-escala for 1, significa que o sinal de entrada é aplicado diretamente ao circuito de
sincronismo. Nestas condições, o sinal aplicado deve ter tempos em alto e em baixo de no mínimo 2
ciclos de instrução mais 20 ns. Por outro lado, se o valor da pré-escala for diferente de 1, os tempos
mínimo de alto e baixo são de 10 ns e o período mínimo depende do fator de divisão, conforme é
mostrado na tabela 9.4. Como o modo síncrono depende do sinal de clock, se o microcontrolador for
colocado em modo SLEEP (baixo consumo) o timer para de funcionar.
Novamente devemos tomar cuidados contra bouncing quando a fonte do sinal de contagem for
mecânica.
Exsto Tecnologia
Microcontroladores PIC16F877A 101
Além do cristal 32.768 Hz são necessários dois capacitores de 15pF dos terminais do cristal a terra.
Para ativar o oscilador, o bit T1OSCEN deve ser setado. Quando isso ocorre, os pinos RC0 E RC1
deixam de trabalhar como I/O e seus estados no PORTB ficam irrelevantes.
5.1.3 Interrupção
O bit de habilitação da interrupção do timer é o TMR1IE do registro PIE1. O bit indicador de overflow
do timer é TMR1IF de PIR1.
• Captura
• Comparação
• PWM (Modulação por largura de pulso)
Esse periférico é controlado por dois registros que operam conjuntamente como um parâmetro de
16 bits (CCP1H e CCP1L) e um registro de controle (CCP1CON). Além disso, nos modos de captura e
comparação é usado e no modo PWM o timer 2 fornece a base de tempo.
Por fim, existe uma interrupção associada ao módulo CCP, que é disparada em situações diferentes
para cada modo.
Os bits CCP1X e CCP1Y são utilizados somente no modo PWM. Os demais bits implementados servem
para seleção de modos de operação, conforme é apresentado na tabela 10.1. Deve-se observar que
após o reset, o módulo CCP fica desativado.
Valor Modo
Exsto Tecnologia
Microcontroladores PIC16F877A 102
Para operação nesse modo, o terminal RB3/CCP1 deve estar configurado como entrada e o timer
deve estar no modo temporizador ou no modo contador síncrono.
O modo captura pode ser utilizado para determinar a diferença de tempo entre dois eventos. Isso
pode ser feito de duas formas. No primeiro evento, o timer é resetado e no segundo, o valor
capturado do timer 1 multiplicado pelo período do seu clock corresponde ao tempo transcorrido
entre os dois eventos. Outra forma é deixar o timer 1 incrementado livremente e capturar seu valor
nos dois eventos. Fazendo uma subtração entre os dois valores capturados, temos o tempo entre os
eventos. Esse procedimento pode ser utilizado para medir velocidade e freqüências (nesse caso
temos o período e sabemos que f = 1/T).
Os modos onde o evento de captura é a ocorrência de 4 ou 16 transições podem ser vistos como
tendo uma pré-escala na entrada. Essa pré-escala pode ser útil para trabalhar com sinais de
freqüências altas, como será mostrado. Sua contagem só pode ser zerada com a mudança de modo
do CCP.
Exsto Tecnologia
Microcontroladores PIC16F877A 103
Durante o modo SLEEP, se ocorrer um evento, o flag é setado, mas o valor de Timer 1 não é
capturado, pois o timer 1 (como temporizador ou contador síncrono) não opera durante o SLEEP. No
reset, zera a pré-escala.
Nesse modo, o par de registros do módulo CCP (CCP1H:CCP1L) é constantemente comparado com o
par de registros do timer 1 (TMR1h:TMR1L). Quando eles coincidem, é setado o flag CCP1IF. Além
disso, podemos zerar o timer 1 ou forçar um estado no pino RB3/CCP1. Quando optamos por zerar o
timer 1, o funcionamento é muito parecido com o do timer 2 em relação ao registro PR2. Quando se
seleciona os modos que forçam estados (‘1’ ou ‘0’) no pino RB3/CCP1, o pino fica no estado oposto
ao desejado até que ocorra a coincidência. Nesse caso, o pino deve ser configurado como saída.
Exsto Tecnologia
Microcontroladores PIC16F877A 104
pulsos de freqüência fixa. Por exemplo, admitindo que estamos trabalhando com o PWM do PIC, sua
resolução máxima é de 10 bits, ou seja, 1023 corresponde a 100% de duty-cicle. Usando uma regra
de três simples, podemos determinar a quanto que corresponde 30%, 25%, 99%, etc. É chamada de
modulação porque permite carregar uma informação (expressa no duty-cicle) em uma portadora
(trem de pulsos).
Outra característica importante do PWM é que, se o sinal for filtrado, podemos obter níveis
analógicos, também proporcionais ao duty-cicle. Isso permite que geremos desde níveis analógicos
fixos até sinais mais complexos, como tons DTMF (de telefonia).
O PWM precisa de uma base de tempo que dará a freqüência do sinal. O módulo CCP utiliza o Timer
2 para conseguir essa base. Isso pode ser observado no diagrame em blocos do PWM, na figura 10.3.
Também é necessário que o pino RB3/CCP1 seja configurado como saída.
A geração do sinal PWM se dá da seguinte maneira. Cada vez que TMR2 coincide com PR2, o pino
RB3/CCP1 é setado e TMR2 é resetado. Isso nos dá a freqüência do sinal. O duty-cicle é conseguido
comparando o CCPR1H concatenado com dois bits de latch com TMR2 concatenado com mais dois
bits, da pré-escala ou gerados pelos ciclos Q; Quando há a coincidência, o pino RB3/CCP1 é zerado.
As concatenações nos dão 10 bits de resolução. Esse processo pode ser observado na figura 10.4.
O registro CCPR1H não é acessível para leitura no modo PWM. O duty-cicle é configurado através de
CCP1L e dos bits 4 e 5 de CCP1CON. Esse valor é atualizado em CCPR1H e nos bits de latch a cada
período.
Exsto Tecnologia
Microcontroladores PIC16F877A 105
Configurar o PWM é estabelecer sua freqüência e seu duty-cicle. De posse desses dois parâmetros,
podemos calcular os valores em cada registro.
Para encontrar o valor de PR2 a partir de um dado valor de período pode ser usada a equação 10.2.
Valor de PR2 deve ser inteiro e menor que 256. Logo, em alguns casos será necessário arredondar
esse valor, o que gerará um pequeno erro entre a freqüência desejada e a real. Com valores
diferentes de pré-escala podemos chegar a valores menores que 256 e a aproximações que levem a
um erro menor.
TPWM
PR 2 = −1
4 × TOSC × TMR2 PS (10.2)
O duty-cicle por sua vez é configurado através de CCPR1L e dos bits 4 e 5 de CCP1CON. Geralmente
se especifica o duty-cicle em porcentagem do tempo total. Assim, dado um duty-cicle em
porcentagem (DC%), o tempo correspondente a ele é encontrado pela equação 10.3
TDC = TPWM × DC %
100 (10.3)
Exsto Tecnologia
Microcontroladores PIC16F877A 106
Dispondo do tempo do duty-cicle, o valor de DC[9:0] é dado pela equação 10.5. Esse valor deve ser
inteiro e menor que 1023. O valor da pré-escala deve ser o mesmo utilizado para a determinação do
período.
T DC
DC[9 : 0] =
TOSC × TMR 2 PS (10.5)
O período (e conseqüentemente a freqüência) é dado pelo registro PR2. Para freqüências altas
(períodos pequenos) existe uma perda da resolução, isto é, na verdade trabalhamos com menos de
10 bits. Por exemplo, se o valor usado para PR2 for 63, os dois bits mais significativos são “perdidos”
e 100% de duty-cicle corresponderá á 255. Teremos um PWM de 8 bits. A resolução, dada em bits,
para uma dada freqüência de PWM é dada pela equação 10.6.
FOSC
log( )
FPWM
RESOLUÇÃO = (10.6)
log( 2)
5.2.4 Interrupção
O bit de habilitação de interrupção é CCP1IE em PIE1. O flag de interrupção é CCP1IF em PIR1.
O evento que dispara a interrupção depende do modo de trabalho. Assim a interrupção significa:
Esse tipo de condução exige pouco ou nenhum preparo para o envio, visto que os dados são tratados
dentro do processador de forma paralela. Outra característica dessa forma de comunicação é a
velocidade. Como a informação toda é enviada de uma só vez, a transferência de informações ocorre
em tempo mínimo.
Exsto Tecnologia
Microcontroladores PIC16F877A 107
As limitações dessa técnica surgem quando as distâncias entre os pontos que se deseja comunicar
aumentam. Em primeiro lugar para interconexão de equipamentos em distâncias grandes o uso de
comunicação paralela exige conectores de muitos pinos e cabos de várias vias.Como pode ser
intuído, o custo dos cabos e conectores é proporcional ao número de vias do cabo.
Além do custo dos cabos outro impedimento para a comunicação paralela são os efeitos reativos
(capacitivos e indutivos) dos meios de comunicação paralela (sejam eles cabos ou trilhas numa
placa). Em altas taxas de transmissão devemos considerar os condutores a luz da teoria de guias de
ondas, que de forma resumida nos diz que em altas freqüências um fio ou uma trilha não devem ser
encarados como um curto-circuito, mas como uma associação de resistências, capacitâncias e
indutâncias. Em virtude disso os sinais podem se degradas por interferência mútua e também, pelas
próprias características do meio. Outro ponto importante é o ruído (interferência) inserido nos
condutores e proveniente do onde eles estão. Novamente o maior número de condutores agrava a
situação. Esses fatos são inerentes a qualquer linha de transmissão de sinais elétricos, mas o agrava
os problemas na comunicação paralela é que cada linha de transmissão é um meio diferente das
demais, ou seja, cada bit é degradado de forma diferente. Isso pode acarretar problemas na
comunicação de dados a distâncias longas (o critério para dizer se uma distância é “grande” é sua
comparação com o comprimento de onda do sinal que se transmite), limitando assim a comunicação
a pequenas distâncias em alta velocidade (por exemplo, barramentos do PC) ou a distâncias maiores
com baixa taxa de transmissão (por exemplo, comunicação entre PC e impressora).
Quanto ao quesito custo essa forma de transmissão é bastante eficiente, porque em sua forma mais
simples pode ser implementada com apenas dois condutores, um para envio de dados e outro de
referência.
A comunicação serial também traz vantagens no aumento das taxas e das distâncias de comunicação.
Técnicas para a redução de ruído e degradação do sinal podem ser aplicadas mais facilmente quando
a informação transita por um único caminho. Além disso, não há problemas em os bits serem
afetados de forma diferente, pois são tratados separadamente.
Em contrapartida, a comunicação serial demanda um circuito mais complexo, uma vez que a
informação que é tratada de forma paralela pelo processador deve ser convertida para o formato
paralelo. Pelo mesmo motivo, a transmissão é mais lenta que a paralela (observando apenas o tempo
do envio de uma informação). O principal problema a ser resolvido na comunicação serial, porém, é
saber quando um bit termina e quando começa o próximo. E ainda, os cabos não deixam de ser guias
de ondas, apresentando os problemas discutidos acima e mantendo sempre uma relação de
compromisso entre o comprimento dos cabos e a taxa transmissão máxima.
Por todas essas razões a quase totalidade das conexões entre equipamentos é feita por comunicação
serial. Entre as formas de comunicação serial mais difundida podemos citar o EIA-232, EIA-485, o USB
e mesmo as LAN´s Ethernet.
A comunicação serial pode se dar de duas maneiras principais, a síncrona e assíncrona, que diferem
na forma de localizar cada bit em uma “rajada”.
Exsto Tecnologia
Microcontroladores PIC16F877A 108
Como o próprio nome diz, na comunicação serial síncrona existe um sincronismo, nesse caso entre o
sinal transmitido e um clock enviado juntamente. O clock permite determinar o exato momento em
que o bit do sinal deve ser lido, evitando assim erros na recepção e a correta montagem do dado na
forma paralela. Entres as formas de comunicação serial síncrona podemos citar o I2C e o SPI, que não
serão tratados aqui.
Já na comunicação assíncrona nenhuma referencia de onde o bit deve ser lido é enviado com o sinal.
A solução nesse caso é “adivinhar” o momento certo de ler o bit. Para isso é necessário que o
receptor saiba a taxa e transmissão, e portanto a duração de cada bit, e que o transmissor indique de
alguma forma onde começa e onde termina a transmissão. Dessa maneira, o receptor aguarda a
chegada da indicação de início, chamado start bit ou bit de início e quando esse é lido ele sabe que a
cada intervalo de tempo, chamado tempo de bit (tB) um bit novo está presente na via de
comunicação. Para minimizar o risco de erro a leitura é feita na metade da duração do bit ou são
feitas algumas amostras durante esse intervalo de tempo.
Aparentemente, se procedermos dessa forma, bastaria enviar um start bit e para sincronizar
receptor e transmissor e depois poderia vir uma seqüência infinita de bits. Na verdade, porém, isso
não ocorre, pois sempre existira uma pequena diferença entre as bases de tempo de TX e RX. Como
uma amostra ocorre tB após a anterior, se esse tempo estiver errado, o erro vais se acumulando até
que se perca o sincronismo. Por exemplo, se o relógio de RX for 5% mais lento ou mais rápido que o
de TX a cada 20 bits recebido o sincronismo será perdido. Na prática os dados são enviados em
“pacotes” de alguns bits, iniciados por um start bit e terminados por um stop bit. O stop bit tem a
função de marcar o fim do pacote, para que um bit de informação não seja confundido com um novo
start bit.
Tempo ocioso
(opcional)
1, 1 ½ ou 2 stop bits
5 a 9 bits de dados
1 start bit
Dos diversos padrões de comunicação serial assíncrona, dois são de especial interesse por sua ampla
utilização nas aplicações de microcontroladores. São eles o EIA-232C e o EIA-485
Exsto Tecnologia
Microcontroladores PIC16F877A 109
5.3.3 EIA-232C
Popularmente conhecido como RS-232, esse protocolo foi inicialmente desenvolvido para permitir a
comunicação entre computadores e modens, para transmissão de dados a longa distância. A norma
que rege o protocolo é a TIA/EIA-232, cuja revisão C é a mais recente (1969).
Devido a sua aplicação inicial como protocolo de comunicação entre um terminal de computador e
um equipamento de comunicação, o protocolo estabelece os conceitos de DTE (Data Terminal
Equipament – Equipamento Terminal de Dados) e DCE (Data Communication Equipament –
Equipamento de comunicação de dados). O sentido dos pinos de comunicação é dado do ponto de
vista do DTE. Como tipicamente o EIA-232 é utilizado para comunicação entre um computador e o
microcontrolador vamos sempre admitir aqui que computador é o DTE e o microcontrolador DTE.
A norma especifica vários pinos mas na prática os mais utilizados são os apresentados na tabela
abaixo. As funções e direções dos pinos são dadas em função do DTE
Os pinos DSR e DTR servem para indicar que os equipamentos estão conectados e prontos para
comunicação. DTS e CTS servem para fazer controle de fluxo: Quando o DTE tem dados para
transmitir ele informa o DCE através de RTS; se o DCE pode receber esses dados CTS é ativado.
Em uma grande maioria dos casos são utilizados apenas os terminais de transmissão e recepção de
dados, podendo ser usado um cabo com apenas 3 fios (TxD, RxD e Terra).
Segundo a norma, a comunicação serial pode suportar taxas de bit (geralmente chamadas baud rate)
de até 20 kbps. É possível realizar comunicação full-duplex, ou seja, nos dois sentidos ao mesmo
tempo.
A distância máxima do cabo de comunicação deve ser inferior a 15 metros (50 pés).
Umas das principais causas da limitação de taxa e distância do EIA-232C é limitação nos tempos de
subida e descida do sinal, que deve ser menor que 4% do tempo de bits.
Exsto Tecnologia
Microcontroladores PIC16F877A 110
TX Cabo RX
+15V +15V
‘0’
+5V
+3V
?
-3V
-5V
‘1’
-15V -15V
No transmissor o nível lógico ‘0’ é representado por uma tensão entre +5 e +15 Volts e o nível lógico
‘1’ é representado por tensões entre -5 e -15 Volts. No receptor tensões entre +3 e +15 Volts são
interpretadas como ‘0’ e entre -3 e -15 Volts interpretadas como ‘1’; tensões entre +3 e -3 Volts
levam a estados ideterminados. A diferença entre os limites de tensão no transmissor (-5V e +5V) e
os limites do receptor (-3V e +3V) constitui a margem de segurança, dentro da qual ruídos e eventuas
perdas no cabo não degradam os dados.
As tensões máxima mínima que podem ser aplicadas ao receptor sem que haja dano são,
respectivamente, +25V e -25V. Além disso, a norma especifica que qualquer curto circuito entre
quaisquer pinos, inclusive o pino de terra, não devem causar dano ao circuito.
Como na maioria das aplicações trabalha com circuitos alimentados com +5V são necessários
conversores de nível para criar uma interface elétrica com o EIA-232, dentre os quais os mais
conhecidos são o MAX232 e seus equivalentes.
A diferença entre os módos Síncrono Mestre e Escravo é que o Mestre gera o clock para os escravos.
Abordaremos somente o modo assíncrono, que nos permitirá implementar uma comunicação sob o
protocolo RS-232 com o PC.
Os pinos do microcontrolador associados à USART são RB6 para transmissão (TxD) e RB7 para
recepção (RxD). Quando a USART está habilitada esses pinos deixam de operar como entradas e
saídas digitais.
Exsto Tecnologia
Microcontroladores PIC16F877A 111
Para configurar transmissão e recepção são utilizados dois registros TXSTA e RCSTA.
Exsto Tecnologia
Microcontroladores PIC16F877A 112
Além das configurações feitas pelos registros acima é importante configurar a taxa de transmissão da
comunicação serial. Isso é feito carregando o valor adequado no registro SPBRG, que configura o
gerador de taxa de transmissão do PIC. Para determinar esse valor é usada a equação 11.1, se o bit
BRGH está ‘0’, e a equação 11.2 se BRGH está em ‘1’.
Fosc
Taxa = (11.1)
64 × ( SPBRG + 1)
Fosc
Taxa = (11.2)
4 × ( SPBRG + 1)
5.3.5 Transmissão
Durante o processo de transmissão serial assíncrona entra em operação o circuito apresentado na
figura 11.3.
O processo de transmissão se inicia quando um dado é escrito no registro TXREG. Quando isso ocorre
o valor de TXREG é transferido para o registro interno TSR (desde que esse esteja vazio) e o flag TXIF
é setado. O valor contido em TSR é enviado de forma serial pelo tino RB6/TxD, conforme a taxa de
transmissão selecionada.
Exsto Tecnologia
Microcontroladores PIC16F877A 113
Feito isso, toda vez que um dado é movido para TXREG o mesmo é automaticamente transmitido de
forma serial.
5.3.6 Recepção
Para receber dados de forma serial o circuito interno a USART comporta-se como apresentado na
figura 11.4
Os dados recebidos pela porta serial são rotacionados e alojados no registro interno RSR. Uma vez
verificado a coerência de start bit e stop bit, os dados são transferidos para o buffer de recepção, isto
é, o registro RCREG e o flag RCIF é setado. Caso haja alguma incoerência com os bits de start e stop,
o indicador de erro de equadramento FERR é setado. O flag RCIF é zerado toda quando o registro
RCREG é lido.
Podem ser recebidos até dois bytes sem que faça a leitura do registro RCREG, sendo que o primeiro
recebido fica armazenado em RCREG e o segundo em RSR, sendo transferido para RCREG assim que
este é lido. Caso chegue um terceiro byte RSR é sobrescrito e o bit de erro OERR é setado.
Para realizar recepção de dados enviados pela serial é necessário seguir os seguintes passos:
Exsto Tecnologia
Microcontroladores PIC16F877A 114
Feito isso, basta monitorar o bit RCIF, que será setado toda vez que existir um dado válido no registro
RCREG.
PIC16F877A possui um ADC com oito canais analógicos. Isso significa que a tensão a ser escolhida
dentre a de oito entradas diferentes, porém não somente uma entrada pode ser convertida por vez.
Além disso, as tensões de referência para a conversão, tanto superior (Vref+) como inferior (Vref-),
podem ser selecionadas por software entre as tensões de alimentação e tensões presentes em
determinados terminais do microcontrolador. Esses valores de tensão estipulam a faixa de valore a
ser convertida. Por exemplo, sendo Vref+ = Vdd e Vref- = Vss temos uma faixa de 5V,
correspondendo o valor 0 a 0V e 1024 a 5V. Para determinar um qual o valor correspondente dentro
dessa faixa, basta aplicar uma simples regra de três. Essas considerações podem ser observadas na
figura 12.1.
Exsto Tecnologia
Microcontroladores PIC16F877A 115
O módulo ADC realiza todo o processo de “Sample and Hold” (Amostragem e retenção). Esse
processo é realizado quando uma determinada entrada é selecionada e inicia-se a carga de um
capacitor interno CHOLD . Após o tempo de carga do capacitor (THOLD) a entrada é desconectada e
inicia-se o processo de conversão da tensão armazenada no capacitor, que é feito pelo método de
aproximações sucessivas. A figura abaixo apresenta o circuito equivalente da entrada da do ADC.
Requisitos de funcionamento
A resistência da fonte da tensão a ser convertida (Rs no circuito acima) não deve ser superior a 10kΩ,
caso contrário o capacitor CHOLD pode não ser completamente carregado quando se iniciar a
conversão.
Além disso, o processo de conversão só poderá ser iniciado depois de decorrido o tempo de carga do
capacitor (THOLD). A ativação do processo de conversão será explicada mais adiante.
O tempo total de amostragem, que vai do instante em que o canal a ser amostrado é selecionado ao
momento em que o resultado da conversão é armazenado nos registros de resultado do AD, é a
soma do tempo de aquisição com o tempo de conversão. O tempo de aquisição varia em função da a
temperatura, da tensão de alimentação e da resistência da fonte do sinal a ser amostrado. Para
temperaturas inferiores a 25oC, alimentação de 5V o tempo de aquisição encontra-se no intervalo:
Já o tempo de conversão depende do clock de conversão. Esse clock pode ser selecionado como
Fosc/2, Fosc/8, Fosc/32 ou baseado em um oscilador RC interno que varia entre 2 e 6 µs. A seleção
do clock de conversão deve ser tal que o período seja de 1,6µs no mínimo.
Finalmente, após uma conversão ser concluída é necessário aguardar 2 períodos do clock de
conversa antes de se reiniciar o processo.
Exsto Tecnologia
Microcontroladores PIC16F877A 116
ADRESH e ADRESL
São os registros onde são armazenados os valores resultantes da conversão. Como se trata de ADC
de 10bits são necessários 2 registros para esse resultado, ficando 2 bits em um registro e 8 em outro.
A disposição desse registro pode ter dois formatos. O formato “justificado a esquerda” é aquele em
os 8 bits mais significativos são armazenados em ADRESH e os 2 menos significativos em ADRESL. Já
no formato “justificado a direita”, os 2 bits mais significativos são armazenados em ADRESH e os 8
menos significativos em ADRESL. O formato é escolhido pelo valor do bit ADFM do registro ADCON1,
conforme ilustrado pela figura abaixo.
ADCON0
Exsto Tecnologia
Microcontroladores PIC16F877A 117
Esses bits permitem configurar a quais dos terminais que são multiplexados com entradas do ADC
serão entradas analógicas e quais serão I/O digitais. As configurações possíveis são apresentadas pela
tabela abaixo.
1. Configurar o AD na inicialização:
a. Selecionar clock de conversão
b. Definir formato do resultado
Exsto Tecnologia
Microcontroladores PIC16F877A 118
O banco de memórias EEPROM é tratado como periférico porque seu funcionamento se assemelha
mais ao de um periférico que as demais memórias. Os endereços de EEPROM não podem ser
acessados diretamente, como endereços de RAM. Seu acesso é feito através de endereçamento
indireto e seguindo certas seqüências obrigatórias de comando. A seguir serão apresentados o
funcionamento dessa memória e as rotinas para acessos de leitura e escrita.
Existem no PIC16F877A 256 bytes de memória EEPROM. O acesso a esses bytes é feito de forma
indireta através dos registros seguintes registros:
Exsto Tecnologia
Microcontroladores PIC16F877A 119
O bit WRERR permite que em aplicações de maior segurança sejam tomadas providências caso
ocorra uma falha na gravação de algum dado. O bit WREN impede a escrita acidental da EEPROM.
Para a escrita da memória, inicialmente os registros EEDATA e EEADR são carregados com o dado a
ser escrito e o endereço, respectivamente. Em seguida deve ser habilitada a escrita, fazendo WREN
igual ‘1’. Em seguida, uma seqüência obrigatória, que consiste em carregar os valor 55h e AAh no
registro EECON2, deve ser realizada para permitir a gravação da memória. Esse é mais um dispositivo
de segurança contra escritas acidentais da EEPROM. Por fim, o bit WR é setado, dando início ao
processo de escrita, e quando ele se torna ‘0’, o processo de gravação foi concluído. WR também só
pode ser setado pelo software.
READ_EEPROM:
; realiza a leitura da EEPROM de dados
; entrada: E2ADR -> endereço a ser lido
; saída: E2DATA -> dado lido
; W -> dado lido
RETURN
WRITE_EEPROM:
; realiza a escrita da EEPROM de dados
; entrada: E2DATA -> Dado a ser escrito
; E2ADR -> Endereço a ser escrito
; saída: nulo
MOVLW 55H ;
Exsto Tecnologia
Microcontroladores PIC16F877A 120
RETURN
Além dos registros usados para EEPROM existem mais dois necessários ao trabalho com a memória
FLASH, uma vez que são maiores tanto o dado (14 bits) como endereço (13 bits):
READ_FLASH:
; realiza a leitura da memória FLASH de programa
; entrada: E2ADR -> LSByte do endereço a ser gravado(Banco 2)
; E2ADRH -> MSByte do endereço a ser gravado(Banco 2)
; saída: E2DATA -> LSByte do contendo o dado lido (Banco 2)
; E2DATH -> MSByte do contendo o dado lido (Banco 2)
BCF STATUS,RP0 ;
BSF STATUS,RP1 ; Banco 2
MOVFW E2ADR ; parte menos significativa
MOVFW EEADR ; do endereço a ser lido
MOVFW E2ADRH ; parte mais significativa
MOVFW EEADRH ; do endereço a ser lido
Exsto Tecnologia
Microcontroladores PIC16F877A 121
RETURN
WRITE_FLASH:
; realiza a escrita da memória FLASH de programa
; entrada: EEADR -> LSByte do endereço a ser gravado(Banco 2)
; EEADRH -> MSByte do endereço a ser gravado(Banco 2)
; EEDATA -> LSByte do dado a ser gravado (Banco 2)
; EEDATH -> MSByte do dado a ser gravado (Banco 2)
; saída: nulo
BCF STATUS,RP0 ;
BSF STATUS,RP1 ; Banco 2
MOVFW E2ADR ; parte menos significativa
MOVFW EEADR ; do endereço a ser escrito
MOVFW E2ADRH ; parte mais significativa
MOVFW EEADRH ; do endereço a ser escrito
MOVFW EEDATA ; parte menos significativa do
MOVWF E2DATA ; dado a ser escrito
MOVFW EEDATH ; parte mais significativa do
MOVWF E2DATH ; dado a ser escrito
BCF STATUS,RP0 ;
BSF EECON1,EEPGD ; Acesso a memória FLASH
BSF EECON1,WREN ; Habilita gravação
BCF INTCON,GIE ; Desabilta interrupções
MOVLW 55h ;
MOVWF EECON2 ; EECON1 <- 55h
MOVLW 0AAh ;
MOVWF EECON2 ; EECON1 <- AAh
BSF EECON1, WR ; Inicia gravação
BCF STATUS,RP0 ;
BCF STATUS,RP1 ; Banco 0
RETURN
Exsto Tecnologia
Microcontroladores PIC16F877A 122
Apêndices
Apêndice A – Conjunto de Instruções do PIC16
Exsto Tecnologia
Microcontroladores PIC16F877A 123
Exsto Tecnologia