Livro Programando Microcontroladores PIC Linguagem C.pdf

118
Notas de Aula Programação Embarcada - ELT024 1 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 30 de Agosto de 2011 1 cbnd Licenciado sobre Criative Commons Attribution-NonCommercial-NoDerivs

Transcript of Livro Programando Microcontroladores PIC Linguagem C.pdf

Page 1: Livro Programando Microcontroladores PIC Linguagem C.pdf

Notas de Aula Programação Embarcada - ELT024 1

Rodrigo Maximiano Antunes de AlmeidaInstituto de Engenharia de Sistemas e Tecnologia da Informação,

Universidade Federal de Itajubá,Minas Gerais,

Brasilrodrigomax @ unifei.edu.br

30 de Agosto de 2011

1cbnd Licenciado sobre Criative Commons Attribution-NonCommercial-NoDerivs

Page 2: Livro Programando Microcontroladores PIC Linguagem C.pdf

Conteúdo

1 Introdução 1. Linguagem C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1. Hardware utilizado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2. Ambiente de programação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

Instalação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3Configuração do gravador ICD2 . . . . . . . . . . . . . . . . . . . . . . . 4Criação de um novo projeto . . . . . . . . . . . . . . . . . . . . . . . . . 5

2 Linguagem C para sistemas embarcados 9. Indentação e padrão de escrita . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9. Comentários . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11. Arquivos .c e .h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11. Diretivas de compilação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

#include . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13#define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13#ifdef, #ifndef, #else e #endif . . . . . . . . . . . . . . . . . . . . . . . . 14

. Tipos de dados em C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15Representação binária e hexadecimal . . . . . . . . . . . . . . . . . . . . . 16Modificadores de tamanho e sinal . . . . . . . . . . . . . . . . . . . . . . . 17Modificadores de acesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18Modificadores de posicionamento . . . . . . . . . . . . . . . . . . . . . . . 19Modificador de persistência . . . . . . . . . . . . . . . . . . . . . . . . . . 19

. Operações aritméticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20. Função main() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21. Rotinas de tempo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23. Operações com bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

NOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25AND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25OR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26XOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26Shift . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26Ligar um bit (bit set) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27Desligar um bit (bit clear) . . . . . . . . . . . . . . . . . . . . . . . . . . . 28Trocar o valor de um bit (bit flip) . . . . . . . . . . . . . . . . . . . . . . 28Verificar o estado de um bit (bit test) . . . . . . . . . . . . . . . . . . . . 29Criando funções através de define’s . . . . . . . . . . . . . . . . . . . . . 30

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

i

Page 3: Livro Programando Microcontroladores PIC Linguagem C.pdf

. Ponteiros e endereços de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

3 Arquitetura de microcontroladores 38. Acesso à memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40. Clock e tempo de instrução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42. Esquema elétrico e circuitos importantes . . . . . . . . . . . . . . . . . . . . . . . 43

Multiplexação nos terminais do microcontrolador . . . . . . . . . . . . . . 44. Registros de configuração do microcontrolador . . . . . . . . . . . . . . . . . . . . 45

4 Programação dos Periféricos 47. Acesso às “portas”do microcontrolador . . . . . . . . . . . . . . . . . . . . . . . . 48. Configuração dos periféricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50. Barramento de Led's . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53. Display de 7 segmentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

Multiplexação de displays . . . . . . . . . . . . . . . . . . . . . . . . . . . 56Criação da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

. Leitura de teclas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59Debounce por software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59Arranjo de leitura por matriz . . . . . . . . . . . . . . . . . . . . . . . . . 62Criação da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

. Display LCD 2x16 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66Criação da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

. Comunicação serial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74RS 232 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74Criação da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

. Conversor AD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79Elementos sensores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79Processo de conversão AD . . . . . . . . . . . . . . . . . . . . . . . . . . . 81Criação da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

. Saídas PWM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85Criação da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

. Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89. Reprodução de Sons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91. Interrupção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92. Watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

5 Arquitetura de desenvolvimento de software 97. One single loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98. Interrupt control system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99. Cooperative multitasking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

Fixação de tempo para execução dos slots . . . . . . . . . . . . . . . . . . 104Utilização do “tempo livre”para interrupções . . . . . . . . . . . . . . . . . 105

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

ii

Page 4: Livro Programando Microcontroladores PIC Linguagem C.pdf

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 Configuração das ferramentas de compilação . . . . . . . . . . . . . . . . . . . . . 51.4 Instalação do ICD2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.5 Resumo das configurações do ICD2 no MPLAB . . . . . . . . . . . . . . . . . . . 61.6 Pedido de atualização do firmware do ICD2 . . . . . . . . . . . . . . . . . . . . . 71.7 Project Explorer do MPLAB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.8 Comparativo de características da família PIC 18fxx5x . . . . . . . . . . . . . . . 8

2.1 Problema das Referências Circulares . . . . . . . . . . . . . . . . . . . . . . . . . 152.2 Solução das referências circulares com #ifndef . . . . . . . . . . . . . . . . . . . . 162.3 Loop infinito de um device driver gerando erro no sistema . . . . . . . . . . . . . 222.4 Exemplo de funcionamento do vetor de interrupção . . . . . . . . . . . . . . . . . 22

3.1 Arquitetura do microcontrolador PIC 18F4550 . . . . . . . . . . . . . . . . . . . 393.2 Memória como um armário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403.3 Memória e periféricos como um armário . . . . . . . . . . . . . . . . . . . . . . . 413.4 Regiões de memórias disponíveis no PIC18F4550 . . . . . . . . . . . . . . . . . . 413.5 Esquema elétrico: Microcontrolador PIC 18F4550 . . . . . . . . . . . . . . . . . . 433.6 Registros de configuração do microcontrolador PIC 18F4550 . . . . . . . . . . . . 45

4.1 Registros de configuração dos periféricos do PIC 18F4550 . . . . . . . . . . . . . 504.2 Barramento de Led's . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534.3 Display de 7 Segmentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544.4 Diagrama elétrico para display de 7 segmentos com anodo comum . . . . . . . . . 544.5 Ligação de 4 displays de 7 segmentos multiplexados . . . . . . . . . . . . . . . . . 554.6 Circuito de leitura de chave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594.7 Oscilação do sinal no momento do chaveamento . . . . . . . . . . . . . . . . . . . 604.8 Circuito de debounce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604.9 Utilização de filtro RC para debounce do sinal . . . . . . . . . . . . . . . . . . . . 614.10 Teclado em arranjo matricial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 634.11 Display Alfanumérico LCD 2x16 . . . . . . . . . . . . . . . . . . . . . . . . . . . 664.12 Display Alfanumérico LCD 2x16 - verso . . . . . . . . . . . . . . . . . . . . . . . 674.13 Caracteres disponíveis para ROM A00 . . . . . . . . . . . . . . . . . . . . . . . . 684.14 Caracteres disponíveis para ROM A02 . . . . . . . . . . . . . . . . . . . . . . . . 694.15 Esquemático de ligação do display de LCD . . . . . . . . . . . . . . . . . . . . . . 714.16 Sinal serializado para transmissão em RS232 . . . . . . . . . . . . . . . . . . . . . 754.17 Lâmpada incandescente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794.18 Potenciômetro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804.19 Potenciômetro como divisor de tensão . . . . . . . . . . . . . . . . . . . . . . . . 804.20 Circuito integrado LM35 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804.21 Diagrama de blocos do LM35 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 814.22 Conversor analógico digital de 2 bits . . . . . . . . . . . . . . . . . . . . . . . . . 824.23 Sinais PWM com variação do duty cycle . . . . . . . . . . . . . . . . . . . . . . . 85

iii

Page 5: Livro Programando Microcontroladores PIC Linguagem C.pdf

5.1 Exemplo de máquina de estados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1015.2 Exemplo da mudança de slots no tempo . . . . . . . . . . . . . . . . . . . . . . . 1055.3 Linha de tempo de um sistema com 1 slot . . . . . . . . . . . . . . . . . . . . . . 1055.4 Comportamento da linha de tempo com interrupções . . . . . . . . . . . . . . . . 105

iv

Page 6: Livro Programando Microcontroladores PIC Linguagem C.pdf

Lista de Tabelas

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

2.1 Tipos de dados e faixa de valores . . . . . . . . . . . . . . . . . . . . . . . . . . . 162.2 Representação decimal - binária - hexadecimal . . . . . . . . . . . . . . . . . . . . 172.3 Alteração de tamanho e sinal dos tipos básicos . . . . . . . . . . . . . . . . . . . 182.4 Operação bit set com define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302.5 Operação bit clear com define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312.6 Operação bit flip com define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322.7 Operação bit test com define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

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

4.1 Endereços de memória para as portas do PIC 18F4550 . . . . . . . . . . . . . . . 484.2 Tabela de configuração do PIC para as experiências . . . . . . . . . . . . . . . . . 514.3 Conversão binário - hexadecimal para displays de 7 segmentos . . . . . . . . . . . 554.4 Lista de comandos aceitos pelo o LCD . . . . . . . . . . . . . . . . . . . . . . . . 704.5 Taxas de transmissão para diferentes protocolos . . . . . . . . . . . . . . . . . . . 744.6 Cálculo do valor da taxa de transmissão da porta serial . . . . . . . . . . . . . . . 764.7 Faixa de frequências máximas e mínimas para cada configuração do prescaler . . 86

v

Page 7: Livro Programando Microcontroladores PIC Linguagem C.pdf

Lista de Programas

2.1 Resumo do disp7seg.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.2 Resumo do disp7seg.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.3 Estrutura de header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.4 Operações aritméticas com tipos diferentes . . . . . . . . . . . . . . . . . . . . . . 204.1 disp7seg.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574.2 disp7seg.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584.3 Utilizando a biblioteca disp7seg . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584.4 teclado.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644.5 teclado.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654.6 Exemplo de uso da biblioteca teclado . . . . . . . . . . . . . . . . . . . . . . . . . 654.7 lcd.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 714.8 lcd.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724.9 Exemplo de uso da biblioteca de LCD . . . . . . . . . . . . . . . . . . . . . . . . 734.10 serial.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774.11 serial.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 784.12 Exemplo de uso da biblioteca de comunicação serial . . . . . . . . . . . . . . . . . 784.13 adc.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 834.14 adc.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 834.15 Exemplo de uso da biblioteca de conversores AD . . . . . . . . . . . . . . . . . . 844.16 pwm.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874.17 pwm.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874.18 Exemplo de uso da biblioteca das saídas PWM . . . . . . . . . . . . . . . . . . . 884.19 timer.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894.20 timer.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 904.21 Exemplo de uso da biblioteca de um temporizador . . . . . . . . . . . . . . . . . 904.22 Reprodução de sons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 914.23 Fontes de Interupção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 934.24 Tratamento das interrupções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944.25 Inicialização do sistema com interrupções . . . . . . . . . . . . . . . . . . . . . . 954.26 Inicialização do sistema com interrupções . . . . . . . . . . . . . . . . . . . . . . 965.1 Exemplo de arquitetura single-loop . . . . . . . . . . . . . . . . . . . . . . . . . . 985.2 Problema na sincronia de tempo para o single-loop . . . . . . . . . . . . . . . . . 985.3 Exemplo de sistema Interrupt-driven . . . . . . . . . . . . . . . . . . . . . . . . . 995.4 Exemplo de sistema Interrupt-driven com base de tempo . . . . . . . . . . . . . . 1005.5 Exemplo de cooperative multitasking . . . . . . . . . . . . . . . . . . . . . . . . . 1025.6 Exemplo de cooperative multitasking com uso do top slot . . . . . . . . . . . . . 1035.7 Exemplo de sistema Cooperative-multitasking com slot temporizado . . . . . . . 1046.1 config.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1086.2 basico.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109

vi

Page 8: Livro Programando Microcontroladores PIC Linguagem C.pdf

Capítulo 1

Introdução

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

Programação para sistemas embarcados exige uma série de cuidados especiais, pois estes sistemasgeralmente possuem restrições de memória e processamento. Por se tratar de sistemas comfunções específicas, as rotinas e técnicas de programação diferem daquelas usadas para projetosde aplicativos para desktops.

Também é necessário conhecer mais a fundo o hardware que será utilizado, pois cada mi-croprocessador possui uma arquitetura diferente, com quantidade e tipos de instruções diversos.Programadores voltados para desktops não precisam se ater tanto a estes itens, pois eles progra-mam para um sistema operacional que realiza o papel de tradutor, disponibilizando uma interfacecomum, 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 especificamente para o hardware em ques-tão. Uma opção para se obter “artificialmente” esta camada de abstração que era gerada pelosistema operacional é a utilização de dois itens: um compilador próprio para o componente emquestão e uma biblioteca de funções. O compilador será o responsável por traduzir a linguagemde alto nível em uma linguagem que o microcontrolador consegue entender. A biblioteca defunções, ou framework, em geral, é disponibilizada pelos fabricantes do microcontrolador.

. Linguagem C

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

Neste curso será utilizada a linguagem C. Esta é uma linguagem com diversas características quea tornam uma boa escolha para o desenvolvimento de software embarcado. Apesar de ser umalinguagem de alto nível, permite ao programador um acesso direto aos dispositivos de hardware.

1

Page 9: Livro Programando Microcontroladores PIC Linguagem C.pdf

2 Introdução

Também é a escolha da maioria dos programadores e gerentes de projetos no que concerneao desenvolvimento de sistemas embarcados como pode ser visto na Figura 1.2.

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

A descontinuidade depois de 2004 se dá devido à mudança de metodologia da pesquisa. Antesde 2005, a pergunta formulada era: “Para o desenvolvimento da sua aplicação embarcada, quaisdas linguagens você usou nos últimos 12 meses?”. Em 2005 a pergunta se tornou: “Meu projetoembarcado atual é programado principalmente em ______”. Múltiplas seleções eram possíveisantes de 2005, permitindo a soma superior a 100%, sendo o valor médio de 209%, o que implicaque a maioria das pessoas escolheu duas ou mais opções.

O maior impacto na pesquisa pode ser visualizado na linguagem assembler: até 2004, estavapresente em 62% das respostas (na média). O que comprova que praticamente todo projeto desistema embarcado exige um pouco de assembler. Do mesmo modo, percebemos que atualmentepoucos projetos são realizados totalmente ou em sua maioria em assembler, uma média de apenas7%.

. Hardware utilizado“People who are really serious about software should make their ownhardware.” - Alan Kay

Como o enfoque deste curso é a programação de sistemas embarcados e não a eletrônica, utili-zaremos um kit de desenvolvimento pronto, baseado num microcontrolador 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 ventilador ligado a uma saída PWM

• 1 buzzer ligado a uma saída PWM

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

Page 10: Livro Programando Microcontroladores PIC Linguagem C.pdf

3 Introdução

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

Cada componente terá seu funcionamento básico explicado para permitir o desenvolvimento derotinas para estes.

. Ambiente de programação

“First, solve the problem. Then, write the code.” - John Johnson

O ambiente utilizado será o MPLAB(R). Este é um ambiente de desenvolvimento disponibilizadopela Microchip(R) gratuitamente. O compilador utilizado será o SDCC, os linkers e assemblersserão disponibilizados pela biblioteca GPUtils.

Como o foco é a aprendizagem de conceitos sobre programação embarcada, poderá ser uti-lizada qualquer plataforma de programação e qualquer compilador/linker. Caso seja utilizadoqualquer conjunto de compilador/linker diferentes deve-se prestar atenção apenas nas diretivaspara gravação.

Para a programação em ambiente Linux recomenda-se o uso da suíte PIKLAB 15.10. Esteprograma foi desenvolvido para KDE 3.5. Além de permitir a integração com o mesmo compiladorutilizado neste curso permite a programação do microcontrolador utilizando o programador ICD2via 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 correta instalaçãodeve-se instalar os softwares segundo a sequência apresentada na Tabela 1.1. Anote o diretórioonde cada software foi instalado.

Após a instalação dos softwares deve-se abrir o arquivo “pic16devices.txt” (de preferência nowordpad) que foi instalado no diretório do SDCC dentro da pasta “include\pic16” (por padrão“C:\Arquivos de programas\SDCC\include\pic16”). No windows vista e windows 7 não é possíveleditar arquivos de sistema. Neste caso clique no arquivo com o botão direito > Propriedades >Segurança > Editar > Usuários e selecionar a opção Controle Total, depois clique em ok. Apósisso será possível editar o arquivo. Procure então a seguintes linhas:

