Sistema embarcados

142

Transcript of Sistema embarcados

Page 1: Sistema embarcados

Notas de Aula Programação Embarcada

Rodrigo Maximiano Antunes de Almeida

Instituto de Engenharia de Sistemas e Tecnologia da Informação,

Universidade Federal de Itajubá,

Minas Gerais,

Brasil

rodrigomax @ unifei.edu.br

2 de Dezembro de 2010

Page 2: Sistema embarcados

Conteúdo

1 Introdução 1

1.1 Linguagem C . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2 Hardware utilizado . . . . . . . . . . . . . . . . . . . . . . . . 31.3 Ambiente de programação . . . . . . . . . . . . . . . . . . . . 3

Instalação . . . . . . . . . . . . . . . . . . . . . . . . 4Con�guração do gravador ICD2 . . . . . . . . . . . . 7Criação de um novo projeto . . . . . . . . . . . . . . 9

2 Linguagem C para sistemas embarcados 12

2.1 Indentação e padrão de escrita . . . . . . . . . . . . . . . . . 122.2 Comentários . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142.3 Arquivos .c e .h . . . . . . . . . . . . . . . . . . . . . . . . . . 152.4 Diretivas de compilação . . . . . . . . . . . . . . . . . . . . . 15

#include . . . . . . . . . . . . . . . . . . . . . . . . . 15#de�ne . . . . . . . . . . . . . . . . . . . . . . . . . . 17#ifdef, #ifndef, #else e #endif . . . . . . . . . . . . . 18

2.5 Tipos de dados em C . . . . . . . . . . . . . . . . . . . . . . . 21Representação binária e hexadecimal . . . . . . . . . . 22Modi�cadores de tamanho e sinal . . . . . . . . . . . . 23Modi�cadores de acesso . . . . . . . . . . . . . . . . . 24Modi�cadores de posicionamento . . . . . . . . . . . . 26Modi�cador de persistência . . . . . . . . . . . . . . . 26

2.6 Operações aritméticas . . . . . . . . . . . . . . . . . . . . . . 272.7 Função main() . . . . . . . . . . . . . . . . . . . . . . . . . . 292.8 Rotinas de tempo . . . . . . . . . . . . . . . . . . . . . . . . . 312.9 Operações com bits . . . . . . . . . . . . . . . . . . . . . . . . 33

NOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34AND . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34OR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35XOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35Shift . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36Ligar um bit (bit set) . . . . . . . . . . . . . . . . . . 36Desligar um bit (bit clear) . . . . . . . . . . . . . . . . 37

i

Page 3: Sistema embarcados

Trocar o valor de um bit (bit �ip) . . . . . . . . . . . 38Veri�car o estado de um bit (bit test) . . . . . . . . . 39Criando funções através de de�nes . . . . . . . . . . . 40

2.10 Debug de sistemas embarcados . . . . . . . . . . . . . . . . . 40Externalizar as informações. . . . . . . . . . . . . . . . 43Programação incremental . . . . . . . . . . . . . . . . 44Checar possíveis pontos de Memory-leak . . . . . . . . 44Cuidado com a fragmentação da memória . . . . . . . 44Otimização de código . . . . . . . . . . . . . . . . . . 44Reproduzir e isolar o erro . . . . . . . . . . . . . . . . 45

2.11 Ponteiros e endereços de memória . . . . . . . . . . . . . . . . 45

3 Arquitetura de microcontroladores 48

3.1 Acesso à memória . . . . . . . . . . . . . . . . . . . . . . . . . 483.2 Clock e tempo de instrução . . . . . . . . . . . . . . . . . . . 513.3 Esquema elétrico e circuitos importantes . . . . . . . . . . . . 53

Multiplexação nos terminais do microcontrolador . . . 543.4 Registros de con�guração do microcontrolador . . . . . . . . . 54

4 Programação dos Periféricos 57

4.1 Acesso às "portas" do microcontrolador . . . . . . . . . . . . 584.2 Con�guração dos periféricos . . . . . . . . . . . . . . . . . . . 594.3 Barramento de Led's . . . . . . . . . . . . . . . . . . . . . . . 634.4 Display de 7 segmentos . . . . . . . . . . . . . . . . . . . . . . 63

Multiplexação de displays . . . . . . . . . . . . . . . . 66Criação da biblioteca . . . . . . . . . . . . . . . . . . 67

4.5 Leitura de teclas . . . . . . . . . . . . . . . . . . . . . . . . . 70Debounce por software . . . . . . . . . . . . . . . . . . 72Arranjo de leitura por matriz . . . . . . . . . . . . . . 73Criação da biblioteca . . . . . . . . . . . . . . . . . . . 76

4.6 Display LCD 2x16 . . . . . . . . . . . . . . . . . . . . . . . . 76Criação da biblioteca . . . . . . . . . . . . . . . . . . 83

4.7 Comunicação serial . . . . . . . . . . . . . . . . . . . . . . . . 88RS 232 . . . . . . . . . . . . . . . . . . . . . . . . . . . 88Criação da biblioteca . . . . . . . . . . . . . . . . . . . 92

4.8 Conversor AD . . . . . . . . . . . . . . . . . . . . . . . . . . . 95Elementos sensores . . . . . . . . . . . . . . . . . . . . 95Processo de conversão AD . . . . . . . . . . . . . . . . 97Criação da biblioteca . . . . . . . . . . . . . . . . . . . 100

4.9 Saídas PWM . . . . . . . . . . . . . . . . . . . . . . . . . . . 103Criação da biblioteca . . . . . . . . . . . . . . . . . . . 104

4.10 Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1074.11 Reprodução de Sons . . . . . . . . . . . . . . . . . . . . . . . 1104.12 Interrupção . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112

ii

Page 4: Sistema embarcados

4.13 Watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117

5 Arquitetura de desenvolvimento de software 119

5.1 One single loop . . . . . . . . . . . . . . . . . . . . . . . . . . 1195.2 Interrupt control system . . . . . . . . . . . . . . . . . . . . . 1215.3 Cooperative multitasking . . . . . . . . . . . . . . . . . . . . 123

Fixação de tempo para execução dos slots . . . . . . . 125Utilização do "tempo livre" para interrupções . . . . . 128

6 Anexos 129

6.1 con�g.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1296.2 basico.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1306.3 Instalar gravadores/depuradores de PIC em sistemas x64 . . . 132

iii

Page 5: Sistema embarcados

Lista de Figuras

1.1 Camadas de abstração de um sistema operacional . . . . . . . 11.2 Pesquisa sobre linguagens utilizadas para projetos de software

embarcado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.3 Con�guração das ferramentas de compilação . . . . . . . . . . 61.4 Instalação do ICD2 . . . . . . . . . . . . . . . . . . . . . . . . 71.5 Resumo das con�gurações do ICD2 no MPLAB . . . . . . . . 81.6 Project Explorer do MPLAB . . . . . . . . . . . . . . . . . . 91.7 Comparativo de características da família PIC 18fxx5x . . . . 11

2.1 Problema das Referências Circulares . . . . . . . . . . . . . . 202.2 Solução das referências circulares com #ifndef . . . . . . . . . 212.3 Loop in�nito de um device driver gerando erro no sistema . . 292.4 Exemplo de funcionamento do vetor de interrupção . . . . . . 30

3.1 Arquitetura do microcontrolador PIC 18F4550 . . . . . . . . 493.2 Memória como um armário . . . . . . . . . . . . . . . . . . . 503.3 Memória e periféricos como um armário . . . . . . . . . . . . 503.4 Regiões de memórias disponíveis no PIC18F4550 . . . . . . . 513.5 Esquema elétrico: Microcontrolador PIC 18F4550 . . . . . . . 533.6 Registros de con�guração do microcontrolador PIC 18F4550 . 55

4.1 Registros de con�guração dos periféricos do PIC 18F4550 . . 604.2 Barramento de Led's . . . . . . . . . . . . . . . . . . . . . . . 634.3 Display de 7 Segmentos . . . . . . . . . . . . . . . . . . . . . 644.4 Diagrama elétrico para display de 7 segmentos com anodo

comum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644.5 Ligação de 4 displays de 7 segmentos multiplexados . . . . . . 664.6 Circuito de leitura de chave . . . . . . . . . . . . . . . . . . . 704.7 Oscilação do sinal no momento do chaveamento . . . . . . . . 714.8 Circuito de debounce . . . . . . . . . . . . . . . . . . . . . . . 714.9 Utilização de �ltro RC para debounce do sinal . . . . . . . . . 724.10 Teclado em arranjo matricial . . . . . . . . . . . . . . . . . . 754.11 Display Alfanumérico LCD 2x16 . . . . . . . . . . . . . . . . 764.12 Display Alfanumérico LCD 2x16 - verso . . . . . . . . . . . . 79

iv

Page 6: Sistema embarcados

4.13 Caracteres disponíveis para ROM A00 . . . . . . . . . . . . . 814.14 Caracteres disponíveis para ROM A02 . . . . . . . . . . . . . 824.15 Esquemático de ligação do display de LCD . . . . . . . . . . . 844.16 Sinal serializado para transmissão em RS232 . . . . . . . . . . 894.17 Lâmpada incandescente . . . . . . . . . . . . . . . . . . . . . 954.18 Potenciômetro . . . . . . . . . . . . . . . . . . . . . . . . . . . 964.19 Potenciômetro como divisor de tensão . . . . . . . . . . . . . 964.20 Circuito integrado LM35 . . . . . . . . . . . . . . . . . . . . . 974.21 Diagrama de blocos do LM35 . . . . . . . . . . . . . . . . . . 984.22 Conversor analógico digital de 2 bits . . . . . . . . . . . . . . 994.23 Sinais PWM com variação do duty cycle . . . . . . . . . . . . 103

5.1 Exemplo de máquina de estados . . . . . . . . . . . . . . . . . 1235.2 Exemplo da mudança de slots no tempo . . . . . . . . . . . . 1255.3 Linha de tempo de um sistema com 1 slot . . . . . . . . . . . 1285.4 Comportamento da linha de tempo com interrupções . . . . . 128

v

Page 7: Sistema embarcados

Lista de Tabelas

1.1 Softwares utilizados no curso . . . . . . . . . . . . . . . . . . 4

2.1 Tipos de dados e faixa de valores . . . . . . . . . . . . . . . . 222.2 Representação decimal - binária - hexadecimal . . . . . . . . . 232.3 Alteração de tamanho e sinal dos tipos básicos . . . . . . . . 242.4 Operação bit set com de�ne . . . . . . . . . . . . . . . . . . . 412.5 Operação bit clear com de�ne . . . . . . . . . . . . . . . . . . 412.6 Operação bit �ip com de�ne . . . . . . . . . . . . . . . . . . . 422.7 Operação bit test com de�ne . . . . . . . . . . . . . . . . . . 42

3.1 Quantidade de operações e tarefas . . . . . . . . . . . . . . . 52

4.1 Endereços de memória para as portas do PIC 18F4550 . . . . 584.2 Tabela de con�guração do PIC para as experiências . . . . . . 614.3 Conversão binário - hexadecimal para displays de 7 segmentos 654.4 Lista de comandos aceitos pelo o LCD . . . . . . . . . . . . . 834.5 Taxas de transmissão para diferentes protocolos . . . . . . . . 884.6 Cálculo do valor da taxa de transmissão da porta serial . . . . 904.7 Faixa de frequências máximas e mínimas para cada con�gu-

ração do prescaler . . . . . . . . . . . . . . . . . . . . . . . . . 104

vi

Page 8: Sistema embarcados

Listings

2.1 Resumo do disp7seg.c . . . . . . . . . . . . . . . . . . . . . . 162.2 Resumo do disp7seg.h . . . . . . . . . . . . . . . . . . . . . . 162.3 Estrutura de header . . . . . . . . . . . . . . . . . . . . . . . 192.4 Operações aritméticas com tipos diferentes . . . . . . . . . . . 274.1 disp7seg.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684.2 disp7seg.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 694.3 Utilizando a biblioteca disp7seg . . . . . . . . . . . . . . . . . 694.4 teclado.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774.5 teclado.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 784.6 Exemplo de uso da biblioteca teclado . . . . . . . . . . . . . . 784.7 lcd.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864.8 lcd.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874.9 Exemplo de uso da biblioteca de LCD . . . . . . . . . . . . . 874.10 serial.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 934.11 serial.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 934.12 Exemplo de uso da biblioteca de comunicação serial . . . . . . 944.13 adc.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1014.14 adc.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1014.15 Exemplo de uso da biblioteca de conversores AD . . . . . . . 1024.16 pwm.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1054.17 pwm.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1064.18 Exemplo de uso da biblioteca das saídas PWM . . . . . . . . 1064.19 timer.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1084.20 timer.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1084.21 Exemplo de uso da biblioteca de um temporizador . . . . . . 1094.22 Reprodução de sons . . . . . . . . . . . . . . . . . . . . . . . 1114.23 Fontes de Interupção . . . . . . . . . . . . . . . . . . . . . . . 1144.24 Tratamento das interrupções . . . . . . . . . . . . . . . . . . . 1154.25 Inicialização do sistema com interrupções . . . . . . . . . . . 1164.26 Inicialização do sistema com interrupções . . . . . . . . . . . 1175.1 Exemplo de arquitetura single-loop . . . . . . . . . . . . . . . 1205.2 Problema na sincronia de tempo para o single-loop . . . . . . 1205.3 Exemplo de sistema Interrupt-driven . . . . . . . . . . . . . . 1215.4 Exemplo de sistema Interrupt-driven com base de tempo . . . 122

vii

Page 9: Sistema embarcados

5.5 Exemplo de cooperative multitasking . . . . . . . . . . . . . . 1245.6 Exemplo de cooperative multitasking com uso do top slot . . 1265.7 Exemplo de sistema Cooperative-multitasking com slot tem-

porizado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1276.1 con�g.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1296.2 basico.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

viii

Page 10: Sistema embarcados

Capítulo 1

Introdução

�The real danger is not that computers will begin to thinklike men, but that men will begin to think like computers.� -Sydney J. Harris

Programação para sistemas embarcados exige uma série de cuidados espe-ciais, pois estes sistemas geralmente possuem restrições de memória e pro-cessamento. Por se tratar de sistemas com funções especí�cas, as rotinas etécnicas de programação diferem daquelas usadas para projetos de aplicati-vos para desktops.

Também é necessário conhecer mais a fundo o hardware que será uti-lizado, pois cada microprocessador possui uma arquitetura diferente, comquantidade e tipos de instruções diversos. Programadores voltados paradesktops não precisam se ater tanto a estes itens, pois eles programam paraum sistema operacional que realiza o papel de tradutor, disponibilizandouma interface comum, independente do hardware utilizado(Figura 1.1).

Firmware

Hardware

Sistema Operacional

Aplicação

Figura 1.1: Camadas de abstração de um sistema operacional

Para sistemas embarcados, é necessário programar especi�camente para

1

Page 11: Sistema embarcados

2 Introdução

o hardware em questão. Uma opção para se obter �arti�cialmente� esta ca-mada de abstração que era gerada pelo sistema operacional é a utilizaçãode dois itens: um compilador próprio para o componente em questão e umabiblioteca de funções. O compilador será o responsável por traduzir a lin-guagem de alto nível em uma linguagem que o microcontrolador consegueentender. A biblioteca de funções, ou framework, em geral, é disponibilizadapelos fabricantes do microcontrolador.

1.1 Linguagem C

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

Neste curso será utilizada a linguagem C. Esta é uma linguagem com diversascaracterísticas que a tornam uma boa escolha para o desenvolvimento desoftware embarcado. Apesar de ser uma linguagem de alto nível, permite aoprogramador um acesso direto aos dispositivos de hardware.

Também é a escolha da maioria dos programadores e gerentes de projetosno que concerne ao desenvolvimento de sistemas embarcados como pode servisto na Figura 1.2.

Figura 1.2: Pesquisa sobre linguagens utilizadas para projetos de softwareembarcado

Fonte: http://www.embedded.com/design/218600142

A descontinuidade depois de 2004 se dá devido à mudança de metodologiada pesquisa. Antes de 2005, a pergunta formulada era: �Para o desenvol-vimento da sua aplicação embarcada, quais das linguagens você usou nosúltimos 12 meses?�. Em 2005 a pergunta se tornou: �Meu projeto embar-cado atual é programado principalmente em ______�. Múltiplas seleçõeseram possíveis antes de 2005, permitindo a soma superior a 100%, sendo ovalor médio de 209%, o que implica que a maioria das pessoas escolheu duasou mais opções.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 12: Sistema embarcados

3 Introdução

O maior impacto na pesquisa pode ser visualizado na linguagem assem-bler: até 2004, estava presente em 62% das respostas (na média). O quecomprova que praticamente todo projeto de sistema embarcado exige umpouco de assembler. Do mesmo modo, percebemos que atualmente poucosprojetos são realizados totalmente ou em sua maioria em assembler, umamédia de apenas 7%.

1.2 Hardware utilizado

�People who are really serious about software should maketheir own hardware.� - Alan Kay

Como o enfoque deste curso é a programação de sistemas embarcados e nãoa eletrônica, utilizaremos um kit de desenvolvimento pronto, baseado nummicrocontrolador PIC.

Como periféricos disponíveis temos:

