Você está na página 1de 118

1

Notas de Aula Programao Embarcada - ELT024

Rodrigo Maximiano Antunes de Almeida


Instituto de Engenharia de Sistemas e Tecnologia da Informao,
Universidade Federal de Itajub,
Minas Gerais,
Brasil
rodrigomax @ unifei.edu.br

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

2 Linguagem C para sistemas embarcados 9


. Indentao e padro de escrita . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
. Comentrios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
. Arquivos .c e .h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
. Diretivas de compilao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
#include . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
#define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
#ifdef, #ifndef, #else e #endif . . . . . . . . . . . . . . . . . . . . . . . . 14
. Tipos de dados em C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Representao binria e hexadecimal . . . . . . . . . . . . . . . . . . . . . 16
Modificadores de tamanho e sinal . . . . . . . . . . . . . . . . . . . . . . . 17
Modificadores de acesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Modificadores de posicionamento . . . . . . . . . . . . . . . . . . . . . . . 19
Modificador de persistncia . . . . . . . . . . . . . . . . . . . . . . . . . . 19
. Operaes aritmticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
. Funo main() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
. Rotinas de tempo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
. Operaes com bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
NOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
AND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
OR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
XOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Shift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Ligar um bit (bit set) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Desligar um bit (bit clear) . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Trocar o valor de um bit (bit flip) . . . . . . . . . . . . . . . . . . . . . . 28
Verificar o estado de um bit (bit test) . . . . . . . . . . . . . . . . . . . . 29
Criando funes atravs de defines . . . . . . . . . . . . . . . . . . . . . 30
. Debug de sistemas embarcados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Externalizar as informaes. . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Programao incremental . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Checar possveis pontos de Memory-leak . . . . . . . . . . . . . . . . . . . 35
Cuidado com a fragmentao da memria . . . . . . . . . . . . . . . . . . 35
Otimizao de cdigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Reproduzir e isolar o erro . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

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

4 Programao dos Perifricos 47


. Acesso s portasdo microcontrolador . . . . . . . . . . . . . . . . . . . . . . . . 48
. Configurao dos perifricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
. Barramento de Led's . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
. Display de 7 segmentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Multiplexao de displays . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Criao da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
. Leitura de teclas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Debounce por software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Arranjo de leitura por matriz . . . . . . . . . . . . . . . . . . . . . . . . . 62
Criao da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
. Display LCD 2x16 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Criao da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
. Comunicao serial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
RS 232 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Criao da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
. Conversor AD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Elementos sensores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Processo de converso AD . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Criao da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
. Sadas PWM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Criao da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
. Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
. Reproduo de Sons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
. Interrupo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
. Watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

5 Arquitetura de desenvolvimento de software 97


. One single loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
. Interrupt control system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
. Cooperative multitasking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Fixao de tempo para execuo dos slots . . . . . . . . . . . . . . . . . . 104
Utilizao do tempo livrepara interrupes . . . . . . . . . . . . . . . . . 105

6 Anexos 107
. config.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
. basico.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
. Instalar gravadores/depuradores de PIC em sistemas x64 . . . . . . . . . . . . . . 110

ii
Lista de Figuras

1.1 Camadas de abstrao de um sistema operacional . . . . . . . . . . . . . . . . . . 1


1.2 Pesquisa sobre linguagens utilizadas para projetos de software embarcado . . . . 2
1.3 Configurao das ferramentas de compilao . . . . . . . . . . . . . . . . . . . . . 5
1.4 Instalao do ICD2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.5 Resumo das configuraes do ICD2 no MPLAB . . . . . . . . . . . . . . . . . . . 6
1.6 Pedido de atualizao do firmware do ICD2 . . . . . . . . . . . . . . . . . . . . . 7
1.7 Project Explorer do MPLAB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.8 Comparativo de caractersticas da famlia PIC 18fxx5x . . . . . . . . . . . . . . . 8

2.1 Problema das Referncias Circulares . . . . . . . . . . . . . . . . . . . . . . . . . 15


2.2 Soluo das referncias circulares com #ifndef . . . . . . . . . . . . . . . . . . . . 16
2.3 Loop infinito de um device driver gerando erro no sistema . . . . . . . . . . . . . 22
2.4 Exemplo de funcionamento do vetor de interrupo . . . . . . . . . . . . . . . . . 22

3.1 Arquitetura do microcontrolador PIC 18F4550 . . . . . . . . . . . . . . . . . . . 39


3.2 Memria como um armrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.3 Memria e perifricos como um armrio . . . . . . . . . . . . . . . . . . . . . . . 41
3.4 Regies de memrias disponveis no PIC18F4550 . . . . . . . . . . . . . . . . . . 41
3.5 Esquema eltrico: Microcontrolador PIC 18F4550 . . . . . . . . . . . . . . . . . . 43
3.6 Registros de configurao do microcontrolador PIC 18F4550 . . . . . . . . . . . . 45

4.1 Registros de configurao dos perifricos do PIC 18F4550 . . . . . . . . . . . . . 50


4.2 Barramento de Led's . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
4.3 Display de 7 Segmentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
4.4 Diagrama eltrico para display de 7 segmentos com anodo comum . . . . . . . . . 54
4.5 Ligao de 4 displays de 7 segmentos multiplexados . . . . . . . . . . . . . . . . . 55
4.6 Circuito de leitura de chave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
4.7 Oscilao do sinal no momento do chaveamento . . . . . . . . . . . . . . . . . . . 60
4.8 Circuito de debounce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
4.9 Utilizao de filtro RC para debounce do sinal . . . . . . . . . . . . . . . . . . . . 61
4.10 Teclado em arranjo matricial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
4.11 Display Alfanumrico LCD 2x16 . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4.12 Display Alfanumrico LCD 2x16 - verso . . . . . . . . . . . . . . . . . . . . . . . 67
4.13 Caracteres disponveis para ROM A00 . . . . . . . . . . . . . . . . . . . . . . . . 68
4.14 Caracteres disponveis para ROM A02 . . . . . . . . . . . . . . . . . . . . . . . . 69
4.15 Esquemtico de ligao do display de LCD . . . . . . . . . . . . . . . . . . . . . . 71
4.16 Sinal serializado para transmisso em RS232 . . . . . . . . . . . . . . . . . . . . . 75
4.17 Lmpada incandescente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.18 Potencimetro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4.19 Potencimetro como divisor de tenso . . . . . . . . . . . . . . . . . . . . . . . . 80
4.20 Circuito integrado LM35 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4.21 Diagrama de blocos do LM35 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
4.22 Conversor analgico digital de 2 bits . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.23 Sinais PWM com variao do duty cycle . . . . . . . . . . . . . . . . . . . . . . . 85

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

1.1 Softwares utilizados no curso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.1 Tipos de dados e faixa de valores . . . . . . . . . . . . . . . . . . . . . . . . . . . 16


2.2 Representao decimal - binria - hexadecimal . . . . . . . . . . . . . . . . . . . . 17
2.3 Alterao de tamanho e sinal dos tipos bsicos . . . . . . . . . . . . . . . . . . . 18
2.4 Operao bit set com define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.5 Operao bit clear com define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.6 Operao bit flip com define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.7 Operao bit test com define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3.1 Quantidade de operaes e tarefas . . . . . . . . . . . . . . . . . . . . . . . . . . 42

4.1 Endereos de memria para as portas do PIC 18F4550 . . . . . . . . . . . . . . . 48


4.2 Tabela de configurao do PIC para as experincias . . . . . . . . . . . . . . . . . 51
4.3 Converso binrio - hexadecimal para displays de 7 segmentos . . . . . . . . . . . 55
4.4 Lista de comandos aceitos pelo o LCD . . . . . . . . . . . . . . . . . . . . . . . . 70
4.5 Taxas de transmisso para diferentes protocolos . . . . . . . . . . . . . . . . . . . 74
4.6 Clculo do valor da taxa de transmisso da porta serial . . . . . . . . . . . . . . . 76
4.7 Faixa de frequncias mximas e mnimas para cada configurao do prescaler . . 86

v
Lista de Programas

2.1 Resumo do disp7seg.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12


2.2 Resumo do disp7seg.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3 Estrutura de header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4 Operaes aritmticas com tipos diferentes . . . . . . . . . . . . . . . . . . . . . . 20
4.1 disp7seg.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
4.2 disp7seg.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
4.3 Utilizando a biblioteca disp7seg . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
4.4 teclado.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.5 teclado.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.6 Exemplo de uso da biblioteca teclado . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.7 lcd.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.8 lcd.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4.9 Exemplo de uso da biblioteca de LCD . . . . . . . . . . . . . . . . . . . . . . . . 73
4.10 serial.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.11 serial.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
4.12 Exemplo de uso da biblioteca de comunicao serial . . . . . . . . . . . . . . . . . 78
4.13 adc.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
4.14 adc.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
4.15 Exemplo de uso da biblioteca de conversores AD . . . . . . . . . . . . . . . . . . 84
4.16 pwm.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
4.17 pwm.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
4.18 Exemplo de uso da biblioteca das sadas PWM . . . . . . . . . . . . . . . . . . . 88
4.19 timer.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
4.20 timer.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
4.21 Exemplo de uso da biblioteca de um temporizador . . . . . . . . . . . . . . . . . 90
4.22 Reproduo de sons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
4.23 Fontes de Interupo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
4.24 Tratamento das interrupes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
4.25 Inicializao do sistema com interrupes . . . . . . . . . . . . . . . . . . . . . . 95
4.26 Inicializao do sistema com interrupes . . . . . . . . . . . . . . . . . . . . . . 96
5.1 Exemplo de arquitetura single-loop . . . . . . . . . . . . . . . . . . . . . . . . . . 98
5.2 Problema na sincronia de tempo para o single-loop . . . . . . . . . . . . . . . . . 98
5.3 Exemplo de sistema Interrupt-driven . . . . . . . . . . . . . . . . . . . . . . . . . 99
5.4 Exemplo de sistema Interrupt-driven com base de tempo . . . . . . . . . . . . . . 100
5.5 Exemplo de cooperative multitasking . . . . . . . . . . . . . . . . . . . . . . . . . 102
5.6 Exemplo de cooperative multitasking com uso do top slot . . . . . . . . . . . . . 103
5.7 Exemplo de sistema Cooperative-multitasking com slot temporizado . . . . . . . 104
6.1 config.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
6.2 basico.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

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

Figura 1.1: Camadas de abstrao de um sistema operacional

Para sistemas embarcados, necessrio programar especificamente para o hardware em ques-


to. Uma opo para se obter artificialmente esta camada de abstrao que era gerada pelo
sistema operacional a utilizao de dois itens: um compilador prprio para o componente em
questo e uma biblioteca de funes. O compilador ser o responsvel por traduzir a linguagem
de alto nvel em uma linguagem que o microcontrolador consegue entender. A biblioteca de
funes, ou framework, em geral, disponibilizada pelos fabricantes do microcontrolador.

. 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

Tambm a escolha da maioria dos programadores e gerentes de projetos no que concerne


ao desenvolvimento de sistemas embarcados como pode ser visto na Figura 1.2.

Figura 1.2: Pesquisa sobre linguagens utilizadas para projetos de software embarcado
Fonte: http://www.embedded.com/design/218600142

A descontinuidade depois de 2004 se d devido mudana de metodologia da pesquisa. Antes


de 2005, a pergunta formulada era: Para o desenvolvimento da sua aplicao embarcada, quais
das linguagens voc usou nos ltimos 12 meses?. Em 2005 a pergunta se tornou: Meu projeto
embarcado atual programado principalmente em ______. Mltiplas selees eram possveis
antes de 2005, permitindo a soma superior a 100%, sendo o valor mdio de 209%, o que implica
que a maioria das pessoas escolheu duas ou mais opes.
O maior impacto na pesquisa pode ser visualizado na linguagem assembler: at 2004, estava
presente em 62% das respostas (na mdia). O que comprova que praticamente todo projeto de
sistema embarcado exige um pouco de assembler. Do mesmo modo, percebemos que atualmente
poucos projetos so realizados totalmente ou em sua maioria em assembler, uma mdia de apenas
7%.

. Hardware utilizado
People who are really serious about software should make their own
hardware. - Alan Kay

Como o enfoque deste curso a programao de sistemas embarcados e no a eletrnica, utili-


zaremos um kit de desenvolvimento pronto, baseado num microcontrolador PIC.
Como perifricos disponveis temos:

1 display LCD 2 linhas por 16 caracteres (compatvel com HD77480)

4 displays de 7 segmentos com barramento de dados compartilhados

8 leds ligados ao mesmo barramento dos displays

16 mini switches organizadas em formato matricial 4x4

1 sensor de temperatura LM35C

1 resistncia de aquecimento ligada a uma sada PWM

1 motor DC tipo ventilador ligado a uma sada PWM

1 buzzer ligado a uma sada PWM

Notas de Aula ELT024 - Programao para Sistemas Embarcados


3 Introduo

1 canal de comunicao serial padro RS-232

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

O ambiente utilizado ser o MPLAB(R). Este um ambiente de desenvolvimento disponibilizado


pela Microchip(R) gratuitamente. O compilador utilizado ser o SDCC, os linkers e assemblers
sero disponibilizados pela biblioteca GPUtils.
Como o foco a aprendizagem de conceitos sobre programao embarcada, poder ser uti-
lizada qualquer plataforma de programao e qualquer compilador/linker. Caso seja utilizado
qualquer conjunto de compilador/linker diferentes deve-se prestar ateno apenas nas diretivas
para gravao.
Para a programao em ambiente Linux recomenda-se o uso da sute PIKLAB 15.10. Este
programa foi desenvolvido para KDE 3.5. Alm de permitir a integrao com o mesmo compilador
utilizado neste curso permite a programao do microcontrolador utilizando o programador ICD2
via USB.

Instalao
A Tabela 1.1 apresenta os softwares que sero utilizados no curso.

Tabela 1.1: Softwares utilizados no curso

Item Verso Licena


IDE MPLAB 8.50 Proprietrio
Compilador SDCC 2.9.00 (win32) GPL
Linker/Assembler GPUtils 0.13.7 (win32) GPL
Plugin MPLAB sdcc-mplab 0.1 GPL

Todos os softwares so gratuitos e esto disponveis na internet. Para correta instalao


deve-se instalar os softwares segundo a sequncia apresentada na Tabela 1.1. Anote o diretrio
onde cada software foi instalado.
Aps a instalao dos softwares deve-se abrir o arquivo pic16devices.txt (de preferncia no
wordpad) que foi instalado no diretrio do SDCC dentro da pasta include\pic16 (por padro
C:\Arquivos de programas\SDCC\include\pic16). No windows vista e windows 7 no possvel
editar arquivos de sistema. Neste caso clique no arquivo com o boto direito > Propriedades >
Segurana > Editar > Usurios e selecionar a opo Controle Total, depois clique em ok. Aps
isso ser possvel editar o arquivo. Procure ento a seguintes linhas:

name 18f4550
using 18f2455

Trocar a letra f minscula da primeira linha, apenas do 18f4550, para um F maisculo:

name 18F4550
using 18f2455

Notas de Aula ELT024 - Programao para Sistemas Embarcados


4 Introduo

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:

// Microchip Language Tools


