Escolar Documentos
Profissional Documentos
Cultura Documentos
Programando Microcontroladores PIC Linguagem C PDF
Programando Microcontroladores PIC Linguagem C PDF
30 de Agosto de 2011
1
cbnd Licenciado sobre Criative Commons Attribution-NonCommercial-NoDerivs
Contedo
1 Introduo 1
. Linguagem C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
. Hardware utilizado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
. Ambiente de programao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Instalao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Configurao do gravador ICD2 . . . . . . . . . . . . . . . . . . . . . . . 4
Criao de um novo projeto . . . . . . . . . . . . . . . . . . . . . . . . . 5
i
. Ponteiros e endereos de memria . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3 Arquitetura de microcontroladores 38
. Acesso memria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
. Clock e tempo de instruo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
. Esquema eltrico e circuitos importantes . . . . . . . . . . . . . . . . . . . . . . . 43
Multiplexao nos terminais do microcontrolador . . . . . . . . . . . . . . 44
. Registros de configurao do microcontrolador . . . . . . . . . . . . . . . . . . . . 45
6 Anexos 107
. config.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
. basico.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
. Instalar gravadores/depuradores de PIC em sistemas x64 . . . . . . . . . . . . . . 110
ii
Lista de Figuras
iii
5.1 Exemplo de mquina de estados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.2 Exemplo da mudana de slots no tempo . . . . . . . . . . . . . . . . . . . . . . . 105
5.3 Linha de tempo de um sistema com 1 slot . . . . . . . . . . . . . . . . . . . . . . 105
5.4 Comportamento da linha de tempo com interrupes . . . . . . . . . . . . . . . . 105
iv
Lista de Tabelas
v
Lista de Programas
vi
Captulo 1
Introduo
The real danger is not that computers will begin to think like men,
but that men will begin to think like computers. - Sydney J. Harris
Programao para sistemas embarcados exige uma srie de cuidados especiais, pois estes sistemas
geralmente possuem restries de memria e processamento. Por se tratar de sistemas com
funes especficas, as rotinas e tcnicas de programao diferem daquelas usadas para projetos
de aplicativos para desktops.
Tambm necessrio conhecer mais a fundo o hardware que ser utilizado, pois cada mi-
croprocessador possui uma arquitetura diferente, com quantidade e tipos de instrues diversos.
Programadores voltados para desktops no precisam se ater tanto a estes itens, pois eles progra-
mam para um sistema operacional que realiza o papel de tradutor, disponibilizando uma interface
comum, independente do hardware utilizado(Figura 1.1).
Aplicao
Sistema Operacional
Firmware
Hardware
. Linguagem C
C is quirky, flawed, and an enormous success. - Dennis M. Ritchie
Neste curso ser utilizada a linguagem C. Esta uma linguagem com diversas caractersticas que
a tornam uma boa escolha para o desenvolvimento de software embarcado. Apesar de ser uma
linguagem de alto nvel, permite ao programador um acesso direto aos dispositivos de hardware.
1
2 Introduo
Figura 1.2: Pesquisa sobre linguagens utilizadas para projetos de software embarcado
Fonte: http://www.embedded.com/design/218600142
. Hardware utilizado
People who are really serious about software should make their own
hardware. - Alan Kay
Cada componente ter seu funcionamento bsico explicado para permitir o desenvolvimento de
rotinas para estes.
. Ambiente de programao
First, solve the problem. Then, write the code. - John Johnson
Instalao
A Tabela 1.1 apresenta os softwares que sero utilizados no curso.
name 18f4550
using 18f2455
name 18F4550
using 18f2455
Aps isto abrir a pasta onde foi instalado o MPLAB (por padro: C:\Arquivos de pro-
gramas\Microchip\MPLAB IDE). Abrir a pasta Core\MTC Suites. Abrir os arquivos sdc-
clink.mtc e gplink.mtc num editor de texto. Apagar o contedo do arquivo sdcclink.mtc.
Copiar todo contedo do arquivo gplink.mtc para o arquivo sdcclink.mtc. Salvar.
Aps o passo acima o arquivo sdcclink.mtc dever conter o seguinte texto:
Em seguida abrir o programa MPLAB e ir ao menu Projects -> Set Language Tool Locations.
Ser apresentada uma tela similar a da Figura 1.3.
Selecione a ferramenta Small Device C Compiler for PIC16 (SDCC16). Expanda a opo
Executables. A ferramenta gpasm e gplink so obtidas no diretrio bin dentro de onde
foi instalado o GPUtils, por padro: C:\Arquivos de programas\gputils\bin. A ferramenta
sdcc16 encontrada no diretrio bin dentro do diretrio onde foi instalado o SDCC com o
nome sdcc.exe, por padro: C:\Arquivos de programas\SDCC\bin\. Clicar em OK. Aps
estes passos a sute MPLAB est pronta para trabalhar com o compilador SDCC+GPUtils.
assinado digitalmente, certifique-se que a verso do firmware pelo menos 1.0.0.0 da fabricante
Microchip, conforme pode ser visto na Figura 1.4 e avance.
Aps o termino da instalao abra o programa MPLAB para configurar o gravador ou depu-
rador. V ao menu Programmer -> Select Programmer -> MPLAB ICD 2. V novamente ao
menu Programmer mas desta vez escolha a opo MPLAB ICD 2 Setup Wizard.
No wizard, escolha a comunicao como USB e depois diga que a placa possui alimentao
independente Target has own power supply. Deixe as outras opes na seleo padro. Antes
de clicar em concluir verifique ao final se o resumo se parece com o da Figura 1.5.
Na primeira vez que o computador se conectar ao ICD2 possvel que o MPLAB precise
atualizar o firmware do ICD2 conforme o aviso que pode ser visto na Figura 1.6.
Aps estes passos o projeto estar criado. Caso a lista de arquivos do projeto no esteja
visvel v ao menu View -> Project.
Para a criao de um novo arquivo v at o menu File -> New. Neste novo arquivo digite
alguma coisa e salve-o. Caso seja o arquivo que conter a funo principal (main) costume
salv-lo com o nome de main.c.
A cada novo arquivo criado necessrio inser-lo no projeto. Para isso deve-se clicar na pasta
correspondente ao tipo de arquivo que se deseja incluir e em seguida Add Files como pode ser
visualizado na Figura 1.7.
Alm dos arquivos criados pelo programador, existem trs arquivos que devem ser adicionados
ao projeto: um de linker e dois de bibliotecas.
1. Linker
2. Bibliotecas
// File: 18f4550.lkr
// Sample linker script for the PIC18F4550 processor
// Not intended for use with MPLAB C18. For C18 projects,
// use the linker scripts provided with that product.
LIBPATH .
Percebemos pelo linker acima que existem 256 bytes de memria eeprom, no voltil, que foi
denominada eedata. Para a memria RAM est reservado um total de 2 kbytes, divididos1 em 4
bancos de memria, sendo que o primeiro foi dividido em duas sees. Estes foram denominados
(acessram-gpr0), gpr1, gpr2, gpr32 .
Para o programa temos disponvel uma regio de 32 kbytes de memria flash, que vai da
posio 0x0000 at 0x7FFF. Este o mesmo endereo da memria RAM. No existe conflito,
pois estamos trabalhando, no caso do PIC, com uma arquitetura Harvard. Nesta existem dois
barramentos e duas memrias diferentes: uma para o programa, denominada CODEPAGE no
linker, e uma para os dados, denominada DATABANK. Notar que apesar da memria eeprom ser
utilizada para armazenamento no voltil de dados, ela est mapeada no barramento de cdigo.
Isto se deve a construo interna do microcontrolador.
Os dados apresentados no linker e descorridos anteriormente podem ser verificados e compa-
rados com outros modelos observando a Figura 1.8.
1
Uma das maiores dificuldades encontradas em se construir um compilador de linguagem C o gasto em termos
de recursos computacionais que dispendido para tratar estes quatro bancos como sequenciais. Na realidade eles
esto todos sobre um mesmo endereo de memria. Para acessar cada um deles necessrio atuar sobre um
registro no PIC, indicando qual banco estar ativo naquele momento.
2
gprX significa General Propouse Ram bank X
9
10 Linguagem C para sistemas embarcados
Podemos notar pelo cdigo anterior que aquele que possui indentao facilita na verificao
de quais instrues/rotinas esto subordinadas s demais.
Outra caracterstica de padronizao est na criao de nomes de funes e de variveis. Pela
linguagem C uma funo ou varivel pode ter qualquer nome desde que: seja iniciada por uma
letra, maiscula ou minscula, e os demais caracteres sejam letras, nmeros ou underscore _.
A linguagem C permite tambm que sejam declaradas duas variveis com mesmo nome caso
possuam letras diferentes apenas quanto caixa (maiscula ou minscula). Por exemplo: var e
vAr so variveis distintas, o que pode gerar erro no desenvolvimento do programa causando
dvidas e erros de digitao.
Por isso convenciona-se que os nomes de variveis sejam escritos apenas em minsculas.
Quando o nome composto, se utiliza uma maiscula para diferenci-los como, por exemplo, as
variveis contPos e contTotal.
Nomes de funo sero escritos com a primeira letra maiscula e no caso de nome composto,
cada inicial ser grafada em maisculo: InicializaTeclado(), ParaSistema().
Tags de definies (utilizados em conjunto com a diretiva #define) sero grafados exclusiva-
mente em maisculo: NUMERODEVOLTAS, CONSTGRAVITACIONAL.
Cada chave ser colocada numa nica linha, conforme exemplo anterior, evitando-se constru-
es do tipo:
Ou
i f ( PORTA == 0 x30 ) {
PORTB = 0 x10 ; }
As regras apresentadas visam fornecer uma identidade visual ao cdigo. Tais regras no so
absolutas, servem apenas para o contexto desta apostila. Em geral, cada instituio ou projeto
possui seu prprio conjunto de normas. importante ter conhecimento deste conjunto e aplic-lo
em seu cdigo.
O estilo adotado nesta apostila conhecido tambm como estilo Allman, bsd (no emacs)
ou ANSI, j que todos os documentos do padro ANSI C utilizam este estilo. Apesar disto o
padro ANSI C no especifica um estilo para ser usado.
. Comentrios
If the code and the comments disagree, then both are probably
wrong. - Norm Schryer
Comentrios so textos que introduzimos no meio do programa fonte com a inteno de torn-
lo mais claro. uma boa prtica em programao inserir comentrios no meio dos nossos
programas. Pode-se comentar apenas uma linha usando o smbolo // (duas barras). Para
comentar mais de uma linha usa-se o smbolo /* (barra e asterisco) antes do comentrio e */
(asterisco e barra) para indicar o final do comentrio.
. Arquivos .c e .h
Na programao em linguagem C utilizamos dois tipos de arquivos com funes distintas. Toda
implementao de cdigo feita no arquivo com extenso .c (code). nele que criamos as
funes, definimos as variveis e realizamos a programao do cdigo. Se existem dois arquivos
.c no projeto e queremos que um deles possa usar as funes do outro arquivo, necessrio
realizar um #include.
Os arquivos .h (header ) tem como funo ser um espelho dos arquivos .c disponibilizando
as funes de um arquivo .c para serem utilizadas em outros arquivos. Nele colocamos todos
os prottipos das funes que queremos que os outros arquivos usem.
Se quisermos que uma funo s possa ser utilizada dentro do prprio arquivo, por motivo
de segurana ou organizao, basta declarar seu prottipo APENAS no arquivo .c.
Se for necessrio que um arquivo leia e/ou grave numa varivel de outro arquivo recomen-
dado criar funes especficas para tal finalidade.
O programa 2.1 apresenta um exemplo de um arquivo de cdigo .c e o programa 2.2 apre-
senta o respectivo arquivo de header .h.
Podemos notar que no arquivo .h a funo AtualizaDisplay() no est presente, deste modo
ela no estar disponvel para os outros arquivos. Podemos notar tambm que para ler ou
gravar a varivel digito necessrio utilizar as funes MudarDigito() e LerDigito(). Notar que
no existe acesso direto s variveis. Este tipo de abordagem insere atrasos no processamento
devido um efeito conhecido como overhead de funes, podendo inclusive causar travamentos
no sistema caso no exista espao suficiente no stack.
. Diretivas de compilao
As diretivas de compilao so instrues que so dadas ao compilador. Elas no sero executa-
das. Todas as diretivas de compilao comeam com um sinal #, conhecido como jogo da velha
ou hash.
#include
A diretiva de compilao #include a responsvel por permitir que o programador utilize no seu
cdigo funes que foram implementadas em outros arquivos, seja por ele prprio ou por outras
pessoas. No necessrio possuir o cdigo fonte das funes que se deseja utilizar. necessrio
apenas de um arquivo que indique os prottipos das funes (como elas devem ser chamadas) e
possuir a funo disponvel em sua forma compilada.
Em geral um arquivo que possui apenas prottipos de funes denominado de Header e
possui a extenso .h.
#define
Outra diretiva muito conhecida a #define. Geralmente utilizada para definir uma constante,
mas pode ser utilizada para que o cdigo fonte seja modificado antes de ser compilado.
#define CONST 15
void main ( void )
void main ( void )
{
{ 45
printf ( "%d" , 15 3 ) ;
printf ( "%d" , CONST 3 ) ;
}
}
void MostraSaidaPadrao ( )
{
#include <s t d i o . h>
#ifdef PADRAO Serial
#define PADRAO S e r i a l
char msg = " SERIAL " ;
void main ( void )
#e l s e SERIAL
{
char msg = " LCD " ;
MostraSaidaPadrao ( ) ;
#endif
}
printf ( msg ) ;
}
Pelo cdigo apresentado percebemos que a mesma funo MostraSaidaPadrao(), apresenta re-
sultados diferentes dependendo de como foi definida a opo PADRAO.
Os defines tambm ajudam a facilitar a localizao dos dispositivos e ajustar as configuraes
no microcontrolador. Todo perifrico possui um ou mais endereos para os quais ele responde.
Estes endereos podem variar inclusive dentro de uma mesma famlia. Por exemplo: o endereo
da porta D (onde esto ligados os leds) 0xF83. Para ligar ou desligar um led preciso alterar
o valor que esta dentro do endereo 0xF83. Para facilitar este procedimento, definido um
ponteiro para este endereo e rotulado com o nome PORTD. Definir OFF como 0 e ON como 1
facilita a leitura do cdigo.
Toda vez que a funo LerTemperatura() for chamada, ela deve fazer um teste e se o valor for
maior que um patamar chamar a funo EnviaSerial() com o cdigo 0x30. Para isso o arquivo
temp.h deve incluir o arquivo serial.h.
Toda vez que a funo LerSerial() receber um valor, ela deve chamar a funo AjustaCalor()
e repassar esse valor. Para isso o arquivo serial.h deve incluir o arquivo temp.h
5 #endif //TAG_CONTROLE
O problema que deste modo criada uma referncia circular sem fim: o compilador l o
arquivo serial.h e percebe que tem que inserir o arquivo temp.h. Inserindo o arquivo temp.h
percebe que tem que inserir o arquivo serial.h, conforme pode ser visto na Figura 2.1.
temp.h
#include serial.h
char LerTemperatura(void);
void AjustaCalor(char val); serial.h
#include temp.h
char LerSerial(void);
void EnviaSerial(char val);
temp.h
#include serial.h
char LerTemperatura(void);
void AjustaCalor(char val);
A soluo criar um dispositivo que permita que o contedo do arquivo seja lido apenas uma
vez. Este dispositivo implementado atravs da estrutura apresentada no programa 2.3.
Segundo o cdigo acima, o contedo que estiver entre o #ifndef e o #endif, s ser mantido
se a a tag TAG_CONTROLE NO estiver definida. Como isto verdade durante a primeira
leitura, o pr-compilador l o arquivo normalmente. Se acontecer uma referncia cclica, na
segunda vez que o arquivo for lido, a tag TAG_CONTROLE j estar definida impedindo
assim que o processo cclico continue, conforme pode ser visto na Figura 2.2.
Geralmente se utiliza como tag de controle o nome do arquivo. Esta tag deve ser nica para
cada arquivo.
. Tipos de dados em C
19 Jan 2038 at 3:14:07 AM. The end of the world according to Unix
(232 seconds after Jan 1st 1970) - Unix date system
O tipo de uma varivel, informa a quantidade de memria, em bytes, que esta ir ocupar e como
esta deve ser interpretada: com ou sem frao (vrgula). Os tipos bsicos de dados na linguagem
temp.h
#infdef TEMP_H
#define TEMP_H
#include serial.h
char LerTemperatura(void);
void AjustaCalor(char val); serial.h
#endif
#infdef SERIAL_H
#define SERIAL_H
#include temp.h
//tag j definida,
//pula o contedo
#endif
Podemos notar que as variveis que possuem maior tamanho podem armazenar valores mai-
ores. Notamos tambm que apenas os tipos float e double possuem casas decimais.
5. Apresentar o resultado
negativos, em compensao podem atingir o dobro do valor de um tipo signed. Na Tabela 2.3
so apresentadas algumas variaes possveis.
Modificadores de acesso
Durante o processo de compilao, existe uma etapa de otimizao do programa. Durante esta
etapa, o compilador pode retirar partes do cdigo ou desfazer loops com perodos fixos. Por
exemplo o cdigo abaixo:
// S t a r t i n g pCode b l o c k
S_Teste__main code
_main :
. line 19 // T e s t e . c w h i l e (X!=X) ;
RETURN
// S t a r t i n g pCode b l o c k
S_Teste__main code
_main :
_00105_DS_ :
. line 19 // T e s t e . c w h i l e (X != X) ;
MOVLW 0 x83 // p r i m e i r a p a r t e do e n d e r e o
MOVWF r0x00
MOVLW 0 x0f // segunda p a r t e do e n d e r e o
MOVWF r0x01
MOVFF r0x00 , FSR0L
MOVFF r0x01 , FSR0H
MOVFF INDF0 , r0x00 // r e a l i z a p r i m e i r a l e i t u r a
MOVLW 0 x83 // p r i m e i r a p a r t e do e n d e r e o
MOVWF r0x01
MOVLW 0 x0f // segunda p a r t e do e n d e r e o
MOVWF r0x02
MOVFF r0x01 , FSR0L
MOVFF r0x02 , FSR0H
MOVFF INDF0 , r0x01 // r e a l i z a segunda l e i t u r a
MOVF r0x00 , W
XORWF r0x01 , W
BNZ _00105_DS_ // f a z o t e s t e para i g u a l d a d e
RETURN
Podemos perceber que, deste modo, o compilador forado a ler a varivel x duas vezes e realizar
o teste para ver se ela permanece com o mesmo valor.
Em algumas situaes necessrio indicar que algumas variveis no podem receber valores
pelo programa. Para isto utilizamos a palavra reservada const. Utilizamos este modificador
para indicar que a varivel representa um local que apenas pode ser lido e no modificado, por
exemplo uma porta para entrada de dados. Nesta situao comum utilizar as palavras volatile
e const junto.
Modificadores de posicionamento
As variveis podem ser declaradas utilizando os modificadores near e far. Estes modificadores
indicam ao compilador em qual regio de memria devem ser colocadas as variveis.
A regio near geralmente se refere zero page. uma regio mais fcil de ser acessada. A
regio far exige mais tempo para executar a mesma funo que a near.
Podemos pensar nestas regies como a memria RAM e a memria Cache do computador.
A segunda mais rpida, mas possui um alto custo e por isso geralmente menor. Em algumas
situaes interessante que algumas variveis nunca saiam do cache, pois so utilizadas com
grande frequncia ou so crticas para o sistema.
Modificador de persistncia
Em geral, as variveis utilizadas dentro das funes perdem seu valor ao trmino da funo. Para
que este valor no se perca podemos utilizar um modificador de persistncia: static. Com esse
modificador a varivel passa a possuir um endereo fixo de memria dado pelo compilador. Alm
disso o compilador no reutiliza este endereo em nenhuma outra parte do cdigo, garantindo
que na prxima vez que a funo for chamada o valor continue o mesmo.
// c r i a um c o n t a d o r p e r s i s t e n t e que
// i n c r e m e n t a d o a cada chamada de f u n o
i n t ContadorPersistente ( i n t reseta )
{
s t a t i c char variavel_persistente ;
i f ( reseta )
{
variavel_persistente = 0 ;
}
else
{
return ( variavel_persistente++) ;
}
return 1;
}
. Operaes aritmticas
If people do not believe that mathematics is simple, it is only be-
cause they do not realize how complicated life is. - John Louis von
Neumann
Um cuidado a se tomar, na programao em C para sistemas embarcados, o resultado de
operaes aritmticas. Por padro na linguagem C o resultado de uma operao aritmtica
possui tamanho igual ao maior operando. Observando o Programa 2.4 notamos alguns exemplos.
No caso 1 (linha 8) uma varivel char somada a um int gera como resultado um int (maior
operando). No possvel armazenar esse resultado num char, haver perda de informao.
A soma de dois char, conforme a linha 9, segundo caso pode gerar um problema se ambos
forem muito prximo do valor limite. Por exemplo: 100 + 100 = 200, que no cabe num char,
j que este s permite armazenar valores de -128 127.
O terceiro caso (linha 10) est correto, a multiplicao de dois char possui um valor mximo
de 127*127=16.129. O problema que a multiplicao de dois char gera um outro char, perdendo
informao. necessrio realizar um typecast antes.
O quarto caso (linha 11) pode apresentar um problema de preciso. A diviso de dois inteiros
no armazena parte fracionria. Se isto no for crtico para o sistema est correto. Lembrar que
a diviso de nmeros inteiros mais rpida que de nmeros fracionrios.
O quinto caso (linha 12) pode apresentar um problema de preciso. O resultado da conta de
um nmero inteiro com um ponto flutuante um ponto flutuante. Armazenar esse valor num
outro nmero inteiro gera perda de informao.
O sexto caso (linha 13) apresenta um problema muito comum. A diviso de dois nmeros
inteiros gera um outro nmero inteiro. No importa se armazenaremos o valor numa varivel
de ponto flutuante haver perda de informao pois os operandos so inteiros. Para evitar esse
problema necessrio um typecast.
No stimo caso (linha 14) pode haver perda de preciso pois o resultado da operao um
double, e estamos armazenando este valor num float.
O oitavo caso (linha 15) similar ao sexto. Estamos realizando uma conta com dois nmeros
inteiros esperando que o resultado seja 0,5. Como os operandos so inteiros a expresso ser
avaliada como resultante em Zero. Uma boa prtica sempre usar .0 ou f aps o nmero
para indicar operaes com vrgula.
pont16 = 40 f / 8 0 . 0 ; // 8 c o r r i g i d o
Devemos tomar cuidado tambm com comparaes envolvendo nmeros com ponto flutuante.
float x = 0 . 1 ;
while ( x != 1 . 1 ) {
printf ( "x = %f\n" , x ) ;
x = x + 0.1;
}
O trecho de cdigo acima apresenta um loop infinito. Como existem restries de preciso nos
nmeros de ponto flutuante (float e double) nem todos os nmeros so representados fielmente.
Os erros de arredondamento podem fazer com que a condio (x !=1.1) nunca seja satisfeita.
Sempre que houver a necessidade de comparao com nmeros de ponto flutuante utilizar maior,
menor ou variaes.
float x = 0 . 1 ;
while ( x < 1 . 1 ) {
printf ( "x = %f\n" , x ) ;
x = x + 0.1;
}
Apesar de sutis estes tipos de erro podem causar um mau funcionamento do sistema. Na
Figura 2.3 apresentado um erro gerado atravs de um loop infinito.
. Funo main()
Todo sistema necessita de iniciar em algum lugar. Em geral, os microcontroladores, assim que
ligados, procuram por suas instrues no primeiro ou ltimo endereo de memria, dependendo
da arquitetura utilizada. O espao de memria disponvel neste endereo geralmente muito
pequeno, apenas o necessrio para inserir uma instruo de pulo e o endereo onde est a funo
principal. Este espao conhecido como posio de reset. Existem ainda outros espaos de
memria similares a este que, geralmente, so alocados prximos. O conjunto destes espaos
conhecido como vetor de interrupo (Figura 2.4).
Endereo Instruo
0x00 Pulo
0x01 0x8A
0x02 Pulo
0x03 0x55
0x04 ...
0x55 Limpa A
0x56 A recebe
0x57 30
0x58 Testa A
0x59 ...
0x8A A recebe
0x8B 50
0x8C Salva em
0x8D Porta B
0x8E ...
compiladores alocam a funo main() em algum lugar da memria onde haja espao disponvel.
Depois disso dispem de uma instruo de pulo para o primeiro endereo de memria, onde foi
alocada a funo main.
Para o compilador SDCC/GPUtils no MPLAB necessrio indicar que queremos que a funo
main() seja chamada toda vez que o sistema for iniciado. Por isso necessrio que a posio de
reset dentro do vetor de interrupo aponte para a funo main. Isto feito atravs do atributo
interrupt 0 logo aps o nome da funo conforme pode ser visto no cdigo abaixo.
Outra coisa interessante que para sistemas embarcados a funo principal no recebe nem
retorna nada. Como ela a primeira a ser chamada no h como enviar algum valor por par-
metro. Ela tambm no retorna nada pois ao trmino desta o sistema no est mais operativo.
Em geral sistemas embarcados so projetados para comearem a funcionar assim que ligados e
apenas parar sua tarefa quando desligados. Como todas as funcionalidades so chamadas dentro
da funo main()1 espera-se que o programa continue executando as instrues dentro dela at
ser desligado ou receber um comando para desligar. Este comportamento pode ser obtido atravs
de um loop infinito. Abaixo esto as duas alternativas mais utilizadas.
. Rotinas de tempo
Time is an illusion, lunchtime doubly so. - Ford Prefect
muito comum necessitar que o microcontrolador fique um tempo sem fazer nada. Uma maneira
de atingir esse objetivo utilizar um lao FOR 2 .
unsigned char i ;
f o r ( i =0; i < 1 0 ; i++) ;
Notar que no estamos utilizando os colchetes. Logo aps fechar os parnteses j existe um
ponto e virgula. Para entender como esse procedimento funciona, e estimar o tempo de espera
preciso entender como o compilador traduz essa funo para assembler.
Percebemos pelo cdigo acima que para realizar um for precisamos de 3 passos de inicializao.
Cada iterao exige 2 passos: uma comparao e um pulo 3 , totalizando 3 ciclos de inicializao
e 3 ciclos de interao.
Se temos um processador trabalhando a 8 MHz, cada instruo executada em 0.5s.4 Para
termos um tempo de espera de 0.5s precisamos de 1 milho de instrues. Se colocarmos loops
encadeados podemos multiplicar a quantidade de instrues que sero executadas. Para obtermos
um valor de 1 milho de instrues devemos utilizar pelo menos 3 loops encadeados. Os valores
dos loops so obtidos de maneira iterativa.
unsigned char i , j , k ;
f o r ( i =0; i < 3 4 ; i++) // 3 + 34 ( 3 0 . 0 0 3 + 3) = 1 . 0 2 0 . 2 0 7 i n s t r u e s
{
f o r ( j =0; j < 1 0 0 ; j++) // 3 + 100 (297 + 3) = 3 0 . 0 0 3 i n s t r u e s
{
f o r ( k =0; k < 9 8 ; k++) ; // 3 + 98 ( 3 ) = 297 i n s t r u e s
}
}
O cdigo acima foi projetado para gerar um atraso de tempo de meio segundo. Compilando
e realizando testes prticos podemos confirmar que o tempo real aproximadamente 0.51 (s).
Esta discrepncia acontece porque agora temos 3 loops encadeados e cada qual com sua varivel
de controle. Deste modo o compilador precisa salvar e carregar cada varivel para realizar a
comparao.
Percebemos assim que para conhecer corretamente o funcionamento do sistema necessrio,
em algumas situaes, abrir o cdigo em assembler gerado pelo compilador para entender como
este executado. Nem sempre o compilador toma as mesmas decises que ns. Alm disso ele
pode gerar otimizaes no cdigo. Existem dois tipos de otimizao: uma visando diminuir o
tempo de execuo do sistema, deixando-o mais rpido e outra que reduz o tamanho do cdigo
final, poupando espao na memria.
A seguir apresentamos um exemplo de funo que gera delays com tempo parametrizado.
Nos sistemas microcontrolados, existem algumas variveis onde cada bit tem uma interpretao
ou funcionalidade diferente. Por isso necessrio realizar algumas operaes que modifiquem
apenas os bits desejados, mantendo o restante dos bits da varivel inalterados.
As operaes da linguagem C que nos permitem trabalhar com as variveis, levando em conta
os valores individuais de cada bit, so chamadas de bitwise operation.
importante ressaltar que as operaes de bitwise possuem funcionalidade semelhante a suas
respectivas operaes lgicas. A diferena que a lgica opera em cima da varivel como um
todo5 enquanto a bitwise opera bit bit.
NOT
A operao NOT lgica retorna um se o valor for zero e 0 se o valor for um.
A !A
0 1
1 0
A operao bitwise NOT (operador ) executa uma NOT lgica. Isso significa que a operao
realizada para cada um dos bits da varivel, no mais para a varivel como um todo. Na tabela
seguinte apresentada a diferena entre as duas operaes.
result = ~A ;
char A = 1 2 ; result = ! A ; // r e s u l t = 243
// A = 0 b00001100 // r e s u l t = 0 // A = 0 b00001100
// r = 0 b11110011
AND
A operao AND lgica (operador &&) retorna 0 se algum dos valores for zero, e 1 se os dois
valores forem diferentes de zero.
A B A&&B
0 0 0
0 1 0
1 0 0
1 1 1
A operao bitwise AND (operador &) executa uma AND lgica para cada par de bits e coloca
o resultado na posio correspondente:
result = A & B ;
char A = 8;
// r e s u l t = 0
// A = 0 b00001000 result = A && B ;
// A = 0 b00001000
char B = 5; // r e s u l t = 1
// B = 0 b00000101
// B = 0 b00000101
// r = 0 b00000000
Lembrar que para linguagem C uma varivel com valor 0 (zero) representa falso, e qualquer outro valor
5
representa verdadeiro.
OR
A operao OR lgica (operador ||) retorna 1 se algum dos valores for diferente de zero, e 0 se
os dois valores forem zero.
A B A||B
0 0 0
0 1 1
1 0 1
1 1 1
A operao bitwise OR (operador |) executa uma OR lgica para cada par de bits e coloca o
resultado na posio correspondente:
result = A | B ;
char A = 8;
// r e s u l t = 13
// A = 0 b00001000 result = A | | B ;
// A = 0 b00001000
char B = 5; // r e s u l t = 1
// B = 0 b00000101
// B = 0 b00000101
// r = 0 b00001101
XOR
A operao XOR no possui correspondente lgica na linguagem C. Esta operao pode ser
representada como A XOR B = (A && !B)||(!A && B)
A B AB
0 0 0
0 1 1
1 0 1
1 1 0
A operao bitwise XOR (operador ) executa uma XOR lgica para cada par de bits e coloca
o resultado na posio correspondente:
Shift
A operao shift desloca os bits para a esquerda (operador <<) ou direita (operador >>).
necessrio indicar quantas casas sero deslocadas.
Para variveis unsigned e inteiras, esta operao funciona como a multiplicao/diviso por
potncia de dois. Cada shift multiplica/divide por 2 o valor. Esta uma prtica muito comum
para evitar a diviso que na maioria dos sistemas embarcados uma operao cara do ponto de
vista de tempo de processamento.
No utilizar esta operao com o intuito de multiplicar/dividir variveis com ponto fixo ou
flutuante nem variveis sinalizadas (signed).
Em diversas ocasies necessrio que trabalhemos com os bits de maneira individual, prin-
cipalmente quando estes bits representam sadas ou entradas digitais, por exemplo chaves ou
leds.
Supondo que temos 8 leds ligados ao microcontrolador. Cada led representado atravs de 1
bit de uma varivel. Para ligarmos ou desligarmos apenas um led por vez, no alterando o valor
dos demais, devemos nos utilizar de alguns passos de lgebra digital.
Se a operao OR for executada com a mscara criada, o resultado apresentar valor 1 na posio
X e manter os valores antigos para as demais posies. Exemplo: Ligar apenas o bit 2 da varivel
PORTD
// d e f i n e ' s para p o r t a s de e n t r a d a e s a d a
#define PORTD ( ( v o l a t i l e n e a r unsigned char ) 0xF83 )
#define TRISD ( ( v o l a t i l e n e a r unsigned char ) 0xF95 )
// i n i c i o do programa
void main ( void ) interrupt 0
{
char mascara ; // v a r i v e l que guarda a mscara
TRISD = 0 x00 ; // c o n f i g u r a a p o r t a D como s a d a
PORTD = 0 x00 ; // l i g a t o d o s os l e d s ( l g i c a n e g a t i v a )
// l i g a o p r i m e i r o b i t da v a r i v e l
mascara = 1 ; // b i t = 0 b00000001
// r o t a c i o n a s e a v a r i v e l para que o b i t 1 c h e g u e na p o s i o d e s e j a d a
mascara = mascara << 2 ; // b i t = 0 b00000100
// L i g a r o b i t 2 , d e s l i g a n d o o 3o l e d
PORTD = PORTD | mascara ;
//mantm o s i s t e m a l i g a d o i n d e f i n i d a m e n t e
for ( ; ; ) ;
}
Se a operao AND for executada com a mscara criada, o resultado apresentar valor 0 na
posio X e manter os valores antigos para as demais posies. Exemplo: Desligar apenas o bit
2 da varivel PORTD.
// d e f i n e ' s para p o r t a s de e n t r a d a e s a d a
#define PORTD ( ( v o l a t i l e n e a r unsigned char ) 0xF83 )
#define TRISD ( ( v o l a t i l e n e a r unsigned char ) 0xF95 )
// i n i c i o do programa
void main ( void ) interrupt 0
{
char mascara ; // v a r i v e l que guarda a mscara
TRISD = 0 x00 ; // c o n f i g u r a a p o r t a D como s a d a
PORTD = 0 xFF ; // d e s l i g a t o d o s os l e d s ( l g i c a n e g a t i v a )
// l i g a o p r i m e i r o b i t da v a r i v e l
mascara = 1 ; // mascara = 0 b00000001
// r o t a c i o n a s e a v a r i v e l para que o b i t 1 c h e g u e na p o s i o d e s e j a d a
mascara = mascara << 2 ; // mascara = 0 b00000100
// i n v e r t e s e os v a l o r e s de cada b i t
mascara = ~mascara ; // mascara = 0 b11111011
// D e s l i g a o b i t 2 , l i g a n d o o 3o l e d
PORTD = PORTD & mascara ;
//mantm o s i s t e m a l i g a d o i n d e f i n i d a m e n t e
for ( ; ; ) ;
}
importante notar que geramos a mscara de maneira idntica quela utilizada no caso
anterior, onde todos os valores so zero e apenas o desejado um. Depois realizamos a inverso
dos valores. Este procedimento realizado desta maneira porque no sabemos o tamanho da
palavra a ser utilizada no microcontrolador: 8 ou 16 bits. Mesmo assim devemos garantir que
todos os bits obtenham o valor correto, o que garantido pela operao de negao. A opo de
inicializar a varivel com apenas um zero e rotacionar pode no funcionar pois, na maioria dos
sistemas, a funo de rotao insere zeros medida que os bits so deslocados e precisamos que
apenas um valor seja zero.
Se a operao XOR for executada com a mscara criada, o valor na posio X ser trocado, de
zero para um ou de um para zero. Exemplo: Trocar o bit 2 e 6 da varivel PORTD
// d e f i n e ' s para p o r t a s de e n t r a d a e s a d a
#define PORTD ( ( v o l a t i l e n e a r unsigned char ) 0xF83 )
#define TRISD ( ( v o l a t i l e n e a r unsigned char ) 0xF95 )
// i n i c i o do programa
void main ( void ) interrupt 0
{
char mascara ; // v a r i v e l que guarda a mascara
TRISD = 0 x00 ; // c o n f i g u r a a p o r t a D como s a d a
PORTD = 0 xF0 ; // d e s l i g a t o d o s os 4 p r i m e i r o s l e d s ( l g i c a n e g a t i v a )
// l i g a o p r i m e i r o b i t da v a r i v e l
mascara = 1 ; // mascara = 0 b00000001
// r o t a c i o n a s e a v a r i v e l para que o b i t 1 c h e g u e na p o s i o d e s e j a d a
mascara = mascara << 2 ; // mascara = 0 b00000100
// L i g a o b i t 2 , d e s l i g a n d o o 3o l e d
PORTD = PORTD ^ mascara ;
// l i g a o p r i m e i r o b i t da v a r i v e l
mascara = 1 ; // mascara = 0 b00000001
// r o t a c i o n a s e a v a r i v e l para que o b i t 1 c h e g u e na p o s i o d e s e j a d a
mascara = mascara << 6 ; // mascara = 0 b01000000
// D e s l i g a o b i t 6 , l i g a n d o o 7o l e d
PORTD = PORTD ^ mascara ;
//mantm o s i s t e m a l i g a d o i n d e f i n i d a m e n t e
for ( ; ; ) ;
}
Realizamos ento uma operao AND com a varivel. O resultado ser zero se o bit X, da
varivel original, for zero. Se o bit da varivel original for um a resposta ser diferente de zero6 .
Exemplo: Testar o bit 2 da varivel PORTD
// d e f i n e ' s para p o r t a s de e n t r a d a e s a d a
#define PORTD ( ( v o l a t i l e n e a r unsigned char ) 0xF83 )
#define TRISD ( ( v o l a t i l e n e a r unsigned char ) 0xF95 )
// i n i c i o do programa
void main ( void ) interrupt 0
{
char mascara ; // v a r i v e l que guarda a mascara
char teste ;
TRISD = 0 x00 ; // c o n f i g u r a a p o r t a D como s a d a
teste = 0 x00 ; // d e s l i g a t o d o s os b i t s
// r o d a r d e p o i s o mesmo programa com os b i t s l i g a d o s .
// t e s t e = 0 x f f ;
// c r i a uma v a r i v e l onde APENAS o p r i m e i r o b i t 1
mascara = 1 ; // mascara = 0 b00000001
// r o t a c i o n a s e a v a r i v e l para que o b i t 1 c h e g u e na p o s i o d e s e j a d a
mascara = mascara << 2 ; // mascara = 0 b00000100
// V e r i f i c a apenas o b i t 2
i f ( teste & mascara )
{
PORTD = 0 x00 ; // s e o r e s u l t a d o f o r v e r d a d e i r o l i g a t o d o s os l e d s
6
A maioria dos compiladores C adotam uma varivel com valor diferente de zero como sendo verdadeiro.
}
else
{
PORTD = 0 xff ; // s e o r e s u l t a d o f o r f a l s o d e s l i g a t o d o s os l e d s
}
//mantm o s i s t e m a l i g a d o i n d e f i n i d a m e n t e
for ( ; ; ) ;
}
char bit = 2 ;
char mascara ;
mascara = 1 << bit ;
arg = arg | mascara ;
Passo a Passo //em 1 l i n h a
arg = arg | (1<<bit ) ;
// ou
arg |= (1<<bit ) ;
// Ligando o b i t 2 da p o r t a D
PORTD = PORTD | (1<<2) ;
Exemplo de uso // ou
PORTD |= (1<<2) ;
char bit = 2 ;
char mascara ;
mascara = 1 << bit ;
arg = arg & ~mascara ;
Passo a Passo //em 1 l i n h a
arg = arg & ~(1<<bit ) ;
// ou
arg &= ~(1<<bit ) ;
// D e s l i g a n d o o b i t 2 da p o r t a D
PORTD = PORTD & ~(1<<2) ;
Exemplo de uso // ou
PORTD &= ~(1<<2) ;
char bit = 2 ;
char mascara ;
mascara = 1 << bit ;
arg = arg ^ mascara ;
Passo a Passo //em 1 l i n h a
arg = arg ^ (1<<bit ) ;
// ou
arg ^= (1<<bit ) ;
// Trocando o v a l o r do b i t 2 da p o r t a D
PORTD = PORTD ^ (1<<2) ;
Exemplo de uso // ou
PORTD ^= (1<<2) ;
char bit = 2 ;
char mascara ;
mascara = 1 << bit ;
Passo a Passo i f ( arg & mascara )
//em 1 l i n h a
i f ( arg & (1<<bit ) )
// Testando o b i t 2 da p o r t a D
i f ( PORTD | (1<<2) )
Exemplo de uso {
// . . .
}
// Testando o b i t 2 da p o r t a D
i f ( BitTst ( PORTD , 2 ) )
Exemplo de uso com de- {
fine // . . .
}
Externalizar as informaes.
A primeira necessidade conhecer o que est acontecendo em teu sistema. Na programao
tradicional para desktop comum utilizarmos de mensagens no console avisando o estado do
programa.
Devemos ter em mente onde necessrio colocar estes alertas e lembrar de retir-los do cdigo
final.
Para a placa em questo utilizaremos o barramento de leds que est ligado porta D. A ope-
rao deste dispositivo ser estudada posteriormente em detalhes. Por enquanto basta sabermos
que cada bit da varivel PORTD est ligada um led diferente. Por causa da construo fsica
da placa, o led aceso com valor 0 (zero) e desligado com o valor 1 (um). Alm disso temos que
configurar a porta D. Isto feito iniciando a varivel TRISD com o valor 0x008 .
// d e f i n e ' s para p o r t a s de e n t r a d a e s a d a
#define PORTD ( ( v o l a t i l e n e a r unsigned char ) 0xF83 )
#define TRISD ( ( v o l a t i l e n e a r unsigned char ) 0xF95 )
// i n i c i o do programa
void main ( void ) interrupt 0
{
// c o n f i g u r a n d o t o d o s os p i n o s como s a d a s
TRISD = 0 x00 ;
PORTD = 0 xFF ; // d e s l i g a t o d o s os l e d s
// l i g a apenas o b i t 1 .
BitClr ( PORTD , 1 ) ;
//mantm o s i s t e m a l i g a d o i n d e f i n i d a m e n t e
for ( ; ; ) ;
Mais informaes sobre debug de sistemas embarcados referir ao artigo The ten secrets of embedded debug-
7
Devemos utilizar os leds como sinais de aviso para entendermos o funcionamento do programa.
Isto pode ser feito atravs das seguintes ideias: Se passar desta parte liga o led X, Se entrar
no IF liga o led Y, se no entrar liga o led Z, Assim que sair do loop liga o led W.
Programao incremental
Ao invs de escrever todo o cdigo e tentar compilar, interessante realizar testes incrementais.
A cada alterao no cdigo realizar um novo teste. Evitar alterar o cdigo em muitos lugares
simultaneamente, no caso de aparecer um erro fica mais difcil saber onde ele est.
Otimizao de cdigo
Apenas se preocupe com otimizao se estiver tendo problemas com o cumprimento de tarefas.
Mesmo assim considere em migrar para uma plataforma mais poderosa. Sistemas embarcados
preconizam segurana e no velocidade.
Caso seja necessrio otimizar o cdigo analise antes o local de realizar a otimizao. No
adianta otimizar uma funo grande se ela chamada apenas uma vez. Utilize-se de ferramentas
do tipo profiler sempre que possvel. Isto evita a perda de tempo e auxilia o programador a
visualizar a real necessidade de otimizao de cdigo.
// a q u i tem um monte de c d i g o . . .
i f ( PORTB >= 5 ) //PORTB no d e v e r i a s e r um v a l o r maior que 5 .
{
BitClr ( PORTD , 3 ) ; // l i g a o l e d 3
for ( ; ; ) ; // t r a v a o programa
}
// a q u i c o n t i n u a com um monte de c d i g o . . .
// c r i a a v a r i v e l a num e n d e r e o de memria a s e r
// d e c i d i d o p e l o c o m p i l a d o r
int a = 0 ;
a = a + 1;
printf ( a ) ; // imprime o v a l o r 1
printf ( &a ) ; // imprime o e n d e r e o de a ( por exemplo 157821)
Conhecer o endereo de uma varivel muito til quando queremos criar um ponteiro para
ela.
Ponteiro uma varivel que, ao invs de armazenar valores, armazena endereos de memria.
Atravs do ponteiro possvel manipular o que est dentro do lugar apontado por ele.
Para definir um ponteiro tambm precisamos indicar ao compilador um tipo. A diferena
que o tipo indica quanto cabe no local apontado pelo ponteiro e no o prprio ponteiro.
Sintaxe:
Exemplo:
i n t apint ;
f l o a t apfloat ;
Deve-se tomar cuidado, pois nos exemplos acima, apint e apfloat so variveis que armazenam
endereos de memria e no valores tipo int ou float. O lugar APONTADO pela varivel apint
que armazena um inteiro, do mesmo modo que o lugar apontado por float armazena um valor
fracionrio.
Se quisermos manipular o valor do endereo utilizaremos apint e apfloat mas se quisermos
manipular o valor que esta dentro deste endereo devemos usar um asterisco antes do nome da
varivel. Exemplo:
apfloat = 3 . 2 ;
apfloat = 3 . 2 ;
A primeira instruo indica ao compilador que queremos que o ponteiro apfloat aponte para
o endereo de memria nmero 3.2, que no existe, gerando um erro. Se quisermos guardar o
valor 3.2 no endereo de memria apontado por apfloat devemos utilizar a segunda expresso.
Para trabalhar com ponteiros preciso muito cuidado. Ao ser definido, um ponteiro tem
como contedo no um endereo, mas algo indefinido. Se tentamos usar o ponteiro assim mesmo,
corremos o risco de que o contedo do ponteiro seja interpretado como o endereo de algum local
da memria vital para outro programa ou at mesmo para o funcionamento da mquina. Neste
caso podemos provocar danos no programa, nos dados, ou mesmo travar a mquina.
necessrio tomar cuidado ao inicializar os ponteiros. O valor atribudo a eles deve ser
realmente um endereo disponvel na memria.
Por exemplo, podemos criar um ponteiro que aponta para o endereo de uma varivel j
definida:
// d e f i n i n d o a v a r i v e l i v a r
i n t ivar ;
// d e f i n i n d o o p o n t e i r o i p t r
i n t iptr ;
// o p o n t e i r o i p t r r e c e b e o v a l o r do e n d e r e o da v a r i v e l i v a r
iptr = &ivar ;
// as prximas l i n h a s so e q u i v a l e n t e s
ivar = 4 2 1 ;
iptr = 4 2 1 ;
Com sistemas embarcados existem alguns endereos de memria que possuem caractersticas
especiais. Estes endereos possuem registros de configurao, interfaces com o meio externo e
variveis importantes para o projetista. pelo meio da utilizao de ponteiros que possvel
acessar tais endereos de maneira simples, atravs da linguagem C.
Arquitetura de microcontroladores
38
39 Arquitetura de microcontroladores
. Acesso memria
A quantidade de memria disponvel que um microcontrolador pode acessar depende de dois
fatores, os tamanhos das palavras de dados e das palavras de endereo.
O tamanho da palavra de dados representa quantos bits podem ser colocados numa nica
posio da memria.
O tamanho da palavra de endereo indica quantas posies de memria o processador con-
segue enxergar.
Por exemplo, um microcontrolador cujo tamanho de dados e o tamanho da palavra de ende-
reo so ambos 8 bits possui uma possibilidade de acessar uma memria de at:
tamanho_da_palavra 2^ tamanho_do_endereco
8 2^8 = 2048 bytes ou 2 kbytes
O termo possibilidade foi usado pois, apesar de poder alcanar toda essa extenso, nem
sempre existe memria fsica para armazenamento. Podemos imaginar a memria como um
armrio. Um armrio com 6 suportes pode abrigar at 6 gavetas. Depende do marceneiro fabricar
e colocar as gavetas neste armrio. Podemos at indicar a posio onde queremos guardar algum
objeto, mas se a gaveta no foi colocada no possvel armazenar nada (Figura 3.2).
Suporte Existe
nmero: gaveta?
1 sim
2 sim
3 no
4 no
5 sim
6 no
Suporte Existe
nmero: gaveta?
1 Vitrine
2 Gaveta
3 Dispenser
4 No
5 Gaveta
6 Cofre
Stack 1 0x000
GPR1
... 0x0FF
Stack 31 0x100
GPR2
0x1FF
Interrupo
GPR3
Baixa prioridade 0x0008 0x2FF
Alta prioridade 0x0018 0x300
GPR4
0x3FF
0x0028
Memria EEPROM
0x7FFF
No implementado ...
0X8000
No implementado 0xF60
0X1FFFFF SFR
0xFFF
A = 1 . 2 3 4 5 6 x 10 ^ 5
B = 3 . 4 5 6 7 x 10 ^ 4
C = A x B
A = 123456; //C = 4 . 2 6 7 5 0 3 5 5 2 x 10 ^9
B = 34567;
C = A x B; // 1 . C o n v e r t e r para o mesmo e x p o e n t e
//C = 4267503552 // 1 2 . 3 4 5 6 x 10 ^ 4
// 3 . 4 5 6 7 x 10 ^ 4
// 1 . M u l t i p l i c a r os nmeros // 2 . M u l t i p l i c a r os nmeros
// 123456 // e somar a m a n t i s s a
// 34567 // 1 2 . 3 4 5 6 x 10 ^ 4
// 4267503552 // x 3 . 4 5 6 7 x 10 ^ 4
// 4 2 . 6 7 5 0 3 5 5 2 x 10 ^ 8
// 3 . C o r r i g i r q u a n t i d a d e de c a s a s dec .
// 4 . 2 6 7 5 0 3 5 5 2 x 10 ^ 9
Conhecer quanto tempo o cdigo leva para ser executado permite ao desenvolvedor saber de
maneira determinstica qual a exigncia a nvel de hardware para o sistema embarcado.
Por exemplo: Um sistema precisa executar 200 operaes a cada milsimo de segundo. Cada
operao possu uma quantidade diferente de tarefas conforme podemos ver na Tabela 3.1.
O total de tarefas a serem realizadas de 341 tarefas por milissegundo. Isso d uma quanti-
dade de 341 mil tarefas por segundo. Se cada tarefa realizada em um ciclo de clock precisamos
de um microcontrolador cujo processador trabalhe no mnimo em 341 kHz.
Nmeros fracionrios podem ser armazenados de dois modos no ambiente digital. O modo mais comum o
1
Para funcionarem, todos os microcontroladores devem ser alimentados com tenso contnua.
O valor varia de modelo para modelo. Alguns podem at mesmo aceitar diversos valores. O PIC
18F4550 por exemplo pode ser alimentado com qualquer tenso contnua entre 2 e 5,5 volts.
Para gerar o clock necessrio, que definir a velocidade na qual o processador ira trabalhar,
em geral utilizado um oscilador a cristal, que possui uma tima preciso.
Alguns microcontroladores podem dispensar o cristal externo optando por utilizar uma malha
RC interna ao chip. Esta alternativa muito menos precisa e geralmente no permite valores
muito altos de clock. A vantagem que sistemas que utilizam malha RC interna como osciladores
primrios possuem um custo menor que sistemas que dependem de malhas de oscilao externa,
seja ela excitada por outra malha RC ou por um cristal.
Existem alguns circuitos que no so essenciais para o funcionamento do sistema, mas auxi-
liam muito no desenvolvimento. Entre estes tipos de circuito o mais importante o que permite
a gravao do programa no prprio circuito. Alguns microcontroladores exigem que o chip seja
retirado do circuito e colocado numa placa especial para grav-lo e somente depois recolocado
na placa para teste. Este um procedimento muito trabalhoso e, devido ao desgaste mecnico
inerente, reduz a vida til do chip.
Para evitar estes problemas, os fabricantes desenvolveram estruturas no chip que permitem
que este seja gravado mesmo estando soldado placa final. Para isso, basta que o desenvolvedor
disponibilize o contato de alguns pinos com um conector. Este conector ser ligado um gra-
vador que facilitar o trabalho de gravao do programa. Para a famlia PIC esta tecnologia
denominada ICSP (in circuit serial programming).
A escolha de qual funcionalidade ser utilizada depende do projetista. Em sistemas mais avan-
ados possvel inclusive utilizar mais de uma funcionalidade no mesmo terminal em perodos
alternados, desde que o circuito seja projetado levando esta opo em considerao.
Dos registros apresentados na Figura 3.6, quatro precisam necessariamente ser configurados
para que o sistema possa funcionar. Dois deles tem relao com a configurao do sistema de
clock: um especifica qual a fonte do sinal de clock, que no caso da placa em questo um
cristal externo, e o outro indica qual o prescaler a ser usado (PLL).
Alm de configurar a frequncia bsica do clock necessrio desligar o watchdog. Este
um circuito para aumentar a segurana do sistema embarcado desenvolvido. Para funcionar
corretamente, o programa deve ser preparado para tal finalidade. Ele ser explicado em detalhes
na seo . e por isso ser mantido desligado nos prximos exemplos.
A ultima configurao necessria desabilitar a programao em baixa tenso. Devido s
ligaes feitas na placa, deixar esta opo ligada impede o funcionamento da placa enquanto
estiver ligada ao gravador. Abaixo o trecho de cdigo que realiza estas configuraes para o
compilador SDCC.
// P l l d e s l i g a d o
code char at 0 x300000 CONFIG1L = 0 x01 ;
// O s c i l a d o r c / c r i s t a l e x t e r n o HS
code char at 0 x300001 CONFIG1H = 0 x0C ;
// Watchdog c o n t r o l a d o por s o f t w a r e
code char at 0 x300003 CONFIG2H = 0 x00 ;
// Sem programao em b a i x a t e n s o
code char at 0 x300006 CONFIG4L = 0 x00 ;
// O s c i l a d o r c / c r i s t a l e x t e r n o HS
#pragma c o n f i g FOSC = HS
// P l l d e s l i g a d o
#pragma c o n f i g CPUDIV = OSC1_PLL2
// Watchdog c o n t r o l a d o por s o f t w a r e
#pragma c o n f i g WDT = OFF
// Sem programao em b a i x a t e n s o
#pragma c o n f i g LVP = OFF
Notar que as diretivas utilizadas so completamente diferentes, mas realizam o mesmo tra-
balho.
Barramento de Led's(.)
Display de 7 segmentos(.)
Sadas PWM(.)
Leitura de teclas(.)
Conversor AD(.)
1
Perifricos que fornecem informaes aos usurios ou enviam comandos da a placa eletrnica para o meio
externo
2
Perifricos que recebem informaes ou comandos do meio externo
47
48 Programao dos Perifricos
Cada porta esta ligada dois endereos de memria. O primeiro armazena o valor que
queremos ler do meio externo ou escrever para o meio externo dependendo da configurao. O
segundo endereo realiza esta configurao indicando quais bits sero utilizados para entrada e
quais sero utilizados para sada (Tabela 4.1).
// i n i c i o do programa
void main ( void ) interrupt 0
{
// d e f i n i m o s como :
// u n s i g n e d c h a r : p o i s os 8 b i t s r e p r e s e n t a m v a l o r e s
// v o l a t i l e : as v a r i v e i s podem mudar a q u a l q u e r momento
// near : i n d i c a p o s i c i o n a m e n t o do r e g i s t r o e s t a na memria
v o l a t i l e near unsigned char PORTD = 0 xF83 ;
v o l a t i l e near unsigned char TRISD = 0 xF95 ;
// c o n f i g u r a n d o t o d o s os p i n o s como s a d a s
// 0 = s a d a ( Output )
// 1 = e n t r a d a ( I n p u t )
TRISD = 0 b00000000 ;
// l i g a apenas os q u a t r o l t i m o s l e d s
PORTD = 0 b11110000 ;
//mantm o s i s t e m a l i g a d o i n d e f i n i d a m e n t e
for ( ; ; ) ;
}
Notar que, por serem ponteiros, sempre que precisarmos utilizar o valor de tais variveis
necessrio que coloquemos o asterisco.
Uma outra maneira de manipular as portas criar defines que permitem o uso das portas
como variveis, sem a necessidade de utilizar ponteiros de modo explicito, nem asteriscos no
cdigo.
// d e f i n e ' s para p o r t a s de e n t r a d a e s a d a
#define PORTD ( ( v o l a t i l e n e a r unsigned char ) 0xF83 )
#define TRISD ( ( v o l a t i l e n e a r unsigned char ) 0xF95 )
// i n i c i o do programa
void main ( void ) interrupt 0
{
// c o n f i g u r a n d o t o d o s os p i n o s como s a d a s
TRISD = 0 b00000000 ;
// l i g a apenas os q u a t r o l t i m o s l e d s
PORTD = 0 b11110000 ;
//mantm o s i s t e m a l i g a d o i n d e f i n i d a m e n t e
for ( ; ; ) ;
}
Como estamos criando um define, uma boa prtica de programao utilizar apenas letras
maisculas para diferenci-lo de uma varivel comum.
Notem que usamos dois asteriscos no define. isto que permite que utilizemos o define como
uma varivel qualquer, sem precisar de usar um asterisco a todo momento, como no caso dos
ponteiros.
A segunda abordagem (com define) preferida em relao primeira pois, dependendo do
compilador, gera cdigos mais rpidos alm de economizar memria. Alm disso, permite que a
definio seja feita apenas uma vez e utilizada em todo o programa.
Para a placa que estamos utilizando, a configurao dos terminais do PIC segue conforme a
Tabela 4.2. Esta configurao reflete a opo do autor de acordo com as possibilidades da placa
e tambm o sistema mnimo para realizao de todas as experiencias da apostila.
Os terminais no citados na Tabela 4.2 (1, 3, 5, 6, 15, 18, 23 e 24) possuem perifricos
que no sero utilizados neste curso. Os terminais 11 e 31 representam a alimentao positiva.
O comum (terra) est ligado ao 12 e ao 32. O microcontrolador utilizado (18f4550) possui o
encapsulamento DIP. Para outros encapsulamentos favor considerar o datasheet.
Da Tabela 4.2, temos que a porta A possui o primeiro bit como entrada analgica e o terceiro
e sexto como sada digital. Os dois bits digitais servem como controle de ativao do display.
22 RD3/SPP3
25 RC6/TX/CK
RS232
26 RC7/RX/DT/SDO
27 RD4/SPP4
28 RD5/SPP5/P1B Barramento de dados para o
29 RD6/SPP6/P1C LCD/7seg/Led
30 RD7/SPP7/P1D
33 RB0/AN12/INT0/SDI
34 RB1/AN10/INT1/SCK
Sadas para alimentao do teclado
35 RB2/AN8/INT2/VMO
36 RB3/AN9/CCP2/VPO
37 RB4/AN11/KBI0/CSSPP
38 RB5/KBI1/PGM
Entradas para leitura do teclado
39 RB6/KBI2/PGC
40 RB7/KBI3/PGD
A porta B possui os 4 primeiros bits como sadas e os quatro ltimos como entrada. Esta
porta serve para leitura da matriz de chaves. possvel realizar a leitura atravs de interrupo.
A porta C possui o segundo e terceiro bit como sada PWM e o stimo e oitavo como
comunicao serial.
A porta E possui apenas os 3 primeiros bits configurados como sadas digitais. So utilizados
para controle de ativao dos displays e tambm como sinais de controle do LCD.
. Barramento de Led's
Existe na placa utilizada um barramento de 8 bits, onde cada linha possui um led associado. Este
barramento est ligado diretamente com a porta D do microcontrolador conforme Figura 4.2.
Podemos notar pela Figura 4.2 que existe um jumper (JP1) que habilita ou no o funcio-
namento destes leds. Alm disso percebemos que se o jumper estiver encaixado, os led's esto
permanentemente ligados ao 5 volts. Deste modo, para que o led acenda, necessrio colocar o
valor 0 (zero) no respectivo bit da porta D. Quando um dispositivo ligado com o valor 0 (zero)
e desligado com o valor 1 (um), dizemos que este dispositivo opera com lgica invertida.
Conforme visto preciso configurar os pinos da porta D como sada, para isso basta escrever
zero em cada um deles no registro TRISD.
. Display de 7 segmentos
Os displays de 7 segmentos (Figura 4.3) so componentes opto eletrnicos utilizados para apre-
sentar informaes para o usurio em formato numrico.
Estes displays foram concebidos com o intuito de gerar os dez algarismos romanos: 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, sendo que os algarismos 0, 6, 7 e 9 podem ser representados de mais de uma
maneira.
Alm dos algarismos possvel representar apenas algumas letras de modo no ambguo: as
maisculas A, C, E, F, H, J, L, P, S, U, Z e as minsculas: a, b, c, d, h, i, n, o, r, t, u.
Os displays podem ser do tipo catodo comum, ou anodo comum indicando qual o tipo de
ligao dos leds. Contudo, esta diferena no ser crtica para este estudo. Na Figura 4.4
podemos visualizar o esquema eltrico e a disposio fsica de cada led no componente.
Figura 4.4: Diagrama eltrico para display de 7 segmentos com anodo comum
http://www.hobbyprojects.com/the_diode/seven_segment_display.html
Pela Figura 4.4 podemos notar que para que aparea o nmero 2 no display necessrio
acender os leds a, b, g, e, d. Se estivermos utilizando um display com catodo comum, precisamos
colocar um nvel alto para ligar o led, ou seja, o led liga com valor 1 (um) e desliga com valor 0
(zero). Isto tambm conhecido como lgica positiva. Na Tabela 4.3 so apresentados os valores
em binrio e em hexadecimal para cada representao alfanumrica3 . Dentre as letras disponveis
esto apresentadas apenas os caracteres A, b, C, d, E, F. Estas foram escolhidos por serem os
mais utilizados para apresentar valores em hexadecimal nos displays. Neste curso utilizaremos a
3
Notar que os valores hexadecimais apresentados servem apenas quando existe uma sequencia na ligao entre
a porta do microcontrolador e os pinos do display. Em alguns sistemas, o display pode ser controlado por duas
portas diferentes, ou possuir alguma alterao na sequencia de ligao. Para tais casos necessrio remontar a
tabela apresentada.
ordem direta apresentada na Tabela 4.3. A utilizao de uma ou outra depende da ligao feita
na placa. A Figura 4.5 apresenta o esquema eltrico disponvel.
Para simplificar a utilizao deste tipo de display comum criar uma tabela cujas posies
representam o valor de converso para o display. Conforme pode ser visto no cdigo a seguir.
Multiplexao de displays
Cada display exige 7 ou 8 terminais de controle, caso tambm seja utilizado o ponto decimal.
Para utilizar 4 displays, por exemplo um relgio com dois dgitos para horas e dois para minutos,
precisaramos de 32 terminais de sada, o que pode ser um custo4 muito alto para o projeto.
Uma tcnica que pode ser utilizada a multiplexao dos displays. Esta tcnica leva em conta
um efeito biolgico denominado percepo retiniana. O olho humano incapaz de perceber
mudanas mais rpidas que 1/30 (s). Outro fator importante que as imagens mais claras
ficam gravadas na retina devido ao tempo que leva para sensibilizar e dessensibilizar as clulas
(bastonetes).
Deste modo podemos ligar e desligar rapidamente o display que a imagem continuar na
retina. Se ligarmos cada display, um por vez, sequencialmente, de maneira suficientemente
rpida, teremos a impresso que todos esto ligados. A frequncia de chaveamento deve ser
mais rpida que 30Hz.
A Figura 4.5 apresenta o circuito com 4 displays multiplexados. Percebemos que os terminais
iguais esto ligados juntos. Percebemos tambm que os terminais de catodo comum esto cada
um ligado uma sada diferente. Com esta arquitetura reduzimos a quantidade de terminais
necessrios de 32 para 12, uma economia de 20 terminais.
Mas esta economia tem um custo, o sistema se torna mais complexo pois no podemos ligar
dois displays ao mesmo tempo.
O controle de qual display ser ligado feito atravs do transistor que permite a ligao do
catodo comum ao terra, ou o anodo comum ao VCC (depende do tipo de dispositivo. Para o
correto funcionamento no basta agora acender os leds corretos para formar o nmero, temos
que seguir um algoritmo mais complexo:
4. desligar o display
6. voltar ao passo 1
Microcontroladores com mais terminais possuem um custo superior, mesmo possuindo os mesmos perifricos
4
internamente.
5
Se a taxa de atualizao dos displays for muito baixa, estes vo apresentar uma variao na intensidade, como
se estivessem piscando. Este efeito chamado de flicker.
Criao da biblioteca
O programa 4.1 apresenta um exemplo de cdigo para criar uma biblioteca para os displays de 7
segmentos. O programa 4.2 apresenta o header da biblioteca. J o programa 4.3 apresenta uma
demonstrao de uso da biblioteca.
5 // i n i c i o do programa
6 void main ( void ) interrupt 0
7 {
8 unsigned i n t tempo ;
9 InicializaDisplays ( ) ;
10 MudaDigito ( 0 , 0 ) ;
11 MudaDigito ( 1 , 1 ) ;
12 MudaDigito ( 2 , 2 ) ;
13 MudaDigito ( 3 , 3 ) ;
14 for ( ; ; )
15 {
16 AtualizaDisplay ( ) ;
17 // g a s t a um tempo para e v i t a r o e f e i t o f l i c k e r
18 f o r ( tempo =0; tempo <1000; tempo++) ;
19 }
20 }
. Leitura de teclas
Para realizar a leitura de uma tecla necessrio criar um circuito que realize a leitura de um
sinal eltrico para o valor zero e outro para o valor um. Os nveis de tenso associados dependem
muito dos circuitos envolvidos. Os nveis mais comuns so os compatveis com TTL, onde o zero
lgico representado por 0v (zero volts) e o um lgico representado por 5v (cinco volts).
Uma maneira de se obter este funcionamento com o uso de uma chave ligada ao VCC e um
pull-down ou uma chave ligada ao terra (GND) e um pull-up.
Pela Figura 4.6 percebemos que a tenso de sada igual a VCC quando a chave est desligada
pois no existe corrente circulando no circuito portanto a queda de tenso em R1 zero. Quando
a chave pressionada uma corrente flui de VCC para o terra passando por R1. Como no existe
nenhuma outra resistncia no circuito toda a tenso fica em cima de R1 e a tenso de sada passa
a ser zero.
Apesar do funcionamento aparentemente simples, este tipo de circuito apresenta um problema
de oscilao do sinal no momento em que a tecla pressionada. Esta oscilao conhecida como
bouncing (Figura 4.7).
Estas oscilaes indevidas podem gerar acionamentos acidentais, causando mau funciona-
mento do programa. Para evitar isso podemos utilizar tcnicas de debounce, por hardware ou
software.
A opo de debounce por hardware pode ser visualizada na Figura 4.8.
Neste circuito, o capacitor desempenha o papel de amortecedor do sinal. Um circuito com um
resistor e um capacitor possui um tempo de atraso para o sinal. Este o tempo necessrio para
carregar o capacitor. Deste modo as alteraes rpidas no sinal, devido oscilao mecnica da
chave, so filtradas e no ocorre o problema dos chaveamentos indevidos conforme pode ser visto
na Figura 4.9. Notar que o nvel do sinal filtrado no chega a zero em nenhum momento, devido
constante de tempo do filtro RC ser maior que o perodo de debounce.
8MHz) de 0,56 (s). Antes de utilizar o valor que estamos lendo na porta em questo devemos
esperar 300 ciclos de clock aps alguma mudana para ter certeza que o sinal se estabilizou, ou
seja, a fase de bouncing acabou.
Notar que, no cdigo, o contador iniciado com o valor 22. Atravs da anlise do assembler
podemos saber que cada ciclo de conferencia do sinal possui 14 instrues. Assim necessrio
que o sinal permanea com o mesmo valor durante 308 ciclos para que a varivel valAtual receba
o valor da porta B. Estes valores podem ser determinados empiricamente atravs de testes com
osciloscpios.
}
else
{
valTemp = PORTB ; // s e mudar , a t u a l i z a o s i s t e m a e r e i n i c i a o tempo
tempo = 2 2 ;
}
}
valAtual = valTemp ; // v a l o r a t u a l i z a d o ;
PORTD = valAtual ; // c o l o c a o v a l o r no barramento de l e d s
}
}
}
}
}
importante notar que o cdigo acima no apresenta debounce em software para as teclas.
possvel realizar um debounce minimizando o gasto com memria e tempo, representando cada
chave como um bit diferente numa varivel. Esta ser a abordagem utilizada na gerao da
biblioteca para o teclado.
Criao da biblioteca
O programa 4.4 apresenta um exemplo de cdigo para criar uma biblioteca para um teclado de
16 teclas com leitura matricial. O header pode ser visto no programa 4.5. J o programa 4.6
apresenta uma demonstrao de uso da biblioteca.
5 // i n i c i o do programa
6 void main ( void ) interrupt 0
7 {
8 InicializaTeclado ( ) ;
9 TRISD = 0 x00 ; // C o n f i g u r a a p o r t a D como s a d a
10 PORTD = 0 xFF ; // d e s l i g a t o d o s os l e d s
11 while (1==1)
12 {
13 DebounceTeclas ( ) ;
14 PORTD = LerTeclas ( ) ;
15 }
16 }
Este mesmo tipo de display pode ser encontrado em diversas verses com tamanhos e cores
diferentes sendo os mais comuns de 1x8, 2x16 e 4x40. Pode ainda ter 16 ou 14 terminais,
dependendo se existe ou no retro iluminao. Estes terminais so identificados como:
1. Terra 9. Bit 2
Criao da biblioteca
Para facilitar o controle do display, podemos criar trs funes, uma para inicializao, uma para
escrever um caractere e a ltima para enviar um comando. Estas funes esto apresentadas no
programa 4.8, que constitui um exemplo de biblioteca. Alm destas trs funes necessrio ter
uma funo de delay, que garanta um determinado tempo para que as informaes sejam lidas
corretamente pelo LCD.
O header desta biblioteca e um exemplo de como us-la so apresentados nos programas 4.7
e 4.9, respectivamente.
5 // i n i c i o do programa
6 void main ( void ) interrupt 0
7 {
8 unsigned i n t i , j ;
9 char msg [ ] = " Hello World !" ;
10 InicializaLCD ( ) ;
11 f o r ( i =0;i <11; i++)
12 {
13 EnviaDados ( msg [ i ] ) ;
14 f o r ( j = 0 ; j < 6 5 0 0 0 ; j++) ;
15 }
16 for ( ; ; ) ;
17 }
. Comunicao serial
Em geral a comunicao entre dois dispositivos eletrnicos realizada de modo serial, isto , as
informaes so passadas bit bit do transmissor para o receptor. Este tipo de comunicao
possui algumas vantagens em relao comunicao paralela, na qual a palavra (byte) enviada
toda de uma vez.
A primeira vantagem a simplificao do hardware. Como os dados so enviados um a um,
necessrio apenas um fio de comunicao e um para retorno.
A segunda a maior taxa de transmisso, o que a primeira vista inconsistente j que num
mesmo ciclo de clock a comunicao paralela envia mais de um bit, enquanto a serial apenas um.
Este fato acontece pois para frequncias muito altas pode existir atraso entre um fio e outro se os
cabos da comunicao paralela possurem qualquer diferena. Alm disso existe o problema do
crosstalking, onde o campo magntico gerado por um cabo induz uma pequena tenso no outro
cabo, atrapalhando a comunicao. Estes problemas aumentam com a frequncia limitando
assim a mxima transferncia possvel pelo barramento paralelo. este o motivo que levou os
projetistas de hardware a desenvolverem o protocolo SATA, em detrimento ao IDE/ATA, para
comunicao entre o HD e a placa me conforme pode ser visto na Tabela 4.5.
RS 232
O protocolo de comunicao RS232 (Recommended Standard 232) um protocolo muito uti-
lizado para comunicao entre dispositivos que transmitem ou recebem pouca quantidade de
informaes. um dos protocolos mais antigos sendo utilizado pela primeira vez em 1962 para
mquinas de escrever eletromecnicas. O padro RS232 reviso C datado de 1969. Em 1986
aparece a reviso D pela EIA (Electronic Industries Alliance). A verso atual do protocolo
datada de 1997 pela TIA (Telecommunications Industry Association) sendo chamada TIA-232-F.
O procedimento de envio de um valor pela serial atravs do padro RS232 pode ser visto
como uma operao de bit-shift.
Por exemplo a letra K: em ASCII codificada como 7610 e em binrio como 110100102 . Na
maioria dos dispositivos primeiro se envia o bit menos significativo. Antes de iniciar a transmisso
dos bits, enviado um bit de comeo, indicando que haver transmisso a partir daquele instante.
Aps isso o bit menos significativo enviado para a sada do microcontrolador. Realiza-se ento
um shift para direita e o novo bit menos significativo reenviado. Esta operao realizada
oito vezes. Aps esse procedimento envia-se um bit de parada, que pode ter a durao de um ou
dois bits.
A Figura 4.16 apresenta o sinal eltrico7 enviado ao longo do tempo para a letra K. Notar a
regio em branco, que se extende entre +3 e -3. Ela indica a regio de tenso na qual o sinal no
7
Para o protocolo RS232 o nvel alto ou 1 (um) aquele com tenses positivas entre +3 e +15. O nvel logico
baixo ou 0 (zero) interpretado entre -3 e -15 volts.
est definido. Caso a tenso lida esteja nestes limiares, seja devido ruidos ou outros problemas,
o sistema de recepo no entender a mensagem e os dados podem ser corrompidos.
A equao que gera o menor erro a terceira. Como queremos trabalhar com uma comuni-
cao assncrona, da Tabela 4.6 obtemos que os bits de configurao devem ser: TXSTA(4) = 0,
BitClr ( BAUDCON , 0 ) ; // D e s a b i l i t a a u t o d e t e c o de v e l o c i d a d e
BitSet ( BAUDCON , 3 ) ; // R e g i s t r o de g e r a o de s i n a l com 16 b i t s
BitClr ( BAUDCON , 6 ) ; // Operao de r e c e p o e s t a a t i v a
BitClr ( RCSTA , 1 ) ; // D e s a b i l i t a b i t de e r r o de o v e r r u n
BitClr ( RCSTA , 2 ) ; // D e s a b i l i t a b i t e r r o na comunicao
BitClr ( RCSTA , 4 ) ; // H a b i l i t a b i t de r e c e p o
BitClr ( RCSTA , 6 ) ; // S e l e c i o n a 8 b i t s
BitSet ( RCSTA , 7 ) ; // C o n f i g u r a RX/TX como p i n o s de comunicao
BitSet ( TXSTA , 2 ) ; //Modo de a l t a v e l o c i d a d e h a b i l i t a d o
BitSet ( TXSTA , 3 ) ; // Envia b i t de parada ( b r e a k c h a r a c t e r b i t )
BitClr ( TXSTA , 4 ) ; //Modo a s s n c r o n o
BitSet ( TXSTA , 5 ) ; // H a b i l i t a t r a n s m i s s o
BitClr ( TXSTA , 6 ) ; // S e l e c i o n a 8 b i t s
SPBRGH = 0 x00 ; // C o n f i g u r a para 56 k (SPBRGH|SPBRG = 32)
SPBRG = 0 x22 ; // C o n f i g u r a para 56 k (SPBRGH|SPBRG = 32)
BitSet ( TRISC , 6 ) ; // C o n f i g u r a p i n o de r e c e p o como e n t r a d a
BitClr ( TRISC , 7 ) ; // C o n f i g u r a p i n o de e n v i o como s a d a
O procedimento de serializao dos bits feito de maneira automtica pelo hardware. En-
quanto ele est realizando este processo no devemos mexer no registro que armazena o byte a
ser enviado. Por isso devemos verificar se o registro est disponvel. Isto feito atravs do bit 4
do registro PIR. Quando este valor estiver em 1 basta escrever o valor que desejamos transmitir
no registro TXREG.
resp = RCREG ; // r e t o r n a o v a l o r
}
return resp ; // r e t o r n a z e r o
}
A metodologia apresentada para leitura e escrita de valores conhecida como pooling. Neste
tipo de abordagem ficamos parados esperando que o valor esteja disponvel para leitura/escrita.
Este o mtodo mais simples para se controlar qualquer tipo de dispositivo. O problema que
o processador fica travado em uma tarefa gastando tempo que seria til para realizar outras
operaes. A melhor alternativa para resolver este problema atravs de interrupes, que sero
abordadas apenas no tpico ..
Criao da biblioteca
O programa 4.10 apresenta um exemplo de cdigo para criar uma biblioteca para comunicao
serial. O arquivo de header apresentado no progrma 4.11 e o exemplo de uso demonstrado no
programa 4.12.
A seguir o arquivo de header.
5 // i n i c i o do programa
6 void main ( void ) interrupt 0
7 {
8 unsigned i n t i , j ;
9 char msg [ ] = " Hello World !" ;
10 unsigned char resp ;
11 TRISD = 0 x00 ; // a c e s s o aos l e d s
12 InicializaSerial ( ) ;
13 j =0;
14 for ( ; ; )
15 {
16 // d e l a y
17 f o r ( i = 0 ; i < 6 5 0 0 0 ; i++) ;
18 // e n v i a dados
19 EnviaSerial ( msg [ j ] ) ;
20 j++;
21 i f ( j > 11)
22 {
23 j =0;
24 EnviaSerial ( 1 3 ) ;
25 }
26 // r e c e b e dados
27 resp = RecebeSerial ( ) ;
28 i f ( resp !=0)
29 {
30 PORTD = resp ;
31 }
32 }
33 }
. Conversor AD
Um conversor de analgico para digital um circuito capaz de transformar um valor de tenso
numa informao binria. O circuito que utilizaremos possui uma preciso de 10 bits, ou seja,
ele capaz de sentir uma variao de praticamente um milsimo8 da excurso mxima do sinal.
Para a configurao que iremos utilizar, com uma fonte de 5v, isto significa uma sensibilidade
de 4.88mV.
Elementos sensores
A converso AD muito utilizada para realizarmos a leitura de sensores. Todo sensor baseado
num transdutor. Um elemento transdutor aquele que consegue transformar um tipo de grandeza
em outro, por exemplo uma lmpada incandescente (Figura 4.17).
Podemos utilizar uma lampada incandescente como sensor de tenso: pega-se uma lmpada
de 220V. Liga-se a lmpada uma tomada desconhecida. Se o brilho for forte a tomada possui
220V, se o brilho for de baixa intensidade, a tomada possui 127V. Se a lmpada no ascender
existe algum problema na fiao, na tomada ou at mesmo na lmpada. A lampada um
transdutor de tenso para luminosidade.
Para a eletrnica estamos interessados em transdutores cuja sada seja uma variao de
tenso, corrente ou resistncia.
Um sistema muito simples de transdutor de ngulo para resistncia o potencimetro (Fi-
gura 4.18).
Se o potencimetro estiver alimentado pelos terminais da extremidade, o terminal central fun-
ciona como um divisor de tenso. O valor de sada proporcional posio do cursor. Podemos
aproximar o potencimetro como duas resistncias conforme apresentado na Figura 4.19.
Deste modo a tenso aplicada em RL (supondo que RL muito maior que R2) :
VS R2 R2
VRL = = VS ( )
R1 + R2 RPot
Se na construo do potencimetro a variao da resistncia ao longo da trilha foi feita de modo
constante, a resistncia varia de maneira linear com a posio do cursor. Deste modo podemos
utilizar o potencimetro como um transdutor de ngulo.
Diversas medidas podem ser realizadas utilizando o conceito de divisor de tenso: luminosi-
dade com LDR's, fora com strain-gages, deslocamento com potencimetros lineares, etc.
Existem alguns sensores que possuem circuitos de amplificao e condicionamento do sinal
embutidos no mesmo envlucro que o elemento sensor. A estes tipos de sensores damos a deno-
minao de ativos.
8
Com uma preciso de 10 bits conseguimos representar 2
10 valores diferentes, ou 1024 valores.
Um sensor ativo possui no mnimo 3 terminais: 2 para alimentao e 1 para sada do sinal.
Um exemplo deste tipo de sensor o LM35 (Figura 4.20) que utilizado para monitoramento
de temperatura.
Na Figura 4.21 apresentado o diagrama de blocos do circuito integrado do LM35. O diodo
utilizado como unidade sensora de temperatura.
Processo de converso AD
Existem alguns circuitos que realizam a converso de um sinal analgico advindo de um trans-
dutor para um sinal digital com uma preciso arbitrria.
A abordagem mais simples a utilizao de comparadores. Cada comparador possui um
nvel diferente de tenso de referncia. Estes nveis so escolhidos de forma que a representao
binria faa sentido.
Exemplo: Converso de um valor analgico que varia de zero cinco volts numa palavra
digital de dois bits.
Para N bits temos N 2 representaes diferentes. interessante ento dividir a amplitude
inicial por N 2 divises iguais. Para N = 2 temos 4 representaes de 1.25v cada.
O circuito eletrnico responsvel pelas comparaes pode ser visualizado na Figura 4.22.
O circuito da Figura 4.22 conhecido como conversor analgico digital do tipo flash onde
cada nvel de tenso possui seu prprio comparador. Existem outras abordagens que minimizam
11 i n t LeValorAD ( void )
12 {
13 unsigned i n t ADvalor ;
14 BitSet ( ADCON0 , 1 ) ; // i n i c i a c o n v e r s o
15 while ( BitTst ( ADCON0 , 1 ) ) ; // e s p e r a t e r m i n a r a c o n v e r s o ;
16 ADvalor = ADRESH ; // l o r e s u l t a d o
17 ADvalor <<= 8 ;
18 ADvalor += ADRESL ;
19 return ADvalor ;
20 }
o uso de conversores (parte mais cara do circuito) mas inserem atraso no processo de converso.
O atraso depende do tipo de circuito que implementado.
Criao da biblioteca
Toda converso leva um determinado tempo que, conforme citado na seo anterior, depende
da arquitetura que estamos utilizando, da qualidade do conversor e, algumas vezes, do valor de
tenso que queremos converter. Para que o microcontrolador realize corretamente a converso
necessrio seguir os seguintes passos:
1. Configurar o conversor
2. Iniciar a converso
4. Ler o valor
. Sadas PWM
As sadas PWM so sadas digitais que possuem um chaveamento acoplado. O sinal muda seu
estado de positivo para zero vrias vezes por segundo. A porcentagem do tempo que este sinal
permanece em nvel Alto define o ciclo de trabalho, ou duty cycle, da sada. A Figura 4.23
apresenta 3 sinais PWM com a mesma frequncia mas com duty cycle diferentes.
Suponha uma sada PWM ligada um resistor. Quando a sada estiver em nvel alto existe
a passagem de corrente eltrica e a resistncia aquece. Quando estiver em nvel baixo a corrente
para. Como a constante trmica do componente alta, leva-se alguns segundos para que o
resistor aquea ou esfrie, possvel ajustar a quantidade de energia mdia com uma frequncia
de sinal PWM suficientemente alta.
Em outras palavras, se a frequncia do PWM for mais alta do que a carga conseguir enxergar,
quando colocarmos o duty cycle em 50%, a carga ir receber 50% da energia total. Se for um
resistor, podemos controlar a temperatura final deste modo, num motor podemos ajustar a
velocidade de rotao que queremos.
Como citado a frequncia do PWM tem que ser suficientemente alta. Esta frequncia depende
do circuito implementado no microcontrolador. No caso do PIC18f4550 calculada segundo a
formula abaixo.
FOSC
Frequencia PWM =
[(PR2 ) + 1] 4 (TMR2 Prescaler )
Com uma frequncia de oscilao de 8MHz (disponvel na placa) podemos atingir frequncias
que variam de 488Hz at 2MHz.
O problema de trabalhar, no caso do PIC, com frequncias muito altas que perdemos
resoluo na definio do duty cycle. Por exemplo, para a frequncia de PWM em 2MHz com
um clock de 8MHz temos uma resoluo de apenas 2 bits. Ou seja, podemos configurar a sada
para 0%, 25%, 50% ou 75% do valor mximo. A resoluo pode ser obtida segundo a formula
abaixo.
log( FFPWM
OSC
)
Resoluo PWM (max ) = bits
log(2)
O PIC18f4550 permite uma resoluo de at 10 bits. Com um oscilador principal de 8 MHz
a frequncia mxima do PWM para utilizarmos os 10 bits de resoluo 7812,5 Hz. Para uma
resoluo de 8 bits a frequncia mxima aumenta para 31.25 kHz.
Utilizando a primeira e segunda formulas podemos montar a Tabela 4.7.
O duty cycle (em porcentagem) calculado de acordo com a frmula abaixo:
Tabela 4.7: Faixa de frequncias mximas e mnimas para cada configurao do prescaler
Criao da biblioteca
Para configurar as sadas PWM devemos especificar a frequncia de trabalho atravs de PR2
e TCON2, alm do duty cycle em CCPR1L e CCPR2L. No registro TRISC configurado o
terminal como uma sada e em CCP1CON e CCP2CON definimos que ele deve trabalhar como
um PWM. O prescaler foi configurado para 16 bits de modo a obter a maior faixa de frequncia
audvel disponvel (Tabela 4.7). Notar que importante realizar primeiro a multiplicao e
somente depois a diviso, para no haver perda de informao. No programa 4.16 apresentado
um cdigo exemplo de como criar as rotinas de operao do PWM. O header desta biblioteca
apresentado no programa 4.17. Por fim, o programa 4.18 apresenta um exemplo de utilizao
desta biblioteca.
12 // tempo em micro s e g u n d o s
13 void ResetaTimer ( unsigned i n t tempo )
14 {
15 // para p l a c a com 8MHz 1 ms = 2 c i c l o s
16 unsigned ciclos = tempo 2 ;
17 // o v e r f l o w a c o n t e c e com 2^151 = 65535 ( max u n s i g n e d i n t )
18 ciclos = 65535 ciclos ;
19 ciclos = 1 4 ; // s u b t r a i tempo de o v e r h e a d ( e x p e r i m e n t a l )
20 TMR0H = ( ciclos >> 8 ) ; // s a l v a a p a r t e a l t a
21 TMR0L = ( ciclos & 0 x00FF ) ; // s a l v a a p a r t e b a i x a
22 BitClr ( INTCON , 2 ) ; // l i m p a a f l a g de o v e r f l o w
23 }
. Timer
Nos microcontroladores existem estruturas prprias para realizar a contagem de tempo, estas
estruturas so denominadas Timers.
O PIC18f4550 possui quatro timers. Para utilizarmos a sada PWM temos que configurar o
timer 2, que gera a base de tempo que sera comparada com o duty cycle.
Ao invs de contarmos quantas instrues so necessrias para criar um delay de um deter-
minado tempo, podemos utilizar os timers. Escolhemos o valor de tempo que queremos contar,
inicializamos as variveis e esperamos acontecer um overflow 9 na contagem do timer.
Para trabalhar com o timer precisamos basicamente de uma funo de inicializao, uma para
resetar o timer e outra para indicar se o tempo configurado anteriormente j passou. Uma quarta
funo AguardaTimer(), foi construda para facilitar o desenvolvimento de algumas rotinas
comuns nos programas. Estas rotintas esto implementadas no programa 4.19 cujo header
apresentado no programa 4.20. O modo de utilizar esta biblioteca apresentado no programa
4.21.
Overflow conhecido como estouro de varivel. Toda varivel digital possui um valor mximo, por exemplo
9
255 para uma varivel do tipo unsigned char. Se uma varivel unsigned char possui o valor 255 e acrescida de
1, seu valor passa a ser zero e acontece o estouro ou overflow.
. Reproduo de Sons
Se ligarmos sada PWM um auto-falante possvel reproduzir sons. Conhecendo a frequncia
de cada uma das notas musicais e a durao destas possvel reproduzir uma msica. Para
reproduzir o tempo com uma preciso melhor podemos utilizar o TIMER0 como unidade de
tempo.
Conforme visto na seo ., o PWM utilizado na placa consegue reproduzir as frequncias
audveis a partir de 488,3Hz. Por isso escolhemos comear a escala musical a partir do C5 (D
Tenor) que possui a frequncia de 523. A segunda escala possui o dobro da frequncia (uma
oitava acima). Para reproduzir a ausncia de som escolhemos a frequncia de 125.000 Hz10 , que
inaudvel. Isto simplifica o programa.
41 //sem som
42 #define v 125000
10
Esta a mxima frequncia possvel para o PWM operado com prescaler de 16x.
. Interrupo
At o momento todos os programas que foram desenvolvidos seguiam um fluxo sequencial sendo
alterado apenas por chamadas de funes, estruturas de deciso ou loop. Um dos problemas de
se utilizar este tipo de estrutura que alguns perifricos possuem um tempo muito grande para
realizarem sua funo como o conversor AD por exemplo. Nesta situao o que fazemos iniciar
a converso e ficar monitorando uma varivel que indicava quando a converso tinha terminado.
Esta tcnica conhecida como pooling.
O problema de se realizar a leitura de algum perifrico por pooling que o processador perde
tempo realizando operaes desnecessrias checando a varivel de controle. Uma alternativa
utilizar um sistema que, quando a operao desejada estivesse finalizada, nos avisasse para que
pudssemos tomar uma providncia. Este procedimento chamado de interrupo.
Alguns dispositivos possuem a possibilidade de operarem com interrupes. Quando a con-
dio do dispositivo for satisfeita (fim da converso para o AD, chegada de informao na serial,
mudana no valor da varivel na porta B) ele gera uma interrupo. A interrupo para o
programa no ponto em que ele estiver, salva todos os dados atuais e vai para uma funo pr-
definida. Esta funo realiza seu trabalho e assim que terminar volta o programa no mesmo
ponto onde estava antes da interrupo.
Dos dispositivos estudados at agora os que geram interrupo so:
Porta Serial: quando chega alguma informao em RCREG ou quando o buffer de transmisso
TXREG estiver disponvel.
Porta B: quando algum dos bits configurados como entrada altera seu valor.
Para gerenciar a interrupo devemos criar uma rotina que ir verificar o tipo de interrupo
que ocorreu e tomara as providncias necessrias. A maneira de declarar que uma funo ser
responsvel pelo tratamento das interrupes depende do compilador.
Para o compilador SDCC basta que coloquemos a expresso interrupt 1 aps o nome da
funo.
Para o compilador C18 da Microchip temos que gerar um cdigo em assembler que indicar
qual funo ser a responsvel pela interrupo.
// I n d i c a r a p o s i o no v e t o r de i n t e r r u p e s
#pragma code h i g h _ v e c t o r=0x08
void interrupt_at_high_vector ( void )
{
_asm GOTO Interrupcao _endasm
}
#pragma code
#pragma i n t e r r u p t NomeDaFuncao
Existe uma correlao entre o nmero que vem depois da expresso interrupt para o com-
pilador SDCC e o nmero ao final da expresso #pragma code high_vector para o C18. Estes
nmeros representam a posio para a qual o microcontrolador vai quando acontece uma inter-
rupo. Estas posies esto numa rea conhecida como vetor de interrupes.
Para o microcontrolador PIC18f4550 este vetor possui trs posies importantes: 0x00(0),
0x08(1) e 0x18(2). O compilador C18 usa a posio fsica e o SDCC o nmero entre parnteses.
A posio 0 (0x00) representa o endereo que o microcontrolador busca quando este acaba
de ser ligado. a posio de reset. Geralmente samos deste vetor e vamos direto para a funo
main().
As posies 1 e 2 (0x08,0x18) so reservadas para as interrupes de alta e baixa prioridade,
respectivamente. necessrio que o programador escolha quais dispositivos so de alta e quais so
de baixa prioridade. Existe ainda um modo de compatibilidade com os microcontroladores mais
antigos no qual todos os perifricos so mapeados na primeira interrupo (0x08). Utilizaremos
este modo por questo de facilidade.
Como todos os perifricos esto mapeados na mesma interrupo, a funo deve ser capaz de
diferenciar entre as diversas fontes de requisio. Uma maneira de se realizar esta verificao
atravs das flags de controle, ou seja, bits que indicam a situao de cada perifrico.
O programa 4.23 apresenta uma funo que trata de todas as fontes possveis de interrupo
para o PIC18f4550.
Em geral no necessrio tratar todas as interrupes, apenas aquelas que influenciaro
o sistema. O programa 4.24 apresenta um exemplo de uma funo que trata as interrupes
advindas da porta B, do timer 0, da serial e do AD.
Para que a funo apresentada no programa 4.24 funcione corretamente devemos inicializar
as interrupes de modo adequado, conforme apresentado no programa 4.25.
3 // i n i c i o do programa
4 void main ( void ) interrupt 0
5 {
6 unsigned i n t i ;
7 unsigned char temp ;
8 TRISD=0x00 ;
9 PORTD=0x00 ;
10 BitSet ( WDTCON , 0 ) ; // l i g a o s i s t e m a de watchdog
11 for ( ; ; )
12 {
13 PORTD++;
14 f o r ( i = 0 ; i < 1 0 0 0 0 ; i++)
15 {
16 CLRWTD ( ) ;
17 }
18 }
19 }
. Watchdog
Por algum motivo o software pode travar em algum ponto, seja por um loop infinito ou por
esperar a resposta de algum componente atravs de pooling de uma varivel.
A primeira condio pode ser evitada atravs de um projeto cuidadoso de software aliado a
uma boa validao. J a segunda exige que os hardwares adjacentes funcionem corretamente.
Se algum hardware apresenta uma falha e no envia a resposta que o microcontrolador est
esperando, este ltimo ir travar. Nestas situaes possvel utilizar o watchdog.
O watchdog um sistema que visa aumentar a segurana do projeto. Ele funciona como
um temporizador que precisa constantemente ser reiniciado. Caso no seja reiniciado no tempo
exigido, o watchdog reinicia o microcontrolador dando a possibilidade de sair de um loop infinito
ou de um pooling sem resposta.
Para habilitar o watchdog necessrio alterar os registros de configurao, especificamente
o CONFIG2H (0x300002). Outro mtodo consiste em deixar o watchdog desligado no registro e
lig-lo atravs de software, como apresentado no programa 4.26.
Notar o #define criado na primeira linha do programa 4.26. A expresso CLRWDT o
comando em assembler responsvel por resetar o watchdog. As diretivas _asm e _endasm
informam ao compilador que os comandos utilizados devem ser transcritos exatamente iguais
para o arquivo assembler a ser gerado.
Se aps ligar o watchdog no realizarmos a operao de reset dele, comentando ou excluindo a
funo CLRWTD(), o sistema ir travar to logo o tempo associado ao watchdog tenha expirado
pela primeira vez, reiniciando o sistema. Como apenas reiniciar no soluciona o problema, pois o
programa criado no ter funo para reiniciar o watchdog, o sistema continua sendo reiniciado
indefinidamente.
Arquitetura de desenvolvimento de
software
Constrained by memory limitations, performance requirements, and
physical and cost considerations, each embedded system design re-
quires a middleware platform tailored precisely to its needs, unused
features occupy precious memory space, while missing capabilities
must be tacked on. - Dr. Richard Soley
97
98 Arquitetura de desenvolvimento de software
Esta a estratgia utilizada at agora nos exemplos apresentados. Dentro da funo principal
colocado um loop infinito. Todas as tarefas so chamadas atravs de funes.
A vantagem de se utilizar esta abordagem a facilidade de se iniciar um projeto. Para
sistemas maiores comea a ficar complicado coordenar as tarefas e garantir a execuo num
tempo determinstico. Outro problema a modificao/ampliao do software. Geralmente a
insero de uma funo no meio do loop pode gerar erros em outras funes devido a restries
de tempo dos perifricos associados.
No exemplo acima, a insero da comunicao serial e os clculos podem atrapalhar a escrita
no display de sete segmentos, gerando flicker.
. Cooperative multitasking
Em computao, multitarefa ou multitasking um processo pelo qual diferentes tarefas compar-
tilham um mesmo recurso, seja ele memria, processamento ou qualquer perifrico disponvel.
Uma maneira de realizar este compartilhamento atravs de uma diviso do tempo: a tarefa
A possui um intervalo ao final do qual deve ceder os recursos para a tarefa B. Quando a mudana
de tarefa feita pela prpria tarefa, o sistema dito cooperativo. Quando existe um sistema
externo que realiza essa troca o sistema denominado preemptivo.
Se a mudana de tarefas for extremamente rpida o efeito resultante, para o ser humano,
de que todas as tarefas esto sendo executadas simultaneamente. Uma das maneiras de se
obter este tipo de operao atravs da criao de uma mquina de estados, como mostrado na
Figura 5.1.
Inicio
Ler Atualiza
Teclado Display
Atualiza Escreve
Display Serial
Atualiza
Ler Serial Display
Nota-se que aps a fase de inicializao o sistema entra num ciclo, como na abordagem one-
single-loop. Outra peculiaridade que algumas tarefas podem ser executadas mais de uma vez
para garantir as restries de tempo. No exemplo a tarefa de atualizao dos displays executada
trs vezes.
A transposio de uma mquina de estado para o cdigo em C realizada atravs de um
switch-case.
possvel retirar todas as atribuies para a varivel slot e colocar no slot-bottom a ex-
presso slot++. A abordagem apresentada foi escolhida por aumentar a robustez do sistema, j
que a varivel slot controla todo o fluxo do programa.
A insero de uma nova tarefa realizada de maneira simples, basta adicionar um outro slot,
ou seja, basta inserir um case/break com a tarefa desejada.
Como a mquina est dentro do loop infinito, a cada vez que o programa passar pelo case,
ele executar apenas um slot. Esta abordagem gera ainda um outro efeito. Como pode ser visto
no cdigo, naturalmente surgem duas regies: top-slot e bottom-slot. Se algum cdigo for
colocado nesta regio ele ser executado toda vez, de modo intercalado, entre os slots. Pela
Figura 5.1, percebemos que exatamente este o comportamento que queremos para a funo
AtualizaDisplay(). Deste modo, podemos remodelar o cdigo fazendo esta alterao.
12 // i n c i o da maquina de e s t a d o
13 switch ( slot ) {
14 case 0 :
15 LeTeclado ( ) ;
16 slot = 1 ;
17 break ;
18 case 1 :
19 AtualizaDisplay ( ) ;
20 slot = 2 ;
21 break ;
22 case 2 :
23 RecebeSerial ( ) ;
24 slot = 3 ;
25 break ;
26 case 3 :
27 AtualizaDisplay ( ) ;
28 slot = 4 ;
29 break ;
30 case 4 :
31 EnviaSerial ( ) ;
32 slot = 5 ;
33 break ;
34 case 5 :
35 AtualizaDisplay ( ) ;
36 slot = 0 ;
37 break ;
38 default :
39 slot = 0 ;
40 break ;
41 }
42 // fim da maquina de e s t a d o
44 // i n c i o do bottoms l o t
45 // fim do bottoms l o t
46 } // fim l o o p i n f i n i t o ( ! ? )
47 }
16 // i n c i o da maquina de e s t a d o
17 switch ( slot )
18 {
19 case 0 :
20 LeTeclado ( ) ;
21 slot = 1 ;
22 break ;
23 case 1 :
24 RecebeSerial ( ) ;
25 slot = 2 ;
26 break ;
27 case 2 :
28 EnviaSerial ( ) ;
29 slot = 0 ;
30 break ;
31 default :
32 slot = 0 ;
33 break ;
34 }
35 // fim da maquina de e s t a d o
38 // i n c i o do bottoms l o t
40 // fim do bottoms l o t
42 } // fim l o o p i n f i n i t o ( ! ? )
43 }
16 // i n c i o da maquina de e s t a d o
17 switch ( slot )
18 {
19 case 0 :
20 LeTeclado ( ) ;
21 slot = 1 ;
22 break ;
23 case 1 :
24 RecebeSerial ( ) ;
25 slot = 2 ;
26 break ;
27 case 2 :
28 EnviaSerial ( ) ;
29 slot = 0 ;
30 break ;
31 default :
32 slot = 0 ;
33 break ;
34 }
35 // fim da maquina de e s t a d o
38 // i n c i o do bottoms l o t
40 // fim do bottoms l o t
41 AguardaTimer ( ) ;
42 } // fim l o o p i n f i n i t o ( ! ? )
43 }
tempo. Notar que o slot 1 (S.1) gasta um tempo de 2.0(ms), o slot 2 de 3.1 (ms) e o slot 3 apenas
1.2 (ms). J o top-slot consome 0.5 (ms) e o bottom-slot 0.3 (ms).
Top
S.1
S.2
S.3
Bottom
"vago"
0 5 10 15 20 25 30
Podemos notar que para o ciclo do primeiro slot so gastos 0.5+2.0+0.3 = 2.8(ms). Deste
modo o sistema fica aguardando na funo AguardaTimer() durante 2.2 (ms) sem realizar
nenhum processamento til. Para o segundo slot temos um tempo "livre"de 5-(0.5+3.1+0.3)=1.1
(ms). O terceiro slot o que menos consome tempo de processamento, possuindo um tempo livre
de 5-(0.5+1.2+0.3)=3.0 (ms).
Top 1 1 1
S.1 3 3 3
Bottom 1 1 1
"vago" 3 3 3
Top 1 1
S.1 1 2 3 3
Bottom 1 1 1
"vago" 2 2 2
Interr. 1 1 1
Cada interrupo gasta um tempo de 1 (ms) conforme pode ser visto na Figura 5.4. Como
temos um tempo vago de 3 (ms) em cada ciclo basta garantir que os eventos que geram a
interrupo no ultrapassem a frequncia de 3 eventos a cada 8 (ms).
Anexos
107
108 Anexos
10 // para o c o m p i l a d o r C18
11 //#pragma c o n f i g FOSC = HS // O s c i l a d o r c / c r i s t a l e x t e r n o HS
12 //#pragma c o n f i g CPUDIV = OSC1_PLL2 // P l l d e s l i g a d o
13 //#pragma c o n f i g WDT = OFF // Watchdog c o n t r o l a d o por s o f t w a r e
14 //#pragma c o n f i g LVP = OFF // Sem programao em b a i x a t e n s o \\\ h l i n e
. config.h
O arquivo config.h possui as diretivas de compilao para configurao do microcontrolador.
. basico.h
O header basico.h possui o endereo de todos os registros do microcontrolador PIC18f4550 que
utilizado nesta apostila. Alm disso contm alguns defines importantes como as funes inline
para limpar a flag de watchdog e para manipulao de bits.
MPLAB ICD 3
Antes de Comear
O dispostivo no deve ser plugado numa porta USB antes de comear a instalao do Driver.
Se voc j plugou o dispositivo e apareceu a informao "Novo hardware encontrado", clique
em cancelar. Desligue o dispositivo e continue com os passos a seguir.
Se voc j utilizou o setup do windows voc instalou os drivers errados. Siga as instrues
de remoo dos drivers antes de prosseguir.
Passo 1
Conecte o dispositivo ao PC usando o cabo USB. Para os dispositivos que exigem alimentao
externa, ligue-a. Se estiver usando um hub USB, tenha certeza que o este possui energia sufici-
ente para alimentar o dispositivo.
Passo 2
A primeira vez que o dispositivo conectado aparece uma mensagem indicando que o sistema
encontrou um novo hardware. Quando aparecer uma janela, escolha a opo Localizar e insta-
lar o driver (recomendado) Nota: Se aparecer uma mensagem perguntando sobre permisso no
Windows 7, clique em sim/continuar.
Passo 3
Escolha a opo: Procurar o driver no meu computador (avanado)
Passo 4
Quando aparecer uma janela pedindo para voc indicar o caminho, procure em C:\Arquivos
de programa (x86)\Microchip\MPLAB IDE\Drivers64. Clique em continuar
Passo 5
A prxima tela ir perguntar se voc quer continuar a instalar o dispositivo. Clique em Instalar
para continuar.
Passo 6
A prxima tela indicar que o software foi instalado corretamente. Clique em fechar para termi-
nar a instalao.
Passo 7
Verificar se o driver est instalado e visivel no Gerenciador de dispositivos em Custom USB
Drivers>Microchip Custom USB Driver Abra a janela do gerenciador de dispositivos (Iniciar-
>Painel de controle->Sistema->Gerenciador de dispositivos). Se o driver no fora instalado
corretamente, continue na seo de soluo de erros (a seguir)
Soluo de erros
Se houve algum problema na instalao do driver siga os passos a seguir.
O Windows tentar instalar o driver mesmo se no encontrar o arquivo correto. No gerenci-
ador de dispositivos dentro da opo Outros dispositivos voc deve encontrar um Dispositivo
no conhecido.
Clique com o boto direito no Dispositivo no conhecido e selecione a opo Atualizar o
Driver do menu.
Na primeira tela de dilogo selecione Procurar no meu computador pelos arquivos do driver.
Continuar a partir do passo 4.