name 18f4550using 18f2455

Trocar a letra “f” minúscula da primeira linha, apenas do 18f4550, para um “F” maiúsculo:

name 18F4550using 18f2455

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

Page 11: Livro Programando Microcontroladores PIC Linguagem C.pdf

4 Introdução

Após isto abrir a pasta onde foi instalado o MPLAB (por padrão: “C:\Arquivos de pro-gramas\Microchip\MPLAB IDE”). Abrir a pasta “Core\MTC Suites”. Abrir os arquivos “sdc-clink.mtc” e “gplink.mtc” num editor de texto. Apagar o conteúdo do arquivo “sdcclink.mtc”.Copiar todo conteúdo do arquivo “gplink.mtc” para o arquivo “sdcclink.mtc”. Salvar.

Após o passo acima o arquivo “sdcclink.mtc” deverá conter o seguinte texto:

// Microchip Language Tools// Configuration File// gplink// Craig Franklin[Tool]Tool=gplinkScriptExtension=lkrDefaultOptions=MultipleNodes=1SpaceBetweenSwitchAndData=1[0]Description=Output filenameSwitch=-oData=1MultipleOptions=0OutputNameSwitch=SwitchHidden=1[1]Description=Map fileSwitch=-mData=0MultipleOptions=0[2]Description=COFF FileSwitch=-cData=0MultipleOptions=0[3]Description=Hex FormatOptionList=INHX8M;INHX8S;INHX32INHX8M=-a INHX8MINHX8S=-a INHX8SINHX32=-a INHX32Data=0[4]Description=Quiet modeSwitch=-qData=0

[5]Description=Library directoriesSwitch=-IData=1MultipleOptions=0LibrarySwitch=SwitchHidden=1[6]Description=Linker script directoriesSwitch=-IData=1MultipleOptions=0LinkerScriptSwitch=SwitchHidden=1[7]Description=Use Shared MemorySwitch=-rData=0[8]Description=Fill ValueSwitch=-fMultipleOptions=0Data=1[9]Description=Stack SizeSwitch=-tMultipleOptions=0Data=1[10]Description=No List Fileswitch=-lData=0

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

Selecione a ferramenta “Small Device C Compiler for PIC16 (SDCC16)”. Expanda a opção“Executables”. A ferramenta “gpasm” e “gplink” são obtidas no diretório “bin” dentro de ondefoi instalado o GPUtils, por padrão: “C:\Arquivos de programas\gputils\bin”. A ferramentasdcc16 é encontrada no diretório “bin” dentro do diretório onde foi instalado o SDCC com onome “sdcc.exe”, por padrão: “C:\Arquivos de programas\SDCC\bin\”. Clicar em “OK”. Apósestes passos a suíte MPLAB está pronta para trabalhar com o compilador SDCC+GPUtils.

Configuração do gravador ICD2

Após instalar o MPLAB já é possível fazer a instalação e configuração do gravador ou depuradorICD2. Conecte-o a qualquer porta USB e aguarde a tela de instalação do Windows. Em algumasversões do windows pode acontecer de você ser perguntado se deseja instalar um software não

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

Page 12: Livro Programando Microcontroladores PIC Linguagem C.pdf

5 Introdução

Figura 1.3: Configuração das ferramentas de compilação

assinado digitalmente, certifique-se que a versão do firmware é pelo menos 1.0.0.0 da fabricanteMicrochip, conforme pode ser visto na Figura 1.4 e avance.

Após o termino da instalação abra o programa MPLAB para configurar o gravador ou depu-rador. Vá ao menu “Programmer -> Select Programmer -> MPLAB ICD 2”. Vá novamente aomenu “Programmer” mas desta vez escolha a opção “ MPLAB ICD 2 Setup Wizard”.

No wizard, escolha a comunicação como USB e depois diga que a placa possui alimentaçãoindependente “Target has own power supply”. Deixe as outras opções na seleção padrão. Antesde clicar em concluir verifique ao final se o resumo se parece com o da Figura 1.5.

Na primeira vez que o computador se conectar ao ICD2 é possível que o MPLAB preciseatualizar o firmware do ICD2 conforme o aviso que pode ser visto na Figura 1.6.

Criação de um novo projeto

Recomenda-se a utilização do assistente disponível para a criação de um novo projeto (menuProject -> Project Wizard). Ele irá questionar sobre (entre parênteses os valores adotados nestecurso):

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 do projeto não estejavisível vá ao menu View -> Project.

Para a criação de um novo arquivo vá até o menu File -> New. Neste novo arquivo digitealguma coisa e salve-o. Caso seja o arquivo que conterá a função principal (main) é costumesalvá-lo com o nome de “main.c”.

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

Page 13: Livro Programando Microcontroladores PIC Linguagem C.pdf

6 Introdução

Figura 1.4: Instalação do ICD2

Figura 1.5: Resumo das configurações do ICD2 no MPLAB

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

Page 14: Livro Programando Microcontroladores PIC Linguagem C.pdf

7 Introdução

Figura 1.6: Pedido de atualização do firmware do ICD2

A cada novo arquivo criado é necessário inserí-lo no projeto. Para isso deve-se clicar na pastacorrespondente ao tipo de arquivo que se deseja incluir e em seguida “Add Files” como pode servisualizado na Figura 1.7.

Figura 1.7: Project Explorer do MPLAB

Além dos arquivos criados pelo programador, existem três arquivos que devem ser adicionadosao projeto: um de linker e dois de bibliotecas.

1. Linker

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

2. Bibliotecas

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

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

O arquivo de linker é o responsável por indicar quais são os espaços de memória disponíveisno chip utilizado, onde começam e de que tipo são (RAM, ROM, Flash) etc.

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

Page 15: Livro Programando Microcontroladores PIC Linguagem C.pdf

8 Introdução

// 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=0x7FFFCODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTEDCODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTEDCODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTEDCODEPAGE NAME=eedata START=0xF00000 END=0xF000FF PROTECTED

ACCESSBANK NAME=accessram START=0x0 END=0x5FDATABANK NAME=gpr0 START=0x60 END=0xFFDATABANK NAME=gpr1 START=0x100 END=0x1FFDATABANK NAME=gpr2 START=0x200 END=0x2FFDATABANK NAME=gpr3 START=0x300 END=0x3FFDATABANK NAME=usb4 START=0x400 END=0x4FF PROTECTEDDATABANK NAME=usb5 START=0x500 END=0x5FF PROTECTEDDATABANK NAME=usb6 START=0x600 END=0x6FF PROTECTEDDATABANK NAME=usb7 START=0x700 END=0x7FF PROTECTEDACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF PROTECTED

Percebemos pelo linker acima que existem 256 bytes de memória eeprom, não volátil, que foidenominada eedata. Para a memória RAM está reservado um total de 2 kbytes, divididos1 em 4bancos de memória, sendo que o primeiro 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 flash, que vai daposição 0x0000 até 0x7FFF. Este é o mesmo endereço da memória RAM. Não existe conflito,pois estamos trabalhando, no caso do PIC, com uma arquitetura Harvard. Nesta existem doisbarramentos e duas memórias diferentes: uma para o programa, denominada CODEPAGE nolinker, e uma para os dados, denominada DATABANK. Notar que apesar da memória eeprom serutilizada para armazenamento não volátil de dados, ela está mapeada no barramento de código.Isto se deve a construção interna do microcontrolador.

Os dados apresentados no linker e descorridos anteriormente podem ser verificados e compa-rados com outros modelos observando a Figura 1.8.

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

1Uma das maiores dificuldades encontradas em se construir um compilador de linguagem C é o gasto em termosde recursos computacionais que é dispendido para tratar estes quatro bancos como sequenciais. Na realidade elesestão todos sobre um mesmo endereço de memória. Para acessar cada um deles é necessário atuar sobre umregistro no PIC, indicando qual banco estará ativo naquele momento.

2gprX significa General Propouse Ram bank X

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

Page 16: Livro Programando Microcontroladores PIC Linguagem C.pdf

Capítulo 2

Linguagem C para sistemas embarcados

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

A programação para sistemas embarcados possui diversas características diferentes da progra-mação voltada para desktop. Do mesmo modo, existem alguns conceitos que geralmente não sãoexplorados nos cursos de linguagens de programação em C, mas que são essenciais para o bomdesenvolvimento deste curso. Estes conceitos serão explanados neste capítulo.

. Indentação e padrão de escrita

“Good programmers use their brains, but good guidelines save ushaving to think out every case.” - Francis Glassborow

É fundamental obedecer um padrão para escrita de programas, de modo que a visualização docódigo seja facilitada.

Na língua portuguesa utilizamos parágrafos para delimitar blocos de frases que possuem amesma ideia. Em linguagem C estes blocos são delimitados por chaves “{” e “}”.

Para demonstrar ao leitor que um parágrafo começou utilizamos um recuo à direita na pri-meira linha. Quando é necessário realizar uma citação de itens coloca-se cada um destes itensnuma linha recuada à direita, algumas vezes com um identificador como um traço “-” ou seta“->” para facilitar a identificação visual.

Com esse mesmo intuito, os recuos e espaçamentos são utilizados para que o código seja maisfacilmente entendido.

Como todo bloco de comandos é iniciado e terminado com uma chave, tornou-se comum queestas (as chaves) estejam no mesmo nível e todo código interno a elas seja deslocado à direita. Seexistir um segundo bloco interno ao primeiro, este deve ser deslocado duas vezes para indicar ahierarquia no fluxo do programa. Segue abaixo um exemplo de um mesmo código com diferençaapenas na indentação.

9

Page 17: Livro Programando Microcontroladores PIC Linguagem C.pdf

10 Linguagem C para sistemas embarcados

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 indentação facilita na verificaçãode quais instruções/rotinas estão subordinadas às demais.

Outra característica de padronização está na criação de nomes de funções e de variáveis. Pelalinguagem C uma função ou variável pode ter qualquer nome desde que: seja iniciada por umaletra, maiúscula ou minúscula, e os demais caracteres sejam letras, números ou underscore “_”.

A linguagem C permite também que sejam declaradas duas variáveis com mesmo nome casopossuam letras diferentes apenas quanto caixa (maiúscula ou minúscula). Por exemplo: “var” e“vAr” são variáveis distintas, o que pode gerar erro no desenvolvimento do programa causandodúvidas e erros de digitação.

Por isso convenciona-se que os nomes de variáveis sejam escritos apenas em minúsculas.Quando o nome é composto, se utiliza uma maiúscula para diferenciá-los como, por exemplo, asvariá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: “InicializaTeclado()”, “ParaSistema()”.

Tags de definições (utilizados em conjunto com a diretiva #define) serão grafados exclusiva-mente em maiúsculo: “NUMERODEVOLTAS”, “CONSTGRAVITACIONAL”.

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ãoabsolutas, servem apenas para o contexto desta apostila. Em geral, cada instituição ou projeto

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

Page 18: Livro Programando Microcontroladores PIC Linguagem C.pdf

11 Linguagem C para sistemas embarcados

possui seu próprio conjunto de normas. É importante ter conhecimento deste conjunto e aplicá-loem 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 C utilizam este estilo. Apesar disto opadrão ANSI C não especifica um estilo para ser usado.

. 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 a intenção de torná-lo mais claro. É uma boa prática em programação inserir comentários no meio dos nossosprogramas. Pode-se comentar apenas uma linha usando o símbolo “//” (duas barras). Paracomentar mais de uma linha usa-se o símbolo “/*” (barra e asterisco) antes do comentário e “*/”(asterisco e barra) para indicar o final 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 ;

}

. Arquivos .c e .h

Na programação em linguagem C utilizamos dois tipos de arquivos com funções distintas. Todaimplementação de código é feita no arquivo com extensão “.c” (code). É nele que criamos asfunções, definimos as variáveis e realizamos a programação do código. Se existem dois arquivos“.c” no projeto e 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” disponibilizandoas funções de um arquivo “.c” para serem utilizadas em outros arquivos. Nele colocamos todosos protótipos das funções que queremos que os outros arquivos usem.

Se quisermos que uma função só possa ser utilizada dentro do próprio arquivo, por motivode segurança ou organização, basta declarar seu protótipo APENAS no arquivo “.c”.

Se for necessário que um arquivo leia e/ou grave numa variável de outro arquivo é recomen-dado criar funções específicas para tal finalidade.

O programa 2.1 apresenta um exemplo de um arquivo de código “.c” e o programa 2.2 apre-senta o respectivo arquivo de header “.h”.

Podemos notar que no arquivo “.h” a função AtualizaDisplay() não está presente, deste modoela não estará disponível para os outros arquivos. Podemos notar também que para ler ougravar a variável “digito” é necessário utilizar as funções MudarDigito() e LerDigito(). Notar quenão existe acesso direto às variáveis. Este tipo de abordagem insere atrasos no processamentodevido à um efeito conhecido como overhead de funções, podendo inclusive causar travamentosno sistema caso não exista espaço suficiente no stack.

. Diretivas de compilação

As diretivas de compilação são instruções que são dadas ao compilador. Elas não serão executa-das. Todas as diretivas de compilação começam com um sinal #, conhecido como jogo da velhaou hash.

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

Page 19: Livro Programando Microcontroladores PIC Linguagem C.pdf

12 Linguagem C para sistemas embarcados

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

Programa 2.2: Resumo do disp7seg.h

1 #ifndef VAR_H2 #define VAR_H3 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 20: Livro Programando Microcontroladores PIC Linguagem C.pdf

13 Linguagem C para sistemas embarcados

#include

A diretiva de compilação #include é a responsável por permitir que o programador utilize no seucódigo funções que foram implementadas em outros arquivos, seja por ele próprio ou por outraspessoas. Não é necessário possuir o código fonte das funções que se deseja utilizar. É necessárioapenas de um arquivo que indique os protótipos das funções (como elas devem ser chamadas) epossuir a função disponível em sua forma compilada.

Em geral um arquivo que possui apenas protótipos de funções é denominado de “Header” epossui a extensão “.h”.

#define

Outra diretiva muito conhecida é a #define. Geralmente é utilizada para definir uma constante,mas pode ser utilizada para que o código fonte seja modificado antes de ser compilado.

Original Compilado Resultado na Tela

#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 #define Resultado na Tela