// Configuration File
// gplink
// Craig Franklin [5]
[Tool] Description=Library directories
Tool=gplink Switch=-I
ScriptExtension=lkr Data=1
DefaultOptions= MultipleOptions=0
MultipleNodes=1 LibrarySwitch=Switch
SpaceBetweenSwitchAndData=1 Hidden=1
[0] [6]
Description=Output filename Description=Linker script directories
Switch=-o Switch=-I
Data=1 Data=1
MultipleOptions=0 MultipleOptions=0
OutputNameSwitch=Switch LinkerScriptSwitch=Switch
Hidden=1 Hidden=1
[1] [7]
Description=Map file Description=Use Shared Memory
Switch=-m Switch=-r
Data=0 Data=0
MultipleOptions=0 [8]
[2] Description=Fill Value
Description=COFF File Switch=-f
Switch=-c MultipleOptions=0
Data=0 Data=1
MultipleOptions=0 [9]
[3] Description=Stack Size
Description=Hex Format Switch=-t
OptionList=INHX8M;INHX8S;INHX32 MultipleOptions=0
INHX8M=-a INHX8M Data=1
INHX8S=-a INHX8S [10]
INHX32=-a INHX32 Description=No List File
Data=0 switch=-l
[4] Data=0
Description=Quiet mode
Switch=-q
Data=0

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.

Configurao do gravador ICD2


Aps instalar o MPLAB j possvel fazer a instalao e configurao do gravador ou depurador
ICD2. Conecte-o a qualquer porta USB e aguarde a tela de instalao do Windows. Em algumas
verses do windows pode acontecer de voc ser perguntado se deseja instalar um software no

Notas de Aula ELT024 - Programao para Sistemas Embarcados


5 Introduo

Figura 1.3: Configurao das ferramentas de compilao

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.

Criao de um novo projeto


Recomenda-se a utilizao do assistente disponvel para a criao de um novo projeto (menu
Project -> Project Wizard). Ele ir questionar sobre (entre parnteses os valores adotados neste
curso):

1. O microcontrolador a ser utilizado (PIC18F4550)

2. A sute de compilao (SDCC 16)

3. O diretrio e nome do projeto

4. Arquivos j existentes cujo programador deseja incluir no projeto

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


6 Introduo

Figura 1.4: Instalao do ICD2

Figura 1.5: Resumo das configuraes do ICD2 no MPLAB

Notas de Aula ELT024 - Programao para Sistemas Embarcados


7 Introduo

Figura 1.6: Pedido de atualizao do firmware do ICD2

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.

Figura 1.7: Project Explorer do MPLAB

Alm dos arquivos criados pelo programador, existem trs arquivos que devem ser adicionados
ao projeto: um de linker e dois de bibliotecas.

1. Linker

(a) C:\Arquivos de programas\gputils\lkr\18f4550.lkr

2. Bibliotecas

(a) C:\Arquivos de programas\SDCC\lib\pic16\libdev18f4550.lib


(b) C:\Arquivos de programas\SDCC\lib\pic16\18f4550.lkr

O arquivo de linker o responsvel por indicar quais so os espaos de memria disponveis


no chip utilizado, onde comeam e de que tipo so (RAM, ROM, Flash) etc.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


8 Introduo

// 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 .

CODEPAGE NAME=page START=0x0 END=0x7FFF


CODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTED
CODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTED
CODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED
CODEPAGE NAME=eedata START=0xF00000 END=0xF000FF PROTECTED

ACCESSBANK NAME=accessram START=0x0 END=0x5F


DATABANK NAME=gpr0 START=0x60 END=0xFF
DATABANK NAME=gpr1 START=0x100 END=0x1FF
DATABANK NAME=gpr2 START=0x200 END=0x2FF
DATABANK NAME=gpr3 START=0x300 END=0x3FF
DATABANK NAME=usb4 START=0x400 END=0x4FF PROTECTED
DATABANK NAME=usb5 START=0x500 END=0x5FF PROTECTED
DATABANK NAME=usb6 START=0x600 END=0x6FF PROTECTED
DATABANK NAME=usb7 START=0x700 END=0x7FF PROTECTED
ACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF PROTECTED

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.

Figura 1.8: Comparativo de caractersticas da famlia PIC 18fxx5x

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

Notas de Aula ELT024 - Programao para Sistemas Embarcados


Captulo 2

Linguagem C para sistemas embarcados

C is quirky, flawed, and an enormous success. - Dennis M. Ritchie

A programao para sistemas embarcados possui diversas caractersticas diferentes da progra-


mao voltada para desktop. Do mesmo modo, existem alguns conceitos que geralmente no so
explorados nos cursos de linguagens de programao em C, mas que so essenciais para o bom
desenvolvimento deste curso. Estes conceitos sero explanados neste captulo.

. Indentao e padro de escrita


Good programmers use their brains, but good guidelines save us
having to think out every case. - Francis Glassborow

fundamental obedecer um padro para escrita de programas, de modo que a visualizao do


cdigo seja facilitada.
Na lngua portuguesa utilizamos pargrafos para delimitar blocos de frases que possuem a
mesma ideia. Em linguagem C estes blocos so delimitados por chaves { e }.
Para demonstrar ao leitor que um pargrafo comeou utilizamos um recuo direita na pri-
meira linha. Quando necessrio realizar uma citao de itens coloca-se cada um destes itens
numa linha recuada direita, algumas vezes com um identificador como um trao - ou seta
-> para facilitar a identificao visual.
Com esse mesmo intuito, os recuos e espaamentos so utilizados para que o cdigo seja mais
facilmente entendido.
Como todo bloco de comandos iniciado e terminado com uma chave, tornou-se comum que
estas (as chaves) estejam no mesmo nvel e todo cdigo interno a elas seja deslocado direita. Se
existir um segundo bloco interno ao primeiro, este deve ser deslocado duas vezes para indicar a
hierarquia no fluxo do programa. Segue abaixo um exemplo de um mesmo cdigo com diferena
apenas na indentao.

9
10 Linguagem C para sistemas embarcados

Cdigo indentado Cdigo no indentado

1 void main ( void ) interrupt 0 void main ( void ) interrupt 0


{ {
unsigned i n t i ; unsigned i n t i ;
unsigned i n t temp ; unsigned i n t temp ;
unsigned i n t teclanova =0; unsigned i n t teclanova =0;
InicializaSerial ( ) ; InicializaSerial ( ) ;
InicializaDisplays ( ) ; InicializaDisplays ( ) ;
InicializaLCD ( ) ; InicializaLCD ( ) ;
InicializaAD ( ) ; InicializaAD ( ) ;
for ( ; ; ) for ( ; ; )
{ {
AtualizaDisplay ( ) ; AtualizaDisplay ( ) ;
i f ( teclanova != Tecla ) i f ( teclanova != Tecla )
{ {
teclanova = Tecla ; teclanova = Tecla ;
f o r ( i =0;i <16; i++) f o r ( i =0;i <16; i++)
{ {
i f ( BitTst ( Tecla , i ) ) i f ( BitTst ( Tecla , i ) )
{ {
EnviaDados ( i+48) ; EnviaDados ( i+48) ;
} }
} }
} }
f o r ( i = 0 ; i < 1 0 0 0 ; i++) ; f o r ( i = 0 ; i < 1 0 0 0 ; i++) ;
} }
} }

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:

i f ( PORTA == 0 x30 ) { PORTB = 0 x10 ; }

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

Notas de Aula ELT024 - Programao para Sistemas Embarcados


11 Linguagem C para sistemas embarcados

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.

#include <s t d i o . h>


#define DIST 260 // d i s t a n c i a e n t r e SP e I t a
i n t main ( i n t argc , char argv [ ] )
{
/ e s s e programa s e r v e para
m o s t r ar como s e i n s e r e c o m e n t r i o s /
printf ( " So Paulo est %d Km de Itajub " , DIST ) ;
return 0 ;
}

. 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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


12 Linguagem C para sistemas embarcados

Programa 2.1: Resumo do disp7seg.c


1 // v a r i v e l usada apenas d e n t r o d e s t e a r q u i v o
2 s t a t i c char temp ;
3 // v a r i v e l que s e r usada tambm f o r a do a r q u i v o
4 s t a t i c char valor ;
5 // f u n e s u s a d a s d e n t r o e f o r a do a r q u i v o
6 void MudaDigito ( char val )
7 {
8 valor = val ;
9 }
10 char LerDigito ( void )
11 {
12 return valor ;
13 }
14 void InicializaDisplays ( void )
15 {
16 // c d i g o da f u n o
17 }
18 // f u n o usada apenas d e n t r o d e s t e a r q u i v o
19 void AtualizaDisplay ( void )
20 {
21 // c d i g o da f u n o
22 }

Programa 2.2: Resumo do disp7seg.h


1 #i f n d e f VAR_H
2 #define VAR_H
3 void MudaDigito ( char val ) ;
4 char LerDigito ( void ) ;
5 void InicializaDisplays ( void ) ;
6 #endif //VAR_H

Notas de Aula ELT024 - Programao para Sistemas Embarcados


13 Linguagem C para sistemas embarcados

#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.

Original Compilado Resultado na Tela

#define CONST 15
void main ( void )
void main ( void )
{
{ 45
printf ( "%d" , 15 3 ) ;
printf ( "%d" , CONST 3 ) ;
}
}

Funo Original Opes de uso com o #define Resultado na Tela

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 ) ;
}

#include <s t d i o . h>


#define PADRAO LCD
void main ( void )
LCD
{
MostraSaidaPadrao ( ) ;
}

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


14 Linguagem C para sistemas embarcados

#ifdef, #ifndef, #else e #endif


As diretivas #ifdef, #ifndef, #else e #endif so muito utilizadas quando queremos gerar dois
programas que diferem apenas num pequeno pedao de cdigo. Por exemplo dois sistemas de
controle de temperatura. O primeiro possui um display de LCD, capaz de mostrar a temperatura
textualmente. O segundo sistema executa a mesma funo que o primeiro, mas um dispositivo
mais barato, portanto possui apenas um led indicativo de sobretemperatura. O cdigo pode ser
escrito da seguinte maneira

void ImprimirTemp ( char valor )


{
#ifdef LCD
Imprime_LCD ( valor )
#e l s e
i f ( valor > 3 0 )
{
led = 1 ;
}
else
{
led = 0 ;
}
#endif //LCD
}

No momento da compilao o pr-compilador ir verificar se a tag LCD foi definida em


algum lugar. Em caso positivo o pr-compilador ir deixar tudo que estiver entre o #ifdef e o
#else e retirar tudo que est entre o #else e o #endif.
Outra funo muito utilizada destas diretivas para evitar a referncia circular. Supondo dois
arquivos, um responsvel pela comunicao serial (serial.h) e o segundo responsvel pelo controle
de temperatura (temp.h). O projeto exige que a temperatura possa ser controlada pela porta
serial e toda vez que a temperatura passar de um determinado patamar deve ser enviado um
alerta pela porta serial. O aquivo da porta serial (serial.h) tem as seguintes funes, apresentadas
a seguir.

char LerSerial ( void ) ;


void EnviaSerial ( char val ) ;

O arquivo de controle da temperatura (temp.h) possui as funes apresentadas a seguir.

char LerTemperatura ( void ) ;


void AjustaCalor ( char val ) ;

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.

#include " serial .h"


char LerTemperatura ( void ) ;
void AjustaCalor ( char val ) ;

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

#include " temp .h"


char LerSerial ( void ) ;
void EnviaSerial ( char val ) ;

Notas de Aula ELT024 - Programao para Sistemas Embarcados


15 Linguagem C para sistemas embarcados

Programa 2.3: Estrutura de header


1 #i f n d e f TAG_CONTROLE
2 #define TAG_CONTROLE
3 // t o d o o c o n t e d o do a r q u i v o vem a q u i .

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);

Figura 2.1: Problema das Referncias Circulares

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

Notas de Aula ELT024 - Programao para Sistemas Embarcados


16 Linguagem C para sistemas embarcados

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

temp.h char LerSerial(void);


void EnviaSerial(char val);
#infdef TEMP_H #endif

//tag j definida,
//pula o contedo

#endif

Figura 2.2: Soluo das referncias circulares com #ifndef

C so apresentados na Tabela 2.1.

Tabela 2.1: Tipos de dados e faixa de valores

Tipo Bits Bytes Faixa de valores


char 8 1 -127 127
int 16 2 -32.768 32.767
float 32 4 3,4 x 10-38 3,4 x 1038
double 64 8 3,4 x 10-308 3,4 x 10308

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.

Representao binria e hexadecimal


A grande maioria dos processadores trabalha com dados binrios, ou seja, aqueles que apenas
assumem valores 0 ou 1. Por isso os tipos apresentados anteriormente podem ser representados
utilizando a base 2. Um valor do tipo char que possui 8 bits ser representado por um nmero
de 8 algarismos, todos 0 (zeros) ou 1 (uns). Para realizarmos a converso de um nmero na base
decimal para a base 2 podemos seguir o seguinte algoritmo:

1. Dividir o nmero por 2

2. Anotar o valor do resto (0 ou 1)

3. Se o valor maior que 0 voltar ao nmero 1

4. Escrever os valores obtidos atravs do passo 2 de trs para frente.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


17 Linguagem C para sistemas embarcados

5. Apresentar o resultado

Por exemplo o nmero 18.


18/2 = 9, resto 0
9/2 = 4, resto 1
4/2 = 2, resto 0
2/2 = 1, resto 0
1/2 = 0, resto 1
Lendo do ltimo resultado para o primeiro temos que
1810 = 100102
Devido a grande utilizao de nmeros binrios na programao de baixo nvel muito comum
escrevemos estes nmeros na base 16 ou hexadecimal. A vantagem de escrever o nmero nesta
base que existe uma converso simples de binrio para hexadecimal e o nmero resultante
ocupa bem menos espao na tela.
A base hexadecimal possui 16 "unidades"diferentes. Como existem apenas 10 algarismos no
sistema de numerao arbico (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) utilizamos 6 letras para complement-los
(A, B, C, D, E, F). A converso entre valores binrios, decimais e hexadecimais apresentada
na Tabela 2.2.
Tabela 2.2: Representao decimal binria - hexadecimal

Decimal Binrio Hexadecimal Decimal Binrio Hexadecimal


0 0000 0 8 1000 8
1 0001 1 9 1001 9
2 0010 2 10 1010 A
3 0011 3 11 1011 B
4 0100 4 12 1100 C
5 0101 5 13 1101 D
6 0110 6 14 1110 E
7 0111 7 15 1111 F

Para converter de binrio para hexadecimal basta dividir o nmero em grupos de 4 em 4, da


esquerda para a direita, e utilizar a tabela acima.
Por exemplo o nmero 18. Sabemos que este nmero em binrio representado por 100102 .
Separando o nmero de 4 em 4 algarismos temos:
1-0010
Pela tabela:
12 = 116
00102 = 216 .
Logo:
100102 . = 1216 .

Modificadores de tamanho e sinal


Um modificador de tipo altera o significado dos tipos base e produz um novo tipo. Existem
quatro tipos de modificadores, dois para o tamanho (long e short) e dois para sinal (unsigned
e signed). Um tipo declarado com o modificador long pode ter tamanho MAIOR ou IGUAL
ao tipo original. Um tipo declarado como short deve ter tamanho MENOR ou IGUAL ao tipo
original. A deciso cabe ao compilador utilizado.
Os tipos declarados como signed possuem um bit reservado para o sinal, deste o valor mximo
que podem atingir menor. Os tipos declarados como unsigned no podem assumir valores

Notas de Aula ELT024 - Programao para Sistemas Embarcados


18 Linguagem C para sistemas embarcados

negativos, em compensao podem atingir o dobro do valor de um tipo signed. Na Tabela 2.3
so apresentadas algumas variaes possveis.