� 1 display LCD 2 linhas por 16 caracteres (compatível 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 resistência de aquecimento ligada a uma saída PWM

� 1 motor DC tipo ligado ventilador a uma saída PWM

� 1 buzzer ligado a uma saída PWM

� 1 canal de comunicação serial padrão RS-232

Cada componente terá seu funcionamento básico explicado para permitir odesenvolvimento de rotinas para estes.

1.3 Ambiente de programação

�First, solve the problem. Then, write the code.� - John John-son

O ambiente utilizado será o MPLAB(R). Este é um ambiente de desenvol-vimento disponibilizado pela Microchip(R) gratuitamente. O compiladorutilizado será o SDCC, os linkers e assemblers serão disponibilizados pelabiblioteca GPUtils.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 13: Sistema embarcados

4 Introdução

Como o foco é a aprendizagem de conceitos sobre programação embar-cada poderá ser utilizada qualquer plataforma de programação e qualquercompilador/linker. Caso seja utilizado qualquer conjunto de compilador/lin-ker diferentes deve-se prestar atenção apenas nas diretivas para gravação.

Para a programação em ambiente Linux recomenda-se o uso da suítePIKLAB 15.10. Este programa foi desenvolvido para KDE 3.5. Além depermitir a integração com o mesmo compilador utilizado neste curso permitea programação do microcontrolador utilizando o programador ICD2 via USB.

Instalação

A Tabela 1.1 apresenta os softwares que serão utilizados no curso.

Tabela 1.1: Softwares utilizados no curso

Item Versão Licença

IDE MPLAB 8.50 Proprietário

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 são gratuitos e estão disponíveis na internet. Para cor-reta instalação deve-se instalar os softwares segundo a sequência apresentadana Tabela 1.1. Anote o diretório onde cada software foi instalado.

Após a instalação dos softwares deve-se abrir o arquivo �pic16devices.txt�(de preferência no wordpad) que foi instalado no diretório do SDCC dentro dapasta �include\pic16� (por padrão �C:\Arquivos de programas\SDCC\include\pic16�).Procure a seguintes linhas:

name 18f4550

using 18f2455

Trocar a letra �f� minúscula da primeira linha, apenas do 18f4550, paraum �F� maiúsculo:

name 18F4550

using 18f2455

Após isto abrir a pasta onde foi instalado o MPLAB (por padrão: �C:\Arquivosde programas\Microchip\MPLAB IDE�). Abrir a pasta �Core\MTC Suites�.Abrir os arquivos �sdcclink.mtc� e �gplink.mtc� num editor de texto. Apa-gar o conteúdo do arquivo �sdcclink.mtc�. Copiar todo conteúdo do arquivo�gplink.mtc� para o arquivo �sdcclink.mtc�. Salvar.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 14: Sistema embarcados

5 Introdução

Após o passo acima o arquivo �sdcclink.mtc� deverá conter o seguintetexto:

// Microchip Language Tools

// Configuration File

// gplink

// Craig Franklin

[Tool]

Tool=gplink

ScriptExtension=lkr

DefaultOptions=

MultipleNodes=1

SpaceBetweenSwitchAndData=1

[0]

Description=Output filename

Switch=-o

Data=1

MultipleOptions=0

OutputNameSwitch=Switch

Hidden=1

[1]

Description=Map file

Switch=-m

Data=0

MultipleOptions=0

[2]

Description=COFF File

Switch=-c

Data=0

MultipleOptions=0

[3]

Description=Hex Format

OptionList=INHX8M;INHX8S;INHX32

INHX8M=-a INHX8M

INHX8S=-a INHX8S

INHX32=-a INHX32

Data=0

[4]

Description=Quiet mode

Switch=-q

Data=0

[5]

Description=Library directories

Switch=-I

Data=1

MultipleOptions=0

LibrarySwitch=Switch

Hidden=1

[6]

Description=Linker script directories

Switch=-I

Data=1

MultipleOptions=0

LinkerScriptSwitch=Switch

Hidden=1

[7]

Description=Use Shared Memory

Switch=-r

Data=0

[8]

Description=Fill Value

Switch=-f

MultipleOptions=0

Data=1

[9]

Description=Stack Size

Switch=-t

MultipleOptions=0

Data=1

[10]

Description=No List File

switch=-l

Data=0

Em seguida abrir o programa MPLAB e ir ao menu �Projects -> Set Lan-guage Tool Locations�. Será apresentada uma tela similar a da Figura 1.3.

Selecione a ferramenta �Small Device C Compiler for PIC16 (SDCC16)�.Expanda a opção �Executables�. A ferramenta �gpasm� e �gplink� são obti-das no diretório �bin� dentro de onde foi instalado o GPUtils (por padrão:�C:\Arquivos de programas\gputils\bin�). A ferramenta sdcc16 é encontrada

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 15: Sistema embarcados

6 Introdução

Figura 1.3: Con�guração das ferramentas de compilação

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 16: Sistema embarcados

7 Introdução

no diretório �bin� dentro do diretório onde foi instalado o SDCC (por pa-drão: �C:\Arquivos de programas\SDCC\bin\�). Clicar em �OK�. Apósestes passos a suíte MPLAB está pronta para trabalhar com o compiladorSDCC+GPUtils.

Con�guração do gravador ICD2

Após instalar o MPLAB já é possível fazer a instalação e con�guração dogravador ou depurador ICD2. Conecte-o a qualquer porta USB e aguardea tela de instalação do Windows. Em algumas versões do windows podeacontecer de você ser perguntado se deseja instalar um software não assinadodigitalmente, certi�que-se que a versão do �rmware é pelo menos 1.0.0.0 dafabricante Microchip, conforme pode ser visto na Figura 1.4 e avance.

Figura 1.4: Instalação do ICD2

Após o termino da instalação abra o programa MPLAB para con�guraro gravador ou depurador. Vá ao menu �Programmer -> Select Programmer-> MPLAB ICD 2�. Vá novamente ao menu �Programmer� mas desta vezescolha a opção � MPLAB ICD 2 Setup Wizard�.

No wizard, escolha a comunicação como USB e depois diga que a placapossui alimentação independente �Target has own power supply�. Deixe asoutras opções na seleção padrão. Antes de clicar em concluir veri�que ao�nal se o resumo se parece com o da Figura 1.5.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 17: Sistema embarcados

8 Introdução

Figura 1.5: Resumo das con�gurações do ICD2 no MPLAB

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 18: Sistema embarcados

9 Introdução

Criação de um novo projeto

Recomenda-se a utilização do assistente disponível para a criação de um novoprojeto (menu Project -> Project Wizard). Ele irá questionar sobre (entreparênteses os valores adotados neste curso):

1. O microcontrolador a ser utilizado (PIC18F4550)

2. A suíte de compilação (SDCC 16)

3. O diretório e nome do projeto

4. Arquivos já existentes cujo programador deseja incluir no projeto

Após estes passos o projeto estará criado. Caso a lista de arquivos doprojeto não esteja visível vá ao menu View -> Project.

Para a criação de um novo arquivo vá até o menu File -> New. Nestenovo arquivo digite alguma coisa e salve-o. Caso seja o arquivo que conteráa função principal (main) é costume salvá-lo com o nome de "main.c".

A cada novo arquivo criado é necessário inserí-lo no projeto. Para issodeve-se clicar na pasta correspondente ao tipo de arquivo que se deseja incluire em seguida "Add Files" como pode ser visualizado na Figura 1.6.

Figura 1.6: Project Explorer do MPLAB

Além dos arquivos criados pelo programador, existem três arquivos quedevem ser adicionados ao projeto: um de linker e dois de bibliotecas.

1. Linker

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

2. Bibliotecas

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 19: Sistema embarcados

10 Introdução

(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 responsável por indicar quais são os espaçosde memória disponíveis no chip utilizado, onde começam e de que tipo são(RAM, ROM, Flash) etc.

// 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 memória eeprom,não volátil, que foi denominada eedata. Para a memória RAM está reservadoum total de 2 kbytes, divididos1 em 4 bancos de memória, sendo que oprimeiro foi dividido em duas seções. Estes foram denominados (acessram-gpr0), gpr1, gpr2, gpr32.

Para o programa temos disponível uma região de 32 kbytes de memória�ash, que vai da posição 0x0000 até 0x7FFF. Este é o mesmo endereço damemória RAM. Não existe con�ito, pois estamos trabalhando, no caso doPIC, com uma arquitetura Harvard. Nesta existem dois barramentos e duasmemórias diferentes: uma para o programa, denominada CODEPAGE no

1Uma das maiores di�culdades encontradas em se construir um compilador de lingua-gem C é o gasto em termos de recursos computacionais que é dispendido para tratar estesquatro bancos como sequênciais. Na realidade eles estão todos sobre um mesmo endereçode memória. Para acessar cada um deles é necessário atuar sobre um registro no PIC,indicando qual banco estará ativo naquele momento.

2gprX signi�ca General Propouse Ram bank X

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 20: Sistema embarcados

11 Introdução

linker, e uma para os dados, denominada DATABANK. Notar que apesar damemória eeprom ser utilizada para armazenamento não volátil de dados, elaestá mapeada no barramento de código. Isto se deve a construção internado microcontrolador.

Os dados apresentados no linker e descorridos anteriormente podem serveri�cados e comparados com outros modelos observando a Figura 1.7.

Figura 1.7: Comparativo de características da família PIC 18fxx5x

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 21: Sistema embarcados

Capítulo 2

Linguagem C para sistemas

embarcados

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

A programação para sistemas embarcados possui diversas características di-ferentes da programação voltada para desktop. Do mesmo modo, existemalguns conceitos que geralmente não são explorados nos cursos de linguagensde programação em C mas que são essenciais para o bom desenvolvimentodeste curso. Estes conceitos serão explanados neste capítulo.

2.1 Indentação e padrão de escrita

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

É fundamental obedecer um padrão para escrita de programas, de modo quea visualização do código seja facilitada.

Na língua portuguesa utilizamos parágrafos para delimitar blocos de fra-ses que possuem a mesma ideia. Em linguagem C estes blocos são delimitadospor chaves �{� e �}�.

Para demonstrar ao leitor que um parágrafo começou utilizamos um recuoà direita na primeira linha. Quando é necessário realizar uma citação deitens coloca-se cada um destes itens numa linha recuada à direita, algumasvezes com um identi�cador como um traço �-� ou seta �->� para facilitar aidenti�cação visual.

Com esse mesmo intuito utiliza-se recuos e espaçamentos para que ocódigo 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 nível e todo códigointerno a elas seja deslocado à direita. Se existir um segundo bloco interno

12

Page 22: Sistema embarcados

13 Linguagem C para sistemas embarcados

ao primeiro, este deve ser deslocado duas vezes para indicar a hierarquia no�uxo do programa. Segue abaixo um exemplo de um mesmo código comdiferença apenas na indentação.

Código indentado Código não indentado

1 void main (void ) interrupt 0{unsigned int i ;unsigned int temp ;unsigned int teclanova=0;InicializaSerial ( ) ;InicializaDisplays ( ) ;InicializaLCD ( ) ;InicializaAD ( ) ;for ( ; ; ){

AtualizaDisplay ( ) ;i f ( teclanova != Tecla ){

teclanova = Tecla ;for (i=0;i<16;i++){

i f ( BitTst ( Tecla , i ) ){

EnviaDados (i+48) ;}

}}

for (i = 0 ; i < 1000 ; i++);}

}

void main (void ) interrupt 0{unsigned int i ;unsigned int temp ;unsigned int teclanova=0;InicializaSerial ( ) ;InicializaDisplays ( ) ;InicializaLCD ( ) ;InicializaAD ( ) ;for ( ; ; ){AtualizaDisplay ( ) ;i f ( teclanova != Tecla ){teclanova = Tecla ;for (i=0;i<16;i++){i f ( BitTst ( Tecla , i ) ){EnviaDados (i+48) ;}}}for (i = 0 ; i < 1000 ; i++);}}

Podemos notar pelo código anterior que aquele que possui identação faci-lita na veri�cação de quais instruções/rotinas estão subordinadas às demais.

Outra característica de padronização esta na criação de nomes de funçõese de variáveis. Pela linguagem C uma função ou variável pode ter qualquernome desde que: seja iniciada por uma letra, maiúscula ou minúscula, e osdemais caracteres sejam letras, números ou underscore �_�.

A linguagem C permite também que sejam declaradas duas variáveis commesmo nome caso possuam letras diferentes apenas quanto caixa (maiúsculaou minúscula). Por exemplo: �var� e �vAr� são variáveis distintas, o quepode gerar erro no desenvolvimento do programa causando dúvidas e errosde digitação.

Por isso convenciona-se que nome de variáveis sejam escritos apenas emminúsculas. Quando o nome é composto, se utiliza uma maiúscula para

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 23: Sistema embarcados

14 Linguagem C para sistemas embarcados

diferenciá-los como por exemplo as variáveis �contPos� e �contTotal�.Nomes de função serão escritos com a primeira letra maiúscula e no caso

de nome composto, cada inicial será grafada em maiúsculo: �InicializaTe-clado()�, �ParaSistema()�.

Tags de de�nições (utilizados em conjunto com a diretiva #de�ne) serãografados exclusivamente em maiúsculo: �NUMERODEVOLTAS�, �CONST-GRAVITACIONAL�.

Cada chave será colocada numa única linha, conforme exemplo anterior,evitando-se construções do tipo:

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

Ou

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

As regras apresentadas visam fornecer uma identidade visual ao código.Tais regras não são absolutas, servem apenas para o contexto desta apostila.Em geral, cada instituição ou projeto possui seu próprio conjunto de normas.É importante ter conhecimento deste conjunto e aplicá-lo em seu código.

O estilo adotado nesta apostila é conhecido também como estilo �Allman�,�bsd� (no emacs) ou ANSI, já que todos os documentos do padrão ANSI Cutilizam este estilo. Apesar disto o padrão ANSI C não especi�ca um estilopara ser usado.

2.2 Comentários

�If the code and the comments disagree, then both are probablywrong.� - Norm Schryer

Comentários são textos que introduzimos no meio do programa fonte com aintenção de torná-lo mais claro. É uma boa prática em programação inserircomentários no meio dos nossos programas. Pode-se comentar apenas umalinha usando o símbolo �//� (duas barras). Para comentar mais de uma linhausa-se o símbolo �/*� (barra e asterisco) antes do comentário e �*/� (asteriscoe barra) para indicar o �nal do comentário.

#include <s td i o . h>#define DIST 260 // d i s t an c i a en t re SP e I t aint main ( int argc , char* argv [ ] ){

/* e s s e programa serve paramostrar como se in s e r e comentários */printf ("São Paulo está %d Km de Itajubá" , DIST ) ;return 0 ;

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 24: Sistema embarcados

15 Linguagem C para sistemas embarcados

}

2.3 Arquivos .c e .h

Na programação em linguagem C utilizamos dois tipos de arquivos com fun-ções distintas. Toda implementação de código é feita no arquivo com ex-tensão �.c� (code). É nele que criamos as funções, de�nimos as variáveis erealizamos a programação do código. Se existem dois arquivos �.c� no projetoe queremos que um deles possa usar as funções do outro arquivo, é necessáriorealizar um #include.

Os arquivos �.h� (header) tem como função ser um espelho dos arquivos�.c� disponibilizando as funções de um arquivo �.c� para serem utilizadasem outros arquivos. Nele colocamos todos os protótipos das funções quequeremos que os outros arquivos usem.

Se quisermos que uma função só possa ser utilizada dentro do próprio ar-quivo, por motivo de segurança ou organização, basta declarar seu protótipoAPENAS no arquivo �.c�.

Se for necessário que um arquivo leia e/ou grave numa variável de outroarquivo é recomendado criar funções especí�cas para tal �nalidade.

O programa 2.1 apresenta um exemplo de um arquivo de código �.c� e oprograma 2.2 apresenta o respectivo arquivo de header �.h�.

Podemos notar que no arquivo �.h� a função AtualizaDisplay() não estápresente, deste modo ela não estará disponível para os outros arquivos. Po-demos notar também que para ler ou gravar a variável �digito� é necessárioutilizar as funções MudarDigito() e LerDigito(). Notar que não existe acessodireto às variáveis. Este tipo de abordagem insere atrasos no processamentodevido à um efeito conhecido como overhead de funções, podendo inclusivecausar travamentos no sistema caso não exista espaço su�ciente no stack.

2.4 Diretivas de compilação

As diretivas de compilação são instruções que são dadas ao compilador. Elasnão serão executadas. Todas as diretivas de compilação começam com umsinal #, conhecido como jogo da velha ou hash.

#include

A diretiva de compilação #include é a responsável por permitir que o pro-gramador utilize no seu código funções que foram implementadas em outrosarquivos, seja por ele próprio ou por outras pessoas. Não é necessário pos-suir o código fonte das funções que se deseja utilizar. É necessário apenasde um arquivo que indique os protótipos das funções (como elas devem serchamadas) e possuir a função disponível em sua forma compilada.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 25: Sistema embarcados

16 Linguagem C para sistemas embarcados

Listing 2.1: Resumo do disp7seg.c

1 // v a r i á v e l usada apenas dentro de s t e arqu ivo2 stat ic char temp ;3 // v a r i á v e l que será usada também fora do arqu ivo4 stat ic char valor ;5 // funções usadas dentro e fo ra do arqu ivo6 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ódigo da função17 }18 // função usada apenas dentro de s t e arqu ivo19 void AtualizaDisplay (void )20 {21 // código da função22 }

Listing 2.2: Resumo do disp7seg.h

1 #ifndef VAR_H2 #define VAR_H

3 void MudaDigito (char val ) ;4 char LerDigito (void ) ;5 void InicializaDisplays (void ) ;6 #endif //VAR_H

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 26: Sistema embarcados

17 Linguagem C para sistemas embarcados

Em geral um arquivo que possui apenas protótipos de funções é denomi-nado de �Header� e possui a extensão �.h�.

#de�ne

Outra diretiva muito conhecida é a #de�ne. Geralmente é utilizada parade�nir uma constante mas pode ser utilizada para que o código fonte sejamodi�cado antes de ser compilado.

Original CompiladoResultado naTela

#define CONST 15void main (void ){

printf ("%d" , CONST * ←↩3) ;

}

void main (void ){

printf ("%d" , 15 * 3) ;}

45

Função Original Opções de uso com o #de�neResultado naTela

void MostraSaidaPadrao ( ){#ifdef PADRAO Serial

char * msg = ←↩"SERIAL" ;

#elsechar * msg = "LCD" ;

#endif

printf ( msg ) ;}

#include <s td i o . h>#define PADRAO Se r i a lvoid main (void ){

MostraSaidaPadrao ( ) ;}

SERIAL

#include <s td i o . h>#define PADRAO LCDvoid main (void ){

MostraSaidaPadrao ( ) ;}

LCD

Pelo código apresentado percebemos que a mesma função MostraSaidaPa-drao(), apresenta resultados diferentes dependendo de como foi de�nida a

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 27: Sistema embarcados

18 Linguagem C para sistemas embarcados

opção PADRAO.Os de�nes também ajudam a facilitar a localização dos dispositivos e

ajustar as con�gurações no microcontrolador. Todo periférico possui um oumais endereços para os quais ele responde. Estes endereços podem variarinclusive dentro de uma mesma família. Por exemplo o endereço da portaD (onde estão ligados os leds) é 0xF83. Para ligar ou desligar um led épreciso alterar o valor que esta dentro do endereço 0xF83. Para facilitar esteprocedimento, é de�nido um ponteiro para este endereço e rotulado com onome PORTD. De�nir OFF como 0 e ON como 1 facilita a leitura do código.

#ifdef, #ifndef, #else e #endif

As diretivas #ifdef, #ifndef, #else e #endif são muito utilizadas quandoqueremos gerar dois programas que diferem apenas num pequeno pedaço decódigo. Por exemplo dois sistemas de controle de temperatura. O primeiropossui um display de LCD, capaz de mostrar a temperatura textualmente. Osegundo sistema executa a mesma função que o primeiro mas é um dispositivomais barato, portanto possui apenas um led indicativo de sobretemperatura.O código pode ser escrito da seguinte maneira

void ImprimirTemp (char valor ){#ifdef LCD

Imprime_LCD ( valor )#else

i f ( valor > 30){

led = 1 ;}else

{led = 0 ;

}#endif //LCD

}

No momento da compilação o pré-compilador irá veri�car se a �tag� LCDfoi de�nida em algum lugar. Em caso positivo o pré-compilador irá deixartudo que estiver entre o #ifdef e o #else e retirará tudo que está entre o#else e o #endif.

Outra função muito utilizada destas diretivas é para evitar a referênciacircular. Supondo dois arquivos, um responsável pela comunicação serial(serial.h) e o segundo responsável pelo controle de temperatura (temp.h).O projeto exige que a temperatura possa ser controlada pela porta serial etoda vez que a temperatura passar de um determinado patamar deve serenviado um alerta pela porta serial. O aquivo da porta serial (serial.h) temas seguintes funções, apresentadas a seguir.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 28: Sistema embarcados

19 Linguagem C para sistemas embarcados

Listing 2.3: Estrutura de header

1 #ifndef TAG_CONTROLE2 #define TAG_CONTROLE

3 // todo o conteúdo do arqu ivo vem aqui .

5 #endif //TAG_CONTROLE

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

O arquivo de controle da temperatura (temp.h) possui as funções apre-sentadas a seguir.

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

Toda vez que a função LerTemperatura() for chamada, ela deve fazer umteste e se o valor for maior que um patamar chamar a função EnviaSerial()com o código 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 função LerSerial() receber um valor, ela deve chamar afunção AjustaCalor() e repassar esse valor. Para isso o arquivo serial.h deveincluir o arquivo temp.h

#include "temp.h"

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

O problema é que deste modo é criada uma referência circular sem �m:o compilador lê o arquivo serial.h e percebe que tem que inserir o arquivotemp.h. Inserindo o arquivo temp.h percebe que tem que inserir o arquivoserial.h, conforme pode ser visto na Figura 2.1.

A solução é criar um dispositivo que permita que o conteúdo do arquivoseja lido apenas uma vez. Este dispositivo é implementado através da estru-tura apresentada no programa 2.3.

Segundo o código acima, o conteúdo que estiver entre o #ifndef e o #en-dif, só será mantido se a a tag �TAG_CONTROLE� NÃO estiver de�nida.Como isto é verdade durante a primeira leitura, o pré-compilador lê o ar-quivo normalmente. Se acontecer uma referência cíclica, na segunda vez queo arquivo for lido, a tag �TAG_CONTROLE� já estará de�nida impedindo

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 29: Sistema embarcados

20 Linguagem C para sistemas embarcados

#include “serial.h”

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

temp.h

#include “temp.h”

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

serial.h

#include “serial.h”

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

temp.h

Figura 2.1: Problema das Referências Circulares

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 30: Sistema embarcados

21 Linguagem C para sistemas embarcados

assim que o processo cíclico continue, conforme pode ser visto na Figura 2.2.

#infdef TEMP_H #define TEMP_H #include “serial.h”

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

temp.h

#infdef SERIAL_H #define SERIAL_H #include “temp.h”

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

serial.h

#infdef TEMP_H

//tag já definida, //pula o conteúdo

#endif

temp.h

Figura 2.2: Solução das referências circulares com #ifndef

Geralmente se utiliza como tag de controle o nome do arquivo. Esta tagdeve ser única para cada arquivo.

2.5 Tipos de dados em C

�19 Jan 2038 at 3:14:07 AM. The end of the world accordingto Unix (232 seconds after Jan 1st 1970)� - Unix date system

O tipo de uma variável, informa a quantidade de memória, em bytes, que estairá ocupar e como esta deve ser interpretada: com ou sem fração (vírgula).Os tipos básicos de dados na linguagem C são 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

�oat 32 4 3,4 x 10-38 à 3,4 x 1038

double 64 8 3,4 x 10-308 à 3,4 x 10308

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 31: Sistema embarcados

22 Linguagem C para sistemas embarcados

Podemos notar que as variáveis que possuem maior tamanho podem ar-mazenar valores maiores. Notamos também que apenas os tipos �oat e dou-ble possuem casas decimais.

Representação binária e hexadecimal

A grande maioria dos processadores trabalha com dados binários, ou seja,aqueles que apenas assumem valores 0 ou 1. Por isso os tipos apresentadosanteriormente podem ser representados utilizando a base 2. Um valor dotipo char que possui 8 bits será representado por um número de 8 algarismos,todos 0 (zeros) ou 1 (uns). Para realizarmos a conversão de um número nabase decimal para a base 2 podemos seguir o seguinte algoritmo:

1. Dividir o número por 2

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

3. Se o valor é maior que 0 voltar ao número 1

4. Escrever os valores obtidos através do passo 2 de trás para frente.

5. Apresentar o resultado

Por exemplo o número 18.18/2 = 9, resto 09/2 = 4, resto 14/2 = 2, resto 02/2 = 1, resto 01/2 = 0, resto 1Lendo do último resultado para o primeiro temos que1810 = 100102Devido a grande utilização de números binários na programação de baixo

nível é muito comum escrevemos estes números na base 16 ou hexadecimal.A vantagem de escrever o número nesta base é que existe uma conversãosimples de binário para hexadecimal e o número resultante ocupa bem menosespaço na tela.

A base hexadecimal possui 16 "unidades"diferentes. Como existem ape-nas 10 algarismos no sistema de numeração arábico (0, 1, 2, 3, 4, 5, 6, 7, 8,9) utilizamos 6 letras para complementá-los (A, B, C, D, E, F). A conversãoentre valores binários, decimais e hexadecimais é apresentada na Tabela 2.2.

Para converter de binário para hexadecimal basta dividir o número emgrupos de 4 em 4, da esquerda para a direita, e utilizar a tabela acima.

Por exemplo o número 18. Sabemos que este número em binário é repre-sentado por 100102. Separando o número de 4 em 4 algarismos temos:

1-0010Pela tabela:

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 32: Sistema embarcados

23 Linguagem C para sistemas embarcados

Tabela 2.2: Representação decimal � binária - hexadecimal

Decimal Binário Hexadecimal Decimal Binário 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

12 = 11600102 = 216.Logo:100102. = 1216.

Modi�cadores de tamanho e sinal

Um modi�cador de tipo altera o signi�cado dos tipos base e produz um novotipo. Existem quatro tipos de modi�cadores, dois para o tamanho (longe short) e dois para sinal (unsigned e signed). Um tipo declarado com omodi�cador long pode ter tamanho MAIOR ou IGUAL ao tipo original.Um tipo declarado como short deve ter tamanho MENOR ou IGUAL aotipo original. A decisão cabe ao compilador utilizado.

Os tipos declarados como signed possuem um bit reservado para o sinal,deste o valor máximo que podem atingir é menor. Os tipos declarados comounsigned não podem assumir valores negativos, em compensação podem atin-gir o dobro do valor de um tipo signed. Na Tabela 2.3 são apresentadasalgumas variações possíveis.

Na linguagem C, por padrão os tipos são sinalizados, ou seja, possuemparte positiva e negativa. Por isso é raro encontrar o modi�cador signed.

Modi�cadores de acesso

Durante o processo de compilação, existe uma etapa de otimização do pro-grama. Durante esta etapa, o compilador pode retirar partes do código oudesfazer loops com períodos �xos. Por exemplo o código abaixo:

#define X (* ( near unsigned char*) 0xF83 )

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 33: Sistema embarcados

24 Linguagem C para sistemas embarcados

Tabela 2.3: Alteração de tamanho e sinal dos tipos básicos

Tipo Bytes Excursão máxima

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

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

}

Quando compilado apresenta o seguinte código em assembler:

// S t a r t i n g pCode b l o c kS_Teste__main code

_main :. line 19 // Teste . c wh i l e (X!=X) ;

RETURN

Enquanto a variável �x� for diferente de �x� o programa não sai do loop.O compilador entende que esta condição nunca irá acontecer e elimina o loopdo código �nal como podemos ver no código gerado, a rotina de return estálogo após a inicialização do programa _main. Para variáveis comuns o valorsó é alterado em atribuições diretas de valor ou de outras variáveis: (x = 4;)ou (x = y;).

Entretanto existe uma condição onde a variável x pode alterar seu valorindependentemente do programa. Se esta variável representar um endereçode memória associado à um periférico físico, seu valor pode mudar indepen-dentemente do �uxo do programa. Para indicar esta situação ao programautilizamos a palavra reservada volatile.

#define X (* ( volat i le near unsigned char*) 0xF83 )void main (void ) interrupt 0{while (X !=X ) ;

}

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 34: Sistema embarcados

25 Linguagem C para sistemas embarcados

Gerando o código em assembler descrito abaixo:

// S t a r t i n g pCode b l o c kS_Teste__main code

_main :_00105_DS_ :

. line 19 // Teste . c wh i l e (X != X) ;MOVLW 0x83 // pr imeira par te do endereçoMOVWF r0x00

MOVLW 0x0f // segunda par te do endereçoMOVWF r0x01

MOVFF r0x00 , FSR0L

MOVFF r0x01 , FSR0H

MOVFF INDF0 , r0x00 // r e a l i z a pr imeira l e i t u r aMOVLW 0x83 // pr imeira par te do endereçoMOVWF r0x01

MOVLW 0x0f // segunda par te do endereçoMOVWF r0x02

MOVFF r0x01 , FSR0L

MOVFF r0x02 , FSR0H

MOVFF INDF0 , r0x01 // r e a l i z a segunda l e i t u r aMOVF r0x00 , W

XORWF r0x01 , W

BNZ _00105_DS_ // f a z o t e s t e para i gua l dadeRETURN

Podemos perceber que, deste modo, o compilador é forçado a ler a variávelx duas vezes e realizar o teste para ver se ela permanece com o mesmo valor.

Em algumas situações é necessário indicar que algumas variáveis não po-dem receber valores pelo programa. Para isto utilizamos a palavra reservadaconst. Utilizamos este modi�cador para indicar que a variável representaum local que apenas pode ser lido e não modi�cado, por exemplo uma portapara entrada de dados. Nesta situação é comum utilizar as palavras volatilee const junto.

#define X (* ( volat i le const near unsigned char*) 0xF83 )// i n i c i o do programavoid main (void ) interrupt 0{

X = 3 ;}

Se tentarmos compilar este código aparecerá a seguinte mensagem deerro:

Teste . c : error 33 : Attempt to assign value to a constant ←↩variable (=)

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 35: Sistema embarcados

26 Linguagem C para sistemas embarcados

Modi�cadores de posicionamento

As variáveis podem ser declaradas utilizando os modi�cadores near e far. Es-tes modi�cadores indicam ao compilador em qual região de memória devemser colocadas as variáveis.

A região near geralmente se refere à �zero page�. É uma região maisfácil de ser acessada. A região far exige mais tempo para executar a mesmafunção que a near.

Podemos pensar nestas regiões como a memória RAM e a memória Cachedo computador. A segunda é mais rápida, mas possui um alto custo e porisso geralmente é menor. Em algumas situações é interessante que algumasvariáveis nunca saiam do cache, pois são utilizadas com grande frequênciaou são críticas para o sistema.

Modi�cador de persistência

Em geral, as variáveis utilizadas dentro das funções perdem seu valor aotérmino da função. Para que este valor não se perca podemos utilizar ummodi�cador de persistência: static. Com esse modi�cador a variável passaa possuir um endereço �xo de memória dado pelo compilador. Além disso ocompilador não reutiliza este endereço em nenhuma outra parte do código,garantindo que na próxima vez que a função for chamada o valor continue omesmo.

// c r i a um contador p e r s i s t e n t e que é// incrementado a cada chamada de funçãoint ContadorPersistente ( int reseta ){stat ic char variavel_persistente ;i f ( reseta ){

variavel_persistente = 0 ;}else

{return ( variavel_persistente++);

}return −1;

}

2.6 Operações aritméticas

�If people do not believe that mathematics is simple, it is onlybecause they do not realize how complicated life is.� - JohnLouis von Neumann

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 36: Sistema embarcados

27 Linguagem C para sistemas embarcados

Listing 2.4: Operações aritméticas com tipos diferentes