void MostraSaidaPadrao ( ){

#ifdef PADRAO Serialchar ∗ msg = "SERIAL" ;

#elsechar ∗ msg = "LCD" ;

#endifprintf ( 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 MostraSaidaPadrao(), apresenta re-sultados diferentes dependendo de como foi definida a opção PADRAO.

Os define’s também ajudam a facilitar a localização dos dispositivos e ajustar as configuraçõesno microcontrolador. Todo periférico possui um ou mais endereços para os quais ele responde.Estes endereços podem variar inclusive dentro de uma mesma família. Por exemplo: o endereçoda porta D (onde estão ligados os leds) é 0xF83. Para ligar ou desligar um led é preciso alteraro valor que esta dentro do endereço 0xF83. Para facilitar este procedimento, é definido umponteiro para este endereço e rotulado com o nome PORTD. Definir OFF como 0 e ON como 1facilita a leitura do código.

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

Page 21: Livro Programando Microcontroladores PIC Linguagem C.pdf

14 Linguagem C para sistemas embarcados

#ifdef, #ifndef, #else e #endif

As diretivas #ifdef, #ifndef, #else e #endif são muito utilizadas quando queremos gerar doisprogramas que diferem apenas num pequeno pedaço de código. Por exemplo dois sistemas decontrole de temperatura. O primeiro possui um display de LCD, capaz de mostrar a temperaturatextualmente. O segundo 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 serescrito da seguinte maneira

void ImprimirTemp (char valor ){

#ifdef LCDImprime_LCD ( valor )

#elsei f ( valor > 30){

led = 1 ;}else{

led = 0 ;}

#endif //LCD}

No momento da compilação o pré-compilador irá verificar se a “tag” LCD foi definida emalgum lugar. Em caso positivo o pré-compilador irá deixar tudo que estiver entre o #ifdef e o#else e retirará tudo que está entre o #else e o #endif.

Outra função muito utilizada destas diretivas é para evitar a referência circular. Supondo doisarquivos, um responsável pela comunicação serial (serial.h) e o segundo responsável pelo controlede temperatura (temp.h). O projeto exige que a temperatura possa ser controlada pela portaserial e toda vez que a temperatura passar de um determinado patamar deve ser enviado umalerta pela porta serial. O aquivo da porta serial (serial.h) tem as seguintes funções, apresentadasa seguir.

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

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

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

Toda vez que a função LerTemperatura() for chamada, ela deve fazer um teste e se o valor formaior que um patamar chamar a função EnviaSerial() com o código 0x30. Para isso o arquivotemp.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 a função AjustaCalor()e repassar esse valor. Para isso o arquivo serial.h deve incluir o arquivo temp.h

#include "temp.h"char LerSerial (void ) ;void EnviaSerial (char val ) ;

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

Page 22: Livro Programando Microcontroladores PIC Linguagem C.pdf

15 Linguagem C para sistemas embarcados

Programa 2.3: Estrutura de header

1 #ifndef TAG_CONTROLE2 #define TAG_CONTROLE3 // todo o conteúdo do arqu ivo vem aqui .

5 #endif //TAG_CONTROLE

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

#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

A solução é criar um dispositivo que permita que o conteúdo do arquivo seja lido apenas umavez. Este dispositivo é implementado através da estrutura apresentada no programa 2.3.

Segundo o código acima, o conteúdo que estiver entre o #ifndef e o #endif, só será mantidose a a tag “TAG_CONTROLE” NÃO estiver definida. Como isto é verdade durante a primeiraleitura, o pré-compilador lê o arquivo normalmente. Se acontecer uma referência cíclica, nasegunda vez que o arquivo for lido, a tag “TAG_CONTROLE” já estará definida impedindoassim que o processo cíclico continue, conforme pode ser visto na Figura 2.2.

Geralmente se utiliza como tag de controle o nome do arquivo. Esta tag deve ser única paracada arquivo.

. Tipos de dados em C

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

O tipo de uma variável, informa a quantidade de memória, em bytes, que esta irá ocupar e comoesta deve ser interpretada: com ou sem fração (vírgula). Os tipos básicos de dados na linguagem

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

Page 23: Livro Programando Microcontroladores PIC Linguagem C.pdf

16 Linguagem C para sistemas embarcados

#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

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

float 32 4 3,4 x 10-38 à 3,4 x 1038

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

Podemos notar que as variáveis que possuem maior tamanho podem armazenar valores mai-ores. Notamos também que apenas os tipos float e double possuem casas decimais.

Representação binária e hexadecimal

A grande maioria dos processadores trabalha com dados binários, ou seja, aqueles que apenasassumem valores 0 ou 1. Por isso os tipos apresentados anteriormente podem ser representadosutilizando a base 2. Um valor do tipo char que possui 8 bits será representado por um númerode 8 algarismos, todos 0 (zeros) ou 1 (uns). Para realizarmos a conversão de um número na basedecimal 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.

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

Page 24: Livro Programando Microcontroladores PIC Linguagem C.pdf

17 Linguagem C para sistemas embarcados

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 nestabase é que existe uma conversão simples de binário para hexadecimal e o número resultanteocupa bem menos espaço na tela.

A base hexadecimal possui 16 "unidades"diferentes. Como existem apenas 10 algarismos nosistema 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ão entre valores binários, decimais e hexadecimais é apresentadana Tabela 2.2.

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

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

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

1-0010Pela tabela:12 = 11600102 = 216.Logo:100102. = 1216.

Modificadores de tamanho e sinal

Um modificador de tipo altera o significado dos tipos base e produz um novo tipo. Existemquatro tipos de modificadores, dois para o tamanho (long e short) e dois para sinal (unsignede signed). Um tipo declarado com o modificador long pode ter tamanho MAIOR ou IGUALao tipo original. Um tipo declarado como short deve ter tamanho MENOR ou IGUAL ao tipooriginal. A decisão cabe ao compilador utilizado.

Os tipos declarados como signed possuem um bit reservado para o sinal, deste o valor máximoque podem atingir é menor. Os tipos declarados como unsigned não podem assumir valores

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

Page 25: Livro Programando Microcontroladores PIC Linguagem C.pdf

18 Linguagem C para sistemas embarcados

negativos, em compensação podem atingir o dobro do valor de um tipo signed. Na Tabela 2.3são apresentadas algumas variações possíveis.

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

Na linguagem C, por padrão os tipos são sinalizados, ou seja, possuem parte positiva enegativa. Por isso é raro encontrar o modificador signed.

Modificadores de acesso

Durante o processo de compilação, existe uma etapa de otimização do programa. Durante estaetapa, o compilador pode retirar partes do código ou desfazer loops com períodos fixos. Porexemplo o código abaixo:

#define X (∗ ( near unsigned char∗) 0xF83 )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 compiladorentende que esta condição nunca irá acontecer e elimina o loop do código final como podemosver no código gerado, a rotina de return está logo após a inicialização do programa _main. Paravariáveis comuns o valor só é 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 valor independentementedo programa. Se esta variável representar um endereço de memória associado à um periféricofísico, seu valor pode mudar independentemente do fluxo do programa. Para indicar esta situaçãoao programa utilizamos a palavra reservada volatile.

#define X (∗ ( volat i le near unsigned char∗) 0xF83 )void main (void ) interrupt 0{

while (X !=X ) ;}

Gerando o código em assembler descrito abaixo:

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

Page 26: Livro Programando Microcontroladores PIC Linguagem C.pdf

19 Linguagem C para sistemas embarcados

// 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 // primeira par te do endereçoMOVWF r0x00MOVLW 0x0f // segunda par te do endereçoMOVWF r0x01MOVFF r0x00 , FSR0LMOVFF r0x01 , FSR0HMOVFF INDF0 , r0x00 // r e a l i z a pr imeira l e i t u r aMOVLW 0x83 // primeira par te do endereçoMOVWF r0x01MOVLW 0x0f // segunda par te do endereçoMOVWF r0x02MOVFF r0x01 , FSR0LMOVFF r0x02 , FSR0HMOVFF INDF0 , r0x01 // r e a l i z a segunda l e i t u r aMOVF r0x00 , WXORWF r0x01 , WBNZ _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ável x duas vezes e realizaro teste para ver se ela permanece com o mesmo valor.

Em algumas situações é necessário indicar que algumas variáveis não podem receber valorespelo programa. Para isto utilizamos a palavra reservada const. Utilizamos este modificadorpara indicar que a variável representa um local que apenas pode ser lido e não modificado, porexemplo uma porta para 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 de erro:

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

Modificadores de posicionamento

As variáveis podem ser declaradas utilizando os modificadores near e far. Estes modificadoresindicam ao compilador em qual região de memória devem ser colocadas as variáveis.

A região near geralmente se refere à “zero page”. É uma região mais fácil de ser acessada. Aregião far exige mais tempo para executar a mesma função que a near.

Podemos pensar nestas regiões como a memória RAM e a memória Cache do computador.A segunda é mais rápida, mas possui um alto custo e por isso geralmente é menor. Em algumassituações é interessante que algumas variáveis nunca saiam do cache, pois são utilizadas comgrande frequência ou são críticas para o sistema.

Modificador de persistência

Em geral, as variáveis utilizadas dentro das funções perdem seu valor ao término da função. Paraque este valor não se perca podemos utilizar um modificador de persistência: static. Com essemodificador a variável passa a possuir um endereço fixo de memória dado pelo compilador. Além

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

Page 27: Livro Programando Microcontroladores PIC Linguagem C.pdf

20 Linguagem C para sistemas embarcados

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

disso o compilador não reutiliza este endereço em nenhuma outra parte do código, garantindoque na próxima vez que a função for chamada o valor continue o mesmo.

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

}

. Operações aritméticas

“If people do not believe that mathematics is simple, it is only be-cause they do not realize how complicated life is.” - John Louis vonNeumann

Um cuidado a se tomar, na programação em C para sistemas embarcados, é o resultado deoperações aritméticas. Por padrão na linguagem C o resultado de uma operação aritméticapossui 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 resultado um int (maioroperando). Não é possível armazenar esse resultado num 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 um problema se ambosforem muito próximo do valor limite. Por exemplo: 100 + 100 = 200, que não cabe num char,já que este só permite armazenar valores de -128 à 127.

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

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

Page 28: Livro Programando Microcontroladores PIC Linguagem C.pdf

21 Linguagem C para sistemas embarcados

O terceiro caso (linha 10) está correto, a multiplicação de dois char possui um valor máximode 127*127=16.129. O problema é que a multiplicação de dois char gera um outro char, perdendoinformação. É necessário realizar um 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. A divisão de dois inteirosnão armazena parte fracionária. Se isto não for crítico para o sistema está correto. Lembrar quea 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. O resultado da conta deum número inteiro com um ponto flutuante é um ponto flutuante. Armazenar esse valor numoutro número inteiro gera perda de informação.

O sexto caso (linha 13) apresenta um problema muito comum. A divisão de dois númerosinteiros gera um outro número inteiro. Não importa se armazenaremos o valor numa variávelde ponto flutuante haverá perda de informação pois os operandos são inteiros. Para evitar esseproblema é 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 resultado da operação é umdouble, e estamos armazenando este valor num float.

O oitavo caso (linha 15) é similar ao sexto. Estamos realizando uma conta com dois númerosinteiros esperando que o resultado seja 0,5. Como os 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úmeropara indicar operaçõ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úmeros com ponto flutuante.

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 infinito. Como existem restrições de precisão nosnúmeros de ponto flutuante (float e double) nem todos os números são representados fielmente.Os erros de arredondamento podem fazer com que a condição (x !=1.1) nunca seja satisfeita.Sempre que houver a necessidade de comparação com números de ponto flutuante utilizar maior,menor ou variações.

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

}

Apesar de sutis estes tipos de erro podem causar um mau funcionamento do sistema. NaFigura 2.3 é apresentado um erro gerado através de um loop infinito.

. Função main()

Todo sistema necessita de iniciar em algum lugar. Em geral, os microcontroladores, assim queligados, procuram por suas instruções no primeiro ou último endereço de memória, dependendoda arquitetura utilizada. O espaço de memória disponível neste endereço é geralmente muito

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

Page 29: Livro Programando Microcontroladores PIC Linguagem C.pdf

22 Linguagem C para sistemas embarcados

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

pequeno, apenas o necessário para inserir uma instrução de pulo e o endereço onde está a funçãoprincipal. Este espaço é conhecido como posição de reset. Existem ainda outros espaços dememória similares a este que, geralmente, são alocados próximos. O conjunto destes espaços éconhecido como vetor de interrupção (Figura 2.4).

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

A maneira de indicar o ponto de início de um programa depende do compilador. Em geral os

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

Page 30: Livro Programando Microcontroladores PIC Linguagem C.pdf

23 Linguagem C para sistemas embarcados

compiladores alocam a função main() em algum lugar da memória onde haja espaço disponível.Depois disso dispõem de uma instrução de pulo para o primeiro endereço de memória, onde foialocada a função main.

Para o compilador SDCC/GPUtils no MPLAB é necessário indicar que queremos que a funçãomain() seja chamada toda vez que o sistema for iniciado. Por isso é necessário que a posição dereset dentro do vetor de 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ódigo abaixo.

void main (void ) interrupt 0{

// aqui entra o código do programa}

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

Em geral sistemas embarcados são projetados para começarem a funcionar assim que ligados eapenas parar sua tarefa quando desligados. Como todas as funcionalidades são chamadas dentroda função main()1 espera-se que o programa continue executando as instruções dentro dela atéser desligado ou receber um comando para desligar. Este comportamento pode ser obtido atravésde um loop infinito. Abaixo estão as duas alternativas mais utilizadas.

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

}}

. Rotinas de tempo

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

É muito comum necessitar que o microcontrolador fique um tempo sem fazer nada. Uma maneirade atingir esse objetivo é utilizar um laço FOR2.

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

Notar que não estamos utilizando os colchetes. Logo após fechar os parênteses já existe umponto e virgula. Para entender como esse procedimento funciona, e estimar o tempo de espera épreciso entender como o compilador traduz 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_ :

1Em sistemas mais complexos algumas tarefas são executadas independentemente da função principal, tendosua 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 31: Livro Programando Microcontroladores PIC Linguagem C.pdf

24 Linguagem C para sistemas embarcados

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 3 passos de inicialização.Cada iteração exige 2 passos: uma comparação e um “pulo”3, totalizando 3 ciclos de inicializaçãoe 3 ciclos de interação.

Se temos um processador trabalhando a 8 MHz, cada instrução é executada em 0.5µs.4 Paratermos um tempo de espera de 0.5s precisamos de 1 milhão de instruções. Se colocarmos loopsencadeados podemos multiplicar a quantidade de instruções que serão executadas. Para obtermosum valor de 1 milhão de instruções devemos utilizar pelo menos 3 loops encadeados. Os valoresdos 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 meio segundo. Compilandoe realizando testes práticos podemos confirmar que o tempo real é aproximadamente 0.51 (s).Esta discrepância acontece porque agora temos 3 loops encadeados e cada qual com sua variávelde controle. Deste modo o compilador precisa salvar e carregar cada variável para realizar acomparação.

Percebemos assim que para conhecer corretamente o funcionamento do sistema é necessário,em algumas situações, abrir o código em assembler gerado pelo compilador para entender comoeste é executado. Nem sempre o compilador toma as mesmas decisões que nós. Além disso elepode gerar otimizações no código. Existem dois tipos de otimização: uma visando diminuir otempo de execução do sistema, deixando-o mais rápido e outra que reduz o tamanho do códigofinal, poupando espaço na memória.

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

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}

}}

}

. Operações com bits

“All of the books in the world contain no more information than isbroadcast as video in a single large American city in a single year.Not all bits have equal value.” - Carl Sagan

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

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

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

Page 32: Livro Programando Microcontroladores PIC Linguagem C.pdf

25 Linguagem C para sistemas embarcados

Nos sistemas microcontrolados, existem algumas variáveis onde cada bit tem uma interpretaçãoou funcionalidade diferente. Por isso é necessário realizar algumas operações que modifiquemapenas os bits desejados, mantendo o restante dos bits da variável inalterados.

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

É importante ressaltar que as operações de bitwise possuem funcionalidade semelhante a suasrespectivas operações lógicas. A diferença é que a lógica opera em cima da variável como umtodo5 enquanto a bitwise opera bit à bit.

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 significa que a operação érealizada para cada um dos bits da variável, não mais para a variável como um todo. Na tabelaseguinte é apresentada a diferença entre as 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 for zero, e 1 se os doisvalores 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 cada par de bits e colocao 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

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

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

Page 33: Livro Programando Microcontroladores PIC Linguagem C.pdf

26 Linguagem C para sistemas embarcados

OR

A operação OR lógica (operador ||) retorna 1 se algum dos valores for diferente de zero, e 0 seos 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 par de bits e coloca oresultado 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. Esta operação pode serrepresentada 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 cada par de bits e colocao 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 = 13// A = 0b00001000// B = 0b00000101// r = 0b00001101

Shift

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

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

Page 34: Livro Programando Microcontroladores PIC Linguagem C.pdf

27 Linguagem C para sistemas embarcados

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 multiplicação/divisão porpotência de dois. Cada shift multiplica/divide por 2 o valor. Esta é uma prática muito comumpara evitar a divisão que na maioria dos sistemas embarcados é uma operação cara do ponto devista de tempo de processamento.

Não utilizar esta operação com o intuito de multiplicar/dividir variáveis com ponto fixo ouflutuante nem variáveis sinalizadas (signed).

Em diversas ocasiões é necessário que trabalhemos com os bits de maneira individual, prin-cipalmente quando estes bits representam saídas ou entradas digitais, por exemplo chaves ouleds.

Supondo que temos 8 leds ligados ao microcontrolador. Cada led é representado através de 1bit de uma variável. Para ligarmos ou desligarmos apenas um led por vez, não alterando o valordos demais, devemos nos utilizar de alguns passos de álgebra digital.

Ligar um bit (bit set)

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

