apostila de sistemas embarcados

63
Última Atualização 23/07/2011 LASEC FEELT APOSTILA DE SISTEMAS EMBARCADOS 1 UNIVERSIDADE FEDERAL DE UBERLÂNDIA FACULDADE DE ENGENHARIA ELÉTRICA FEELT

Upload: lucasmqs

Post on 02-Aug-2015

737 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Apostila de Sistemas Embarcados

 

 

  

 

 

 

 

 

 

 

Última Atualização 23/07/2011

LASEC FEELT 

APOSTILA DE SISTEMAS EMBARCADOS 1 

 

UNIVERSIDADE FEDERAL DE UBERLÂNDIA FACULDADE DE ENGENHARIA ELÉTRICA ‐ FEELT 

 

Page 2: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página2 

ESCLARECIMENTOS

Esta apostila foi criada para servir de roteiro para as aulas da Disciplina de Sistemas Embarcados, oferecida pela Faculdade de Engenharia Elétrica da Universidade Federal de Uberlândia. Este material deve ser utilizado em conjunto com os tutoriais “Como Criar um Projeto em C para ARM” e “Gravando e Debugando o Microcontrolador ARM”.

Todos os arquivos dos programas na Linguagem C, utilizados nos exemplos de sala de aula, podem ser encontrados nas subpastas da pasta Aulas, que foi criada durante a descompactação do arquivo Aulas.zip, disponível para download no site: www.lasec.feelt.ufu.br

Sumário ESCLARECIMENTOS ....................................................................................................................... 2 

Introdução ..................................................................................................................................... 4 

Microcontrolador ARM ................................................................................................................. 7 

Softwares para Programar ARM ................................................................................................. 10 

LED_Blink ..................................................................................................................................... 11 

Exercício Proposto ................................................................................................................... 11 

Programa LED_Blink Comentado ............................................................................................ 13 

Configurando o Clock da CPU ...................................................................................................... 15 

Operadores Lógicos Bit a Bit ....................................................................................................... 16 

Display de 7 Segmentos .............................................................................................................. 18 

Exercício Proposto ................................................................................................................... 19 

Números mágicos em programação ........................................................................................... 21 

Portabilidade e o Pré‐processador C ........................................................................................... 28 

Tipos Primitivos em C .................................................................................................................. 30 

Exercício Proposto ................................................................................................................... 36 

Teclado Matricial ......................................................................................................................... 37 

Exercício Proposto ................................................................................................................... 39 

Display de Cristal Líquido ............................................................................................................ 40 

Exercício Proposto ................................................................................................................... 43 

Interface de Comunicação SPI ..................................................................................................... 44 

Operações “ATOMIC” .................................................................................................................. 45 

“STRUCTURE PADDING”  E  SERIALIZAÇÃO” ............................................................................... 50 

Referências .................................................................................................................................. 61 

Page 3: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página3 

Edição e Revisão: ..................................................................................................................... 62 

Agradecimentos ...................................................................................................................... 62 

 

Page 4: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página4 

Introdução

Na década de 30 e 40 os primeiros computadores possuíam tarefas específicas. O Atanasoft-Berry Computer, o ABC, mostrado na Figura 01, foi o primeiro computador a usar eletricidade, inventado por John Vincent Atanasoff e Clifford Berry em 1939. O computador tinha válvulas eletrônicas, números binários, capacitores e 1 quilômetro de fios.

Figura 1- Primeiro computador a usar eletricidade, inventado por John Vincent Atanasoff e Clifford Berry em 1939.

O primeiro sistema embarcado reconhecido foi o Apollo Guidance Computer (AGC), desenvolvido por Charles Stark Draper no MIT, na década de 60. O AGC, mostrado na Figura 01, realizava o processamento de dados e o controle em tempo real do sistema de orientação e navegação do Módulo de Comando e do Módulo Lunar da espaçonave desenvolvida no Programa Apolo.  

Interface do AGC AGC montado no painel de controle da Apollo

Figura 2 - Apollo Guidance Computer, considerado o primeiro sistema embarcado moderno.

Page 5: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página5 

O primeiro sistema embarcado de produção em massa foi o computador guia do míssil nuclear LGM-30 Míssil Minuteman, lançado em 1961. Ele possuía um disco rígido para a memória principal. Quando a segunda versão do míssil entrou em produção em 1966, o computador guia foi substituído por um novo, que constituiu o primeiro uso em larga escala de circuitos integrados.

A tecnologia desse projeto reduziu o preço de circuitos integrados como a porta lógica NAND de mil para três dólares americanos cada, permitindo seu uso em sistemas comerciais. 

“A coisa mais indispensável a um homem é reconhecer o uso que deve fazer do seu próprio conhecimento.” – Platão (428 a 348 a.C)

Um dos primeiros minuteman Figura 3 - O LGM-30 Minuteman é um projeto de míssil balístico intercontinental (ICBM)

nuclear dos Estados Unidos.

Desde suas primeiras aplicações na década de 1960, os sistemas embarcados vêm reduzindo seu preço. Também tem havido um aumento no poder de processamento e funcionalidade. Em 1978 foi lançada pela National Engineering Manufacturers Association a norma para microcontroladores programáveis.

Em meados da década de 1980, vários componentes externos foram integrados no mesmo chip do processador, o que resultou em circuitos integrados chamados microcontroladores e na difusão dos sistemas embarcados.

Com o custo de microcontroladores menor que um dólar americano, tornou-se viável substituir componentes analógicos caros como potenciômetros e capacitores por eletrônica digital controlada por pequenos microcontroladores. No final da década de 1980, os sistemas embarcados já eram a norma ao invés da exceção em dispositivos eletrônicos (URL 1).

Page 6: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página6 

Um sistema embarcado (ou sistema embutido) é um sistema no qual o circuito que processa os dados é dedicado ao dispositivo ou sistema que ele controla. Diferente de computadores de propósito geral, como o computador pessoal, um sistema embarcado realiza um conjunto de tarefas predefinidas, geralmente com requisitos específicos. Já que o sistema é dedicado a tarefas específicas pode-se otimizar o projeto reduzindo-se tamanho, recursos computacionais e custo do produto.

Em geral os sistemas embarcados possuem uma capacidade de processamento reduzida em comparação com computadores desktops. Ao invés de utilizar microprocessadores, os desenvolvedores preferem utilizar microcontroladores, pois estes já possuem diversos periféricos integrados no mesmo chip.

Outra diferença é a variedade de arquiteturas disponíveis tais como ARM, MIPS, Coldfire/68k, PowerPC, x86, PIC, 8051, Atmel AVR, Renesas H8, SH, V850, FR-V, M32R, Z80 e Z8. Isso contrasta com o mercado de computadores pessoais, limitados à somente algumas arquiteturas.

A área de sistemas embarcados é uma das áreas com crescimento mais dinâmico e rápido no setor industrial. Sistemas embarcados são aplicados em diversas áreas como automotiva/transporte, governo/militar, equipamentos hospitalares, telecomunicações, aeronáutica, aeroespacial, eletrodomésticos, automação residencial, automação industrial, automação agrícola, automação de indústrias petroquímicas. Estima-se que as casas nos Estados Unidos da América possuem em média de 30 a 40 aparelhos que utilizam dispositivos dedicados e que aproximadamente 98% de todos os microprocessadores em uso no mundo são usados em sistemas embarcados.

A programação de sistemas embarcados já vem ocorrendo a mais de trinta anos, porém, devido o crescimento da capacidade computacional e o aumento da complexidade dos circuitos dedicados, as disciplinas que tratam da programação desses circuitos no meio acadêmico é um assunto relativamente novo. Além disso, disciplinas relacionadas a esse assunto são consideradas interdisciplinares, pois combinam áreas como ciência da computação, engenharia elétrica, matemática aplicada e teoria de controle.

Com o tremendo crescimento na computação embarcada aumentou-se a demanda de engenheiros e cientistas da computação, contudo, a maioria dos programas acadêmicos desenvolvem habilidades de programação e projeto de hardware para computação de propósito geral que operam sobre aplicações comerciais e, portanto, não desenvolvem habilidades que são adequadas a programação e desenvolvimento de hardware para sistemas embarcados. O resultado disso é que as indústrias, nos Estados Unidos, por exemplo, estão tendo dificuldade em encontrar profissionais com habilidades adequadas para trabalhar com esses sistemas, o que compromete o desenvolvimento de

Page 7: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página7 

indústrias de base tecnológica. Isso ocorre porque uma empresa de base tecnológica está fundamentada em seu capital humano e social.

Os países europeus desenvolveram uma comunidade científica chamada ARTIST. O objetivo do Grupo de Excelência ARTIST é fortificar as pesquisas de sistemas embarcados na Europa e promover o desenvolvimento desta nova área multidisciplinar. A ambição desta organização é a produção e transferência de conhecimento que promovam a inovação industrial (URL 2). Para atingir esta meta, o Grupo ARTIST já desenvolveu diretrizes curriculares de graduação em sistemas embarcados.

No Japão e em muitos outros países orientais disciplinas sobre sistemas embarcados são oferecidas nos cursos de Ciência da Computação e de Engenharia. A maior parte das universidades da China oferece curso de graduação em engenharia de software embarcada. Na Coréia 19 universidades possuem curso de programação de sistemas dedicados.

Várias universidades no Brasil oferecem disciplinas intituladas Computação Móveis ou Sistemas Móveis que utilizam J2ME, porém, este ambiente (máquina virtual e subconjunto do sistema JAVA) está disponível apenas em PDAs, smart phones, algumas IHMs e outros dispositivos com maiores recursos de memória no hardware. A implementação J2ME CLDC mais limitada requer de 160KB a 512KB de ROM apenas para a VM e as bibliotecas, além de 192KB de RAM sem considerar qualquer subsistema de apoio (URL 3, URL 4). Do ponto de vista comercial existe ainda o custo de licença relacionado a uma implementação J2ME.

Os sistemas embarcados tratados nesta apostila possuem limitações muito maiores no hardware como memória reduzida (de 1KB a 64KB de RAM), baixíssimo consumo, alta integração e capacidade limitada de processamento. São em sua grande maioria destinados a algum controle/monitoração e programados utilizando a linguagem C, que, ao contrário do Assembly, permite portabilidade e certificação SIL (Safety Integrity Level) (URL 5).

Microcontrolador ARM

Todos os exemplos apresentados nesta apostila foram implementados para o microcontrolador LPC2148 fabricado pela NXP. Ele é baseado no núcleo ARM7 que possui uma arquitetura RISC e pode operar com instruções de 16 ou 32 bits. Arquitetura de microprocessador RISC é utilizada principalmente em sistemas embarcados como PDAs, telefones celulares, calculadoras, periféricos do computador, equipamentos POS (Point-Of-Sale). Também

Page 8: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página8 

utilizadas na indústria automotiva, médica e em aplicações de controle industrial. Primeiro protótipo do processador, o ARM1, surgiu em 1995 e desde então mais de um bilhão desses dispositivos já foram construídos e essa tecnologia não parou de evoluir. A arquitetura ARM foi desenvolvida com o intuito de se obter o melhor desempenho possível respeitando as seguintes características:

Ser simples: tem um conjunto de instruções reduzido, pois sua arquitetura é baseada na filosofia de projeto RISC (Reduced Instruction Set Computer);

Ocupar pouca área: otimização de área feita através de várias simplificações como, por exemplo, deixar tarefas secundárias ou específicas (I/O, operações de ponto flutuante, etc) a cargo dos co-processadores;

Ter baixo consumo de energia: redução obtida através da simplicidade do circuito, pipeline curto (operando a baixas frequências) e um projeto que privilegia o mínimo consumo de energia sempre que o processador não estiver em operação;

Possui 16 registradores de uso geral; As instruções são de três endereços e o conjunto de instruções é

extensível com o uso de até 16 co-processadores; Capacidade de executar instruções de 16 bits utilizando a arquitetura

Thumb – codificação de instruções ARM que permite performance de 32bit a um custo de sistema de 8/16bit;

Arquitetura ARM é licenciada, de maneira que diversos fabricantes produzam chips semelhantes.

A família ARM7 é um conjunto de microprocessadores RISC de 32 bits de baixa tensão otimizados para uso comercial. Oferece até 130MIPs e incorpora o conjunto de instruções Thumb de 16bits. A família divide-se em:

• ARM7TDMI: Núcleo que processa números inteiros com pipeline de três estágios que oferece alta performance com um baixíssimo consumo de energia;

• ARM7TDMI-S: Versão sintetizada do núcleo ARM7TDMI, ideal para projetos onde portabilidade e flexibilidade são características imprescindíveis;

• ARM7EJ-S: Núcleo otimizado e sintetizado com extensões na arquitetura e no conjunto de instruções para suportar operações DSP e aceleração nas aplicações Java utilizando tecnologia ARM Jazelle DBX;

• ARM720T: Núcleo que processa números inteiros, com MMU (unidade de gerenciamento de memória) e cachê unificada de 8KB para plataformas de aplicação abertas tais como Windows CE, Linux, Palm CS e Symbian OS.

Page 9: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página9 

Características do ARM7: Arquitetura RISC de 32-bit com conjunto de instruções ARM e Thumb; Pipeline de 3 estágios (arquitetura von Neumann); Performance de até 130 MIPs (Dhrystone 2.1) num típico processador

de 0.13µm; Baixíssimo consumo de energia; Amplo SO e suporte RTOS – incluindo Windows CE, Palm OS, Symbian

OS, Linux; Excelente suporte de debug para desenvolvimento SoC, incluindo

interface ETM; Disponibilidade de processos de 0.25µm, 0.18µm e 0.13µm; Código é compatível com processadores ARM9 e permitem a

reutilização dos códigos de aplicação; Migração e suporte para novas tecnologias de processadores.

O ARM7 é um processador RISC de 32-bit que faz uso de instruções Thumb para reduzir a densidade de código e executar efetivamente as instruções. Muitos periféricos podem ser utilizados junto com essa arquitetura, de acordo com a finalidade da utilização. Porém alguns são utilizados com mais frequência. O principal periférico é a memória, pois nela que se encontram todas as instruções, rotinas de execução, dados, etc. Elas podem ter tamanhos variados e ser do tipo ROM ou RAM e, atualmente, as mais usadas em microcontroladores são a Flash e SRAM, respectivamente. Timers (Temporizadores) também são importantes, pois são utilizados para gerar bases de tempo que podem ser utilizadas para os mais diversos fins, como, por exemplo, gerar sinais de clock para outros periféricos, calcular intervalos de tempo ou medir período de sinais. É possível encontrar microcontroladores de 3 (NXP) à 32 canais (Texas). Outro periférico frequentemente utilizado junto com o ARM é o conversor A/D. Ele quem faz a representação digital de uma grandeza analógica que pode ser velocidade, temperatura, tempo, etc. Atualmente, pode-se encontrar de 4 (Zilog) à 16 canais (Atmel, ST) de conversores em um mesmo microcontrolador.

As principais características do microcontrolador ARM, modelo LPC2148 da NXP são descritas a seguir: Clock de até 60MHz, configurado através de PLL interno; Realização de operações a até 60 MHz; Dois timers/counters de 32 bits; Unidade lógica aritmética com arquitetura RISC de 32 bits com

instruções de soma e subtração executadas em um único ciclo, instruções de multiplicação e multiplicação longa (32x32 bits e resultado

Page 10: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página10 

em 64bits), instrução de multiplicar e acumular usada para implementação de filtros digitais, etc;

Memória flash interna de 512 kB; Configuração da frequência de operação dos periféricos; Periféricos podem ser habilitados e desabilitados individualmente; Possui USB 2.0 fullspeed com RAM para o endpoint de 2kB; Duas unidades UART (Universal Asynchronous Receiver/Transmitter); Duas interfaces com o padrão I2C (Inter-Intergrated Circuit); Uma interface com o padrão SPI (Serial Peripheral Interface); Uma interface com o padrão SSP (Synchronous Serial Port); Interfaces seriais múltiplas incluindo duas UARTs, sendo que uma

possui controle de fluxo implementado em hardware, I2C e SPI; Dois conversores A/D de aproximação sucessiva de 10 bits com até 8

entradas analógicas multiplexadas cada que podem realizar até 400.000 conversões por segundo;

Conversor D/A de 10 bits; Controlador de interrupções com prioridade programável; etc.

Softwares para Programar ARM

Os softwares utilizados na disciplina de Sistemas Embarcados para programar ARM estão disponíveis na área de DOWNLOAD do site www.lasec.feelt.ufu.br

Descrição dos softwares utilizados:

1) Java SE Runtime Enviroment 2) Eclipse

1.1) Plug-In do Elipse: CDT GNU Cross Development Tools 1.2) Plug-In do Elipse: Zylin Embedded CDT

3) YAGARTO GNU ARM toolchain 4) YAGARTO Tools

O instalador irá acrescentar no Path do Windows os caminhos: C:\ARM\yagarto\bin e C:\ARM\yagartotools\bin

OBS1: O arquivo Tutorial - Instalando os Softwares para Programar ARM.pdf contém instruções detalhadas de todos os passos necessários para realizar a instalação dos softwares.

OBS2: Todos os softwares utilizados são distribuídos gratuitamente pelos seus respectivos fornecedores.