1 void main (void )2 {3 char var08 ;4 int var16 ;5 long int var32 ;6 f loat pont16 ;7 double pont32 ;8 var8 = var8 + var16 ; // 19 var8 = var8 + var8 ; // 210 var16 = var8 * var8 ; // 311 var32 = var32 / var16 ; // 412 var32 = pont32 * var32 ; // 513 pont16 = var8 / var16 ; // 614 pont16 = pont32 * var32 ; // 715 pont16 = 40 / 80 ; // 816 }

Um cuidado a se tomar, na programação em C para sistemas embarcados,é o resultado de operações aritméticas. Por padrão na linguagem C o resul-tado de uma operação aritmética possui tamanho igual ao maior operando.Observando o Programa 2.4 notamos alguns exemplos.

No caso 1 (linha 8) uma variável char somada a um int gera como re-sultado um int (maior operando). Não é possível armazenar esse resultadonum char, haverá perda de informação.

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 umproblema se ambos forem muito próximo do valor limite. Por exemplo: 100+ 100 = 200, que não cabe num char, já que este só permite armazenarvalores de -128 à 127.

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

O terceiro caso (linha 10) está correto, a multiplicação de dois char possuium valor máximo de 127*127=16.129. O problema é que a multiplicação dedois char gera um outro char, perdendo informação. É necessário realizarum typecast antes.

var16 = (( int ) var8 ) * var8 ; // 3 c o r r i g i d o

O quarto caso (linha 11) pode apresentar um problema de precisão. Adivisão de dois inteiros não armazena parte fracionária. Se isto não for crítico

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 37: Sistema embarcados

28 Linguagem C para sistemas embarcados

para o sistema está correto. Lembrar que a divisão de números inteiros émais rápida que de números fracionários.

O quinto caso (linha 12) pode apresentar um problema de precisão. Oresultado da conta de um número inteiro com um ponto �utuante é umponto �utuante. Armazenar esse valor num outro número inteiro gera perdade informação.

O sexto caso (linha 13) apresenta um problema muito comum. A divi-são de dois números inteiros gera um outro número inteiro. Não importase armazenaremos o valor numa variável de ponto �utuante haverá perdade informação pois os operandos são inteiros. Para evitar esse problema énecessário um typecast.

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

No sétimo caso (linha 14) pode haver perda de precisão pois o resultadoda operação é um double, e estamos armazenando este valor num �oat.

O oitavo caso (linha 15) é similar ao sexto. Estamos realizando umaconta com dois números inteiros esperando que o resultado seja 0,5. Comoos operandos são inteiros a expressão será avaliada como resultante em Zero.Uma boa prática é sempre usar ".0" ou "f" após o número para indicaroperações com vírgula.

pont16 = 40f / 8 0 . 0 ; // 8 c o r r i g i d o

Devemos tomar cuidado também com comparações envolvendo númeroscom ponto �utuante.

f loat x = 0 . 1 ;while (x != 1 . 1 ) {printf ("x = %f\n" , x ) ;x = x + 0 . 1 ;

}

O trecho de código acima apresenta um loop in�nito. Como existemrestrições de precisão nos números de ponto �utuante (�oat e double) nemtodos os números são representados �elmente. Os erros de arredondamentopodem fazer com que a condição (x !=1.1) nunca seja satisfeita. Sempreque houver a necessidade de comparação com números de ponto �utuanteutilizar maior, menor ou variações.

f loat x = 0 . 1 ;while (x < 1 . 1 ) {printf ("x = %f\n" , x ) ;x = x + 0 . 1 ;

}

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 38: Sistema embarcados

29 Linguagem C para sistemas embarcados

Apesar de sutis estes tipos de erro podem causar um mau funcionamentodo sistema. Na Figura 2.3 é apresentado um erro gerado através de um loopin�nito.

Figura 2.3: Loop in�nito de um device driver gerando erro no sistema

2.7 Função main()

Todo sistema necessita de iniciar em algum lugar. Em geral, os microcon-troladores, assim que ligados, procuram por suas instruções no primeiro ouúltimo endereço de memória, dependendo da arquitetura utilizada. O espaçode memória disponível neste endereço é geralmente muito pequeno, apenaso necessário para inserir uma instrução de pulo e o endereço onde está afunção principal. Este espaço é conhecido como posição de reset. Exis-tem ainda outros espaços de memória similares a este que, geralmente, sãoalocados próximos. O conjunto destes espaços é conhecido como vetor deinterrupção (Figura 2.4).

A maneira de indicar o ponto de início de um programa depende docompilador. Em geral os compiladores alocam a função main() em algumlugar da memória onde haja espaço disponível. Depois disso dispõem de umainstrução de pulo para o primeiro endereço de memória, onde foi alocada afunção main.

Para o compilador SDCC/GPUtils no MPLAB é necessário indicar quequeremos que a função main() seja chamada toda vez que o sistema foriniciado. Por isso é necessário que a posição de reset dentro do vetor de

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 39: Sistema embarcados

30 Linguagem C para sistemas embarcados

0x58 Testa A0x57 300x56 A recebe0x55 Limpa A

0x59 ...

0x8D Porta B0x8C Salva em0x8B 500x8A A recebe

0x8E ...

0x03 0x550x02 Pulo0x01 0x8A

0x04 ...

0x00 PuloEndereço Instrução

Figura 2.4: Exemplo de funcionamento do vetor de interrupção

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 40: Sistema embarcados

31 Linguagem C para sistemas embarcados

interrupção aponte para a função main. Isto é feito através do atributo�interrupt 0� logo após o nome da função conforme pode ser visto no códigoabaixo.

void main (void ) interrupt 0{

// aqui entra o código do programa}

Outra coisa interessante é que para sistemas embarcados a função prin-cipal não recebe nem retorna nada. Como ela é a primeira a ser chamadanão há como enviar algum valor por parâmetro. Ela também não retornanada pois ao término desta o sistema não está mais operativo.

Em geral sistemas embarcados são projetados para começarem a funci-onar assim que ligados e apenas parar sua tarefa quando desligados. Comotodas as funcionalidades são chamadas dentro da função main()1 espera-seque o programa continue executando as instruções dentro dela até ser desli-gado ou receber um comando para desligar. Este comportamento pode serobtido através de um loop in�nito. Abaixo estão as duas alternativas maisutilizadas.

void main (void ) interrupt 0{for ( ; ; ){

// aqui entra o// código p r i n c i p a l

}}

void main (void ) interrupt 0{while (1 ){

// aqui entra o// código p r i n c i p a l

}}

2.8 Rotinas de tempo

�Time is an illusion, lunchtime doubly so.� - Ford Prefect

É muito comum necessitar que o microcontrolador �que um tempo sem fazernada. Uma maneira de atingir esse objetivo é utilizar um laço FOR2.

unsigned char i ;for (i=0; i < 10 ; i++);

1Em sistemas mais complexos algumas tarefas são executadas independentemente dafunção principal, tendo sua execução controlada através de interrupções.

2Este método não é aconselhado em sistemas de maior porte.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 41: Sistema embarcados

32 Linguagem C para sistemas embarcados

Notar que não estamos utilizando os colchetes. Logo após fechar os pa-rênteses já existe um ponto e virgula. Para entender como esse procedimentofunciona, e estimar o tempo de espera é preciso entender como o compiladortraduz essa função para assembler.

// código em assemb ler 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 0x0a // co loca o va 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 va l o r de W para F (1 c i c l o )

_00107_DS_ :DECFSZ r0x00 , F //decrementa F, se F > 0 executa a ←↩

próxima l i nha (1 c i c l o )BRA _00107_DS_ //" pu la " para o luga r marcado como ←↩

_00107_DS_ (2 c i c l o s )

Percebemos pelo código acima que para realizar um for precisamos de 3passos de inicialização. Cada iteração exige 2 passos: uma comparação e um�pulo�3, totalizando 3 ciclos de inicialização e 3 ciclos de interação.

Se temos um processador trabalhando a 8 MHz, cada instrução é execu-tada em 0.5us.4 Para termos um tempo de espera de 0.5s precisamos de 1milhão de instruções. Se colocarmos loops encadeados podemos multiplicara quantidade de instruções que serão executadas. Para obtermos um valorde 1 milhão de instruções devemos utilizar pelo menos 3 loops encadeados.Os valores dos loops são obtidos de maneira iterativa.

unsigned char i , j , k ;for (i=0; i < 34 ; i++) //3 + 34 * (30.003 + 3) = 1.020 .207 ←↩

i n s t r u çõ e s{for (j=0; j < 100 ; j++) //3 + 100 * (297 + 3) = 30.003 ←↩

i n s t r u çõ e s{for (k=0; k < 98 ; k++); // 3 + 98 * (3) = 297 in s t r u çõ e s

}}

O código acima foi projetado para gerar um atraso de tempo de meiosegundo. Compilando e realizando testes práticos podemos con�rmar que otempo real é aproximadamente 0.51 (s). Esta discrepância acontece porqueagora temos 3 loops encadeados e cada qual com sua variável de controle.Deste modo o compilador precisa salvar e carregar cada variável para realizara comparação.

Percebemos assim que para conhecer corretamente o funcionamento dosistema é necessário, em algumas situações, abrir o código em assembler ge-

3Este valor só é valido quando estamos trabalhando com variáveis char. Se utilizarmosvariáveis int o código em assembler será diferente e teremos que realizar uma nova análise.

4No PIC, cada instrução precisa de 4 ciclos de clock. Para 8MHz, 1 ciclo = 0.5µs.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 42: Sistema embarcados

33 Linguagem C para sistemas embarcados

rado pelo compilador para entender como o este é executado. Nem sempreo compilador toma as mesmas decisões que nós. Além disso ele pode gerarotimizações no código. Existem dois tipos de otimização: uma visando di-minuir o tempo de execução do sistema, deixando-o mais rápido e outra quereduz o tamanho do código �nal, poupando espaço na memória.

A seguir apresentamos um exemplo de função que gera delays com tempoparametrizado.

void delay (unsigned int DL ){unsigned char i , j , k ;while (DL−−) // executa DL veze s .{for (i=0; i < 34 ; i++) //3 + 34 * (30.003 + 3) = 1.020 .207 ←↩

i n s t r u çõ e s{for (j=0; j < 100 ; j++) //3 + 100 * (297 + 3) = 30.003 ←↩

i n s t r u çõ e s{for (k=0; k < 98 ; k++); // 3 + 98 * (3) = 297 in s t r u çõ e s

}}

}}

2.9 Operações com bits

�All of the books in the world contain no more informationthan is broadcast as video in a single large American city ina single year. Not all bits have equal value.� - Carl Sagan

Nos sistemas microcontrolados, existem algumas variáveis onde cada bit temuma interpretação ou funcionalidade diferente. Por isso é necessário realizaralgumas operações que modi�quem apenas os bits desejados, mantendo orestante dos bits da variável inalterados.

As operações da linguagem C que nos permitem trabalhar com as variá-veis, levando em conta os valores individuais de cada bit, são chamadas debitwise operation.

É importante ressaltar que as operações de bitwise possuem funcionali-dade semelhante a suas respectivas operações lógicas. A diferença é que alógica opera em cima da variável como um todo5 enquanto a bitwise operabit à bit.

5Lembrar que para linguagem C uma variável com valor 0 (zero) representa falso, equalquer outro valor representa verdadeiro.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 43: Sistema embarcados

34 Linguagem C para sistemas embarcados

NOT

A operação NOT lógica retorna um se o valor for zero e 0 se o valor for um.

A !A

0 1

1 0

A operação bitwise NOT (operador �) executa uma NOT lógica. Isso signi�caque a operação é realizada para cada um dos bits da variável, não mais paraa variável como um todo. Na tabela seguinte é apresentada a diferença entreas duas operações.

Declaração Lógico Bitwise

char A = 12 ;// A = 0b00001100

result = ! A ;// r e s u l t = 0

result = ~A ;// r e s u l t = 243// A = 0b00001100// r = 0b11110011

AND

A operação AND lógica (operador &&) retorna 0 se algum dos valores forzero, 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 operação bitwise AND (operador &) executa uma AND lógica para cadapar de bits e coloca o resultado na posição correspondente:

Declaração Lógico Bitwise

char A = 8 ;// A = 0b00001000char B = 5 ;// B = 0b00000101

result = A && B ;// r e s u l t = 1

result = A & B ;// r e s u l t = 0// A = 0b00001000// B = 0b00000101// r = 0b00000000

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 44: Sistema embarcados

35 Linguagem C para sistemas embarcados

OR

A operação OR lógica (operador ||) retorna 1 se algum dos valores for dife-rente 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 operação bitwise OR (operador |) executa uma OR lógica para cada parde bits e coloca o resultado na posição correspondente:

Declaração Lógico Bitwise

char A = 8 ;// A = 0b00001000char B = 5 ;// B = 0b00000101

result = A | | B ;// r e s u l t = 1

result = A | B ;// r e s u l t = 13// A = 0b00001000// B = 0b00000101// r = 0b00001101

XOR

A operação XOR não possui correspondente lógica na linguagem C. Estaoperação pode ser representada como A XOR B = (A && !B)||(!A && B)

A B A ⊕ B

0 0 0

0 1 1

1 0 1

1 1 0

A operação bitwise XOR (operador �) executa uma XOR lógica para cadapar de bits e coloca o resultado na posição correspondente:

Declaração Lógico Bitwise

char A = 8 ;// A = 0b00001000char B = 5 ;// B = 0b00000101

// não e x i s t e em C

result = A ^ B ;// r e s u l t = 15// A = 0b00001000// B = 0b00000101// r = 0b00001101

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 45: Sistema embarcados

36 Linguagem C para sistemas embarcados

Shift

A operação shift desloca os bits para a esquerda (operador <<) ou direita(operador >>). É necessário indicar quantas casas serão deslocadas.

Declaração Shift Esquerda Shift Direita

char A = 8 ;// A = 0b00001000

result = A << 2 ;// r e s u l t = 32// A = 0b00001000// r = 0b00100000

result = A >> 2 ;// r e s u l t = 2// A = 0b00001000// r = 0b00000010

Para variáveis unsigned e inteiras, esta operação funciona como a multi-plicação/divisão por potência de dois. Cada shift multiplica/divide por 2 ovalor. Esta é uma prática muito comum para evitar a divisão que na maioriados sistemas embarcados é uma operação cara do ponto de vista de tempode processamento.

Não utilizar esta operação com o intuito de multiplicar/dividir variáveiscom ponto �xo ou �utuante nem variáveis sinalizadas (signed).

Em diversas ocasiões é necessário que trabalhemos com os bits de maneiraindividual, principalmente quando estes bits representam saídas ou entradasdigitais, por exemplo chaves ou leds.

Supondo que temos 8 leds ligados ao microcontrolador. Cada led é re-presentado através de 1 bit de uma variável. Para ligarmos ou desligarmosapenas um led por vez, não alterando o valor dos demais, devemos nos uti-lizar de alguns passos de álgebra digital.

Ligar um bit (bit set)

Para ligar apenas um bit, utilizaremos uma operação OU. Supondo doisoperandos A e B. Se A é 1 o resultado de (A | B) é 1 independente de B. SeA é 0 o resultado é igual ao valor de B.

Se o objetivo é ligar apenas o bit da posição X devemos criar um valoronde todas as posições são 0's com exceção da posição desejada. Para umamáscara binária de N bits temos (N>=X):

Posição N . . . X+1 X X-1 . . . 0

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

Se a operação OR for executada com a máscara criada, o resultado apre-sentará valor 1 na posição X e manterá os valores antigos para as demaisposições. Exemplo: Ligar apenas o bit 2 da variável PORTD

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 46: Sistema embarcados

37 Linguagem C para sistemas embarcados

// d e f i n e s para por ta s de entrada e sa ída#define PORTD (* ( volat i le near unsigned char*) 0xF83 )#define TRISD (* ( volat i le near unsigned char*) 0xF95 )// i n i c i o do programavoid main (void ) interrupt 0{char mascara ; // v a r i á v e l que guarda a máscaraTRISD = 0x00 ; // con f i gura a por ta D como sa ídaPORTD = 0x00 ; // l i g a todos os l e d s ( l ó g i c a nega t i va )// l i g a o pr imeiro b i t da v a r i á v e lmascara = 1 ; // b i t = 0b00000001// rotac iona−se a v a r i á v e l para que o b i t 1 chegue na pos ição←↩

dese jadamascara = mascara << 2 ; // b i t = 0b00000100// Ligar o b i t 2 , d e s l i g ando o 2o l e dPORTD = PORTD | mascara ;//mantém o s is tema l i g a d o inde f in idamentefor ( ; ; ) ;

}

Desligar um bit (bit clear)

Para desligar apenas um bit o procedimento é similar ao utilizado para ligar.Ao invés de utilizarmos uma operação OU, utilizaremos uma operação AND.A operação AND tem a característica de, dados A e B valores binários, se Aé 1, a resposta de (A & B) será o próprio valor de B, se a A=0, a resposta ézero, independente de B.

Novamente é necessário gerar uma máscara. Mas para esta situação eladeve possuir todos os bits iguais à um com exceção de X, o bit que queremosdesligar.

posição N . . . X+1 X X-1 . . . 0

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

Se a operação AND for executada com a máscara criada, o resultadoapresentará valor 0 na posição X e manterá os valores antigos para as demaisposições. Exemplo: Desligar apenas o bit 2 da variável PORTD.

// d e f i n e s para por ta s de entrada e sa ída#define PORTD (* ( volat i le near unsigned char*) 0xF83 )#define TRISD (* ( volat i le near unsigned char*) 0xF95 )// i n i c i o do programavoid main (void ) interrupt 0{char mascara ; // v a r i á v e l que guarda a máscaraTRISD = 0x00 ; // con f i gura a por ta D como sa ídaPORTD = 0xFF ; // d e s l i g a todos os l e d s ( l ó g i c a ←↩

nega t i va )

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 47: Sistema embarcados

38 Linguagem C para sistemas embarcados

// l i g a o pr imeiro b i t da v a r i á v e lmascara = 1 ; // mascara = 0b00000001// rotac iona−se a v a r i á v e l para que o b i t 1 chegue na pos ição←↩

dese jadamascara = mascara << 2 ; // mascara = 0b00000100// inve r t e−se os v a l o r e s de cada b i tmascara = ~mascara ; // mascara = 0b11111011// Des l i ga o b i t 2 , l i g ando o 2o l e dPORTD = PORTD & mascara ;//mantém o s is tema l i g a d o inde f in idamentefor ( ; ; ) ;

}

É importante notar que geramos a máscara de maneira idêntica àquelautilizada no caso anterior, onde todos os valores são zero e apenas o desejado éum. Depois realizamos a inversão dos valores. Este procedimento é realizadodesta maneira porque não sabemos o tamanho da palavra a ser utilizada nomicrocontrolador: 8 ou 16 bits. Mesmo assim devemos garantir que todos osbits obtenham o valor correto, o que é garantido pela operação de negação.A opção de inicializar a variável com apenas um zero e rotacionar pode nãofuncionar pois, na maioria dos sistemas, a função de rotação insere zeros àmedida que os bits são deslocados e precisamos que apenas um valor sejazero.

Trocar o valor de um bit (bit �ip)

Para trocar o valor de um bit utilizaremos como artifício algébrico a operaçãoXOR. Dado duas variáveis binárias A e B , se A é 1, o valor resultante deA XOR B é o oposto do valor de B, se A=0, a resposta se mantém igual aovalor de B.

Podemos perceber que para trocar o valor de apenas um bit a máscaraserá idêntica àquela utilizada para ligar um bit:

posição N . . . X+1 X X-1 . . . 0

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

Se a operação XOR for executada com a máscara criada, o valor na posiçãoX será trocado, de zero para um ou de um para zero. Exemplo: Trocar o bit2 e 6 da variável PORTD

// d e f i n e s para por ta s de entrada e sa ída#define PORTD (* ( volat i le near unsigned char*) 0xF83 )#define TRISD (* ( volat i le near unsigned char*) 0xF95 )// i n i c i o do programavoid main (void ) interrupt 0{char mascara ; // v a r i á v e l que guarda a mascaraTRISD = 0x00 ; // con f i gura a por ta D como sa ída

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 48: Sistema embarcados

39 Linguagem C para sistemas embarcados

PORTD = 0xF0 ; // d e s l i g a todos os 4 pr imeiros l e d s ( l ó g i c a ←↩nega t i va )

// l i g a o pr imeiro b i t da v a r i á v e lmascara = 1 ; // mascara = 0b00000001// rotac iona−se a v a r i á v e l para que o b i t 1 chegue na pos ição←↩

dese jadamascara = mascara << 2 ; // mascara = 0b00000100// inve r t e−se os v a l o r e s de cada b i t da mascaramascara = ~mascara ; // mascara = 0b11111011//Liga o b i t 2 , d e s l i g ando o l e d 2PORTD = PORTD ^ mascara ;// l i g a o pr imeiro b i t da v a r i á v e lmascara = 1 ; // mascara = 0b00000001// rotac iona−se a v a r i á v e l para que o b i t 1 chegue na pos ição←↩

dese jadamascara = mascara << 6 ; // mascara = 0b01000000// inve r t e−se os v a l o r e s de cada b i t da mascaramascara = ~mascara ; // mascara = 0b11111011// Des l i ga o b i t 6 , l i g ando o l e d 6PORTD = PORTD ^ mascara ;//mantém o s is tema l i g a d o inde f in idamentefor ( ; ; ) ;

}

Percebemos através do exemplo que a utilização do procedimento apre-sentado troca o valor do bit escolhido. Foi utilizado o mesmo procedimentoduas vezes. Na primeira, um bit foi ligado e, na segunda, outro foi desligado.

Veri�car o estado de um bit (bit test)

Para veri�car se o bit X está um utilizaremos novamente a mesma máscarautilizada para bit set e bit toggle:

posição N . . . X+1 X X-1 . . . 0

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

Realizamos então uma operação AND com a variável. O resultado serázero se o bit X, da variável original, for zero. Se o bit da variável original forum a resposta será diferente de zero6.

Exemplo: Testar o bit 3 e 4 da variável PORTD

// d e f i n e s para por ta s de entrada e sa ída#define PORTD (* ( volat i le near unsigned char*) 0xF83 )#define TRISD (* ( volat i le near unsigned char*) 0xF95 )// i n i c i o do programavoid main (void ) interrupt 0{

6A maioria dos compiladores C adotam uma variável com valor diferente de zero comosendo verdadeiro.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 49: Sistema embarcados

40 Linguagem C para sistemas embarcados

char mascara ; // v a r i á v e l que guarda a mascarachar teste ;TRISD = 0x00 ; // con f i gura a por ta D como sa ídateste = 0x00 ; // d e s l i g a todos os b i t s// rodar depo 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 primeiro b i t é 1mascara = 1 ; // mascara = 0b00000001// rotac iona−se a v a r i á v e l para que o b i t 1 chegue na pos ição←↩

dese jadamascara = mascara << 2 ; // mascara = 0b00000100// Ver i f i c a apenas o b i t 2i f ( teste & mascara ){

PORTD = 0x00 ; // se o r e s u l t a do f o r verdade i ro l i g a todos os←↩l e d s

}else

{PORTD = 0xff ; // se o r e s u l t a do f o r f a l s o d e s l i g a todos os ←↩

l e d s}//mantém o s is tema l i g a d o inde f in idamentefor ( ; ; ) ;

}

Criando funções através de de�nes

Uma opção no uso de de�nes é criar funções simples que podem ser escritasem apenas uma linha. Utilizando um pouco de algebrismo e parênteses, épossível escrever as quatro operações anteriores numa única linha. De possedesta simpli�cação podemos criar uma função para facilitar o uso destasoperações através de um de�ne conforme podemos ver nas tabelas 2.4, 2.5,2.6 e 2.7.

2.10 Debug de sistemas embarcados7

�In the beginner's mind there are many possibilities; in theexpert's mind there are few.� - Shunryu Suzuki

A veri�cação de sistemas embarcados apresenta algumas restrições, de modogeral não é possível inferir sobre a operação do sistema sem paralisá-lo. Comoeste tipo de sistema possui vários dispositivos agregados, que funcionam in-dependentemente do processador, é necessário utilizar abordagens diferentespara realizar o debug.

7Mais informações sobre debug de sistemas embarcados referir ao artigo �The ten secretsof embedded debugging� de Stan Schneider e Lori Fraleigh

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 50: Sistema embarcados

41 Linguagem C para sistemas embarcados

Tabela 2.4: Operação bit set com de�ne

Operação Bit set

Passo a Passo

char bit = 2 ;char mascara ;mascara = 1 << bit ;arg = arg | mascara ;

Uma linha arg = arg | (1<<bit )

Com de�ne #define BitSet ( arg , b i t ) ( ( arg ) |= (1<<b i t ) )

Tabela 2.5: Operação bit clear com de�ne

Operação Bit clear

Passo a Passo

char bit = 2 ;char mascara ;mascara = 1 << bit ;arg = arg & ~mascara ;

Uma linha arg = arg & ~(1<<bit )

Com de�ne #define BitSet ( arg , b i t ) ( ( arg ) &= ~(1<<b i t ) )

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 51: Sistema embarcados

42 Linguagem C para sistemas embarcados

Tabela 2.6: Operação bit �ip com de�ne

Operação Bit �ip

Passo a Passo

char bit = 2 ;char mascara ;mascara = 1 << bit ;arg = arg ^ mascara ;

Uma linha arg = arg ^ (1<<bit )

Com de�ne #define BitSet ( arg , b i t ) ( ( arg ) ^= (1<<b i t ) )

Tabela 2.7: Operação bit test com de�ne

Operação Bit clear

Passo a Passo

char bit = 2 ;char mascara ;mascara = 1 << bit ;arg = arg & mascara ;

Uma linha arg = arg & (1<<bit )

Com de�ne #define BitSet ( arg , b i t ) ( ( arg ) &= (1<<b i t ) )

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 52: Sistema embarcados

43 Linguagem C para sistemas embarcados

Devemos lembrar que além do software devemos levar em conta possíveisproblemas advindos do hardware. Debounce, tempo de chaveamento, limitedo barramento de comunicação são exemplos de pontos a serem consideradosno momento de depuração.

Externalizar as informações.