Se o objetivo é ligar apenas o bit da posição X devemos criar um valor onde todas as posiçõessão 0's com exceção da posição desejada. Para uma má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 apresentará valor 1 na posiçãoX e manterá os valores antigos para as demais posições. Exemplo: Ligar apenas o bit 2 da variávelPORTD

// de 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 3o l e dPORTD = PORTD | mascara ;//mantém o s is tema l i g a d o inde f in idamentefor ( ; ; ) ;

}

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

Page 35: Livro Programando Microcontroladores PIC Linguagem C.pdf

28 Linguagem C para sistemas embarcados

Desligar um bit (bit clear)

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

Novamente é necessário gerar uma máscara. Mas para esta situação ela deve possuir todosos bits iguais à um com exceção de X, o bit que queremos desligar.

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 resultado apresentará valor 0 naposição X e manterá os valores antigos para as demais posições. Exemplo: Desligar apenas o bit2 da variável PORTD.

// de 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 )// 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 3o 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 àquela utilizada no casoanterior, onde todos os valores são zero e apenas o desejado é um. Depois realizamos a inversãodos valores. Este procedimento é realizado desta maneira porque não sabemos o tamanho dapalavra a ser utilizada no microcontrolador: 8 ou 16 bits. Mesmo assim devemos garantir quetodos os bits obtenham o valor correto, o que é garantido pela operação de negação. A opção deinicializar a variável com apenas um zero e rotacionar pode não funcionar pois, na maioria dossistemas, a função de rotação insere zeros à medida que os bits são deslocados e precisamos queapenas um valor seja zero.

Trocar o valor de um bit (bit flip)

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

Podemos perceber que para trocar o valor de apenas um bit a máscara será idêntica àquelautilizada 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ção X será trocado, dezero para um ou de um para zero. Exemplo: Trocar o bit 2 e 6 da variável PORTD

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

Page 36: Livro Programando Microcontroladores PIC Linguagem C.pdf

29 Linguagem C para sistemas embarcados

// de 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 ídaPORTD = 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//Liga o b i t 2 , d e s l i g ando o 3o l e dPORTD = 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// Des l i ga o b i t 6 , l i g ando o 7o l e dPORTD = 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 apresentado troca o valordo bit escolhido. Foi utilizado o mesmo procedimento duas vezes. Na primeira, um bit foi ligadoe, na segunda, outro foi desligado.

Verificar o estado de um bit (bit test)

Para verificar se o bit X está um utilizaremos novamente a mesma máscara utilizada para bit sete 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, davariável original, for zero. Se o bit da variável original for um a resposta será diferente de zero6.

Exemplo: Testar o bit 2 da variável PORTD

// de 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 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 su l t a do f o r verdade i ro l i g a todos os l e d s

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

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

Page 37: Livro Programando Microcontroladores PIC Linguagem C.pdf

30 Linguagem C para sistemas embarcados

}else{

PORTD = 0xff ; // se o r e su 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 define’s

Uma opção no uso de define’s é criar funções simples que podem ser escritas em apenas umalinha. Utilizando um pouco de algebrismo e parênteses, é possível escrever as quatro operaçõesanteriores numa única linha. De posse desta simplificação podemos criar uma função para facilitaro uso destas operações através de um define conforme podemos ver nas tabelas 2.4, 2.5, 2.6 e2.7.

Tabela 2.4: Operação bit set com define

Operação Bit set

Passo a Passo

char bit = 2 ;char mascara ;mascara = 1 << bit ;arg = arg | mascara ;//em 1 l i nhaarg = arg | (1<<bit ) ;//ouarg |= (1<<bit ) ;

Exemplo de uso

//Ligando o b i t 2 da por ta DPORTD = PORTD | (1<<2) ;//ouPORTD |= (1<<2) ;

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

Exemplo de uso com de-fine

//Ligando o b i t 2 da por ta DBitSet ( PORTD , 2 ) ;

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

Page 38: Livro Programando Microcontroladores PIC Linguagem C.pdf

31 Linguagem C para sistemas embarcados

Tabela 2.5: Operação bit clear com define

Operação Bit clear

Passo a Passo

char bit = 2 ;char mascara ;mascara = 1 << bit ;arg = arg & ~mascara ;//em 1 l i nhaarg = arg & ~(1<<bit ) ;//ouarg &= ~(1<<bit ) ;

Exemplo de uso

//Des l igando o b i t 2 da porta DPORTD = PORTD & ~(1<<2) ;//ouPORTD &= ~(1<<2) ;

Com define #define BitClr ( arg , b i t ) ( ( arg ) &= ~(1<<b i t ) )

Exemplo de uso com de-fine

//Des l igando o b i t 2 da porta DBitClr ( PORTD , 2 ) ;

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

Page 39: Livro Programando Microcontroladores PIC Linguagem C.pdf

32 Linguagem C para sistemas embarcados

Tabela 2.6: Operação bit flip com define

Operação Bit flip

Passo a Passo

char bit = 2 ;char mascara ;mascara = 1 << bit ;arg = arg ^ mascara ;//em 1 l i nhaarg = arg ^ (1<<bit ) ;//ouarg ^= (1<<bit ) ;

Exemplo de uso

//Trocando o va l o r do b i t 2 da porta DPORTD = PORTD ^ (1<<2) ;//ouPORTD ^= (1<<2) ;

Com define #define BitFlp ( arg , b i t ) ( ( arg ) ^= (1<<b i t ) )

Exemplo de uso com de-fine

//Trocando o va l o r do b i t 2 da porta DBitFlp ( PORTD , 2 ) ;

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

Page 40: Livro Programando Microcontroladores PIC Linguagem C.pdf

33 Linguagem C para sistemas embarcados

Tabela 2.7: Operação bit test com define

Operação Bit test

Passo a Passo

char bit = 2 ;char mascara ;mascara = 1 << bit ;i f ( arg & mascara )//em 1 l i nhai f ( arg & (1<<bit ) )

Exemplo de uso

//Testando o b i t 2 da por ta Di f ( PORTD | (1<<2) ){

// . . .}

Com define #define BitTst ( arg , b i t ) ( ( arg ) & (1<<b i t ) )

Exemplo de uso com de-fine

//Testando o b i t 2 da por ta Di f ( BitTst ( PORTD , 2 ) ){

// . . .}

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

Page 41: Livro Programando Microcontroladores PIC Linguagem C.pdf

34 Linguagem C para sistemas embarcados

. Debug de sistemas embarcados7

“In the beginner's mind there are many possibilities; in the expert'smind there are few.” - Shunryu Suzuki

A verificação de sistemas embarcados apresenta algumas restrições e de modo geral não é possívelinferir sobre a operação do sistema sem paralisá-lo. Como este tipo de sistema possui váriosdispositivos agregados, que funcionam independentemente do processador, é necessário utilizarabordagens diferentes para realizar o debug.

Devemos lembrar que além do software devemos levar em conta possíveis problemas advindosdo hardware. Debounce, tempo de chaveamento, limite do barramento de comunicação sãoexemplos de pontos a serem considerados no momento de depuração.

Externalizar as informações.

A primeira necessidade é conhecer o que está acontecendo em teu sistema. Na programaçãotradicional para desktop é comum utilizarmos de mensagens no console avisando o estado doprograma.

#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 informacao" ) ;}else{

printf ("Problemas na comunicacao" ) ;}return 0 ;

}

Devemos ter em mente onde é necessário colocar estes alertas e lembrar de retirá-los do códigofinal.

Para a placa em questão utilizaremos o barramento de leds que está ligado à porta D. A ope-ração deste dispositivo será estudada posteriormente em detalhes. Por enquanto basta sabermosque cada bit da variável PORTD está ligada à um led diferente. Por causa da construção físicada placa, o led é aceso com valor 0 (zero) e desligado com o valor 1 (um). Além disso temos queconfigurar a porta D. Isto é feito iniciando a variável TRISD com o valor 0x008.

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

7Mais informações sobre debug de sistemas embarcados referir ao artigo “The ten secrets of embedded debug-ging” de Stan Schneider e Lori Fraleigh

8As variáveis PORTD e TRISD são definidas como unsigned char e possuem portanto 8 bits.

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

Page 42: Livro Programando Microcontroladores PIC Linguagem C.pdf

35 Linguagem C para sistemas embarcados

}

Devemos utilizar os leds como sinais de aviso para entendermos o funcionamento do programa.Isto pode ser feito através das seguintes ideias: “Se passar desta parte liga o led X”, “Se entrarno IF liga o led Y, se não entrar liga 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 realizar testes incrementais.A cada alteração no código realizar um novo teste. Evitar alterar o código em muitos lugaressimultaneamente, no caso de aparecer um erro fica 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ções são liberadas emalgum ponto do programa.

Cuidado com a fragmentação da memória

Sistemas com grande frequência na alocação/liberação de memória podem fragmentar a memóriaaté o ponto de inviabilizar os espaços livres disponíveis, eventualmente travando o sistema.Quando trabalhar com rotinas de nível mais baixo, mais próximo ao hardware, tente utilizarapenas mapeamento estático de memória.

Otimização de código

Apenas se preocupe com otimização se estiver tendo problemas com o cumprimento de tarefas.Mesmo assim considere em migrar para uma plataforma mais poderosa. Sistemas embarcadospreconizam segurança e não velocidade.

Caso seja necessário otimizar o código analise antes o local de realizar a otimização. Nãoadianta otimizar uma função grande se ela é chamada apenas uma vez. Utilize-se de ferramentasdo tipo profiler sempre que possível. Isto evita a perda de tempo e auxilia o programador avisualizar a real necessidade 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 tentarcorrigir o erro se não houver maneira de verificar se ele foi eliminado.

No momento em que se consegue um procedimento de como reproduzir o erro podemoscomeçar a visualizar onde ele pode estar. A partir deste momento devemos isolar onde o erroestá acontecendo. Uma maneira de se fazer isto em sistemas embarcados é colocar um loopinfinito dentro de um teste, que visa verificar alguma condição de anomalia. Se o sistema entrarneste teste devemos sinalizar através dos meios disponíveis, ligar/desligar algum led por exemplo.

// aqui tem um monte de código . . .i f ( PORTB >= 5) //PORTB não dever 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 . . .

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

Page 43: Livro Programando Microcontroladores PIC Linguagem C.pdf

36 Linguagem C para sistemas embarcados

. Ponteiros e endereços de memória“Writing in C or C++ is like running a chain saw with all the safetyguards removed.” - Bob Gray

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

Para conhecermos o endereço de uma variável podemos utilizar o operador &. Cuidado! Esteoperador também é utilizado para realização da operaçã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 criar um ponteiro paraela.

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

Para definir um ponteiro também precisamos indicar ao compilador um tipo. A diferença éque o tipo indica “quanto” cabe no local apontado pelo ponteiro e não o próprio ponteiro.

Sintaxe:

tipo ∗ nome da variavel ;

Exemplo:

int ∗apint ;f loat ∗apfloat ;

Deve-se tomar cuidado, pois nos exemplos acima, apint e apfloat são variáveis que armazenamendereços de memória e não valores tipo int ou float. O lugar APONTADO pela variável apinté que armazena um inteiro, do mesmo modo que o lugar apontado por float armazena um valorfracionário.

Se quisermos manipular o valor do endereço utilizaremos apint e apfloat mas se quisermosmanipular o valor que esta dentro deste endereço devemos usar um asterisco antes do nome davariável. Exemplo:

apfloat = 3 . 2 ;∗apfloat = 3 . 2 ;

A primeira instrução indica ao compilador que queremos que o ponteiro apfloat aponte parao endereço de memória número 3.2, que não existe, gerando um erro. Se quisermos guardar ovalor 3.2 no endereço de memória apontado por apfloat devemos utilizar a segunda expressão.

Para trabalhar com ponteiros é preciso muito cuidado. Ao ser definido, um ponteiro temcomo conteúdo não um endereço, mas algo indefinido. Se tentamos usar o ponteiro assim mesmo,corremos o risco de que o conteúdo do ponteiro seja interpretado como o endereço de algum localda memória vital para outro programa ou até mesmo para o funcionamento da máquina. Nestecaso podemos provocar danos no programa, nos dados, ou mesmo travar a máquina.

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

Por exemplo, podemos criar um ponteiro que aponta para o endereço de uma variável jádefinida:

// de f i n indo a v a r i á v e l i v a r

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

Page 44: Livro Programando Microcontroladores PIC Linguagem C.pdf

37 Linguagem C para sistemas embarcados

int ivar ;// de f i n 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 possuem característicasespeciais. Estes endereços possuem registros de configuração, interfaces com o meio externo evariáveis importantes para o projetista. É pelo meio da utilização de ponteiros que é possívelacessar tais endereços de maneira simples, através da linguagem C.

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

Page 45: Livro Programando Microcontroladores PIC Linguagem C.pdf

Capítulo 3

Arquitetura de microcontroladores

“Any sufficiently advanced technology is indistinguishable from ma-gic.” - Arthur C. Clarke

Os microcontroladores são formados basicamente por um processador, memória e periféricosinterligados através de um barramento conforme Figura 3.1.

Em geral, os periféricos são tratados do mesmo modo que a memória, ou seja, para o pro-cessador não existe diferença se estamos tratando com um valor guardado na memória RAM oucom o valor da leitura de um conversor analógico digital. Isto acontece porque existem circuitoseletrônicos que criam um nível de abstração em hardware. Deste modo todos os dispositivosaparecem como endereços de memória.

38

Page 46: Livro Programando Microcontroladores PIC Linguagem C.pdf

39 Arquitetura de microcontroladores

Figura 3.1: Arquitetura do microcontrolador PIC 18F4550

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

Page 47: Livro Programando Microcontroladores PIC Linguagem C.pdf

40 Arquitetura de microcontroladores

. Acesso à memória

A quantidade de memória disponível que um microcontrolador pode acessar depende de doisfatores, os tamanhos das palavras de dados e das palavras de endereço.

O tamanho da palavra de dados representa quantos bits podem ser colocados numa únicaposição da memória.

O tamanho da palavra de endereço indica quantas posições de memória o processador con-segue enxergar.

Por exemplo, um microcontrolador cujo tamanho de dados e o tamanho da palavra de ende-reço são ambos 8 bits possui uma possibilidade de acessar uma memória de até:

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

O termo possibilidade foi usado pois, apesar de poder alcançar toda essa extensão, nemsempre existe memória física para armazenamento. Podemos imaginar a memória como umarmário. Um armário com 6 suportes pode abrigar até 6 gavetas. Depende do marceneiro fabricare colocar as gavetas neste 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 “sistemas de armazenamento”nos espaços (Figura 3.3). Alguns destes sistemas podem permitir que o usuário enxergue o queesta dentro mas não mexa. Alguns vão permitir que o usuário coloque coisas mas não retire.Outros ainda podem permitir que a pessoa retire objetos mas não possa repô-los.

Esta variedade de “sistemas de armazenamento” representam a variedade de tipos de memóriae de interfaces de periféricos que possuímos.

A memória é identificada através de um endereço. Por estarmos tratando de sistemas digitais,o valor do endereço é codificado em binário. Como visto anteriormente, escrever em binário étrabalhoso e muito propenso a gerar erros. Visando facilitar esse processo, é comumente adotadoo sistema hexadecimal para indicar o local de memória.

Os dispositivos são então ligados à um determinado número de endereço que passa a identificá-lo de forma única. O mesmo acontece para a memória RAM e memória ROM. Elas estão ligadas àuma série de endereços. Se, portanto, é preciso salvar uma variável na memória, tem-se que saberquais endereços estão ligados à memória RAM. Se quisermos ler alguma informação gravada namemória ROM, é preciso conhecer a localização exata antes de realizar a leitura.

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

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

Page 48: Livro Programando Microcontroladores PIC Linguagem C.pdf

41 Arquitetura de microcontroladores

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

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

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

Page 49: Livro Programando Microcontroladores PIC Linguagem C.pdf

42 Arquitetura de microcontroladores

. Clock e tempo de instrução

O microcontrolador é capaz de realizar apenas uma tarefa por vez. Estas tarefas são executadassempre a intervalos regulares definidos pelo clock do sistema. O clock define então a velocidadecom que o processador trabalha.

Algumas operações são mais demoradas pois são compostas de uma quantidade maior detarefas. Por exemplo a soma.