Page 11: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página11 

LED_Blink

O objetivo deste exemplo é criar um programa que irá configurar o pino P0.31 de um microcontrolador ARM LPC2148 como entrada/saída digital (I/O). Este pino será utilizado para acionar um LED, como mostra a Figura 03.

Para atingir esta meta, os seguintes passos serão executados:

Passo 1: Crie um novo projeto denominado LED_Blink. As instruções sobre como criar um projeto estão no arquivo denominado Tutorial - Como Criar um Projeto em C para ARM.pdf, disponível no arquivo Aulas.zip Passo 2: Copiar o conteúdo do arquivo LED_Blink.txt, localizado em ...\Aulas\Aula_01\Programas, e colar no arquivo main.c criado no projeto LED_Blink. Onde ...\ representa o local onde o arquivo Aulas.zip foi descompactado. Passo 3: Compilar o programa de acordo com as instruções fornecidas no arquivo chamado Tutorial - Como Criar um Projeto em C para ARM.pdf Passo 4: Transferir o arquivo binário gerado para o microcontrolador ARM.

Exercício Proposto Exercício 01: Crie um programa para acionar de modo sequencial e ininterrupto os quatro LEDs mostrados na Figura 04. O LED 1 deverá piscar, depois o LED 2, e assim sucessivamente, até retornar para o LED 1 novamente. Utilize a função delay_ms do módulo delay_loop para implementar o tempo de espera.

Page 12: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página12 

XTAL162

XTAL261P0.0/TxD0/PWM1

19

P0.1/RxD0/PWM3/EINT0 21

P0.2/SCL0/CAP0.022

P0.3/SDA0/MAT0..0/EINT1 26

P0.4/SCK0/CAP0.1/AD0.627

P0.5/MISO0/MAT0.1/AD0.7 29

P0.6/MOSI0/CAP0.2/AD1.030

P0.7/SSEL0/PWM2/EINT231

P0.8/TxD1/PWM4/AD1.133

P0.9/RxD1/PWM6/EINT334

P0.10/RTS1/CAP1.0/AD1.235

P0.11/CTS1/CAP1.1/SCL137

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.439

P0.14/DCD1/EINT1/SDA141

P0.15/RI1/EINT2/AD1.545

P0.16/EINT0/MAT0.2/CAP0.246

P0.17/CAP1.2/SCK1/MAT1.247

P0.18/CAP1.3/MISO1/MAT1.353

P0.19/MAT1.2/MOSI1/CAP1.254

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.31

P0.22/AD1.7/CAP0.0/MAT0.02

P0.2358

P0.25/AD0.4/AOUT9

P0.27/AD0.0/CAP0.1/MAT0.1 11

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.3 14

P0.30/AD0.3/EINT3/CAP0.015

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT016

P1.17/TRACEPKT112

P1.18/TRACEPKT28

P1.19/TRACEPKT34

P1.20/TRACESYNC48

P1.21/PIPESTAT044

P1.22/PIPESTAT140

P1.23/PIPESTAT236

P1.24/TRACECLK32

P1.25/EXTIN028

P1.26/RTCK24

P1.27/TDO64

P1.28/TDI60

P1.29/TCK56

P1.30/TMS52

P1.31/TRST20

V343

V351

VSS18

VSS25

VSS42

VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.31 17

P0.26/AD0.510

U1

LPC2138

3.3V

D3

LED-GREEN

R7

300

3.3V

3 4

U2:B

74HCT04

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

Figura 4 – LED acionado pelo pino P0.31

XTAL162

XTAL261

P0.0/TxD0/PWM119

P0.1/RxD0/PWM3/EINT021

P0.2/SCL0/CAP0.022

P0.3/SDA0/MAT0..0/EINT126

P0.4/SCK0/CAP0.1/AD0.627

P0.5/MISO0/MAT0.1/AD0.729

P0.6/MOSI0/CAP0.2/AD1.030

P0.7/SSEL0/PWM2/EINT231

P0.8/TxD1/PWM4/AD1.133

P0.9/RxD1/PWM6/EINT334

P0.10/RTS1/CAP1.0/AD1.235

P0.11/CTS1/CAP1.1/SCL137

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.439

P0.14/DCD1/EINT1/SDA141

P0.15/RI1/EINT2/AD1.545

P0.16/EINT0/MAT0.2/CAP0.246

P0.17/CAP1.2/SCK1/MAT1.247

P0.18/CAP1.3/MISO1/MAT1.353

P0.19/MAT1.2/MOSI1/CAP1.254

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.31

P0.22/AD1.7/CAP0.0/MAT0.02

P0.2358

P0.25/AD0.4/AOUT9

P0.27/AD0.0/CAP0.1/MAT0.111

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.314

P0.30/AD0.3/EINT3/CAP0.015

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT016

P1.17/TRACEPKT112

P1.18/TRACEPKT28

P1.19/TRACEPKT34

P1.20/TRACESYNC48

P1.21/PIPESTAT044

P1.22/PIPESTAT140

P1.23/PIPESTAT236

P1.24/TRACECLK32

P1.25/EXTIN028

P1.26/RTCK24

P1.27/TDO64

P1.28/TDI60

P1.29/TCK56

P1.30/TMS52

P1.31/TRST20

V343

V351

VSS18

VSS25

VSS42

VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.3117

P0.26/AD0.510

U1

LPC2138

3.3V

LED 1

LED-GREEN

R7

300

3.3V

1 2

U2:A

74HCT04

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

LED 2

LED-GREEN

R2

300

3.3V

3 4

U2:B

74HCT04

LED 3

LED-GREEN

R3

300

3.3V

5 6

U2:C

74HCT04

LED 4

LED-GREEN

R4

300

3.3V

13 12

U2:D

74HCT04

Figura 5 – LEDs acionados pelos pinos P0.31, P0.25, P0.19 e P0.14

Page 13: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página13 

Programa LED_Blink Comentado /* =============================== C/C++ SOURCE FILE ================================ */ /** \file \description Escrever o que a rotina faz \author Nome do autor */ /* ================================================================================== */ /*------------------------------------------------------------------------------------*/ /* INCLUDES */ /*------------------------------------------------------------------------------------*/ #include "LPC214x.h" // A diretiva #include informa ao compilador que ele deve incluir o arquivo LPC214x.h, pois este arquivo contém endereços de memória e de registradores que serão utilizados no programa. #include "cpu_init.h" // A diretiva #include informa ao compilador para incluir o módulo cpu_init.h, pois este arquivo contém as rotinas de inicialização da CPU do ARM LPC2148. /*------------------------------------------------------------------------------------*/ /* FUNCTION IMPLEMENTATION */ /*------------------------------------------------------------------------------------*/ int main (void) // A função main() é a primeira função a ser executada, todo programa deve possuir uma. { int j = 0; // Declara a variável j como inteiro de 32bit, porque a arquitetura do ARM é de 32bit, por isso, a faixa de valores de j é de -2.147.483.648 a +2.147.483.647 cpu_init(); // Chama a rotina que inicializa a CPU do ARM LPC2148 PINSEL1 &= ~((1<<30)|(1<<31)); // O PINSEL1 é um registrador que seleciona a função dos pinos (P0.16-31) do PORT0 e utiliza 2 bits de configuração para cada pino. Neste caso, quando o bit 30 e 31 do registrador é igual a 0 (zero), o pino P0.31 é configurado como entrada/saída (I/O)- Ver item 7.4.1, denominado Pin Function Select Register no documento LPC214X User Manual.pdf IODIR0 |= (1<<31); // O registrador IODIR0 é utilizado para definir se um determinado pino será utilizado como entrada ou saída. Se um determinado Bit deste registrador for configurado com o valor 1, o pino do microcontrolador correspondente a este bit será configurado como saída, por outro lado, se um determinado Bit do registrador IODIR0 for configurado com o valor 0, o pino do microcontrolador correspondente a este bit será configurado como entrada. while(1){ IOSET0 = (1<<31); // O registrador IOSET0 é utilizado para produzir nível lógico alto (1) em um pino configurado como saída. Toda vez que um bit deste registrador for escrito com o valor 1, o pino correspondente a este bit será forçado a assumir nível lógico alto (1). Escrever 0 em um bit deste registrador não produz efeito. )- Ver Table 65: GPIO register map (legacy VPB accessible registers) no documento LPC214X User Manual.pdf. Deste modo, não se deve utilizar IOSET ou IOCLR com o operador ( |= ) ou com o operador ( &= ), pois o compilador irá gerar código inútil. for (j = 0; j < 1000000; j++ ) asm volatile ("NOP"); // Espera // asm("assembly code"); Este é o formato de uma instrução assembly básica acrescentada em um código C. A instrução assembly NOP (No Operation Performed) faz com que a CPU permaneça em espera durante o tempo que leva para uma instrução ser executada. A palavra reservada volatile impede que o compilador otimize esta linha de código, “forçando” ele a acrescentar no código a instrução NOP, mesmo que ela não realize uma operação. IOCLR0 = (1<<31); // // O registrador IOCLR0 é utilizado para produzir nível lógico baixo (0) em um pino configurado como saída. Toda vez que um bit deste registrador for escrito com o valor 1, o pino correspondente a este bit será forçado a assumir nível lógico baixo (0). Escrever 0 em um bit deste registrador não produz efeito. Deste modo, não se deve utilizar IOSET ou IOCLR com o operador ( |= ) ou com o operador ( &= ), pois o compilador irá gerar código inútil. for (j = 0; j < 1000000; j++ ) asm volatile ("NOP"); // Espera } return(0); // É boa prática utilizar “return” na função main() para informar ao sistema operacional quando a execução do programa foi finalizada. } /*------------------------------------------------------------------------------------*/ /* EOF */ /*------------------------------------------------------------------------------------*/

Page 14: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página14 

Observação: A definição padrão para a função main segundo ANSI C é: int main(int argc, char *argv[]) { ... return 0; // retorna um código de erro para o sistema operacional (0 = nenhum erro) }

No entanto, em se tratando de sistemas embarcados, isto depende do sistema operacional usado, do compilador, das bibliotecas e, às vezes, da forma como se chama a rotina principal (main), a partir do boot que é feito em linguagem assembly. Por isso, o mais comum é: int main(void) { ... return 0; // retorna um código de erro para o sistema operacional (0 = nenhum erro) }

Page 15: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página15 

Configurando o Clock da CPU

O clock da cpu é configurado no arquivo cpu_init.h. Este arquivo contém vários defines que facilitam o ajuste do clock desejado como mostrado a seguir.

// Considerando um cristal de 12 MHz, o valor do Mutiplicador e Divisor são: #define cristal_12MHz_cpu_60MHz 0x24 // 0x24 - Clock do processador (cclk) configurado para 60MHz #define cristal_12MHz_cpu_48MHz 0x23 // 0x23 - Clock do processador (cclk) configurado para 48MHz #define cristal_12MHz_cpu_36MHz 0x42 // 0x42 - Clock do processador (cclk) configurado para 36MHz #define cristal_12MHz_cpu_24MHz 0x41 // 0x41 - Clock do processador (cclk) configurado para 24MHz #define cristal_12MHz_cpu_12MHz 0x60 // 0x60 - Clock do processador (cclk) configurado para 12MHz //-------------------------------------------------------------------------------------- //--- A frequência da CPU deve ser configurada aqui!!! --------------------------------- #define cpuMHz cristal_12MHz_cpu_60MHz // Define o clock da CPU do ARM #define bus_div0 0x01 // Barramento com a mesma frequência da CPU #define bus_div2 0x10 // Barramento com metade (1/2) da frequência da CPU #define bus_div4 0x00 // Barramento com um quarto (1/4) da frequência da CPU //-------------------------------------------------------------------------------------- //--- A frequência do barramento dos periféricos deve ser configurada aqui!!! ---------- #define bus_freq bus_div0 // Define a frequência do barramento dos periféricos

Se for necessário criar outros defines, para atender as especificações de

cristais de outras frequências, de acordo com o UM10139 Volume 1: LPC214x User Manual, a configuração da frequência do CLOCK é fornecida por (CCLK = M × FOSC). Onde: CCLK: valor da freqüência do CLOCK do processador; M: valor do multiplicador do PLL que controla a da freqüência do CLOCK do processador; Fosc: frequência do oscilador a cristal/oscilador externo.

Supondo que Fosc = 12MHz e CCLK = 60 MHz: M = CCLK / Fosc M = 60 MHz / 12 MHz M= 5 Consequentemente M - 1 = 4 deverá ser escrito no registrador

PLLCFG[4:0] que possui a função de configurar o valor do multiplicador e divisor do PLL.

O valor do divisor ( P ) do PLL dever ser configurado de tal forma que a frequência do PLL (FCCO) fique entre 156 MHz e 320 MHz. Deste modo, para Fcco = 156 MHz, P = 156 MHz / (2 x 60 MHz) = 1.3 e para Fcco = 320 MHz, P = 320 MHz / (2 x 60 MHz) = 2.67.

Portanto, o único valor inteiro para P que satisfaz ambas as condições de acordo com a Tabela 22 do UM10139 Volume 1: LPC214x User Manual é P = 2. Logo, de acordo com a Tabela 22, o valor 1 deverá ser escrito em PLLCFG[6:5].

Page 16: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página16 

Operadores Lógicos Bit a Bit

Os operadores lógicos Bit a Bit são muito úteis na configuração de registradores.

A linguagem de programação C possui operadores que realizam operações lógicas "bit a bit" em números do tipo inteiro. Uma operação bit a bit pode ser utilizada para testar, atribuir, ou deslocar bits. No entanto, as operações bit a bit não podem ser usadas em float, double, long double, void ou outros tipos mais complexos.

A Tabela 01 mostra os operadores lógicos bit a bit da linguagem de programação C.

Tabela 01 – Operadores Lógicos Bit a Bit. 

Operador Ação

& E (AND)

| OU (OR)

^ XOR (OU Exclusivo)

~ NÃO (NOT)

>> Deslocamento de bits à direita

>> Deslocamento de bits à esquerda

Para que apenas um BIT seja forçado a assumir nível lógico alto ( 1 ), em

um determinado registrador, é necessário utilizar o operador lógico OU e uma máscara que possua apenas o bit desejado em nível lógico alto ( 1 ).

A Figura 6 mostra como forçar para nível alto o bit 10 de um registrador denominado Registrador_X.

BIT: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Registrador_X: 1 0 0 0 0 0 0 0 1 1 1 1 0 1 1 0

Operador OU ou ou ou ou ou ou ou ou ou ou ou ou ou ou ou ou

Máscara: 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0

Registrador_X: 1 0 0 0 0 1 0 0 1 1 1 1 0 1 1 0

Figura 6 – Operador Lógico OU

Na linguagem C esta operação pode ser realizada da seguinte maneira:

uint16_t Registrador_X = 0b1000000011110110; // cria uma variável de 16 bits chamada Registrador_X e a inicializa com o número do tipo binário 0b1000000011110110

uint16_t Mascara = 1 << 10; //inicializa uma Mascara de 16 bits com o bit 10 igual a 1

Registrador_X |= Mascara; // Esta linha de código realiza os três passos descritos abaixo:

1) Lê o valor do Registrador_X; 2) Realiza uma operação lógica OU bit a bit do valor lido com a Mascara; 3) Armazena o resultado no Registrador_X.

Page 17: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página17 

Para que apenas um BIT seja forçado a assumir nível lógico baixo ( 0 ), em um determinado registrador, é necessário utilizar o operador lógico E e uma máscara que possua apenas o bit desejado em nível lógico baixo ( 0 ).

A Figura 7 mostra como forçar para nível alto o bit 10 de um registrador denominado Registrador_X.

BIT: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Registrador_X: 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 0

Operador E E E E E E E E E E E E E E E E E

Máscara: 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1

Registrador_X: 1 0 1 1 1 0 1 1 1 1 1 1 0 1 1 0

Figura 7 – Operador Lógico E

Na linguagem C esta operação pode ser realizada da seguinte maneira:

uint16_t Registrador_X = 0b1011111111110110; // cria uma variável de 16 bits chamada Registrador_X e a inicializa com o número do tipo binário 0b1011111111110110

uint16_t Mascara = ~(1 << 10); //inicializa uma Mascara de 16 bits com o bit 10 igual a 1 e em seguida inverte todos os bits, isto é, os bits igual a 1 são convertidos em 0 e os bits igual a 0 são convertidos em 1

Registrador_X &= Mascara; // Esta linha de código realiza os três passos descritos abaixo:

1) Lê o valor do Registrador_X; 2) Realiza uma operação lógica E bit a bit do valor lido com a Mascara; 3) Armazena o resultado no Registrador_X.

Para que apenas um BIT seja negado, isto é, se for nível lógico alto ( 1 )

seja forçado a assumir nível lógico baixo ( 0 ) e vice-versa, em um determinado registrador, é necessário utilizar o operador lógico XOR (OU Exclusivo) e uma máscara que possua apenas o bit desejado em nível lógico alto ( 1 ).

A Figura 7 mostra como negar o bit 10 de um registrador denominado Registrador_X.

BIT: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Registrador_X: 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 0

Operador XOR XOR XOR XOR ... ... ... ... ... .. .. ... ... ... ... XOR XOR