A primeira necessidade é conhecer o que está acontecendo em teu sistema.Na programação tradicional para desktop é comum utilizarmos de mensagensno console avisando o estado do programa.

#include "stdio.h"

#include "serial.h"

// i n i c i o do programaint main ( int argc , char* argv [ ] ){

printf ("Inicializando sistema" ) ;i f ( CheckForData ( ) ){

printf ("Chegou informação" ) ;}else

{printf ("Problemas na comunicação" ) ;

}return 0 ;

}

Devemos ter em mente onde é necessário colocar estes alertas e lembrarde retirá-los do código �nal.

Para a placa em questão utilizaremos o barramento de leds que estáligado à porta D. A operação deste dispositivo será estudada posteriormenteem detalhes. Por enquanto basta sabermos que cada bit da variável PORTDestá ligada à um led diferente. Por causa da construção física da placa, oled é aceso com valor 0 (zero) e desligado com o valor 1 (um). Além dissotemos que con�gurar a porta D. Isto é feito iniciando a variável TRISD como valor 0x008.

// d e f i n e s para por ta s de entrada e sa ída#define PORTD (* ( volat i le near unsigned char*) 0xF83 )#define TRISD (* ( volat i le near unsigned char*) 0xF95 )// i n i c i o do programavoid main (void ) interrupt 0{

// conf igurando todos os pinos como sa ída sTRISD = 0x00 ;

8As variáveis PORTD e TRISD são de�nidas como unsigned char e possuem portanto8 bits.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 53: Sistema embarcados

44 Linguagem C para sistemas embarcados

PORTD = 0xFF ; // d e s l i g a todos os l e d s// l i g a apenas o b i t 1 .BitClr ( PORTD , 1 ) ;//mantém o s is tema l i g a d o inde f in idamentefor ( ; ; ) ;

}

Devemos utilizar os leds como sinais de aviso para entendermos o funci-onamento do programa. Isto pode ser feito através das seguintes ideias: �Sepassar desta parte liga o led X�, �Se entrar no IF liga o led Y, se não entrarliga o led Z�, �Assim que sair do loop liga o led W�.

Programação incremental

Ao invés de escrever todo o código e tentar compilar, é interessante realizartestes incrementais. A cada alteração no código realizar um novo teste. Evi-tar alterar o código em muitos lugares simultaneamente, no caso de aparecerum erro �ca mais difícil saber onde ele está.

Checar possíveis pontos de Memory-leak

Se for necessário realizar alocação dinâmica garantir que todas as alocaçõessão liberadas em algum ponto do programa.

Cuidado com a fragmentação da memória

Sistemas com grande frequência na alocação/liberação de memória podemfragmentar a memória até o ponto de inviabilizar os espaços livres disponí-veis, eventualmente travando o sistema. Quando trabalhar com rotinas denível mais baixo, mais próximo ao hardware, tente utilizar apenas mapea-mento estático de memória.

Otimização de código

Apenas se preocupe com otimização se estiver tendo problemas com o cum-primento de tarefas. Mesmo assim considere em migrar para uma plataformamais poderosa. Sistemas embarcados preconizam segurança e não velocidade.

Caso seja necessário otimizar o código analise antes o local de realizara otimização. Não adianta otimizar uma função grande se ela é chamadaapenas uma vez. Utilize-se de ferramentas do tipo pro�ler sempre que possí-vel. Isto evita a perda de tempo e auxilia o programador a visualizar a realnecessidade de otimização de código.

Reproduzir e isolar o erro

Quando houver algum erro deve-se primeiro entender como reproduzi-lo.Não é possível tentar corrigir o erro se não houver maneira de veri�car se ele

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 54: Sistema embarcados

45 Linguagem C para sistemas embarcados

foi eliminado.No momento em que se consegue um procedimento de como reproduzir

o erro podemos começar a visualizar onde ele pode estar. A partir destemomento devemos isolar onde o erro está acontecendo. Uma maneira de sefazer isto em sistemas embarcados é colocar um loop in�nito dentro de umteste, que visa veri�car alguma condição de anomalia. Se o sistema entrarneste teste devemos sinalizar através dos meios disponíveis, ligar/desligaralgum led por exemplo.

// aqui tem um monte de código . . .i f ( PORTB >= 5) //PORTB não deve r i a ser um va l o r maior ←↩

que 5 .{

BitClr ( PORTD , 3 ) ; // l i g a o l e d 3for ( ; ; ) ; // t rava o programa

}// aqui cont inua com um monte de código . . .

2.11 Ponteiros e endereços de memória

�Writing in C or C++ is like running a chain saw with allthe safety guards removed.� - Bob Gray

Toda variável criada é armazenada em algum lugar da memória. Este lugaré de�nido de maneira única através de um endereço.

Para conhecermos o endereço de uma variável podemos utilizar o ope-rador &. Cuidado! Este operador também é utilizado para realização daoperação bitwise AND. Exemplo:

// c r i a a v a r i á v e l a num endereço de memória a ser// dec i d i do pe l o compi ladorint a = 0 ;a = a + 1 ;printf ( a ) ; // imprime o va l o r 1printf ( &a ) ; // imprime o endereço de a ( por exemplo 157821)

Conhecer o endereço de uma variável é muito útil quando queremos criarum ponteiro para ela.

Ponteiro é uma variável que, ao invés de armazenar valores, armazenaendereços de memória. Através do ponteiro é possível manipular o que estádentro do lugar apontado por ele.

Para de�nir um ponteiro também precisamos indicar ao compilador umtipo. A diferença é que o tipo indica �quanto� cabe no local apontado peloponteiro e não o próprio ponteiro.

Sintaxe:

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 55: Sistema embarcados

46 Linguagem C para sistemas embarcados

tipo * nome da variavel ;

Exemplo:

int *apint ;f loat *apfloat ;

Deve-se tomar cuidado, pois nos exemplos acima, apint e ap�oat sãovariáveis que armazenam endereços de memória e não valores tipo int ou�oat. O lugar APONTADO pela variável apint é que armazena um inteiro, domesmo modo que o lugar apontado por �oat armazena um valor fracionário.

Se quisermos manipular o valor do endereço utilizaremos apint e ap�oatmas se quisermos manipular o valor que esta dentro deste endereço devemosusar um asterisco antes do nome da variável. Exemplo:

apfloat = 3 . 2 ;*apfloat = 3 . 2 ;

A primeira instrução indica ao compilador que queremos que o ponteiroap�oat aponte para o endereço de memória número 3.2, que não existe,gerando um erro. Se quisermos guardar o valor 3.2 no endereço de memóriaapontado por ap�oat devemos utilizar a segunda expressão.

Para trabalhar com ponteiros é preciso muito cuidado. Ao ser de�nido,um ponteiro tem como conteúdo não um endereço, mas algo inde�nido. Setentamos usar o ponteiro assim mesmo, corremos o risco de que o conteúdodo ponteiro seja interpretado como o endereço de algum local da memóriavital para outro programa ou até mesmo para o funcionamento da máquina.Neste caso podemos provocar danos no programa, nos dados, ou mesmotravar a máquina.

É necessário tomar cuidado ao inicializar os ponteiros. O valor atribuídoa eles deve ser realmente um endereço disponível na memória.

Por exemplo, podemos criar um ponteiro que aponta para o endereço deuma variável já de�nida:

// de f in indo a v a r i á v e l i v a rint ivar ;// de f in indo o pon te i ro i p t rint *iptr ;//o pon te i ro i p t r recebe o va l o r do endereço da v a r i á v e l i v a riptr = &ivar ;// as próximas l i n h a s são e q u i v a l e n t e sivar = 421 ;*iptr = 421 ;

Com sistemas embarcados existem alguns endereços de memória que pos-suem características especiais. Estes endereços possuem registros de con�-guração, interfaces com o meio externo e variáveis importantes para o pro-

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 56: Sistema embarcados

47 Linguagem C para sistemas embarcados

jetista. É pelo meio da utilização de ponteiros que é possível acessar taisendereços de maneira simples, através da linguagem C.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 57: Sistema embarcados

Capítulo 3

Arquitetura de

microcontroladores

�Any su�ciently advanced technology is indistinguishablefrom magic.� - Arthur C. Clarke

Os microcontroladores são formados basicamente por um processador, me-mória e periféricos interligados através de um barramento conforme Fi-gura 3.1.

Em geral, os periféricos são tratados do mesmo modo que a memória, ouseja, para o processador não existe diferença se estamos tratando com umvalor guardado na memória RAM ou com o valor da leitura de um conver-sor analógico digital. Isto acontece porque existem circuitos eletrônicos quecriam um nível de abstração em hardware. Deste modo todos os dispositivosaparecem como endereços de memória.

3.1 Acesso à memória

A quantidade de memória disponível para um microcontrolador pode acessardepende de dois fatores, os tamanhos das palavras de dados e das palavrasde endereço.

O tamanho da palavra de dados representa quantos bits podem ser colo-cado numa única posição da memória.

O tamanho da palavra de endereço indica quantas posições de memóriao processador consegue enxergar.

Por exemplo, um microcontrolador cujo tamanho de dados e o tamanhoda palavra de endereço são ambos 8 bits possui uma possibilidade memóriade:

tamanho_da_palavra * 2^tamanho_do_endereco8 * 2^8 = 2048 bytes ou 2 kbytes

48

Page 58: Sistema embarcados

49 Arquitetura de microcontroladores

Figura 3.1: Arquitetura do microcontrolador PIC 18F4550

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 59: Sistema embarcados

50 Arquitetura de microcontroladores

O termo possibilidade foi usado pois, apesar de poder alcançar toda essaextensão, nem sempre existe memória física para armazenamento. Podemosimaginar a memória como um armário. Um armário com 6 suportes podeabrigar até 6 gavetas. Depende do marceneiro fabricar e colocar as gavetasneste armário. Podemos até indicar a posição onde queremos guardar algumobjeto, mas se a gaveta não foi colocada não é possível armazenar nada(Figura 3.2).

Suporte número:

Existe gaveta?

1 sim

2 sim

3 não

4 não

5 sim

6 não

Figura 3.2: Memória como um armário

Ao invés de gavetas o marceneiro pode pensar em colocar outros "sistemasde armazenamento" nos espaços (Figura 3.3). Alguns destes sistemas podempermitir que o usuário enxergue o que esta dentro mas não mexa. Alguns vãopermitir que o usuário coloque coisas mas não retire. Outros ainda podempermitir que a pessoa retire objetos mas não possa repô-los.

Suporte número:

Existe gaveta?

1 Vitrine

2 Gaveta

3 Dispenser

4 Não

5 Gaveta

6 Cofre

Figura 3.3: Memória e periféricos como um armário

Esta variedade de "sistemas de armazenamento" representam a variedadede tipos de memória e de interfaces de periféricos que possuímos.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 60: Sistema embarcados

51 Arquitetura de microcontroladores

A memória é identi�cada através de um endereço. Por estarmos tratandode sistemas digitais, o valor do endereço é codi�cado em binário. Comovisto anteriormente, escrever em binário é trabalhoso e muito propenso agerar erros. Visando facilitar esse processo, é comumente adotado o sistemahexadecimal para indicar o local de memória.

Os dispositivos são então ligados à um determinado número de endereçoque passa a identi�cá-lo de forma única. O mesmo acontece para a memóriaRAM e memória ROM. Elas estão ligadas à uma série de endereços. Se,portanto, eu preciso de salvar uma variável na memória, tenho que saberquais endereços estão ligados à memória RAM. Se quero ler alguma infor-mação gravada na memória ROM, preciso conhecer a localização exata antesde realizar a leitura.

Stack 1

Stack 31

ResetBaixa prioridadeAlta prioridade

Memória EEPROM

Não implementado

...GPR1

GPR3

GPR4

GPR2

Não implementado

SFR

0x00000x00080x0018

0x00280x7FFF

0X80000X1FFFFF

0x0000x0FF

0x2000x2FF

0x3000x3FF

0x1000x1FF

...

0xF600xFFF

Vet

or d

eIn

terr

upçã

o

Figura 3.4: Regiões de memórias disponíveis no PIC18F4550

A porta D do microcontrolador PIC 4550 por exemplo está no endereço0xF83, destinado aos registros de função especial ou special function register,SFR Figura 3.4).

3.2 Clock e tempo de instrução

O microcontrolador é capaz de realizar apenas uma tarefa por vez. Estastarefas são executadas sempre a intervalos regulares de�nidos pelo clock dosistema. O clock de�ne então a velocidade com que o processador trabalha.

Algumas operações são mais demoradas pois são compostas de uma quan-tidade maior de tarefas. Por exemplo a soma.

A soma de números inteiros é feita de maneira direta enquanto para so-

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 61: Sistema embarcados

52 Arquitetura de microcontroladores

mar dois números fracionários, que estão em notação cientí�ca1, é necessárioigualar as potencias antes de realizar a soma. Por este motivo a segundaoperação é mais demorada que a primeira.

Exemplo:

Multiplicação de inteiros Multiplicação de fracionários

A = 123456;B = 34567;C = A x B ;//C = 4267503552

// 1 . Mu l t i p l i c a r os ←↩números

// 123456// * 34567// 4267503552

A = 1.23456 x 10 ^ 5B = 3.4567 x 10 ^ 4C = A x B

//C = 4.267503552 x 10 ^9

// 1 . Converter para o mesmo expoente// 12.3456 x 10 ^ 4// 3.4567 x 10 ^ 4// 2 . Mu l t i p l i c a r os números//e somar a mantissa// 12.3456 x 10 ^ 4// x 3.4567 x 10 ^ 4// 42.67503552 x 10 ^ 8// 3 . Cor r i g i r quant idade de casas dec .// 4.267503552 x 10 ^ 9

Conhecer quanto tempo o código leva para ser executado permite aodesenvolvedor saber de maneira determinística qual é a exigência a nível dehardware para o sistema embarcado.

Por exemplo: Um sistema precisa de executar 200 operações a cada milé-simo de segundo. Cada operação possuí uma quantidade diferente de tarefasconforme podemos ver na Tabela 3.1.

Tabela 3.1: Quantidade de operações e tarefas

Operação com: Quantidade Total de tarefas

1 tarefa 104 104

2 tarefas 63 126

3 tarefas 21 63

4 tarefas 12 48

Total 200 341

1Números fracionários podem ser armazenados de dois modos no ambiente digital. Omodo mais comum é o ponto �utuante que se assemelha à notação cientí�ca.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 62: Sistema embarcados

53 Arquitetura de microcontroladores

O total de tarefas a serem realizadas é de 341 tarefas por milissegundo.Isso dá uma quantidade de 341 mil tarefas por segundo. Se cada tarefaé realizada em um ciclo de clock precisamos de um microcontrolador cujoprocessador trabalhe no mínimo em 341 kHz.

3.3 Esquema elétrico e circuitos importantes

Um microcontrolador é representado através de esquema elétrico. O es-quema elétrico apresenta ao projetista todos os componentes e suas ligaçõesconforme apresentado na Figura 3.5.

Figura 3.5: Esquema elétrico: Microcontrolador PIC 18F4550

Para funcionarem, todos os microcontroladores devem ser alimentadoscom tensão contínua. O valor varia de modelo para modelo. Alguns podematé mesmo aceitar diversos valores. O PIC 18F4550 por exemplo pode seralimentado com qualquer tensão contínua entre 2 e 5,5 volts.

Para gerar o clock necessário, que de�nirá a velocidade na qual o proces-sador ira trabalhar, em geral é utilizado um oscilador a cristal, que possuiuma ótima precisão.

Alguns microcontroladores podem dispensar o cristal externo optandopor utilizar uma malha RC interna ao chip. Esta alternativa é muito menosprecisa e geralmente não permite valores muito altos de clock. A vantagemé que sistemas que utilizam malha RC interna como osciladores primários

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 63: Sistema embarcados

54 Arquitetura de microcontroladores

possuem um custo menor que sistemas que dependem de malhas de oscilaçãoexterna, seja ela excitada por outra malha RC ou por um cristal.

Existem alguns circuitos que não são essenciais para o funcionamentodo sistema, mas auxiliam muito no desenvolvimento. Entre estes tipos decircuito o mais importante é o que permite a gravação do programa no pró-prio circuito. Alguns microcontroladores exigem que o chip seja retirado docircuito e colocado numa placa especial para gravá-lo e somente depois re-colocado na placa para teste. Este é um procedimento muito trabalhoso e,devido ao desgaste mecânico inerente, reduz a vida útil do chip.

Para evitar estes problemas, os fabricantes desenvolveram estruturas nochip que permitem que este seja gravado mesmo estando soldado à placa �nal.Para isso, basta que o desenvolvedor disponibilize o contato de alguns pinoscom um conector. Este conector será ligado à um gravador que facilitaráo trabalho de gravação do programa. Para a família PIC esta tecnologia édenominada ICSP (in circuit serial programming).

Multiplexação nos terminais do microcontrolador

Conforme pode ser observado na Figura 3.5, alguns pinos/terminais possuemmais de uma descrição. Por exemplo o terminal 8, a descrição deste termi-nal é "RE0/AN5/CK1SPP". Isto indica que dependendo da con�guraçãoescolhida ele pode ser um terminal:

� de entrada ou saída referente ao primeiro bit da porta E (RE0)

� de leitura analógica pertencente ao quinto conversor analógico - digital(AN5)

� utilizado para enviar um clock externo de comunicação paralela (CK1SPP)

A escolha de qual funcionalidade será utilizada depende do projetista. Emsistemas mais avançados é possível inclusive utilizar mais de uma funciona-lidade no mesmo terminal em períodos alternados, desde que o circuito sejaprojetado levando esta opção em consideração.

3.4 Registros de con�guração do microcontrolador

A maioria dos terminais dos microcontroladores podem ser con�gurados paratrabalhar de diversas maneiras. Esta con�guração é realizada através deregistros especiais. Estes registros são posições de memória pré-de�nidospelo fabricante. Para conhecer quais são e o que fazem é preciso recorrer aodatasheet do componente.

Além dos registros de con�guração dos terminais, existem registros queindicam como o microcontrolador deve operar. O microcontrolador PIC18f4550

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 64: Sistema embarcados

55 Arquitetura de microcontroladores

Figura 3.6: Registros de con�guração do microcontrolador PIC 18F4550

possui dez registros que controlam seu modo de operação, velocidade, modode gravação, etc. Estes registros são apresentados na Figura 3.6.

Dos registros apresentados na Figura 3.6, quatro precisam necessaria-mente ser con�gurados para que o sistema possa funcionar. Dois deles temrelação com a con�guração do sistema de clock: um especi�ca qual é a fontedo sinal de clock, que no caso da placa em questão é um cristal externo, eooutro indica qual o prescaler a ser usado (PLL).

Além de con�gurar a frequência básica do clock é necessário desligar owatchdog. Este é um circuito para aumentar a segurança do sistema em-barcado desenvolvido. Para funcionar corretamente, o programa deve serpreparado para tal �nalidade. Ele será explicado em detalhes na seção 4.13

e por isso será mantido desligado nos próximos exemplos.A ultima con�guração necessária é desabilitar a programação em baixa

tensão. Devido às ligações feitas na placa, deixar esta opção ligada impedeo funcionamento da placa enquanto estiver ligada ao gravador. Abaixo otrecho de código que realiza estas con�gurações para o compilador SDCC.

// P l l d e s l i g a docode char at 0x300000 CONFIG1L = 0x01 ;// Osc i lador c/ c r i s t a l ex terno HScode char at 0x300001 CONFIG1H = 0x0C ;// Watchdog con t ro lado por so f twarecode char at 0x300003 CONFIG2H = 0x00 ;// Sem programação em baixa tensãocode char at 0x300006 CONFIG4L = 0x00 ;

A primeira coluna de números indica a posição do registro que armazenaas con�gurações. A segunda coluna representa os códigos utilizados paracon�guração. Para conhecer as demais opções de con�gurações devemos

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 65: Sistema embarcados

56 Arquitetura de microcontroladores

consultar o manual do usuário.Estas con�gurações são dependentes do compilador a ser usado. A se-

guir demonstramos os códigos necessários para o compilador C18 da Micro-chip(R).

// Osc i lador c/ c r i s t a l ex terno HS#pragma c on f i g FOSC = HS// P l l d e s l i g a do#pragma c on f i g CPUDIV = OSC1_PLL2// Watchdog con t ro lado por so f tware#pragma c on f i g WDT = OFF// Sem programação em baixa tensão#pragma c on f i g LVP = OFF

Notar que as diretivas utilizadas são completamente diferentes, mas rea-lizam o mesmo trabalho.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 66: Sistema embarcados

Capítulo 4

Programação dos Periféricos

�In theory, there is no di�erence between theory and practice;In practice, there is.� - Chuck Reid

Periféricos são os componentes, circuitos ou sistemas ligados ao microcon-trolador, interna ou externamente. Eles podem ser utilizados para realizarinterface entre o homem e o equipamento ou incluir funcionalidades extrasao sistema, como comunicação, segurança, etc.

Os periféricos de saída1 que serão abordados neste curso serão:

� Barramento de Led's(4.3)

� Display de 7 segmentos(4.4)

� Display LCD 2x16(4.6)

� Saídas PWM(4.9)

Entre os periféricos de entrada2 temos:

� Leitura de teclas(4.5)

� Conversor AD(4.8)

Além de sistemas de entrada e saída de dados será abordado um dis-positivo de comunicação serial (4.7), um tratador de Interrupção(4.12), umTimer(4.10) e um dispositivo de segurança: Watchdog(4.13).

1Periféricos que fornecem informações aos usuários ou enviam comandos da a placaeletrônica para o meio externo

2Periféricos que recebem informações ou comandos do meio externo

57

Page 67: Sistema embarcados

58 Programação dos Periféricos

4.1 Acesso às "portas" do microcontrolador

Omicrocontrolador possui "portas" que permitem o interfaceamento do meioexterno para o meio interno. Algumas portas podem trabalhar como recep-toras ou transmissoras de sinais. Algumas podem operar dos dois modossendo necessário con�gurá-las antes de sua utilização.

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 endereços de memória. O primeiro ar-mazena o valor que queremos ler do meio externo ou escrever para o meioexterno dependendo da con�guração. O segundo endereço realiza esta con-�guração indicando quais bits serão utilizados para entrada e quais serãoutilizados para saída (Tabela 4.1).

Tabela 4.1: Endereços de memória para as portas do PIC 18F4550

Porta Endereço dos dados Endereço de con�guração (TRIS)

PORTA 0xF80 0xF92

PORTB 0xF81 0xF93

PORTC 0xF82 0xF94

PORTD 0xF83 0xF95

PORTE 0xF84 0xF96

Aqui o conceito de ponteiros se faz extremamente necessário. Já queconhecemos os endereços �xos onde as portas se encontram, podemos criarponteiros para tais endereços de forma que possamos utilizar as portas comose fossem variáveis. Exemplo:

// i n i c i o do programavoid main (void ) interrupt 0{

// de f in imos como :// unsigned char : po i s os 8 b i t s representam va 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 qua l quer momento

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 68: Sistema embarcados

59 Programação dos Periféricos

//near : ind i ca posic ionamento do r e g i s t r o e s t a na memóriavolat i le near unsigned char *PORTD = 0xF83 ;volat i le near unsigned char *TRISD = 0xF95 ;// conf igurando todos os pinos como sa ída s// 0 = sa ída (Output )// 1 = entrada ( Input )*TRISD = 0b00000000 ;// l i g a apenas os quatro ú l t imos l e d s*PORTD = 0b11110000 ;//mantém o s is tema l i g a d o inde f in idamentefor ( ; ; ) ;

}

Notar que, por serem ponteiros, sempre que precisarmos utilizar o valorde tais variáveis é necessário que coloquemos o asterisco.

Uma outra maneira de manipular as portas é criar de�nes que permitemo uso das portas como variáveis, sem a necessidade de utilizar ponteiros demodo explicito, nem asteriscos no código.

// d e f i n e s para por ta s de entrada e sa ída#define PORTD (* ( volat i le near unsigned char*) 0xF83 )#define TRISD (* ( volat i le near unsigned char*) 0xF95 )// i n i c i o do programavoid main (void ) interrupt 0{

// conf igurando todos os pinos como sa ída sTRISD = 0b00000000 ;// l i g a apenas os quatro ú l t imos l e d sPORTD = 0b11110000 ;//mantém o s is tema l i g a d o inde f in idamentefor ( ; ; ) ;

}

Como estamos criando um de�ne, é uma boa prática de programaçãoutilizar apenas letras maiúsculas para diferenciá-lo de uma variável comum.

Notem que usamos dois asteriscos no de�ne. É isto que permite queutilizemos o de�ne como uma variável qualquer, sem precisar de usar umasterisco a todo momento, como no caso dos ponteiros.

A segunda abordagem (com de�ne) é preferida em relação à primeira pois,dependendo do compilador, gera códigos mais rápidos além de economizarmemória. Além disso, permite que a de�nição seja feita apenas uma vez eutilizada em todo o programa.

4.2 Con�guração dos periféricos

�Make everything as simple as possible, but not simpler.� -Albert Einstein

Em geral, os terminais das portas são multiplexados com outros dispositivos.Para saber como con�gurar cada porta é preciso conhecer os registros de

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 69: Sistema embarcados

60 Programação dos Periféricos