A soma de números inteiros é feita de maneira direta enquanto para somar dois númerosfracionários, que estão em notação científica1, é necessário igualar as potencias antes de realizara soma. Por este motivo a segunda operaçã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 ao desenvolvedor saber demaneira determinística qual é a exigência a nível de hardware para o sistema embarcado.

Por exemplo: Um sistema precisa executar 200 operações a cada milésimo de segundo. Cadaoperação possuí uma quantidade diferente de tarefas conforme 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

O total de tarefas a serem realizadas é de 341 tarefas por milissegundo. Isso dá uma quanti-dade de 341 mil tarefas por segundo. Se cada tarefa é realizada em um ciclo de clock precisamosde um microcontrolador cujo processador trabalhe no mínimo em 341 kHz.

1Números fracionários podem ser armazenados de dois modos no ambiente digital. O modo mais comum é oponto flutuante que se assemelha à notação científica.

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

Page 50: Livro Programando Microcontroladores PIC Linguagem C.pdf

43 Arquitetura de microcontroladores

. Esquema elétrico e circuitos importantes

Um microcontrolador é representado através de esquema elétrico. O esquema elétrico apresentaao projetista todos os componentes e suas ligações conforme apresentado na Figura 3.5.

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

Para funcionarem, todos os microcontroladores devem ser alimentados com tensão contínua.O valor varia de modelo para modelo. Alguns podem até mesmo aceitar diversos valores. O PIC18F4550 por exemplo pode ser alimentado com qualquer tensão contínua entre 2 e 5,5 volts.

Para gerar o clock necessário, que definirá a velocidade na qual o processador ira trabalhar,em geral é utilizado um oscilador a cristal, que possui uma ótima precisão.

Alguns microcontroladores podem dispensar o cristal externo optando por utilizar uma malhaRC interna ao chip. Esta alternativa é muito menos precisa e geralmente não permite valoresmuito altos de clock. A vantagem é que sistemas que utilizam malha RC interna como osciladoresprimários possuem um custo menor que sistemas que dependem de malhas de oscilação externa,seja ela excitada por outra malha RC ou por um cristal.

Existem alguns circuitos que não são essenciais para o funcionamento do sistema, mas auxi-liam muito no desenvolvimento. Entre estes tipos de circuito o mais importante é o que permitea gravação do programa no próprio circuito. Alguns microcontroladores exigem que o chip sejaretirado do circuito e colocado numa placa especial para gravá-lo e somente depois recolocadona placa para teste. Este é um procedimento muito trabalhoso e, devido ao desgaste mecânicoinerente, reduz a vida útil do chip.

Para evitar estes problemas, os fabricantes desenvolveram estruturas no chip que permitemque este seja gravado mesmo estando soldado à placa final. Para isso, basta que o desenvolvedordisponibilize o contato de alguns pinos com um conector. Este conector será ligado à um gra-vador que facilitará o trabalho de gravação do programa. Para a família PIC esta tecnologia édenominada ICSP (in circuit serial programming).

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

Page 51: Livro Programando Microcontroladores PIC Linguagem C.pdf

44 Arquitetura de microcontroladores

Multiplexação nos terminais do microcontrolador

Conforme pode ser observado na Figura 3.5, alguns pinos/terminais possuem mais de uma des-crição. Por exemplo o terminal 8, a descrição deste terminal é “RE0/AN5/CK1SPP”. Isto indicaque dependendo da configuração escolhida 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. Em sistemas mais avan-çados é possível inclusive utilizar mais de uma funcionalidade no mesmo terminal em períodosalternados, desde que o circuito seja projetado levando esta opção em consideração.

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

Page 52: Livro Programando Microcontroladores PIC Linguagem C.pdf

45 Arquitetura de microcontroladores

. Registros de configuração do microcontrolador

A maioria dos terminais dos microcontroladores podem ser configurados para trabalhar de di-versas maneiras. Esta configuração é realizada através de registros especiais. Estes registrossão posições de memória pré-definidas pelo fabricante. Para conhecer quais são e o que fazem épreciso recorrer ao datasheet do componente.

Além dos registros de configuração dos terminais, existem registros que indicam como o mi-crocontrolador deve operar. O microcontrolador PIC18f4550 possui dez registros que controlamseu modo de operação, velocidade, modo de gravação, etc. Estes registros são apresentados naFigura 3.6.

Figura 3.6: Registros de configuração do microcontrolador PIC 18F4550

Dos registros apresentados na Figura 3.6, quatro precisam necessariamente ser configuradospara que o sistema possa funcionar. Dois deles tem relação com a configuração do sistema declock: um especifica qual é a fonte do sinal de clock, que no caso da placa em questão é umcristal externo, e o outro indica qual o prescaler a ser usado (PLL).

Além de configurar a frequência básica do clock é necessário desligar o watchdog. Este éum circuito para aumentar a segurança do sistema embarcado desenvolvido. Para funcionarcorretamente, o programa deve ser preparado para tal finalidade. Ele será explicado em detalhesna seção . e por isso será mantido desligado nos próximos exemplos.

A ultima configuração necessária é desabilitar a programação em baixa tensão. Devido àsligações feitas na placa, deixar esta opção ligada impede o funcionamento da placa enquantoestiver ligada ao gravador. Abaixo o trecho de código que realiza estas configurações para ocompilador 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 armazena as configurações.A segunda coluna representa os códigos utilizados para configuração. Para conhecer as demaisopções de configurações devemos consultar o manual do usuário.

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

Page 53: Livro Programando Microcontroladores PIC Linguagem C.pdf

46 Arquitetura de microcontroladores

Estas configurações são dependentes do compilador a ser usado. A seguir demonstramos oscódigos necessários para o compilador C18 da Microchip(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 realizam o mesmo tra-balho.

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

Page 54: Livro Programando Microcontroladores PIC Linguagem C.pdf

Capítulo 4

Programação dos Periféricos

“In theory, there is no difference between theory and practice; Inpractice, there is.” - Chuck Reid

Periféricos são os componentes, circuitos ou sistemas ligados ao microcontrolador, interna ouexternamente. Eles podem ser utilizados para realizar interface entre o homem e o equipamentoou incluir funcionalidades extras ao 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(.)

• Display de 7 segmentos(.)

• Display LCD 2x16(.)

• Saídas PWM(.)

Entre os periféricos de entrada2 temos:

• Leitura de teclas(.)

• Conversor AD(.)

Além de sistemas de entrada e saída de dados será abordado um dispositivo de comunicaçãoserial (.), um tratador de Interrupção(.), um Timer(.) e um dispositivo de segurança:Watchdog(.).

1Periféricos que fornecem informações aos usuários ou enviam comandos da a placa eletrônica para o meioexterno

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

47

Page 55: Livro Programando Microcontroladores PIC Linguagem C.pdf

48 Programação dos Periféricos

. Acesso às “portas” do microcontrolador

O microcontrolador possui “portas” que permitem o interfaceamento do meio externo para o meiointerno. Algumas portas podem trabalhar como receptoras ou transmissoras de sinais. Algumaspodem operar dos dois modos sendo necessário configurá-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 armazena o valor quequeremos ler do meio externo ou escrever para o meio externo dependendo da configuração. Osegundo endereço realiza esta configuração indicando quais bits serão utilizados para entrada equais serão utilizados 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 configuraçã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á que conhecemos os endereçosfixos onde as portas se encontram, podemos criar ponteiros para tais endereços de forma quepossamos utilizar as portas como se 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//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 valor de tais variáveis énecessário que coloquemos o asterisco.

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

Page 56: Livro Programando Microcontroladores PIC Linguagem C.pdf

49 Programação dos Periféricos

Uma outra maneira de manipular as portas é criar define’s que permitem o uso das portascomo variáveis, sem a necessidade de utilizar ponteiros de modo explicito, nem asteriscos nocódigo.

// de 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 define, é uma boa prática de programação utilizar apenas letrasmaiúsculas para diferenciá-lo de uma variável comum.

Notem que usamos dois asteriscos no define. É isto que permite que utilizemos o define comouma variável qualquer, sem precisar de usar um asterisco a todo momento, como no caso dosponteiros.

A segunda abordagem (com define) é preferida em relação à primeira pois, dependendo docompilador, gera códigos mais rápidos além de economizar memória. Além disso, permite que adefinição seja feita apenas uma vez e utilizada em todo o programa.

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

Page 57: Livro Programando Microcontroladores PIC Linguagem C.pdf

50 Programação dos Periféricos

. Configuração dos periféricos

“Make everything as simple as possible, but not simpler.” - AlbertEinstein

Em geral, os terminais das portas são multiplexados com outros dispositivos. Para saber comoconfigurar cada porta é preciso conhecer os registros de configuração que atuam sobre a portadesejada. A Figura 4.1 apresenta todos os registros disponíveis do microcontrolador 18F4550.

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

Para a placa que estamos utilizando, a configuração dos terminais do PIC segue conforme aTabela 4.2. Esta configuração reflete a opção do autor de acordo com as possibilidades da placae também o sistema mínimo para realizaçã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éricosque não serão utilizados neste curso. Os terminais 11 e 31 representam a alimentação positiva.O comum (terra) está ligado ao 12 e ao 32. O microcontrolador utilizado (18f4550) possui oencapsulamento DIP. Para outros encapsulamentos favor considerar o datasheet.

Da Tabela 4.2, temos que a porta A possui o primeiro bit como entrada analógica e o terceiroe sexto como saída digital. Os dois bits digitais servem como controle de ativação do display.

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

Page 58: Livro Programando Microcontroladores PIC Linguagem C.pdf

51 Programação dos Periféricos

Tabela 4.2: Tabela de configuração do PIC para as experiências

Terminal Descrição do pino Função

2 RA0/AN0 Potenciômetro / Sensor de Temperatura

4 RA2/AN2/VREF-/CVREF Display 2

7 RA5/AN4/SS/C2OUT Display 1

8 RE0/AN5/CK1SPP RS-LCD / Display 3

9 RE1/AN6/CK2SPP EN-LCD

10 RE2/AN7/OESPP RW-LCD / Display 4

13 OSC1/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 do teclado34 RB1/AN10/INT1/SCK

35 RB2/AN8/INT2/VMO

36 RB3/AN9/CCP2/VPO

37 RB4/AN11/KBI0/CSSPP

Entradas para leitura do teclado38 RB5/KBI1/PGM

39 RB6/KBI2/PGC

40 RB7/KBI3/PGD

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

Page 59: Livro Programando Microcontroladores PIC Linguagem C.pdf

52 Programação dos Periféricos

TRISA = 0b00000001 ; // conf igurando os t e rmina i s como entrada e sa ídaADCON1 = 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 últimos como entrada. Estaporta serve para leitura da matriz de chaves. É possível realizar a leitura através de interrupção.

TRISB = 0b11110000 ; // conf igurando os t e 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 e oitavo comocomunicação serial.

TRISC = 0b10000000 ; // conf igurando os t e rmina i s como saída , apenas RC7 é entradaCCP1CON = 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 nela são transmitidos,simultaneamente, para os leds, os displays de 7 segmentos e o display de LCD.

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

A porta E possui apenas os 3 primeiros bits configurados como saídas digitais. São utilizadospara controle de ativação dos displays e também como sinais de controle do LCD.

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

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

Page 60: Livro Programando Microcontroladores PIC Linguagem C.pdf

53 Programação dos Periféricos

. Barramento de Led's

Existe na placa utilizada um barramento de 8 bits, onde cada linha possui um led associado. Estebarramento está ligado diretamente com a porta D do microcontrolador conforme Figura 4.2.

Figura 4.2: Barramento de Led's

Podemos notar pela Figura 4.2 que existe um jumper (JP1) que habilita ou não o funcio-namento destes leds. Além disso percebemos que se o jumper estiver encaixado, os led's estãopermanentemente ligados ao 5 volts. Deste modo, para que o led acenda, é necessário colocar ovalor 0 (zero) no respectivo bit da porta D. Quando um dispositivo é ligado com o valor 0 (zero)e desligado com o valor 1 (um), dizemos que este dispositivo opera com lógica invertida.

Conforme visto é preciso configurar os pinos da porta D como saída, para isso basta escreverzero 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

}

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

Page 61: Livro Programando Microcontroladores PIC Linguagem C.pdf

54 Programação dos Periféricos

. Display de 7 segmentos

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

Figura 4.3: Display de 7 SegmentosFonte: Peter Halasz - http://commons.wikimedia.org/wiki/File:Seven_segment_02_Pengo.jpg

Estes displays foram concebidos com o intuito de gerar os dez algarismos romanos: 0, 1, 2,3, 4, 5, 6, 7, 8, 9, sendo que os algarismos 0, 6, 7 e 9 podem ser representados de mais de umamaneira.

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

Os displays podem ser do tipo catodo comum, ou anodo comum indicando qual o tipo deligação dos leds. Contudo, esta diferença não será crítica para este estudo. Na Figura 4.4podemos visualizar o esquema elétrico e a disposiçã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 no display é necessárioacender os leds a, b, g, e, d. Se estivermos utilizando um display com catodo comum, precisamoscolocar um nível alto para ligar o 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 valoresem binário e em hexadecimal para cada representação alfanumérica3. Dentre as letras disponíveisestão apresentadas apenas os caracteres A, b, C, d, E, F. Estas foram escolhidos por serem osmais utilizados para apresentar valores em hexadecimal nos displays. Neste curso utilizaremos a

3Notar que os valores hexadecimais apresentados servem apenas quando existe uma sequencia na ligação entrea porta do microcontrolador e os pinos do display. Em alguns sistemas, o display pode ser controlado por duasportas diferentes, ou possuir alguma alteração na sequencia de ligação. Para tais casos é necessário remontar atabela apresentada.

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

Page 62: Livro Programando Microcontroladores PIC Linguagem C.pdf

55 Programação dos Periféricos

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

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

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

Para simplificar a utilização deste tipo de display é comum criar uma tabela cujas posiçõesrepresentam o valor de conversão para o display. Conforme pode ser visto no código a seguir.