Máscara: 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0

Registrador_X: 1 0 1 1 1 0 1 1 1 1 1 1 0 1 1 0

Figura 8 – Operador Lógico XOR (OU Exclusivo)

Na linguagem C esta operação pode ser realizada da seguinte maneira:

uint16_t Registrador_X = 0b1011111111110110; // cria uma variável de 16 bits chamada Registrador_X e a inicializa com o número do tipo binário 0b1011111111110110 uint16_t Mascara = 1 << 10; //inicializa uma Mascara de 16 bits com o bit 10 igual a 1 Registrador_X ^= Mascara; // Esta linha de código realiza os três passos descritos abaixo:

1) Lê o valor do Registrador_X; 2) Realiza uma operação lógica XOR bit a bit do valor lido com a Mascara; 3) Armazena o resultado no Registrador_X.

Page 18: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página18 

Display de 7 Segmentos

O objetivo deste exemplo é criar um programa que irá acionar um display de 7 segmentos, como exibido na Figura 05. Toda vez que um push botton for pressionado, o display será incrementado de uma unidade até 9.

Após exibir o número 9, na próxima vez que o botão for pressionado, o display deverá exibir o número 0.

Os seguintes passos deverão ser executados:

Passo 1: Crie um novo projeto denominado Display_7Seg01. As instruções sobre como criar um projeto estão no arquivo denominado Tutorial - Como Criar um Projeto em C para ARM.pdf, disponível no arquivo Aulas.zip Passo 2: Copiar o conteúdo do arquivo Display_7Seg01.txt, localizado em ...\Aulas\Display_7Seg01\Programas, e colar no arquivo main.c criado no projeto Display_7Seg01. Onde ...\ representa o local onde o arquivo Aulas.zip foi descompactado. Passo 3: Compilar o programa de acordo com as instruções fornecidas no arquivo chamado Tutorial - Como Criar um Projeto em C para ARM.pdf Passo 4: Transferir o arquivo binário gerado para o microcontrolador ARM.

XTAL162

XTAL261P0.0/TxD0/PWM1 19

P0.1/RxD0/PWM3/EINT0 21

P0.2/SCL0/CAP0.0 22

P0.3/SDA0/MAT0..0/EINT1 26

P0.4/SCK0/CAP0.1/AD0.6 27

P0.5/MISO0/MAT0.1/AD0.7 29

P0.6/MOSI0/CAP0.2/AD1.0 30

P0.7/SSEL0/PWM2/EINT2 31

P0.8/TxD1/PWM4/AD1.1 33

P0.9/RxD1/PWM6/EINT3 34

P0.10/RTS1/CAP1.0/AD1.2 35

P0.11/CTS1/CAP1.1/SCL1 37

P0.12/DSR1/MAT1.0/AD1.3 38

P0.13/DTR1/MAT1.1/AD1.439

P0.14/DCD1/EINT1/SDA141

P0.15/RI1/EINT2/AD1.545

P0.16/EINT0/MAT0.2/CAP0.246

P0.17/CAP1.2/SCK1/MAT1.247

P0.18/CAP1.3/MISO1/MAT1.353

P0.19/MAT1.2/MOSI1/CAP1.254

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.31

P0.22/AD1.7/CAP0.0/MAT0.02

P0.2358

P0.25/AD0.4/AOUT9

P0.27/AD0.0/CAP0.1/MAT0.111

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.314

P0.30/AD0.3/EINT3/CAP0.015

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT016

P1.17/TRACEPKT112

P1.18/TRACEPKT2 8

P1.19/TRACEPKT3 4

P1.20/TRACESYNC 48

P1.21/PIPESTAT0 44

P1.22/PIPESTAT1 40

P1.23/PIPESTAT2 36

P1.24/TRACECLK 32

P1.25/EXTIN0 28

P1.26/RTCK 24

P1.27/TDO 64

P1.28/TDI 60

P1.29/TCK 56

P1.30/TMS 52

P1.31/TRST 20

V343V351

VSS18VSS25VSS42VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.3117

P0.26/AD0.510

U1

LPC2138

3.3V

R7

300

3 4

U2:B

74HCT04

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

R22k2

3.3

V

R3

300

1 2

U2:A

74HCT04

R4

300

5 6

U2:C

74HCT04R5

300

13 12

U2:D

74HCT04

R6

300

11 10

U2:E

74HCT04R8

300

9 8

U2:F

74HCT04

R9

300

1 2

U3:A

74HCT04

3.3V

Figura 9 - Display de 7 Segmentos acionado pelos pinos P1.25, P1.26, P1.27, P1.28, P1.29, P1.30 e P1.31

Page 19: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página19 

O display utilizado no circuito da Figura 05 é do tipo anodo comum e possui a configuração interna mostrada na Figura 06 (b).

Os pinos do microcontrolador que acionam os segmentos estão ligados aos segmentos de acordo com as informações apresentadas na Tabela 01, coluna intitulada Pino Ex.01.

a

b

f

g

c

e

d

AnodoComum

(a)  (b) Figura 10 – (a) Display de 7 seguimentos catodo comum (b) display de 7 seguimentos

anodo comum.

Tabela 01 – Pinos e Segmentos

Pino Ex.01 Pino Ex. 02 Segmento P1.25 P1.18 a P1.26 P1.19 b P1.27 P1.20 c P1.28 P1.21 d P1.29 P1.22 e P1.30 P1.23 f P1.31 P1.24 g

Exercício Proposto Exercício 01: Crie um programa para acionar dois displays de 7 segmentos, conforme mostrado na Figura 07. Toda vez que um push botton for pressionado, o display será incrementado de uma unidade. Faça os displays contarem de 0 a 15 e após exibir o número 15, na próxima vez que o botão for pressionado, o display deverá exibir o número 0.

Os pinos do microcontrolador estão ligados aos segmentos especificados na Tabela 01.

Page 20: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página20 

Programa:

#include "LPC214x.h" // Informa ao compilador que ele deve incluir o arquivo LPC214x.h. #include "cpu_init.h" // Informa ao compilador para incluir o arquivo cpu_init.h int main (void) { cpu_init(); // Chama a rotina de inicialização da CPU int i = 0; // Declara um inteiro de 32bit e inicializa com o valor zero // O registrador PINSEL2 controla a função dos pinos do PORT1. Se o bit 2 do registrador PINSEL2 for igual a 0 (zero), os pinos P1.36-26 são configurados como entrada/saída e se o bit 3 deste registrador for igual a 0 (zero), os pinos P1.25-16 são configurados como entrada/saída. Por padrão, os bits 2 e 3 são inicializados com valor 0 (zero)- Ver Table 62: Pin function Select register 2 no documento LPC214X User Manual.pdf IODIR1 |= (1<<25)|(1<<26)|(1<<27)|(1<<28)|(1<<29)|(1<<30)|(1<<31); // Configura os pinos P1.25 a P1.31 como saída IOCLR1 = 0xFFFFFFFF; // Força todos os pinos do PORT1 para nível baixo IOSET1 = (1<<25)|(1<<26)|(1<<27)|(1<<28)|(1<<29)|(1<<30); // Força nível alto nos pinos P1.25, P1.26, P1.27, P1.28, P1.29 e P1.30 while(1){ if (!(IOPIN0 & (1<<15))) //Verifica se o Botão foi pressionado { IOCLR1 = 0xFFFFFFFF; // Força nível baixo em todos os pinos do PORT1 // Conversor Decimal para 7 Segmentos switch (i) { case 0: // Escreve 0 no display IOSET1 = (1<<25)|(1<<26)|(1<<27)|(1<<28)|(1<<29)|(1<<30); break; case 1: // Escreve 1 no display IOSET1 = (1<<26)|(1<<27); break; case 2: // Escreve 2 no display IOSET1 = (1<<25)|(1<<26)|(1<<28)|(1<<29)|(1<<31); break; case 3: // Escreve 3 no display IOSET1 = (1<<25)|(1<<26)|(1<<27)|(1<<28)|(1<<31); break; case 4: // Escreve 4 no display IOSET1 = (1<<26)|(1<<27)|(1<<30)|(1<<31); break; case 5: // Escreve 5 no display IOSET1 = (1<<25)|(1<<27)|(1<<28)|(1<<30)|(1<<31); break; case 6: // Escreve 6 no display IOSET1 = (1<<25)|(1<<27)|(1<<28)|(1<<30)|(1<<29)|(1<<31); break; case 7: // Escreve 7 no display IOSET1 = (1<<25)|(1<<26)|(1<<27); break; case 8: // Escreve 8 no display IOSET1 = (1<<25)|(1<<26)|(1<<27)|(1<<28)|(1<<29)|(1<<30)|(1<<31); break; case 9: // Escreve 9 no display IOSET1 = (1<<25)|(1<<26)|(1<<27)|(1<<30)|(1<<31); break; default: // O default escreve 0 no display

IOSET1 = (1<<25)|(1<<26)|(1<<27)|(1<<28)|(1<<29)|(1<<30); }

// O While espera enquanto o Botão estiver pressinado while (!(IOPIN0 & (1<<15))){ asm volatile ("NOP");} i++; // Incrementa i if (i >= 10){ //Verifica se i é maior ou igual a 10 i = 0; } } } return(0); }

Page 21: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página21 

XTAL162

XTAL261P0.0/TxD0/PWM1

19

P0.1/RxD0/PWM3/EINT0 21

P0.2/SCL0/CAP0.022

P0.3/SDA0/MAT0..0/EINT1 26

P0.4/SCK0/CAP0.1/AD0.627

P0.5/MISO0/MAT0.1/AD0.729

P0.6/MOSI0/CAP0.2/AD1.030

P0.7/SSEL0/PWM2/EINT231

P0.8/TxD1/PWM4/AD1.1 33

P0.9/RxD1/PWM6/EINT334

P0.10/RTS1/CAP1.0/AD1.235

P0.11/CTS1/CAP1.1/SCL137

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.4 39

P0.14/DCD1/EINT1/SDA141

P0.15/RI1/EINT2/AD1.5 45

P0.16/EINT0/MAT0.2/CAP0.246

P0.17/CAP1.2/SCK1/MAT1.2 47

P0.18/CAP1.3/MISO1/MAT1.353

P0.19/MAT1.2/MOSI1/CAP1.2 54

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.31

P0.22/AD1.7/CAP0.0/MAT0.02

P0.2358

P0.25/AD0.4/AOUT9

P0.27/AD0.0/CAP0.1/MAT0.111

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.3 14

P0.30/AD0.3/EINT3/CAP0.015

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT016

P1.17/TRACEPKT112

P1.18/TRACEPKT28

P1.19/TRACEPKT3 4

P1.20/TRACESYNC48

P1.21/PIPESTAT044

P1.22/PIPESTAT140

P1.23/PIPESTAT236

P1.24/TRACECLK 32

P1.25/EXTIN028

P1.26/RTCK 24

P1.27/TDO64

P1.28/TDI60

P1.29/TCK56

P1.30/TMS52

P1.31/TRST 20

V343

V351

VSS18

VSS25

VSS42

VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.31 17

P0.26/AD0.510

U1

LPC2138

3.3V

R7

300

3 4

U2:B

74HCT04

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

R22k2

3.3

V

R3

300

1 2

U2:A

74HCT04

R4

300

5 6

U2:C

74HCT04R5

300

13 12

U2:D

74HCT04

R6

300

11 10

U2:E

74HCT04R8

300

9 8

U2:F

74HCT04

R9

300

1 2

U3:A

74HCT04

3.3V

R10

300

3 4

U3:B

74HCT04

R11

300

5 6

U3:C

74HCT04

R12

300

13 12

U3:D

74HCT04R13

300

11 10

U3:E

74HCT04

R14

300

9 8

U3:F

74HCT04R15

300

1 2

U4:A

74HCT04

R16

300

3 4

U4:B

74HCT04

(COM)

 

Figura 11 – Display de 7 Segmentos de dezena e unidade.

Números mágicos em programação

Em programação o termo número mágico é dado para números que aparecem no código, geralmente sem explicação. São chamados de mágicos por ironia; o seu uso não é considerado uma boa prática de programação. A maior parte das linguagens de programação permite que criem nomes descritivos para representar estes números. Estes nomes são chamados constantes. Seu uso facilita a leitura e a manutenção do código. O uso de constantes é preferível ao de números mágicos.

Exemplo: Suponha que um programa de cálculo trigonométrico faça uso do número π em diversos lugares. A princípio o programador usou a aproximação 3.14 e a colocou numericamente em todos os lugares que ela era necessária. O número 3.14 a princípio é facilmente reconhecível como π por qualquer pessoa com algum conhecimento de matemática. Porém nos testes o programador descobriu que precisaria de uma aproximação melhor, como 3.1415926. Agora ele tem que procurar todas as ocorrências de 3.14 no programa e substituí-la pela nova aproximação. Este procedimento é trabalhoso e sujeito a erros. Se o programador tivesse usado uma constante com o nome PI, em vez do número mágico 3.14, bastaria mudar a aproximação na definição da constante (URL 6). Isto posto, para evitar a presença de números mágicos no programa do exemplo anterior, a diretiva #define pode ser utilizada para especificar o segmento do display que está sendo acionado por um determinado pino do microcontrolador, como mostrado a seguir:

Page 22: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página22 

Programa com #define:

#include "LPC214x.h" #include "cpu_init.h" /*------------------------------------------------------------------------------------*/ /* DEFINITIONS AND MACROS */ /*------------------------------------------------------------------------------------*/ #define seg_a (1<<25) // Pino 25 do PORT1 #define seg_b (1<<26) // Pino 26 do PORT1 #define seg_c (1<<27) // Pino 27 do PORT1 #define seg_d (1<<28) // Pino 28 do PORT1 #define seg_e (1<<29) // Pino 29 do PORT1 #define seg_f (1<<30) // Pino 30 do PORT1 #define seg_g (1<<31) // Pino 31 do PORT1 #define button (1<<15) // Botão /*------------------------------------------------------------------------------------*/ /* FUNCTION IMPLEMENTATION */ /*------------------------------------------------------------------------------------*/ int main (void) // Primeira função a ser executada, todo programa deve possuir uma. { cpu_init(); // Chama a rotina de inicialização da CPU int i = 0; // Declara um inteiro de 32bit (-2.147.483.648 a +2.147.483.647) // O registrador PINSEL2 controla a função dos pinos do PORT1. Se o bit 2 do registrador PINSEL2 for igual a 0 (zero), os pinos P1.36-26 são configurados como entrada/saída e se o bit 3 deste registrador for igual a 0 (zero), os pinos P1.25-16 são configurados como entrada/saída. Por padrão, os bits 2 e 3 são inicializados com valor 0 (zero)- Ver Table 62: Pin function Select register 2 no documento LPC214X User Manual.pdf IODIR1 |= seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; // P1.25 a P1.31 como saída IOCLR1 = 0xFFFFFFFF; // Força todos os pinos do PORT1 para nível baixo IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f; // Nível alto nos pinos P1.25 a P1.30 while(1){ if (!(IOPIN0 & button)) //Verifica se o Botão foi pressionado { IOCLR1 = 0xFFFFFFFF; // Força nível baixo em todos os pinos do PORT1 switch (i) // Conversor Decimal para 7 Segmentos { case 0: IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f; break; // 0 no display case 1: IOSET1 = seg_b|seg_c; break; // 1 no display case 2: IOSET1 = seg_a|seg_b|seg_d|seg_e|seg_g; break; // 2 no display case 3: IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_g; break; // 3 no display case 4: IOSET1 = seg_b|seg_c|seg_f|seg_g; break; // 4 no display case 5: IOSET1 = seg_a|seg_c|seg_d|seg_f|seg_g; break; // 5 no display case 6: IOSET1 = seg_a|seg_c|seg_d|seg_f|seg_e|seg_g; break; // 6 no display case 7: IOSET1 = seg_a|seg_b|seg_c; break; // 7 no display case 8: IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; break;// 8 case 9: IOSET1 = seg_a|seg_b|seg_c|seg_f|seg_g; break; // 9 no display default: IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f; // 0 no display } while (!(IOPIN0 & button)); // Espera enquanto o Botão estiver pressinado i++; // Incrementa i if (i >= 10){ i = 0; } } } return(0); } /*------------------------------------------------------------------------------------*/ /* EOF */ /*------------------------------------------------------------------------------------*/

Page 23: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página23 

Exercício Resolvido 01: Crie um programa para acionar dois displays de 7 segmentos, conforme mostrado na Figura 08. Toda vez que um push botton for pressionado, o display será incrementado de uma unidade. Faça os displays contarem de 0 a 15 e após exibir o número 15, na próxima vez que o botão for pressionado, o display deverá exibir o número 0. Observe que o segmento (a) de ambos os displays são acionados pelo mesmo pino do microcontrolador. O mesmo ocorre com os segmentos (b), (c), (d), (e), (f) e (g) de ambos os displays, como especificado na Tabela 02.

XTAL162

XTAL261

P0.0/TxD0/PWM119

P0.1/RxD0/PWM3/EINT021

P0.2/SCL0/CAP0.0 22

P0.3/SDA0/MAT0..0/EINT126

P0.4/SCK0/CAP0.1/AD0.627