con�guração que atuam sobre a porta desejada. A Figura 4.1 apresentatodos os registros disponíveis do microcontrolador 18F4550.

Figura 4.1: Registros de con�guração dos periféricos do PIC 18F4550

Para a placa que estamos utilizando, a con�guração dos terminais doPIC segue conforme a Tabela 4.2. Esta con�guração re�ete a opção do autorde acordo com as possibilidades da placa e também o sistema mínimo pararealização de todas as experiencias da apostila.

Os terminais não citados na Tabela 4.2 (1, 3, 5, 6, 15, 18, 23 e 24)possuem periféricos que não serão utilizados neste curso. Os terminais 11 e31 representam a alimentação positiva. O comum (terra) está ligado ao 12e ao 32. O microcontrolador utilizado (18f4550) possui o encapsulamentoDIP. Para outros encapsulamentos favor considerar o datasheet.

Da Tabela 4.2, temos que a porta A possui o primeiro bit como entradaanalógica e o terceiro e sexto como saída digital. Os dois bits digitais servem

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 70: Sistema embarcados

61 Programação dos Periféricos

Tabela 4.2: Tabela de con�guração do PIC para as experiênciasTerminal Descrição do pino Função

2 RA0/AN0Potenciômetro / Sensor deTemperatura

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

14 OSC2/CLKO/RA6

16 RC1/T1OSI/CCP2 Aquecedor

17 RC2/CCP1/P1A Ventilador / Buzzer

19 RD0/SPP0

Barramento de dados para oLCD/7seg/Led

20 RD1/SPP1

21 RD2/SPP2

22 RD3/SPP3

25 RC6/TX/CKRS232

26 RC7/RX/DT/SDO

27 RD4/SPP4

Barramento de dados para oLCD/7seg/Led

28 RD5/SPP5/P1B

29 RD6/SPP6/P1C

30 RD7/SPP7/P1D

33 RB0/AN12/INT0/SDI

Saídas para alimentação doteclado

34 RB1/AN10/INT1/SCK

35 RB2/AN8/INT2/VMO

36 RB3/AN9/CCP2/VPO

37 RB4/AN11/KBI0/CSSPP

Entradas para leitura doteclado

38 RB5/KBI1/PGM

39 RB6/KBI2/PGC

40 RB7/KBI3/PGD

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 71: Sistema embarcados

62 Programação dos Periféricos

como controle de ativação do display.

TRISA = 0b00000010 ; // conf igurando os te rmina i s como entrada ←↩e sa ída

ADCON1 = 0b00001110 ; //apenas o pr imeiro termina l é ana lóg i co

A porta B possui os 4 primeiros bits como saídas e os quatro últimoscomo entrada. Esta porta serve para leitura da matriz de chaves. É possívelrealizar a leitura através de interrupção.

TRISB = 0b11110000 ; // conf igurando os te rmina i s como entrada ←↩e sa ída

// con f i guração com in te r rupção h a b i l i t a d aINTCON = 0b11000101 ;INTCON2 = 0b00000001 ;// con f i guração sem in te r rupçãoINTCON = 0b00000000 ;INTCON2 = 0b00000001 ;SPPCFG = 0b00000000 ; //RB0 e RB4 são con t ro l ados pe l a por ta ←↩

B e não pe l o SPP

A porta C possui o segundo e terceiro bit como saída PWM e o sétimo eoitavo como comunicação serial.

TRISC = 0b10000000 ; // conf igurando os te rmina i s como saída , ←↩apenas RC7 é entrada

CCP1CON = 0b00001100 ; // con f i gura o segundo termina l como PWMCCP2CON = 0b00001100 ; // con f i gura o t e r c e i r o termina l como PWMTXTA = 0b00101100 ; // con f i gura a transmissão de dados da ←↩

s e r i a lRCSTA = 0b10010000 ; // con f i gura a recepção de dados da s e r i a lBAUDCON = 0b00001000 ; // con f i gura s i s tema de v e l o c i dade da ←↩

s e r i a lSPBRGH = 0b00000000 ; // con f i gura para 56kSPBRG = 0b00100010 ; // con f i gura para 56k

A porta D é utilizada como barramento de dados. Os valores escritos nelasão transmitidos, simultaneamente, para os leds, os displays de 7 segmentose o display de LCD.

TRISD = 0b00000000 ; // conf igurando os te rmina i s como sa ída

A porta E possui apenas os 3 primeiros bits con�gurados como saídasdigitais. São utilizados para controle de ativação dos displays e tambémcomo sinais de controle do LCD.

TRISE = 0b00000000 ; // conf igurando os te rmina i s como sa ída

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 72: Sistema embarcados

63 Programação dos Periféricos

4.3 Barramento de Led's

Existe na placa utilizada um barramento de 8 bits, onde cada linha possuium led associado. Este barramento está ligado diretamente com a porta Ddo microcontrolador conforme Figura 4.2.

Figura 4.2: Barramento de Led's

Podemos notar pela Figura 4.2 que existe um jumper (JP1) que habilitaou não o funcionamento destes leds. Além disso percebemos que se o jumperestiver encaixado, os led's estão permanentemente ligados ao 5 volts. Destemodo, para que o led acenda, é necessário colocar o valor 0 (zero) no respec-tivo bit da porta D. Quando um dispositivo é ligado com o valor 0 (zero) edesligado com o valor 1 (um), dizemos que este dispositivo opera com lógicainvertida.

Conforme visto é preciso con�gurar os pinos da porta D como saída, paraisso basta escrever zero em cada um deles no registro TRISD.

void main (void ) interrupt 0{

TRISD = 0x00 ; // con f i gura os pinos da por ta D como sa ídaPORTD = 0xF0 ; // l i g a apenas os quatro ú l t imos b i t s .for ( ; ; ) ; //mantém o s is tema num loop i n f i n i t o

}

4.4 Display de 7 segmentos

Os displays de 7 segmentos (Figura 4.3) são componentes opto eletrônicosutilizados para apresentar informações para o usuário em formato numérico.

Estes displays foram concebidos com o intuito de gerar os dez algarismosromanos: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, sendo que os algarismos 0, 6, 7 e 9 podemser representados de mais de uma maneira.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 73: Sistema embarcados

64 Programação dos Periféricos

Figura 4.3: Display de 7 SegmentosFonte: Peter Halasz -

http://commons.wikimedia.org/wiki/File:Seven_segment_02_Pengo.jpg

Além dos algarismos é possível representar apenas algumas letras demodo não ambíguo: as maiúsculas A, C, E, F, H, J, L, P, S, U, Z e asminúsculas: a, b, c, d, h, i, n, o, r, t, u.

Os displays podem ser do tipo catodo comum, ou anodo comum indicandoqual o tipo de ligação dos leds. Contudo, esta diferença não será críticapara este estudo. Na Figura 4.4 podemos visualizar o esquema elétrico e adisposição física de cada led no componente.

Figura 4.4: Diagrama elétrico para display de 7 segmentos com anodo comumhttp://www.hobbyprojects.com/the_diode/seven_segment_display.html

Pela Figura 4.4 podemos notar que para que apareça o número 2 nodisplay é necessário acender os leds a, b, g, e, d. Se estivermos utilizandoum display com catodo comum, precisamos colocar um nível alto para ligaro led, ou seja, o led liga com valor 1 (um) e desliga com valor 0 (zero). Isto étambém conhecido como lógica positiva. Na Tabela 4.3 são apresentados os

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 74: Sistema embarcados

65 Programação dos Periféricos

valores em binário e em hexadecimal para cada representação alfanumérica3.Dentre as letras disponíveis estão apresentadas apenas os caracteres A, b, C,d, E, F. Estas foram escolhidos por serem os mais utilizados para apresentarvalores em hexadecimal nos displays. Neste curso utilizaremos a ordem direta

Tabela 4.3: Conversão binário - 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

apresentada na Tabela 4.3. A utilização de uma ou outra depende da ligaçãofeita na placa. A Figura 4.5 apresenta o esquema elétrico disponível.

Para simpli�car a utilização deste tipo de display é comum criar umatabela cujas posições representam o valor de conversão para o display. Con-forme pode ser visto no código a seguir.

void main (void ) interrupt 0

3Notar que os valores hexadecimais apresentados servem apenas quando existe umasequencia na ligação entre a porta do microcontrolador e os pinos do display. Em algunssistemas, o display pode ser controlado por duas portas diferentes, ou possuir alguma alte-ração na sequencia de ligação. Para tais casos é necessário remontar a tabela apresentada.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 75: Sistema embarcados

66 Programação dos Periféricos

Figura 4.5: Ligação de 4 displays de 7 segmentos multiplexados

{// ve to r que armazena a conversão dos a l gar i smos para o ←↩

d i s p l a y 7 segconst char conv [ ] = {0x3F , 0x06 , 0x5B , 0x4F , 0x66 , 0x6D , ←↩

0x7D , 0x07 ,0x7F , 0x6F , 0x77 , 0x7C , 0x39 , 0x5E , 0x79 , 0x71 } ;

unsigned int var , time ;TRISD = 0x00 ;TRISA = 0x00 ;PORTA = 0xFF ;for ( var = 0 ; var < 16 ; var++){

// co loca os ca ra c t e r e s em sequênc ia na sa ídaPORTD = conv [ var ] ;//apenas para contar tempofor ( time = 0 ; time < 65000; time++);

}}

Multiplexação de displays

Cada display exige 7 ou 8 terminais de controle, caso também seja utilizadoo ponto decimal. Para utilizar 4 displays, por exemplo um relógio com doisdígitos para horas e dois para minutos, precisaríamos de 32 terminais desaída, o que pode ser um custo4 muito alto para o projeto.

Uma técnica que pode ser utilizada é a multiplexação dos displays. Estatécnica leva em conta um efeito biológico denominado percepção retiniana.O olho humano é incapaz de perceber mudanças mais rápidas que 1/30 (s).

4Microcontroladores com mais terminais possuem um custo superior, mesmo possuindoos mesmos periféricos internamente.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 76: Sistema embarcados

67 Programação dos Periféricos

Outro fator importante é que as imagens mais claras �cam gravadas naretina devido ao tempo que leva para sensibilizar e dessensibilizar as células(bastonetes).

Deste modo podemos ligar e desligar rapidamente o display que a imagemcontinuará na retina. Se ligarmos cada display, um por vez, sequencialmente,de maneira su�cientemente rápida, teremos a impressão que todos estãoligados. A frequência de �chaveamento� deve ser mais rápida que 30Hz.

A Figura 4.5 apresenta o circuito com 4 displays multiplexados. Perce-bemos que os terminais iguais estão ligados juntos. Percebemos também queos terminais de catodo comum estão cada um ligado à uma saída diferente.Com esta arquitetura reduzimos a quantidade de terminais necessários de 32para 12, uma economia de 20 terminais.

Mas esta economia tem um custo, o sistema se torna mais complexo poisnão podemos ligar dois displays ao mesmo tempo.

O controle de qual display será ligado é feito através do transistor quepermite a ligação do catodo comum ao terra, ou o anodo comum ao VCC(depende do tipo de dispositivo. Para o correto funcionamento não bastaagora acender os leds corretos para formar o número, temos que seguir umalgoritmo mais complexo:

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

2. ligar o display X através da linha de comando

3. esperar um tempo adequado para evitar �icker5

4. desligar o display

5. escolher o próximo display (X+1)

6. voltar ao passo 1

Criação da biblioteca

O programa 4.1 apresenta um exemplo de código para criar uma bibliotecapara os displays de 7 segmentos. O programa 4.2 apresenta o header dabiblioteca. Já o programa 4.3 apresenta uma demonstração de uso da bibli-oteca.

5Se a taxa de atualização dos displays for muito baixa, estes vão apresentar uma vari-ação na intensidade, como se estivessem piscando. Este efeito é chamado de �icker.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 77: Sistema embarcados

68 Programação dos Periféricos

Listing 4.1: disp7seg.c

1 #include "disp7seg.h"

2 // ve to r para armazenar a ←↩conversão do d i s p l a y

3 stat ic const char valor [ ] = ←↩{0x3F , 0x06 , 0x5B , 0x4F , ←↩0x66 , 0x6D , 0x7D , 0x07 , ←↩0x7F , 0x6F , 0x77 , 0x7C , ←↩0x39 , 0x5E , 0x79 , 0x71 } ;

4 // ind i ca o d i s p l a y a t ua l5 stat ic char display ;6 // va l o r e s dos d i s p l a y s7 stat ic char v0 , v1 , v2 , v3 ;8 void MudaDigito (char val , char←↩

pos )9 {10 i f ( pos == 0)11 {12 v0 = val ;13 }14 i f ( pos == 1)15 {16 v1 = val ;17 }18 i f ( pos == 2)19 {20 v2 = val ;21 }22 i f ( pos == 3)23 {24 v3 = val ;25 }26 }