void main (void ) interrupt 0{

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

Page 63: Livro Programando Microcontroladores PIC Linguagem C.pdf

56 Programação dos Periféricos

// 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 rac 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 utilizado o ponto decimal.Para utilizar 4 displays, por exemplo um relógio com dois dígitos para horas e dois para minutos,precisaríamos de 32 terminais de saída, o que pode ser um custo4 muito alto para o projeto.

Uma técnica que pode ser utilizada é a multiplexação dos displays. Esta técnica leva em contaum efeito biológico denominado percepção retiniana. O olho humano é incapaz de percebermudanças mais rápidas que 1/30 (s). Outro fator importante é que as imagens mais clarasficam gravadas na retina devido ao tempo que leva para sensibilizar e dessensibilizar as células(bastonetes).

Deste modo podemos ligar e desligar rapidamente o display que a imagem continuará naretina. Se ligarmos cada display, um por vez, sequencialmente, de maneira suficientementerápida, teremos a impressão que todos estão ligados. A frequência de “chaveamento” deve sermais rápida que 30Hz.

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

Mas esta economia tem um custo, o sistema se torna mais complexo pois não podemos ligardois displays ao mesmo tempo.

O controle de qual display será ligado é feito através do transistor que permite a ligação docatodo comum ao terra, ou o anodo comum ao VCC (depende do tipo de dispositivo. Para ocorreto funcionamento não basta agora acender os leds corretos para formar o número, temosque seguir um algoritmo 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 flicker5

4. desligar o display

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

6. voltar ao passo 14Microcontroladores com mais terminais possuem um custo superior, mesmo possuindo os mesmos periféricos

internamente.5Se a taxa de atualização dos displays for muito baixa, estes vão apresentar uma variação na intensidade, como

se estivessem piscando. Este efeito é chamado de flicker.

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

Page 64: Livro Programando Microcontroladores PIC Linguagem C.pdf

57 Programação dos Periféricos

Criação da biblioteca

O programa 4.1 apresenta um exemplo de código para criar uma biblioteca para os displays de 7segmentos. O programa 4.2 apresenta o header da biblioteca. Já o programa 4.3 apresenta umademonstração de uso da biblioteca.

Programa 4.1: disp7seg.c

1 #include "disp7seg.h"2 // ve to r para armazenar a conversão do ←↩

d i s p l a y3 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 65: Livro Programando Microcontroladores PIC Linguagem C.pdf

58 Programação dos Periféricos

Programa 4.2: disp7seg.h

1 #ifndef DISP7SEG_H2 #define DISP7SEG_H3 void MudaDigito (char val , char pos ) ;4 void AtualizaDisplay (void ) ;5 void InicializaDisplays (void ) ;6 #endif

Programa 4.3: Utilizando a biblioteca disp7seg

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

5 // i n i c i o do 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 66: Livro Programando Microcontroladores PIC Linguagem C.pdf

59 Programação dos Periféricos

. Leitura de teclas

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

Uma maneira de se obter este funcionamento é com o uso de uma chave ligada ao VCC e umpull-down ou uma chave ligada ao terra (GND) e um pull-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 a chave está desligadapois não existe corrente circulando no circuito portanto a queda de tensão em R1 é zero. Quandoa chave é pressionada uma corrente flui de VCC para o terra passando por R1. Como não existenenhuma outra resistência no circuito toda a tensão fica em cima de R1 e a tensão de saída passaa ser zero.

Apesar do funcionamento aparentemente simples, este tipo de circuito apresenta um problemade oscilação do sinal no momento em que a tecla é pressionada. Esta oscilação é conhecida comobouncing (Figura 4.7).

Estas oscilações indevidas podem gerar acionamentos acidentais, causando mau funciona-mento do programa. Para evitar isso podemos utilizar técnicas de debounce, por hardware ousoftware.

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 atraso para o sinal. Este é o tempo necessário paracarregar o capacitor. Deste modo as alterações rápidas no sinal, devido à oscilação mecânica dachave, são filtradas e não ocorre o problema dos chaveamentos indevidos conforme pode ser vistona Figura 4.9. Notar que o nível do sinal filtrado não chega a zero em nenhum momento, devidoà constante de tempo do filtro RC ser maior que o período de debounce.

Debounce por software

O debounce por software em geral é utilizado em situações onde se deseja aumentar a robustezde uma entrada que já possua um debounce por hardware ou reduzir o custo da placa utilizandoapenas a solução por software. A grande desvantagem deste tipo de sistema é inserir um atrasona detecção da informação.

Para realizar o debounce por software precisamos ter uma noção do tempo que a chaveprecisa para estabilizar. Da Figura 4.7 temos que este tempo, para uma determinada chave é deaproximadamente 150 (µs). Um ciclo de clock do sistema em questão (PIC18f4550 com cristal de

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

Page 67: Livro Programando Microcontroladores PIC Linguagem C.pdf

60 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 68: Livro Programando Microcontroladores PIC Linguagem C.pdf

61 Programação dos Periféricos

Figura 4.9: Utilização de filtro RC para debounce do sinalhttp://www.labbookpages.co.uk/electronics/debounce.html – A. Greensted (modificado)

8MHz) é de 0,56 (µs). Antes de utilizar o valor que estamos lendo na porta em questão devemosesperar 300 ciclos de clock após alguma mudança para ter certeza que o sinal se estabilizou, ouseja, a fase de bouncing acabou.

Notar que, no código, o contador é iniciado com o valor 22. Através da análise do assemblerpodemos saber que cada ciclo de conferencia do sinal possui 14 instruções. Assim é necessárioque o sinal permaneça com o mesmo valor durante 308 ciclos para que a variável valAtual recebao valor da porta B. Estes valores podem ser determinados empiricamente através de testes comosciloscó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 ; // con f i gura todos os b i t s da por ta B como d i g i t a i sfor ( ; ; ){

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

6Lembrar que cada ciclo do PIC necessita de 4 ciclos de clock externo

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

Page 69: Livro Programando Microcontroladores PIC Linguagem C.pdf

62 Programação dos Periféricos

}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 u a 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 do microcontrolador.Para um teclado maior é possível que o microcontrolador não possua terminais disponíveis emquantidade suficiente. Do mesmo modo que no caso dos displays é possível multiplexar aschaves aumentando a quantidade de chave por terminal. Novamente, este ganho, em termos dehardware, aumenta a complexidade para o software e juntamente com este, o custo em termosde tempo de computação.

Uma das técnicas mais eficientes para a geração deste teclado é o arranjo em formato matri-cial. Com esta configuração podemos, com N terminais, ler até (N/2)2̂ chaves.

Conforme podemos ver na Figura 4.10, cada chave pode ser identificada unicamente pelasua posição (linha, coluna). Os terminais ligados às linhas serão configurados como entrada,que servirão para ler os valores das teclas. Os terminais ligados às colunas serão configuradoscomo saídas, fornecendo energia para as chaves. A leitura é realizada então por um processoconhecido como varredura: liga-se uma coluna por vez e verifica-se quais chaves daquela colunaestã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 ofor (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 ) ;

}}

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

Page 70: Livro Programando Microcontroladores PIC Linguagem C.pdf

63 Programação dos Periféricos

Figura 4.10: Teclado em arranjo matricial

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

Page 71: Livro Programando Microcontroladores PIC Linguagem C.pdf

64 Programação dos Periféricos

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

}}

}

É importante notar que o código acima não apresenta debounce em software para as teclas. Épossível realizar um debounce minimizando o gasto com memória e tempo, representando cadachave como um bit diferente numa variável. Esta será a abordagem utilizada na geração dabiblioteca para o teclado.

Criação da biblioteca

O programa 4.4 apresenta um exemplo de código para criar uma biblioteca para um teclado de16 teclas com leitura matricial. O header pode ser visto no programa 4.5. Já o programa 4.6apresenta uma demonstração de uso da biblioteca.

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

Page 72: Livro Programando Microcontroladores PIC Linguagem C.pdf

65 Programação dos Periféricos

Programa 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

Programa 4.6: Exemplo de uso da biblioteca teclado

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

5 // i n i c i o do programa6 void main (void ) interrupt 07 {8 InicializaTeclado ( ) ;9 TRISD = 0x00 ; //Configura a por ta D como sa ída

10 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 73: Livro Programando Microcontroladores PIC Linguagem C.pdf

66 Programação dos Periféricos

. Display LCD 2x16

O display de LCD utilizado neste curso possui duas linhas por 16 colunas de caracteres, compatí-vel com o HD44780 que é um padrão muito utilizado na indústria. Na Figura 4.11 é apresentadoum modelo genérico deste tipo de display. A Figura 4.12 apresenta o verso do display com osterminais expostos.

Figura 4.11: Display Alfanumérico LCD 2x16

Este mesmo tipo de display pode ser encontrado em diversas versões com tamanhos e coresdiferentes sendo os mais comuns de 1x8, 2x16 e 4x40. Pode ainda ter 16 ou 14 terminais,dependendo se existe ou não retro iluminação. Estes terminais são identificados como:

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 8para o barramento de dados. Este tipo de display possui, integrado, um microcontrolador pararealizar as rotinas de manutenção do estado do display, controle da luminosidade e interface com

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

Page 74: Livro Programando Microcontroladores PIC Linguagem C.pdf

67 Programação dos Periféricos

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

o restante do sistema eletrônico. A comunicação é realizada através de um barramento paralelode 8 bits, por onde são enviados os dados/comandos.

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

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

O terminal EN indica ao display que ele pode ler/executar o que está no barramento dedados.

Atenção, o display utilizado apresenta os terminais colocados de maneira nã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 codificação ASCII, sendo que os caracteres de 0 à127 são padronizados. Os caracteres de 128 à 255 dependem do fabricante do display. É possíveltambém criar algumas representações, símbolos definidos pelo usuário e armazenar na memóriainterna do display. Para um display com a ROM do tipo A00 temos os caracteres definidos naFigura 4.13. Para a ROM A02 temos a Figura 4.14.

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

Page 75: Livro Programando Microcontroladores PIC Linguagem C.pdf

68 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 76: Livro Programando Microcontroladores PIC Linguagem C.pdf

69 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 77: Livro Programando Microcontroladores PIC Linguagem C.pdf

70 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 configura o endereçopara 0. 0 0 0 0 0 0 0 0 0 1 37 us

Configura o endereço para 0. Retorna o dis-play para o início se houve alguma operaçãode shift.

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

Configura a movimentação do cursor e o modode shift do display 0 0 0 0 0 0 0 1 ID S 37 us

Configura o display (D) inteiro para desligadoou ligado, cursor (C) ligado 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 sem alterar oconteúdo 0 0 0 0 0 1 SC RL - - 37 us

Configura o tamanho da palavra (DL), nú-mero de linhas (N) e fonte dos caracteres (F) 0 0 0 0 1 DL N F - - 37 us

Desloca o cursor para a posição desejada: li-nha e coluna. 0 0 1 X 0 0 Coluna 37 us

Verifica se o display está disponível ou se estaocupado com alguma operação interna. 0 1 BF - - - - - - - 10 us

Definiçõ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 para esquerdaDL: 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 - Datasheet Hitachi (modificado)

Os terminais de dados estão ligados à porta D, juntamente com o display de 7 segmentos ebarramento de dados. Para estes dispositivos funcionarem em conjunto é necessário multiplexa-los no tempo. Os terminais de controle estão ligados à porta E conforme o esquema apresentadona Figura 4.15.

Criação da biblioteca

Para facilitar o controle do display, podemos criar três funções, uma para inicialização, uma paraescrever um caractere e a última para enviar um comando. Estas funções estão apresentadas noprograma 4.8, que constitui um exemplo de biblioteca. Além destas três funções é necessário teruma função de delay, que garanta um determinado tempo para que as informações sejam lidascorretamente pelo LCD.

O header desta biblioteca e um exemplo de como usá-la são apresentados nos programas 4.7e 4.9, respectivamente.

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

Page 78: Livro Programando Microcontroladores PIC Linguagem C.pdf

71 Programação dos Periféricos

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

Programa 4.7: lcd.h

1 #ifndef LCD_H2 #define LCD_H3 void EnviaComando (char cmd ) ;4 void EnviaDados (char valor ) ;5 void InicializaLCD (void ) ;6 #endif //LCD_H

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

Page 79: Livro Programando Microcontroladores PIC Linguagem C.pdf

72 Programação dos Periféricos

Programa 4.8: 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 80: Livro Programando Microcontroladores PIC Linguagem C.pdf

73 Programação dos Periféricos

Programa 4.9: Exemplo de uso da biblioteca de LCD

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

5 // i n i c i o do 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 81: Livro Programando Microcontroladores PIC Linguagem C.pdf

74 Programação dos Periféricos

. Comunicação serial

Em geral a comunicação entre dois dispositivos eletrônicos é realizada de modo serial, isto é, asinformações são passadas bit à bit do transmissor para o receptor. Este tipo de comunicaçãopossui algumas vantagens em relação à comunicação paralela, na qual a palavra (byte) é enviadatoda de uma vez.

A primeira vantagem é a simplificação do hardware. Como os dados são enviados um a um,é necessário apenas um fio de comunicação e um para retorno.

A segunda é a maior taxa de transmissão, o que a primeira vista é inconsistente já que nummesmo ciclo de clock a comunicação paralela envia mais de um bit, enquanto a serial apenas um.Este fato acontece pois para frequências muito altas pode existir atraso entre um fio e outro se oscabos da comunicação paralela possuírem qualquer diferença. Além disso existe o problema docrosstalking, onde o campo magnético gerado por um cabo induz uma pequena tensão no outrocabo, atrapalhando a comunicação. Estes problemas aumentam com a frequência limitandoassim a máxima transferência possível pelo barramento paralelo. É este o motivo que levou osprojetistas de hardware a desenvolverem o protocolo SATA, em detrimento ao IDE/ATA, paracomunicação entre o HD e a placa mãe conforme pode ser 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 protocolo muito uti-lizado para comunicação entre dispositivos que transmitem ou recebem pouca quantidade deinformações. É um dos protocolos mais antigos sendo utilizado pela primeira vez em 1962 paramáquinas de escrever eletromecânicas. O padrão RS232 revisão C é datado de 1969. Em 1986aparece a revisão D pela EIA (Electronic Industries Alliance). A versão atual do protocolo édatada de 1997 pela TIA (Telecommunications Industry Association) sendo chamada TIA-232-F.

O procedimento de envio de um valor pela serial através do padrão RS232 pode ser vistocomo uma operação de bit-shift.

Por exemplo a letra K: em ASCII é codificada como 7610 e em binário como 110100102. Namaioria dos dispositivos primeiro se envia o bit menos significativo. Antes de iniciar a transmissãodos bits, é enviado um bit de começo, indicando que haverá transmissão a partir daquele instante.Após isso o bit menos significativo é enviado para a saída do microcontrolador. Realiza-se entãoum shift para direita e o “novo” bit menos significativo é “reenviado”. Esta operação é realizadaoito vezes. Após esse procedimento envia-se um bit de parada, que pode ter a duração de um oudois bits.

A Figura 4.16 apresenta o sinal elétrico7 enviado ao longo do tempo para a letra K. Notar aregião em branco, que se extende entre +3 e -3. Ela indica a região de tensão na qual o sinal não

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

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

Page 82: Livro Programando Microcontroladores PIC Linguagem C.pdf

75 Programação dos Periféricos

está definido. Caso a tensão lida esteja nestes limiares, seja devido à ruidos ou outros problemas,o sistema de 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 compatibilidade no nível físico(do hardware) e lógico (no software).

Para o hardware basta compatibilizar o tipo de conector, os níveis de tensão e a pinagem dosconectores.

Para o nível de software temos que definir a codificação utilizada (ASCII, UTF-8, etc),especificar o fluxo de caracteres (quantidade de bits por caractere, tamanho do start/stop bit,paridade) e a taxa de transmissão desejada.

Estas configurações são realizadas através de 5 registros TXSTA, RCSTA, BAUDCON, SP-BRGH e SPBRG.

Os registros TXSTA e RCSTA são responsáveis por configurar o meio de transmissão: pre-sença/ausência de bit de parada, tamanho da palavra de um caractere, transmissão síncrona/as-síncrona.

O registro BAUDCON é responsável por configurar o controle de velocidade de transmissão.Os registros SPBRGH e SPBRG representam o byte mais alto e o mais baixo 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.Como visto na Tabela 4.6 existem três formulas diferentes para calcular a taxa de transmissão.

A melhor maneira de configurar a taxa de transmissão da porta serial é verificar qual dos métodosgera o menor erro para uma dada taxa de transmissão.

Por exemplo, queremos uma taxa de transmissão de 57,6 kbps. A frequência disponível é umcristal de 8MHz. Usando as três formulas chegamos aos seguintes valores:

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

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

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

A equação que gera o menor erro é a terceira. Como queremos trabalhar com uma comuni-cação assíncrona, da Tabela 4.6 obtemos que os bits de configuração devem ser: TXSTA(4) = 0,

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

Page 83: Livro Programando Microcontroladores PIC Linguagem C.pdf

76 Programação dos Periféricos

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

Bits de Configuraçã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 8bitsF232 =

FOSC

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

0 1 1 16bitsF232 =

FOSC

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

1 1 x 16bits

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