P0.5/MISO0/MAT0.1/AD0.7 29

P0.6/MOSI0/CAP0.2/AD1.030

P0.7/SSEL0/PWM2/EINT231

P0.8/TxD1/PWM4/AD1.1 33

P0.9/RxD1/PWM6/EINT334

P0.10/RTS1/CAP1.0/AD1.235

P0.11/CTS1/CAP1.1/SCL1 37

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.439

P0.14/DCD1/EINT1/SDA1 41

P0.15/RI1/EINT2/AD1.545

P0.16/EINT0/MAT0.2/CAP0.2 46

P0.17/CAP1.2/SCK1/MAT1.247

P0.18/CAP1.3/MISO1/MAT1.353

P0.19/MAT1.2/MOSI1/CAP1.254

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.31

P0.22/AD1.7/CAP0.0/MAT0.02

P0.2358

P0.25/AD0.4/AOUT9

P0.27/AD0.0/CAP0.1/MAT0.111

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.314

P0.30/AD0.3/EINT3/CAP0.015

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT016

P1.17/TRACEPKT112

P1.18/TRACEPKT2 8

P1.19/TRACEPKT34

P1.20/TRACESYNC48

P1.21/PIPESTAT0 44

P1.22/PIPESTAT140

P1.23/PIPESTAT236

P1.24/TRACECLK 32

P1.25/EXTIN028

P1.26/RTCK24

P1.27/TDO 64

P1.28/TDI60

P1.29/TCK56

P1.30/TMS 52

P1.31/TRST20

V343

V351

VSS18VSS

25VSS

42VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.3117

P0.26/AD0.510

U1

LPC2138

3.3V

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

R22k2

3.3

V

R10

300

3 4

U3:B

74HCT04

R11

300

5 6

U3:C

74HCT04

R12

300

13 12

U3:D

74HCT04R13

300

11 10

U3:E

74HCT04

R14

300

9 8

U3:F

74HCT04R15

300

1 2

U4:A

74HCT04

R16

300

3 4

U4:B

74HCT04Q1BC337

R3

2.2k

Q2BC337

R4

2.2k

 

Figura 12 – Display de 7 Segmentos de dezena e unidade.

 

Tabela 02 – Segmentos de dois displays diferentes acionados pelo mesmo pino do microcontrolador.

Pino Segmento

dos Displays

P1.18 A

P1.19 B

P1.20 C

P1.21 D

P1.22 E

P1.23 F

P1.24 G

Page 24: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página24 

Resolução: Para que o observador tenha a impressão que os números, exibidos em ambos os displays, estejam sendo mostrados simultaneamente, é necessário que os displays sejam acionados alternadamente em uma frequência maior ou igual a 24 vezes por segundo cada um.

Em 1826 o médico e filólogo inglês Peter Mark Roget publicou um estudo informando que o olho humano retém a imagem que se forma na retina por alguns décimos de segundo a mais (aproximadamente 1/24 de segundo), mesmo após o clarão que a provocou haver desaparecido. Portanto, como a imagem na retina persiste no intervalo de tempo compreendido entre duas imagens sucessivas, o número em um determinado display deverá ser mostrado no exato instante em que o número exibido anteriormente estiver desaparecendo de nossa "memória visual", o que irá produzir a sensação de que o número está sendo exibido continuamente.

OBS1: Em softwares de simulação como o PROTEUS, por exemplo, a sensação de que o número está sendo exibido continuamente pode não ser obtida.

OBS2: Observe que os displays são do tipo catodo comum e o buffer 74HCT04 que aciona cada segmento é inversor, logo, os segmentos serão ligados quando os pinos do microcontrolador estiverem em nível lógico baixo.

O arquivo intitulado Exercício Resolvido01.txt, localizado em ...\Aulas\Display_7Seg01\Exercício Resolvido01\Programas, contém o programa do Exercício Resolvido01 digitado.

Programa do Exercício Resolvido 01

#include "LPC214x.h" #include "cpu_init.h" #include "stdint.h" /*------------------------------------------------------------------------------------*/ /* DEFINITIONS AND MACROS */ /*------------------------------------------------------------------------------------*/ #define seg_a (1<<18) // Segmento a do display #define seg_b (1<<19) // Segmento a do display #define seg_c (1<<20) // Segmento a do display #define seg_d (1<<21) // Segmento a do display #define seg_e (1<<22) // Segmento a do display #define seg_f (1<<23) // Segmento a do display #define seg_g (1<<24) // Segmento a do display #define tran_dez (1<<25) // Transistor da Unidade #define tran_uni (1<<26) // Transistor da Dezena #define botton (1<<15) // Botão /*------------------------------------------------------------------------------------*/ /* FUNCTION IMPLEMENTATION */ /*------------------------------------------------------------------------------------*/ //-------------------------------------------------------------------------------------- //--- Rotina que converte um número decimal para 7 Segmentos --------------------------- void Decimal_to_7Segment(int i){ switch (i) { case 0: IOCLR1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f; break; // 0 no display

Page 25: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página25 

case 1: IOCLR1 = seg_b|seg_c; break; // 1 no display case 2: IOCLR1 = seg_a|seg_b|seg_d|seg_e|seg_g; break; // 2 no display case 3: IOCLR1 = seg_a|seg_b|seg_c|seg_d|seg_g; break; // 3 no display case 4: IOCLR1 = seg_b|seg_c|seg_f|seg_g; break; // 4 no display case 5: IOCLR1 = seg_a|seg_c|seg_d|seg_f|seg_g; break; // 5 no display case 6: IOCLR1 = seg_a|seg_c|seg_d|seg_f|seg_e|seg_g; break; // 6 no display case 7: IOCLR1 = seg_a|seg_b|seg_c; break; // 7 no display case 8: IOCLR1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; break; // 8 no display case 9: IOCLR1 = seg_a|seg_b|seg_c|seg_f|seg_g; break; // 9 no display default: IOCLR1 = seg_a|seg_b|seg_c|seg_f|seg_g; // 0 no display } } //--- Rotina Principal ----------------------------------------------------------------- int main (void) { cpu_init(); // Chama a rotina de inicialização da CPU int j = 0; // Declara um inteiro de 32bit (-2.147.483.648 a +2.147.483.647) int uni = 0; // Declara um inteiro de 32bit (-2.147.483.648 a +2.147.483.647) int dez = 0; // Declara um inteiro de 32bit (-2.147.483.648 a +2.147.483.647) int cont = 0; // Declara um inteiro de 32bit (-2.147.483.648 a +2.147.483.647) // O registrador PINSEL2 controla a função dos pinos do PORT1. Se o bit 2 do registrador PINSEL2 for igual a 0 (zero), os pinos P1.36-26 são configurados como entrada/saída e se o bit 3 deste registrador for igual a 0 (zero), os pinos P1.25-16 são configurados como entrada/saída. Por padrão, os bits 2 e 3 são inicializados com valor 0 (zero)- Ver Table 62: Pin function Select register 2 no documento LPC214X User Manual.pdf IODIR1 |= seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g|tran_dez|tran_uni; // Pinos como saída IOCLR1 = tran_dez|tran_uni; // Nível baixo nos pinos que acionam os transistores IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; // Nível baixo nos segmentos while(1){ IOSET1 = tran_dez; // Faz o Transistor da dezena entrar na saturação Decimal_to_7Segment(dez); for (j = 0; j < 5000; j++ ) asm volatile ("NOP"); // Espera até os segmentos assumirem brilho máximo. Este tempo deve ser configurado na prática IOCLR1 = tran_dez; // Faz o Transistor da dezena entrar em corte IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; // Nível baixo nos segmentos IOSET1 = tran_uni; // Faz o Transistor da unidade entrar em saturação Decimal_to_7Segment(uni); // Chama Decimal_to_7Segment() para exibir unidade for (j = 0; j < 5000; j++ ) asm volatile ("NOP"); // Espera IOCLR1 = tran_uni; // Faz o Transistor da unidade entrar em corte IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; // Nível baixo nos segmentos if (!(IOPIN0 & botton)) // Verifica se o Botão foi pressionado { while (!(IOPIN0 & botton)); // Espera enquanto o Botão estiver pressinado cont++; // Incrementa a variável cont if (cont >= 16){ cont = 0; } uni = cont % 10; // uni = resto da divisão de cont por 10 dez = cont / 10; // dez = cont dividido por 10 } } return(0); } Implementando a rotina Decimal_to_7Segment( ) usando tabela:

#include "LPC214x.h" #include "cpu_init.h" #include "stdint.h"

Page 26: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página26 

/*------------------------------------------------------------------------------------*/ /* DEFINITIONS AND MACROS */ /*------------------------------------------------------------------------------------*/ #define seg_a (1<<18) // Pino 18 do PORT1 #define seg_b (1<<19) // Pino 19 do PORT1 #define seg_c (1<<20) // Pino 20 do PORT1 #define seg_d (1<<21) // Pino 21 do PORT1 #define seg_e (1<<22) // Pino 22 do PORT1 #define seg_f (1<<23) // Pino 23 do PORT1 #define seg_g (1<<24) // Pino 24 do PORT1 #define tran_dez (1<<25) // Pino 25 do PORT1 #define tran_uni (1<<26) // Pino 26 do PORT1 #define botton (1<<15) // Botão /*------------------------------------------------------------------------------------*/ /* FUNCTION IMPLEMENTATION */ /*------------------------------------------------------------------------------------*/ //-------------------------------------------------------------------------------------- //--- Rotina que converte um número decimal para 7 Segmentos --------------------------- void Decimal_to_7Segment(uint8_t i){ const uint32_t tabela[10] = { seg_a|seg_b|seg_c|seg_d|seg_e|seg_f, // Escreve 0 no display seg_b|seg_c, // Escreve 1 no display seg_a|seg_b|seg_d|seg_e|seg_g, // Escreve 2 no display seg_a|seg_b|seg_c|seg_d|seg_g, // Escreve 3 no display seg_b|seg_c|seg_f|seg_g, // Escreve 4 no display seg_a|seg_c|seg_d|seg_f|seg_g, // Escreve 5 no display seg_a|seg_c|seg_d|seg_f|seg_e|seg_g, // Escreve 6 no display seg_a|seg_b|seg_c, // Escreve 7 no display seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g, // Escreve 8 no display seg_a|seg_b|seg_c|seg_f|seg_g // Escreve 9 no display }; if (i > 9){ i = 0; } IOCLR1 = tabela[i]; } //--- Rotina Principal ----------------------------------------------------------------- int main (void) { cpu_init(); // Chama a rotina de inicialização da CPU int j = 0; // Declara um inteiro de 32bit (-2.147.483.648 a +2.147.483.647) int uni = 0; // Declara um inteiro de 32bit (-2.147.483.648 a +2.147.483.647) int dez = 0; // Declara um inteiro de 32bit (-2.147.483.648 a +2.147.483.647) int cont = 0; // Declara um inteiro de 32bit (-2.147.483.648 a +2.147.483.647) // O registrador PINSEL2 controla a função dos pinos do PORT1. Se o bit 2 do registrador PINSEL2 for igual a 0 (zero), os pinos P1.36-26 são configurados como entrada/saída e se o bit 3 deste registrador for igual a 0 (zero), os pinos P1.25-16 são configurados como entrada/saída. Por padrão, os bits 2 e 3 são inicializados com valor 0 (zero)- Ver Table 62: Pin function Select register 2 no documento LPC214X User Manual.pdf IODIR1 |= seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g|tran_dez|tran_uni; // Pinos como saída IOCLR1 = tran_dez|tran_uni; // Nível baixo nos pinos que acionam os transistores IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; // Nível baixo nos segmentos while(1){ IOSET1 = tran_dez; // Faz o Transistor da dezena entrar na saturação Decimal_to_7Segment(dez); for (j = 0; j < 5000; j++ ) asm volatile ("NOP"); // Espera até os segmentos assumirem brilho máximo. Este tempo deve ser configurado na prática IOCLR1 = tran_dez; // Faz o Transistor da dezena entrar em corte IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; // Nível baixo nos segmentos IOSET1 = tran_uni; // Faz o Transistor da unidade entrar em saturação

Page 27: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página27 

Decimal_to_7Segment(uni); // Chama Decimal_to_7Segment() para exibir unidade for (j = 0; j < 5000; j++ ) asm volatile ("NOP"); // Espera IOCLR1 = tran_uni; // Faz o Transistor da unidade entrar em corte IOSET1 = seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; // Nível baixo nos segmentos if (!(IOPIN0 & botton)) // Verifica se o Botão foi pressionado { while (!(IOPIN0 & botton)); // Espera enquanto o Botão estiver pressinado cont++; // Incrementa a variável cont if (cont >= 16){ cont = 0; } uni = cont % 10; // uni = resto da divisão de cont por 10 dez = cont / 10; // dez = cont dividido por 10 } } return(0); }

Page 28: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página28 

Portabilidade e o Pré-processador C Um código portável possui módulos que são reutilizados quando se migra

de uma plataforma de desenvolvimento para outra ou de um modelo de microcontrolador para outro.

Ao se modularizar um código, tomando-se os cuidados para torná-lo portável, a maior parte dos módulos são reutilizados exigindo do programador o trabalho de reajustar somente os módulos que comandam os dispositivos periféricos que são particulares a um determinado modelo de microcontrolador.

Deste modo, "Portabilidade" significa escrever o seu programa (código), de tal forma que o código funcione mesmo em ambientes diferentes, isto é, em vários processadores, sistemas operacionais, versões de bibliotecas, etc.

Se o programa for portável, basta recompilar o código em um sistema novo e ele deverá rodar sem problemas.

Por outro lado, os códigos não portáteis geram muitos problemas de manutenção, controle de versões, possuem legibilidade ruim e são de difícil compreensão.

O uso criterioso das diretivas do pré-processador auxiliam a tornar o código portável.

Um pré-processador é um programa que recebe texto e efetua conversões léxicas nele. As conversões podem incluir substituição de macros, inclusão condicional e inclusão de outros arquivos.

A linguagem de programação C possui um pré-processador que efetua as seguintes transformações:

Substitui trígrafos por equivalentes; Concatena arquivos de código-fonte; Substitui comentários por espaços em branco; Reage a linhas iniciadas com um caractere de cardinal (#),

efetuando substituição de macros, inclusão de arquivos, inclusão condicional e outras operações.

Segue dois exemplos de uso do pré-processador: Exemplo 1: O CRC de um Frame MODBUS pode ser calculado de duas

maneiras. A primeira é utilizando tabelas e a segunda é por meio de expressão aritmética que realiza o cálculo do CRC bit a bit.

Utilizar tabela consome mais memória enquanto calcular bit a bit requer maior processamento. Deste modo, o melhor método a ser utilizado depende dos recursos de processamento disponíveis no µC utilizado.

A Figura 13 mostra o uso do pré-processador para facilitar a escolha do método de cálculo do CRC-16. Caso a macro USE_CRC_TABLE for igual a 1 o CRC-16 será calculado por meio de tabela que exigirá mais memória, mas em contrapartida será mais rápido. Por outro lado, quando a macro USE_CRC_TABLE for igual a 0, o cálculo do CRC será realizado por meio de expressão aritmética que calcula o CRC bit a bit, o que exigirá maior processamento.

Page 29: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página29 

Figura 13 – Uso do pré-processador no cálculo do CRC-16.

Exemplo 2: Diz respeito a configuração de registradores que controlam os

periféricos de um microcontrolador que é realizada por meio de registradores especiais onde cada bit ou um conjunto de bits ajustam ou habilitam uma determinada função.

A multiplexação de funções em pinos de microcontroladores é prática comum. Por esse motivo, a função desejada deve ser escolhida por meio de registradores de configuração.

A Figura 14 mostra as funções dos pinos P0.4, P0.5 e P0.6. Supondo que um dispositivo com interface SPI esta conectado neles, o pino P0.4 deve ser configurado com a função SCK0, o pino P05 com a função MISO0 e o pino P0.6 com a função MOSI0.

Figura 14 - Configuração de Registrador.

O registrador que configura as funções dos pinos é o PINSEL0 e, de acordo com as instruções contidas na figura, o bit 8, 10, e 12 devem ser igual a 1 para que a interface SPI seja habilitada. Neste caso, o pré-processador pode ser utilizado para facilitar a configuração e deixar claro os bits que assumiram valor igual a 1 ( PINSEL0 |= (1<<8)|(1<<10)|(1<<12); ). Por outro lado, a abordagem que utiliza um número hexadecimal para configurar os pinos, deixa o código de difícil compreensão ( PINSEL0 |= 0x00001500; ).

Vale salientar que o uso do pré-processador não afeta o desempenho do firmware porque é executado antes da compilação. Ele é executado automaticamente todas as vezes que o programa é compilado e os comandos a serem executados são dados através de diretivas do pré-processador.

As linhas que começam com um # são comandos para o pré-processador. A linha inteira é reservada para este comando (nenhum código C pode

Page 30: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página30 

aparecer nesta linha e comandos do pré-processador não podem estar separados em diversas linhas).

O uso do pré-processador é recomendável no sentido de elevar a portabilidade do código e facilitar a compreensão do mesmo.

Ademais, a utilização de compiladores, RTOS e bibliotecas que possuem códigos abertos consistem em boa prática no desenvolvimento de sistemas embarcados.