Tabela 2.3: Alterao de tamanho e sinal dos tipos bsicos

Tipo Bytes Excurso mxima


unsigned char 1 0 255
signed char 1 -128 127
unsigned int 2 0 65.535
signed int 2 -32.768 32.767
long int 4 -2.147.483.648 2.147.483.647
unsigned long int 4 0 4.294.967.295
short int 2 -32.768 32.767

Na linguagem C, por padro os tipos so sinalizados, ou seja, possuem parte positiva e


negativa. Por isso raro encontrar o modificador signed.

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:

#define X ( ( n e a r unsigned char ) 0xF83 )


void main ( void ) interrupt 0
{
while ( X!=X ) ;
}

Quando compilado apresenta o seguinte cdigo em assembler:

// 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

Enquanto a varivel x for diferente de x o programa no sai do loop. O compilador


entende que esta condio nunca ir acontecer e elimina o loop do cdigo final como podemos
ver no cdigo gerado, a rotina de return est logo aps a inicializao do programa _main. Para
variveis comuns o valor s alterado em atribuies diretas de valor ou de outras variveis: (x
= 4;) ou (x = y;).
Entretanto existe uma condio onde a varivel x pode alterar seu valor independentemente
do programa. Se esta varivel representar um endereo de memria associado um perifrico
fsico, seu valor pode mudar independentemente do fluxo do programa. Para indicar esta situao
ao programa utilizamos a palavra reservada volatile.

#define X ( ( v o l a t i l e n e a r unsigned char ) 0xF83 )


void main ( void ) interrupt 0
{
while ( X!=X ) ;
}

Gerando o cdigo em assembler descrito abaixo:

Notas de Aula ELT024 - Programao para Sistemas Embarcados


19 Linguagem C para sistemas embarcados

// 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.

#define X ( ( v o l a t i l e const n e a r unsigned char ) 0xF83 )


// i n i c i o do programa
void main ( void ) interrupt 0
{
X = 3;
}

Se tentarmos compilar este cdigo aparecer a seguinte mensagem de erro:

Teste . c : error 3 3 : Attempt to assign value to a constant variable (=)

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

Notas de Aula ELT024 - Programao para Sistemas Embarcados


20 Linguagem C para sistemas embarcados

Programa 2.4: Operaes aritmticas com tipos diferentes


1 void main ( void )
2 {
3 char var08 ;
4 i n t var16 ;
5 long i n t var32 ;
6 f l o a t pont16 ;
7 double pont32 ;
8 var8 = var8 + var16 ; // 1
9 var8 = var8 + var8 ; // 2
10 var16 = var8 var8 ; // 3
11 var32 = var32 / var16 ; // 4
12 var32 = pont32 var32 ; // 5
13 pont16 = var8 / var16 ; // 6
14 pont16 = pont32 var32 ; // 7
15 pont16 = 40 / 8 0 ; // 8
16 }

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.

var32 = var8 + var16 ; // 1 c o r r i g i d o

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.

var16 = var8 + var8 ; // 2 c o r r i g i d o

Notas de Aula ELT024 - Programao para Sistemas Embarcados


21 Linguagem C para sistemas embarcados

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.

var16 = ( ( i n t ) var8 ) var8 ; // 3 c o r r i g i d o

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.

pont16 = ( ( f l o a t ) var8 ) / var16 ; // 6 c o r r i g i d o

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

Notas de Aula ELT024 - Programao para Sistemas Embarcados


22 Linguagem C para sistemas embarcados

Figura 2.3: Loop infinito de um device driver gerando erro no sistema

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 ...

Figura 2.4: Exemplo de funcionamento do vetor de interrupo

A maneira de indicar o ponto de incio de um programa depende do compilador. Em geral os

Notas de Aula ELT024 - Programao para Sistemas Embarcados


23 Linguagem C para sistemas embarcados

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.

void main ( void ) interrupt 0


{
// a q u i e n t r a o c d i g o do programa
}

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.

void main ( void ) interrupt 0 void main ( void ) interrupt 0


{ {
for ( ; ; ) while ( 1 )
{ {
// a q u i e n t r a o // a q u i e n t r a o
// c d i g o p r i n c i p a l // c d i g o p r i n c i p a l
} }
} }

. 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.

// c d i g o em a s s e m b l e r e q u i v a l e n t e f o r ( i =0; i <10; i ++) ;


MOVF r0x00 , W // i n i c i a l i z a W com 0 (1 c i c l o )
SUBLW 0 x0a // c o l o c a o v a l o r 10 (0 x0a ) no r e g i s t r o W (1 c i c l o )
MOVWF r0x00 //muda o v a l o r de W para F (1 c i c l o )
_00107_DS_ :
1
Em sistemas mais complexos algumas tarefas so executadas independentemente da funo principal, tendo
sua execuo controlada atravs de interrupes.
2
Este mtodo no aconselhado em sistemas de maior porte.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


24 Linguagem C para sistemas embarcados

DECFSZ r0x00 , F // decrementa F , s e F > 0 e x e c u t a a prxima l i n h a (1 c i c l o )


BRA _00107_DS_ // " p u l a " para o l u g a r marcado como _00107_DS_ (2 c i c l o s )

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.

void delay ( unsigned i n t DL )


{
unsigned char i , j , k ;
while ( DL) // e x e c u t a DL v e z e s .
{
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
}
}
}
}

. Operaes com bits


All of the books in the world contain no more information than is
broadcast as video in a single large American city in a single year.
Not all bits have equal value. - Carl Sagan
Este valor s valido quando estamos trabalhando com variveis char. Se utilizarmos variveis int o cdigo
3

em assembler ser diferente e teremos que realizar uma nova anlise.


4
Para 8MHz, 1 ciclo = 0.125s. No PIC, cada instruo precisa de 4 ciclos de clock, portanto 0.5s.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


25 Linguagem C para sistemas embarcados

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.

Declarao Lgico Bitwise

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:

Declarao Lgico Bitwise

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


26 Linguagem C para sistemas embarcados

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:

Declarao Lgico Bitwise

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:

Declarao Lgico Bitwise


result = A ^ B ;
char A = 8;
// r e s u l t = 13
// A = 0 b00001000
// no e x i s t e em C // A = 0 b00001000
char B = 5;
// B = 0 b00000101
// B = 0 b00000101
// r = 0 b00001101

Shift
A operao shift desloca os bits para a esquerda (operador <<) ou direita (operador >>).
necessrio indicar quantas casas sero deslocadas.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


27 Linguagem C para sistemas embarcados

Declarao Shift Esquerda Shift Direita

result = A << 2 ; result = A >> 2 ;


char A = 8 ; // r e s u l t = 32 // r e s u l t = 2
// A = 0 b00001000 // A = 0 b00001000 // A = 0 b00001000
// r = 0 b00100000 // r = 0 b00000010

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.

Ligar um bit (bit set)


Para ligar apenas um bit, utilizaremos uma operao OU. Supondo dois operandos A e B. Se A
1 o resultado de (A | B) 1 independente de B. Se A 0 o resultado igual ao valor de B.
Se o objetivo ligar apenas o bit da posio X devemos criar um valor onde todas as posies
so 0's com exceo da posio desejada. Para uma mscara binria de N bits temos (N>=X):

Posio N . . . X+1 X X-1 . . . 0


Valor 0 ... 0 1 0 ... 0

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 ( ; ; ) ;
}

Notas de Aula ELT024 - Programao para Sistemas Embarcados


28 Linguagem C para sistemas embarcados

Desligar um bit (bit clear)


Para desligar apenas um bit o procedimento similar ao utilizado para ligar. Ao invs de utilizar-
mos uma operao OU, utilizaremos uma operao AND. A operao AND tem a caracterstica
de, dados A e B valores binrios, se A 1, a resposta de (A & B) ser o prprio valor de B, se a
A=0, a resposta zero, independente de B.
Novamente necessrio gerar uma mscara. Mas para esta situao ela deve possuir todos
os bits iguais um com exceo de X, o bit que queremos desligar.

posio N . . . X+1 X X-1 . . . 0


Valor 1 ... 1 0 1 ... 1

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.

Trocar o valor de um bit (bit flip)


Para trocar o valor de um bit utilizaremos como artifcio algbrico a operao XOR. Dado duas
variveis binrias A e B , se A 1, o valor resultante de A XOR B o oposto do valor de B, se
A=0, a resposta se mantm igual ao valor de B.
Podemos perceber que para trocar o valor de apenas um bit a mscara ser idntica quela
utilizada para ligar um bit:

posio N . . . X+1 X X-1 . . . 0


Valor 0 ... 0 1 0 ... 0

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

Notas de Aula ELT024 - Programao para Sistemas Embarcados


29 Linguagem C para sistemas embarcados

// 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 ( ; ; ) ;
}

Percebemos atravs do exemplo que a utilizao do procedimento apresentado troca o valor


do bit escolhido. Foi utilizado o mesmo procedimento duas vezes. Na primeira, um bit foi ligado
e, na segunda, outro foi desligado.

Verificar o estado de um bit (bit test)


Para verificar se o bit X est um utilizaremos novamente a mesma mscara utilizada para bit set
e bit toggle:

posio N . . . X+1 X X-1 . . . 0


Valor 0 ... 0 1 0 ... 0

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


30 Linguagem C para sistemas embarcados

}
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 ( ; ; ) ;
}

Criando funes atravs de defines


Uma opo no uso de defines criar funes simples que podem ser escritas em apenas uma
linha. Utilizando um pouco de algebrismo e parnteses, possvel escrever as quatro operaes
anteriores numa nica linha. De posse desta simplificao podemos criar uma funo para facilitar
o uso destas operaes atravs de um define conforme podemos ver nas tabelas 2.4, 2.5, 2.6 e
2.7.
Tabela 2.4: Operao bit set com define

Operao Bit set

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) ;

Com define #define B i t S e t ( arg , b i t ) ( ( a r g ) |= (1<< b i t ) )

Exemplo de uso com de- // Ligando o b i t 2 da p o r t a D


fine BitSet ( PORTD , 2 ) ;

Notas de Aula ELT024 - Programao para Sistemas Embarcados


31 Linguagem C para sistemas embarcados

Tabela 2.5: Operao bit clear com define

Operao Bit clear

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) ;

Com define #define B i t C l r ( arg , b i t ) ( ( a r g ) &= ~(1<< b i t ) )

Exemplo de uso com de- // D e s l i g a n d o o b i t 2 da p o r t a D


fine BitClr ( PORTD , 2 ) ;

Notas de Aula ELT024 - Programao para Sistemas Embarcados


32 Linguagem C para sistemas embarcados

Tabela 2.6: Operao bit flip com define

Operao Bit flip

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) ;

Com define #define B i t F l p ( arg , b i t ) ( ( a r g ) ^= (1<< b i t ) )

Exemplo de uso com de- // Trocando o v a l o r do b i t 2 da p o r t a D


fine BitFlp ( PORTD , 2 ) ;

Notas de Aula ELT024 - Programao para Sistemas Embarcados


33 Linguagem C para sistemas embarcados

Tabela 2.7: Operao bit test com define

Operao Bit test

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 {
// . . .
}

Com define #define B i t T s t ( arg , b i t ) ( ( a r g ) & (1<< b i t ) )

// Testando o b i t 2 da p o r t a D
i f ( BitTst ( PORTD , 2 ) )
Exemplo de uso com de- {
fine // . . .
}

Notas de Aula ELT024 - Programao para Sistemas Embarcados


34 Linguagem C para sistemas embarcados

. Debug de sistemas embarcados7


In the beginner's mind there are many possibilities; in the expert's
mind there are few. - Shunryu Suzuki
A verificao de sistemas embarcados apresenta algumas restries e de modo geral no possvel
inferir sobre a operao do sistema sem paralis-lo. Como este tipo de sistema possui vrios
dispositivos agregados, que funcionam independentemente do processador, necessrio utilizar
abordagens diferentes para realizar o debug.
Devemos lembrar que alm do software devemos levar em conta possveis problemas advindos
do hardware. Debounce, tempo de chaveamento, limite do barramento de comunicao so
exemplos de pontos a serem considerados no momento de depurao.

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.

#include " stdio .h"


#include " serial .h"
// i n i c i o do programa
i n t main ( i n t argc , char argv [ ] )
{
printf ( " Inicializando sistema " ) ;
i f ( CheckForData ( ) )
{
printf ( " Chegou informacao " ) ;
}
else
{
printf ( " Problemas na comunicacao " ) ;
}
return 0 ;
}

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

ging de Stan Schneider e Lori Fraleigh


8
As variveis PORTD e TRISD so definidas como unsigned char e possuem portanto 8 bits.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


35 Linguagem C para sistemas embarcados

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.

Checar possveis pontos de Memory-leak


Se for necessrio realizar alocao dinmica garantir que todas as alocaes so liberadas em
algum ponto do programa.

Cuidado com a fragmentao da memria


Sistemas com grande frequncia na alocao/liberao de memria podem fragmentar a memria
at o ponto de inviabilizar os espaos livres disponveis, eventualmente travando o sistema.
Quando trabalhar com rotinas de nvel mais baixo, mais prximo ao hardware, tente utilizar
apenas mapeamento esttico de memria.

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.

Reproduzir e isolar o erro


Quando houver algum erro deve-se primeiro entender como reproduzi-lo. No possvel tentar
corrigir o erro se no houver maneira de verificar se ele foi eliminado.
No momento em que se consegue um procedimento de como reproduzir o erro podemos
comear a visualizar onde ele pode estar. A partir deste momento devemos isolar onde o erro
est acontecendo. Uma maneira de se fazer isto em sistemas embarcados colocar um loop
infinito dentro de um teste, que visa verificar alguma condio de anomalia. Se o sistema entrar
neste teste devemos sinalizar atravs dos meios disponveis, ligar/desligar algum led por exemplo.

// 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 . . .

Notas de Aula ELT024 - Programao para Sistemas Embarcados


36 Linguagem C para sistemas embarcados

. Ponteiros e endereos de memria


Writing in C or C++ is like running a chain saw with all the safety
guards removed. - Bob Gray
Toda varivel criada armazenada em algum lugar da memria. Este lugar definido de maneira
nica atravs de um endereo.
Para conhecermos o endereo de uma varivel podemos utilizar o operador &. Cuidado! Este
operador tambm utilizado para realizao da operao bitwise AND. Exemplo:

// 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:

tipo nome da variavel ;

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

Notas de Aula ELT024 - Programao para Sistemas Embarcados


37 Linguagem C para sistemas embarcados

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


Captulo 3

Arquitetura de microcontroladores

Any sufficiently advanced technology is indistinguishable from ma-


gic. - Arthur C. Clarke

Os microcontroladores so formados basicamente por um processador, memria e perifricos


interligados atravs de um barramento conforme Figura 3.1.
Em geral, os perifricos so tratados do mesmo modo que a memria, ou seja, para o pro-
cessador no existe diferena se estamos tratando com um valor guardado na memria RAM ou
com o valor da leitura de um conversor analgico digital. Isto acontece porque existem circuitos
eletrnicos que criam um nvel de abstrao em hardware. Deste modo todos os dispositivos
aparecem como endereos de memria.

38
39 Arquitetura de microcontroladores

Figura 3.1: Arquitetura do microcontrolador PIC 18F4550

Notas de Aula ELT024 - Programao para Sistemas Embarcados


40 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

Figura 3.2: Memria como um armrio

Ao invs de gavetas o marceneiro pode pensar em colocar outros sistemas de armazenamento