BAUDCON(3) = 1 e TXSTA(2) = 1. A seguir temos todo o processo de configuração da portaserial 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 e c 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 e c 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ática pelo hardware. En-quanto ele está realizando este processo não devemos mexer no registro que armazena o byte aser enviado. Por isso devemos verificar se o registro está disponível. Isto é feito através do bit 4do registro PIR. Quando este valor estiver em 1 basta escrever o valor que desejamos transmitirno 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ático pelo hardware dodispositivo. Assim que um byte estiver disponível o sistema seta o bit 5 do registro PIR1 epodemos então ler o valor disponível no registro RCREG.

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{

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

Page 84: Livro Programando Microcontroladores PIC Linguagem C.pdf

77 Programação dos Periféricos

Programa 4.10: serial.c

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

4 void EnviaSerial (unsigned char c )5 {6 while ( ! BitTst ( PIR1 , 4 ) ) ; //aguarda o r e g i s t r o f i c a r d i s p 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 }

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

}

A metodologia apresentada para leitura e escrita de valores é conhecida como pooling. Nestetipo de abordagem ficamos parados esperando que o valor esteja disponível para leitura/escrita.Este é o método mais simples para se controlar qualquer tipo de dispositivo. O problema é queo processador fica travado em uma tarefa gastando tempo que seria útil para realizar outrasoperações. A melhor alternativa para resolver este problema é através de interrupções, que serãoabordadas apenas no tópico ..

Criação da biblioteca

O programa 4.10 apresenta um exemplo de código para criar uma biblioteca para comunicaçãoserial. O arquivo de header é apresentado no progrma 4.11 e o exemplo de uso demonstrado noprograma 4.12.

A seguir o arquivo de header.

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

Page 85: Livro Programando Microcontroladores PIC Linguagem C.pdf

78 Programação dos Periféricos

Programa 4.11: serial.h

1 #ifndef SERIAL_H2 #define SERIAL_H3 void EnviaSerial (unsigned char c ) ;4 unsigned char RecebeSerial (void ) ;5 void InicializaSerial (void ) ;6 #endif //SERIAL_H

Programa 4.12: Exemplo de uso da biblioteca de 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 86: Livro Programando Microcontroladores PIC Linguagem C.pdf

79 Programação dos Periféricos

. Conversor AD

Um conversor de analógico para digital é um circuito capaz de transformar um valor de tensãonuma informação binária. O circuito que utilizaremos possui uma precisão de 10 bits, ou seja,ele é capaz de sentir uma variação de praticamente um milésimo8 da excursão máxima do sinal.Para a configuração que iremos utilizar, com uma fonte de 5v, isto significa uma sensibilidadede 4.88mV.

Elementos sensores

A conversão AD é muito utilizada para realizarmos a leitura de sensores. Todo sensor é baseadonum transdutor. Um elemento transdutor é aquele que consegue transformar um tipo de grandezaem outro, por exemplo uma lâ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âmpadade 220V. Liga-se a lâmpada à uma tomada desconhecida. Se o brilho for forte a tomada possui220V, se o brilho for de baixa intensidade, a tomada possui 127V. Se a lâmpada não ascenderexiste algum problema na fiaçã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 seja uma variação detensão, corrente ou resistência.

Um sistema muito simples de transdutor de ângulo para resistência é o potenciômetro (Fi-gura 4.18).

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

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

VRL =VS ∗R2

R1 +R2= VS ∗ ( R2

RPot)

Se na construção do potenciômetro a variação da resistência ao longo da trilha foi feita de modoconstante, a resistência varia de maneira linear com a posição do cursor. Deste modo podemosutilizar o potenciômetro como um transdutor de ângulo.

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

Existem alguns sensores que possuem circuitos de amplificação e condicionamento do sinalembutidos no mesmo envólucro que o elemento sensor. A estes tipos de sensores damos a deno-minação de ativos.

8Com uma precisão de 10 bits conseguimos representar 21̂0 valores diferentes, ou 1024 valores.

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

Page 87: Livro Programando Microcontroladores PIC Linguagem C.pdf

80 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

Figura 4.20: Circuito integrado LM35

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

Page 88: Livro Programando Microcontroladores PIC Linguagem C.pdf

81 Programação dos Periféricos

Um sensor ativo possui no mínimo 3 terminais: 2 para alimentação e 1 para saída do sinal.Um exemplo deste tipo de sensor é o LM35 (Figura 4.20) que é utilizado para monitoramentode temperatura.

Na Figura 4.21 é apresentado o diagrama de blocos do circuito integrado do LM35. O diodoé utilizado como unidade sensora de temperatura.

Figura 4.21: Diagrama de blocos do LM35

Quando polarizado através de uma corrente constante, havendo mudança de temperatura atensão em cima do diodo muda. Os dois amplificadores e as respectivas realimentações estãoinseridas no circuito para amplificar e estabilizar as variações de tensão.

Processo de conversão AD

Existem alguns circuitos que realizam a conversão de um sinal analógico advindo de um trans-dutor para um sinal digital com uma precisão arbitrária.

A abordagem mais simples é a utilização de comparadores. Cada comparador possui umnível diferente de tensão de referência. Estes níveis são escolhidos de forma que a representaçãobinária faça sentido.

Exemplo: Conversão de um valor analógico que varia de zero à cinco volts numa palavradigital de dois bits.

Para N bits temos N2 representações diferentes. É interessante então dividir a amplitudeinicial por N2 divisões iguais. Para N = 2 temos 4 representaçõ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 visualizado na Figura 4.22.O circuito da Figura 4.22 é conhecido como conversor analógico digital do tipo flash onde

cada nível de tensão possui seu próprio comparador. Existem outras abordagens que minimizam

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

Page 89: Livro Programando Microcontroladores PIC Linguagem C.pdf

82 Programação dos Periféricos

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

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

Page 90: Livro Programando Microcontroladores PIC Linguagem C.pdf

83 Programação dos Periféricos

Programa 4.13: adc.c

1 #include "adc.h"2 #include "basico.h"3 void InicializaAD (void )4 {5 BitSet ( TRISA , 0 ) ; // s e t a o b i t 0 como 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 BitSet ( ADCON0 , 1 ) ; // 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 }

Programa 4.14: adc.h

1 #ifndef ADC_H2 #define ADC_H3 void InicializaAD (void ) ;4 int LeValorAD (void ) ;5 #endif //ADC_H

o uso de conversores (parte mais cara do circuito) mas inserem atraso no processo de conversão.O atraso depende do tipo de circuito que é implementado.

Criação da biblioteca

Toda conversão leva um determinado tempo que, conforme citado na seção anterior, dependeda arquitetura que estamos utilizando, da qualidade do conversor e, algumas vezes, do valor detensão que queremos converter. Para que o microcontrolador realize corretamente a conversão énecessário seguir os seguintes passos:

1. Configurar o conversor

2. Iniciar a conversão

3. Monitorar o final da conversão

4. Ler o valor

Os programas 4.13 e 4.14 apresentam os arquivos de código e header de uma bibliotecaexemplo para conversores analógicos para digital no microcontrolador PIC. O programa 4.15apresenta um código exemplificando o uso da biblioteca criada.

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

Page 91: Livro Programando Microcontroladores PIC Linguagem C.pdf

84 Programação dos Periféricos

Programa 4.15: Exemplo de uso da biblioteca de conversores AD

1 #include "basico.h"2 #include "config.h"3 #include "disp7seg.h"4 #include "adc.h"5 // i n i c i o do 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 92: Livro Programando Microcontroladores PIC Linguagem C.pdf

85 Programação dos Periféricos

. Saídas PWM

As saídas PWM são saídas digitais que possuem um chaveamento acoplado. O sinal muda seuestado de positivo para zero várias vezes por segundo. A porcentagem do tempo que este sinalpermanece em nível Alto define o ciclo de trabalho, ou duty cycle, da saída. A Figura 4.23apresenta 3 sinais PWM com 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 estiver em nível alto existea passagem de corrente elétrica e a resistência aquece. Quando estiver em nível baixo a correntepara. Como a constante térmica do componente é alta, leva-se alguns segundos para que oresistor aqueça ou esfrie, é possível ajustar a quantidade de energia média com uma frequênciade sinal PWM suficientemente alta.

Em outras palavras, se a frequência do PWM for mais alta do que a carga conseguir enxergar,quando colocarmos o duty cycle em 50%, a carga irá receber 50% da energia total. Se for umresistor, podemos controlar a temperatura final deste modo, num motor podemos ajustar avelocidade de rotação que queremos.

Como citado a frequência do PWM tem que ser suficientemente alta. Esta frequência dependedo circuito implementado no microcontrolador. No caso do PIC18f4550 é calculada segundo aformula abaixo.

FrequenciaPWM =FOSC

[(PR2 ) + 1] ∗ 4 ∗ (TMR2Prescaler )

Com uma frequência de oscilação de 8MHz (disponível na placa) podemos atingir frequênciasque variam de 488Hz até 2MHz.

O problema de trabalhar, no caso do PIC, com frequências muito altas é que perdemosresolução na definição do duty cycle. Por exemplo, para a frequência de PWM em 2MHz comum clock de 8MHz temos uma resolução de apenas 2 bits. Ou seja, podemos configurar a saídapara 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 oscilador principal de 8 MHza frequência máxima do PWM para utilizarmos os 10 bits de resolução é 7812,5 Hz. Para umaresolução de 8 bits a frequência máxima aumenta para 31.25 kHz.

Utilizando a primeira e segunda formulas podemos montar a Tabela 4.7.O duty cycle (em porcentagem) é calculado de acordo com a fórmula abaixo:

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

Page 93: Livro Programando Microcontroladores PIC Linguagem C.pdf

86 Programação dos Periféricos

Tabela 4.7: Faixa de frequências máximas e mínimas para cada configuração do 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

DutyCyclePWM =[CCPRxL : CCPxCON (5 : 4)]

(PR2 + 1) ∗ 4

Criação da biblioteca

Para configurar as saídas PWM devemos especificar a frequência de trabalho através de PR2e TCON2, além do duty cycle em CCPR1L e CCPR2L. No registro TRISC é configurado oterminal como uma saída e em CCP1CON e CCP2CON definimos que ele deve trabalhar comoum PWM. O prescaler foi configurado para 16 bits de modo a obter a maior faixa de frequênciaaudível disponível (Tabela 4.7). Notar que é importante realizar primeiro a multiplicação esomente depois a divisão, para não haver perda de informação. No programa 4.16 é apresentadoum código exemplo de como criar as rotinas de operação do PWM. O header desta bibliotecaé apresentado no programa 4.17. Por fim, o programa 4.18 apresenta um exemplo de utilizaçãodesta biblioteca.

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

Page 94: Livro Programando Microcontroladores PIC Linguagem C.pdf

87 Programação dos Periféricos

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

Programa 4.17: pwm.h

1 #ifndef PWM_H2 #define PWM_H3 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

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

Page 95: Livro Programando Microcontroladores PIC Linguagem C.pdf

88 Programação dos Periféricos

Programa 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 96: Livro Programando Microcontroladores PIC Linguagem C.pdf

89 Programação dos Periféricos

Programa 4.19: timer.c

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

12 //tempo em micro 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 pr e s c a l e r28 BitSet ( T0CON , 7 ) ; // l i g a o t imer 029 }

. Timer

Nos microcontroladores existem estruturas próprias para realizar a contagem de tempo, estasestruturas são denominadas Timers.

O PIC18f4550 possui quatro timers. Para utilizarmos a saída PWM temos que configurar otimer 2, que gera a base de tempo que sera comparada com o duty cycle.

Ao invés de contarmos quantas instruções são necessárias para criar um delay de um deter-minado tempo, podemos utilizar os timers. Escolhemos o valor de tempo que queremos contar,inicializamos as variáveis e esperamos acontecer um “overflow”9 na contagem do timer.

Para trabalhar com o timer precisamos basicamente de uma função de inicialização, uma pararesetar o timer e outra para indicar se o tempo configurado anteriormente já passou. Uma quartafunção “AguardaTimer()”, foi construída para facilitar o desenvolvimento de algumas rotinascomuns nos programas. Estas rotintas estão implementadas no programa 4.19 cujo header éapresentado no programa 4.20. O modo de utilizar esta biblioteca é apresentado no programa4.21.

9Overflow é conhecido como estouro de variável. Toda variável digital possui um valor máximo, por exemplo255 para uma variável do tipo unsigned char. Se uma variável unsigned char possui o valor 255 e é acrescida de1, seu valor passa a ser zero e acontece o estouro ou overflow.

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

Page 97: Livro Programando Microcontroladores PIC Linguagem C.pdf

90 Programação dos Periféricos

Programa 4.20: timer.h

1 #ifndef TIMER_H2 #define TIMER_H3 char FimTimer (void ) ;4 void AguardaTimer (void ) ;5 //tempo em micro segundos6 void ResetaTimer (unsigned int tempo ) ;7 void InicializaTimer (void ) ;8 #endif //TIMER_H

Programa 4.21: Exemplo de uso da biblioteca de um temporizador

1 // i n i c i o do 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 98: Livro Programando Microcontroladores PIC Linguagem C.pdf

91 Programação dos Periféricos

. Reprodução de Sons

Se ligarmos à saída PWM um auto-falante é possível reproduzir sons. Conhecendo a frequênciade cada uma das notas musicais e a duração destas é possível reproduzir uma música. Parareproduzir o tempo com uma precisão melhor podemos utilizar o TIMER0 como unidade detempo.

Conforme visto na seção ., o PWM utilizado na placa consegue reproduzir as frequênciasaudíveis a partir de 488,3Hz. Por isso escolhemos começar a escala musical a partir do C5 (DóTenor) que possui a frequência de 523. A segunda escala possui o dobro da frequência (umaoitava acima). Para reproduzir a ausência de som escolhemos a frequência de 125.000 Hz10, queé inaudível. Isto simplifica o programa.

Programa 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 musicais12 #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 }

10Esta é 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 99: Livro Programando Microcontroladores PIC Linguagem C.pdf

92 Programação dos Periféricos

. Interrupção

Até o momento todos os programas que foram desenvolvidos seguiam um fluxo sequencial sendoalterado apenas por chamadas de funções, estruturas de decisão ou loop. Um dos problemas dese utilizar este tipo de estrutura é que alguns periféricos possuem um tempo muito grande pararealizarem sua função como o conversor AD por exemplo. Nesta situação o que fazemos é iniciara conversão e ficar monitorando uma variável que indicava quando a conversão tinha terminado.Esta técnica é conhecida como pooling.

O problema de se realizar a leitura de algum periférico por pooling é que o processador perdetempo realizando operações desnecessárias checando a variável de controle. Uma alternativa éutilizar um sistema que, quando a operação desejada estivesse finalizada, nos avisasse para quepudéssemos tomar uma providência. Este procedimento é chamado de interrupção.

Alguns dispositivos possuem a possibilidade de operarem com interrupções. Quando a con-dição do dispositivo for satisfeita (fim da conversão para o AD, chegada de informação na serial,mudança no valor da variável na porta B) ele gera uma interrupção. A interrupção para oprograma no ponto em que ele estiver, salva todos os dados atuais e vai para uma função pré-definida. Esta função realiza seu trabalho e assim que terminar volta o programa no mesmoponto 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 o buffer de transmissãoTXREG estiver disponível.

• Conversor AD: quando o resultado da conversão estiver disponível para leitura.

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

• Timer 0: quando acontece overflow em seu contador

Para gerenciar a interrupção devemos criar uma rotina que irá verificar o tipo de interrupçãoque ocorreu e tomara as providências necessárias. A maneira de declarar que uma função seráresponsável pelo tratamento das interrupções depende do compilador.

Para o compilador SDCC basta que coloquemos a expressão “interrupt 1” após o nome dafunção.

void NomeDaFuncao (void ) interrupt 1{

// código . . .}

Para o compilador C18 da Microchip temos que gerar um código em assembler 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 nenhum valor.

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

Page 100: Livro Programando Microcontroladores PIC Linguagem C.pdf

93 Programação dos Periféricos

Programa 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 ) ) { /∗ código ∗/ } //Flag de ove r f l ow do TIMER15 i f ( BitTst ( PIR1 , 1 ) ) { /∗ código ∗/ } //Flag de comparação do TIMER2 com PR26 i f ( BitTst ( PIR1 , 2 ) ) { /∗ código ∗/ } //Flag de comparação do CCP17 i f ( BitTst ( PIR1 , 3 ) ) { /∗ código ∗/ } //Flag de fim de operação na porta ←↩

pa r a l e l a8 i f ( BitTst ( PIR1 , 4 ) ) { /∗ código ∗/ } //Flag de fim de transmissão da S e r i a l9 i f ( BitTst ( PIR1 , 5 ) ) { /∗ código ∗/ } //Flag de recepção da S e r i a l

10 i f ( BitTst ( PIR1 , 6 ) ) { /∗ código ∗/ } //Flag de fim de conversão do AD11 i f ( BitTst ( PIR1 , 7 ) ) { /∗ código ∗/ } //Flag de l e i t u r a / e s c r i t a da porta ←↩

pa r a l e l a12 i f ( BitTst ( PIR2 , 0 ) ) { /∗ código ∗/ } //Flag de comparação do CCP213 i f ( BitTst ( PIR2 , 1 ) ) { /∗ código ∗/ } //Flag de ove r f l ow do TIMER314 i f ( BitTst ( PIR2 , 2 ) ) { /∗ código ∗/ } //Flag de condição de Tensão Alta /Baixa15 i f ( BitTst ( PIR2 , 3 ) ) { /∗ código ∗/ } //Flag de de tecção de c o l i s ã o no ←↩