Toda vez que se acrescenta em um projeto bibliotecas com código fechado, haverá o risco da má operação do código fechado que não poderá ser solucionado sem o auxílio do fornecedor. Além disso, existe o risco da repentina descontinuidade do fornecedor/suporte das bibliotecas utilizadas.

Tipos Primitivos em C

As variáveis numéricas em C possuem duas categorias: tipo inteiro ( int ) e ponto flutuante ( float ).

O hardware que realiza a aritmética de ponto flutuante é mais complexo e, consequentemente, mais caro do que o hardware utilizado em operações aritméticas com números inteiros. Assim, para se reduzir custos de produção em larga escala, a maior parte dos microcontroladores não possuem hardware dedicado para executar operações matemáticas de dados representados em ponto flutuante. Por isso, em sistemas embarcados, evita-se o uso de variáveis do tipo ponto flutuante.

Porém, cada processador possui um tamanho de palavra definido pelas características intrínsecas de hardware. Deste modo, existe uma expectativa que os compiladores C implementariam o tipo int correspondente ao tamanho da palavra definida pelo hardware, permitindo aos programadores utilizarem o inteiro (int) com o máximo de eficiência.

Considerando que existem microcontroladores de 8, 16 e 32 bits e que o compilador C utilizado irá implementar o inteiro de acordo com as características de hardware, o valor mínimo e máximo do inteiro irá mudar de acordo com a arquitetura do microcontrolador utilizado. Ao se migrar de um microcontrolador de 16 bits para um de 8 ocorreria uma redução drástica nos valores de máximos e mínimos do tipo inteiro e de todos os tipos primitivos definidos na linguagem C. Portanto, a portabilidade do código fica prejudicada exigindo do programador alterações no código para que se adéque a nova arquitetura.

Page 31: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página31 

Com o objetivo de minimizar este problema, a biblioteca stdint.h foi criada. Ela define o tamanho exato do tipo primitivo de acordo com a norma C99 Standart Data Types criado pela comunidade ANSI/ISSO.

Portanto, em se tratando de programação para microcontroladores, devido as diferentes arquiteturas existentes, uma boa prática de programação é se utilizar o C99 Standart Data Types criado pela comunidade ANSI/ISO que define o tamanho exato do tipo primitivo.

A Tabela 06 mostra os valores de mínimo e máximo do tipo inteiro (int) e inteiro sem sinal (unsigned int) para arquiteturas de 8, 16 e 32 bit.

Tabela 06 – Tipo inteiro de 8, 16 e 32bit

MICROCONTROLADORES 8, 16 e 32 bit Arquitetura Tipo n bit n byte Escala de Valores

8 bit int 8 1 -127 a 128 16 bit int 16 2 -32.768 a 32.767 32 bit int 32 4 –2.147.483.648 a 2.147.438.647 8 bit unsigned int 8 1 0 a 255 16 bit unsigned int 16 2 0 a 65.535 32 bit unsigned int 32 4 0 a 4.294.967.295

Observa-se que quando a palavra aumenta um byte o valor de máximo e mínimo varia drasticamente. Um inteiro de 8 bit varia de -127 a 128 enquanto um inteiro de 16 bit varia de -32.768 a 32.768 e um de 32 bit de -2.147.483.648 (Dois bilhões cento e quarenta e sete milhões quatrocentos e oitenta e três mil seiscentos e quarenta e oito)

Deste modo, de acordo com a Tabela 07, se o código for implementado

para um microcontrolador de 32 bit terá problemas de incompatibilidade do tipo inteiro se for utilizado em um microcontrolador de 16 ou 8 bit. Do mesmo modo, um firmware criado para um microcontrolador de 16 bit terá problemas de incompatibilidade do tipo inteiro se for usado em um microcontrolador de 8 bit.

Tabela 07 – Mudança de Plataforma

MUDANÇA DE PLATAFORMA DE PARA

32 bit 16 ou 8 bit 16 bit 8 bit

Tentando resolver problemas de portabilidade, em 1989, a comunidade ANSI/ISSO criou o C89 Standart Data Types.

Depois de uma década de testes, o Padrão C89 foi revisado dando origem ao C99 Standart Data Types, como mostrado na Tabela 08.

Page 32: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página32 

Esse padrão criou o int8_t que especifica o tamanho do inteiro que está sendo utilizado permitindo que o programador tome providências quando a operação não for atômica.

Tabela 08 – C99 Standart Data Types

TIPO DESCRIÇÃO int8_t Inteiro de 8 bit com sinal uint8_t Inteiro de 8 bit sem sinal int16_t Inteiro de 16 bit com sinal

uint16_t Inteiro de 16 bit sem sinal int32_t Inteiro de 32 bit com sinal

uint32_t Inteiro de 32 bit sem sinal int64_t Inteiro de 64 bit com sinal

uint64_t Inteiro de 64 bit sem sinal

1) int8_t especifica um inteiro com sinal de 8 bit 2) uint8_t especifica um inteiro sem sinal de 8 bit 3) int16_t especifica um inteiro com sinal de 16 bit 4) uint16_t especifica um inteiro sem sinal de 16 bit 5) int32_t especifica um inteiro com sinal de 32 bit 6) uint32_t especifica um inteiro sem sinal de 32 bit 7) int64_t especifica um inteiro com sinal de 64 bit 8) uint64_t especifica um inteiro sem sinal de 64 bit

O exemplo a seguir elucida alguns inconvenientes que surgem quando se

muda de uma plataforma para outra que possui a palavra menor. Exemplo: Uma indústria possui um equipamento que utiliza um

microcontrolador de 16 bit modelo ST7F269 e decide refazer o projeto e utilizar a versão de 8 bit ST72264, como mostrado na Figura 11. Tanto um quando o outro possuem um A/D de 10 bit o que mantém a precisão na leitura do sinal do sensor.

A empresa pretende fabricar 1.000.000 unidades do equipamento e a diferença de preço entre o modelo de 16 bit para o de 8 bit é de US$ 2,00. Portanto a empresa irá economizar 2.000.000,00 (dois milhões de dólares).

Figura 15 – Mudança de plataforma de microcontrolador de 16 bit para

microcontrolador de 8 bit.

Page 33: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página33 

Além disso, vale salientar que a operação de leitura/escrita de um inteiro de 16 bit em uma arquitetura de 8 bit é uma operação não atômica, portanto, o trecho da atualização deverá ser protegido. Exercício Resolvido 02: Quando se deseja acionar um ou mais displays de 7 segmentos utilizando-se um número reduzido de pinos de um determinado microcontrolador, utiliza-se shift register para acionar os segmentos do display, como mostrado na Figura 09.

Sabendo que o pino P1.30 do microcontrolador está conectado ao clock do shift register e o pino P1.31 do microcontrolador conectado ao pino de dados do shift register, crie um programa para acionar um display de 7 segmentos, conforme mostrado na Figura 09. Toda vez que um push botton for pressionado, o display será incrementado de uma unidade. Faça o display contar de 0 a 9 e após exibir o número 9, na próxima vez que o botão for pressionado, o display deverá exibir o número 0.

XTAL162

XTAL261P0.0/TxD0/PWM1 19

P0.1/RxD0/PWM3/EINT0 21

P0.2/SCL0/CAP0.022

P0.3/SDA0/MAT0..0/EINT126

P0.4/SCK0/CAP0.1/AD0.627

P0.5/MISO0/MAT0.1/AD0.7 29

P0.6/MOSI0/CAP0.2/AD1.030

P0.7/SSEL0/PWM2/EINT231

P0.8/TxD1/PWM4/AD1.133

P0.9/RxD1/PWM6/EINT3 34

P0.10/RTS1/CAP1.0/AD1.2 35

P0.11/CTS1/CAP1.1/SCL137

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.4 39

P0.14/DCD1/EINT1/SDA1 41

P0.15/RI1/EINT2/AD1.545

P0.16/EINT0/MAT0.2/CAP0.246

P0.17/CAP1.2/SCK1/MAT1.2 47

P0.18/CAP1.3/MISO1/MAT1.353

P0.19/MAT1.2/MOSI1/CAP1.254

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.3 1

P0.22/AD1.7/CAP0.0/MAT0.02

P0.2358

P0.25/AD0.4/AOUT 9

P0.27/AD0.0/CAP0.1/MAT0.111

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.3 14

P0.30/AD0.3/EINT3/CAP0.0 15

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT016

P1.17/TRACEPKT1 12

P1.18/TRACEPKT28

P1.19/TRACEPKT34

P1.20/TRACESYNC48

P1.21/PIPESTAT0 44

P1.22/PIPESTAT1 40

P1.23/PIPESTAT236

P1.24/TRACECLK32

P1.25/EXTIN0 28

P1.26/RTCK 24

P1.27/TDO64

P1.28/TDI60

P1.29/TCK56

P1.30/TMS 52

P1.31/TRST20

V343

V351

VSS18VSS

25VSS

42VSS

50

RTXC13

RTXC25

V3A7

VBAT49

P0.3117

P0.26/AD0.5 10

U1

LPC2138

3.3V

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

R22k2

3.3

V

300300

300300300300

SR

G8

R

C1/

->

&1D

13

2

4 5 6 10

8

11 12

9

13

U274HCT164

3.3V

330

3.3V

 

Figura 16 – Acionamento de display de 7 Segmentos com shift register.

Tabela 03 – Conexão dos pinos do shift register 74HCT164 com os segmentos do display

Pino do Shift Register

Pino do Shift Register

Segmento do Display

3 Q0

4 Q1 A

5 Q2 B

6 Q3 C

10 Q4 D

11 Q5 E

12 Q6 F

13 Q7 G

Page 34: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página34 

Resolução: A Tabela 04 mostra a operação do circuito integrado 74HCT164.

De acordo com esta tabela, o pino ____

MR deve permanecer em nível lógico alto para que o shift register opere normalmente. Nesta situação, quando os pinos DSA e DSB assumirem nível lógico alto e ocorrer uma borda de subida de clock, todos os bits do shift register serão deslocados ( 0 1 2 3 4 5 6 7Q Q Q Q Q Q Q Q )  e Q0 assumirá nível lógico

alto. Por outro lado, quando DSA e DSB estiverem em nível lógico baixo e ocorrer uma borda de subida de clock, todos os bits do shift register serão deslocados ( 0 1 2 3 4 5 6 7Q Q Q Q Q Q Q Q )  e Q0 assumirá

nível lógico baixo.

Tabela 04 – Tabela de operação do circuito integrado 74HCT164

 

De acordo com a Figura 09, um segmento do display somente é ligado quando o pino utilizado para acioná-lo assumir nível lógico baixo. Deste modo, os níveis de tensão em cada pino do shift register para que o display mostre os números decimais de 0 a 9 são apresentados na Tabela 05.

Tabela 05 – Tensão em cada pino do shift register para que o dispay mostre os números decimais de 0 a 9

DECIMAL

Pinos do Shift Register 74HCT164 3 4 5 6 10 11 12 13

Segmentos ( NC ) ( a ) ( b ) ( c ) ( d ) ( e ) ( f ) ( g )

0 X 0 0 0 0 0 0 1 1 X 1 0 0 1 1 1 1 2 X 0 0 1 0 0 1 0 3 X 0 0 0 0 1 1 0 4 X 1 0 0 1 1 0 0 5 X 0 1 0 0 1 0 0 6 X 1 1 0 0 0 0 0 7 X 0 0 0 1 1 1 1 8 X 0 0 0 0 0 0 0 9 X 0 0 0 0 1 0 0

Page 35: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página35 

Programa do Exercício Resolvido 02

#include "LPC214x.h" #include "cpu_init.h" #include <stdint.h> #define clk (1<<30) // Clock utilizado no shift register #define data (1<<31) // Dados enviados para o shift register #define button (1<<15) // Define o pino do botão //--- Rotina que Serializa um Número Decimal para o Display ---------------------------- void Serialize_to_Display(uint8_t i){ uint8_t num = 0; uint8_t j = 0; switch (i) { case 0: num = 0b00000001; break; // Escreve 0 no display case 1: num = 0b01001111; break; // Escreve 1 no display case 2: num = 0b00010010; break; // Escreve 2 no display case 3: num = 0b00000110; break; // Escreve 3 no display case 4: num = 0b01001100; break; // Escreve 4 no display case 5: num = 0b00100100; break; // Escreve 5 no display case 6: num = 0b01100000; break; // Escreve 6 no display case 7: num = 0b00001111; break; // Escreve 7 no display case 8: num = 0b00000000; break; // Escreve 8 no display case 9: num = 0b00000100; break; // Escreve 9 no display default: num = 0b00000001; // Escreve 0 no display } for (j = 0; j <= 7; j++ ){ if (num & 1){ IOSET1 = data; // Pino de dados em nível alto IOCLR1 = clk; // Pino de clock em nível baixo IOSET1 = clk; // Pino de clock em nível alto } else{ IOCLR1 = data; // Pino de dados em nível baixo IOCLR1 = clk; // Pino de clock em nível baixo IOSET1 = clk; // Pino de clock em nível alto } num = num >> 1; } } //--- Rotina Principal ----------------------------------------------------------------- int main (void){ cpu_init(); // Chama a rotina de inicialização da CPU uint8_t cont = 0; // Declara um inteiro de 32bit PINSEL1 |= 0x00000000; // Configura todos os pinos como entrada/saída (I/O) IODIR1 |= clk|data; // Configura os pinos de clk e data como saída while(1){ if (!(IOPIN0 & button)) // Verifica se o Botão foi pressionado { while (!(IOPIN0 & button)); // Espera enquanto o Botão estiver pressinado Serialize_to_Display(cont); cont++; // Incrementa a variável cont if (cont >= 10){ cont = 0; } } } return(0); }

Page 36: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página36 

O arquivo intitulado Exercício Resolvido02.txt, localizado em ...\Aulas\Display_7Seg01\Exercício Resolvido02\Programas, contém o programa do Exercício Resolvido02 digitado.

Exercício Proposto Exercício 02: Crie um programa para acionar três displays de 7 segmentos, conforme mostrado na Figura 10. Considerando que o push botton conectado no pino P0.15 incrementa a unidade, o que está conectado ao pino P0.8 incrementa a dezena e o que está ligado ao pino P0.0 a centena, toda vez que um push botton for pressionado, o display correspondente a unidade, dezena ou centena será incrementado de uma unidade. Faça os displays contarem de 0 a 9 e após exibirem o número 9, na próxima vez que o botão correspondente for pressionado, o display deverá exibir o número 0.

Os níveis de tensão em cada pino do shift register para que o display mostre os números decimais de 0 a 9 são apresentados na Tabela 05.

XTAL162

XTAL261

P0.0/TxD0/PWM119

P0.1/RxD0/PWM3/EINT021

P0.2/SCL0/CAP0.022

P0.3/SDA0/MAT0..0/EINT126

P0.4/SCK0/CAP0.1/AD0.627

P0.5/MISO0/MAT0.1/AD0.729

P0.6/MOSI0/CAP0.2/AD1.0 30

P0.7/SSEL0/PWM2/EINT231

P0.8/TxD1/PWM4/AD1.133

P0.9/RxD1/PWM6/EINT334

P0.10/RTS1/CAP1.0/AD1.2 35

P0.11/CTS1/CAP1.1/SCL137

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.439

P0.14/DCD1/EINT1/SDA141

P0.15/RI1/EINT2/AD1.545

P0.16/EINT0/MAT0.2/CAP0.246

P0.17/CAP1.2/SCK1/MAT1.247

P0.18/CAP1.3/MISO1/MAT1.3 53

P0.19/MAT1.2/MOSI1/CAP1.254

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.31

P0.22/AD1.7/CAP0.0/MAT0.0 2

P0.2358

P0.25/AD0.4/AOUT9

P0.27/AD0.0/CAP0.1/MAT0.111

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.314

P0.30/AD0.3/EINT3/CAP0.015

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT016

P1.17/TRACEPKT112

P1.18/TRACEPKT2 8

P1.19/TRACEPKT34

P1.20/TRACESYNC48

P1.21/PIPESTAT044

P1.22/PIPESTAT140

P1.23/PIPESTAT236

P1.24/TRACECLK32

P1.25/EXTIN028

P1.26/RTCK24

P1.27/TDO 64

P1.28/TDI60

P1.29/TCK56

P1.30/TMS52

P1.31/TRST 20

V343

V351

VSS18

VSS25

VSS42

VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.31 17

P0.26/AD0.510

U1

LPC2138

3.3V

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

R2

2k2

3.3V

300300

300300300300

SR

G8

R

C1

/->

&1

D1

32

4 5 6 10

8

11 12

9

13

U274HCT164

3.3V

330

3.3V

300300

300300300300

SR

G8

R

C1

/->

&1

D1

32

4 5 6 10

8

11 12

9

13

U374HCT164

3.3V

330

U3(MR)

300300

300300300300

SR

G8

R

C1

/->

&1

D1

32

4 5 6 10

8

11 12

9

13

U474HCT

3.3V

330

U4(MR)

R24

2k2

3.3

V

R25

2k2

3.3

V

 

Figura 17 – Acionamento de três displays de 7 segmentos com shift register.