nos espaos (Figura 3.3). Alguns destes sistemas podem permitir que o usurio enxergue o que
esta dentro mas no mexa. Alguns vo permitir que o usurio coloque coisas mas no retire.
Outros ainda podem permitir que a pessoa retire objetos mas no possa rep-los.
Esta variedade de sistemas de armazenamento representam a variedade de tipos de memria
e de interfaces de perifricos que possumos.
A memria identificada atravs de um endereo. Por estarmos tratando de sistemas digitais,
o valor do endereo codificado em binrio. Como visto anteriormente, escrever em binrio
trabalhoso e muito propenso a gerar erros. Visando facilitar esse processo, comumente adotado
o sistema hexadecimal para indicar o local de memria.
Os dispositivos so ento ligados um determinado nmero de endereo que passa a identific-
lo de forma nica. O mesmo acontece para a memria RAM e memria ROM. Elas esto ligadas
uma srie de endereos. Se, portanto, preciso salvar uma varivel na memria, tem-se que saber
quais endereos esto ligados memria RAM. Se quisermos ler alguma informao gravada na
memria ROM, preciso conhecer a localizao exata antes de realizar a leitura.
A porta D do microcontrolador PIC 4550 por exemplo est no endereo 0xF83, destinado aos
registros de funo especial ou special function register, SFR Figura 3.4).

Notas de Aula ELT024 - Programao para Sistemas Embarcados


41 Arquitetura de microcontroladores

Suporte Existe
nmero: gaveta?
1 Vitrine

2 Gaveta

3 Dispenser

4 No

5 Gaveta

6 Cofre

Figura 3.3: Memria e perifricos como um armrio

Stack 1 0x000
GPR1
... 0x0FF
Stack 31 0x100
GPR2
0x1FF
Interrupo

Reset 0x0000 0x200


Vetor de

GPR3
Baixa prioridade 0x0008 0x2FF
Alta prioridade 0x0018 0x300
GPR4
0x3FF
0x0028
Memria EEPROM
0x7FFF
No implementado ...
0X8000
No implementado 0xF60
0X1FFFFF SFR
0xFFF

Figura 3.4: Regies de memrias disponveis no PIC18F4550

Notas de Aula ELT024 - Programao para Sistemas Embarcados


42 Arquitetura de microcontroladores

. Clock e tempo de instruo


O microcontrolador capaz de realizar apenas uma tarefa por vez. Estas tarefas so executadas
sempre a intervalos regulares definidos pelo clock do sistema. O clock define ento a velocidade
com que o processador trabalha.
Algumas operaes so mais demoradas pois so compostas de uma quantidade maior de
tarefas. Por exemplo a soma.
A soma de nmeros inteiros feita de maneira direta enquanto para somar dois nmeros
fracionrios, que esto em notao cientfica1 , necessrio igualar as potencias antes de realizar
a soma. Por este motivo a segunda operao mais demorada que a primeira.
Exemplo:

Multiplicao de inteiros Multiplicao de fracionrios

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.

Tabela 3.1: Quantidade de operaes e tarefas

Operao com: Quantidade Total de tarefas


1 tarefa 104 104
2 tarefas 63 126
3 tarefas 21 63
4 tarefas 12 48
Total 200 341

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

ponto flutuante que se assemelha notao cientfica.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


43 Arquitetura de microcontroladores

. Esquema eltrico e circuitos importantes


Um microcontrolador representado atravs de esquema eltrico. O esquema eltrico apresenta
ao projetista todos os componentes e suas ligaes conforme apresentado na Figura 3.5.

Figura 3.5: Esquema eltrico: Microcontrolador PIC 18F4550

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).

Notas de Aula ELT024 - Programao para Sistemas Embarcados


44 Arquitetura de microcontroladores

Multiplexao nos terminais do microcontrolador


Conforme pode ser observado na Figura 3.5, alguns pinos/terminais possuem mais de uma des-
crio. Por exemplo o terminal 8, a descrio deste terminal RE0/AN5/CK1SPP. Isto indica
que dependendo da configurao escolhida ele pode ser um terminal:

de entrada ou sada referente ao primeiro bit da porta E (RE0)

de leitura analgica pertencente ao quinto conversor analgico - digital (AN5)

utilizado para enviar um clock externo de comunicao paralela (CK1SPP)

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


45 Arquitetura de microcontroladores

. Registros de configurao do microcontrolador


A maioria dos terminais dos microcontroladores podem ser configurados para trabalhar de di-
versas maneiras. Esta configurao realizada atravs de registros especiais. Estes registros
so posies de memria pr-definidas pelo fabricante. Para conhecer quais so e o que fazem
preciso recorrer ao datasheet do componente.
Alm dos registros de configurao dos terminais, existem registros que indicam como o mi-
crocontrolador deve operar. O microcontrolador PIC18f4550 possui dez registros que controlam
seu modo de operao, velocidade, modo de gravao, etc. Estes registros so apresentados na
Figura 3.6.

Figura 3.6: Registros de configurao do microcontrolador PIC 18F4550

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 ;

A primeira coluna de nmeros indica a posio do registro que armazena as configuraes.


A segunda coluna representa os cdigos utilizados para configurao. Para conhecer as demais
opes de configuraes devemos consultar o manual do usurio.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


46 Arquitetura de microcontroladores

Estas configuraes so dependentes do compilador a ser usado. A seguir demonstramos os


cdigos necessrios para o compilador C18 da Microchip(R).

// 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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


Captulo 4

Programao dos Perifricos

In theory, there is no difference between theory and practice; In


practice, there is. - Chuck Reid

Perifricos so os componentes, circuitos ou sistemas ligados ao microcontrolador, interna ou


externamente. Eles podem ser utilizados para realizar interface entre o homem e o equipamento
ou incluir funcionalidades extras ao sistema, como comunicao, segurana, etc.
Os perifricos de sada1 que sero abordados neste curso sero:

Barramento de Led's(.)

Display de 7 segmentos(.)

Display LCD 2x16(.)

Sadas PWM(.)

Entre os perifricos de entrada2 temos:

Leitura de teclas(.)

Conversor AD(.)

Alm de sistemas de entrada e sada de dados ser abordado um dispositivo de comunicao


serial (.), um tratador de Interrupo(.), um Timer(.) e um dispositivo de segurana:
Watchdog(.).

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

. Acesso s portas do microcontrolador


O microcontrolador possui portas que permitem o interfaceamento do meio externo para o meio
interno. Algumas portas podem trabalhar como receptoras ou transmissoras de sinais. Algumas
podem operar dos dois modos sendo necessrio configur-las antes de sua utilizao.
O microcontrolador PIC 18F4550 possui 5 portas

PORTA: bidirecional com 7 bits

PORTB: bidirecional com 8 bits

PORTC: bidirecional com 7 bits

PORTD: bidirecional com 8 bits

PORTE: 3 bits bidirecionais e 1 bit apenas entrada

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).

Tabela 4.1: Endereos de memria para as portas do PIC 18F4550

Porta Endereo dos dados Endereo de configurao (TRIS)


PORTA 0xF80 0xF92
PORTB 0xF81 0xF93
PORTC 0xF82 0xF94
PORTD 0xF83 0xF95
PORTE 0xF84 0xF96

Aqui o conceito de ponteiros se faz extremamente necessrio. J que conhecemos os endereos


fixos onde as portas se encontram, podemos criar ponteiros para tais endereos de forma que
possamos utilizar as portas como se fossem variveis. Exemplo:

// 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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


49 Programao dos Perifricos

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


50 Programao dos Perifricos

. Configurao dos perifricos


Make everything as simple as possible, but not simpler. - Albert
Einstein
Em geral, os terminais das portas so multiplexados com outros dispositivos. Para saber como
configurar cada porta preciso conhecer os registros de configurao que atuam sobre a porta
desejada. A Figura 4.1 apresenta todos os registros disponveis do microcontrolador 18F4550.

Figura 4.1: Registros de configurao dos perifricos do PIC 18F4550

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


51 Programao dos Perifricos

Tabela 4.2: Tabela de configurao do PIC para as experincias

Terminal Descrio do pino Funo


2 RA0/AN0 Potencimetro / Sensor de Temperatura
4 RA2/AN2/VREF-/CVREF Display 2
7 RA5/AN4/SS/C2OUT Display 1
8 RE0/AN5/CK1SPP RS-LCD / Display 3
9 RE1/AN6/CK2SPP EN-LCD
10 RE2/AN7/OESPP RW-LCD / Display 4
13 OSC1/CLKI
Cristal
14 OSC2/CLKO/RA6
16 RC1/T1OSI/CCP2 Aquecedor
17 RC2/CCP1/P1A Ventilador / Buzzer
19 RD0/SPP0
20 RD1/SPP1 Barramento de dados para o
21 RD2/SPP2 LCD/7seg/Led

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

Notas de Aula ELT024 - Programao para Sistemas Embarcados


52 Programao dos Perifricos

TRISA = 0 b00000001 ; // c o n f i g u r a n d o os t e r m i n a i s como e n t r a d a e s a d a


ADCON1 = 0 b00001110 ; // apenas o p r i m e i r o t e r m i n a l a n a l g i c o

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.

TRISB = 0 b11110000 ; // c o n f i g u r a n d o os t e r m i n a i s como e n t r a d a e s a d a


// c o n f i g u r a o com i n t e r r u p o h a b i l i t a d a
INTCON = 0 b11000101 ;
INTCON2 = 0 b00000001 ;
// c o n f i g u r a o sem i n t e r r u p o
INTCON = 0 b00000000 ;
INTCON2 = 0 b00000001 ;
SPPCFG = 0 b00000000 ; //RB0 e RB4 so c o n t r o l a d o s p e l a p o r t a B e no p e l o SPP

A porta C possui o segundo e terceiro bit como sada PWM e o stimo e oitavo como
comunicao serial.

TRISC = 0 b10000000 ; // c o n f i g u r a n d o os t e r m i n a i s como s a d a , apenas RC7 e n t r a d a


CCP1CON = 0 b00001100 ; // c o n f i g u r a o segundo t e r m i n a l como PWM
CCP2CON = 0 b00001100 ; // c o n f i g u r a o t e r c e i r o t e r m i n a l como PWM
TXTA = 0 b00101100 ; // c o n f i g u r a a t r a n s m i s s o de dados da s e r i a l
RCSTA = 0 b10010000 ; // c o n f i g u r a a r e c e p o de dados da s e r i a l
BAUDCON = 0 b00001000 ; // c o n f i g u r a s i s t e m a de v e l o c i d a d e da s e r i a l
SPBRGH = 0 b00000000 ; // c o n f i g u r a para 56 k
SPBRG = 0 b00100010 ; // c o n f i g u r a para 56 k

A porta D utilizada como barramento de dados. Os valores escritos nela so transmitidos,


simultaneamente, para os leds, os displays de 7 segmentos e o display de LCD.

TRISD = 0 b00000000 ; // c o n f i g u r a n d o os t e r m i n a i s como s a d a

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.

TRISE = 0 b00000000 ; // c o n f i g u r a n d o os t e r m i n a i s como s a d a

Notas de Aula ELT024 - Programao para Sistemas Embarcados


53 Programao dos Perifricos

. 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.

Figura 4.2: Barramento de Led's

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.

void main ( void ) interrupt 0


{
TRISD = 0 x00 ; // c o n f i g u r a os p i n o s da p o r t a D como s a d a
PORTD = 0 xF0 ; // l i g a apenas os q u a t r o l t i m o s b i t s .
for ( ; ; ) ; //mantm o s i s t e m a num l o o p i n f i n i t o
}

Notas de Aula ELT024 - Programao para Sistemas Embarcados


54 Programao dos Perifricos

. 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.

Figura 4.3: Display de 7 Segmentos


Fonte: Peter Halasz - http://commons.wikimedia.org/wiki/File:Seven_segment_02_Pengo.jpg

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


55 Programao dos Perifricos

Tabela 4.3: Converso binrio - hexadecimal para displays de 7 segmentos

Ordem inversa Ordem direta


Display a b c d e f g Hex (0abcdefg) g f e d c b a Hex (0gfedcba)
0 1 1 1 1 1 1 0 7E 0 1 1 1 1 1 1 3F
1 0 1 1 0 0 0 0 30 0 0 0 0 1 1 0 06
2 1 1 0 1 1 0 1 6D 1 0 1 1 0 1 1 5B
3 1 1 1 1 0 0 1 79 1 0 0 1 1 1 1 4F
4 0 1 1 0 0 1 1 33 1 1 0 0 1 1 0 66
5 1 0 1 1 0 1 1 5B 1 1 0 1 1 0 1 6D
6 1 0 1 1 1 1 1 5F 1 1 1 1 1 0 1 7D
7 1 1 1 0 0 0 0 70 0 0 0 0 1 1 1 07
8 1 1 1 1 1 1 1 7F 1 1 1 1 1 1 1 7F
9 1 1 1 1 0 1 1 7B 1 1 0 1 1 1 1 6F
A 1 1 1 0 1 1 1 77 1 1 1 0 1 1 1 77
b 1 0 1 1 1 1 0 5E 1 1 1 1 1 0 0 7C
C 1 0 0 1 1 1 1 4F 0 1 1 1 0 0 1 39
d 0 1 1 1 1 0 1 3D 1 0 1 1 1 1 0 5E
E 1 0 0 1 1 1 1 4F 1 1 1 1 0 0 1 79
F 1 0 0 0 1 1 1 47 1 1 1 0 0 0 1 71

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.

Figura 4.5: Ligao de 4 displays de 7 segmentos multiplexados

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.

void main ( void ) interrupt 0


{

Notas de Aula ELT024 - Programao para Sistemas Embarcados


56 Programao dos Perifricos

// v e t o r que armazena a c o n v e r s o dos a l g a r i s m o s para o d i s p l a y 7 s e g


const char conv [ ] = {0 x3F , 0 x06 , 0 x5B , 0 x4F , 0 x66 , 0 x6D , 0 x7D , 0 x07 ,
0 x7F , 0 x6F , 0 x77 , 0 x7C , 0 x39 , 0 x5E , 0 x79 , 0 x71 } ;
unsigned i n t var , time ;
TRISD = 0 x00 ;
TRISA = 0 x00 ;
PORTA = 0 xFF ;
f o r ( var = 0 ; var < 1 6 ; var++)
{
// c o l o c a os c a r a c t e r e s em s e q u n c i a na s a d a
PORTD = conv [ var ] ;
// apenas para c o n t a r tempo
f o r ( time = 0 ; time < 6 5 0 0 0 ; time++) ;
}
}

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:

1. colocar no barramento de dados o valor a ser mostrado no display X

2. ligar o display X atravs da linha de comando

3. esperar um tempo adequado para evitar flicker5

4. desligar o display

5. escolher o prximo display (X+1)

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


57 Programao dos Perifricos

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.

Programa 4.1: disp7seg.c