barramento16 i f ( BitTst ( PIR2 , 4 ) ) { /∗ código ∗/ } //Flag de fim e s c r i t a na memoria f l a s h17 i f ( BitTst ( PIR2 , 5 ) ) { /∗ código ∗/ } //Flag de in t e r rupção da USB18 i f ( BitTst ( PIR2 , 6 ) ) { /∗ código ∗/ } //Flag de mudança na entrada de ←↩

comparação19 i f ( BitTst ( PIR2 , 7 ) ) { /∗ código ∗/ } //Flag de f a l h a no o s c i l a d o r20 i f ( BitTst ( INTCON , 0 ) ) { /∗ código ∗/ } //Flag de mudança na PORTA B21 i f ( BitTst ( INTCON , 1 ) ) { /∗ código ∗/ } //Flag de in t e r rupção ex terna INT022 i f ( BitTst ( INTCON , 2 ) ) { /∗ código ∗/ } //Flag de ove r f l ow no TIMER023 i f ( BitTst ( INTCON3 , 0 ) ) { /∗ código ∗/ } //Flag de in t e r rupção ex terna INT124 i f ( BitTst ( INTCON3 , 1 ) ) { /∗ código ∗/ } //Flag de in t e r rupção ex terna INT225 }

Existe uma correlação entre o número que vem depois da expressão “interrupt” para o com-pilador SDCC e o número ao final da expressão “#pragma code high_vector” para o C18. Estesnúmeros representam a posição para a qual o microcontrolador vai quando acontece uma inter-rupçã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 importantes: 0x00(0),0x08(1) e 0x18(2). O compilador C18 usa a posição física e o SDCC o número entre parênteses.

A posição 0 (0x00) representa o endereço que o microcontrolador busca quando este acabade ser ligado. É a posição de reset. Geralmente saímos deste vetor e vamos direto para a funçãomain().

As posições 1 e 2 (0x08,0x18) são reservadas para as interrupções de alta e baixa prioridade,respectivamente. É necessário que o programador escolha quais dispositivos são de alta e quais sãode baixa prioridade. Existe ainda um modo de compatibilidade com os microcontroladores maisantigos no qual todos os periféricos são mapeados na primeira interrupção (0x08). Utilizaremoseste modo por questão de facilidade.

Como todos os periféricos estão mapeados na mesma interrupção, a função deve ser capaz dediferenciar entre as diversas fontes de requisição. Uma maneira de se realizar esta verificação éatravés das flags 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 fontes possíveis de interrupçãopara o PIC18f4550.

Em geral não é necessário tratar todas as interrupções, apenas aquelas que influenciarãoo sistema. O programa 4.24 apresenta um exemplo de uma função que trata as interrupçõesadvindas da porta B, do timer 0, da serial e do AD.

Para que a função apresentada no programa 4.24 funcione corretamente devemos inicializaras interrupções de modo adequado, conforme apresentado no programa 4.25.

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

Page 101: Livro Programando Microcontroladores PIC Linguagem C.pdf

94 Programação dos Periféricos

Programa 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 do

10 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 l r (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 102: Livro Programando Microcontroladores PIC Linguagem C.pdf

95 Programação dos Periféricos

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

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

Page 103: Livro Programando Microcontroladores PIC Linguagem C.pdf

96 Programação dos Periféricos

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

. Watchdog

Por algum motivo o software pode travar em algum ponto, seja por um loop infinito ou poresperar a resposta de algum componente através de pooling de uma variável.

A primeira condição pode ser evitada através de um projeto cuidadoso de software aliado auma boa validação. Já a segunda exige que os hardwares adjacentes funcionem corretamente.Se algum hardware apresenta uma falha e não envia a resposta que o microcontrolador estáesperando, este último irá travar. Nestas situações é possível utilizar o watchdog.

O watchdog é um sistema que visa aumentar a segurança do projeto. Ele funciona comoum temporizador que precisa constantemente ser reiniciado. Caso não seja reiniciado no tempoexigido, o watchdog reinicia o microcontrolador dando a possibilidade de sair de um loop infinitoou de um pooling sem resposta.

Para habilitar o watchdog é necessário alterar os registros de configuração, especificamenteo CONFIG2H (0x300002). Outro método consiste em deixar o watchdog desligado no registro eligá-lo através de software, como é apresentado no programa 4.26.

Notar o #define criado na primeira linha do programa 4.26. A expressão CLRWDT é ocomando em assembler responsável por resetar o watchdog. As diretivas _asm e _endasminformam ao compilador que os comandos utilizados devem ser transcritos exatamente iguaispara o arquivo assembler a ser gerado.

Se após ligar o watchdog não realizarmos a operação de reset dele, comentando ou excluindo afunção CLRWTD(), o sistema irá travar tão logo o tempo associado ao watchdog tenha expiradopela primeira vez, reiniciando o sistema. Como apenas reiniciar não soluciona o problema, pois oprograma criado não terá função para reiniciar o watchdog, o sistema continua sendo reiniciadoindefinidamente.

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

Page 104: Livro Programando Microcontroladores PIC Linguagem C.pdf

Capítulo 5

Arquitetura de desenvolvimento desoftware

“Constrained by memory limitations, performance requirements, andphysical and cost considerations, each embedded system design re-quires a middleware platform tailored precisely to its needs, unusedfeatures occupy precious memory space, while missing capabilitiesmust be tacked on.” - Dr. Richard Soley

No desenvolvimento de um sistema de maior porte, é importante definir o tipo de arquiteturaque iremos utilizar. Neste capítulo apresentamos três abordagens possíveis. A escolha deve serbaseada no tipo de dispositivo a ser desenvolvido, na complexidade do sistema, na possibilidadede gerar subprodutos e dos requisitos de tempo.

97

Page 105: Livro Programando Microcontroladores PIC Linguagem C.pdf

98 Arquitetura de desenvolvimento de software

Programa 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 s

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

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

. One single loop

“1 Infinite Loop, Cupertino, CA 95014.” - Endereço da Apple

Esta é a estratégia utilizada até agora nos exemplos apresentados. Dentro da função principal écolocado um loop infinito. Todas as tarefas são chamadas através de funções.

A vantagem de se utilizar esta abordagem é a facilidade de se iniciar um projeto. Parasistemas maiores começa a ficar complicado coordenar as tarefas e garantir a execução numtempo determinístico. Outro problema é a modificação/ampliação do software. Geralmente ainserção de uma função no meio do loop pode gerar erros em outras funções devido a restriçõesde tempo dos periféricos associados.

No exemplo acima, a inserção da comunicação serial e os cálculos podem atrapalhar a escritano display de sete segmentos, gerando flicker.

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

Page 106: Livro Programando Microcontroladores PIC Linguagem C.pdf

99 Arquitetura de desenvolvimento de software

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

. Interrupt control system

Uma parte dos desenvolvedores de sistemas embarcados, que possuem restrições de tempo deatendimento mais rigorosos, optam por garantir estas restrições através de interrupções.

Na maioria dos sistemas microcontroladores, as interrupções são atendidas num tempo muitocurto, cerca de alguns ciclos de instrução, o que para a maioria dos sistemas é suficiente. Deve-se,entretanto, tomar cuidado com a quantidade de periféricos que geram interrupções e a prioridadedada a cada um deles.

Outra abordagem muito utilizada é a geração de uma interrupção com tempo fixo, por exem-plo a cada 5ms.

A grande vantagem da abordagem citada é que a inserção de mais código dentro do loopprincipal não atrapalha a velocidade com que o display é atualizado, que está fixo em 5(ms).

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

Page 107: Livro Programando Microcontroladores PIC Linguagem C.pdf

100 Arquitetura de desenvolvimento de software

Programa 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 ResetaTimer (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 108: Livro Programando Microcontroladores PIC Linguagem C.pdf

101 Arquitetura de desenvolvimento de software

. Cooperative multitasking

Em computação, multitarefa ou multitasking é um processo pelo qual diferentes tarefas compar-tilham um mesmo recurso, seja ele memória, processamento ou qualquer periférico disponível.

Uma maneira de realizar este compartilhamento é através de uma divisão do tempo: a tarefaA possui um intervalo ao final do qual deve ceder os recursos para a tarefa B. Quando a mudançade tarefa é feita pela própria tarefa, o sistema é dito cooperativo. Quando existe um sistemaexterno que realiza 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 simultaneamente. Uma das maneiras de seobter este tipo de operação é através da criação de uma máquina de estados, como mostrado naFigura 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, como na abordagem one-single-loop. Outra peculiaridade é que algumas tarefas podem ser executadas mais de uma vezpara garantir as restrições de tempo. No exemplo a tarefa de atualização dos displays é executadatrês vezes.

A transposição de uma máquina de estado para o código em C é realizada através de umswitch-case.

É possível retirar todas as atribuições para a variável slot e colocar no “slot-bottom” a ex-pressão slot++. A abordagem apresentada foi escolhida por aumentar a robustez do sistema, jáque a variável slot controla todo o fluxo do programa.

A inserção de uma nova tarefa é realizada de maneira simples, basta adicionar um outro slot,ou seja, basta inserir um case/break com a tarefa desejada.

Como a máquina está dentro do loop infinito, a cada vez que o programa passar pelo case,ele executará apenas um slot. Esta abordagem gera ainda um outro efeito. Como pode ser vistono código, naturalmente surgem duas regiões: “top-slot” e “bottom-slot”. Se algum código forcolocado nesta região ele será executado toda vez, de modo intercalado, entre os slots. PelaFigura 5.1, percebemos que é exatamente este o comportamento que queremos para a funçãoAtualizaDisplay(). Deste modo, podemos remodelar o código fazendo esta alteração.

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

Page 109: Livro Programando Microcontroladores PIC Linguagem C.pdf

102 Arquitetura de desenvolvimento de software

Programa 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 110: Livro Programando Microcontroladores PIC Linguagem C.pdf

103 Arquitetura de desenvolvimento de software

Programa 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 111: Livro Programando Microcontroladores PIC Linguagem C.pdf

104 Arquitetura de desenvolvimento de software

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

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 }

Fixação de tempo para execução dos slots

Do modo apresentado até agora, assim que uma função termina, o sistema automaticamentepassa para a próxima tarefa. Uma característica desejada é que estas funções possuam umtempo determinado para funcionar. Deste modo, todo o sistema se torna mais previsível.

A maneira mais simples de realizar este procedimento é criar uma rotina de tempo. Toda vezque um slot terminar, o sistema ficará aguardando o tempo escolhido para reiniciar o sistema.

No exemplo apresentado é inserida a função AguardaTimer() no bottom-slot de modo que apróxima função só executará quando passar os 5 (ms).

Como este é um modo simples de implementar um sistema multitarefa podemos notar quese a função ultrapassar 5 (ms) todo o cronograma será afetado. É necessário então garantir quetodo e cada slot será executado em menos de 5 (ms). Isto deve ser feito através de testes debancada.

Na Figura 5.2 está um exemplo de como um sistema com 3 slots se comporta ao longo do

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

Page 112: Livro Programando Microcontroladores PIC Linguagem C.pdf

105 Arquitetura de desenvolvimento de software

tempo. Notar que o slot 1 (S.1) gasta um tempo de 2.0(ms), o slot 2 de 3.1 (ms) e o slot 3 apenas1.2 (ms). Já o top-slot consome 0.5 (ms) e o bottom-slot 0.3 (ms).

Top

S.1

S.2

S.3

Bottom

"vago"

0 5 10 15 20 25 30

Figura 5.2: Exemplo da mudança de slots no tempo

Podemos notar que para o ciclo do primeiro slot são gastos 0.5+2.0+0.3 = 2.8(ms). Destemodo o sistema fica “aguardando” na função AguardaTimer() durante 2.2 (ms) sem realizarnenhum processamento útil. Para o segundo slot temos um tempo "livre"de 5-(0.5+3.1+0.3)=1.1(ms). O terceiro slot é o que menos consome tempo de processamento, possuindo um tempo livrede 5-(0.5+1.2+0.3)=3.0 (ms).

Utilização do “tempo livre” para interrupções

Conforme visto anteriormente, dependendo do tempo escolhido para o slot e do “tamanho” dafunção, podem existir espaços vagos na linha de tempo do processador. A Figura 5.3 apresentauma linha de tempo de um sistema que possui apenas 1 slot. Já a Figura 5.4 demonstra o mesmosistema sendo interrompido 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

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

Page 113: Livro Programando Microcontroladores PIC Linguagem C.pdf

106 Arquitetura de desenvolvimento de software

Cada interrupção gasta um tempo de 1 (ms) conforme pode ser visto na Figura 5.4. Comotemos um tempo “vago” de 3 (ms) em cada ciclo basta garantir que os eventos que geram ainterrupção não ultrapassem a frequência de 3 eventos a cada 8 (ms).

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

Page 114: Livro Programando Microcontroladores PIC Linguagem C.pdf

Capítulo 6

Anexos

107

Page 115: Livro Programando Microcontroladores PIC Linguagem C.pdf

108 Anexos

Programa 6.1: config.h

1 //para o compi lador SDCC + GPUtils2 #ifndef CONFIG_H3 #define CONFIG_H4 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 baixa 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 cont 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

. config.h

O arquivo config.h possui as diretivas de compilação para configuração do microcontrolador.

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

Page 116: Livro Programando Microcontroladores PIC Linguagem C.pdf

109 Anexos

Programa 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 // de 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)

. basico.h

O header basico.h possui o endereço de todos os registros do microcontrolador PIC18f4550 que éutilizado nesta apostila. Além disso contém alguns define’s importantes como as funções inlinepara limpar a flag de watchdog e para manipulação de bits.

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

Page 117: Livro Programando Microcontroladores PIC Linguagem C.pdf

110 Anexos

. Instalar gravadores/depuradores de PIC em sistemas x64

Os passos a seguir devem ser seguidos para instalar os device drivers corretamente em sistemasoperacionais de 64 bits. Atualmente apenas os seguintes aparelhos 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 a instalação do Driver.

Se você já plugou o dispositivo e apareceu a informação "Novo hardware encontrado", cliqueem cancelar. Desligue o dispositivo e continue com os passos a seguir.

Se você já utilizou o setup do windows você instalou os drivers errados. Siga as instruçõesde remoção dos drivers antes de prosseguir.

Passo 1Conecte o dispositivo ao PC usando o cabo USB. Para os dispositivos que exigem alimentaçãoexterna, ligue-a. Se estiver usando um hub USB, tenha certeza que o este possui energia sufici-ente para alimentar o dispositivo.

Passo 2A primeira vez que o dispositivo é conectado aparece uma mensagem indicando que o sistemaencontrou um novo hardware. Quando aparecer uma janela, escolha a opção “Localizar e insta-lar o driver (recomendado)” Nota: Se aparecer uma mensagem perguntando sobre permissão noWindows 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, procure em “C:\Arquivosde programa (x86)\Microchip\MPLAB IDE\Drivers64”. Clique em continuar

Passo 5A próxima tela irá perguntar se você quer continuar a instalar o dispositivo. Clique em Instalarpara continuar.

Passo 6A próxima tela indicará que o software foi instalado corretamente. Clique em fechar para termi-nar a instalação.

Passo 7Verificar se o driver está instalado e visivel no Gerenciador de dispositivos em “Custom USBDrivers>Microchip Custom USB Driver” Abra a janela do gerenciador de dispositivos (Iniciar->Painel de controle->Sistema->Gerenciador de dispositivos). Se o driver não fora instaladocorretamente, continue na seção de solução de erros (a seguir)

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

Page 118: Livro Programando Microcontroladores PIC Linguagem C.pdf

111 Anexos

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 arquivo correto. No gerenci-ador de dispositivos dentro da opção “Outros dispositivos” você deve encontrar um “Dispositivonão conhecido”.

Clique com o botão direito no “Dispositivo não conhecido” e selecione a opção “Atualizar oDriver” do menu.

Na primeira tela de diálogo selecione “Procurar no meu computador pelos arquivos do driver”.Continuar a partir do passo 4.

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