Exercício 03: Comente sobre as vantagens e desvantagens de se utilizar o circuito exibido na Figura 10.

Page 37: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página37 

Teclado Matricial

Crie uma rotina para varrer o teclado matricial 4x4 apresentado na Figura 11. Toda vez que uma tecla numérica do teclado for pressionada, o número correspondente deve ser exibido no display.

Os diodos D2, D3, D4 e D5 são utilizados em série com as linhas do teclado para proporcionar proteção para os pinos do microcontrolador, impedindo que qualquer falha de configuração nos pinos venha a danificá-los. Por exemplo, se os pinos P1.16 e P1.28 forem configurados como saída e um deles assumir o nível lógico alto e o outro baixo, quando a tecla 7 for pressionada, ocorrerá um curto circuito nos pinos que poderá resultar em danos permanentes de hardware. Os diodos utilizados neste tipo de aplicação são, em geral, diodos de sinal do tipo 1N914 ou 1N4148.

XTAL162

XTAL261

P0.0/TxD0/PWM119

P0.1/RxD0/PWM3/EINT021

P0.2/SCL0/CAP0.022

P0.3/SDA0/MAT0..0/EINT1 26

P0.4/SCK0/CAP0.1/AD0.6 27

P0.5/MISO0/MAT0.1/AD0.7 29

P0.6/MOSI0/CAP0.2/AD1.0 30

P0.7/SSEL0/PWM2/EINT2 31

P0.8/TxD1/PWM4/AD1.133

P0.9/RxD1/PWM6/EINT334

P0.10/RTS1/CAP1.0/AD1.235

P0.11/CTS1/CAP1.1/SCL137

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.4 39

P0.14/DCD1/EINT1/SDA1 41

P0.15/RI1/EINT2/AD1.5 45

P0.16/EINT0/MAT0.2/CAP0.2 46

P0.17/CAP1.2/SCK1/MAT1.247

P0.18/CAP1.3/MISO1/MAT1.353

P0.19/MAT1.2/MOSI1/CAP1.254

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.31

P0.22/AD1.7/CAP0.0/MAT0.0 2

P0.23 58

P0.25/AD0.4/AOUT 9

P0.27/AD0.0/CAP0.1/MAT0.111

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.314

P0.30/AD0.3/EINT3/CAP0.015

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT0 16

P1.17/TRACEPKT1 12

P1.18/TRACEPKT2 8

P1.19/TRACEPKT34

P1.20/TRACESYNC48

P1.21/PIPESTAT044

P1.22/PIPESTAT140

P1.23/PIPESTAT236

P1.24/TRACECLK32

P1.25/EXTIN0 28

P1.26/RTCK 24

P1.27/TDO 64

P1.28/TDI 60

P1.29/TCK56

P1.30/TMS52

P1.31/TRST20

V343

V351

VSS18

VSS25

VSS42VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.3117

P0.26/AD0.5 10

U1

LPC2138

3.3V

R7

300

3 4

U2:B

74HCT04

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

R2

2k23.3V

R3

300

1 2

U2:A

74HCT04

R4

300

5 6

U2:C

74HCT04R5

300

13 12

U2:D

74HCT04

R6

300

11 10

U2:E

74HCT04R8

300

9 8

U2:F

74HCT04

R9

300

1 2

U3:A

74HCT04

3.3V

1 2 3

654

8 97

++0 =

A

B

C

D

1 2 43D2

D3

D4

D5

R1010k

R1110k

R1210k

R1310k

3.3V

Figura 18 – Teclado Matricial

Resolução: Os pinos P1.16, P1.17, P1.18 e P1.19 devem ser configurados como saída e os pinos P1.28, P1.29, P1.30 e P1.31 como entrada. Toda vez que o pino P1.16 assumir nível lógico baixo e a tecla 7 for pressionada, o pino P1.28 também assumirá nível lógico baixo, pois o pino P1.16, configurado como saída, irá drenar toda corrente fornecida pelo resistor de pull-up R10.

Page 38: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página38 

Programa

#include "LPC214x.h" #include "cpu_init.h" #include <stdint.h> // Biblioteca que define o tamanho exato do tipo primitivo /*------------------------------------------------------------------------------------*/ /* DEFINITIONS AND MACROS */ /*------------------------------------------------------------------------------------*/ #define LINHA_A (1<<16) #define LINHA_B (1<<17) #define LINHA_C (1<<18) #define LINHA_D (1<<19) #define COLUNA_1 (1<<28) #define COLUNA_2 (1<<29) #define COLUNA_3 (1<<30) #define seg_a (1<<0) // Segmento a #define seg_b (1<<1) // Segmento b #define seg_c (1<<2) // Segmento c #define seg_d (1<<3) // Segmento d #define seg_e (1<<4) // Segmento e #define seg_f (1<<5) // Segmento f #define seg_g (1<<6) // Segmento g //-------------------------------------------------------------------------------------- //--- Rotina que converte um número decimal para 7 Segmentos --------------------------- void Decimal_to_7Segment(uint8_t i){ IOCLR0 |= 0xFFFFFFFF; // Força nível baixo em todos os pinos do PORT0 switch (i) { case 0: IOSET0 |= seg_a|seg_b|seg_c|seg_d|seg_e|seg_f; break; // 0 no display case 1: IOSET0 |= seg_b|seg_c; break; // 1 no display case 2: IOSET0 |= seg_a|seg_b|seg_d|seg_e|seg_g; break; // 2 no display case 3: IOSET0 |= seg_a|seg_b|seg_c|seg_d|seg_g; break; // 3 no display case 4: IOSET0 |= seg_b|seg_c|seg_f|seg_g; break; // 4 no display case 5: IOSET0 |= seg_a|seg_c|seg_d|seg_f|seg_g; break; // 5 no display case 6: IOSET0 |= seg_a|seg_c|seg_d|seg_f|seg_e|seg_g; break; // 6 no display case 7: IOSET0 |= seg_a|seg_b|seg_c; break; // 7 no display case 8: IOSET0 |= seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; break; //8 no display case 9: IOSET0 |= seg_a|seg_b|seg_c|seg_f|seg_g; break; // Escreve 9 no display default: break; // Escreve 0 no display } } //-------------------------------------------------------------------------------------- //--- Rotina que varre o teclado ------------------------------------------------------- uint8_t Varre_Teclado(void){ uint8_t i = 10; // Se i permanecer igual a 10 significa que nenhuma tecla foi pressionada IOCLR1 |= LINHA_A; // Nível baixo na Linha A if (!(IOPIN1 & COLUNA_1)){ i = 7; while (!(IOPIN1 & COLUNA_1)); // Aguarda soltar botão } if (!(IOPIN1 & COLUNA_2)){ i = 8; while (!(IOPIN1 & COLUNA_2)); // Aguarda soltar botão } if (!(IOPIN1 & COLUNA_3)){ i = 9; while (!(IOPIN1 & COLUNA_3)); // Aguarda soltar botão } IOSET1 |= LINHA_A; // Nível alto na Linha A IOCLR1 |= LINHA_B; // Nível baixo na Linha B if (!(IOPIN1 & COLUNA_1)){ i = 4; while (!(IOPIN1 & COLUNA_1)); // Aguarda soltar botão } if (!(IOPIN1 & COLUNA_2)){ i = 5; while (!(IOPIN1 & COLUNA_2)); // Aguarda soltar botão }

Page 39: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página39 