28 void InicializaDisplays (void )29 {30 // con f i guração dos pinos de ←↩

con t r o l e31 BitClr ( TRISA , 2 ) ;32 BitClr ( TRISA , 5 ) ;33 BitClr ( TRISE , 0 ) ;34 BitClr ( TRISE , 2 ) ;35 //apenas AN0 é ana lóg i co36 ADCON1 = 0x0E ;37 //Porta de dados38 TRISD = 0x00 ;39 }

40 void AtualizaDisplay (void )41 {42 // d e s l i g a todos os d i s p l a y s43 PORTA = 0x00 ;44 PORTE = 0x00 ;45 // d e s l i g a todos os l e d s46 PORTD = 0x00 ;47 // l i g a apenas o d i s p l a y da vez48 switch ( display )49 {50 case 0 :51 PORTD = valor [ v0 ] ;52 BitSet ( PORTA , 5 ) ;53 display = 1 ;54 break ;55 case 1 :56 PORTD = valor [ v1 ] ;57 BitSet ( PORTA , 2 ) ;58 display = 2 ;59 break ;60 case 2 :61 PORTD = valor [ v2 ] ;62 BitSet ( PORTE , 0 ) ;63 display = 3 ;64 break ;65 case 3 :66 PORTD = valor [ v3 ] ;67 BitSet ( PORTE , 2 ) ;68 display = 0 ;69 break ;70 default :71 display = 0 ;72 break ;73 }74 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 78: Sistema embarcados

69 Programação dos Periféricos

Listing 4.2: disp7seg.h

1 #ifndef DISP7SEG_H2 #define DISP7SEG_H

3 void MudaDigito (char val , char pos ) ;4 void AtualizaDisplay (void ) ;5 void InicializaDisplays (void ) ;6 #endif

Listing 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 programa6 void main (void ) interrupt 07 {8 unsigned int 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 // gas ta um tempo para e v i t a r o e f e i t o f l i c k e r18 for ( tempo=0;tempo<1000;tempo++);19 }20 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 79: Sistema embarcados

70 Programação dos Periféricos

4.5 Leitura de teclas

Para realizar a leitura de uma tecla é necessário criar um circuito que realizea leitura de um sinal elétrico para o valor zero e outro para o valor um.Os níveis de tensão associados dependem muito dos circuitos envolvidos.Os níveis mais comuns são os compatíveis com TTL, onde o zero lógico érepresentado por 0v (zero volts) e o um lógico é representado por 5v (cincovolts).

Uma maneira de se obter este funcionamento é com o uso de uma chaveligada ao VCC e um pull-down ou uma chave ligada ao terra (GND) e umpull-up.

Figura 4.6: Circuito de leitura de chavehttp://www.labbookpages.co.uk/electronics/debounce.html - Dr. Andrew

Greensted

Pela Figura 4.6 percebemos que a tensão de saída é igual a VCC quando achave está desligada pois não existe corrente circulando no circuito portantoa queda de tensão em R1 é zero. Quando a chave é pressionada uma corrente�ui de VCC para o terra passando por R1. Como não existe nenhuma outraresistência no circuito toda a tensão �ca em cima de R1 e a tensão de saídapassa a ser zero.

Apesar do funcionamento aparentemente simples, este tipo de circuitoapresenta um problema de oscilação do sinal no momento em que a tecla épressionada. Esta oscilação é conhecida como bouncing (Figura 4.7).

Estas oscilações indevidas podem gerar acionamentos acidentais, cau-sando mau funcionamento do programa. Para evitar isso podemos utilizartécnicas de debounce, por hardware ou software.

A opção 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 atrasopara o sinal. Este é o tempo necessário para carregar o capacitor. Deste

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 80: Sistema embarcados

71 Programação dos Periféricos

Figura 4.7: Oscilação do sinal no momento do chaveamentohttp://www.labbookpages.co.uk/electronics/debounce.html - Dr. Andrew

Greensted

Figura 4.8: Circuito de debouncehttp://www.ikalogic.com/debouncing.php - Ibrahim Kamal

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 81: Sistema embarcados

72 Programação dos Periféricos

modo as alterações rápidas no sinal, devido à oscilação mecânica da chave,são �ltradas e não ocorre o problema dos chaveamentos indevidos conformepode ser visto na Figura 4.9. Notar que o nível do sinal �ltrado não chegaa zero em nenhum momento, devido à constante de tempo do �ltro RC sermaior que o período de debounce.

Figura 4.9: Utilização de �ltro RC para debounce do sinalhttp://www.labbookpages.co.uk/electronics/debounce.html � A. Greensted

(modi�cado)

Debounce por software

O debounce por software em geral é utilizado em situações onde se desejaaumentar a robustez de uma entrada que já possua um debounce por hard-ware ou reduzir o custo da placa utilizando apenas a solução por software.A grande desvantagem deste tipo de sistema é inserir um atraso na detecçãoda informação.

Para realizar o debounce por software precisamos ter uma noção dotempo que a chave precisa para estabilizar. Da Figura 4.7 temos que estetempo, para uma determinada chave é de aproximadamente 150 (µs). Umciclo de clock do sistema em questão (PIC18f4550 com cristal de 8MHz) éde 0,5 (µs). Antes de utilizar o valor que estamos lendo na porta em questãodevemos esperar 300 ciclos de clock após alguma mudança para ter certezaque o sinal se estabilizou, ou seja, a fase de bouncing acabou.

Notar que, no código, o contador é iniciado com o valor 22. Através daanálise do assembler podemos saber que cada ciclo de conferencia do sinal

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 82: Sistema embarcados

73 Programação dos Periféricos

possui 14 instruções. Assim é necessário que o sinal permaneça com o mesmovalor durante 308 ciclos para que a variável valAtual receba o valor da portaB. Estes valores podem ser determinados empiricamente através de testescom osciloscópios.

void main (void ) interrupt 0{unsigned char valTemp ;unsigned char valAtual ;unsigned char tempo ;TRISB = 0xF0 ; //mantém os 4 ú l t imos b i t s como entradaTRISD = 0x00 ; //Configura a por ta D como sa ídaPORTB = 0x00 ; // l i g a os 4 pr imeiros b i t sBitClr ( INTCON2 , 7 ) ; // h a b i l i t a pu l l−upADCON1 = 0b00001110 ; //apenas AN0 é ana lóg ico , e a ←↩

r e f e r en c i a é baseada na fon t efor ( ; ; ){

//aguarda uma mudança na porta Bwhile ( valAtual==PORTB ) ;//quando acontecer alguma mudança , conta um tempo pra ver ←↩

se é permanentevalTemp = PORTB ;tempo = 22 ;while ( tempo > 0){

i f ( valTemp == PORTB ) // se não mudar cont inua a contar{

tempo−−;}else

{valTemp = PORTB ; // se mudar , a t u a l i z a o s i s tema e ←↩

r e i n i c i a o tempotempo = 22 ;

}}valAtual = valTemp ; // va l o r a t ua l i z a do ;PORTD = valAtual ; // co loca o va l o r no barramento de l e d s

}}

Arranjo de leitura por matriz

Para cada tecla/botão que é colocado no projeto, é necessário um terminal domicrocontrolador. Para um teclado maior é possível que o microcontroladornão possua terminais disponíveis em quantidade su�ciente. Do mesmo modoque no caso dos displays é possível multiplexar as chaves aumentando aquantidade de chave por terminal. Novamente, este ganho, em termos dehardware, aumenta a complexidade para o software e juntamente com este,

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 83: Sistema embarcados

74 Programação dos Periféricos

o custo em termos de tempo de computação.Uma das técnicas mais e�cientes para a geração deste teclado é o arranjo

em formato matricial. Com esta con�guração podemos, com N terminais,ler até (N/2)�2 chaves.

Conforme podemos ver na Figura 4.10, cada chave pode ser identi�cadaunicamente pela sua posição (linha, coluna). Os terminais ligados às linhasserão con�gurados como entrada, que servirão para ler os valores das teclas.Os terminais ligados às colunas serão con�gurados como saídas, fornecendoenergia para as chaves. A leitura é realizada então por um processo conhecidocomo varredura: liga-se uma coluna por vez e veri�ca-se quais chaves daquelacoluna estão ligadas.

void main (void ) interrupt 0{unsigned char i , j ;unsigned char chave [ 2 ] [ 4 ] = {{0 ,0 , 0 , 0} , {0 , 0 , 0 , 0}} ;INTCON2 &= 0x7F ; // h a b i l i t a pu l l−upADCON1 = 0b00001110 ; //apenas AN0 é ana lóg ico ,TRISB = 0xF0 ; // os 4 ú l t imos b i t s são entradaTRISD = 0x00 ; // con f i gura a por ta D como sa ídaPORTD = 0xff ;for ( ; ; ){for (i = 0 ; i < 2 ; i++){

PORTB = 0xff ; //" d e s l i g a " todas as co lunasfor (j = 0 ; j < 100 ; j++);BitClr ( PORTB , i ) ; //" l i g a " o b i t da coluna correspondente

// gas ta tempo para ga ran t i r que o pino a t i n g i u o ←↩n i v e l a l t o

for (j = 0 ; j < 100 ; 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 matr iz .

for (j = 0 ; j < 4 ; j++){

i f ( ! BitTst ( PORTB , j+4) ){

chave [ i ] [ j ] = 1 ;BitSet ( PORTD , j+4*i ) ;

}else

{chave [ i ] [ j ] = 0 ;BitClr ( PORTD , j+4*i ) ;

}}

}}

}

É importante notar que o código acima não apresenta debounce em soft-ware para as teclas. É possível realizar um debounce minimizando o gasto

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 84: Sistema embarcados

75 Programação dos Periféricos

Figura 4.10: Teclado em arranjo matricial

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 85: Sistema embarcados

76 Programação dos Periféricos

com memória e tempo, representando cada chave como um bit diferentenuma variável. Esta será a abordagem utilizada na geração da bibliotecapara o teclado.

Criação da biblioteca

O programa 4.4 apresenta um exemplo de código para criar uma bibliotecapara um teclado de 16 teclas com leitura matricial. O header pode ser vistono programa 4.5. Já o programa 4.6 apresenta uma demonstração de uso dabiblioteca.

4.6 Display LCD 2x16

O display de LCD utilizado neste curso possui duas linhas por 16 colunasde caracteres, compatível com o HD44780 que é um padrão muito utilizadona indústria. Na Figura 4.11 é apresentado um modelo genérico deste tipode display. A Figura 4.12 apresenta o verso do display com os terminaisexpostos.

Figura 4.11: Display Alfanumérico LCD 2x16

Este mesmo tipo de display pode ser encontrado em diversas versões comtamanhos e cores diferentes sendo os mais comuns de 1x8, 2x16 e 4x40. Podeainda ter 16 ou 14 terminais, dependendo se existe ou não retro iluminação.Estes terminais são identi�cados como:

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 86: Sistema embarcados

77 Programação dos Periféricos

Listing 4.4: teclado.c

1 #include "teclado.h"

2 #include "basico.h"

3 stat ic unsigned int valor = 0x0000 ;4 unsigned int LerTeclas (void ) {5 return valor ;6 }7 void DebounceTeclas (void ) {8 unsigned char i , j ;9 stat ic unsigned char tempo ;10 stat ic unsigned int valorNovo = 0x0000 ;11 stat ic unsigned int valorAntigo = 0x0000 ;12 for (i = 0 ; i < 4 ; i++){13 PORTB |= 0x0F ; // d e s l i g a todas as co lunas14 BitClr ( PORTB , ( i ) ) ; // l i g a a coluna correspondente15 // gas ta tempo sem r e a l i z a r função nece s sá r i o para ga ran t i r ←↩

que o pino a t i n g i u o n i v e l a l t o16 for (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 l18 for (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 = 10 ;30 valorAntigo = valorNovo ;31 }32 i f ( tempo == 0) {33 valor = valorAntigo ;34 }35 }

37 void InicializaTeclado (void ) {38 TRISB = 0xF0 ; // quatro entradas e quatro sa ída s39 INTCON2 &= 0x7F ; // h a b i l i t a pu l l−up40 ADCON1 = 0b00001110 ; //apenas AN0 é ana lóg i co41 SPPCFG = 0x00 ;42 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 87: Sistema embarcados

78 Programação dos Periféricos

Listing 4.5: teclado.h

1 #ifndef TECLADO_H2 #define TECLADO_H

4 unsigned int LerTeclas (void ) ;5 void DebounceTeclas (void ) ;6 void InicializaTeclado (void ) ;7 #endif //TECLADO_H

Listing 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 programa6 void main (void ) interrupt 07 {8 InicializaTeclado ( ) ;9 TRISD = 0x00 ; //Configura a por ta D como sa ída10 PORTD = 0xFF ; // d e s l i g a todos os l e d s11 while (1==1)12 {13 DebounceTeclas ( ) ;14 PORTD = LerTeclas ( ) ;15 }16 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 88: Sistema embarcados

79 Programação dos Periféricos

Figura 4.12: Display Alfanumérico LCD 2x16 - verso

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 89: Sistema embarcados

80 Programação dos Periféricos

1. Terra

2. VCC (+5V)

3. Ajuste do contraste

4. Seleção de registro(RS)

5. Read/Write (RW)

6. Clock, Enable (EN)

7. Bit 0

8. Bit 1

9. Bit 2

10. Bit 3

11. Bit 4

12. Bit 5

13. Bit 6

14. Bit 7

15. Backlight + (opcional)

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 manutenção doestado do display, controle da luminosidade e interface com o restante dosistema eletrônico. A comunicação é realizada através de um barramentoparalelo de 8 bits, por onde são enviados os dados/comandos.

O terminal RS indica ao display se o barramento contém um comando aser executado (0) ou uma informação para ser exibida (1).

O terminal RW indica ao display se ele receberá um valor (0) ou seestamos requisitando alguma informação (1).

O terminal EN indica ao display que ele pode ler/executar o que está nobarramento de dados.

Atenção, o display utilizado apresenta os terminais colocados de maneiranão sequêncial, conforme pode ser visto na Figura 4.12. Deste modo não équalquer display que é compatível.

As informações são enviadas através da codi�cação ASCII, sendo que oscaracteres de 0 à 127 são padronizados. Os caracteres de 128 à 255 dependemdo fabricante do display. É possível também criar algumas representações,símbolos de�nidos pelo usuário e armazenar na memória interna do display.Para um display com a ROM do tipo A00 temos os caracteres de�nidos naFigura 4.13. Para a ROM A02 temos a Figura 4.14.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 90: Sistema embarcados

81 Programação dos Periféricos

Figura 4.13: Caracteres disponíveis para ROM A00http://www.sparkfun.com/datasheets/LCD/HD44780.pdf - Datasheet

Hitachi

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 91: Sistema embarcados

82 Programação dos Periféricos

Figura 4.14: Caracteres disponíveis para ROM A02http://www.sparkfun.com/datasheets/LCD/HD44780.pdf - Datasheet

Hitachi

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 92: Sistema embarcados

83 Programação dos Periféricos

Os comandos reconhecidos pelo display são apresentados na Tabela 4.4.

Tabela 4.4: Lista de comandos aceitos pelo o LCD

Instrução RS RW Barramento de dados (bit) Tempo

7 6 5 4 3 2 1 0

Limpa todo o display e con�gura oendereço para 0.

0 0 0 0 0 0 0 0 0 1 37 us

Con�gura o endereço para 0. Re-torna o display para o início sehouve alguma operação de shift.

0 0 0 0 0 0 0 0 1 - 1.52 ms

Con�gura a movimentação do cur-sor e o modo de shift do display

0 0 0 0 0 0 0 1 ID S 37 us

Con�gura o display (D) inteiro paradesligado ou ligado, cursor (C) li-gado ou desligado e "blinking" (B)do cursor.

0 0 0 0 0 0 1 D C B 37 us

Move o cursor e/ou o display semalterar o conteúdo

0 0 0 0 0 1 SC RL - - 37 us

Con�gura o tamanho da palavra(DL), número de linhas (N) e fontedos caracteres (F)

0 0 0 0 1 DL N F - - 37 us

Desloca o cursor para a posição de-sejada: linha e coluna.

0 0 1 X 0 0 Coluna 37 us

Veri�ca se o display está disponívelou se esta ocupado com alguma ope-ração interna.

0 1 BF - - - - - - - 10 us

De�nições das opções

ID: 1 � Incrementa, 0 � DecrementaS: 1 � O display acompanha o deslocamentoSC: 1 � Desloca o display, 0 � Desloca o cursorRL: 1 � Move para direita, 0 � Move paraesquerdaDL: 1 � 8 bits, 0 � 4 bits

N: 1 � 2 linhas, 0 � 1 linhaF: 1 � 5x10 pontos, 0 � 5x8 pontosBF: 1 � Ocupado, 0 � DisponívelX: 1 � 2a linha, 0 � 1a linhaColuna: nible que indica a coluna

http://www.sparkfun.com/datasheets/LCD/HD44780.pdf - DatasheetHitachi (modi�cado)

Os terminais de dados estão ligados à porta D, juntamente com o displayde 7 segmentos e barramento de dados. Para estes dispositivos funcionaremem conjunto é necessário multiplexa-los no tempo. Os terminais de controleestão ligados à porta E conforme o esquema apresentado na Figura 4.15.

Criação da biblioteca

Para facilitar o controle do display, podemos criar quatro funções, uma parainicialização, uma para escrever um caractere, outra para enviar um comando

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 93: Sistema embarcados

84 Programação dos Periféricos

Figura 4.15: Esquemático de ligação do display de LCD

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 94: Sistema embarcados

85 Programação dos Periféricos

e a última para veri�car se o display está disponível. Estas funções estãoapresentadas no programa 4.7, que constitui um exemplo de biblioteca. Oheader desta biblioteca e um exemplo de como usá-la são apresentados nosprogramas 4.8 e 4.9, respectivamente.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 95: Sistema embarcados

86 Programação dos Periféricos

Listing 4.7: lcd.c

1 #include "lcd.h"

2 #include "basico.h"

3 #define RS 04 #define EN 15 #define RW 2

7 void InicializaLCD (void )8 {9 // I n i c i a l i z a o LCD10 Delay2ms ( ) ;11 Delay2ms ( ) ;12 Delay2ms ( ) ;13 Delay2ms ( ) ;14 Delay2ms ( ) ;15 // con f i g . de d i reção (E/S)16 BitClr ( TRISE , RS ) ; //RS17 BitClr ( TRISE , EN ) ; //EN18 BitClr ( TRISE , RW ) ; //RW19 TRISD = 0x00 ; //dados20 ADCON1 = 0b00001110 ;21 // con f i gura o d i s p l a y22 //8 b i t s , 2 l inhas , 5x823 EnviaComando (0 x38 ) ;24 //modo incrementa l25 EnviaComando (0 x06 ) ;26 // d i sp l ay , cursor e b l i n k i n g on27 EnviaComando (0 x0F ) ;28 // zera contadores in t e rno s29 EnviaComando (0 x03 ) ;30 // l impar d i s p l a y31 EnviaComando (0 x01 ) ;32 // pos ição i n i c i a l33 EnviaComando (0 x80 ) ;34 }

36 void Delay40us (void ) {37 unsigned char i ;38 for (i=0; i < 25 ; i++);39 }

41 void Delay2ms (void ) {42 unsigned char i ;43 for (i=0; i < 200 ; i++){44 Delay40us ( ) ;45 }46 }

47 void EnviaDados (char valor )48 {49 //dados50 BitSet ( PORTE , RS ) ;51 // h a b i l i t a e s c r i t a52 BitClr ( PORTE , RW ) ;53 PORTD = valor ;54 // h a b i l i t a l e i t u r a55 BitSet ( PORTE , EN ) ;56 Delay40us ( ) ;57 // termina l e i t u r a58 BitClr ( PORTE , EN ) ;59 // de ixa em n í v e l ba ixo60 BitClr ( PORTE , RS ) ;61 // de ixa em n í v e l ba ixo62 BitClr ( PORTE , RW ) ;63 Delay40us ( ) ;64 }

66 void EnviaComando (char cmd )67 {68 //comando69 BitClr ( PORTE , RS ) ;70 // h a b i l i t a e s c r i t a71 BitClr ( PORTE , RW ) ;72 PORTD = cmd ;73 // h a b i l i t a l e i t u r a74 BitSet ( PORTE , EN ) ;75 Delay2ms ( ) ;76 // termina l e i t u r a77 BitClr ( PORTE , EN ) ;78 // de ixa em n í v e l ba ixo79 BitClr ( PORTE , RS ) ;80 // de ixa em n í v e l ba ixo81 BitClr ( PORTE , RW ) ;82 Delay2ms ( ) ;83 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 96: Sistema embarcados

87 Programação dos Periféricos

Listing 4.8: lcd.h

1 #ifndef LCD_H2 #define LCD_H

3 void EnviaComando (char cmd ) ;4 void EnviaDados (char valor ) ;5 void InicializaLCD (void ) ;6 #endif //LCD_H

Listing 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 programa6 void main (void ) interrupt 07 {8 unsigned int i , j ;9 char msg [ ] = "Hello World!" ;10 InicializaLCD ( ) ;11 for (i=0;i<11;i++)12 {13 EnviaDados ( msg [ i ] ) ;14 for (j = 0 ; j < 65000; j++);15 }16 for ( ; ; ) ;17 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 97: Sistema embarcados

88 Programação dos Periféricos

4.7 Comunicação serial

Em geral a comunicação entre dois dispositivos eletrônicos é realizada demodo serial, isto é, as informações são passadas bit à bit do transmissorpara o receptor. Este tipo de comunicação possui algumas vantagens emrelação à comunicação paralela, na qual a palavra (byte) é enviada toda deuma vez.

A primeira vantagem é a simpli�cação do hardware. Como os dados sãoenviados um a um, é necessário apenas um �o de comunicação e um pararetorno.

A segunda é a maior taxa de transmissão, o que a primeira vista é in-consistente já que num mesmo ciclo de clock a comunicação paralela enviamais de um bit, enquanto a serial apenas um. Este fato acontece pois parafrequências muito altas pode existir atraso entre um �o e outro se os cabosda comunicação paralela possuírem qualquer diferença. Além disso existe oproblema do crosstalking, onde o campo magnético gerado por um cabo in-duz uma pequena tensão no outro cabo, atrapalhando a comunicação. Estesproblemas aumentam com a frequência limitando assim a máxima trans-ferência possível pelo barramento paralelo. É este o motivo que levou osprojetistas de hardware a desenvolverem o protocolo SATA, em detrimentoao IDE/ATA, para comunicação entre o HD e a placa mãe conforme podeser visto na Tabela 4.5.

Tabela 4.5: Taxas de transmissão 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 comunicação RS232 (Recommended Standard 232) é um pro-tocolo muito utilizado para comunicação entre dispositivos que transmitemou recebem pouca quantidade de informações. É um dos protocolos maisantigos sendo utilizado pela primeira vez em 1962 para máquinas de escrever

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 98: Sistema embarcados

89 Programação dos Periféricos

eletromecânicas. O padrão RS232 revisão C é datado de 1969. Em 1986 apa-rece a revisão D pela EIA (Electronic Industries Alliance). A versão atualdo protocolo é datada de 1997 pela TIA (Telecommunications Industry As-sociation) sendo chamada TIA-232-F.

O procedimento de envio de um valor pela serial através do padrão RS232pode ser visto como uma operação de bit-shift.

Por exemplo a letra K. Em ASCII é codi�cada como 7610 e em bináriocomo 110100102. Na maioria dos dispositivos primeiro se envia o bit menossigni�cativo. Antes de iniciar a transmissão dos bits, é enviado um bit decomeço, indicando que haverá transmissão a partir daquele instante. Apósisso o bit menos signi�cativo é enviado para a saída do microcontrolador.Realiza-se então um shift para direita e o �novo� bit menos signi�cativo é�reenviado�. Esta operação é realizada oito vezes. Após esse procedimentoenvia-se um bit de parada, que pode ter a duração de um ou dois bits.

A Figura 4.16 apresenta o sinal elétrico6 enviado ao longo do tempopara a letra K. Notar a região em branco, que se extende entre +3 e -3. Elaindica a região de tensão na qual o sinal não está de�nido. Caso a tensão lidaesteja nestes limiares, seja devido à ruidos ou outros problemas, o sistemade recepção não entenderá a mensagem e os dados podem ser corrompidos.

Figura 4.16: Sinal serializado para transmissão em RS232

Para o correto funcionamento do protocolo devemos garantir compatibi-lidade no nível físico (do hardware) e lógico (no software).

Para o hardware basta compatibilizar o tipo de conector, os níveis detensão e a pinagem dos conectores.

6Para o protocolo RS232 o nível alto ou 1 (um) é aquele com tensões positivas entre+3 e +15. O nível logico baixo ou 0 (zero) é interpretado entre -3 e -15 volts.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 99: Sistema embarcados

90 Programação dos Periféricos

Para o nível de software temos que de�nir a codi�cação utilizada (ASCII,UTF-8, etc), especi�car o �uxo de caracteres (quantidade de bits por carac-tere, tamanho do start/stop bit, paridade) e a taxa de transmissão desejada.

Estas con�gurações são realizadas através de 5 registros TXSTA, RCSTA,BAUDCON, SPBRGH e SPBRG.

Os registros TXSTA e RCSTA são responsáveis por con�gurar o meiode transmissão: presença/ausência de bit de parada, tamanho da palavra deum caractere, transmissão síncrona/assíncrona.

O registro BAUDCON é responsável por con�gurar o controle de veloci-dade de transmissão.

Os registros SPBRGH e SPBRG representam o byte mais alto e o maisbaixo da palavra de 16 bits que indica a taxa de transmissão.

A taxa de transmissão pode ser calculada segundo a Tabela 4.6.

Tabela 4.6: Cálculo do valor da taxa de transmissão da porta serial

Bits de Con�guração Precisão Taxa de transmissão

TXSTA:4 BAUDCON:3 TXSTA:2

0 0 0 8bits F232 =FOSC

[64 ∗ (n + 1)]0 0 1 8bits

F232 =FOSC

[16 ∗ (n + 1)]0 1 0 16bits

0 1 1 16bits

F232 =FOSC

[4 ∗ (n + 1)]1 0 x 8bits

1 1 x 16bits

x � não importa, n � valor do par SPBRGH:SPBRG

Como visto na Tabela 4.6 existem três formulas diferentes para calcular ataxa de transmissão. A melhor maneira de con�gurar a taxa de transmissãoda porta serial é veri�car qual dos métodos gera o menor erro para uma dadataxa de transmissão.

Por exemplo, queremos uma taxa de transmissão de 57,6 kbps. A frequên-cia disponível é um cristal de 8MHz. Usando as três formulas chegamos aosseguintes 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 equação que gera o menor erro é a terceira. Como queremos trabalharcom uma comunicação assíncrona, da Tabela 4.6 obtemos que os bits de

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 100: Sistema embarcados

91 Programação dos Periféricos

con�guração devem ser: TXSTA(4) = 0, BAUDCON(3) = 1 e TXSTA(2) =1. A seguir temos todo o processo de con�guração da porta serial RS232.

BitClr ( BAUDCON , 0 ) ; // De s a b i l i t a auto de tecção de v e l o c i dadeBitSet ( BAUDCON , 3 ) ; // Reg i s t ro de geração de s i n a l com 16 b i t sBitClr ( BAUDCON , 6 ) ; //Operação de recepção e s t a a t i v aBitClr ( RCSTA , 1 ) ; // De s a b i l i t a b i t de erro de overrunBitClr ( RCSTA , 2 ) ; // De s a b i l i t a b i t erro na comunicaçãoBitClr ( RCSTA , 4 ) ; // Hab i l i t a b i t de recepçãoBitClr ( RCSTA , 6 ) ; // Se l ec iona 8 b i t sBitSet ( RCSTA , 7 ) ; //Configura RX/TX como pinos de comunicaçãoBitSet ( TXSTA , 2 ) ; //Modo de a l t a v e l o c i dade h a b i l i t a d oBitSet ( TXSTA , 3 ) ; //Envia b i t de parada ( break charac t e r b i t )BitClr ( TXSTA , 4 ) ; //Modo ass íncronoBitSet ( TXSTA , 5 ) ; // Hab i l i t a transmissãoBitClr ( TXSTA , 6 ) ; // Se l ec iona 8 b i t sSPBRGH = 0x00 ; //Configura para 56k (SPBRGH|SPBRG = 32)SPBRG = 0x22 ; //Configura para 56k (SPBRGH|SPBRG = 32)BitSet ( TRISC , 6 ) ; //Configura pino de recepção como entradaBitClr ( TRISC , 7 ) ; //Configura pino de envio como sa ída

O procedimento de serialização dos bits é feito de maneira automáticapelo hardware. Enquanto ele está realizando este processo não devemosmexer no registro que armazena o byte a ser enviado. Por isso devemosveri�car se o registro está disponível. Isto é feito através do bit 4 do registroPIR. Quando este valor estiver em 1 basta escrever o valor que desejamostransmitir 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 on í v e lTXREG=c ; // co loca o va l o r para ser enviado

}

O processo de desserialização também é realizado de modo automáticopelo hardware do dispositivo. Assim que um byte estiver disponível o sistemaseta o bit 5 do registro PIR1 e podemos então ler o valor disponível no registroRCREG.

unsigned char RecebeSerial (void ){char resp = 0 ;i f ( BitTst ( PIR1 , 5 ) ) // Ver i f i c a se e x i s t e algum va l o r ←↩

d i s p on í v e l{

resp = RCREG ; // re torna o va l o r}return resp ; // re torna zero

}

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 101: Sistema embarcados

92 Programação dos Periféricos

A metodologia apresentada para leitura e escrita de valores é conhecidacomo pooling. Neste tipo de abordagem �camos parados esperando que ovalor esteja disponível para leitura/escrita. Este é o método mais simplespara se controlar qualquer tipo de dispositivo. O problema é que o processa-dor �ca travado em uma tarefa gastando tempo que seria útil para realizaroutras operações. A melhor alternativa para resolver este problema é atravésde interrupções, que serão abordadas apenas no tópico 4.12.

Criação da biblioteca

O programa 4.10 apresenta um exemplo de código para criar uma bibliotecapara comunicação serial. O arquivo de header é apresentado no progrma4.11 e o exemplo de uso demonstrado no programa 4.12.

A seguir o arquivo de header.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 102: Sistema embarcados

93 Programação dos Periféricos

Listing 4.10: serial.c

1 #include {\ textquotedb l } s e r i a l . h{\ textquotedb l }2 #include {\ textquotedb l } bas i co . h{\ textquotedb l }

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 on í v e l7 TXREG=c ; // co loca o va l o r para ser enviado8 }

10 unsigned char RecebeSerial (void )11 {12 char resp = 0 ;13 i f ( BitTst ( PIR1 , 5 ) ) // Ver i f i c a se e x i s t e algum va l o r ←↩

d i s p on i v e l14 {15 resp = RCREG ; // re torna o va l o r16 }17 return resp ; // re torna zero18 }

20 void InicializaSerial (void )21 {22 TXSTA = 0b00101100 ; // con f i gura a transmissão de dados da ←↩

s e r i a l23 RCSTA = 0b10010000 ; // con f i gura a recepção de dados da ←↩

s e r i a l24 BAUDCON = 0b00001000 ; // con f i gura s i s tema de v e l o c i dade da ←↩

s e r i a l25 SPBRGH = 0b00000000 ; // con f i gura para 56k26 SPBRG = 0b00100010 ; // con f i gura para 56k27 BitSet ( TRISC , 6 ) ; // pino de recepção de dados28 BitClr ( TRISC , 7 ) ; // pino de envio de dados29 }

Listing 4.11: serial.h

1 #ifndef SERIAL_H2 #define SERIAL_H

3 void EnviaSerial (unsigned char c ) ;4 unsigned char RecebeSerial (void ) ;5 void InicializaSerial (void ) ;6 #endif //SERIAL_H

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 103: Sistema embarcados

94 Programação dos Periféricos

Listing 4.12: Exemplo de uso da biblioteca de comunicação serial

1 #include "basico.h"

2 #include "config.h"

3 #include "serial.h"

5 // i n i c i o do programa6 void main (void ) interrupt 07 {8 unsigned int i , j ;9 char msg [ ] = "Hello World!" ;10 unsigned char resp ;11 TRISD = 0x00 ; // acesso aos l e d s12 InicializaSerial ( ) ;13 j=0;14 for ( ; ; )15 {16 // de lay17 for (i = 0 ; i < 65000; i++);18 // envia dados19 EnviaSerial ( msg [ j ] ) ;20 j++;21 i f (j > 11)22 {23 j=0;24 EnviaSerial (13) ;25 }26 // recebe dados27 resp = RecebeSerial ( ) ;28 i f ( resp !=0)29 {30 PORTD = resp ;31 }32 }33 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 104: Sistema embarcados

95 Programação dos Periféricos

4.8 Conversor AD

Um conversor de analógico para digital é um circuito capaz de transformarum valor de tensão numa informação binária. O circuito que utilizaremospossui uma precisão de 10 bits, ou seja, ele é capaz de sentir uma variação depraticamente um milésimo7 da excursão máxima do sinal. Para a con�gura-ção que iremos utilizar, com uma fonte de 5v, isto signi�ca uma sensibilidadede 4.88mV.

Elementos sensores

A conversão AD é muito utilizada para realizarmos a leitura de sensores.Todo sensor é baseado num transdutor. Um elemento transdutor é aqueleque consegue transformar um tipo de grandeza em outro, por exemplo umalâmpada incandescente (Figura 4.17).

Figura 4.17: Lâmpada incandescente

Podemos utilizar uma lampada incandescente como sensor de tensão:pega-se uma lâmpada de 220V. Liga-se a lâmpada à uma tomada desconhe-cida. Se o brilho for forte a tomada possui 220V, se o brilho for de baixaintensidade, a tomada possui 127V. Se a lâmpada não ascender existe algumproblema na �ação, na tomada ou até mesmo na lâmpada. A lampada é umtransdutor de tensão para luminosidade.

Para a eletrônica estamos interessados em transdutores cuja saída sejauma variação de tensão, corrente ou resistência.

Um sistema muito simples de transdutor de ângulo para resistência é opotenciômetro (Figura 4.18).

Se o potenciômetro estiver alimentado pelos terminais da extremidade,o terminal central funciona como um divisor de tensão. O valor de saída éproporcional à posição do cursor. Podemos aproximar o potenciômetro comoduas resistências conforme apresentado na Figura 4.19.

7Com uma precisão de 10 bits conseguimos representar 2�10 valores diferentes, ou 1024valores.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 105: Sistema embarcados

96 Programação dos Periféricos

Figura 4.18: Potenciômetro

Figura 4.19: Potenciômetro como divisor de tensãohttp://en.wikipedia.org/wiki/File:Potentiometer_with_load.png

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 106: Sistema embarcados

97 Programação dos Periféricos

Deste modo a tensão aplicada em RL (supondo que RL é muito maiorque R2) é:

VRL =VS ∗R2

R1 + R2= VS ∗ (

R2

RPot)

Se na construção do potenciômetro a variação da resistência ao longo datrilha foi feita de modo constante, a resistência varia de maneira linear coma posição do cursor. Deste modo podemos utilizar o potenciômetro comoum transdutor de ângulo.

Diversas medidas podem ser realizadas utilizando o conceito de divisorde tensão: luminosidade com LDR's, força com strain-gages, deslocamentocom potenciômetros lineares, etc.

Figura 4.20: Circuito integrado LM35

Existem alguns sensores que possuem circuitos de ampli�cação e condi-cionamento do sinal embutidos no mesmo envólucro que o elemento sensor.A estes tipos de sensores damos a denominação de ativos.

Um sensor ativo possui no mínimo 3 terminais: 2 para alimentação e 1para saída 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 integradodo LM35. O diodo é utilizado como unidade sensora de temperatura.

Quando polarizado através de uma corrente constante, havendo mudançade temperatura a tensão em cima do diodo muda. Os dois ampli�cadorese as respectivas realimentações estão inseridas no circuito para ampli�car eestabilizar as variações de tensão.

Processo de conversão AD

Existem alguns circuitos que realizam a conversão de um sinal analógicoadvindo de um transdutor para um sinal digital com uma precisão arbitrária.

A abordagem mais simples é a utilização de comparadores. Cada com-parador possui um nível diferente de tensão de referência. Estes níveis são

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 107: Sistema embarcados

98 Programação dos Periféricos

Figura 4.21: Diagrama de blocos do LM35

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 108: Sistema embarcados

99 Programação dos Periféricos

escolhidos de forma que a representação binária faça sentido.Exemplo: Conversão de um valor analógico que varia de zero à cinco

volts numa palavra digital de dois bits.Para N bits temos N2 representações diferentes. É interessante então

dividir a amplitude inicial por N2 divisões iguais. Para N = 2 temos 4representações de 1.25v cada.

Representação binária com 2 bits Valor em tensão

00 0.625v

01 1.875v

10 3.125v

11 4.375v

O circuito eletrônico responsável pelas comparações pode ser visualizadona Figura 4.22.

Figura 4.22: Conversor analógico digital de 2 bitshttp://en.wikipedia.org/wiki/File:Flash_ADC.png - Jon Guerber

O circuito da Figura 4.22 é conhecido como conversor analógico digital dotipo �ash onde cada nível de tensão possui seu próprio comparador. Existem

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 109: Sistema embarcados

100 Programação dos Periféricos

outras abordagens que minimizam o uso de conversores (parte mais cara docircuito) mas inserem atraso no processo de conversão. O atraso depende dotipo de circuito que é implementado.

Criação da biblioteca

Toda conversão leva um determinado tempo que, conforme citado na seçãoanterior, depende da arquitetura que estamos utilizando, da qualidade doconversor e, algumas vezes, do valor de tensão que queremos converter. Paraque o microcontrolador realize corretamente a conversão é necessário seguiros seguintes passos:

1. Con�gurar o conversor

2. Iniciar a conversão

3. Monitorar o �nal da conversão

4. Ler o valor

Os programas 4.13 e 4.14 apresentam os arquivos de código e header deuma biblioteca exemplo para conversores analógicos para digital no micro-controlador PIC. O programa 4.15 apresenta um código exempli�cando ouso da biblioteca criada.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 110: Sistema embarcados

101 Programação dos Periféricos

Listing 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 entrada6 ADCON0 = 0b00000001 ; // s e l e c i ona o cana l 0 e l i g a o ad7 ADCON1 = 0b00001110 ; //apenas AN0 é ana lóg ico , a r e f e r en c i a é←↩

baseada na fon t e8 ADCON2 = 0b10101010 ; //FOSC /32 , Alinhamento à d i r e i t a e ←↩

tempo de conv = 12 TAD9 }

11 int LeValorAD (void )12 {13 unsigned int ADvalor ;14 ADCON0 |= 0b00000010 ; // i n i c i a conversão15 while ( BitTst ( ADCON0 , 1 ) ) ; // espera terminar a conversão ;16 ADvalor = ADRESH ; // l ê o r e s u l t a do17 ADvalor <<= 8 ;18 ADvalor += ADRESL ;19 return ADvalor ;20 }

Listing 4.14: adc.h

1 #ifndef ADC_H2 #define ADC_H

3 void InicializaAD (void ) ;4 int LeValorAD (void ) ;5 #endif //ADC_H

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 111: Sistema embarcados

102 Programação dos Periféricos

Listing 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 programa6 void main (void ) interrupt 07 {8 unsigned int i ;9 int temp = 0 ;10 InicializaDisplays ( ) ;11 InicializaAD ( ) ;12 for ( ; ; )13 {14 temp = LeValorAD ( ) ;15 temp %= 10000;16 MudaDigito ( temp / 1000 ,3) ;17 temp %= 1000 ;18 MudaDigito ( temp / 100 ,2 ) ;19 temp %= 100 ;20 MudaDigito ( temp / 10 ,1 ) ;21 temp %= 10 ;22 MudaDigito ( temp , 0 ) ;23 AtualizaDisplay ( ) ;24 for (i = 0 ; i < 1000 ; i++);25 }26 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 112: Sistema embarcados

103 Programação dos Periféricos

4.9 Saídas PWM

As saídas PWM são saídas digitais que possuem um chaveamento acoplado.O sinal muda seu estado de positivo para zero várias vezes por segundo. Aporcentagem do tempo que este sinal permanece em nível Alto de�ne o ciclode trabalho, ou duty cycle, da saída. A Figura 4.23 apresenta 3 sinais PWMcom a mesma frequência mas com duty cycle diferentes.

Figura 4.23: Sinais PWM com variação do duty cycle

Suponha uma saída PWM ligada à um resistor. Quando a saída estiverem nível alto existe a passagem de corrente elétrica e a resistência aquece.Quando estiver em nível baixo a corrente para. Como a constante térmicado componente é alta, leva-se alguns segundos para que o resistor aqueça ouesfrie, é possível ajustar a quantidade de energia média com uma frequênciade sinal PWM su�cientemente alta.

Em outras palavras, se a frequência do PWM for mais alta do que acarga conseguir enxergar, quando colocarmos o duty cycle em 50%, a cargairá receber 50% da energia total. Se for um resistor, podemos controlar atemperatura �nal deste modo, num motor podemos ajustar a velocidade derotação que queremos.

Como citado a frequência do PWM tem que ser su�cientemente alta.Esta frequência depende do circuito implementado no microcontrolador. Nocaso do PIC18f4550 é calculada segundo a formula abaixo.

FrequenciaPWM =FOSC

[(PR2 ) + 1] ∗ 4 ∗ (TMR2Prescaler )

Com uma frequência de oscilação de 8MHz (disponível na placa) podemosatingir frequências que variam de 488Hz até 2MHz.

O problema de trabalhar, no caso do PIC, com frequências muito altasé que perdemos resolução na de�nição do duty cycle. Por exemplo, para afrequência de PWM em 2MHz com um clock de 8MHz temos uma resolução

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 113: Sistema embarcados

104 Programação dos Periféricos

de apenas 2 bits. Ou seja, podemos con�gurar a saída para 0%, 25%, 50%ou 75% do valor máximo. A resolução pode ser obtida segundo a formulaabaixo.

ResoluçãoPWM (max ) =log( FOSC

FPWM)

log(2)bits

O PIC18f4550 permite uma resolução de até 10 bits. Com um osciladorprincipal de 8 MHz a frequência máxima do PWM para utilizarmos os 10bits de resolução é 7812,5 Hz. Para uma resolução de 8 bits a frequênciamáxima aumenta para 31.25 kHz.

Utilizando a primeira e segunda formulas podemos montar a Tabela 4.7.

Tabela 4.7: Faixa de frequências máximas e mínimas para cada con�guraçãodo prescaler

Prescaler Freq. máxima (PR2 = 0) Freq. mínima (PR2 = 0)

1 2.000.000 7.812,5

4 500.000 1.953,2

16 125.000 488,3

O duty cycle (em porcentagem) é calculado de acordo com a fórmulaabaixo:

DutyCyclePWM =[CCPRxL : CCPxCON (5 : 4)]

(PR2 + 1) ∗ 4

Criação da biblioteca

Para con�gurar as saídas PWM devemos especi�car a frequência de trabalhoatravés de PR2 e TCON2, além do duty cycle em CCPR1L e CCPR2L. Noregistro TRISC é con�gurado o terminal como uma saída e em CCP1CON eCCP2CON de�nimos que ele deve trabalhar como um PWM. O prescaler foicon�gurado para 16 bits de modo a obter a maior faixa de frequência audíveldisponível (Tabela 4.7). Notar que é importante realizar primeiro a multipli-cação e somente depois a divisão, para não haver perda de informação. Noprograma 4.16 é apresentado um código exemplo de como criar as rotinasde operação do PWM. O header desta biblioteca é apresentado no programa4.17. Por �m, o programa 4.18 apresenta um exemplo de utilização destabiblioteca.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 114: Sistema embarcados

105 Programação dos Periféricos

Listing 4.16: pwm.c

1 #include "pwm.h"

2 #include "basico.h"

4 void SetaPWM1 (unsigned char porcento )5 {6 // formula do duty c y c l e :7 //DC_porcento = V / ((PR2+1)*4;8 //V = DC/100 * (PR2+1) * 4 = DC * (PR2+1) /259 unsigned int val = ((unsigned int ) porcento ) *( PR2+1) ;10 val = val / 25 ;11 // garante que tem apenas 10 b i t s12 val &= 0x03ff ;13 // os 8 pr imeiros b i t s são co locados no CCPR1L14 CCPR1L = val >> 2 ;15 // os ú l t imos do i s são co locados na pos ição 5 e 4 do CCP1CON16 CCP1CON |= ( val & 0x0003 ) << 4 ;17 }

19 void SetaPWM2 (unsigned char porcento )20 {21 //100 * 256 = 25.60022 unsigned int val = porcento * PR2 ;23 val /= 25 ;24 // garante que tem apenas 10 b i t s25 val &= 0x03ff ;26 // os 8 pr imeiros b i t s são co locados no CCPR1L27 CCPR2L = val >> 2 ;28 // os ú l t imos do i s são co locados na pos ição 5 e 4 do CCP1CON29 CCP2CON |= ( val & 0x0003 ) << 4 ;30 }

32 void SetaFreqPWM (unsigned int freq )33 {34 //PR2 = fo s c /( fpwm*4* p r e s c a l e r )−1 = (8000000/( f r e q *4*16) ) − 135 PR2 = (125000/( freq ) ) {}− 1 ;36 }

38 void InicializaPWM (void )39 {40 BitClr ( TRISC , 2 ) ; // con f i gura os pinos como sa ída s41 BitClr ( TRISC , 3 ) ;42 T2CON |= 0b00000011 ; // con f i gura o p r e s c a l e do t imer 2 para←↩

1:1643 BitSet ( T2CON , 2 ) ; //Liga o t imer 244 CCP1CON |= 0b00001100 ; // con f i gura CCP1 como um PWM45 CCP2CON |= 0b00001100 ; // con f i gura CCP2 como um PWM46 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 115: Sistema embarcados

106 Programação dos Periféricos

Listing 4.17: pwm.h

1 #ifndef PWM_H2 #define PWM_H

3 void SetaPWM1 (unsigned char porcento ) ;4 void SetaPWM2 (unsigned char porcento ) ;5 void SetaFreqPWM (unsigned int freq ) ;6 void InicializaPWM (void ) ;7 #endif //PWM_H

Listing 4.18: Exemplo de uso da biblioteca das saídas 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 programa6 void main (void ) interrupt 07 {8 int temp ;9 InicializaPWM ( ) ;10 InicializaAD ( ) ;11 for ( ; ; ) {12 temp = LeValorAD ( ) ;13 // ajus tando a f r e quênc i a de acordo com entrada ana lóg i ca14 SetaFreqPWM ( temp ) ;15 // ajus tando o duty−c y c l e para 50%16 SetaPWM1 (50) ;17 }18 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 116: Sistema embarcados

107 Programação dos Periféricos

4.10 Timer

Nos microcontroladores existem estruturas próprias para realizar a contagemde tempo, estas estruturas são denominadas Timers.

O PIC18f4550 possui quatro timers. Para utilizarmos a saída PWMtemos que con�gurar o timer 2, que gera a base de tempo que sera comparadacom o duty cycle.

Ao invés de contarmos quantas instruções são necessárias para criar umdelay de um determinado tempo, podemos utilizar os timers. Escolhemos ovalor de tempo que queremos contar, inicializamos as variáveis e esperamosacontecer um �over�ow�8 na contagem do timer.

Para trabalhar com o timer precisamos basicamente de uma função deinicialização, uma para resetar o timer e outra para indicar se o tempo con-�gurado anteriormente já passou. Uma quarta função "AguardaTimer()",foi construída para facilitar o desenvolvimento de algumas rotinas comunsnos programas. Estas rotintas estão implementadas no programa 4.19 cujoheader é apresentado no programa 4.20. O modo de utilizar esta bibliotecaé apresentado no programa 4.21.

8Over�ow é conhecido como estouro de variável. Toda variável digital possui um valormáximo, por exemplo 255 para uma variável do tipo unsigned char. Se uma variávelunsigned char possui o valor 255 e é acrescida de 1, seu valor passa a ser zero e aconteceo estouro ou over�ow.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 117: Sistema embarcados

108 Programação dos Periféricos

Listing 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 segundos13 void ResetaTimer (unsigned int tempo )14 {15 //para p laca com 8MHz 1 ms = 2 c i c l o s16 unsigned ciclos = tempo * 2 ;17 // ove r f l ow acontece com 2^15−1 = 65535 (max unsigned i n t )18 ciclos = 65535 − ciclos ;19 ciclos −= 14 ; // s u b t r a i tempo de overhead ( exper imenta l )20 TMR0H = ( ciclos >> 8) ; // sa l v a a par te a l t a21 TMR0L = ( ciclos & 0x00FF ) ; // sa l v a a par te ba ixa22 BitClr ( INTCON , 2 ) ; // limpa a f l a g de ove r f l ow23 }

25 void InicializaTimer (void )26 {27 T0CON = 0b00001000 ; // con f i gura t imer 0 sem p r e s c a l e r28 BitSet ( T0CON , 7 ) ; // l i g a o t imer 029 }

Listing 4.20: timer.h

1 #ifndef TIMER_H2 #define TIMER_H

3 char FimTimer (void ) ;4 void AguardaTimer (void ) ;5 //tempo em ms6 char ResetaTimer (unsigned int tempo ) ;7 void InicializaTimer (void ) ;8 #endif //TIMER_H

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 118: Sistema embarcados

109 Programação dos Periféricos

Listing 4.21: Exemplo de uso da biblioteca de um temporizador

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

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 119: Sistema embarcados

110 Programação dos Periféricos

4.11 Reprodução de Sons

Se ligarmos à saída PWM um auto-falante é possível reproduzir sons. Co-nhecendo a frequência de cada uma das notas musicais e a duração destas épossível reproduzir uma música. Para reproduzir o tempo com uma precisãomelhor podemos utilizar o TIMER0 como unidade de tempo.

Conforme visto na seção 4.9, o PWM utilizado na placa consegue re-produzir as frequências audíveis a partir de 488,3Hz. Por isso escolhemoscomeçar a escala musical a partir do C5 (Dó Tenor) que possui a frequênciade 523. A segunda escala possui o dobro da frequência (uma oitava acima).Para reproduzir a ausência de som escolhemos a frequência de 125.000 Hz9,que é inaudível. Isto simpli�ca o programa.

9Esta é a máxima frequência possível para o PWM operado com prescaler de 16x.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 120: Sistema embarcados

111 Programação dos Periféricos

Listing 4.22: Reprodução de sons

1 #include "config.h"

3 #include "basico.h"

5 #include "pwm.h"

7 #include "timer.h"

10 // f r e quênc i a das11 // notas musica is12 #define C 52313 #define CS 55414 #define D 58715 #define DS 62216 #define E 65917 #define F 69818 #define FS 74019 #define G 78420 #define GS 83021 #define A 88022 #define AS 93223 #define B 987

26 // segunda o i t a va27 #define C2 C*228 #define C2S CS*229 #define D2 D*230 #define D2S DS*231 #define E2 E*232 #define F2 F*233 #define F2S FS*234 #define G2 G*235 #define G2S GS*236 #define A2 A*237 #define A2S AS*238 #define B2 B*2

41 //sem som42 #define v 125000

43 // i n i c i o do programa44 void main (void )45 {46 unsigned char cont=0;47 unsigned char pos=0;48 // Imper ia l March (SW Episode V)49 unsigned char tempo [ ] = {50 , 10 , 50 , ←↩

10 , 50 , 10 , 50 , 5 , 25 , 5 , 50 , 5 , 50 ,←↩5 , 25 , 5 , 50 , 50 , 50 , 10 , 50 , 10 , ←↩

50 , 10 , 50 , 5 , 25 , 5 , 50 , 5 , 50 , 5 , ←↩25 , 5 , 50 , 50 , 100 , 5 , 25 , 5 , 25 , ←↩10 , 100 , 5 , 50 , 5 , 25 , 2 , 10 , 2 , 10 ,←↩2 , 100 , 250} ;

50 unsigned int notas [ ] = {G , v , G , v , G , ←↩v , E , v , B , v , G , v , E , v , B , v , G , ←↩v , D2S , v , D2S , v , D2S , v , E2 , v , B ,←↩v , FS , v , E , v , B , v , G , v , G2S , v ,←↩G , v , G , v , G2S , v , G2 , v , F2S , v , ←↩

F2 , v , E2 , v , F2S , v } ;51 InicializaPWM ( ) ;52 InicializaTimer ( ) ;53 SetaFreqPWM ( notas [ 0 ] ) ;54 SetaPWM1 (50) ; // garante duty−c y c l e de 50%55 for ( ; ; )56 {57 AguardaTimer ( ) ;58 ResetaTimer (10000) ;59 cont ++;60 i f ( cont >= tempo [ pos ] )61 {62 pos++;63 SetaFreqPWM ( notas [ pos ] ) ;64 SetaPWM1 (50) ;65 cont=0;66 }67 }68 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 121: Sistema embarcados

112 Programação dos Periféricos

4.12 Interrupção

Até o momento todos os programas que foram desenvolvidos seguiam um�uxo sequencial sendo alterado apenas por chamadas de funções, estruturasde decisão ou loop. Um dos problemas de se utilizar este tipo de estrutura éque alguns periféricos possuem um tempo muito grande para realizarem suafunção como o conversor AD por exemplo. Nesta situação o que fazemos éiniciar a conversão e �car monitorando uma variável que indicava quando aconversão tinha terminado. Esta técnica é conhecida como pooling.

O problema de se realizar a leitura de algum periférico por pooling é queo processador perde tempo realizando operações desnecessárias checando avariável de controle. Uma alternativa é utilizar um sistema que, quandoa operação desejada estivesse �nalizada, nos avisasse para que pudéssemostomar uma providência. Este procedimento é chamado de interrupção.

Alguns dispositivos possuem a possibilidade de operarem com interrup-ções. Quando a condição do dispositivo for satisfeita (�m da conversão parao AD, chegada de informação na serial, mudança no valor da variável naporta B) ele gera uma interrupção. A interrupção para o programa no pontoem que ele estiver, salva todos os dados atuais e vai para uma função pré-de�nida. Esta função realiza seu trabalho e assim que terminar volta oprograma no mesmo ponto onde estava antes da interrupção.

Dos dispositivos estudados até agora os que geram interrupção são:

� Porta Serial: quando chega alguma informação em RCREG ou quando obu�er de transmissão TXREG estiver disponível.

� Conversor AD: quando o resultado da conversão estiver disponível paraleitura.

� Porta B: quando algum dos bits con�gurados como entrada altera seuvalor.

� Timer 0: quando acontece over�ow em seu contador

Para gerenciar a interrupção devemos criar uma rotina que irá veri�car otipo de interrupção que ocorreu e tomara as providências necessárias. Amaneira de declarar que uma função será responsável pelo tratamento dasinterrupções depende do compilador.

Para o compilador SDCC basta que coloquemos a expressão �interrupt1� após o nome da função.

void NomeDaFuncao (void ) interrupt 1{

// código . . .}

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 122: Sistema embarcados

113 Programação dos Periféricos

Para o compilador C18 da Microchip temos que gerar um código emassembler que indicará qual função será a responsável pela interrupção.

void NomeDaFuncao (void ){

// código . . .}

// Ind i car a pos ição no ve to r de in t e r rupçõe s#pragma code high_vector=0x08void interrupt_at_high_vector (void ){_asm GOTO Interrupcao _endasm

}#pragma code#pragma i n t e r r up t NomeDaFuncao

A função que irá tratar da interrupção não retorna nem recebe nenhumvalor.

Existe uma correlação entre o número que vem depois da expressão �inter-rupt� para o compilador SDCC e o número ao �nal da expressão �#pragmacode high_vector� para o C18. Estes números representam a posição para aqual o microcontrolador vai quando acontece uma interrupção. Estas posi-ções estão numa área conhecida como vetor de interrupções.

Para o microcontrolador PIC18f4550 este vetor possui três posições im-portantes: 0x00(0), 0x08(1) e 0x18(2). O compilador C18 usa a posição físicae o SDCC o número entre parênteses.

A posição 0 (0x00) representa o endereço que o microcontrolador buscaquando este acaba de ser ligado. É a posição de reset. Geralmente saímosdeste vetor e vamos direto para a função main().

As posições 1 e 2 (0x08,0x18) são reservadas para as interrupções dealta e baixa prioridade, respectivamente. É necessário que o programadorescolha quais dispositivos são de alta e quais são de baixa prioridade. Existeainda um modo de compatibilidade com os microcontroladores mais antigosno qual todos os periféricos são mapeados na primeira interrupção (0x08).Utilizaremos este modo por questão de facilidade.

Como todos os periféricos estão mapeados na mesma interrupção, a fun-ção deve ser capaz de diferenciar entre as diversas fontes de requisição. Umamaneira de se realizar esta veri�cação é através das �ags de controle, ou seja,bits que indicam a situação de cada periférico.

O programa 4.23 apresenta uma função que trata de todas as fontespossíveis de interrupção para o PIC18f4550.

Em geral não é necessário tratar todas as interrupções, apenas aquelasque in�uenciarão o sistema. O programa 4.24 apresenta um exemplo de umafunção que trata as interrupções advindas da porta B, do timer 0, da seriale do AD.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 123: Sistema embarcados

114 Programação dos Periféricos

Listing 4.23: Fontes de Interupção

1 void Interrupcao (void ) interrupt 1 {2 // não é nece s sá r i o u t i l i z a r todos os i f ' s apenas aque l e s3 // das in t e r rupçõe s de se jadas4 i f ( BitTst ( PIR1 , 0 ) ) { /* cod igo */ } //Flag de ove r f l ow do ←↩

TIMER15 i f ( BitTst ( PIR1 , 1 ) ) { /* cod igo */ } //Flag de comparação do ←↩

TIMER2 com PR26 i f ( BitTst ( PIR1 , 2 ) ) { /* cod igo */ } //Flag de comparação do ←↩

CCP17 i f ( BitTst ( PIR1 , 3 ) ) { /* cod igo */ } //Flag de fim de ←↩

operação na porta p a r a l e l a8 i f ( BitTst ( PIR1 , 4 ) ) { /* cod igo */ } //Flag de fim de ←↩

t ransmissão da S e r i a l9 i f ( BitTst ( PIR1 , 5 ) ) { /* cod igo */ } //Flag de recepção da ←↩

S e r i a l10 i f ( BitTst ( PIR1 , 6 ) ) { /* cod igo */ } //Flag de fim de ←↩

conversão do AD11 i f ( BitTst ( PIR1 , 7 ) ) { /* cod igo */ } //Flag de ←↩

l e i t u r a / e s c r i t a da por ta p a r a l e l a12 i f ( BitTst ( PIR2 , 0 ) ) { /* cod igo */ } //Flag de comparação do ←↩

CCP213 i f ( BitTst ( PIR1 , 1 ) ) { /* cod igo */ } //Flag de ove r f l ow do ←↩

TIMER314 i f ( BitTst ( PIR1 , 2 ) ) { /* cod igo */ } //Flag de condição de ←↩

Tensão Alta /Baixa15 i f ( BitTst ( PIR1 , 3 ) ) { /* cod igo */ } //Flag de de tecção de ←↩

c o l i s ã o no barramento16 i f ( BitTst ( PIR1 , 4 ) ) { /* cod igo */ } //Flag de fim e s c r i t a na←↩

memoria f l a s h17 i f ( BitTst ( PIR1 , 5 ) ) { /* cod igo */ } //Flag de in t e r rupção da←↩

USB18 i f ( BitTst ( PIR1 , 6 ) ) { /* cod igo */ } //Flag de mudança na ←↩

entrada de comparação19 i f ( BitTst ( PIR1 , 7 ) ) { /* cod igo */ } //Flag de f a l h a no ←↩

o s c i l a d o r20 i f ( BitTst ( INTCON , 0 ) ) { /* cod igo */ } //Flag de mudança na ←↩

PORTA B21 i f ( BitTst ( INTCON , 1 ) ) { /* cod igo */ } //Flag de in t e r rupção ←↩

ex terna INT022 i f ( BitTst ( INTCON , 2 ) ) { /* cod igo */ } //Flag de ove r f l ow no ←↩

TIMER023 i f ( BitTst ( INTCON3 , 0 ) ) { /* cod igo */ } //Flag de in t e r rupção ←↩

ex terna INT124 i f ( BitTst ( INTCON3 , 1 ) ) { /* cod igo */ } //Flag de in t e r rupção ←↩

ex terna INT225 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 124: Sistema embarcados

115 Programação dos Periféricos

Listing 4.24: Tratamento das interrupções

1 stat ic unsigned int ADvalor ;2 stat ic unsigned char Serial ;3 stat ic unsigned int Tecla ;4 void Interrupcao (void ) interrupt 15 {6 char i , j ;7 i f ( BitTst ( PIR1 , 6 ) ) //AD : fim de conversão8 {9 ADvalor = ADRESH ; // l ê o r e s u l t a do10 ADvalor <<= 8 ;11 ADvalor += ADRESL ;12 BitClr ( PIR1 , 6 ) ; // limpa a f l a g13 }14 i f ( BitTst ( PIR1 , 5 ) ) // S e r i a l : recepção15 {16 // Bi tC lr (PIR1 , 5 ) ;17 Serial = RCREG ; // limpa soz inho quando l ê18 }19 i f ( BitTst ( INTCON , 0 ) ) //PORTA B : mudou va l o r20 {21 for (i = 0 ; i < 4 ; i++){22 PORTB |= 0xFF ;23 BitClr ( PORTB , ( i ) ) ;24 for (j=0;j<10;j++);25 for (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 = 0x00 ;34 BitClr ( INTCON , 0 ) ;35 }36 i f ( BitTst ( INTCON , 2 ) ) //TIMER0: Overf low37 {38 //tempo maximo de in t e r rupção do t imer 039 BitClr ( INTCON , 2 ) ; // limpa a f l a g40 TMR0H = 0x00 ; // r e i n i c i a contador de tempo41 TMR0L = 0x00 ; // r e i n i c i a contador de tempo42 ADCON0 |= 0b00000010 ; // i n i c i a conversão43 }44 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 125: Sistema embarcados

116 Programação dos Periféricos

Listing 4.25: Inicialização do sistema com interrupções

1 void main (void )2 {3 unsigned int i , temp , teclanova=0;4 // conf igurando todas as in t e r rupçõe s5 TRISD = 0x00 ;6 TRISB = 0xF0 ; //mantém os 4 ú l t imos b i t s como entrada7 PORTB = 0x00 ; //mantem l i g a d a s as 4 co lunas8 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 compa t i b i l i d ade )14 BitSet ( PIE1 , 6 ) ; // l i g a a in t e r rupção para o AD15 BitSet ( PIE1 , 5 ) ; // l i g a a in t e r rupção para a recepção na ←↩

s e r i a l16 BitSet ( INTCON , 5 ) ; // l i g a a in t e r rupção para o t imer 017 BitSet ( INTCON , 3 ) ; // l i g a a in t e r rupção para a por ta B18 BitSet ( INTCON , 7 ) ; // h a b i l i t a todas as in t e r rupçõe s g l o b a i s19 BitSet ( INTCON , 6 ) ; // h a b i l i t a todas as in t e r rupçõe s de ←↩

p e r i f é r i c o s20 for ( ; ; ) {21 AtualizaDisplay ( ) ;22 temp = ADvalor ;23 temp %=10000;24 MudaDigito ( temp / 1000 , 3) ;25 temp %=1000;26 MudaDigito ( temp / 100 , 2) ;27 temp %=100;28 MudaDigito ( temp / 10 , 1) ;29 temp %=10;30 MudaDigito ( temp , 0) ;31 i f ( teclanova != Tecla ) {32 teclanova = Tecla ;33 for (i=0;i<16;i++){34 i f ( BitTst ( Tecla , i ) ) {35 EnviaDados (i+48) ;36 }37 }38 }39 for (i = 0 ; i < 1000 ; i++);40 }41 }

Para que a função apresentada no programa 4.24 funcione corretamentedevemos inicializar as interrupções de modo adequado, conforme apresentadono programa 4.25.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 126: Sistema embarcados

117 Programação dos Periféricos

Listing 4.26: Inicialização do sistema com interrupções

1 #define CLRWTD() _asm CLRWDT _endasm

3 // i n i c i o do programa4 void main (void ) interrupt 05 {6 unsigned int i ;7 unsigned char temp ;8 TRISD=0x00 ;9 PORTD=0x00 ;10 BitSet ( WDTCON , 0 ) ; // l i g a o s i s tema de watchdog11 for ( ; ; )12 {13 PORTD++;14 for (i = 0 ; i < 10000; i++)15 {16 CLRWTD ( ) ;17 }18 }19 }

4.13 Watchdog

Por algum motivo o software pode travar em algum ponto, seja por um loopin�nito ou por esperar a resposta de algum componente através de poolingde uma variável.

A primeira condição pode ser evitada através de um projeto cuidadoso desoftware aliado a uma boa validação. Já a segunda exige que os hardwaresadjacentes funcionem corretamente. Se algum hardware apresenta uma falhae não envia a resposta que o microcontrolador está esperando, este últimoirá travar. Nestas situações é possível utilizar o watchdog.

O watchdog é um sistema que visa aumentar a segurança do projeto. Elefunciona como um temporizador que precisa constantemente ser reiniciado.Caso não seja reiniciado no tempo exigido, o watchdog reinicia o microcon-trolador dando a possibilidade de sair de um loop in�nito ou de um poolingsem resposta.

Para habilitar o watchdog é necessário alterar os registros de con�gura-ção, especi�camente o CONFIG2H (0x300002). Outro método consiste emdeixar o watchdog desligado no registro e ligá-lo através de software, comoé apresentado no programa 4.26.

Notar o #de�ne criado na primeira linha do programa 4.26. A expressãoCLRWDT é o comando em assembler responsável por resetar o watchdog.As diretivas _asm e _endasm informam ao compilador que os comandosutilizados devem ser transcritos exatamente iguais para o arquivo assembler

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 127: Sistema embarcados

118 Programação dos Periféricos

a ser gerado.Se após ligar o watchdog não realizarmos a operação de reset dele, co-

mentando ou excluindo a função CLRWTD(), o sistema irá travar tão logo otempo associado ao watchdog tenha expirado pela primeira vez, reiniciandoo sistema. Como apenas reiniciar não soluciona o problema, pois o programacriado não terá função para reiniciar o watchdog, o sistema continua sendoreiniciado inde�nidamente.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 128: Sistema embarcados

Capítulo 5

Arquitetura de

desenvolvimento de software

�Constrained by memory limitations, performance require-ments, and physical and cost considerations, each embeddedsystem design requires a middleware platform tailored pre-cisely to its needs, unused features occupy precious memoryspace, while missing capabilities must be tacked on.� - Dr. Ri-chard Soley

No desenvolvimento de um sistema de maior porte, é importante de�nir otipo de arquitetura que iremos utilizar. Neste capítulo apresentamos quatroabordagens possíveis. A escolha deve ser baseada no tipo de dispositivoa ser desenvolvido, na complexidade do sistema, na possibilidade de gerarsubprodutos e dos requisitos de tempo.

5.1 One single loop

�1 In�nite Loop, Cupertino, CA 95014.� - Endereço da Apple

Esta é a estratégia utilizada até agora nos exemplos apresentados. Dentro dafunção principal é colocado um loop in�nito. Todas as tarefas são chamadasatravés de funções.

A vantagem de se utilizar esta abordagem é a facilidade de se iniciarum projeto. Para sistemas maiores começa a �car complicado coordenar astarefas e garantir a execução num tempo determinístico. Outro problema éa modi�cação/ampliação do software. Geralmente a inserção de uma funçãono meio do loop pode gerar erros em outras funções devido a restrições detempo dos periféricos associados.

No exemplo acima, a inserção da comunicação serial e os cálculos podematrapalhar a escrita no display de sete segmentos, gerando �icker.

119

Page 129: Sistema embarcados

120 Arquitetura de desenvolvimento de software

Listing 5.1: Exemplo de arquitetura single-loop

1 // seção de i n c l u d e s2 #include "basico.h"

3 #include "config.h"

4 #include "teclado.h"

5 #include "disp7seg.h"

6 // função p r i n c i p a l7 void main (void ) interrupt 08 {9 // dec laração das v a r i á v e i s10 int ia , ib , ic ;11 f loat 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 s13 InicializaTeclado ( ) ;14 InicializaDisplay ( ) ;15 // loop p r i n c i p a l16 for ( ; ; )17 {18 //chamada das t a r e f a s19 ia = LerTeclas ( ) ;20 ImprimeDisplay ( ia ) ; //tem que ser executado pe l o menos a ←↩

cada 10(ms)21 }22 }

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

1 // loop p r i n c i p a l2 for ( ; ; )3 {4 //chamada das t a r e f a s5 ia = LerTeclas ( ) ;6 ImprimeDisplay ( ia ) ; //tem que ser executado pe l o menos a ←↩

cada 10(ms)7 ic = RecebeSerial ( ) ;8 fa = 2.0 * ic / 3 . 1 4 ;9 EnviaSerial ( fa & 0x00FF ) ;10 EnviaSerial ( fa >> 8) ;11 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 130: Sistema embarcados

121 Arquitetura de desenvolvimento de software

Listing 5.3: Exemplo de sistema Interrupt-driven

1 int ia ;2 // tratamento do t e c l a do v ia in t e r rupção3 void Interrupcao (void ) interrupt 14 {5 i f ( BitTst ( INTCON , 0 ) ) //PORTA B : mudou va l o r6 {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 s14 InicializaTeclado ( ) ;15 InicializaDisplay ( ) ;16 // i n i c i a l i z a ç ã o da in t e r rupção17 BitClr ( RCON , 7 ) ; // d e s a b i l i t a IPEN (modo de compa t i b i l i d ade )18 BitSet ( INTCON , 3 ) ; // l i g a a in t e r rupção para a por ta B19 BitSet ( INTCON , 7 ) ; // h a b i l i t a todas as in t e r rupçõe s g l o b a i s20 BitSet ( INTCON , 6 ) ; // h a b i l i t a todas as in t e r rupçõe s de ←↩

p e r i f é r i c o s21 for ( ; ; ) // loop p r i n c i p a l22 {23 //chamada das t a r e f a s24 ImprimeDisplay ( ia ) ;25 }26 }

5.2 Interrupt control system

Uma parte dos desenvolvedores de sistemas embarcados, que possuem res-trições de tempo de atendimento mais rigorosos, optam por garantir estasrestrições através de interrupções.

Na maioria dos sistemas microcontroladores as interrupções são atendidasnum tempo muito curto, cerca de alguns ciclos de instrução, o que para amaioria dos sistemas é su�ciente. Deve-se entretanto tomar cuidado com aquantidade de periféricos que geram interrupções e a prioridade dada a cadaum deles.

Outra abordagem muito utilizada é a geração de uma interrupção comtempo �xo, por exemplo a cada 5ms.

A grande vantagem da abordagem citada é que a inserção de mais códigodentro do loop principal não atrapalha a velocidade com que o display éatualizado, que está �xo em 5(ms).

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 131: Sistema embarcados

122 Arquitetura de desenvolvimento de software

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

1 int ia ;2 // e x i t e apenas uma fon t e de in t e r rupção : Timer 03 void Interrupcao (void ) interrupt 14 {5 TimerReset (5000) ; // r e i n i c i a t imer para próxima in t e r rupção6 ImprimeDisplay ( ia ) ;7 BitSet ( INTCON , 5 ) ; // r e l i g a a in t e r rupção para o t imer 08 }

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 s13 InicializaTeclado ( ) ;14 InicializaDisplay ( ) ;15 InicializaTimer ( ) ;16 // i n i c i a l i z a ç ã o da in t e r rupção17 BitClr ( RCON , 7 ) ; // d e s a b i l i t a IPEN (modo de compa t i b i l i d ade )18 BitSet ( INTCON , 5 ) ; // l i g a a in t e r rupção para o t imer 019 BitSet ( INTCON , 7 ) ; // h a b i l i t a todas as in t e r rupçõe s g l o b a i s20 BitSet ( INTCON , 6 ) ; // h a b i l i t a todas as in t e r rupçõe s de ←↩

p e r i f é r i c o s21 ResetaTimer (5000) ;22 for ( ; ; ) // loop p r i n c i p a l23 {24 ia = LerTeclas ( ) ;25 }26 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 132: Sistema embarcados

123 Arquitetura de desenvolvimento de software

5.3 Cooperative multitasking

Em computação, multitarefa ou multitasking é um processo pelo qual dife-rentes tarefas compartilham um mesmo recurso, seja ele memória, processa-mento ou qualquer periférico disponível.

Uma maneira de realizar este compartilhamento é através de uma divisãodo tempo: a tarefa A possui um intervalo ao �nal do qual deve ceder osrecursos para a tarefa B. Quando a mudança de tarefa é feita pela própriatarefa, o sistema é dito cooperativo. Quando existe um sistema externo querealiza essa troca o sistema é denominado preemptivo.

Se a mudança de tarefas for extremamente rápida o efeito resultante,para o ser humano, é de que todas as tarefas estão sendo executadas simul-taneamente. Uma das maneiras de se obter este tipo de operação é atravésda criação de uma máquina de estados como mostrado na Figura 5.1.

Inicio

LerTeclado

AtualizaDisplay

EscreveSerial

AtualizaDisplayLer Serial

AtualizaDisplay

Figura 5.1: Exemplo de máquina de estados

Nota-se que após a fase de inicialização o sistema entra num ciclo, comona abordagem one-single-loop. Outra peculiaridade é que algumas tarefaspodem ser executadas mais de uma vez para garantir as restrições de tempo,no exemplo a tarefa de atualização dos displays é executada três vezes.

A transposição de uma máquina de estado para o código em C é realizadaatravés de um switch-case.

É possível retirar todas as atribuições para a variável slot e colocar no"slot-bottom" a expressão slot++. A abordagem apresentada foi escolhidapor aumentar a robustez do sistema, já que a variável slot controla todo o�uxo do programa.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 133: Sistema embarcados

124 Arquitetura de desenvolvimento de software

Listing 5.5: Exemplo de cooperative multitasking

1 void main (void ) interrupt 0{2 // dec laração das v a r i á v e i s3 char slot ;4 // funções de i n i c i a l i z a ç ã o5 InicializaSerial ( ) ;6 InicializaTeclado ( ) ;7 InicializaDisplay ( ) ;8 for ( ; ; ) { // i n i c i o do loop i n f i n i t o9 //*************** i n c i o do top−s l o t ******************

10 //**************** f im do top−s l o t ******************

12 //*********** i n í c i o da maquina de es tado ************

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 //************ f im da maquina de es tado **************

44 //************** i n c i o do bottom−s l o t *****************

45 //*************** f im do bottom−s l o t *****************

46 } // fim loop i n f i n i t o ( ! ? )47 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 134: Sistema embarcados

125 Arquitetura de desenvolvimento de software

A inserção de uma nova tarefa é realizada de maneira simples, bastaadicionar um outro slot, ou seja, basta inserir um case/break com a tarefadesejada.

Como a máquina esta dentro do loop in�nito a cada vez que o programapassar pelo case, ele executará apenas um slot. Esta abordagem gera outroefeito. Como pode ser visto no código naturalmente surgem duas regiões:"top-slot" e "bottom-slot". Se algum código for colocado nesta região eleserá executado toda vez, de modo intercalado, entre os slots. Pela Figura 5.1,percebemos que é exatamente este o comportamento que queremos para afunção AtualizaDisplay(). Deste modo podemos remodelar o código fazendoesta alteração.

Fixação de tempo para execução dos slots

Do modo apresentado até agora, assim que uma função termina o sistemaautomaticamente passa para a próxima tarefa. Uma característica desejadaé que estas funções possuam um tempo determinado para funcionar. Destemodo todo o sistema se torna mais previsível.

A maneira mais simples de realizar este procedimento é criar uma rotinade tempo. Toda vez que um slot terminar, o sistema �cará aguardando otempo escolhido para reiniciar o sistema.

No exemplo apresentado é inserida a função AguardaTimer() no bottom-slot de modo que a próxima função só executará quando passar os 5 (ms).

Como este é um modo simples de implementar um sistema multitarefapodemos notar que se a função ultrapassar 5 (ms) todo o cronograma seráafetado. É necessário então garantir que todo e cada slot será executado emmenos de 5 (ms). Isto deve ser feito através de testes de bancada.

Na Figura 5.2 está um exemplo de como um sistema com 3 slots secomporta ao longo do tempo. Notar que o slot 1 (S.1) gasta um tempo de2.0(ms), o slot 2 de 3.1 (ms) e o slot 3 apenas 1.2 (ms). Já o top-slot consome0.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 mudança de slots no tempo

Podemos notar que para o ciclo do primeiro slot são gastos 0.5+2.0+0.3 =

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 135: Sistema embarcados

126 Arquitetura de desenvolvimento de software

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

1 void main (void )2 {3 // dec laração das v a r i á v e i s4 char slot ;5 // funções de i n i c i a l i z a ç ã o6 InicializaSerial ( ) ;7 InicializaTeclado ( ) ;8 InicializaDisplay ( ) ;9 for ( ; ; ) // i n i c i o do loop i n f i n i t o10 {11 //*************** i n c i o do top−s l o t ******************

12 AtualizaDisplay ( ) ;13 //**************** f im do top−s l o t ******************

16 //*********** i n í c i o da maquina de es tado ************

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 //************ f im da maquina de es tado **************

38 //************** i n c i o do bottom−s l o t *****************

40 //*************** f im do bottom−s l o t *****************

42 } // fim loop i n f i n i t o ( ! ? )43 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 136: Sistema embarcados

127 Arquitetura de desenvolvimento de software

Listing 5.7: Exemplo de sistema Cooperative-multitasking com slot tempo-rizado

1 void main (void )2 {3 // dec laração das v a r i á v e i s4 char slot ;5 // funções de i n i c i a l i z a ç ã o6 InicializaDisplay ( ) ;7 InicializaTimer ( ) ;8 for ( ; ; ) // i n i c i o do loop i n f i n i t o9 {10 //*************** i n c i o do top−s l o t ******************

11 ResetaTimer (5000) ; //5 ms para cada s l o t12 AtualizaDisplay ( ) ;13 //**************** f im do top−s l o t ******************

16 //*********** i n í c i o da maquina de es tado ************

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 //************ f im da maquina de es tado **************

38 //************** i n c i o do bottom−s l o t *****************

40 //*************** f im do bottom−s l o t *****************

41 AguardaTimer ( ) ;42 } // fim loop i n f i n i t o ( ! ? )43 }

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 137: Sistema embarcados

128 Arquitetura de desenvolvimento de software

2.8(ms). Deste modo o sistema �ca "aguardando" na função AguardaTimer()durante 2.2 (ms) sem realizar nenhum processamento útil. Para o segundoslot 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 livrede 5-(0.5+1.2+0.3)=3.0 (ms).

Utilização do "tempo livre" para interrupções

Conforme visto no item , dependendo do tempo escolhido para o slot e do"tamanho" da função, podem existir espaços vagos na linha de tempo doprocessador. A Figura 5.3 apresenta uma linha de tempo de um sistema quepossui apenas 1 slot. Já a Figura 5.4 demonstra o mesmo sistema sendointerrompido através de interrupções assíncronas.

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 interrupções

Cada interrupção gasta um tempo de 1 (ms) conforme pode ser vistona Figura 5.4. Como temos um tempo "vago" de 3 (ms) em cada ciclobasta garantir que os eventos que geram a interrupção não ultrapassem afrequência de 3 eventos a cada 8 (ms).

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 138: Sistema embarcados

Capítulo 6

Anexos

6.1 con�g.h

O arquivo con�g.h possui as diretivas de compilação para con�guração domicrocontrolador.

6.2 basico.h

O header basico.h possui o endereço de todos os registros do microcontroladorPIC18f4550 que é utilizado nesta apostila. Além disso contém alguns de�nes

Listing 6.1: con�g.h

1 //para o compi lador SDCC + GPUtils2 #ifndef CONFIG_H3 #define CONFIG_H

4 code char at 0x300000 CONFIG1L = 0x01 ; // P l l d e s l i g a do5 code char at 0x300001 CONFIG1H = 0x0C ; // Osc i lador c/ ←↩

c r i s t a l ex terno HS6 code char at 0x300003 CONFIG2H = 0x00 ; // Watchdog ←↩

con t ro lado por so f tware7 code char at 0x300006 CONFIG4L = 0x00 ; // Sem programação em←↩

ba ixa tensão8 #endif //CONFIG_H

10 //para o compi lador C1811 //#pragma con f i g FOSC = HS // Osc i lador c/ c r i s t a l ex terno←↩

HS12 //#pragma con f i g CPUDIV = OSC1_PLL2 // P l l d e s l i g a do13 //#pragma con f i g WDT = OFF // Watchdog con t ro lado por ←↩

so f tware14 //#pragma con f i g LVP = OFF // Sem programação em baixa ←↩

tensão \\\ h l i n e

129

Page 139: Sistema embarcados

130 Anexos

importantes como as funções inline para limpar a �ag de watchdog e paramanipulação de bits.

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 140: Sistema embarcados

131 Anexos

Listing 6.2: basico.h

1 // função para l impar o watchdog2 #define CLRWTD() _asm CLRWDT _endasm3 // funções de b i t4 #define BitSet ( arg , b i t ) ( ( arg ) |= (1<<b i t ) )5 #define BitClr ( arg , b i t ) ( ( arg ) &= ~(1<<b i t ) )6 #define BitFlp ( arg , b i t ) ( ( arg ) ^= (1<<b i t ) )7 #define BitTst ( arg , b i t ) ( ( arg ) & (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 s9 #define PORTA (* ( volat i le near unsigned char*) 0xF80 )10 #define PORTB (* ( volat i le near unsigned char*) 0xF81 )11 #define PORTC (* ( volat i le near unsigned char*) 0xF82 )12 #define PORTD (* ( volat i le near unsigned char*) 0xF83 )13 #define PORTE (* ( volat i le near unsigned char*) 0xF84 )14 #define TRISA (* ( volat i le near unsigned char*) 0xF92 )15 #define TRISB (* ( volat i le near unsigned char*) 0xF93 )16 #define TRISC (* ( volat i le near unsigned char*) 0xF94 )17 #define TRISD (* ( volat i le near unsigned char*) 0xF95 )18 #define TRISE (* ( volat i le near unsigned char*) 0xF96 )19 #define INTCON (* ( volat i le near unsigned char*) 0xFF2)20 #define INTCON2 (* ( volat i le near unsigned char*) 0xFF1)21 #define PIE1 (* ( volat i le near unsigned char*) 0xF9D)22 #define PIR1 (* ( volat i le near unsigned char*) 0xF9E)23 #define TMR0L (* ( volat i le near unsigned char*) 0xFD6)24 #define TMR0H (* ( volat i le near unsigned char*) 0xFD7)25 #define T0CON (* ( volat i le near unsigned char*) 0xFD5)26 #define SPPCON (* ( volat i le near unsigned char*) 0xF65 )27 #define SPPCFG (* ( volat i le near unsigned char*) 0xF63 )28 #define ADCON2 (* ( volat i le near unsigned char*) 0xFC0)29 #define ADCON1 (* ( volat i le near unsigned char*) 0xFC1)30 #define ADCON0 (* ( volat i le near unsigned char*) 0xFC2)31 #define ADRESL (* ( volat i le near unsigned char*) 0xFC3)32 #define ADRESH (* ( volat i le near unsigned char*) 0xFC4)33 #define RCSTA (* ( volat i le near unsigned char*) 0xFAB)34 #define TXSTA (* ( volat i le near unsigned char*) 0xFAC)35 #define TXREG (* ( volat i le near unsigned char*) 0xFAD)36 #define RCREG (* ( volat i le near unsigned char*) 0xFAE)37 #define SPBRG (* ( volat i le near unsigned char*) 0xFAF)38 #define SPBRGH (* ( volat i le near unsigned char*) 0xFB0)39 #define BAUDCON (* ( volat i le near unsigned char*) 0xFB8)40 #define RCON (* ( volat i le near unsigned char*) 0xFD0)41 #define WDTCON (* ( volat i le near unsigned char*) 0xFD1)42 #define T2CON (* ( volat i le near unsigned char*) 0xFCA)43 #define PR2 (* ( volat i le near unsigned char*) 0xFCB)44 #define CCP2CON (* ( volat i le near unsigned char*) 0xFBA)45 #define CCPR2L (* ( volat i le near unsigned char*) 0xFBB)46 #define CCP1CON (* ( volat i le near unsigned char*) 0xFBD)47 #define CCPR1L (* ( volat i le near unsigned char*) 0xFBE)

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 141: Sistema embarcados

132 Anexos

6.3 Instalar gravadores/depuradores de PIC em sis-temas x64

Os passos a seguir devem ser seguidos para instalar os device drivers correta-mente em sistemas operacionais de 64 bits. Atualmente apenas os seguintesaparelhos são 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 ComeçarO dispostivo não deve ser plugado numa porta USB antes de começar ainstalação do Driver.

Se você já plugou o dispositivo e apareceu a informação "Novo hardwareencontrado", clique em cancelar. Desligue o dispositivo e continue com ospassos a seguir.

Se você já utilizou o setup do windows você instalou os drivers errados.Siga as instruções de remoção dos drivers antes de prosseguir.

Passo 1Conecte o dispositivo ao PC usando o cabo USB. Para os dispositivos queexigem alimentação externa, ligue-a. Se estiver usando um hub USB, tenhacerteza que o este possui energia su�ciente para alimentar o dispositivo.

Passo 2A primeira vez que o dispositivo é conectado aparece uma mensagem indi-cando que o sistema encontrou um novo hardware. Quando aparecer umajanela, escolha a opção "Localizar e instalar o driver (recomendado)" Nota:Se aparecer uma mensagem perguntando sobre permissão no Windows 7,clique em sim/continuar.

Passo 3Escolha a opção: "Procurar o driver no meu computador (avançado)"Passo 4

Quando aparecer uma janela pedindo para você indicar o caminho, pro-cure em "C:\Arquivos de programa (x86)\Microchip\MPLAB IDE\Drivers64".

Notas de Aula ELT024 - Programação para Sistemas Embarcados

Page 142: Sistema embarcados

133 Anexos

Clique em continuar

Passo 5A próxima tela irá perguntar se você quer continuar a instalar o dispositivo.Clique em Instalar para continuar.

Passo 6A próxima tela indicará que o software foi instalado corretamente. Cliqueem fechar para terminar a instalação.

Passo 7Veri�car se o driver está instalado e visivel no Gerenciador de dispositi-vos em "Custom USB Drivers>Microchip Custom USB Driver" Abra a ja-nela do gerenciador de dispositivos (Iniciar->Painel de controle->Sistema->Gerenciador de dispositivos). Se o driver não fora instalado corretamente,continue na seção de solução de erros (a seguir)

Solução de errosSe houve algum problema na instalação do driver siga os passos a seguir.

O Windows tentará instalar o driver mesmo se não encontrar o arquivocorreto. No gerenciador de dispositivos dentro da opção "Outros dispositi-vos" você deve encontrar um "Dispositivo não conhecido".

Clique com o botão direito no "Dispositivo não conhecido" e selecione aopção "Atualizar o Driver" do menu.

Na primeira tela de diálogo selecione "Procurar no meu computador pelosarquivos do driver".

Continuar a partir do passo 4.

Notas de Aula ELT024 - Programação para Sistemas Embarcados