1 #include " disp7seg .h"
2 // v e t o r para armazenar a c o n v e r s o do -
display
3 s t a t i c const char valor [ ] = {0 x3F , - 40 void AtualizaDisplay ( void )
0 x06 , 0 x5B , 0 x4F , 0 x66 , 0 x6D , - 41 {
0 x7D , 0 x07 , 0 x7F , 0 x6F , 0 x77 , - 42 // d e s l i g a t o d o s os d i s p l a y s
0 x7C , 0 x39 , 0 x5E , 0 x79 , 0 x71 } ; 43 PORTA = 0 x00 ;
4 // i n d i c a o d i s p l a y a t u a l 44 PORTE = 0 x00 ;
5 s t a t i c char display ; 45 // d e s l i g a t o d o s os l e d s
6 // v a l o r e s dos d i s p l a y s 46 PORTD = 0 x00 ;
7 s t a t i c char v0 , v1 , v2 , v3 ; 47 // l i g a apenas o d i s p l a y da v e z
8 void MudaDigito ( char val , char pos ) 48 switch ( display )
9 { 49 {
10 i f ( pos == 0 ) 50 case 0 :
11 { 51 PORTD = valor [ v0 ] ;
12 v0 = val ; 52 BitSet ( PORTA , 5 ) ;
13 } 53 display = 1 ;
14 i f ( pos == 1 ) 54 break ;
15 { 55 case 1 :
16 v1 = val ; 56 PORTD = valor [ v1 ] ;
17 } 57 BitSet ( PORTA , 2 ) ;
18 i f ( pos == 2 ) 58 display = 2 ;
19 { 59 break ;
20 v2 = val ; 60 case 2 :
21 } 61 PORTD = valor [ v2 ] ;
22 i f ( pos == 3 ) 62 BitSet ( PORTE , 0 ) ;
23 { 63 display = 3 ;
24 v3 = val ; 64 break ;
25 } 65 case 3 :
26 } 66 PORTD = valor [ v3 ] ;
67 BitSet ( PORTE , 2 ) ;
28 void InicializaDisplays ( void ) 68 display = 0 ;
29 { 69 break ;
30 // c o n f i g u r a o dos p i n o s de c o n t r o l e 70 default :
31 BitClr ( TRISA , 2 ) ; 71 display = 0 ;
32 BitClr ( TRISA , 5 ) ; 72 break ;
33 BitClr ( TRISE , 0 ) ; 73 }
34 BitClr ( TRISE , 2 ) ; 74 }
35 // apenas AN0 a n a l g i c o
36 ADCON1 = 0 x0E ;
37 // Porta de dados
38 TRISD = 0 x00 ;
39 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


58 Programao dos Perifricos

Programa 4.2: disp7seg.h


1 #i f n d e f DISP7SEG_H
2 #define DISP7SEG_H
3 void MudaDigito ( char val , char pos ) ;
4 void AtualizaDisplay ( void ) ;
5 void InicializaDisplays ( void ) ;
6 #endif

Programa 4.3: Utilizando a biblioteca disp7seg


1 #include " basico .h"
2 #include " config .h"
3 #include " disp7seg .h"

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 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


59 Programao dos Perifricos

. 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.

Figura 4.6: Circuito de leitura de chave


http://www.labbookpages.co.uk/electronics/debounce.html - Dr. Andrew Greensted

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.

Debounce por software


O debounce por software em geral utilizado em situaes onde se deseja aumentar a robustez
de uma entrada que j possua um debounce por hardware ou reduzir o custo da placa utilizando
apenas a soluo por software. A grande desvantagem deste tipo de sistema inserir um atraso
na deteco da informao.
Para realizar o debounce por software precisamos ter uma noo do tempo que a chave
precisa para estabilizar. Da Figura 4.7 temos que este tempo, para uma determinada chave de
aproximadamente 150 (s). Um ciclo de clock do sistema em questo (PIC18f4550 com cristal de

Notas de Aula ELT024 - Programao para Sistemas Embarcados


60 Programao dos Perifricos

Figura 4.7: Oscilao do sinal no momento do chaveamento


http://www.labbookpages.co.uk/electronics/debounce.html - Dr. Andrew Greensted

Figura 4.8: Circuito de debounce


http://www.ikalogic.com/debouncing.php - Ibrahim Kamal

Notas de Aula ELT024 - Programao para Sistemas Embarcados


61 Programao dos Perifricos

Figura 4.9: Utilizao de filtro RC para debounce do sinal


http://www.labbookpages.co.uk/electronics/debounce.html A. Greensted (modificado)

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.

void main ( void ) interrupt 0


{
unsigned char valTemp ;
unsigned char valAtual ;
unsigned char tempo ;
TRISB = 0 xF0 ; //mantm os 4 l t i m o s b i t s como e n t r a d a
TRISD = 0 x00 ; // C o n f i g u r a a p o r t a D como s a d a
PORTB = 0 x00 ; // l i g a os 4 p r i m e i r o s b i t s
BitClr ( INTCON2 , 7 ) ; // h a b i l i t a p u l l up
ADCON1 = 0 b00001110 ; // c o n f i g u r a t o d o s os b i t s da p o r t a B como d i g i t a i s
for ( ; ; )
{
// aguarda uma mudana na p o r t a B
while ( valAtual==PORTB ) ;
// quando a c o n t e c e r alguma mudana , c o n t a um tempo pra v e r s e permanente
valTemp = PORTB ;
tempo = 2 2 ;
while ( tempo > 0 )
{
i f ( valTemp == PORTB ) // s e no mudar c o n t i n u a a c o n t a r
{
tempo ;
6
Lembrar que cada ciclo do PIC necessita de 4 ciclos de clock externo

Notas de Aula ELT024 - Programao para Sistemas Embarcados


62 Programao dos Perifricos

}
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
}
}

Arranjo de leitura por matriz


Para cada tecla/boto que colocado no projeto, necessrio um terminal do microcontrolador.
Para um teclado maior possvel que o microcontrolador no possua terminais disponveis em
quantidade suficiente. Do mesmo modo que no caso dos displays possvel multiplexar as
chaves aumentando a quantidade de chave por terminal. Novamente, este ganho, em termos de
hardware, aumenta a complexidade para o software e juntamente com este, o custo em termos
de tempo de computao.
Uma das tcnicas mais eficientes para a gerao deste teclado o arranjo em formato matri-
cial. Com esta configurao podemos, com N terminais, ler at (N/2)2 chaves.
Conforme podemos ver na Figura 4.10, cada chave pode ser identificada unicamente pela
sua posio (linha, coluna). Os terminais ligados s linhas sero configurados como entrada,
que serviro para ler os valores das teclas. Os terminais ligados s colunas sero configurados
como sadas, fornecendo energia para as chaves. A leitura realizada ento por um processo
conhecido como varredura: liga-se uma coluna por vez e verifica-se quais chaves daquela coluna
esto ligadas.

void main ( void ) interrupt 0


{
unsigned char i , j ;
unsigned char chave [ 2 ] [ 4 ] = { { 0 , 0 , 0 , 0 } , { 0 , 0 , 0 , 0 } } ;
INTCON2 &= 0 x7F ; // h a b i l i t a p u l l up
ADCON1 = 0 b00001110 ; // apenas AN0 a n a l g i c o ,
TRISB = 0 xF0 ; // os 4 l t i m o s b i t s so e n t r a d a
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 ;
for ( ; ; )
{
f o r ( i = 0 ; i < 2 ; i++)
{
PORTB = 0 xff ; // " d e s l i g a " t o d a s as c o l u n a s
f o r ( j = 0 ; j < 1 0 0 ; j++) ;
BitClr ( PORTB , i ) ; // " l i g a " o b i t da c o l u n a c o r r e s p o n d e n t e
// g a s t a tempo para g a r a n t i r que o p i n o a t i n g i u o n i v e l a l t o
f o r ( j = 0 ; j < 1 0 0 ; j++) ;
// r e a l i z a o t e s t e para cada b i t e a t u a l i z a a m a t r i z .
f o r ( j = 0 ; j < 4 ; j++)
{
i f ( ! BitTst ( PORTB , j+4) )
{
chave [ i ] [ j ] = 1 ;
BitSet ( PORTD , j+4i ) ;
}
else
{
chave [ i ] [ j ] = 0 ;
BitClr ( PORTD , j+4i ) ;
}
}

Notas de Aula ELT024 - Programao para Sistemas Embarcados


63 Programao dos Perifricos

Figura 4.10: Teclado em arranjo matricial

Notas de Aula ELT024 - Programao para Sistemas Embarcados


64 Programao dos Perifricos

Programa 4.4: teclado.c


1 #include " teclado .h"
2 #include " basico .h"
3 s t a t i c unsigned in t valor = 0 x0000 ;
4 unsigned i n t LerTeclas ( void ) {
5 return valor ;
6 }
7 void DebounceTeclas ( void ) {
8 unsigned char i , j ;
9 s t a t i c unsigned char tempo ;
10 s t a t i c unsigned in t valorNovo = 0 x0000 ;
11 s t a t i c unsigned in t valorAntigo = 0 x0000 ;
12 f o r ( i = 0 ; i < 4 ; i++){
13 PORTB |= 0 x0F ; // d e s l i g a t o d a s as c o l u n a s
14 BitClr ( PORTB , ( i ) ) ; // l i g a a c o l u n a c o r r e s p o n d e n t e
15 // g a s t a tempo sem r e a l i z a r f u n o n e c e s s r i o para g a r a n t i r que o p i n o -
atingiu o nivel alto
16 f o r ( j =0;j <100; j++) ;
17 // r e a l i z a o t e s t e para cada b i t e a t u a l i z a a v a r i v e l
18 f o r ( j = 0 ; j < 4 ; j++) {
19 i f ( ! BitTst ( PORTB , j+4) ) {
20 BitSet ( valorNovo , ( i 4 )+j ) ;
21 } else {
22 BitClr ( valorNovo , ( i 4 )+j ) ;
23 }
24 }
25 }
26 i f ( valorAntigo == valorNovo ) {
27 tempo ;
28 } else {
29 tempo = 1 0 ;
30 valorAntigo = valorNovo ;
31 }
32 i f ( tempo == 0 ) {
33 valor = valorAntigo ;
34 }
35 }

37 void InicializaTeclado ( void ) {


38 TRISB = 0 xF0 ; // q u a t r o e n t r a d a s e q u a t r o s a d a s
39 INTCON2 &= 0 x7F ; // h a b i l i t a p u l l up
40 ADCON1 = 0 b00001110 ; // apenas AN0 a n a l g i c o
41 SPPCFG = 0 x00 ;
42 }

}
}
}

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


65 Programao dos Perifricos

Programa 4.5: teclado.h


1 #i f n d e f TECLADO_H
2 #define TECLADO_H

4 unsigned i n t LerTeclas ( void ) ;


5 void DebounceTeclas ( void ) ;
6 void InicializaTeclado ( void ) ;
7 #endif //TECLADO_H

Programa 4.6: Exemplo de uso da biblioteca teclado


1 #include " basico .h"
2 #include " config .h"
3 #include " teclado .h"

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 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


66 Programao dos Perifricos

. Display LCD 2x16


O display de LCD utilizado neste curso possui duas linhas por 16 colunas de caracteres, compat-
vel com o HD44780 que um padro muito utilizado na indstria. Na Figura 4.11 apresentado
um modelo genrico deste tipo de display. A Figura 4.12 apresenta o verso do display com os
terminais expostos.

Figura 4.11: Display Alfanumrico LCD 2x16

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

2. VCC (+5V) 10. Bit 3

3. Ajuste do contraste 11. Bit 4

4. Seleo de registro(RS) 12. Bit 5

5. Read/Write (RW) 13. Bit 6

6. Clock, Enable (EN) 14. Bit 7

7. Bit 0 15. Backlight + (opcional)

8. Bit 1 16. Backlight Gnd (opcional)

Trabalharemos apenas com 11 terminais: os 3 de controle do display (RS,RW,EN) e os 8


para o barramento de dados. Este tipo de display possui, integrado, um microcontrolador para
realizar as rotinas de manuteno do estado do display, controle da luminosidade e interface com

Notas de Aula ELT024 - Programao para Sistemas Embarcados


67 Programao dos Perifricos

Figura 4.12: Display Alfanumrico LCD 2x16 - verso

o restante do sistema eletrnico. A comunicao realizada atravs de um barramento paralelo


de 8 bits, por onde so enviados os dados/comandos.
O terminal RS indica ao display se o barramento contm um comando a ser executado (0)
ou uma informao para ser exibida (1).
O terminal RW indica ao display se ele receber um valor (0) ou se estamos requisitando
alguma informao (1).
O terminal EN indica ao display que ele pode ler/executar o que est no barramento de
dados.
Ateno, o display utilizado apresenta os terminais colocados de maneira no sequncial,
conforme pode ser visto na Figura 4.12. Deste modo no qualquer display que compatvel.
As informaes so enviadas atravs da codificao ASCII, sendo que os caracteres de 0
127 so padronizados. Os caracteres de 128 255 dependem do fabricante do display. possvel
tambm criar algumas representaes, smbolos definidos pelo usurio e armazenar na memria
interna do display. Para um display com a ROM do tipo A00 temos os caracteres definidos na
Figura 4.13. Para a ROM A02 temos a Figura 4.14.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


68 Programao dos Perifricos

Figura 4.13: Caracteres disponveis para ROM A00


http://www.sparkfun.com/datasheets/LCD/HD44780.pdf - Datasheet Hitachi

Notas de Aula ELT024 - Programao para Sistemas Embarcados


69 Programao dos Perifricos

Figura 4.14: Caracteres disponveis para ROM A02


http://www.sparkfun.com/datasheets/LCD/HD44780.pdf - Datasheet Hitachi

Notas de Aula ELT024 - Programao para Sistemas Embarcados


70 Programao dos Perifricos

Os comandos reconhecidos pelo display so apresentados na Tabela 4.4.

Tabela 4.4: Lista de comandos aceitos pelo o LCD

Instruo RS RW Barramento de dados (bit) Tempo


7 6 5 4 3 2 1 0
Limpa todo o display e configura o endereo
0 0 0 0 0 0 0 0 0 1 37 us
para 0.
Configura o endereo para 0. Retorna o dis-
play para o incio se houve alguma operao 0 0 0 0 0 0 0 0 1 - 1.52 ms
de shift.
Configura a movimentao do cursor e o modo
0 0 0 0 0 0 0 1 ID S 37 us
de shift do display
Configura o display (D) inteiro para desligado
ou ligado, cursor (C) ligado ou desligado e 0 0 0 0 0 0 1 D C B 37 us
blinking (B) do cursor.
Move o cursor e/ou o display sem alterar o
0 0 0 0 0 1 SC RL - - 37 us
contedo
Configura o tamanho da palavra (DL), n-
0 0 0 0 1 DL N F - - 37 us
mero de linhas (N) e fonte dos caracteres (F)
Desloca o cursor para a posio desejada: li-
0 0 1 X 0 0 Coluna 37 us
nha e coluna.
Verifica se o display est disponvel ou se esta
0 1 BF - - - - - - - 10 us
ocupado com alguma operao interna.
Definies das opes
ID: 1 Incrementa, 0 Decrementa N: 1 2 linhas, 0 1 linha
S: 1 O display acompanha o deslocamento F: 1 5x10 pontos, 0 5x8 pontos
SC: 1 Desloca o display, 0 Desloca o cursor BF: 1 Ocupado, 0 Disponvel
RL: 1 Move para direita, 0 Move para esquerda X: 1 2a linha, 0 1a linha
DL: 1 8 bits, 0 4 bits Coluna: nible que indica a coluna
http://www.sparkfun.com/datasheets/LCD/HD44780.pdf - Datasheet Hitachi (modificado)

Os terminais de dados esto ligados porta D, juntamente com o display de 7 segmentos e


barramento de dados. Para estes dispositivos funcionarem em conjunto necessrio multiplexa-
los no tempo. Os terminais de controle esto ligados porta E conforme o esquema apresentado
na Figura 4.15.

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


71 Programao dos Perifricos

Figura 4.15: Esquemtico de ligao do display de LCD

Programa 4.7: lcd.h


1 #i f n d e f LCD_H
2 #define LCD_H
3 void EnviaComando ( char cmd ) ;
4 void EnviaDados ( char valor ) ;
5 void InicializaLCD ( void ) ;
6 #endif //LCD_H

Notas de Aula ELT024 - Programao para Sistemas Embarcados


72 Programao dos Perifricos

Programa 4.8: lcd.c


1 #include " lcd .h"
2 #include " basico .h"
3 #define RS 0
4 #define EN 1 47 void EnviaDados ( char valor )
5 #define RW 2 48 {
49 // dados
7 void InicializaLCD ( void ) 50 BitSet ( PORTE , RS ) ;
8 { 51 // h a b i l i t a e s c r i t a
9 // I n i c i a l i z a o LCD 52 BitClr ( PORTE , RW ) ;
10 Delay2ms ( ) ; 53 PORTD = valor ;
11 Delay2ms ( ) ; 54 // h a b i l i t a l e i t u r a
12 Delay2ms ( ) ; 55 BitSet ( PORTE , EN ) ;
13 Delay2ms ( ) ; 56 Delay40us ( ) ;
14 Delay2ms ( ) ; 57 // t e r m i n a l e i t u r a
15 // c o n f i g . de d i r e o (E/S ) 58 BitClr ( PORTE , EN ) ;
16 BitClr ( TRISE , RS ) ; //RS 59 // d e i x a em n v e l b a i x o
17 BitClr ( TRISE , EN ) ; //EN 60 BitClr ( PORTE , RS ) ;
18 BitClr ( TRISE , RW ) ; //RW 61 // d e i x a em n v e l b a i x o
19 TRISD = 0 x00 ; // dados 62 BitClr ( PORTE , RW ) ;
20 ADCON1 = 0 b00001110 ; 63 Delay40us ( ) ;
21 // c o n f i g u r a o d i s p l a y 64 }
22 // 8 b i t s , 2 l i n h a s , 5 x8
23 EnviaComando ( 0 x38 ) ; 66 void EnviaComando ( char cmd )
24 //modo i n c r e m e n t a l 67 {
25 EnviaComando ( 0 x06 ) ; 68 // comando
26 // d i s p l a y , c u r s o r e b l i n k i n g on 69 BitClr ( PORTE , RS ) ;
27 EnviaComando ( 0 x0F ) ; 70 // h a b i l i t a e s c r i t a
28 // z e r a c o n t a d o r e s i n t e r n o s 71 BitClr ( PORTE , RW ) ;
29 EnviaComando ( 0 x03 ) ; 72 PORTD = cmd ;
30 // l i m p a r d i s p l a y 73 // h a b i l i t a l e i t u r a
31 EnviaComando ( 0 x01 ) ; 74 BitSet ( PORTE , EN ) ;
32 // p o s i o i n i c i a l 75 Delay2ms ( ) ;
33 EnviaComando ( 0 x80 ) ; 76 // t e r m i n a l e i t u r a
34 } 77 BitClr ( PORTE , EN ) ;
78 // d e i x a em n v e l b a i x o
36 void Delay40us ( void ) { 79 BitClr ( PORTE , RS ) ;
37 unsigned char i ; 80 // d e i x a em n v e l b a i x o
38 f o r ( i =0; i < 2 5 ; i++) ; 81 BitClr ( PORTE , RW ) ;
39 } 82 Delay2ms ( ) ;
83 }
41 void Delay2ms ( void ) {
42 unsigned char i ;
43 f o r ( i =0; i < 2 0 0 ; i++){
44 Delay40us ( ) ;
45 }
46 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


73 Programao dos Perifricos

Programa 4.9: Exemplo de uso da biblioteca de LCD


1 #include " basico .h"
2 #include " config .h"
3 #include " lcd .h"

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 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


74 Programao dos Perifricos

. 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.

Tabela 4.5: Taxas de transmisso para diferentes protocolos

Protocolo Taxa (Mbit/s) Taxa (Mb/s)


ATA 33 (Ultra DMA) 264 33
ATA 66 (Ultra DMA) 528 66
ATA 100 (Ultra DMA) 800 100
ATA 133 (Ultra DMA) 1064 133
Serial ATA (SATA-150) 1200 150
Serial ATA 2 (SATA-300) 2400 300
Serial ATA 3 (SATA-600) 4800 600

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


75 Programao dos Perifricos

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.

Figura 4.16: Sinal serializado para transmisso em RS232

Para o correto funcionamento do protocolo devemos garantir compatibilidade no nvel fsico


(do hardware) e lgico (no software).
Para o hardware basta compatibilizar o tipo de conector, os nveis de tenso e a pinagem dos
conectores.
Para o nvel de software temos que definir a codificao utilizada (ASCII, UTF-8, etc),
especificar o fluxo de caracteres (quantidade de bits por caractere, tamanho do start/stop bit,
paridade) e a taxa de transmisso desejada.
Estas configuraes so realizadas atravs de 5 registros TXSTA, RCSTA, BAUDCON, SP-
BRGH e SPBRG.
Os registros TXSTA e RCSTA so responsveis por configurar o meio de transmisso: pre-
sena/ausncia de bit de parada, tamanho da palavra de um caractere, transmisso sncrona/as-
sncrona.
O registro BAUDCON responsvel por configurar o controle de velocidade de transmisso.
Os registros SPBRGH e SPBRG representam o byte mais alto e o mais baixo da palavra de
16 bits que indica a taxa de transmisso.
A taxa de transmisso pode ser calculada segundo a Tabela 4.6.
Como visto na Tabela 4.6 existem trs formulas diferentes para calcular a taxa de transmisso.
A melhor maneira de configurar a taxa de transmisso da porta serial verificar qual dos mtodos
gera o menor erro para uma dada taxa de transmisso.
Por exemplo, queremos uma taxa de transmisso de 57,6 kbps. A frequncia disponvel um
cristal de 8MHz. Usando as trs formulas chegamos aos seguintes valores:

n1 = 1; F232 = 62.500, err = -7,64%

n2 = 8, F232 = 55.555, err = 3,63%

n3 = 32, F232 = 57.142, err = 0,79%

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,

Notas de Aula ELT024 - Programao para Sistemas Embarcados


76 Programao dos Perifricos

Tabela 4.6: Clculo do valor da taxa de transmisso da porta serial

Bits de Configurao Preciso Taxa de transmisso


TXSTA:4 BAUDCON:3 TXSTA:2
FOSC
0 0 0 8bits F232 =
[64 (n + 1)]
0 0 1 8bits FOSC
F232 =
0 1 0 16bits [16 (n + 1)]
0 1 1 16bits
FOSC
1 0 x 8bits F232 =
[4 (n + 1)]
1 1 x 16bits
x no importa, n valor do par SPBRGH:SPBRG

BAUDCON(3) = 1 e TXSTA(2) = 1. A seguir temos todo o processo de configurao da porta


serial RS232.

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.

void EnviaSerial ( unsigned char c )


{
while ( ! BitTst ( PIR1 , 4 ) ) ; // aguarda o r e g i s t r o f i c a r d i s p o n v e l
TXREG=c ; // c o l o c a o v a l o r para s e r e n v i a d o
}

O processo de desserializao tambm realizado de modo automtico pelo hardware do


dispositivo. Assim que um byte estiver disponvel o sistema seta o bit 5 do registro PIR1 e
podemos ento ler o valor disponvel no registro RCREG.

unsigned char RecebeSerial ( void )


{
char resp = 0 ;
i f ( BitTst ( PIR1 , 5 ) ) // V e r i f i c a s e e x i s t e algum v a l o r d i s p o n v e l
{

Notas de Aula ELT024 - Programao para Sistemas Embarcados


77 Programao dos Perifricos

Programa 4.10: serial.c


1 #include " serial .h"
2 #include " basico .h"

4 void EnviaSerial ( unsigned char c )


5 {
6 while ( ! BitTst ( PIR1 , 4 ) ) ; // aguarda o r e g i s t r o f i c a r d i s p o n v e l
7 TXREG=c ; // c o l o c a o v a l o r para s e r e n v i a d o
8 }

10 unsigned char RecebeSerial ( void )


11 {
12 char resp = 0 ;
13 i f ( BitTst ( PIR1 , 5 ) ) // V e r i f i c a s e e x i s t e algum v a l o r d i s p o n i v e l
14 {
15 resp = RCREG ; // r e t o r n a o v a l o r
16 }
17 return resp ; // r e t o r n a z e r o
18 }

20 void InicializaSerial ( void )


21 {
22 TXSTA = 0 b00101100 ; // c o n f i g u r a a t r a n s m i s s o de dados da s e r i a l
23 RCSTA = 0 b10010000 ; // c o n f i g u r a a r e c e p o de dados da s e r i a l
24 BAUDCON = 0 b00001000 ; // c o n f i g u r a s i s t e m a de v e l o c i d a d e da s e r i a l
25 SPBRGH = 0 b00000000 ; // c o n f i g u r a para 56 k
26 SPBRG = 0 b00100010 ; // c o n f i g u r a para 56 k
27 BitSet ( TRISC , 6 ) ; // p i n o de r e c e p o de dados
28 BitClr ( TRISC , 7 ) ; // p i n o de e n v i o de dados
29 }

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


78 Programao dos Perifricos

Programa 4.11: serial.h


1 #i f n d e f SERIAL_H
2 #define SERIAL_H
3 void EnviaSerial ( unsigned char c ) ;
4 unsigned char RecebeSerial ( void ) ;
5 void InicializaSerial ( void ) ;
6 #endif //SERIAL_H

Programa 4.12: Exemplo de uso da biblioteca de comunicao serial


1 #include " basico .h"
2 #include " config .h"
3 #include " serial .h"

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 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


79 Programao dos Perifricos

. 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).

Figura 4.17: Lmpada incandescente

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


80 Programao dos Perifricos

Figura 4.18: Potencimetro

Figura 4.19: Potencimetro como divisor de tenso


http://en.wikipedia.org/wiki/File:Potentiometer_with_load.png

Figura 4.20: Circuito integrado LM35

Notas de Aula ELT024 - Programao para Sistemas Embarcados


81 Programao dos Perifricos

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.

Figura 4.21: Diagrama de blocos do LM35

Quando polarizado atravs de uma corrente constante, havendo mudana de temperatura a


tenso em cima do diodo muda. Os dois amplificadores e as respectivas realimentaes esto
inseridas no circuito para amplificar e estabilizar as variaes de tenso.

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.

Representao binria com 2 bits Valor em tenso


00 0.625v
01 1.875v
10 3.125v
11 4.375v

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

Notas de Aula ELT024 - Programao para Sistemas Embarcados


82 Programao dos Perifricos

Figura 4.22: Conversor analgico digital de 2 bits


http://en.wikipedia.org/wiki/File:Flash_ADC.png - Jon Guerber

Notas de Aula ELT024 - Programao para Sistemas Embarcados


83 Programao dos Perifricos

Programa 4.13: adc.c


1 #include " adc .h"
2 #include " basico .h"
3 void InicializaAD ( void )
4 {
5 BitSet ( TRISA , 0 ) ; // s e t a o b i t 0 como e n t r a d a
6 ADCON0 = 0 b00000001 ; // s e l e c i o n a o c a n a l 0 e l i g a o ad
7 ADCON1 = 0 b00001110 ; // apenas AN0 a n a l g i c o , a r e f e r e n c i a b a s e a d a na f o n t e
8 ADCON2 = 0 b10101010 ; //FOSC /32 , Alinhamento d i r e i t a e tempo de conv = 12 TAD
9 }

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 }

Programa 4.14: adc.h


1 #i f n d e f ADC_H
2 #define ADC_H
3 void InicializaAD ( void ) ;
4 i n t LeValorAD ( void ) ;
5 #endif //ADC_H

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

3. Monitorar o final da converso

4. Ler o valor

Os programas 4.13 e 4.14 apresentam os arquivos de cdigo e header de uma biblioteca


exemplo para conversores analgicos para digital no microcontrolador PIC. O programa 4.15
apresenta um cdigo exemplificando o uso da biblioteca criada.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


84 Programao dos Perifricos

Programa 4.15: Exemplo de uso da biblioteca de conversores AD


1 #include " basico .h"
2 #include " config .h"
3 #include " disp7seg .h"
4 #include " adc .h"
5 // i n i c i o do programa
6 void main ( void ) interrupt 0
7 {
8 unsigned i n t i ;
9 i n t temp = 0 ;
10 InicializaDisplays ( ) ;
11 InicializaAD ( ) ;
12 for ( ; ; )
13 {
14 temp = LeValorAD ( ) ;
15 temp %= 1 0 0 0 0 ;
16 MudaDigito ( temp / 1 0 0 0 , 3 ) ;
17 temp %= 1 0 0 0 ;
18 MudaDigito ( temp / 100 , 2 ) ;
19 temp %= 1 0 0 ;
20 MudaDigito ( temp / 10 ,1) ;
21 temp %= 1 0 ;
22 MudaDigito ( temp ,0) ;
23 AtualizaDisplay ( ) ;
24 f o r ( i = 0 ; i < 1 0 0 0 ; i++) ;
25 }
26 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


85 Programao dos Perifricos

. 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.

Figura 4.23: Sinais PWM com variao do duty cycle

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:

Notas de Aula ELT024 - Programao para Sistemas Embarcados


86 Programao dos Perifricos

Tabela 4.7: Faixa de frequncias mximas e mnimas para cada configurao do prescaler

Prescaler Freq. mxima (PR2 = 0) Freq. mnima (PR2 = 0)


1 2.000.000 7.812,5
4 500.000 1.953,2
16 125.000 488,3

[CCPRxL : CCPxCON (5 : 4)]


DutyCycle PWM =
(PR2 + 1) 4

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


87 Programao dos Perifricos

Programa 4.16: pwm.c


1 #include " pwm .h"
2 #include " basico .h"

4 void SetaPWM1 ( unsigned char porcento )


5 {
6 // f o r m u l a do d u t y c y c l e :
7 // DC_porcento = V / ( ( PR2+1) 4 ;
8 //V = DC/100 (PR2+1) 4 = DC (PR2+1) /25
9 unsigned i n t val = ( ( unsigned i n t ) porcento ) ( PR2 +1) ;
10 val = val / 2 5 ;
11 // g a r a n t e que tem apenas 10 b i t s
12 val &= 0 x03ff ;
13 // os 8 p r i m e i r o s b i t s so c o l o c a d o s no CCPR1L
14 CCPR1L = val >> 2 ;
15 // os l t i m o s d o i s so c o l o c a d o s na p o s i o 5 e 4 do CCP1CON
16 CCP1CON |= ( val & 0 x0003 ) << 4 ;
17 }

19 void SetaPWM2 ( unsigned char porcento )


20 {
21 // 100 256 = 2 5 . 6 0 0
22 unsigned i n t val = porcento PR2 ;
23 val /= 2 5 ;
24 // g a r a n t e que tem apenas 10 b i t s
25 val &= 0 x03ff ;
26 // os 8 p r i m e i r o s b i t s so c o l o c a d o s no CCPR1L
27 CCPR2L = val >> 2 ;
28 // os l t i m o s d o i s so c o l o c a d o s na p o s i o 5 e 4 do CCP1CON
29 CCP2CON |= ( val & 0 x0003 ) << 4 ;
30 }

32 void SetaFreqPWM ( unsigned i n t freq )


33 {
34 //PR2 = f o s c /( fpwm4 p r e s c a l e r )1 = ( 8 0 0 0 0 0 0 / ( f r e q 416) ) 1
35 PR2 = ( 1 2 5 0 0 0 / ( freq ) ) 1 ;
36 }

38 void InicializaPWM ( void )


39 {
40 BitClr ( TRISC , 2 ) ; // c o n f i g u r a os p i n o s como s a d a s
41 BitClr ( TRISC , 3 ) ;
42 T2CON |= 0 b00000011 ; // c o n f i g u r a o p r e s c a l e do t i m e r 2 para 1 : 1 6
43 BitSet ( T2CON , 2 ) ; // L i g a o t i m e r 2
44 CCP1CON |= 0 b00001100 ; // c o n f i g u r a CCP1 como um PWM
45 CCP2CON |= 0 b00001100 ; // c o n f i g u r a CCP2 como um PWM
46 }

Programa 4.17: pwm.h


1 #i f n d e f PWM_H
2 #define PWM_H
3 void SetaPWM1 ( unsigned char porcento ) ;
4 void SetaPWM2 ( unsigned char porcento ) ;
5 void SetaFreqPWM ( unsigned i n t freq ) ;
6 void InicializaPWM ( void ) ;
7 #endif //PWM_H

Notas de Aula ELT024 - Programao para Sistemas Embarcados


88 Programao dos Perifricos

Programa 4.18: Exemplo de uso da biblioteca das sadas PWM


1 #include " config .h"
2 #include " basico .h"
3 #include " pwm .h"
4 #include " adc .h"
5 // i n i c i o do programa
6 void main ( void ) interrupt 0
7 {
8 i n t temp ;
9 InicializaPWM ( ) ;
10 InicializaAD ( ) ;
11 for ( ; ; ) {
12 temp = LeValorAD ( ) ;
13 // a j u s t a n d o a f r e q u n c i a de acordo com e n t r a d a a n a l g i c a
14 SetaFreqPWM ( temp ) ;
15 // a j u s t a n d o o dutyc y c l e para 50%
16 SetaPWM1 ( 5 0 ) ;
17 }
18 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


89 Programao dos Perifricos

Programa 4.19: timer.c


1 #include " basico .h"
2 #include " timer .h"
3 char FimTimer ( void )
4 {
5 return BitTst ( INTCON , 2 ) ;
6 }
7 void AguardaTimer ( void )
8 {
9 while ( ! BitTst ( INTCON , 2 ) ) ;
10 }

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 }

25 void InicializaTimer ( void )


26 {
27 T0CON = 0 b00001000 ; // c o n f i g u r a t i m e r 0 sem p r e s c a l e r
28 BitSet ( T0CON , 7 ) ; // l i g a o t i m e r 0
29 }

. 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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


90 Programao dos Perifricos

Programa 4.20: timer.h


1 #i f n d e f TIMER_H
2 #define TIMER_H
3 char FimTimer ( void ) ;
4 void AguardaTimer ( void ) ;
5 // tempo em micro s e g u n d o s
6 void ResetaTimer ( unsigned i n t tempo ) ;
7 void InicializaTimer ( void ) ;
8 #endif //TIMER_H

Programa 4.21: Exemplo de uso da biblioteca de um temporizador


1 // i n i c i o do programa
2 void main ( void ) interrupt 0
3 {
4 unsigned i n t cont ;
5 TRISD=0x00 ;
6 InicializaTimer ( ) ;
7 ResetaTimer ( 1 0 0 0 0 ) ;
8 cont = 0 ;
9 for ( ; ; )
10 {
11 AguardaTimer ( ) ;
12 ResetaTimer ( 1 0 0 0 0 ) ;
13 cont ++;
14 i f ( cont >= 5 0 ) // 50 10ms = 0 ,5 s
15 {
16 PORTD ^= 0 xFF ;
17 cont = 0 ;
18 }
19 }
20 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


91 Programao dos Perifricos

. 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.

Programa 4.22: Reproduo de sons


1 #include " config .h"

3 #include " basico .h"


43 // i n i c i o do programa
5 #include " pwm .h" 44 void main ( void )
45 {
7 #include " timer .h" 46 unsigned char cont =0;
47 unsigned char pos =0;
48 // I m p e r i a l March (SW E p i s o d e V)
10 // f r e q u n c i a das 49 unsigned char tempo [ ] = { 5 0 , 1 0 , 5 0 , 1 0 , 5 0 , 1 0 , -
11 // n o t a s m u s i c a i s 5 0 , 5 , 2 5 , 5 , 5 0 , 5 , 5 0 , 5 , 2 5 , 5 , 5 0 , 5 0 , 5 0 , -
12 #define C 523 1 0 , 5 0 , 1 0 , 5 0 , 1 0 , 5 0 , 5 , 2 5 , 5 , 5 0 , 5 , 5 0 , -
13 #define CS 554 5 , 2 5 , 5 , 5 0 , 5 0 , 1 0 0 , 5 , 2 5 , 5 , 2 5 , 1 0 , 1 0 0 , -
14 #define D 587 5 , 50 , 5 , 25 , 2 , 10 , 2 , 10 , 2 , 100 , 250};
15 #define DS 622 50 unsigned i n t notas [ ] = {G , v , G , v , G , v , E , v , B , -
16 #define E 659 v , G , v , E , v , B , v , G , v , D2S , v , D2S , v , -
17 #define F 698 D2S , v , E2 , v , B , v , FS , v , E , v , B , v , G , v , -
18 #define FS 740 G2S , v , G , v , G , v , G2S , v , G2 , v , F2S , v , F2 , -
19 #define G 784 v , E2 , v , F2S , v } ;
20 #define GS 830 51 InicializaPWM ( ) ;
21 #define A 880 52 InicializaTimer ( ) ;
22 #define AS 932 53 SetaFreqPWM ( notas [ 0 ] ) ;
23 #define B 987 54 SetaPWM1 ( 5 0 ) ; // g a r a n t e dutyc y c l e de 50%
55 for ( ; ; )
56 {
26 // segunda o i t a v a 57 AguardaTimer ( ) ;
27 #define C2 C2 58 ResetaTimer ( 1 0 0 0 0 ) ;
28 #define C2S CS2 59 cont ++;
29 #define D2 D2 60 i f ( cont >= tempo [ pos ] )
30 #define D2S DS2 61 {
31 #define E2 E2 62 pos++;
32 #define F2 F2 63 SetaFreqPWM ( notas [ pos ] ) ;
33 #define F2S FS2 64 SetaPWM1 ( 5 0 ) ;
34 #define G2 G2 65 cont =0;
35 #define G2S GS2 66 }
36 #define A2 A2 67 }
37 #define A2S AS2 68 }
38 #define B2 B2

41 //sem som
42 #define v 125000

10
Esta a mxima frequncia possvel para o PWM operado com prescaler de 16x.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


92 Programao dos Perifricos

. 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.

Conversor AD: quando o resultado da converso estiver disponvel para leitura.

Porta B: quando algum dos bits configurados como entrada altera seu valor.

Timer 0: quando acontece overflow em seu contador

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.

void NomeDaFuncao ( void ) interrupt 1


{
// c d i g o . . .
}

Para o compilador C18 da Microchip temos que gerar um cdigo em assembler que indicar
qual funo ser a responsvel pela interrupo.

void NomeDaFuncao ( void )


{
// c d i g o . . .
}

// 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

A funo que ir tratar da interrupo no retorna nem recebe nenhum valor.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


93 Programao dos Perifricos

Programa 4.23: Fontes de Interupo


1 void Interrupcao ( void ) interrupt 1 {
2 // no n e c e s s r i o u t i l i z a r t o d o s os i f ' s apenas a q u e l e s
3 // das i n t e r r u p e s d e s e j a d a s
4 i f ( BitTst ( PIR1 , 0 ) ) { / c d i g o / } // F l a g de o v e r f l o w do TIMER1
5 i f ( BitTst ( PIR1 , 1 ) ) { / c d i g o / } // F l a g de comparao do TIMER2 com PR2
6 i f ( BitTst ( PIR1 , 2 ) ) { / c d i g o / } // F l a g de comparao do CCP1
7 i f ( BitTst ( PIR1 , 3 ) ) { / c d i g o / } // F l a g de fim de o p e r a o na p o r t a -
paralela
8 i f ( BitTst ( PIR1 , 4 ) ) { / c d i g o / } // F l a g de fim de t r a n s m i s s o da S e r i a l
9 i f ( BitTst ( PIR1 , 5 ) ) { / c d i g o / } // F l a g de r e c e p o da S e r i a l
10 i f ( BitTst ( PIR1 , 6 ) ) { / c d i g o / } // F l a g de fim de c o n v e r s o do AD
11 i f ( BitTst ( PIR1 , 7 ) ) { / c d i g o / } // F l a g de l e i t u r a / e s c r i t a da p o r t a -
paralela
12 i f ( BitTst ( PIR2 , 0 ) ) { / c d i g o / } // F l a g de comparao do CCP2
13 i f ( BitTst ( PIR2 , 1 ) ) { / c d i g o / } // F l a g de o v e r f l o w do TIMER3
14 i f ( BitTst ( PIR2 , 2 ) ) { / c d i g o / } // F l a g de c o n d i o de Tenso A l t a / Baixa
15 i f ( BitTst ( PIR2 , 3 ) ) { / c d i g o / } // F l a g de d e t e c o de c o l i s o no -
barramento
16 i f ( BitTst ( PIR2 , 4 ) ) { / c d i g o / } // F l a g de fim e s c r i t a na memoria f l a s h
17 i f ( BitTst ( PIR2 , 5 ) ) { / c d i g o / } // F l a g de i n t e r r u p o da USB
18 i f ( BitTst ( PIR2 , 6 ) ) { / c d i g o / } // F l a g de mudana na e n t r a d a de -
comparao
19 i f ( BitTst ( PIR2 , 7 ) ) { / c d i g o / } // F l a g de f a l h a no o s c i l a d o r
20 i f ( BitTst ( INTCON , 0 ) ) { / c d i g o / } // F l a g de mudana na PORTA B
21 i f ( BitTst ( INTCON , 1 ) ) { / c d i g o / } // F l a g de i n t e r r u p o e x t e r n a INT0
22 i f ( BitTst ( INTCON , 2 ) ) { / c d i g o / } // F l a g de o v e r f l o w no TIMER0
23 i f ( BitTst ( INTCON3 , 0 ) ) { / c d i g o / } // F l a g de i n t e r r u p o e x t e r n a INT1
24 i f ( BitTst ( INTCON3 , 1 ) ) { / c d i g o / } // F l a g de i n t e r r u p o e x t e r n a INT2
25 }

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


94 Programao dos Perifricos

Programa 4.24: Tratamento das interrupes


1 s t a t i c unsigned in t ADvalor ;
2 s t a t i c unsigned char Serial ;
3 s t a t i c unsigned in t Tecla ;
4 void Interrupcao ( void ) interrupt 1
5 {
6 char i , j ;
7 i f ( BitTst ( PIR1 , 6 ) ) //AD : fim de c o n v e r s o
8 {
9 ADvalor = ADRESH ; // l o r e s u l t a d o
10 ADvalor <<= 8 ;
11 ADvalor += ADRESL ;
12 BitClr ( PIR1 , 6 ) ; // l i m p a a f l a g
13 }
14 i f ( BitTst ( PIR1 , 5 ) ) // S e r i a l : r e c e p o
15 {
16 // B i t C l r ( PIR1 , 5 ) ;
17 Serial = RCREG ; // l i m p a s o z i n h o quando l
18 }
19 i f ( BitTst ( INTCON , 0 ) ) //PORTA B : mudou v a l o r
20 {
21 f o r ( i = 0 ; i < 4 ; i++){
22 PORTB |= 0 xFF ;
23 BitClr ( PORTB , ( i ) ) ;
24 f o r ( j =0;j <10; j++) ;
25 f o r ( j = 0 ; j < 4 ; j++){
26 i f ( ! BitTst ( PORTB , j+4) ) {
27 BitSet ( Tecla , ( i 4 )+j ) ;
28 } else {
29 BitClr ( Tecla , ( i 4 )+j ) ;
30 }
31 }
32 }
33 PORTB = 0 x00 ;
34 BitClr ( INTCON , 0 ) ;
35 }
36 i f ( BitTst ( INTCON , 2 ) ) //TIMER0 : O v e r f l o w
37 {
38 // tempo maximo de i n t e r r u p o do t i m e r 0
39 BitClr ( INTCON , 2 ) ; // l i m p a a f l a g
40 TMR0H = 0 x00 ; // r e i n i c i a c o n t a d o r de tempo
41 TMR0L = 0 x00 ; // r e i n i c i a c o n t a d o r de tempo
42 ADCON0 |= 0 b00000010 ; // i n i c i a c o n v e r s o
43 }
44 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


95 Programao dos Perifricos

Programa 4.25: Inicializao do sistema com interrupes


1 void main ( void )
2 {
3 unsigned i n t i , temp , teclanova =0;
4 // c o n f i g u r a n d o t o d a s as i n t e r r u p e s
5 TRISD = 0 x00 ;
6 TRISB = 0 xF0 ; //mantm os 4 l t i m o s b i t s como e n t r a d a
7 PORTB = 0 x00 ; //mantem l i g a d a s as 4 c o l u n a s
8 InicializaSerial ( ) ;
9 InicializaDisplays ( ) ;
10 InicializaLCD ( ) ;
11 InicializaAD ( ) ;
12 InicializaTimer ( ) ;
13 BitClr ( RCON , 7 ) ; // d e s a b i l i t a IPEN ( modo de c o m p a t i b i l i d a d e )
14 BitSet ( PIE1 , 6 ) ; // l i g a a i n t e r r u p o para o AD
15 BitSet ( PIE1 , 5 ) ; // l i g a a i n t e r r u p o para a r e c e p o na s e r i a l
16 BitSet ( INTCON , 5 ) ; // l i g a a i n t e r r u p o para o t i m e r 0
17 BitSet ( INTCON , 3 ) ; // l i g a a i n t e r r u p o para a p o r t a B
18 BitSet ( INTCON , 7 ) ; // h a b i l i t a t o d a s as i n t e r r u p e s g l o b a i s
19 BitSet ( INTCON , 6 ) ; // h a b i l i t a t o d a s as i n t e r r u p e s de p e r i f r i c o s
20 for ( ; ; ) {
21 AtualizaDisplay ( ) ;
22 temp = ADvalor ;
23 temp %=10000;
24 MudaDigito ( temp / 1 0 0 0 , 3 ) ;
25 temp %=1000;
26 MudaDigito ( temp / 1 0 0 , 2 ) ;
27 temp %=100;
28 MudaDigito ( temp / 1 0 , 1 ) ;
29 temp %=10;
30 MudaDigito ( temp , 0 ) ;
31 i f ( teclanova != Tecla ) {
32 teclanova = Tecla ;
33 f o r ( i =0;i <16; i++){
34 i f ( BitTst ( Tecla , i ) ) {
35 EnviaDados ( i+48) ;
36 }
37 }
38 }
39 f o r ( i = 0 ; i < 1 0 0 0 ; i++) ;
40 }
41 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


96 Programao dos Perifricos

Programa 4.26: Inicializao do sistema com interrupes


1 #define CLRWTD( ) _asm CLRWDT _endasm

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


Captulo 5

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

No desenvolvimento de um sistema de maior porte, importante definir o tipo de arquitetura


que iremos utilizar. Neste captulo apresentamos trs abordagens possveis. A escolha deve ser
baseada no tipo de dispositivo a ser desenvolvido, na complexidade do sistema, na possibilidade
de gerar subprodutos e dos requisitos de tempo.

97
98 Arquitetura de desenvolvimento de software

Programa 5.1: Exemplo de arquitetura single-loop


1 // s e o de i n c l u d e s
2 #include " basico .h"
3 #include " config .h"
4 #include " teclado .h"
5 #include " disp7seg .h"
6 // f u n o p r i n c i p a l
7 void main ( void ) interrupt 0
8 {
9 // d e c l a r a o das v a r i v e i s
10 i n t ia , ib , ic ;
11 f l o a t fa , fb , fc ;
12 // i n i c i a l i z a o dos p e r i f r i c o s
13 InicializaTeclado ( ) ;
14 InicializaDisplays ( ) ;
15 // l o o p p r i n c i p a l
16 for ( ; ; )
17 {
18 // chamada das t a r e f a s
19 ia = LerTeclas ( ) ;
20 ImprimeDisplay ( ia ) ; // tem que s e r e x e c u t a d o p e l o menos a cada 10(ms)
21 }
22 }

Programa 5.2: Problema na sincronia de tempo para o single-loop


1 // l o o p p r i n c i p a l
2 for ( ; ; )
3 {
4 // chamada das t a r e f a s
5 ia = LerTeclas ( ) ;
6 ImprimeDisplay ( ia ) ; // tem que s e r e x e c u t a d o p e l o menos a cada 10(ms)
7 ic = RecebeSerial ( ) ;
8 fa = 2 . 0 ic / 3 . 1 4 ;
9 EnviaSerial ( fa & 0 x00FF ) ;
10 EnviaSerial ( fa >> 8 ) ;
11 }

. One single loop


1 Infinite Loop, Cupertino, CA 95014. - Endereo da Apple

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


99 Arquitetura de desenvolvimento de software

Programa 5.3: Exemplo de sistema Interrupt-driven


1 i n t ia ;
2 // t r a t a m e n t o do t e c l a d o v i a i n t e r r u p o
3 void Interrupcao ( void ) interrupt 1
4 {
5 i f ( BitTst ( INTCON , 0 ) ) //PORTA B : mudou v a l o r
6 {
7 ia = LerTeclas ( ) ;
8 }
9 }

11 void main ( void )


12 {
13 // i n i c i a l i z a o dos p e r i f r i c o s
14 InicializaTeclado ( ) ;
15 InicializaDisplay ( ) ;
16 // i n i c i a l i z a o da i n t e r r u p o
17 BitClr ( RCON , 7 ) ; // d e s a b i l i t a IPEN ( modo de c o m p a t i b i l i d a d e )
18 BitSet ( INTCON , 3 ) ; // l i g a a i n t e r r u p o para a p o r t a B
19 BitSet ( INTCON , 7 ) ; // h a b i l i t a t o d a s as i n t e r r u p e s g l o b a i s
20 BitSet ( INTCON , 6 ) ; // h a b i l i t a t o d a s as i n t e r r u p e s de p e r i f r i c o s
21 f o r ( ; ; ) // l o o p p r i n c i p a l
22 {
23 // chamada das t a r e f a s
24 ImprimeDisplay ( ia ) ;
25 }
26 }

. Interrupt control system


Uma parte dos desenvolvedores de sistemas embarcados, que possuem restries de tempo de
atendimento mais rigorosos, optam por garantir estas restries atravs de interrupes.
Na maioria dos sistemas microcontroladores, as interrupes so atendidas num tempo muito
curto, cerca de alguns ciclos de instruo, o que para a maioria dos sistemas suficiente. Deve-se,
entretanto, tomar cuidado com a quantidade de perifricos que geram interrupes e a prioridade
dada a cada um deles.
Outra abordagem muito utilizada a gerao de uma interrupo com tempo fixo, por exem-
plo a cada 5ms.
A grande vantagem da abordagem citada que a insero de mais cdigo dentro do loop
principal no atrapalha a velocidade com que o display atualizado, que est fixo em 5(ms).

Notas de Aula ELT024 - Programao para Sistemas Embarcados


100 Arquitetura de desenvolvimento de software

Programa 5.4: Exemplo de sistema Interrupt-driven com base de tempo


1 i n t ia ;
2 // e x i t e apenas uma f o n t e de i n t e r r u p o : Timer 0
3 void Interrupcao ( void ) interrupt 1
4 {
5 ResetaTimer ( 5 0 0 0 ) ; // r e i n i c i a t i m e r para prxima i n t e r r u p o
6 ImprimeDisplay ( ia ) ;
7 BitSet ( INTCON , 5 ) ; // r e l i g a a i n t e r r u p o para o t i m e r 0
8 }

10 void main ( void )


11 {
12 // i n i c i a l i z a o dos p e r i f r i c o s
13 InicializaTeclado ( ) ;
14 InicializaDisplay ( ) ;
15 InicializaTimer ( ) ;
16 // i n i c i a l i z a o da i n t e r r u p o
17 BitClr ( RCON , 7 ) ; // d e s a b i l i t a IPEN ( modo de c o m p a t i b i l i d a d e )
18 BitSet ( INTCON , 5 ) ; // l i g a a i n t e r r u p o para o t i m e r 0
19 BitSet ( INTCON , 7 ) ; // h a b i l i t a t o d a s as i n t e r r u p e s g l o b a i s
20 BitSet ( INTCON , 6 ) ; // h a b i l i t a t o d a s as i n t e r r u p e s de p e r i f r i c o s
21 ResetaTimer ( 5 0 0 0 ) ;
22 f o r ( ; ; ) // l o o p p r i n c i p a l
23 {
24 ia = LerTeclas ( ) ;
25 }
26 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


101 Arquitetura de desenvolvimento de software

. 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

Figura 5.1: Exemplo de mquina de estados

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


102 Arquitetura de desenvolvimento de software

Programa 5.5: Exemplo de cooperative multitasking


1 void main ( void ) interrupt 0{
2 // d e c l a r a o das v a r i v e i s
3 char slot ;
4 // f u n e s de i n i c i a l i z a o
5 InicializaSerial ( ) ;
6 InicializaTeclado ( ) ;
7 InicializaDisplay ( ) ;
8 f o r ( ; ; ) { // i n i c i o do l o o p i n f i n i t o
9 // i n c i o do tops l o t
10 // fim do tops l o t

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 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


103 Arquitetura de desenvolvimento de software

Programa 5.6: Exemplo de cooperative multitasking com uso do top slot


1 void main ( void )
2 {
3 // d e c l a r a o das v a r i v e i s
4 char slot ;
5 // f u n e s de i n i c i a l i z a o
6 InicializaSerial ( ) ;
7 InicializaTeclado ( ) ;
8 InicializaDisplay ( ) ;
9 f o r ( ; ; ) // i n i c i o do l o o p i n f i n i t o
10 {
11 // i n c i o do tops l o t
12 AtualizaDisplay ( ) ;
13 // fim do tops l o t

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 }

Notas de Aula ELT024 - Programao para Sistemas Embarcados


104 Arquitetura de desenvolvimento de software

Programa 5.7: Exemplo de sistema Cooperative-multitasking com slot temporizado


1 void main ( void )
2 {
3 // d e c l a r a o das v a r i v e i s
4 char slot ;
5 // f u n e s de i n i c i a l i z a o
6 InicializaDisplay ( ) ;
7 InicializaTimer ( ) ;
8 f o r ( ; ; ) // i n i c i o do l o o p i n f i n i t o
9 {
10 // i n c i o do tops l o t
11 ResetaTimer ( 5 0 0 0 ) ; // 5 ms para cada s l o t
12 AtualizaDisplay ( ) ;
13 // fim do tops l o t

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 }

Fixao de tempo para execuo dos slots


Do modo apresentado at agora, assim que uma funo termina, o sistema automaticamente
passa para a prxima tarefa. Uma caracterstica desejada que estas funes possuam um
tempo determinado para funcionar. Deste modo, todo o sistema se torna mais previsvel.
A maneira mais simples de realizar este procedimento criar uma rotina de tempo. Toda vez
que um slot terminar, o sistema ficar aguardando o tempo escolhido para reiniciar o sistema.
No exemplo apresentado inserida a funo AguardaTimer() no bottom-slot de modo que a
prxima funo s executar quando passar os 5 (ms).
Como este um modo simples de implementar um sistema multitarefa podemos notar que
se a funo ultrapassar 5 (ms) todo o cronograma ser afetado. necessrio ento garantir que
todo e cada slot ser executado em menos de 5 (ms). Isto deve ser feito atravs de testes de
bancada.
Na Figura 5.2 est um exemplo de como um sistema com 3 slots se comporta ao longo do

Notas de Aula ELT024 - Programao para Sistemas Embarcados


105 Arquitetura de desenvolvimento de software

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

Figura 5.2: Exemplo da mudana de slots no tempo

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).

Utilizao do tempo livre para interrupes


Conforme visto anteriormente, dependendo do tempo escolhido para o slot e do tamanho da
funo, podem existir espaos vagos na linha de tempo do processador. A Figura 5.3 apresenta
uma linha de tempo de um sistema que possui apenas 1 slot. J a Figura 5.4 demonstra o mesmo
sistema sendo interrompido atravs de interrupes assncronas.

Top 1 1 1
S.1 3 3 3
Bottom 1 1 1
"vago" 3 3 3

Figura 5.3: Linha de tempo de um sistema com 1 slot

Top 1 1
S.1 1 2 3 3
Bottom 1 1 1
"vago" 2 2 2
Interr. 1 1 1

Figura 5.4: Comportamento da linha de tempo com interrupes

Notas de Aula ELT024 - Programao para Sistemas Embarcados


106 Arquitetura de desenvolvimento de software

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).

Notas de Aula ELT024 - Programao para Sistemas Embarcados


Captulo 6

Anexos

107
108 Anexos

Programa 6.1: config.h


1 // para o c o m p i l a d o r SDCC + GPUtils
2 #i f n d e f CONFIG_H
3 #define CONFIG_H
4 code char at 0 x300000 CONFIG1L = 0 x01 ; // Pll desligado
5 code char at 0 x300001 CONFIG1H = 0 x0C ; // 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
6 code char at 0 x300003 CONFIG2H = 0 x00 ; // Watchdog c o n t r o l a d o por s o f t w a r e
7 code char at 0 x300006 CONFIG4L = 0 x00 ; // Sem programao em b a i x a t e n s o
8 #endif //CONFIG_H

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


109 Anexos

Programa 6.2: basico.h


1 // f u n o para l i m p a r o watchdog
2 #define CLRWTD( ) _asm CLRWDT _endasm
3 // f u n e s de b i t
4 #define B i t S e t ( arg , b i t ) ( ( a r g ) |= (1<< b i t ) )
5 #define B i t C l r ( arg , b i t ) ( ( a r g ) &= ~(1<< b i t ) )
6 #define B i t F l p ( arg , b i t ) ( ( a r g ) ^= (1<< b i t ) )
7 #define B i t T s t ( arg , b i t ) ( ( a r g ) & (1<< b i t ) )
8 // d e f i n e ' s para r e g i s t r o s e s p e c i a i s
9 #define PORTA ( ( v o l a t i l e n e a r unsigned char ) 0xF80 )
10 #define PORTB ( ( v o l a t i l e n e a r unsigned char ) 0xF81 )
11 #define PORTC ( ( v o l a t i l e n e a r unsigned char ) 0xF82 )
12 #define PORTD ( ( v o l a t i l e n e a r unsigned char ) 0xF83 )
13 #define PORTE ( ( v o l a t i l e n e a r unsigned char ) 0xF84 )
14 #define TRISA ( ( v o l a t i l e n e a r unsigned char ) 0xF92 )
15 #define TRISB ( ( v o l a t i l e n e a r unsigned char ) 0xF93 )
16 #define TRISC ( ( v o l a t i l e n e a r unsigned char ) 0xF94 )
17 #define TRISD ( ( v o l a t i l e n e a r unsigned char ) 0xF95 )
18 #define TRISE ( ( v o l a t i l e n e a r unsigned char ) 0xF96 )
19 #define INTCON ( ( v o l a t i l e n e a r unsigned char ) 0xFF2 )
20 #define INTCON2 ( ( v o l a t i l e n e a r unsigned char ) 0xFF1 )
21 #define PIE1 ( ( v o l a t i l e n e a r unsigned char ) 0xF9D)
22 #define PIR1 ( ( v o l a t i l e n e a r unsigned char ) 0xF9E )
23 #define TMR0L ( ( v o l a t i l e n e a r unsigned char ) 0xFD6)
24 #define TMR0H ( ( v o l a t i l e n e a r unsigned char ) 0xFD7)
25 #define T0CON ( ( v o l a t i l e n e a r unsigned char ) 0xFD5)
26 #define SPPCON ( ( v o l a t i l e n e a r unsigned char ) 0xF65 )
27 #define SPPCFG ( ( v o l a t i l e n e a r unsigned char ) 0xF63 )
28 #define ADCON2 ( ( v o l a t i l e n e a r unsigned char ) 0xFC0 )
29 #define ADCON1 ( ( v o l a t i l e n e a r unsigned char ) 0xFC1 )
30 #define ADCON0 ( ( v o l a t i l e n e a r unsigned char ) 0xFC2 )
31 #define ADRESL ( ( v o l a t i l e n e a r unsigned char ) 0xFC3 )
32 #define ADRESH ( ( v o l a t i l e n e a r unsigned char ) 0xFC4 )
33 #define RCSTA ( ( v o l a t i l e n e a r unsigned char ) 0xFAB)
34 #define TXSTA ( ( v o l a t i l e n e a r unsigned char ) 0xFAC)
35 #define TXREG ( ( v o l a t i l e n e a r unsigned char ) 0xFAD)
36 #define RCREG ( ( v o l a t i l e n e a r unsigned char ) 0xFAE)
37 #define SPBRG ( ( v o l a t i l e n e a r unsigned char ) 0xFAF)
38 #define SPBRGH ( ( v o l a t i l e n e a r unsigned char ) 0xFB0 )
39 #define BAUDCON ( ( v o l a t i l e n e a r unsigned char ) 0xFB8 )
40 #define RCON ( ( v o l a t i l e n e a r unsigned char ) 0xFD0)
41 #define WDTCON ( ( v o l a t i l e n e a r unsigned char ) 0xFD1)
42 #define T2CON ( ( v o l a t i l e n e a r unsigned char ) 0xFCA)
43 #define PR2 ( ( v o l a t i l e n e a r unsigned char ) 0xFCB)
44 #define CCP2CON ( ( v o l a t i l e n e a r unsigned char ) 0xFBA)
45 #define CCPR2L ( ( v o l a t i l e n e a r unsigned char ) 0xFBB)
46 #define CCP1CON ( ( v o l a t i l e n e a r unsigned char ) 0xFBD)
47 #define CCPR1L ( ( v o l a t i l e n e a r unsigned char ) 0xFBE)

. 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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados


110 Anexos

. Instalar gravadores/depuradores de PIC em sistemas x64


Os passos a seguir devem ser seguidos para instalar os device drivers corretamente em sistemas
operacionais de 64 bits. Atualmente apenas os seguintes aparelhos so suportados:

MPLAB REAL ICE? in-circuit emulator

MPLAB ICE 2000 with USB converter

MPLAB ICD 2 (P/N 10-00397)

MPLAB ICD 3

MPLAB PM3 (P/N 10-00398)

PIC32MX Starter Kit

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)

Notas de Aula ELT024 - Programao para Sistemas Embarcados


111 Anexos

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.

Notas de Aula ELT024 - Programao para Sistemas Embarcados

Você também pode gostar