if (!(IOPIN1 & COLUNA_3)){ i = 6; while (!(IOPIN1 & COLUNA_3)){ asm volatile ("NOP");} // Aguarda soltar botão } IOSET1 |= LINHA_B; // Nível alto na Linha B IOCLR1 |= LINHA_C; // Nível baixo na Linha C if (!(IOPIN1 & COLUNA_1)){ i = 1; while (!(IOPIN1 & COLUNA_1)); // Aguarda soltar botão } if (!(IOPIN1 & COLUNA_2)){ i = 2; while (!(IOPIN1 & COLUNA_2)); // Aguarda soltar botão } if (!(IOPIN1 & COLUNA_3)){ i = 3; while (!(IOPIN1 & COLUNA_3)); // Aguarda soltar botão } IOSET1 |= LINHA_C; // Nível baixo na Linha A IOCLR1 |= LINHA_D; // Nível baixo na Linha A if (!(IOPIN1 & COLUNA_2)){ i = 0; while (!(IOPIN1 & COLUNA_2)); // Aguarda soltar botão } IOSET1 |= LINHA_D; // Nível alto na Linha D return(i); } //-------------------------------------------------------------------------------------- //--- Rotina Principal ----------------------------------------------------------------- int main (void) { cpu_init(); // Chama a rotina de inicialização da CPU PINSEL0 |= 0x00000000; // Configura PORT0 como entrada/saída (I/O). PINSEL1 |= 0x00000000; // Configura PORT0 como entrada/saída (I/O). IODIR0 |= seg_a|seg_b|seg_c|seg_d|seg_e|seg_f|seg_g; // Configura os pinos que acionam os segmentos como saída IODIR1 |= LINHA_A|LINHA_B|LINHA_C|LINHA_D; // Configura os pinos que acionam as linhas como saída IOCLR0 |= 0xFFFFFFFF; // Força todos os pinos do PORT0 para nível baixo IOSET0 |= seg_g; // Liga o segmento g uint8_t k = 10; // Cria uma variável de 8bit sem sinal (0 a 255) while(1){ k = Varre_Teclado(); // Varre o teclado if (k != 10){ Decimal_to_7Segment(k); } } return(0); }

Exercício Proposto Exercício 01: Crie um programa para varrer o teclado e acionar três displays de 7 segmentos, conforme mostrado na Figura 12. Quando uma tecla for pressionada, o número, correspondente a tecla pressionada, deverá ser exibido no display da unidade e o número que estava sendo exibido na unidade deverá ser deslocado para o display da dezena. Do mesmo modo, o número que estava sendo exibido no display da dezena deverá ser deslocado para o display da centena.

Page 40: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página40 

XTAL162

XTAL261

P0.0/TxD0/PWM119

P0.1/RxD0/PWM3/EINT021

P0.2/SCL0/CAP0.022

P0.3/SDA0/MAT0..0/EINT126

P0.4/SCK0/CAP0.1/AD0.627

P0.5/MISO0/MAT0.1/AD0.729

P0.6/MOSI0/CAP0.2/AD1.030

P0.7/SSEL0/PWM2/EINT231

P0.8/TxD1/PWM4/AD1.133

P0.9/RxD1/PWM6/EINT334

P0.10/RTS1/CAP1.0/AD1.235

P0.11/CTS1/CAP1.1/SCL137

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.439

P0.14/DCD1/EINT1/SDA141

P0.15/RI1/EINT2/AD1.545

P0.16/EINT0/MAT0.2/CAP0.246

P0.17/CAP1.2/SCK1/MAT1.247

P0.18/CAP1.3/MISO1/MAT1.353

P0.19/MAT1.2/MOSI1/CAP1.254

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.31

P0.22/AD1.7/CAP0.0/MAT0.02

P0.2358

P0.25/AD0.4/AOUT9

P0.27/AD0.0/CAP0.1/MAT0.111

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.314

P0.30/AD0.3/EINT3/CAP0.015

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT016

P1.17/TRACEPKT112

P1.18/TRACEPKT28

P1.19/TRACEPKT34

P1.20/TRACESYNC48

P1.21/PIPESTAT044

P1.22/PIPESTAT140

P1.23/PIPESTAT236

P1.24/TRACECLK32

P1.25/EXTIN028

P1.26/RTCK24

P1.27/TDO64

P1.28/TDI60

P1.29/TCK56

P1.30/TMS52

P1.31/TRST20

V343

V351

VSS18

VSS25

VSS42

VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.3117

P0.26/AD0.510

U1

LPC2138

3.3V

X1CRYSTAL

REQ=12MHz

C3

100pF

1 2 3

654

8 97

++0 =

A

B

C

D

1 2 43

D2

D3

D4

D5

R210k

R310k

R410k

R510k

3.3V

300300

300300300300

SR

G8

R

C1

/->

&1

D1

32

4 5 6 10

8

11 12

9

13

U274HCT164

3.3V

330

3.3V

300300

300300300300

SR

G8

R

C1

/->

&1

D1

32

4 5 6 10

8

11 12

9

13

U374HCT164

3.3V

330

U3(MR)

300300

300300300300

SR

G8

R

C1

/->

&1

D1

32

4 5 6 10

8

11 12

9

13

U474HCT

3.3V

330

U4(MR)

Figura 19 – Teclado Matricial e três displays acionados por shift register.

Display de Cristal Líquido

Utilize o módulo LCD para acionar um display de cristal líquido alfanumérico de 2x16 de acordo com as especificações da Tabela 09 e do diagrama esquemático mostrado na Figura 13. A primeira linha do display deverá exibir “SIST. EMBARCADOS” e a segunda linha a palavra “Contador:” seguida de uma variável decimal que será incrementada toda vez que o push botton conectado ao pino P1.31 do LPC2148 for pressionado.

Tabela 09 – Conexão dos pinos do LPC2148 com os pinos do LCD

Pino do LPC2148

Pino do LCD

P0.10 D4

P0.11 D5

P0.12 D6

P0.13 D7

P0.22 RS

P0.28 RW

P0.29 F

Page 41: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página41 

XTAL162

XTAL261P0.0/TxD0/PWM1

19

P0.1/RxD0/PWM3/EINT0 21

P0.2/SCL0/CAP0.0 22

P0.3/SDA0/MAT0..0/EINT1 26

P0.4/SCK0/CAP0.1/AD0.6 27

P0.5/MISO0/MAT0.1/AD0.7 29

P0.6/MOSI0/CAP0.2/AD1.0 30

P0.7/SSEL0/PWM2/EINT2 31

P0.8/TxD1/PWM4/AD1.1 33

P0.9/RxD1/PWM6/EINT3 34

P0.10/RTS1/CAP1.0/AD1.2 35

P0.11/CTS1/CAP1.1/SCL137

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.439

P0.14/DCD1/EINT1/SDA1 41

P0.15/RI1/EINT2/AD1.5 45

P0.16/EINT0/MAT0.2/CAP0.2 46

P0.17/CAP1.2/SCK1/MAT1.2 47

P0.18/CAP1.3/MISO1/MAT1.3 53

P0.19/MAT1.2/MOSI1/CAP1.2 54

P0.20/MAT1.3/SSEL1/EINT3 55

P0.21/PWM5/AD1.6/CAP1.3 1

P0.22/AD1.7/CAP0.0/MAT0.0 2

P0.2358

P0.25/AD0.4/AOUT9

P0.27/AD0.0/CAP0.1/MAT0.1 11

P0.28/AD0.1/CAP0.2/MAT0.2 13

P0.29/AD0.2/CAP0.3/MAT0.3 14

P0.30/AD0.3/EINT3/CAP0.0 15

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT0 16

P1.17/TRACEPKT1 12

P1.18/TRACEPKT2 8

P1.19/TRACEPKT34

P1.20/TRACESYNC48

P1.21/PIPESTAT044

P1.22/PIPESTAT1 40

P1.23/PIPESTAT2 36

P1.24/TRACECLK 32

P1.25/EXTIN0 28

P1.26/RTCK 24

P1.27/TDO 64

P1.28/TDI 60

P1.29/TCK 56

P1.30/TMS 52

P1.31/TRST 20

V343V351

VSS18VSS25VSS42VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.31 17

P0.26/AD0.5 10

U1

LPC2138

3.3V

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

R25

2k2

3.3V

D7

14D

613

D5

12D

411

D3

10D

29

D1

8D

07

E6

RW

5R

S4

VS

S1

VD

D2

VE

E3

LCDLM016L

Figura 20 – Acionando um display de cristal líquido alfanumérico de 2x16.

Resolução: Passo 1: Crie um novo projeto denominado LCD. Passo 2: Copiar o conteúdo do arquivo LCD.txt, localizado em ...\Aulas\LCD\Programas, e colar no arquivo main.c criado no projeto LCD. Passo 3: Importar para o projeto LCD os arquivos delay_loop.c, delay_loop.h, iprintf.c, iprintf.h, lcd.c e lcd.h, localizados na pasta _Módulos do ARM LPC2148 em C:\ARM\PROGRAMAS\LPC2148\

As instruções sobre como importar arquivos estão no Tutorial - Como Criar um Projeto em C para ARM.pdf, disponível no arquivo Aulas.zip Passo 4: Compilar o programa. Passo 5: Transferir o arquivo binário gerado para o microcontrolador ARM.

Page 42: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página42 

Programa

#include "LPC214x.h" #include "cpu_init.h" #include "iprintf.h" // Separa uma string em caracteres para poder enviá-los serialmente #include "lcd.h" // Módulo com rotinas de inicialização e operação do LCD #include "stdint.h" // Standard C data types #define button (1<<31) // Botão int main(void) { cpu_init(); // Chama a rotina de inicialização da CPU uint16_t i=0; lcd_init(); // Rotina de inicialização do display lcd_line1(); // Leva o cursor do display para o início da linha 1 lcd_string("SIST. EMBARCADOS"); // Escreve string na linha lcd_line2(); // Leva o cursor do display para o início da linha 2 iprintf("Contador:%d",i); // Escreve string na linha while(1){ if (!(IOPIN1 & button)) // Verifica se o Botão foi pressionado { i++; while (!(IOPIN1 & button)); // Espera soltar botão lcd_line2(); // Leva o cursor do display para o início da linha 2 iprintf("Contador:%d",i); // Escreve string na linha } } return 0; } //------------------------------------------------------------------------------------ // EOF //------------------------------------------------------------------------------------ Comentário sobre o Módulo LCD

A configuração dos pinos do microcontrolador utilizados para acionar as linhas de controle e dados do LCD 2x16 é realizada na rotina lcd_init() que se encontra no arquivo lcd.c.

//--------------------------------------------------------------------- void lcd_init(void) { // P0.10, P0.11, P0.12 e P0.13 como entrada/saída (2 bits de configuração cada pino)

PINSEL0 &= ~((1<<20)|(1<<21)|(1<<22)|(1<<23)|(1<<24)|(1<<25)|(1<<26)|(1<<27)); // P0.21, P0.22, P0.28 e P0.29 como entrada/saída (2 bits de configuração cada pino) PINSEL1 &= ~((1<<10)|(1<<11)|(1<<12)|(1<<13)|(1<<24)|(1<<25)|(1<<26)|(1<<27)); //Configura E, RS, RW, D7, D6, D5 e D4 como saída IODIR0 |= LCD_DATA_MASK|LCD_CONTROL_MASK|LUZ; // Força nível lógico baixo nos pinos E, RS, RW, D7, D6, D5 e D4 IOCLR0 = LCD_DATA_MASK|LCD_CONTROL_MASK;

Os registradores PINSEL0 e PINSEL1 utilizam dois bits para configurar a função de cada pino do microcontrolador, por isso, o número de cada pino não coincide com a posição dos bits no registrador como ocorre com os registradores IODIR, IOCLR e IOSET.

Page 43: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página43 

As máscaras LCD_DATA_MASK, LCD_CONTROL_MASK e LUZ foram definidas no trecho de código “DEFINITIONS AND MACROS”, como apresentado a seguir: /*------------------------------------------------------------------------------------*/ /* DEFINITIONS AND MACROS */ /*------------------------------------------------------------------------------------*/ #define E (1<<28) //!< Pino que liga/desliga o LCD, conectado no pino P0.20 do LPC2148 #define RS (1<<22) //!< Informa ao LCD se a informação é um comando ou dado, conectado no pino P0.22 do LPC2148 #define RW (1<<29) //!< Pino que informa se a operação é de leitura ou escrita, conectado no pino P0.29 do LPC2148 (0 = write to LCD module, 1 = read from LCD module) #define busyflag (1<<13) //!< Verifica se o LCD está ocupado, isto é pronto para receber o próximo comando. #define DB4 (1<<10) //!< Pino de dado DB4 (LSB), conectado ao pino P0.10 do LPC2148 #define DB5 (1<<11) //!< Pino de dado DB5, conectado ao pino P0.11 do LPC2148 #define DB6 (1<<12) //!< Pino de dado DB6, conectado ao pino P0.12 do LPC2148 #define DB7 (1<<13) //!< Pino de dado DB4 (MSB), conectado ao pino P0.13 do LPC2148 #define LUZ (1<<21) //!< Liga/desliga a backlight do LCD, conectado no pino P0.21 do LPC2148 #define LCD_DATA_MASK (DB4 | DB5 | DB6 | DB7) #define LCD_CONTROL_MASK (E | RW | RS)

Exercício Proposto Exercício 01: Faça um programa para somar, subtrair, multiplicar ou dividir dois números decimais de apenas um dígito cada. O diagrama esquemático que deverá ser utilizado é mostrado na Figura 16.

XTAL162

XTAL261

P0.0/TxD0/PWM119

P0.1/RxD0/PWM3/EINT021

P0.2/SCL0/CAP0.022

P0.3/SDA0/MAT0..0/EINT1 26

P0.4/SCK0/CAP0.1/AD0.6 27

P0.5/MISO0/MAT0.1/AD0.7 29

P0.6/MOSI0/CAP0.2/AD1.0 30

P0.7/SSEL0/PWM2/EINT2 31

P0.8/TxD1/PWM4/AD1.133

P0.9/RxD1/PWM6/EINT334

P0.10/RTS1/CAP1.0/AD1.235

P0.11/CTS1/CAP1.1/SCL137

P0.12/DSR1/MAT1.0/AD1.338

P0.13/DTR1/MAT1.1/AD1.4 39

P0.14/DCD1/EINT1/SDA1 41

P0.15/RI1/EINT2/AD1.5 45

P0.16/EINT0/MAT0.2/CAP0.2 46

P0.17/CAP1.2/SCK1/MAT1.247

P0.18/CAP1.3/MISO1/MAT1.353

P0.19/MAT1.2/MOSI1/CAP1.254

P0.20/MAT1.3/SSEL1/EINT355

P0.21/PWM5/AD1.6/CAP1.31

P0.22/AD1.7/CAP0.0/MAT0.0 2

P0.23 58

P0.25/AD0.4/AOUT 9

P0.27/AD0.0/CAP0.1/MAT0.111

P0.28/AD0.1/CAP0.2/MAT0.213

P0.29/AD0.2/CAP0.3/MAT0.314

P0.30/AD0.3/EINT3/CAP0.015

V323

RST57

VREF63

VSS6

VSSA59

P1.16/TRACEPKT0 16

P1.17/TRACEPKT1 12

P1.18/TRACEPKT2 8

P1.19/TRACEPKT34

P1.20/TRACESYNC48

P1.21/PIPESTAT044

P1.22/PIPESTAT140

P1.23/PIPESTAT236

P1.24/TRACECLK32

P1.25/EXTIN0 28

P1.26/RTCK 24

P1.27/TDO 64

P1.28/TDI 60

P1.29/TCK56

P1.30/TMS52

P1.31/TRST20

V343

V351

VSS18

VSS25

VSS42VSS50

RTXC13

RTXC25

V3A7

VBAT49

P0.3117

P0.26/AD0.5 10

U1

LPC2138

3.3V

3.3V

C1

22pF

C2

22pF

X1CRYSTAL

FREQ=12MHz

D1

DIODE

R1

47k

C3

100pF

D7

14D

613

D5

12D

411

D3

10D

29

D1

8D

07

E6

RW

5R

S4

VS

S1

VD

D2

VE

E3

LCDLM016L

1 2 3

654

8 97

++0 =

A

B

C

D

1 2 43

D2

D3

D4

D5

R1210k

R1310k

R1410k

R1510k

3.3V

Figura 21 – Teclado e display.

Page 44: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página44 

Interface de Comunicação SPI

O SPI é uma interface de comunicação síncrona que opera no modo full-duplex. Esta interface é composta por 4 sinais, como descriminado abaixo:

Sinais de dados: MOSI (Master data Output, Slave data Input) e MISO (Master data Input, Slave data Output) são responsáveis pela transferência de dados entre o master e o slave;

Sinais de controle: SCLK (Serial Clock) e /SS (Slave Select).

Em modo “escravo”, o microcontrolador comporta-se como um componente da rede, recebendo o sinal de relógio. Em modo “mestre”, o microcontrolador gera um sinal de relógio e deve ter um pino de I/O para habilitação de cada periférico. A interface SPI é muito utilizada em conversor digital analógico, relógio de tempo real, DIGIPOTs, mémorias flash, cartões SD/MMC, dentre outros circuitos integrados. A Figura 17 mostra o diagrama esquemático da ligação entre dois dispositivos que utilizam a interface de comunicação SPI e a Figura 18 exibe o diagrama esquemático de um dispositivo mestre comunicando com três escravos. Os pinos SS1, SS2 e SS3 são utilizados para selecionar o dispositivo escravo que se deseja comunicar.

Master Slave

SCLK

MOSI

MISO

SCLK

Figura 22 - Comunicação entre o dispositivo mestre (máster) e o escravo (slave) utilizando o protocolo SPI.

SPI MasterSlave 01

SCLKMOSIMISO

Slave 02

Slave 03

SS

SCLKMOSIMISO

SS

SCLKMOSIMISO

SS

SCLKMOSIMISO

SS

1SS2SS3

Figura 23 - Comunicação entre um dispositivo mestre e três escravos utilizando a interface de comunicação SPI.

Page 45: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página45 

Operações “ATOMIC”

Uma operação é “ATOMIC” quando o processador utiliza apenas um ciclo de instrução para executá-la. Deste modo, uma operação que é “ATOMIC” em um microcontrolador com arquitetura de 16 bit não é “ATOMIC” em um microcontrolador de 8 bit.

A operação não “ATOMIC” ocorre quando o processador tenta atualizar uma variável maior do que o tamanho da palavra da arquitetura. Por exemplo, durante a atualização de uma variável de 16 bit em um microcontrolador que possui arquitetura de 8 bit, pode ocorrer perda de dados ou dados corrompidos se o processador for interrompido durante o processo de atualização. A Tabela 10 mostra um resumo das operações, de acordo com a arquitetura, para o tipo inteiro definido pelo C99 Standard Data Types.

Tabela 10 – Operações Atômicas e Não Atômicas

OPERAÇÕES “ATOMIC” TIPO µC de 8bit µC de 16bit µC de 32bit int8_t

uint8_t int16_t

uint16_t int32_t

uint32_t int64_t

uint64_t

Um operação int8_t em uma arquitetura de 8 bit, ou 16 bit ou 32 bit

ou 64 bit é atômica e o mesmo ocorre com o uint8_t Um operação com um int16_t em uma arquitetura de 8 bit não é

atômica, porém em uma arquitetura de 16 bit ou 32 bit ou 64 bit ela é atômica, o mesmo ocorre com o uint16_t

Um operação com um int32_t em uma arquitetura de 8 bit ou 16 bit não é atômica, porém em uma arquitetura de 32 bit ou 64 bit ela é atômica, o mesmo ocorre com o uint64_t

Um operação com um int64_t somente é atômica em uma arquitetura de 64 bit e o mesmo ocorre com o tipo uint64_t

Exemplo 01: Vamos analisar o que ocorre ao se tentar atualizar uma variável de 32 bit em um µC que possui arquitetura de 8 bit, como apresentado na Figura 22.

Page 46: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página46 

A Figura 24 ( a ) mostra o código assembly, correspondente a atualização da variável NoAtomicOperation de 32 bit, realizada em um microcontrolador PIC, modelo 16F877A, que possui arquitetura de 8 bit.

Figura 24 - Atualização da variável NoAtomicOperation de 32 bit.

A primeira instrução move o valor 0xAB para o registrador de trabalho W e a segunda armazena o valor no endereço de memória 0x29

A terceira instrução move o valor 0xCD para o registrador de trabalho W e a quarta armazena o valor no endereço de memória 0x28.

A quinta instrução move o valor 0xEF para o registrador de trabalho W e a sexta armazena o valor no endereço de memória 0x27.

E, por fim, a sétima instrução move o valor 0x01 para o registrador de trabalho W e a oitava armazena o valor no endereço de memória 0x26.

Portando, 8 instruções foram necessárias para atualizar o valor da variável NoATomicOperation, o que caracteriza esta operação como sendo não atômica.

Por outro lado, a Figura 22 (b) exibe o código assembly correspondente a atualização da variável AtomicOperation de 32 bit, realizada em um uC ARM, modelo LPC2148, que possui arquitetura de 32 bit.

A primeira instrução carrega o valor ABCDEF01 do endereço de memória flash 340 no registrador r3 e a segunda instrução move o valor do registrador r3 para a posição de memória indicada pelo ponteiro de pilha sp.

Apenas uma instrução (str) foi necessária para atualizar a variável, o que caracteriza esta operação como sendo atômica.

Exemplo 02: As informações em um protocolo MODBUS RTU são

transmitidas em frames que possuem um campo de endereço, um campo com a função a ser executada, um campo de dados e, por fim, o do CRC.

Entre os frames é acrescentado um silêncio na linha maior ou igual a 3,5 vezes o tempo de transmissão de um caractere utilizado para indicar o fim ou início de um frame.

Este exemplo analisa uma operação não atômica de uma variável conhecida como “tick conter”, utilizada na temporização “time out” dos frames em um protocolo MODBUS.

Page 47: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página47 

Figura 25 - Atualização da variável de 32 bit não atômica, utilizada na temporização de frames MODBUS, conhecida como “tick counter”.

Em aplicações que necessitam temporizar várias tarefas e que utilizam µC

que possuem pouco recurso de hardware um contador de tempo denominado TickCounter é muito utilizado. Ele é atualizado toda vez que uma rotina de interrupção de timer é chamada.

Supondo que a variável TickCounter é do tipo uint32_t, como mostra a Figura 26, toda vez que a interrupção do timer ocorrer o valor desta variável será incrementada.

Em outro trecho do código ocorre a verificação do “time out” efetuado pelo cálculo do tempo decorrido entre o tempo atual e o de transmissão do último byte.

No exemplo da Figura 26, o valor do TickCounter no instante de tempo em que o último byte foi transmitido era de 0x000000AB e, depois de algum tempo, durante a verificação de “time out”, exatamente no instante de atualização da variável TempoAtual, ocorreu uma interrupção.

Durante a atualização da variável TempoAtual, a instrução assembly MOVF 29, W move o valor do byte mais significativo da variável TickCounter para o registrador de trabalho e a instrução MOVWF 31 move o valor do registrador de trabalho W para a posição de memória do byte mais significativo da variável TempoAtual.

Na sequência, a instrução assembly MOVF 28, W move o valor do segundo byte mais significativo da variável TickCounter para o registrador de trabalho e a instrução MOVWF 30 move o valor do registrador de trabalho W para a posição de memória do segundo byte mais significativo da variável TempoAtual.

Page 48: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página48 

Neste instante, ocorre uma interrupção que atualiza o valor da variável TickCounter fazendo que o valor seja atualizado para 0x00010000. Retornando da interrupção a atualização da variável TempoAtual prossegue.

A próxima instrução assembly MOVF 27, W move o valor do segundo byte menos significativo da variável TickCounter para o registrador de trabalho e a instrução MOVWF 2F move o valor do registrador de trabalho W para a posição de memória do segundo byte menos significativo da variável TempoAtual.

A próxima instrução assembly MOVF 26, W move o valor do byte menos significativo da variável TickCounter para o registrador de trabalho e a instrução MOVWF 2E move o valor do registrador de trabalho W para a posição de memória do byte menos significativo da variável TempoAtual.

O valor esperado para a variável TempoAtual é 0x0000FFFF, contudo, foi atualizada com o valor 0x00000000. Após o calculo do tempo decorrido o valor obtido é 0xFFFFFF55 sendo que o valor esperado é 0x000000AB. O valor 0xFFFFFF55 indica um fim de frame enquanto o valor correto 0x0000FF54 indica que ele ainda não terminou.

Figura 26 - Operação não atômica de uma variável conhecida como “tick conter”, utilizada na temporização “time out” dos frames em um protocolo MODBUS.

A Figura 27 apresenta a mesma situação realizada em um µC de 32 bit. Supondo que a variável TickCounter é do tipo uint32_t, toda vez que a

interrupção do timer ocorrer o valor da variável TickCounter será incrementada.

Page 49: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página49 

No exemplo mostrado na Figura 27, o valor do TickCounter no instante de tempo em que o último byte foi transmitido era de 0x000000AB e, depois de algum tempo, durante a verificação de “time out”, exatamente no instante de atualização da variável TempoAtual, ocorreu uma interrupção.

Durante a atualização da variável TempoAtual, a instrução ldr r3, [sp] carrega o valor da variável TickCounter no registrador r3.

Neste instante, ocorre uma interrupção que atualiza o valor da variável TickCounter, fazendo com que o valor seja atualizado para 0x00010000 e, após o retorno da interrupção, a atualização da variável TempoAtual prossegue com a instrução assembly str r3,[sp, #4] que move o valor do registrador r3 para a posição de memória da variável TempoAtual.

Neste exemplo, o valor da variável foi atualizada com apenas uma instrução (str), o que caracteriza uma operação atômica.

O valor esperado para a variável TempoAtual era 0x0000FFFF e foi atualizado com esse valor.

Após o calculo do tempo decorrido, o valor obtido é 0x0000FF54 que corresponde ao valor esperado.

Figura 27 - Operação atômica de uma variável conhecida como “tick conter”, utilizada na temporização “time out” dos frames em um protocolo MODBUS.

Page 50: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página50 

“STRUCTURE PADDING” E

SERIALIZAÇÃO

“Structure Padding”’ está relacionado com alinhamento de memória, portanto, entender o que é alinhamento de memória é o primeiro passo.

A maior parte dos processadores prefere, ou até mesmo necessita, que o acesso a memória seja alinhado. Isso significa que quando o processador acessa um bloco de n bytes na memória, o endereço inicial deve ser um múltiplo de n.

Por exemplo, uma variável de quatro bytes deve estar limitada em uma fronteira de quatro bytes (o endereço deve ser múltiplo de 4); uma variável de dois bytes deve estar limitada em dois bytes (o endereço deve ser múltiplo de 2); e assim sucessivamente.

O alinhamento é importante porque permite a utilização do tipo int com o máximo de eficiência.

Entretanto, os processadores frequentemente possuem diferentes requerimentos para o acesso a memória. Por exemplo, a arquitetura Intel x86 permite o acesso desalinhado de memória, mas, neste caso, impõe uma queda significativa no desempenho.

Um acesso desalinhado em um processador RISC resultará em uma falta no processador causando uma falha. Se a falha for tratada por uma interrupção síncrona “trap”, o acesso desalinhado deverá ocorrer via software e será lento.

Em um microcontrolador ARM um acesso de memória desalinhado resultará em um dado incorreto e, provavelmente, indesejável. Algumas versões de ARM com unidades de gerenciamento de memória podem realizar verificação de alinhamento, mas essa característica não é padronizada em todas as famílias.

A Figura 28 mostra uma palavra de 4 Bytes e seus submúltiplos: meia palavra e byte.

Figura 28 – Palavra de 4 Bytes e seus submúltiplos: meia palavra e byte.

A Figura 29 mostra o diagrama esquemático da memória do µC ARM de 32 bit modelo LPC 2148.

Page 51: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página51 

Neste exemplo, o endereço de Uma Palavra deve possuir o final 0, 4, 8 ou C. Isto é, deve ser múltiplo de 4 bytes. Consequentemente, o endereço de uma Meia Palavra deve terminar com 0, 2, 4, 6, 8, A, C ou E. Isto é, deve ser múltiplo de 2 bytes. Por fim, o endereço de Byte pode assumir qualquer valor.

Figura 29 – Uma Palavra, Meia Palavra e Um Byte.

A Figura 30 mostra no diagrama esquemático da memória de um ARM o alinhamento do tipo inteiro.

A variável Alinhado1 é do tipo inteiro sem sinal de 32 bit, foi inicializada e declarada com o valor 0xABCEDF01, está representada em verde no diagrama de memória e possui endereço com final 8, o que indica que está alinhada.

O ARM7 é “little endian”, por isso, o byte menos significativo da variável está alocado nos endereços menos significativo da memória.

As variáveis Alinhado2 e 3 são do tipo inteiro sem sinal de 16 bit, foram declaradas e inicializadas com os valores 0x2345 e 0x6789, respectivamente. Elas estão representadas em amarelo no diagrama da memória, possuem o endereço com final 4 e 6 (valores múltiplo de 2), o que indica que estão alinhadas.

As variáveis Alinhado 5, 6, 7 e 8 são do tipo inteiro sem sinal de 8 bit, foram declaradas e inicializadas com os valores 0x12, 0x34, 0x56, 0x78 e 0x9A, respectivamente, estão representadas em laranja e o endereço delas pode assumir qualquer valor.

As variáveis foram declaradas e inicializadas na seguinte ordem: primeiro a variável de 32bit, depois as duas de 16 bit e, por fim, as de 8 bit.

Page 52: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página52 

Figura 30 – Uma Palavra, Meia Meia Palavra e Um Byte alinhados.

A Figura 30 mostra como ficou o mapa de memória, após a inicialização das variáveis em uma sequência diferente da apresentada no exemplo anterior.

 Figura 31 – Exemplo de “Structure Padding”.

Page 53: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página53 

Neste exemplo, para alinhar a memória, o compilador acrescentou bytes sem propósito de modo a manter o endereço das variáveis de 16 bit múltiplos de 2, esse processo é conhecido como “structure padding”.

Nota-se que o compilador não utilizou a memória de modo eficiente, pois poderia ter alocado duas variáveis de 8 bit nos endereços com final 452 e 456.

A Figura 32 mostra um exemplo de variáveis desalinhadas na memória. A variável do tipo inteiro de 32 bit encontra-se desalinhada, pois possui endereço com final D que não é um múltiplo de 4. O mesmo está ocorrendo com as variáveis de 16 bit, pois possuem endereço com final 1 e 7, que não são múltiplos 2.

A escrita e acesso desalinhado de memória geram operações não atômicas que diminuem o desempenho da CPU e reduzem o espaço de memória de programa. Este tipo de operação de acesso e escrita de memória podem ocasionar o travamento ou interrupção da CPU se não for tratado corretamente.

Figura 32 – Exemplo de variáveis desalinhadas na memória.

O exemplo a seguir mostra como o “Padding” pode afetar a comunicação MODBUS.

Exemplo: Uma rede MODBUS é composta por um dispositivo Mestre, um meio

físico e um ou mais escravos. A Figura 33 mostra uma rede composta por um Mestre (CLP), um escreva (o adaptador) e um meio físico RS485.

Figura 33 – Rede MODBUS.

Page 54: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página54 

Os dados que percorrem o meio físico RS485 são organizados em frames

MODBUS, como mostra a Figura 34. Eles possuem um campo de endereço, que especifica a operação a ser realizada “function code”, um campo de dados e um para o CRC.

Figura 34 – Frame MODBUS.

De acordo com as especificações MODBUS, o frame que realiza uma requisição é formado por 1 byte que define o “function code”, dois bytes que especificam o endereço do primeiro registrador de 16 bit a ser lido e, por fim, a quantidade de registradores a ser lido.

De modo semelhante, o frame da resposta é composto por um byte que contém o “function code”, um byte que especifica o número de registradores lidos e em seguida os valores dos registradores lidos.

A Figura 35 apresenta um exemplo de frame MODBUS que realiza a requisição da leitura de um sensor e outro frame que fornece a resposta.

 

Figura 35 – Exemplo de Requisição e Resposta de Frame MODBUS.

Observa-se que o frame MODBUS é estruturado em vários campos, e, portanto, poderia ser implementado na forma de estrutura na Linguagem de Programação C.

Page 55: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página55 

A estrutura facilitaria a manipulação dos campos, a compreensão do código e a serialização do frame. Para se serializar o frame, bastaria fornecer para a rotina de serialização o endereço do primeiro elemento da estrutura, enviar para a serial o primeiro byte, incrementar o endereço, enviar para a porta serial o segundo elemento e assim sucessivamente até o último byte do frame.

Neste exemplo, o valor do registrador, no campo de dados da resposta, não pode ser estimado porque depende do valor do nível de tensão na entrada do A/D, da resolução do A/D e da tensão de referência no A/D.

O código C que implementa a estrutura do frame, de acordo com a Figura 36, pode ser dividido em:

1) Estrutura do cabeçalho, contendo o endereço do escravo e o

“function code”; 2) Estrutura do “function code” que lê registradores: de acordo com

especificações MODBUS, a estrutura do “function code” para que o Mestre solicite a leitura de registradores para o Escravo é composta pelo endereço do primeiro registrador a ser lido seguido do número de registradores a serem lidos. Por outro lado, a estrutura do “function code” para que o Escravo responda solicitação de leitura do Mestre é composta pelo número de registradores lidos seguido dos valores dos registradores lidos;

3) Declaração da estrutura do Frame MODBUS com acréscimo do campo CRC.

Figura 36 – Exemplo de Requisição e Resposta de Frame MODBUS.

Page 56: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página56 

Por fim, a função utilizada na serialização do frame recebe como parâmetro o endereço do frame e o tamanho dele e envia os bytes para a porta serial.

A Figura 37 mostra o trecho da memória de um microcontrolador LPC2148 utilizado para armazenar os valores de um frame MODBUS.

Em roxo, no endereço com final 658 está o endereço do escravo. Em verde, no endereço com final 659 está o “function code”. Em amarelo, no endereço com final 65C está o endereço do primeiro registrador a ser lido. Novamente, em amarelo, no endereço com final 65E está o número de registradores. Em ciano, no endereço com final 660 está armazenado o CRC.

Em vermelho, dentro da estrutura, temos um elemento estranho. O famoso “PADDING”, cujo valor não pode ser previsto, porque é um valor qualquer presente na memória.

Conforme já comentado anteriormente, o “PADDING” ocorre porque a maior parte dos processadores prefere, ou até mesmo necessita, que o acesso a memória seja alinhado.

Figura 37 - Trecho de memória que armazena um Frame MODBUS em um LPC2148.

A Figura 38 mostra uma rede MODBUS RTU que utiliza o meio físico

RS485. Esta figura também mostra o código da estrutura do ModFrame e o código da rotina que envia os bytes do Frame MODBUS pela interface serial.

A presença do “Padding”, neste exemplo, traz as seguintes desvantagens:

Diminui a portabilidade;

Page 57: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página57 

eleva custo de desenvolvimento de novos produtos (plataformas diferentes);

gasto maior com manutenção de código (plataformas diferentes); Diminui o desempenho da rede; Necessita de microcontroladores mais caros (+memória); Localização e posição do “padding” depende do grau de otimização e do

compilador (GCC, Workbench, Vision...).

Figura 38 – Desvantagens do “Structure Padding” na transmissão serial.

Uma solução para o problema é copiar o conteúdo dos campos do frame para um buffer e em seguida enviar para a porta serial.

Page 58: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página58 

BOAS PRÁTICAS EM PROGRAMAÇÃO

Boas práticas em programação visam tornar o código mais legível, facilitar a operação de debug e favorecer a reutilização do código em outras aplicações.

Vale salientar que se o código for gerado para fins comerciais, os nomes de variáveis, funções, modificadores de tipo e comentários devem ser em inglês.

Na sequência são apresentadas algumas das práticas de programação mais comuns:

Escolher Bons Nomes Quando estiver escolhendo um nome para uma variável ou função, evite

nomes ambíguos, porque é melhor escolher nomes que descrevam o propósito da variável ou da função.

Nomes abreviados também devem ser evitados, pois outros programadores podem não entender o que a abreviação significa.

Um bom nome é aquele que descreve da melhor maneira possível, em apenas algumas palavras, a intenção da variável ou da função.

Por fim, os nomes das funções devem começar com letra maiúscula.

Variáveis e Modificadores de Tipo Consiste em boa prática em programação especificar o tipo da variável no

inicio do nome de cada variável, como sugerido na Tabela 11.

Tabela 11 – Identificadores sugeridos para especificar o tipo de variável

Tipo de Dados

Escala de Valores Identificador

Sugerido char Especificação do Compilador c

char8 uint8_t c8 int8_t -128 a 127 i8

uint8_t 0 a 255 u8 int16_t -32768 a 32767 i16

uint16_t 0 a 65535 u16 int32_t –2.147.483.648 a 2.147.438.647 i32

uint32_t 0 a 4.294.967.295 u32

int64_t -9.223.372.036.854.775.808 a +9.223.372.036.854.775.807 i64

uint64_t 0 a +18.446.744.073.709.551.615 u64 float32 ver IEEE 754 (float) f32 float64 ver IEEE 754 (double) f64

Page 59: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página59 

boolean FALSE e TRUE b void --- v

Deste modo, se for necessário declarar uma variável do tipo uint8_t,

chamada VelocidadeDoCarro, a variável deverá ser declarada da seguinte maneira:

uint8_t u8_VelocidadeDoCarro = 0; Uma variável chamada TemperaturaDoAr do tipo int16_t será declarada

do seguinte modo: uint16_t u16_AirTemperature = 0;

OBS: É muito importante ao se declarar uma variável inicializá-la com algum valor.

Seguindo a mesma linha de raciocínio, as variáveis do tipo ponteiro, os

vetores, as estruturas e os enum também devem ser especificados quando forem declarados. A Tabela 12 apresenta os identificadores sugeridos.

Tabela 12 – Identificadores sugeridos para os modificadores de tipo

Modificador de Tipo Identificador

Sugerido Arrays a

Enumeração ( enum ) en Pointers p

Structures ( struct ) st

Exemplo:

uint16_t VelocidadeDoMercedes = 258; uint16_t VelocidadeDaFerrari = 350; uint16_t VelocidadeDoBugatti = 407; uint16_t *p_VelocidadeDoCarro; p_VelocidadeDoCarro =&VelocidadeDoMercedes;

 

A linha de código ( uint16_t *p_CarSpeed; ) declara um ponteiro do tipo inteiro 16 bits cujo nome inicia com ( p ) conforme sugerido na Tabela 12. Este procedimento facilita o reconhecimento de uma variável do tipo ponteiro em um programa que possua muitas linhas de código, facilita a compreensão do código por outros programadores, favorece a reutilização de código, dentre outras vantagens.

Page 60: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página60 

Comentários Evitar o uso de comentários do tipo /* xxx */ dentro do corpo de funções.

Exemplo:

Correto

if (u8_Variavel1 != u8_Variavel2) { u16_pressao = 10000; // valor máximo .. } /******************************* * Inicializar_CPU ********************************/

void Inicializar_CPU(void) { .. }

Evitar

if (u8_Variavel1 != u8_Variavel2) { u16_pressao = 10000; /* valor máximo */ .. } void Inicializar_CPU(void) { /* Inicializar CPU */ .. }

Constantes Aconselha-se a não utilizar zero antes de constantes do tipo inteiro, porque

ela será tratada pelo compilador C como um número octal.

Por exemplo:

ToneladasDeLaranja = 120; ToneladasDePera = 071;

Neste exemplo, observa-se que a variável ToneladasDeLaranja assumiu o valor 120 em decimal, contudo, a variável ToneladasDePera assumiu o valor 57 em decimal e não 71 como se pretendia.

Chaves  

Chaves não podem ser evitadas, elas devem ser alocadas em uma linha própria, exceto na inicialização de array, quando vier após while em laços do tipo do-while ou após definição de nomes de tipos - Typedef.

Page 61: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página61 

Exemplo:

Correto

do { Código; }while( b_Fim == False);

if (u8_Largura != 10) { CalculaVolume( ); }

Evitar

if (u16_Largura < 1000) u32_Area = u16_Altura * u16_Largura;

if (u16_Largura < 1000){ u32_Area = u16_Altura * u16_Largura;} if (u16_Largura < 1000) { u32_Area = u16_Altura * u16_Largura; } if (u16_Largura < 1000) { u32_Area = u16_Altura * u16_Largura; }

Unions: A declaração union aloca uma única posição de memória onde podem ser armazenadas várias variáveis diferentes sendo que toda vez que se armazena um valor, o valor anterior é perdido. As declarações unions devem ser evitadas na programação de sistemas embarcados.

Goto: O comando goto realiza um salto para um local especificado por um label. Este comando não deve ser utilizado na programação de sistemas embarcados.

Exercício Proposto  

Aplicar as práticas de programação propostas nos programas apresentados como exemplo e nos programas propostos.  

Referências  

URL1: Página oficial da Network of Excellence on Embedded Systems Design. Disponível em:<http://pt.wikipedia.org/wiki/Sistema_embarcado>. Acesso em: março de 2011.

URL2: Página oficial da Network of Excellence on Embedded Systems Design. Disponível em:< http://www.artist-embedded.org/artist/>. Acesso em: junho de 2010.

Page 62: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página62 

URL3: Página oficial da SUN. Disponível em: < http://java.sun.com/products/cldc/overview.html#6>. Acesso em: julho de 2010.

URL4: Página oficial da Java Community Process. Disponível em: <http://jcp.org/en/jsr/detail?id=139>. Acesso em: julho 2010.

URL5: Página oficial da International Electrotechnical Commission. Disponível em: <http://www.iec.ch/zone/fsafety/pdf_safe/hld.pdf>. Acesso em julho 2010.

URL 6: Página oficial da Wikipedia, a encyclopédia livre. Disponível em: <http://pt.wikipedia.org/wiki/N%C3%BAmero_m%C3%A1gico_(inform%C3%A1tica)>. Acesso em abril 2011.

Edição e Revisão: Universidade Federal de Uberlândia Faculdade de Engenharia Elétrica

LASEC – Laboratório de Automação, Servomecanismos e Controle

www.lasec.feelt.ufu.br

STHS Tecnologia

http://www.sths.com.br

Prof. Fábio Vincenzi R. da Silva Eng. Gilson Fonseca Peres Filho

[email protected]

Agradecimentos  

Antes de começar a citar nomes, gostaríamos de agradecer a todos de modo geral, pois temos falado com muitas pessoas tanto no meio acadêmico quanto no comércio, indústria e serviços sobre os benefícios de se criar material didático para esta área de Sistemas Embarcados. A resposta de todos têm sido muito encorajamento e entusiasmo. Obrigado, vocês ajudaram muito.

Agradecemos a todos aqueles que contribuíram e que ainda contribuirão com exemplos e sugestões para melhorar este material didático e com apoio financeiro para a construção de kits didáticos utilizados nas aulas e laboratórios de pesquisa. Neste sentido, em nome de todos aqueles que já se beneficiaram e daqueles que irão se beneficiar com este material, nossos mais sinceros agradecimentos aos amigos:

Universidade Federal de Uberlândia Faculdade de Engenharia Elétrica – FEELT

Ernane Antônio Alves Coelho (Professor da FEELT - UFU) Felipe Adriano da Silva Gonçalves (Aluno da FEELT - UFU) Igor Borges Tavares (Aluno da FEELT - UFU) João Batista Vieira Júnior (Professor da FEELT - UFU) Leandro dos Santos Martins (Aluno de Mestrado da FEELT - UFU) Raony Barrios (Aluno da FEELT – UFU)

Page 63: Apostila de Sistemas Embarcados

1° Edição 03/2011 

Prof.FábioV.R.S.www.lasec.feelt.ufu.br&Eng.GilsonF.P.F.www.sths.com.br Página63