monografia - luiz fernando cruz v5
TRANSCRIPT
UNIVERSIDADE LUTERANA DO BRASIL CURSO DE CIÊNCIA DA COMPUTAÇÃO
CÂMPUS GRAVATAÍ
AUTOMAÇÃO RESIDENCIAL
REMOTA UTILIZANDO
SINALIZAÇÃO DTMF
Luiz Fernando Castro da Cruz
Monografia desenvolvida durante a disciplina de Trabalho
de Conclusão de Curso em Informática II e apresentada ao
Curso de Ciência da Computação da Universidade
Luterana do Brasil, campus Gravataí, como pré-requisito
para a obtenção do título de Bacharel em Ciência da
Computação.
Orientador: Prof. Júlio Carlos Balzano de Mattos
Gravataí, julho de 2007.
2
Universidade Luterana do Brasil – ULBRA
Curso de Ciência da Computação – Campus Gravataí
Reitor:
Pastor Ruben Eugen Becker
Vice-Reitor:
Eng. Leandro Eugênio Becker
Diretor do Campus Gravataí:
Prof. Felício Korb
Coordenadora do Curso de Ciência da Computação (Campus Gravataí):
Prof.ª Patrícia Nogueira Hübler
Coordenador das Disciplinas de Trabalho de Conclusão de Curso (Campus Gravataí):
Prof. Roland Teodorowitsch
Banca Avaliadora composta por: Data da defesa: 13/07/2007.
Prof. Júlio Carlos Balzano de Mattos (Orientador)
Prof. Elgio Schlemer
Prof.ª Roland Teodorowitsch
CIP – Catalogação na Publicação
CRUZ, Luiz Fernando
Automação Residencial Remota utilizando Sinalização DTMF /
Luiz Fernando Castro da Cruz; [orientado por] Júlio Carlos Balzano
de Mattos. – Gravataí: 2006.
72 p.: il.
Trabalho de Conclusão de Curso (Graduação em Ciência da
Computação). Universidade Luterana do Brasil, 2006.
1. Automação Residencial. 2. DTMF. 3. Microcontroladores. I.
Mattos, Júlio Carlos Balzano. II. Automação Residencial Remota
utilizando Sinalização DTMF.
Endereço:
Universidade Luterana do Brasil – Campus Gravataí
Avenida Itacolomi, 3.600 – Bairro São Vicente
CEP: 94170-240 – Gravataí – RS – Brasil
”A vida é aquilo que acontece enquanto você está ocupado
fazendo outros planos.”
John Lennon
Dedico este trabalho a um grande amigo que se fez
presente e inspirador em meu crescimento dentro da
informática, inclusive na essência deste trabalho. Meu
colega de trabalho e amigo Daniel Korb.
5
AGRADECIMENTOS
À minha família, em especial meu tio Gelson Queiroz, que me incentivou a estudar
informática e meu pai que me apóia nessa trajetória até hoje.
Ao professor José Luis Duizith, à coordenadora do curso Patrícia Hübler, e aos
funcionários Oscar Resende e Daniel Korb, que acreditaram no meu potencial.
Ao meu orientador e professor Júlio por sua dedicação e competência, e à direção e
supervisão do meu emprego pela compreensão do momento de desenvolvimento deste
trabalho.
Aos colaboradores diretos ou indiretos deste trabalho Fabrício Assis, Alexandre
Parreira, minha irmã Carolina e, em especial, ao colega Odone Soledar.
Grandes colegas, companheiros e amigos como Rodrigo, Cassius e Michele também
merecem meus sinceros agradecimentos.
SUMÁRIO
LISTA DE FIGURAS ............................................................................................................... 7
LISTA DE TABELAS .............................................................................................................. 8
LISTA DE QUADROS ............................................................................................................. 9
LISTA DE ABREVIATURAS E SIGLAS ............................................................................ 10
RESUMO ................................................................................................................................. 11
ABSTRACT ............................................................................................................................. 12
1 INTRODUÇÃO .................................................................................................................. 13 1.1 OBJETIVOS DO TRABALHO ............................................................................................ 14
1.2 ORGANIZAÇÃO DO TEXTO ............................................................................................ 14
2 AUTOMAÇÃO RESIDENCIAL ...................................................................................... 15 2.1 RETROFITTING ............................................................................................................. 18
2.2 REDES DOMÉSTICAS ..................................................................................................... 18
3 SINALIZAÇÃO DTMF ..................................................................................................... 20
4 DESCRIÇÃO DA SOLUÇÃO .......................................................................................... 22 4.1 APLICAÇÃO CLIENTE REMOTA ...................................................................................... 22
4.1.1 Plataforma J2ME ................................................................................................. 23
4.1.2 Implementação da aplicação ................................................................................ 25
4.2 DISPOSITIVO SERVIDOR LOCAL .................................................................................... 29
4.2.1 Parte atendedora ................................................................................................... 30
4.2.2 Parte decodificadora ............................................................................................ 31
4.2.3 Parte controladora ................................................................................................ 33
4.2.4 Parte ativadora ..................................................................................................... 38
4.3 COMUNICAÇÃO ENTRE CLIENTE E SERVIDOR ................................................................ 39
4.3.1 Descrição do protocolo ........................................................................................ 40
4.4 ANÁLISE DA SOLUÇÃO ................................................................................................. 44
5 CONCLUSÃO .................................................................................................................... 46
ANEXO A – CÓDIGO-FONTE DA CLASSE PRINCIPAL DA APLICAÇÃO
CLIENTE ............................................................................................................................ 47
ANEXO B – CÓDIGO-FONTE DA CLASSE RECORD STORE PERSONAL .............. 63
ANEXO C – CÓDIGO-FONTE DA PARTE CONTROLADORA ................................... 66
REFERÊNCIAS ...................................................................................................................... 71
LISTA DE FIGURAS
Figura 1 – Benefícios da automação residencial ...................................................................... 16
Figura 2 – Controle remoto ...................................................................................................... 17
Figura 3 – Aparelhos telefônicos por tipo de sinalização ......................................................... 20
Figura 4 – Combinação de tons em freqüências diferentes ...................................................... 21
Figura 5 – Ambiente e componentes da solução ...................................................................... 22
Figura 6 – Estrutura da aplicação cliente remota ..................................................................... 23
Figura 7 – Plataformas Java...................................................................................................... 24
Figura 8 – Menu inicial da aplicação........................................................................................ 26
Figura 9 – Tela de Configurações............................................................................................. 26
Figura 10 – Tela de Controle .................................................................................................... 28
Figura 11 – Comunicação entre as partes do dispositivo servidor local .................................. 29
Figura 12 – Circuito detector de chamada telefônica ............................................................... 30
Figura 13 – Circuito atendedor de chamada ............................................................................. 31
Figura 14 – Esquema básico de ligação do CI 8870................................................................. 32
Figura 15 – Kit Cerebot e suas ligações ................................................................................... 36
Figura 16 – Circuito de amplificação de sinal .......................................................................... 38
Figura 17 – Exemplo de ligação de um relé ............................................................................. 39
Figura 18 – Camadas da solução .............................................................................................. 39
Figura 19 – Alterações do formato dos dados na solução ........................................................ 40
Figura 20 – Fluxo de tratamento do protocolo ......................................................................... 41
Figura 21 – Expressão regular do protocolo da solução ........................................................... 41
Figura 22 – Autômato finito determinístico que define o protocolo de comunicação ............. 42
Figura 23 – Exemplo do cálculo Módulo 11 ............................................................................ 43
Figura 24 – Simulação de seqüências de tons .......................................................................... 44
Figura 25 – Tons verificadores calculados ............................................................................... 45
LISTA DE TABELAS
Tabela 1 – Freqüências DTMF e teclas correspondentes ......................................................... 21
Tabela 2 – Freqüências DTMF de eventos telefônicos ............................................................. 21
Tabela 3 – Saídas do CI 8870 por tom DTMF .......................................................................... 32
Tabela 4 – Componentes da parte decodificadora .................................................................... 33
Tabela 5 – Portas do kit Cerebot X Portas do microcontrolador Atmega64............................. 35
Tabela 6 – Configuração de sensibilidade de interrupção no Atmega64 .................................. 37
LISTA DE QUADROS
Quadro 1 – Sistemas residenciais automatizáveis .................................................................... 15
Quadro 2 – Benefícios aos usuários ......................................................................................... 16
Quadro 3 – Comparação entre soluções de redes ..................................................................... 19
Quadro 4 – Requisitos do profile MIDP ................................................................................... 24
Quadro 5 – Classes utilizadas na aplicação cliente .................................................................. 25
Quadro 6 – Métodos da classe RecordStorePersonal .............................................................. 27
Quadro 7 – Estrutura do RecordStore CONFIGS .................................................................... 27
Quadro 8 – Vantagens e desvantagens da solução ................................................................... 45
LISTA DE ABREVIATURAS E SIGLAS
AFD Autômato Finito Determinístico
API Application Programming Interface
ATX Advanced Technology Extended
BACnet Building Automation and Control Network
CAN Controller Area Networks
CDC Connected Device Configuration
CEBus Consumer Eletronic Bus
CI Circuito Integrado
CLDC Connected Limited Device Configuration
CSMA/CD Carrier Sense Multiple Access with Collision Detection
DDD Discagem Direta à Distância
DDR Data Direction Register
DFPQ Distributed Fair Priority Queuing
DTMF Dual Tone Multi Frequential
GSM Global System for Mobile Communications
HPNA Home Phoneline Networking Alliance
HTTPS HiperText Transfer Protocol Secure
IR Infrared
JAR Java Archive
JTAG Joint Test Action Group
JVM Java Virtual Machine
J2EE Java 2 Enterprise Edition
J2ME Java 2 Micro Edition
J2SE Java 2 Standard Edition
MAC Media Access Control
MIDP Mobile Information Device Profile
PDA Personal Digital Assistants
RAM Random Access Memory
RMS Record Management System
ROM Read Only Memory
SIM Subscriber Identity Module
SPI Serial Peripheral Interface
UPnP Universal Plug and Play
URL Uniform Resource Locator
USB Universal Serial Bus
UTP Unshielded Twisted Pair
XML Extencible Markup Language
11
RESUMO
Atualmente, existem poucas soluções de automação residencial disponíveis no
mercado, principalmente modelos de baixo custo e que não necessitam de grandes alterações
estruturais no ambiente doméstico. Este trabalho descreve uma solução voltada à área de
automação residencial, onde é possível ativar e desativar remotamente elementos residenciais.
O modelo é composto de uma aplicação cliente, instalada em um telefone móvel celular, e um
dispositivo servidor, conectado à linha telefônica de uma residência. O dispositivo servidor
possui portas onde podem ser conectados eletrodomésticos e sistemas residenciais. Este tem
como componente principal um microcontrolador de baixo custo, responsável pela
interpretação dos comandos recebidos. A comunicação entre a aplicação cliente remota e o
dispositivo servidor local é feita utilizando a sinalização DTMF, tendo os tons transmitidos
através da rede de telefonia.
Palavras-chaves: Automação residencial; DTMF; Microcontroladores.
ABSTRACT
Title: “Remote Residential Automation using DTMF Signals”
Nowadays, there are few solutions of residential automation in the market, mainly low
cost solutions and solutions that do not change the current houses structure. This work
presents a residential automation solution, where it is possible to activate and disable
residential elements remotely. The model is composed by a client application installed in a
cellular phone and a server device connected to the residential phone line. The server device
ports can be connected to domestic appliances. The main component of the server device is a
low cost microcontroller, responsible for the execution of the received commands. The
communication between the client application and the server device is made using DTMF
signals, transmitted using the telephone net.
Key-words: Residential automation; DTMF; Microcontrollers.
1 INTRODUÇÃO
Cada vez mais é necessária a automatização de processos de nosso cotidiano. A
automação residencial veio para suprir esta necessidade, porém ainda não é uma realidade na
grande maioria das residências, provavelmente devido ao custo elevado e poucas soluções
disponíveis no mercado. A carência de soluções na área residencial está diretamente ligada ao
fato dos fabricantes de dispositivos e prestadores de serviço terem optado por atender em um
primeiro momento à área industrial, e posteriormente a predial.
Inicialmente, tanto as áreas predial quanto residencial utilizavam tecnologias oriundas
da automação industrial. Porém, com o passar do tempo, observou-se que, tanto a automação
predial quanto a residencial, possuíam características específicas, o que fez com que o
mercado desenvolvesse soluções para atender as necessidades particulares de cada área
(ARAUJO, 2005).
A automação residencial visa agilizar e facilitar os processos residenciais através de
soluções inteligentes, programáveis e centralizadas, proporcionando satisfação sem que seja
necessária a intervenção contínua dos usuários. Dentre os benefícios proporcionados
destacam-se: a segurança, trazendo proteção a eventuais invasões, vazamentos de água e gás e
incêndios; o conforto, com controle de temperatura ambiente, iluminação e acesso; e a
economia de energia, racionando o consumo na iluminação, temperatura e eletrodomésticos.
Uma parte muito importante em uma solução deste tipo é a interface. Interfaces
amigáveis, ágeis e simplificadas são imprescindíveis, visto que a automação residencial tem
como objetivo facilitar tarefas.
O mercado atual de automação residencial vem exigindo soluções para novos anseios,
não bastando simplesmente automatizar as tarefas do cotidiano doméstico com conforto,
disponibilidade, rapidez e acessibilidade. As soluções atuais devem aproveitar ao máximo os
recursos pré-existentes e promover formas integradas de entretenimento e informação
distribuída. A maior contribuição para este fato é a expansão e facilidade de acesso à
informática nas residências, e a disponibilidade de eletrodomésticos com muitos formas de
conexão e recursos multimídia a preços atraentes.
Novas tecnologias tendem a seguir um modelo onde a localização geográfica não
impede sua utilização. Na automação residencial não é diferente. Ativar alarmes, acender
luzes, fechar janelas, controlar eletrodomésticos, dentre outras, são tarefas que podem ser
automatizadas e tornam-se muito mais interessantes com a possibilidade de serem executadas
remotamente. Esta capacidade de controlar dispositivos remotamente é chamada de teleação.
14
Hoje, têm-se buscado minimizar o impacto de adaptação de uma residência não
projetada para receber a automação, através de soluções que utilizam meios comuns e
disponíveis como, por exemplo, as redes de eletricidade e telefonia.
1.1 OBJETIVOS DO TRABALHO
O objetivo deste trabalho é apresentar uma solução de baixo custo e fácil instalação,
capaz de controlar remotamente dispositivos de uma residência. O modelo idealizado consiste
na centralização do controle em uma aplicação para telefones celulares, que utilizará tons
DTMF para comunicar-se, através da rede de telefonia, com um dispositivo baseado em um
microcontrolador, instalado em uma linha telefônica presente na residência que se deseja
automatizar, acionando relés ligados a elementos residenciais, de acordo com a vontade do
operador da aplicação.
1.2 ORGANIZAÇÃO DO TEXTO
No capítulo 2 estão apresentados os principais conceitos referentes à automação
residencial, benefícios que ela proporciona, processo de adaptação de residências e opções de
infra-estrutura de redes domésticas. O capítulo 3 descreve o funcionamento da sinalização
DTMF, que é hoje o sistema de sinalização da grande maioria das redes de telefonia do
mundo. A solução desenvolvida neste trabalho é detalhadamente descrita no capítulo 4,
apresentando os principais componentes da solução, protocolo de comunicação utilizado,
técnicas e recursos utilizados na implementação, e uma análise revelando vantagens e
desvantagens do modelo proposto. Por fim, no capítulo 5, são apresentadas as conclusões e
trabalhos futuros.
2 AUTOMAÇÃO RESIDENCIAL
Parmegianni (2003) define automação como “a técnica de fazer com que um processo,
sistema ou aparelho opere automaticamente através de dispositivos mecânicos, eletrônicos ou
eletromecânicos que possam simular operadores humanos”. A automação residencial também
é conhecida como domótica, que é composta pelas palavras domus, que significa casa em
latim, e robota que significa robótica em tcheco. A domótica é a área responsável pela
automação do ambiente residencial. A enciclopédia digital Wikipedia define a palavra
domótica como “o termo que designa a utilização da eletrônica e da informática para melhorar
a funcionalidade e o conforto de uma casa ou edifício” (WIKIPEDIA, 2007-a).
O principal objetivo da automação residencial é facilitar o uso de equipamentos com
rapidez, disponibilidade e segurança, proporcionando maior conforto. As soluções devem
proporcionar este conforto de forma simples, facilitando a interação do usuário com o sistema.
O Quadro 1 apresenta os sistemas comuns de uma residência que podem ser
beneficiados pela automação residencial.
Quadro 1 – Sistemas residenciais automatizáveis
Sistema Detalhes
Telefonia Secretária eletrônica, comunicadores e serviços de mensagens.
Informática Rede doméstica, acesso compartilhado, serviços via Internet.
Elétrico Controle de cargas, sistema de distribuição, monitoramento de falhas,
sistema de geração de emergência, tarifações setorizadas.
Segurança Alarmes, monitoramento, controle de acesso, prevenção de acidentes,
iluminação de segurança, simulador de presença, controle de rondas.
Iluminação Iluminação ambiente, iluminação decorativa, iluminação externa.
Controle predial Elevadores, aspiração central, porteiros eletrônicos.
Hidráulico e gás Aquecimento e pressurização de água, irrigação externa, manutenção de
piscinas, sistema de controle e distribuição de gás.
Entretenimento Home-Theater, TV por assinatura, distribuição de vídeo, som ambiente,
jogos.
Climatização Ar-condicionado, ventilação, controle de janelas e cortinas.
Os benefícios proporcionados pela automação residencial concentram-se basicamente
em segurança, conforto, economia de energia e comunicação. O Quadro 2 apresenta os
principais benefícios aos usuários da automação residencial, com detalhes e exemplos.
16
Quadro 2 – Benefícios aos usuários
Benefício Detalhes / Exemplos
Economia de
energia
A energia é utilizada apenas onde e quando é realmente necessária.
Controle remoto, temporizadores e sensores podem eliminar gastos
desnecessários.
Conveniência Monitoramento remoto, centralizadores de comandos, ações baseadas
em previsão ou programação e controle centralizado.
Segurança
Circuito fechado de TV, onde um visitante pode ser visto de qualquer
televisor da residência. Simulação de presença no interior da
residência utilizando os sistemas de iluminação e som, por exemplo.
Economia de tempo
e esforço
Programar o sistema de som para que baixe o volume quando o
telefone tocar e programar o sistema de iluminação baseado no dia da
semana.
Conforto
Ajuste de temperatura de piscinas, banheiras, aquecedores, ar-
condicionados através de sensores, previsão e programação com
interface inteligente.
Acessibilidade
Para o segmento de usuários com deficiências a automação
residencial não é só uma questão de conveniência, mas também de
adaptação e uma ferramenta que auxilia na independência dentro
deste ambiente.
Sistemas operados por toque ou voz.
Valorização do
imóvel
Residências que incluem tecnologia de automação residencial
possuem uma gama maior de compradores, facilidade de venda e
maior valor agregado.
Abaixo, a Figura 1 ilustra uma residência que usufrui de alguns dos benefícios
descritos anteriormente, como sistema de segurança com câmera de vigilância e alarme,
sistemas de climatização e iluminação, entretenimento integrado, e facilidades como portão
automático, portas sem chave e qualidade da água da piscina (AMORY e PETRINI, 2001).
Figura 1 – Benefícios da automação residencial
Além das vantagens de utilização proporcionadas, a automação residencial também
proporciona a valorização do imóvel. Este fato faz com que, cada vez mais, empresas
17
construtoras projetem residências preparadas para o uso destas tecnologias ou mesmo já as
incluindo.
Seu público-alvo é composto por: pessoas práticas; pessoas que acompanham a
evolução tecnológica; pessoas que primam pelo conforto; pessoas que dispõem de pouco
tempo; pessoas que desejam maior segurança; e pessoas que desejam valorizar o imóvel.
Observando a evolução das tecnologias é possível perceber que a automação se baseia,
principalmente, em 3 áreas: comunicação de dados, inteligência artificial e interface homem-
máquina. A comunicação garante que os dados possam fluir através das camadas. A
inteligência permite aos dispositivos alterarem o seu comportamento sem a intervenção
humana, através da percepção do estado do ambiente. A interface é a responsável pela
qualidade da interação entre o usuário e os dispositivos, sendo a parte de maior impacto no
sucesso de uma solução de automação residencial (PARMEGGIANI, 2003).
Dentro das idéias propostas destaca-se a possibilidade de controlar dispositivos
remotamente. Este recurso tem o nome de teleação e surgiu da necessidade de interligar a rede
interna de uma casa com redes externas, de forma que os moradores possam controlar,
monitorar e administrar seu lar à distância conforme pode ser visualizado na Figura 2
(AMORY e PETRINI, 2001).
Figura 2 – Controle remoto
O grande desafio na automação residencial é a integração dos dispositivos com troca e
compartilhamento de informações e ações baseadas no ambiente como um todo. Um cenário
para representar esta idéia seria um relógio, que forneceria data e hora para os dispositivos, ao
invés de cada um deles ter sua própria fonte destas informações. Qualquer alteração na data
ou hora do relógio refletiria em todos os dispositivos.
Outra grande dificuldade está na falta de padrões, tanto de infra-estrutura como de
comunicação. A padronização evitaria que para cada dispositivo adicionado à residência se
tenha a necessidade de modificar a estrutura da solução.
A comunicação em uma solução de automação residencial pode utilizar tanto um
protocolo proprietário, onde a compatibilidade normalmente só acontece entre produtos da
própria empresa desenvolvedora do padrão, quanto um protocolo aberto, que proporciona
compatibilidade entre diferentes dispositivos de diferentes empresas. Um padrão define uma
arquitetura para interligação dos dispositivos e o protocolo que será implementado para
permitir a comunicação entre eles (ARAUJO, 2005).
O ambiente residencial automatizado é composto por dispositivos inteligentes que são
os componentes que realizam as tarefas. Estes dispositivos podem ser divididos basicamente
em atuadores, que recebem instruções do gerenciador e as executa, e sensores, que são
18
responsáveis por transmitir informações do estado do ambiente analisado ao gerenciador
(CORUJA, 2005).
2.1 RETROFITTING
Um projeto de automação pode ser melhor dimensionado quando previsto na fase
inicial da construção do imóvel. Porém, a maioria das residências não possuem estrutura física
ideal para implantação, sendo necessário um processo de adaptação. Esta adaptação de
residências para receber um sistema eletrônico é denominada retrofitting (BOLZANI, 2004).
Comparando intervenções realizadas em construções recentes com antigas, nota-se que
as antigas necessitam de um grande conjunto de mudanças para integrar novos equipamentos.
Nesta mudança deve-se procurar utilizar soluções que não aumentem muito o custo de
implantação e não alterem o estilo da residência.
Antes de qualquer intervenção em uma residência que se deseja automatizar, deve-se
fazer um estudo detalhado, avaliando equipamentos e sistemas. Após este levantamento
definem-se níveis de automação para cada item, a segurança a ser implantada, e as condições
a serem obedecidas pelo sistema de informações. Também é preciso definir interfaces de
comunicações entre subsistemas, e interfaces para equipamentos já existentes na residência.
Todo este processo de adaptação de uma residência não projetada a receber a
automação deve ser documentado, detalhando todas as modificações até a finalização da obra,
inclusive contendo plantas e mapa de cabeamento (BOLZANI, 2004).
2.2 REDES DOMÉSTICAS
As redes domésticas são interconexões de eletro-eletrônicos de uso residencial através
de um meio que possibilite a troca de dados entre eles (BOLZANI, 2004).
Existem alguns fatores de grande relevância em uma solução de automação
residencial, que são o meio físico em que as informações trafegam e protocolo utilizado para
que esta comunicação aconteça, formando uma rede doméstica, muitas vezes extensível a
pontos externos de controle remoto.
Dentre as soluções de redes destacam-se:
Ethernet – é a principal forma de interligação de computadores em redes, e
uma das melhores alternativas como plataforma para redes domésticas. Utiliza
o protocolo CSMA/CD para coordenar o acesso ao meio físico. O
endereçamento é feito com base numa seqüência de 48 bits, denominada
endereço MAC.
Wi-Fi (802.11b / 802.11g) – este padrão permite a transmissão de dados sem
fio. Algumas soluções proprietárias a utilizam com o propósito de comando
remoto, tornando-as mais flexíveis e práticas. A especificação 802.11b pode
coexistir à Ethernet com fio, tendo um funcionamento compatível e
comparável com esta. A especificação 802.11g provê taxas de até 20Mbps,
superiores aos 11Mbps do 802.11b.
Home PNA (Home Phoneline Networking Alliance) – esta solução utiliza o
padrão Ethernet 802.3 sobre cabeamento telefônico. Porém, a camada MAC
tradicional foi substituída pela HPNA 2.0 que introduz oito níveis de
19
prioridade de acesso e uma técnica de tratamento de colisão denominada
DFPQ (Distributed Fair Priority Queuing) que minimiza os efeitos da
implementação em um meio físico diferente do UTP categoria 5 utilizado em
cabeamento estruturado em redes de computadores.
Powerline Home Plug – utiliza a rede de energia elétrica como meio físico
para transmissão dos dados. Esta solução utiliza um chipset PowerPacket que
reúne todos os circuitos necessários para transmissão via rede elétrica a
14Mbps.
Bluetooth – utiliza sinais de rádio de alta freqüência e curto alcance. Os
transmissores utilizados nesta solução consomem pouquíssima energia e
ocupam áreas muito pequenas, menores que 1cm². Possui uma baixa taxa de
operação de 1Mbps e se limita a distancia de operação de 10 metros para uma
comunicação com qualidade.
ZigBee – é uma solução equivalente ao Bluetooth, mas com uma taxa de
transmissão menor, entre 20 e 250Kbps, porém com um alcance muito maior,
de até 100 metros com boa qualidade de transmissão. Possibilita a interligação
de até 250 nós por rede.
O Quadro 3 apresenta uma comparação entre as soluções citadas acima, descrevendo
suas necessidades e principais problemas (BOLZANI, 2004).
Quadro 3 – Comparação entre soluções de redes
Solução Descrição Velocidade Necessidades Problemas
Ethernet Conexões entre
computadores Até 1000Mbps
Placas de rede e cabo
UTP categoria 5
Impossibilidade
em alguns
retrofittings e
alto custo
Wi-Fi
(802.11b /
802.11g)
Rede sem fio
Até
11Mbps (802.11b) e
54Mbps (802.11g)
Um ponto de acesso e
uma placa de rede
wireless para cada
componente
Segurança e alto
custo
Home
PNA
Rede de dados
que utiliza o
cabeamento
telefônico
Até 128Mbps
Um adaptador e acesso
à linha telefônica para
cada dispositivo
Poucos
fabricantes de
componentes
Powerline
Home
Plug
Rede de dados
que utiliza a
fiação elétrica
Até 30Mbps Um adaptador por
dispositivo
Poucos
fabricantes de
componentes e
alto custo
Bluetooth Conexão sem
fio Até 1Mbps
Um adaptador por
dispositivo
Velocidade e
alcance baixos
ZigBee
Rede de
controle sem
fio
Até 0.3Mbps Um adaptador por
dispositivo
Velocidade
baixa
Além das soluções citadas acima existem outras tantas muito utilizadas, por exemplo:
CEBus (Consumer Eletronic Bus), Enikia, INARI Powerline, X-10, IR – Infravermelho,
Sharewave, LonWorks, BACnet, Konnex KNX, Siemens Instabus, CAN (Controller Area
Networks), ETI Alliance, UPnP (Universal Plug and Play), JINI, Echonet, dentre outras.
20
3 SINALIZAÇÃO DTMF
Hoje a sinalização DTMF é o padrão das redes de telefonia de todo o mundo e são
largamente utilizados na implementação de sistemas de baixo custo que necessitam troca de
poucas informações.
Antigamente a discagem dos telefones era feita utilizando a sinalização decádica, mais
conhecida como discagem por pulso. Neste tipo de sinalização, ao se ocupar a linha, um laço
era fechado, e ocorriam interrupções tantas vezes quanto o número discado. Por exemplo, ao
discar a tecla 8 através do disco do telefone, o laço era aberto 8 vezes. A posição 0 causava 10
aberturas no laço.
Devido o surgimento dos telefones com teclado (substituindo o disco telefônico),
centrais telefônicas modernas e disseminação de filtros analógicos e posteriormente digitais,
passou-se a utilizar uma combinação de tons em freqüências diferentes para sinalização
telefônica. O sistema de sinalização DTMF, também conhecido como touch tones, foi
desenvolvido pela Bell Labs, visando permitir a discagem DDD que utiliza enlaces sem fio
como os de micro-ondas e por satélite (WIKIPEDIA, 2007-b). A Figura 3 mostra um aparelho
telefônico que utiliza a sinalização decádica e outro que utiliza a sinalização DTMF.
Figura 3 – Aparelhos telefônicos por tipo de sinalização
Cada tecla do telefone (do 0 ao 9, mais os caracteres “*” e “#”) é representada por um
par de tons, um de baixa e outro de alta freqüência. Apesar dos aparelhos telefônicos
utilizarem somente 12 teclas, ainda existem outros 4 tons (do A ao D) que são basicamente
utilizados por técnicos em telefonia e pelo exército. Diferentemente da sinalização decádica
que envia impulsos elétricos para a central telefônica, a sinalização DTMF envia tons audíveis
(sinais de freqüência). A Tabela 1 apresenta as freqüências DTMF e teclas correspondentes.
21
Tabela 1 – Freqüências DTMF e teclas correspondentes
Freqüências altas F
req
üên
cia
s
baix
as
1209 Hz 1336 Hz 1477 Hz 1633 Hz
697 Hz 1 2 3 A
770 Hz 4 5 6 B
852 Hz 7 8 9 C
941 Hz * 0 # D
Um tom DTMF nada mais é do que a combinação de dois tons de freqüências
diferentes como mostra a Figura 4.
Figura 4 – Combinação de tons em freqüências diferentes
Além dos tons que representam os dígitos do teclado telefônico (mais do A ao D)
existem freqüências que representam eventos telefônicos, apresentados na Tabela 2.
Tabela 2 – Freqüências DTMF de eventos telefônicos
Evento Freqüência baixa Freqüência alta
Tom de ocupado 480 Hz 620 Hz
Tom de discagem 350 Hz 440 Hz
Tom de chamada 440 Hz 480 Hz
As freqüências foram escolhidas de forma a evitar harmônicas, ou seja, nenhuma
freqüência é múltipla de outra e o resultado da diferença ou da soma de duas freqüências
nunca iguala a uma das freqüências (SGT, 2007).
A duração mínima dos tons deveria ser de no mínimo 70 ms, embora algumas
aplicações consigam identificar confiavelmente tons em um período tão curto quanto 45 ms.
22
4 DESCRIÇÃO DA SOLUÇÃO
A solução é composta por uma aplicação cliente, instalada em um telefone móvel
celular, e um dispositivo servidor baseado em um microcontrolador, conectado a uma linha
telefônica da residência que se deseja automatizar. A comunicação acontece utilizando um
protocolo próprio que designa um padrão na seqüência dos tons DTMF enviados da aplicação
cliente para o dispositivo servidor. São previstos os comandos de ligar e desligar para os
dispositivos ligados ao dispositivo servidor local. A Figura 5 ilustra o ambiente com os
componentes da solução.
Figura 5 – Ambiente e componentes da solução
A solução permite minimizar o processo de retrofitting de residências não preparadas
para receber a automação de processos. Para instalação da solução são necessários apenas 3
passos: instalação da aplicação cliente em um telefone celular, ligação do dispositivo servidor
em uma linha telefônica da residência, e ligação dos aparelhos da residência às saídas do
dispositivo servidor local.
A solução proposta tem como objetivo cobrir somente os conceitos básicos da
automação residencial, como centralização de tarefas e controle remoto, não abordando, por
exemplo, comunicação entre dispositivos controlados e modelo estrutural interno da
residência.
4.1 APLICAÇÃO CLIENTE REMOTA
A aplicação cliente remota apresenta ao usuário uma interface simplificada e intuitiva
utilizada para interagir com os recursos disponíveis da residência. O processo de envio dos
comandos definidos na aplicação consiste em primeiramente discar para o número de telefone
onde o dispositivo servidor local está conectado e, após atendida a chamada, enviar os tons
DTMF no padrão estabelecido pelo protocolo de comunicação.
Para evitar que a cada envio de comando se tivesse que discar e digitar senha optou-se
por criar uma parte onde fosse possível armazenar dados persistentes, ou seja, que mesmo
desligando o aparelho celular estes não fossem perdidos. A Figura 6 mostra as duas partes que
23
compõem a aplicação: parte de configurações onde são definidos parâmetros fixos da
aplicação que ficam armazenados persistentemente, e a parte de controle, que utiliza os
parâmetros definidos na parte de configurações juntamente com parâmetros de comando
definidos a cada envio.
Figura 6 – Estrutura da aplicação cliente remota
Foi utilizada a linguagem Java sobre a plataforma para dispositivos móveis J2ME para
o desenvolvimento da aplicação. Antes de detalhar este desenvolvimento é descrita a estrutura
básica da plataforma.
4.1.1 Plataforma J2ME
A plataforma J2ME é uma edição da linguagem Java projetada para dispositivos com
memória, vídeo e poder de processamento limitados. Esta tecnologia disponibiliza uma
linguagem de programação fácil de dominar (Java), um ambiente em tempo de execução que
oferece uma plataforma segura e portável e acesso a conteúdo dinâmico, além de contar com
uma comunidade de aproximadamente 2 milhões de programadores (MUCHOW, 2004). O
J2ME atende uma grande variedade de dispositivos eletrônicos graças a sua estrutura formada
basicamente por configurations, profiles e APIs opcionais.
A parte mais básica que necessita estar presente em todo e qualquer dispositivo que
suporte esta tecnologia é a configuration. Existem duas configurations, a CLDC (Connected
Limited Device Configuration) que rege as configurações para aparelhos bem pequenos como
celulares e PDAs, e a CDC (Connected Device Configuration) que é uma extensão da CLDC
para atender aparelhos um pouco maiores e geralmente fixos como televisão digital e sistemas
automotivos. A CDC utiliza a máquina virtual JVM J2SE, já a CLDC utiliza uma máquina
mais limitada, a KVM. A KVM necessita de 40 a 80KB de memória de programa, 20 a 40KB
de memória dinâmica heap e pode ser executada em processadores com baixo desempenho
como, por exemplo, processadores de 16 bits com freqüência de 25MHz.
Um profile é um conjunto de bibliotecas para um tipo particular de dispositivo, que
combinadas a uma configuration provêem um serviço completo para que aplicações possam
ser executadas. O profile mais utilizado é o MIDP (Mobile Information Device Profile), que
junto ao CLDC aparece em quase todos os celulares do mercado atual (CARNIEL e
TEIXEIRA, 2005).
24
A Figura 7 apresenta as diferentes edições de Java e suas camadas. A coluna 1 indica a
plataforma J2EE destinada a aplicativos baseados em servidor, a coluna 2 a plataforma J2SE
projetada para execução em máquinas simples como computadores pessoais, as coluna 3 e 4 a
plataforma J2ME projetada para dispositivos com memória, vídeo e poder de processamento
limitados, e por fim a coluna 5 destinada a smart-cards e dispositivos similares como cartões
SIM utilizados em celulares GSM (MUCHOW, 2004).
Figura 7 – Plataformas Java
O profile MIDP, normalmente utilizado em telefones celulares, possui alguns
requisitos de hardware e software, estes listados no Quadro 4.
Quadro 4 – Requisitos do profile MIDP
Hardware Software
Tela mínima 96 x 54 pixels Gráficos Suporte à escrita de gráficos
bitmap na tela
Entrada de
usuário
Teclado de telefone, teclado
QWERTY1 ou tela de toque
Sistema
operacional
Fornecer agendamento mínimo,
tratamento de exceções,
processamento de interrupções, e
recursos para executar JVM
Memória ROM 128KB para componentes MID
8KB para dados persistentes
Entrada de
usuário
Aceitar a entrada e passar as
informações para a JVM
Memória RAM 32KB Persistência Recursos de leitura e escrita
Rede Com conectividade sem fio Rede Acesso a recursos de interligação
em rede
A MIDP versão 2.0 possui suporte HTTPS, soquetes e datagramas, extensões para a
interface de baixo nível e um analisador XML.
Um aplicativo projetado para ser executado em um dispositivo móvel é uma MIDlet,
que tem como classes básicas a CLDC e a MIDP. Para a distribuição de uma MIDlet ou um
conjunto delas, estas são empacotadas em uma única entidade conhecida como arquivo JAR
(MUCHOW, 2004).
1 QWERTY é o layout de teclado utilizado em computadores, e seu nome vem das primeiras 6 letras que formam a palavra
QWERTY (WIKIPEDIA, 2007-c).
25
4.1.2 Implementação da aplicação
Para o desenvolvimento da aplicação foi utilizado o ambiente gráfico NetBeans, na
versão 5.5, com o pacote adicional para desenvolvimento de aplicações que utilizam a
configuration CLDC. Este pacote adicional inclui um emulador de telefone celular.
Para que fosse possível efetuar uma chamada a partir da aplicação se escolheu a
profile MIDP versão 2.0, que disponibiliza a função platformRequest para este e outros fins.
O profile MIDP 2.0 provê um conjunto de classes próprias para desenvolvimento de
aplicações para telefones celulares. Dentre as classes disponíveis foram utilizadas as
apresentadas no Quadro 5.
Quadro 5 – Classes utilizadas na aplicação cliente
Classe Descrição
SplashScreen Utilizada para telas de abertura de aplicações
List Utilizada para listas de opções de menus
ListElement Classe que se refere a cada elemento dentro de um List
Form Utilizada para criação de formulários, onde serve de recipiente
para outros elementos
ChoiceGroup Utilizada para escolha única ou múltipla de elementos
ChoiceElement Refere-se a cada elemento dentro de um ChoiceGroup
TextField Utilizada para entrada de texto e números
StringItem Utilizada para fazer indicações textuais fixas (rótulos)
WaitScreen Utilizada para telas de espera enquanto uma determinada tarefa
executa. A tarefa é definida pela classe SimpleCancellableTask.
A classe WaitScreen também retorna se houve sucesso ou falha
na execução da tarefa
Alert Utilizada para mostrar mensagens de alerta
Command Classe que define uma estrutura de comando para uma aplicação
J2ME
Image Classe que define uma imagem na aplicação
Font Classe que define uma formatação de fonte
SimpleCancellableTask Classe que define um trecho de código. Esta classe é utilizada
em conjunto com a WaitScreen
A tela inicial da aplicação, formada por um objeto List e objetos ListElement, tem a
função de menu principal, onde pode-se selecionar uma das quatro opções disponíveis para
mudança de tela. As telas acessíveis por este menu são: Controlar, onde o usuário irá definir
os parâmetros de comando e enviar o comando ao dispositivo servidor local; Configurações,
onde o usuário irá definir os parâmetros fixos da aplicação; Ajuda, onde é encontrada uma
explicação sucinta de como utilizar a aplicação; e Sobre, onde são apresentados créditos e
características da aplicação. A Figura 8 mostra a tela inicial da aplicação em funcionamento.
26
Figura 8 – Menu inicial da aplicação
Ao selecionar a opção de Configurações a aplicação exibe o formulário de
configurações. Este formulário é formado por um objeto Form e cinco campos de entrada de
dados TextField. O primeiro campo refere-se ao número de telefone onde o dispositivo
servidor estará ligado. Este possui uma máscara que limita a entrada de 10 caracteres
numéricos. O segundo campo refere-se à senha de segurança utilizada para que somente o
usuário detentor dela possa controlar a residência. O campo de senha possui uma máscara que
limita a entrada de 6 caracteres numéricos. Os últimos três campos referem-se às descrições
dos elementos conectados às portas do dispositivo servidor local, para facilitar a identificação
na tela de Controle. Estes campos possuem um limite de 20 caracteres alfanuméricos. A
Figura 9 apresenta a tela de Configurações com exemplos de entradas já inseridos.
Figura 9 – Tela de Configurações
As informações inseridas nos campos do formulário de Configurações são
armazenados em um objeto RecordStore, pertencente ao pacote RMS (Record Management
System). O RMS é um poderoso recurso do profile MIDP utilizado para armazenamento
persistente de dados. O mecanismo de armazenamento do RMS é implementado com uma
coleção de registros, onde cada registro é organizado como um vetor de bytes. O tamanho do
vetor pode variar para cada registro, e não existem limitações para seu conteúdo. Um
RecordStore pode ser imaginado como uma série de linhas em uma tabela, com um
identificador exclusivo para cada linha (MUCHOW, 2004). Um RecordStore deve ter um
27
nome de no máximo 32 caracteres. No protótipo foi utilizado o nome “CONFIGS” para o
RecordStore. Para facilitar algumas operações com o objeto RecordStore optou-se pela
criação de uma classe com métodos personalizados, denominada RecordStorePersonal
(código-fonte no ANEXO B). A classe RecordStorePersonal implementa os métodos
descritos no Quadro 6.
Quadro 6 – Métodos da classe RecordStorePersonal
Método Descrição do método Parâmetros Descrição dos parâmetros
open
Abre o RecordStore CONFIGS.
Caso ele não exista, o método o
cria com 5 entradas vazias.
close Fecha o RecordStore CONFIGS.
add Cria uma entrada no
RecordStore CONFIGS. nome
String que será inserida no
registro.
getRecord Recupera um registro do
RecordStore CONFIGS. id
Identificador do registro que
se deseja recuperar.
update Atualiza a string de um
determinado registro.
id Identificador do registro que
se deseja atualizar.
nome String que será inserida no
registro.
O armazenamento dos dados inseridos nos campos do formulário de Configurações
inicia quando o usuário seleciona a opção Salvar. Ao selecionar esta opção, o código inserido
em um objeto SimpleCancellableTask entra em execução, que por sua vez está inserido em
um objeto WaitScreen. Uma mensagem de status é mostrada ao usuário após a execução do
código, através de um objeto Alert. Quem identifica o sucesso ou falha na execução do código
inserido no SimpleCancellableTask é o objeto WaitScreen, este que redireciona para o objeto
Alert adequado. O código consiste em abrir o RecordStore CONFIGS, atualizar os registros
referentes aos campos do formulário de Configurações, e por fim fechá-lo. O Quadro 7 mostra
a estrutura do RecordStore CONFIGS.
Quadro 7 – Estrutura do RecordStore CONFIGS
Identificador Descrição do registro Exemplo de dados inseridos
1 Telefone onde o dispositivo servidor
local está ligado 5133333333
2 Senha de segurança 123456
3 Descrição do elemento conectado à
porta 1 do dispositivos servidor local Luz do pátio
4 Descrição do elemento conectado à
porta 2 do dispositivos servidor local Alarme
5 Descrição do elemento conectado à
porta 3 do dispositivos servidor local Cafeteira
Após o usuário ter inserido os parâmetros fixos da aplicação através do formulário de
Configurações, já é possível enviar comandos através da tela de Controle. A tela de controle,
assim como a tela de Configurações, é formada por um objeto Form. Este formulário é
acessado através do menu da tela inicial selecionando a opção Controlar. Dentro do objeto
Form existem 3 objetos ChoiceGroup, e cada um destes possui 3 objetos ChoiceElement. Os
28
objetos ChoiceGroup estão configurados para seleção exclusiva e aparência drop-down list2.
Cada objeto ChoiceGroup refere-se a uma porta do dispositivo servidor local, e seus itens
ChoiceElement referem-se aos 3 possíveis estados que podem ser definidos da aplicação, que
são: “Ligar”, para ligar o elemento ligado à porta; “Desligar”, para desligar o elemento ligado
à porta; e “Não alterar”, caso não se deseje nem ligar nem desligar o elemento ligado à porta,
deixando à vontade de um possível hóspede da casa ou no estado atual. Este formulário busca
as descrições dos elementos conectados às portas do dispositivo servidor local, definidos no
formulário de Configurações, e mostra acima de cada ChoiceGroup para deixar mais clara a
escolha dos estados. Caso não seja inserido nada nestes parâmetros a descrição assume
somente o número das portas do dispositivo servidor. A Figura 10 mostra a tela de Controle
com exemplos de estados definidos aos elementos da residência.
Figura 10 – Tela de Controle
Após definidos os parâmetros de comando, ou seja, definidos os estados para as portas
do dispositivo servidor local, o usuário efetiva o envio do comando selecionando a opção
Enviar. Ao selecionar esta opção, assim como na tela de Configurações ao selecionar Salvar,
o código inserido em um objeto SimpleCancellableTask entra em execução, que por sua vez
está inserido em um objeto WaitScreen. Uma mensagem de status é mostrada ao usuário após
a execução do código, através de um objeto Alert. Quem identifica o sucesso ou falha na
execução do código inserido no SimpleCancellableTask é o objeto WaitScreen, este que
redireciona para o objeto Alert adequado. O código consiste, basicamente, em abrir o
RecordStore CONFIGS para recuperar os registros onde estão inseridos o número do telefone
onde o dispositivo servidor está ligado e a senha de segurança, montar uma string no formato
URL scheme “tel”, e chamar o método platformRequest que interpretará a string, fazendo
uma chamada e, após atendida, enviará os tons DTMF que representam o comando. O método
platformRequest só está disponível no profile MIDP 2.0. Uma URL scheme “tel” descreve
uma conexão de um terminal de voz normal, caixas postais de voz ou serviços operados por
tons DTMF (RFC, 2000). A aplicação utiliza as especificações mais básicas desta definição.
A string inicia “tel:” para designar que é uma chamada telefônica, após vem o número do
telefone para onde se deseja efetuar a chamada, em seguida o caractere “p” que serve para
aguardar um segundo de pausa após o atendimento da chamada, evitando que os tons DTMF
seguintes sejam enviados à operadora juntamente com o número de telefone, e por fim, os
tons DTMF que representam o comando definido pelo usuário, formado pelos parâmetros
2 Drop-down list é um elemento gráfico de formulários semelhante a uma lista, onde só é possível selecionar um item.
Quando o elemento está inativo só é possível visualizar um item (o selecionado), quando ativo lista todos os itens.
29
fixos da aplicação definidos na tela de Configurações e os parâmetros de comando definidos
na tela de Controle.
As telas de Ajuda e Sobre são formadas pelo objeto Form com um objeto StringItem
com texto puro não alterável.
O código-fonte da classe principal da aplicação cliente remota está disponível no
ANEXO A.
Para instalação da aplicação em um telefone celular é necessário utilizar algum meio
de comunicação disponível pelo aparelho para comunicação com um computador ou servidor
de aplicações Java. Para a implementação da aplicação foi utilizado como base um aparelho
Nokia modelo 6001, conectado ao computador via cabo de dados USB, e a aplicação Nokia
PC Suíte para transferência do pacote JAR da aplicação. O pacote JAR reúne todas as
bibliotecas, código da aplicação e resources3 para distribuição. No protótipo, a aplicação ficou
com tamanho de 109KB.
4.2 DISPOSITIVO SERVIDOR LOCAL
O dispositivo servidor local é o componente da solução que recebe o comando enviado
pela aplicação cliente remota e efetiva a vontade do usuário. Este deve estar ligado a uma
linha telefônica da residência, e pode ser dividido em 4 partes: parte atendedora, que
identifica que existe uma chamada na linha e a atende para que a aplicação cliente remota
possa enviar os tons DTMF referentes ao comando; parte decodificadora, que decodifica o
sinal audível dos tons DTMF e converte para um nibble4; parte controladora, que valida e
interpreta a seqüência binária enviada pela parte decodificadora; e parte ativadora, que efetiva
o comando desejado pelo usuário. A Figura 11 ilustra a comunicação entre as partes do
dispositivo servidor local.
Figura 11 – Comunicação entre as partes do dispositivo servidor local
A seguir são detalhadas as partes do dispositivo servidor local.
3 Resources são recursos adicionais de uma aplicação como imagens e fontes.
4 Nibble é uma seqüência de quatro bits.
30
4.2.1 Parte atendedora
Esta parte do dispositivo servidor é responsável por detectar quando existe uma
chamada telefônica e atendê-la. Quando o usuário seleciona a opção de enviar um comando
na aplicação cliente remota, esta realiza uma chamada telefônica para o número onde o
dispositivo servidor local está ligado e prepara a seqüência de tons DTMF que representam o
comando. Somente depois de atendida a ligação a aplicação cliente iniciará o envio dos tons
DTMF. Ao perceber que existe uma chamada, a parte atendedora a atende e libera a entrada
dos tons DTMF que compõem o comando na parte decodificadora.
O protótipo implementa a parte atendedora utilizando componentes eletrônicos e um
aparelho telefônico. Esta parte pode ser subdividida em: detecção de chamada telefônica e
atendimento da chamada. A detecção da chamada é feita utilizando o circuito apresentado na
Figura 12.
Figura 12 – Circuito detector de chamada telefônica
O trecho entre o pino 5 do fotoacoplador5 4N25 e o resistor de 100KΩ se mantém com
potencial de 5V em estado normal. Quando ocorre uma chamada telefônica este trecho fica
com potencial de 0V. Esta mudança faz com que seja possível detectar quando uma chamada
telefônica ocorre. O atendimento é feito por um circuito ligado ao trecho que detecta a
chamada no circuito descrito anteriormente e a um telefone. A Figura 13 apresenta o circuito
que atende a chamada.
5 Fotoacoplador é um componente formado basicamente por um led e um fototransístor dentro de um CI, com a função de
transferir uma informação elétrica entre dois circuitos através de luz, ou seja, sem contato elétrico entre eles (BURGOS,
2007).
31
Figura 13 – Circuito atendedor de chamada
O CI 74HC04 utilizado no circuito atendedor é um módulo de inversores, ou seja, é
um circuito integrado que inverte um valor de entrada e disponibiliza em uma saída. Por
exemplo, o detector de chamada ligado no pino 1 do CI se mantém com potencial 5V, então o
pino 2 fica 0V. Quando existe uma chamada, o potencial no pino 1 passa a ser 0V, então no
pino 2 fica 5V. O CI possui inversores aos pares, ou seja, a cada dois pinos um inversor. O
atendimento ocorre quando o capacitor eletrolítico de 100μF se carrega por completo e se
descarrega no terra. Isto faz com que no pino 4 do CI se tenha o sinal, que será amplificado
pelo transistor para reter a bobina do relé. Nos contatos do relé está ligado o gancho de um
telefone, simulando o atendimento manual. Quando isto ocorre o áudio é liberado na saída do
fone, esta que estará ligada à parte decodificadora.
4.2.2 Parte decodificadora
A parte decodificadora é quem recebe os tons DTMF e os traduz para uma seqüência
binária. A cada tom recebido a parte decodificadora repassa à parte controladora um nibble.
Para o desenvolvimento desta parte foram utilizados componentes eletrônicos,
formando um circuito, que tem o par da linha telefônica como entrada e 5 saídas binárias,
onde 4 delas identificam o tom recebido e a outra identifica o momento de recebimento de um
tom.
O elemento central desta parte é o circuito integrado 8870 (MITEL, 1995). O CI
(circuito integrado) 8870 é um receptor DTMF de tamanho reduzido, baixo consumo de
energia e alto desempenho. Este é utilizado em sistemas de controle por rádio, sistemas de
cartão de crédito, identificador de chamadas, dentre outras aplicações. Ele consegue
decodificar todos os 16 tons DTMF, visto que sua saída é de 4 bits, ou seja, 16 combinações
possíveis. A Tabela 3 mostra os tons e sua saída depois de decodificada pelo CI 8870.
32
Tabela 3 – Saídas do CI 8870 por tom DTMF
Tom Saída Tom Saída Tom Saída Tom Saída
1 0001 5 0101 9 1001 A 1101
2 0010 6 0110 0 1010 B 1110
3 0011 7 0111 * 1011 C 1111
4 0100 8 1000 # 1100 D 0000
Este CI necessita de alguns componentes eletrônicos periféricos, que podem ser
alterados para ajustes e adaptação às características de cada aplicação, dentro das variações
permitidas descritas na documentação do componente. A Figura 14 mostra o esquema básico
de ligação do CI 8870, este que foi utilizado nesta solução.
Figura 14 – Esquema básico de ligação do CI 8870
A Figura 14 mostra que existe somente a entrada de um fio no CI, indicado como
“DTMF Input”. Esta entrada não pode vir diretamente da linha telefônica, devendo ser tratada
por um circuito ou por um aparelho telefônico. No caso da entrada vir de um aparelho
telefônico deve-se utilizar um dos fios da saída para o fone. O fio não utilizado deve ser
ligado diretamente no terra. A indicação “VDD” refere-se à alimentação do circuito, que é de 5
volts corrente contínua. Os pinos 5, 6 e 9 devem ser ligados no terra. O tom DTMF
decodificado para formato binário pode ser recuperado nos pinos 11, 12, 13 e 14, sendo no
pino 11 o dígito menos significativo. Mesmo quando o CI não está recebendo tons, suas
saídas mantém o valor do último tom decodificado. Durante a recepção de um tom o pino 15
tem valor lógico “1”, após este reassume o valor “0”.
Caso a linha telefônica tenha uma qualidade muito ruim o CI 8870 pode não
decodificar os tons, sendo necessário um ajuste em sua entrada, conforme descrito em seu
datasheet6 (MITEL, 1995). Isto ocorre porque os tons que trafegam pela linha estão expostos
a interferências na rede de telefonia. Existem diversos efeitos nocivos que podem alterar o
sinal como atenuação, distorção, atraso, ruído, etc.
6 Datasheet é um documento com informações técnicas de um determinado produto.
33
Somente a título de esclarecimento, para identificar a posição correta de um circuito
integrado deve-se observar a marca no seu corpo, esta que deve ficar para cima. O pino um é
o primeiro da esquerda superior. Alguns circuitos indicam a posição do pino 1 com um ponto.
Os pinos são contados sequencialmente no sentido anti-horário.
Para facilitar a compreensão e visualização do esquema o protótipo utiliza leds em
cada um dos 5 pinos de saída. Para inserção dos leds no esquema é necessário ligar as pernas
maiores (anodo) às saídas do CI 8870, e as pernas menores (catodo) a resistores de 470Ω,
estes que por sua vez são ligados ao terra. Resistores não possuem polaridade.
Para alimentação do esquema utilizou-se uma fonte ATX de computador, visto que
esta possui saída de 5 volts no par vermelho e preto de seus conectores. Para ligar a fonte foi
necessária uma ponte entre o fio verde e um preto (terra) do conector de 20 pinos.
A Tabela 4 mostra os componentes necessários para montagem da parte
decodificadora, incluindo os leds para visualização.
Tabela 4 – Componentes da parte decodificadora
Quantidade Componente Descrição Identificação na Figura 14
1 Fonte 5 volts VDD
1 CI 8870
Se desejável pode-se
adquirir um socket para CIs
de 18 pinos.
MT8870D/MT8870-D1
2 Resistor 100K Ω R1 e R2
1 Resistor 300K Ω R3
5 Resistor 470K Ω Não consta
2 Capacitor 100nF C1 e C2
1 Oscilador 3.579545 MHz X-tal
5 Led Vermelho comum Não consta
Para facilitar testes do esquema é recomendável utilizar uma placa protoboard onde é
possível conectar os componentes eletrônicos sem que seja necessário soldá-los em uma
placa.
4.2.3 Parte controladora
Esta parte do dispositivo servidor local é responsável por validar e interpretar a
seqüência de tons DTMF decodificados pela parte decodificadora e enviar sinais elétricos
para a parte ativadora indicando quais portas devem ser ativadas e quais desativadas.
O componente principal desta parte é o microcontrolador de 8 bits Atmega64 da
Atmel (ATMEL, 2006). Este é um microcontrolador de alto desempenho, baixo consumo de
energia e armazenamento não volátil de programa. Ele possui 6 portas bi-direcionais de 8 bits
identificadas da letra A até a letra F, e uma porta de 5 bits identificada como G. Cada porta
possui 3 registradores:
DDx (Data Direction Registrer) – acessado pelo endereço DDRx, este
registrador define a direção dos pinos da porta. Os bits do registrador DDx que
tiverem valor “1” estão configurados como saída, e os que tiverem valor “0”
estão configurados como entrada;
34
PORTx (Data Register) – pode-se atribuir um valor à este registrador para os
bits configurados como entrada no registrador DDx;
PINx (Input Pins Address) – pode-se ler os valores dos bits do registrador
independente da configuração do registrador DDx.
O “x” após o nome do registrador deve ser substituído pelo nome da porta que se
deseja trabalhar, por exemplo, para a porta B são os registradores: DDRB, PORTB e PINB.
As portas também podem assumir funções específicas para trabalhar com memória externa,
contadores e temporizadores, interrupções, dentre outras.
Para a implementação do protótipo foi utilizada o kit de desenvolvimento Cerebot
fabricada pela Digilent (DIGILENT, 2005) que inclui o microcontrolador Atmega64,
brevemente explicado anteriormente. Este kit é utilizado para estudos, projetos de robótica e
aplicações de teste de laboratório. O kit possui conectores de entrada/saída, 3 tipos de entrada
para fonte de energia, e diversos módulos e componentes periféricos. Para programação do
microcontrolador foi utilizado os seguintes softwares:
WinAVR Programmers Notepad – editor de linguagem C para arquitetura
AVR;
WinAVR MFile – criador de arquivo Makefile para a arquitetura AVR;
Digilent AVR Programmer – utilizado para transferir o programa para o
microcontrolador (fornecido pelo fabricante do kit Cerebot);
Digilent Adept – este não foi utilizado, mas sem ele instalado não foi possível
transferir o programa para o microcontrolador (fornecido pelo fabricante do kit
Cerebot).
O kit Cerebot possui uma interface JTAG7 (Joint Test Action Group) ou SPI (Serial
Peripheral Interface) para comunicação com o computador via porta paralela. O cabo JTAG
ou SPI deve ser conectado onde existe a indicação “Digilent ISP” no kit.
Para alimentação do kit foi utilizada a mesma fonte de alimentação da parte
decodificadora, através da entrada “J5”.
Este kit possui algumas portas para entrada e saída de dados. Estas não estão
diretamente relacionadas às portas do microcontrolador incluso Atmega64. Cada porta do
Cerebot, denominada Pmod, relaciona seus pinos com bits das portas do microcontrolador.
Todas as Pmods possuem 6 pinos, sendo o pino 5 o terra e o pino 6 saída da alimentação. Um
exemplo para demonstrar a relação entre as portas Pmod do kit Cerebot com as portas do
microcontrolador seria a Pmod “JPA” que tem seu pino 1 associado ao bit 7 da porta D do
microcontrolador, pino 2 associado ao bit 4 da porta B, pino 3 associado ao bit 5 da porta D,
pino 4 associado ao bit 7 da porta B. Os pinos são contados iniciando em 1 (do pino 1 ao pino
4), já os bits são contados iniciando em 0, sendo o sétimo o mais significativo (do bit 0 ao bit
7). A Tabela 5 apresenta as oito portas Pmod do kit Cerebot e as associações aos bits das
portas do microcontrolador.
7 JTAG é um padrão para prover acesso a testes externos a circuitos integrados.
35
Tabela 5 – Portas do kit Cerebot X Portas do microcontrolador Atmega64
Porta Pmod Pino 1 Pino 2 Pino 3 Pino 4
JA Bit 7 da Porta D Bit 4 da Porta B Bit 5 da Porta D Bit 7 da Porta B
JB Bit 6 da Porta D Bit 5 da Porta B Bit 4 da Porta D Bit 6 da Porta B
JC Bit 6 da Porta E Bit 4 da Porta E Bit 7 da Porta E Bit 5 da Porta E
JD Bit 2 da Porta E Bit 3 da Porta E Bit 0 da Porta E Bit 1 da Porta E
JE Bit 0 da Porta D Bit 1 da Porta D Bit 2 da Porta D Bit 3 da Porta D
JF Bit 0 da Porta F Bit 1 da Porta F Bit 2 da Porta F Bit 3 da Porta F
JG Bit 5 da Porta F Bit 7 da Porta F Bit 6 da Porta F Bit 4 da Porta F
JM Bit 0 da Porta B Bit 2 da Porta B Bit 3 da Porta B Bit 1 da Porta B
A parte controladora utiliza 3 portas Pmod do kit Cerebot como segue:
1. JB – Entrada dos nibbles gerados pela parte decodificadora;
2. JE – Entrada de sinais de interrupção;
3. JC – Saídas para a parte ativadora.
Para a entrada dos bits, gerados pela parte decodificadora, na parte controladora foi
utilizado ligações diretas das 4 saídas do CI 8870 para a porta JB do kit Cerebot (pino 11 do
CI no pino 1 da Pmod B, pino 12 do CI no pino 2 da Pmod B, e assim sucessivamente).
O pino 15 do CI 8870, que fica com valor lógico “1” quando um tom está sendo
recebido e valor lógico “0” quando não está recebendo, foi utilizado para gerar uma
interrupção no microcontrolador. Cada vez que a interrupção é gerada o programa inserido no
microcontrolador irá ler a entrada referente ao tom decodificado (Pmod JB). A ligação da
saída do CI 8870 foi ligada por uma via simples ao pino 2 da porta JE. O pino 2 da porta JE
está associado ao bit 1 da porta D do microcontrolador (os bits são contados a partir do zero).
Como citado anteriormente as portas do microcontrolador podem assumir funções específicas,
neste caso o bit 1 da porta D assume a função de receber um valor lógico associado à
interrupção externa INT1. Também pode ser desejável ter uma interrupção para reiniciar o
dispositivo servidor local, que pode ser ligada no pino 1 da porta JE que está associado ao bit
0 da porta D do microcontrolador. Pode-se colocar um botão ligado ao pino indicado para
chamar esta interrupção.
Após receber uma seqüência de tons decodificados, validar e processar estas
informações, o microcontrolador irá gerar a saída na Pmod JC. Cada um dos 4 pinos da Pmod
JC designa uma saída diferente, como segue:
Pino 1 – saída que designa qual estado a porta 1 do dispositivo servidor local
deve assumir (ativada caso valor lógico “1” ou desativada caso valor lógico
“0”);
Pino 2 – saída que designa qual estado a porta 2 do dispositivo servidor local
deve assumir (ativada caso valor lógico “1” ou desativada caso valor lógico
“0”);
Pino 3 – saída que designa qual estado a porta 3 do dispositivo servidor local
deve assumir (ativada caso valor lógico “1” ou desativada caso valor lógico
“0”);
Pino 4 – saída que designa algum erro na validação dos tons DTMF
decodificados recebidos, ou seja, assume valor lógico “1” caso o comando
36
enviado pela aplicação cliente remota tenha algum erro de validação ou
transmissão.
Não foi necessária a ligação dos pinos de terra e alimentação das portas Pmod (pinos 5
e 6 respectivamente). A Figura 15 mostra o kit Cerebot e as ligações necessárias para o
funcionamento da parte controladora.
Figura 15 – Kit Cerebot e suas ligações
Deve-se configurar os registradores de direção, acessados por DDRx, das portas do
microcontrolador que serão utilizadas. Como descrito anteriormente, cada porta Pmod do kit
Cerebot utiliza uma ou mais portas do microcontrolador, portanto deve-se definir a direção
dos bits das portas do microcontrolador, utilizadas pelas Pmods. Por exemplo, a Pmod JB
utiliza as portas B e D do microcontrolador, mais precisamente os bits 5 e 6 da porta B e bits 4
e 6 da porta D, sendo que estes devem ser definidos como entrada, pois a porta B serve para a
entrada dos nibbles da parte decodificadora, então o programa define os registradores de
direção de dados DDRB e DDRD, nos bits citados. Quando um bit de um registrador DDRx é
definido com valor 0 este representa que no mesmo bit do registrador PORTx está sendo
esperada a entrada de valor, caso valor 1 está sendo esperada a saída de valor.
Para utilizar interrupções alguns registradores também devem ser configurados no
microcontrolador. O microcontrolador Atmega64 possui 8 interrupções (INT0 à INT7), e
estas devem ser habilitadas e configuradas de acordo com a necessidade. Para habilitar uma
interrupção é necessário definir com valor 1 o bit correspondente ao número da interrupção no
registrador EIMSK. Para definir a sensibilidade da interrupção devem-se definir dois bits por
interrupção, no registrador EICRA para INT0 até INT3 e no registrador EICRB para INT4 até
INT7. Estes bits são identificados como ISCn1 e ISCn0, onde “n” é o número da interrupção.
37
A Tabela 6 descreve as possibilidades de sensibilidade de interrupções no microcontrolador
Atmega64.
Tabela 6 – Configuração de sensibilidade de interrupção no Atmega64
ISCn1 ISCn0 Descrição
0 0 O nível baixo em INTn gera a interrupção
0 1 Qualquer mudança lógica em INTn gera a interrupção
1 0 A interrupção INTn é gerada na borda de descida
1 1 A interrupção INTn é gerada na borda de subida
Para que as interrupções fiquem ativas, após configurados os registradores EIMSK e
EICRx, deve-se executar a instrução _SEI(). Para desativar as interrupções pode-se utilizar a
instrução _CLI(). As funções “sei()” e “cli()” que executam estas instruções estão na
biblioteca “avr/interrupt.h”.
O código de tratamento da execução deve ser escrito dentro da função
“ISR(INTx_vect)”, onde “x” é o número da interrupção.
Além da biblioteca “avr/interrupt.h” citada acima deve-se utilizar a “avr/io.h”, e é
recomendável utilizar também a “inttypes.h” para utilizar o tipo “uint8_t” que define números
inteiros de 8 bits sem sinal.
O programa da parte controladora foi escrito na linguagem C (código-fonte no
ANEXO C) e estruturado em funções que definem bem o funcionamento da parte
controladora. Estas desempenham basicamente as seguintes funções:
Configuração do microcontrolador;
Tratamento de interrupções;
Leitura de entrada;
Validação do protocolo;
Verificação de senha;
Verificação de integridade da entrada;
Tratamento de erros;
Geração de saída.
A interrupção externa INT1 foi utilizada para ler os tons decodificados um a um. Esta
leitura consiste em operações bit a bit nas portas B e D do microcontrolador, visto que estas
estão associadas à porta Pmod B do kit Cerebot, que é onde estão conectadas as saídas do CI
8870 da parte decodificadora relativas aos tons decodificados.
Outra função da parte controladora é o tratamento do protocolo que consiste
basicamente das funções “mudaEstado()” e “processaMudanca()”. A primeira tem a função de
navegação entre os estados do autômato que valida a seqüência de tons válida. A segunda tem
a função de tratar os tons entrantes em determinados estados do autômato. Dentre os
tratamentos da função “processaMudanca()” estão a validação de senha, verificação de
integridade dos tons recebidos, alerta de erro, e geração das saídas. As saídas geradas pela
parte controladora são definidas utilizando operações bit a bit na porta E do microcontolador,
relacionada à Pmod C. Dentre as saídas está também a sinalização de erro (bit 5).
38
Para programar isoladamente a parte controladora podem-se utilizar módulos externos
do kit Cerebot como, por exemplo, módulo de botões para simular interrupções, módulo de 4
chaves para simular os tons entrantes, e módulo de leds para simular as saídas.
4.2.4 Parte ativadora
A parte ativadora é quem faz com que os elementos conectados às portas do
dispositivo servidor local sejam ligados ou desligados de acordo com as saídas geradas pela
parte controladora.
O processo de ativação ou desativação das portas é muito simples. Consiste em
amplificar os sinais de saída da parte controladora para atracar ou desatracar bobinas de relés,
estes que servem como interruptores para os elementos conectados às portas. É preciso
amplificar as saídas da parte controladora, pois estas não são suficientes para influenciar
mudanças nas bobinas dos relés, ou seja, a corrente é baixa. Para que estas saídas possam
alterar o estado dos relés elaborou-se um circuito eletrônico simplificado, onde a peça
principal é um transistor. A Figura 16 mostra o circuito de amplificação para a parte
ativadora.
Figura 16 – Circuito de amplificação de sinal
O resistor pode ser ajustado em função da potência do sinal de entrada, ou seja, quanto
mais fraco for o sinal de entrada, menor deve ser o valor desse resistor. O diodo em paralelo
com a bobina do relé tem a função de descarregar a corrente gerada por força contra-
eletromotriz8 no relé. O diodo também impede que o transistor seja danificado quando o
circuito é desligado e o rele desatraca, desviando a corrente gerada para o ponto 5V que neste
momento fica em queda para 0V visto que a fonte foi desligada.
Com a parte ativadora utilizando relés é possível acionar elementos ligados a redes de
grande corrente, como rede elétrica 110V ou 220V, a partir de uma pequena corrente. Os relés
funcionam como interruptores. Quando uma corrente circula por sua bobina é criado um
campo magnético que atrai um contato, desviando ou interrompendo o fluxo de energia de
8 Força contra-eletromotriz, também chamada de força eletromotriz inversa, é a tensão elétrica desenvolvida num circuito
indutivo por uma corrente variável ou alternada atravessando-o. A polaridade da tensão é a cada instante, oposta à da tensão
aplicada, a amplitude ou intensidade nunca é maior do que o valor nominal constante. (WIKIPEDIA, 2007-d).
39
seus contatos. Ao interromper a alimentação da bobina esta faz com que o contato mude
novamente. A Figura 17 mostra um exemplo de funcionamento de um relé, este utilizado no
protótipo desta solução.
Figura 17 – Exemplo de ligação de um relé
O ponto C indicado na figura é o contato comum para os pontos NA e NF. O ponto
NA (normalmente aberto) é o contato que fica aberto quando a bobina não está alimentada, já
o ponto NF (normalmente fechado) é exatamente o oposto de NA.
Também é possível ativar circuitos muito maiores encadeando relés de potência maior
e contatoras, dando a possibilidade de cortar totalmente a energia da residência. Após os relés
das portas do dispositivo local é interessante colocar tomadas onde possam ser ligados os
elementos residenciais que se deseja controlar.
4.3 COMUNICAÇÃO ENTRE CLIENTE E SERVIDOR
A comunicação entre a aplicação cliente remota e o dispositivo servidor local utiliza
como meio a rede de telefonia, e como padrão a sinalização DTMF. A informação trafega por
camadas (partes) da solução desde a entrada de dados do usuário até a efetivação dos
comandos na residência. A Figura 18 ilustra as camadas da solução.
Figura 18 – Camadas da solução
Primeiramente o usuário entra com os dados de configuração da solução na aplicação
cliente, e quando desejar envia comandos para controlar elementos da residência. O
40
dispositivo servidor recebe o comando em DTMF e logo decodifica estes para formato digital.
O comando é interpretado e então executado na residência.
Durante todo o processo proposto pela solução o formato dados vai se alterando,
facilitando a identificação das camadas, como pode ser visto na Figura 19.
Figura 19 – Alterações do formato dos dados na solução
A solução utiliza um protocolo próprio para a comunicação entre a aplicação cliente
remota e o dispositivo servidor local, definindo como os tons DTMF devem ser transmitindo
para que um comando seja aceito e efetivado na residência. A seção a seguir descreve
detalhadamente o protocolo criado para atender a solução.
4.3.1 Descrição do protocolo
O protocolo desenvolvido serve para que um comando, formado por tons DTMF,
enviado pela aplicação cliente pela rede de telefonia, possa ser interpretado pela parte
controladora do dispositivo servidor.
41
O protocolo divide um comando em 3 partes: senha de segurança, estado das portas, e
verificação de integridade. A Figura 20 mostra um diagrama com o fluxo de tratamento do
protocolo.
Figura 20 – Fluxo de tratamento do protocolo
O início de um comando é identificado por um tom de asterisco. Logo após o tom que
identifica o início de um comando deve vir a senha de segurança, esta que somente pode
conter os tons numéricos, e pode ter comprimento de 0 até 6. Em seguida deve vir o tom de
sustenido indicando o final da senha e início da definição dos estados das portas. O tom de
sustenido deve vir mesmo que a senha tenha comprimento 0, ou seja, mesmo que ela não
exista. Após, deve vir a definição de estado de pelo menos uma porta. Cada definição de
estado de porta é composta pelo tom do número da porta mais o tom 0 para indicar que ela
deve ser desativada ou o tom 1 para indicar que ela deve ser ativada. O número máximo de
pares é igual ao número de portas da solução. Pode-se omitir o estado de uma porta afim de
mantê-la no estado que se encontra, não existindo a obrigação de defini-la. Assim como para
dividir a senha da definição dos estados foi utilizado o tom de sustenido, logo após a definição
das portas também deve vir um tom de sustenido. Após, deve vir um tom verificador,
calculado utilizando tons anteriores, fora o tom de início de comando. Este verificador
somente pode conter tons numéricos ou sustenido, este que indica o dígito verificador 10.
Finalmente, a identificação do fim de um comando é indicada por um tom de asterisco.
Um exemplo de comando válido para o protocolo seria a seqüência de tons
“*123456#112031#4*” (excluindo as aspas). Pode-se ver que, neste exemplo, a senha é
“123456” e os estados das portas a serem definidos são ativar a porta 1, desativar a porta 2 e
ativar a porta 3. Também nota-se que o tom verificador calculado a partir dos anteriores (fora
o asterisco) resultou no tom “4”.
O protocolo de comunicação pode ser representado pela expressão regular mostrada na
Figura 21.
Figura 21 – Expressão regular do protocolo da solução
42
Na Figura 21, as áreas em vermelho referem-se aos tons delimitadores do protocolo, já
as áreas em azul referem-se, primeiro à senha de segurança, após à definição do estado das
portas, e por fim ao dígito verificador. Uma expressão regular permite definir precisamente
uma linguagem ou protocolo.
O autômato é um reconhecedor para uma linguagem que toma como entrada uma
cadeia “x” e responde “sim” se “x” for uma sentença da linguagem, e “não” caso contrário.
Para validação do protocolo foi construído um autômato finito determinístico (AHO, SETHI e
ULLMAN, 1986). Um autômato finito determinístico (AFD) é um caso especial de autômato
finito não-determinístico no qual:
1. Nenhum estado possui uma transição vazia (ε);
2. Para cada estado “s” é símbolo de entrada “a” existe no máximo um lado
rotulado “a” deixando “s”.
A construção de um autômato é importante para documentar o protocolo, facilitando
sua interpretação, além de simplificar a programação, visto que para codificá-lo em alguma
linguagem de programação é preciso de uma estrutura simplificada composta por desvios
condicionais.
A Figura 22 mostra o autômato finito determinístico construído para definir o
protocolo de comunicação utilizado na solução.
Figura 22 – Autômato finito determinístico que define o protocolo de comunicação
Por medida de segurança optou-se por inserir uma verificação simples quanto à
integridade dos tons recebidos, visto que, devido a problemas na rede de telefonia, como
ruídos, alguns tons não enviados possam ser falsamente detectados ou tons enviados não
43
sejam detectados, na entrada do dispositivo servidor local. Esta verificação de integridade
consiste em enviar um dígito verificador calculado a partir dos tons anteriores a sua posição,
excluindo o tom de início de comando asterisco. O cálculo utilizado neste protocolo chama-se
Módulo 11 (WIKIPEDIA, 2007-e), que consiste em multiplicar individualmente os valores
integrantes do cálculo por um número incrementado a cada posição, começando por 2,
iniciando da direita para a esquerda. Somam-se os resultados das multiplicações, multiplica-se
por 10 e divide-se por 11. O resto da divisão é o dígito verificador. Por exemplo, o dígito
verificador para a seqüência. Como a divisão é feita por 11 é possível que o resto seja 10.
É importante notar que, o tom 0 representa o valor 10, tanto no cálculo quanto como
dígito verificador. Já o tom de sustenido representa o valor 0 como dígito verificador, porém
no cálculo tem valor 12. Isto ocorre devido a parte decodificadora do dispositivo servidor
local utilizar o valor 10 para o tom 0, e o valor 0 para o tom D. Optou-se de não utilizar os
tons internos (A, B, C e D) pois existem alguns telefones celulares que não os envia.
O cálculo do dígito verificador é feito pela aplicação cliente remota ao enviar um
comando, e pelo dispositivo servidor local para verificação de integridade, comparando o tom
enviado na posição do dígito verificador com o resultado obtido através de seu cálculo, que
caso sejam iguais garantem que os tons chegaram exatamente como foram enviados, caso
contrário pode-se deduzir que ocorreu algum erro na transmissão do comando.
A Figura 23 mostra um exemplo de cálculo Módulo 11 para gerar o dígito verificador
para o protocolo da solução.
Figura 23 – Exemplo do cálculo Módulo 11
Pelo fato do protocolo se basear em um autômato finito determinístico a atualização
deste torna-se facilitada. As implementações, tanto na aplicação cliente remota quanto no
dispositivo local também podem ser facilmente alteradas para adaptar-se a possíveis
modificações no protocolo.
44
4.4 ANÁLISE DA SOLUÇÃO
A solução foi analisada e testada para que se possa ter certeza de sua viabilidade e
confiabilidade, e fique mais fácil perceber as vantagens do modelo proposto. Em uma
primeira análise, foi realizada uma série de simulações para descobrir o tempo médio de envio
de um comando. A aplicação cliente remota envia cada tom em um intervalo de
aproximadamente 1 segundo, então temos, para um comando mínimo, com senha de
comprimento 0 e somente uma definição de estado para uma porta, aproximadamente 7
segundos. Um exemplo de comando mínimo seria a seqüência “*#11#8*”, onde não há senha
e se ativa a porta um do dispositivo servidor local. Para um comando máximo, com senha de
comprimento 6 e definições de estados para as 3 portas, aproximadamente 17 segundos. Um
exemplo de comando máximo seria a seqüência “*123456#112031#4*”, onde a senha ocupa
todo o seu comprimento possível, se ativa as portas 1 e 3, e se desativa a porta 2 do
dispositivo servidor local. Logo, temos um tempo médio de 12 segundos para enviar um
comando da aplicação cliente para o dispositivo servidor.
Outra análise que pode ser feita diz respeito ao tratamento do protocolo. Foram
testadas diversas possibilidades de seqüência dos tons de um comando para que fosse
analisado o tratamento do autômato. A Figura 24 apresenta uma simulação de envio de tons e
o resultado final gerado pelo autômato.
Figura 24 – Simulação de seqüências de tons
A Figura 24 mostra a entrada de tons da esquerda para a direita. A cor rosa identifica
um erro, abortando a seqüência. A cor verde identifica entrada de tons correta. A cor azul
identifica um tom que dispara um determinado teste nos tons anteriores. Os quatro primeiros
tons marcados com a cor azul disparam o teste da senha, já os outros disparam o teste dos
pares de definição dos estados das portas. Para facilitar outros testes, a Figura 25 apresentada
logo abaixo lista os tons verificadores já calculados a partir dos estados definidos na
aplicação. A senha utilizada foi “123”.
45
Figura 25 – Tons verificadores calculados
A instalação da solução é muito simples. Consiste em instalar a aplicação cliente
remota em um telefone celular, ligar o dispositivo servidor local em uma linha telefônica da
residência e conectar às portas os elementos que se deseja automatizar pela solução. Esta
facilidade de instalação faz com que o processo de retrofitting seja bastante reduzido.
O Quadro 8 apresenta vantagens e desvantagens da solução.
Quadro 8 – Vantagens e desvantagens da solução
Vantagens Desvantagens
Fácil instalação, tanto da aplicação quanto do
dispositivo
Ajustes na parte decodificadora em linhas
telefônicas problemáticas
Baixo custo de implementação Custo variável por envio de comando
Utilização de componentes comuns, sendo
fácil encontrá-los
Não retorna status para a aplicação cliente
remota
Acesso remoto sem limites de distância
Solução dividida em camadas, facilitando a
atualização e manutenção
Apesar de a solução ter sido projetada para automação residencial esta solução
também pode ser bem aproveitada em sistemas de automação predial.
46
5 CONCLUSÃO
Soluções de automação ainda não são comuns nas residências, visto disponíveis ainda
não são acessíveis devido ao custo elevado, dificuldade de instalação, e difícil acesso a estas
tecnologias. A solução proposta neste trabalho apresentou uma alternativa de baixo custo,
fácil instalação e adaptação em quaisquer modelos de residências. O modelo torna-se atraente
devido a minimização do processo de retrofitting em residências não projetadas para receber
tecnologias de automação.
Com o modelo proposto é possível controlar remotamente elementos de uma
residência como, por exemplo, eletrodomésticos, sistema de iluminação, sistema de alarme e
até alimentação elétrica geral. O baixo custo deve-se aos componentes utilizados que são
facilmente encontrados no comércio de componentes eletrônicos. Como componente principal
a solução tem, mais especificamente no dispositivo servidor, um microcontrolador que, dentre
muitas vantagens pode-se destacar seu baixo custo, alto desempenho e fácil utilização. Outra
vantagem da solução apresentada é a possibilidade de envio de comandos a partir de um
telefone móvel celular, visto que estes já estão difundidos no mercado e sua característica faz
com que o campo de utilização seja limitada somente pela cobertura de sinal telefônico. O
modelo se mostrou confiável e eficaz no que se propõe, conseguindo prover comodidade e
conforto para usuários que desejam controlar elementos de suas residências à distancia.
Como trabalho futuro, a solução poderia ter características aperfeiçoadas como, por
exemplo, retornar um status da execução do comando à aplicação remota, ajuste automático
na entrada da parte decodificadora para filtrar possíveis problemas na linha telefônica, adição
de outros estados para as portas do dispositivo servidor local, maior flexibilidade quanto a
ampliação do número de portas do modelo, e diminuição do tempo de transmissão dos
comandos. O fato da solução ser dividida em camadas facilita a expansão, atualização e até
substituição de partes do modelo.
ANEXO A – CÓDIGO-FONTE DA CLASSE PRINCIPAL DA
APLICAÇÃO CLIENTE
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import rms.RecordStorePersonal;
public class VisualMidlet extends MIDlet implements CommandListener {
/** Creates a new instance of VisualMidlet */
public VisualMidlet() {
initialize();
}
RecordStorePersonal rsp = new RecordStorePersonal();
private org.netbeans.microedition.lcdui.SplashScreen splInicial;
private Image imgSplash;
private List lstInicial;
private Form frmControlar;
private Form frmConfiguracoes;
private Form frmAjuda;
private Form frmSobre;
private Font fntPequena;
private TextField txtTelefone;
private TextField txtSenha;
private TextField txtP1;
private TextField txtP2;
private TextField txtP3;
private Command okSalvar;
private org.netbeans.microedition.lcdui.WaitScreen waitConfiguracoes;
private Alert altFalhaSalvarConfiguracoes;
private Alert altSucessoSalvarConfiguracoes;
private Command backSobre;
private StringItem strAjuda;
private Command backAjuda;
private Command backConfiguracoes;
private StringItem strSobre;
private Command backControlar;
private org.netbeans.microedition.util.SimpleCancellableTask taskSalvar;
private Command exitInicial;
private ChoiceGroup chgrpPorta1;
private ChoiceGroup chgrpPorta2;
private ChoiceGroup chgrpPorta3;
private Command okEnviar;
private org.netbeans.microedition.util.SimpleCancellableTask taskEnviar;
private Image imgControlar;
private Image imgConfiguracoes;
private Image imgAjuda;
private Image imgSobre;
private Image imgLigar;
private Image imgDesligar;
48
private Image imgNaoAlterar;
private org.netbeans.microedition.lcdui.WaitScreen waitEnviar;
private Alert altFalhaEnviarComando;
private Alert altSucessoEnviarComando;
/** Called by the system to indicate that a command has been invoked on a
particular displayable.
* @param command the Command that ws invoked
* @param displayable the Displayable on which the command was invoked
*/
public void commandAction(Command command, Displayable displayable) {
// Insert global pre-action code here
if (displayable == splInicial) {
if (command == splInicial.DISMISS_COMMAND) {
// Insert pre-action code here
getDisplay().setCurrent(get_lstInicial());
// Insert post-action code here
}
} else if (displayable == lstInicial) {
if (command == lstInicial.SELECT_COMMAND) {
switch (get_lstInicial().getSelectedIndex()) {
case 0:
// Insert pre-action code here
getDisplay().setCurrent(get_frmControlar());
try{
rsp.open();
chgrpPorta1.setLabel("P1 - " + rsp.getRecord(3));
chgrpPorta1.setSelectedIndex(0, true);
chgrpPorta2.setLabel("P2 - " + rsp.getRecord(4));
chgrpPorta2.setSelectedIndex(0, true);
chgrpPorta3.setLabel("P3 - " + rsp.getRecord(5));
chgrpPorta3.setSelectedIndex(0, true);
rsp.close();
}catch(Exception e){
System.out.print(e);
}
// Insert post-action code here
break;
case 1:
// Insert pre-action code here
getDisplay().setCurrent(get_frmConfiguracoes());
try{
rsp.open();
txtTelefone.setString(rsp.getRecord(1));
txtSenha.setString(rsp.getRecord(2));
txtP1.setString(rsp.getRecord(3));
txtP2.setString(rsp.getRecord(4));
txtP3.setString(rsp.getRecord(5));
rsp.close();
}catch(Exception e){
System.out.print(e);
}
// Insert post-action code here
break;
case 2:
// Insert pre-action code here
getDisplay().setCurrent(get_frmAjuda());
// Insert post-action code here
break;
case 3:
// Insert pre-action code here
getDisplay().setCurrent(get_frmSobre());
// Insert post-action code here
break;
}
} else if (command == exitInicial) {
49
// Insert pre-action code here
exitMIDlet();
// Insert post-action code here
}
} else if (displayable == frmConfiguracoes) {
if (command == okSalvar) {
// Insert pre-action code here
getDisplay().setCurrent(get_waitConfiguracoes());
// Insert post-action code here
} else if (command == backConfiguracoes) {
// Insert pre-action code here
getDisplay().setCurrent(get_lstInicial());
// Insert post-action code here
}
} else if (displayable == waitConfiguracoes) {
if (command == waitConfiguracoes.FAILURE_COMMAND) {
// Insert pre-action code here
getDisplay().setCurrent(get_altFalhaSalvarConfiguracoes(),
get_frmConfiguracoes());
// Insert post-action code here
} else if (command == waitConfiguracoes.SUCCESS_COMMAND) {
// Insert pre-action code here
getDisplay().setCurrent(get_altSucessoSalvarConfiguracoes(),
get_frmConfiguracoes());
// Insert post-action code here
}
} else if (displayable == frmSobre) {
if (command == backSobre) {
// Insert pre-action code here
getDisplay().setCurrent(get_lstInicial());
// Insert post-action code here
}
} else if (displayable == frmAjuda) {
if (command == backAjuda) {
// Insert pre-action code here
getDisplay().setCurrent(get_lstInicial());
// Insert post-action code here
}
} else if (displayable == frmControlar) {
if (command == backControlar) {
// Insert pre-action code here
getDisplay().setCurrent(get_lstInicial());
// Insert post-action code here
} else if (command == okEnviar) {
// Insert pre-action code here
getDisplay().setCurrent(get_waitEnviar());
// Insert post-action code here
}
} else if (displayable == waitEnviar) {
if (command == waitEnviar.FAILURE_COMMAND) {
// Insert pre-action code here
getDisplay().setCurrent(get_altFalhaEnviarComando(),
get_frmControlar());
// Insert post-action code here
} else if (command == waitEnviar.SUCCESS_COMMAND) {
// Insert pre-action code here
getDisplay().setCurrent(get_altSucessoEnviarComando(),
get_frmControlar());
// Insert post-action code here
}
}
// Insert global post-action code here
}
/** This method initializes UI of the application.
*/
private void initialize() {
50
// Insert pre-init code here
getDisplay().setCurrent(get_splInicial());
// Insert post-init code here
}
/**
* This method should return an instance of the display.
*/
public Display getDisplay() {
return Display.getDisplay(this);
}
/**
* This method should exit the midlet.
*/
public void exitMIDlet() {
getDisplay().setCurrent(null);
destroyApp(true);
notifyDestroyed();
}
/** This method returns instance for splInicial component and should be called
instead of accessing splInicial field directly.
* @return Instance for splInicial component
*/
public org.netbeans.microedition.lcdui.SplashScreen get_splInicial() {
if (splInicial == null) {
// Insert pre-init code here
splInicial = new
org.netbeans.microedition.lcdui.SplashScreen(getDisplay());
splInicial.setCommandListener(this);
splInicial.setTitle("");
splInicial.setFullScreenMode(true);
splInicial.setText("");
splInicial.setImage(get_imgSplash());
// Insert post-init code here
}
return splInicial;
}
/** This method returns instance for imgSplash component and should be called
instead of accessing imgSplash field directly.
* @return Instance for imgSplash component
*/
public Image get_imgSplash() {
if (imgSplash == null) {
// Insert pre-init code here
try {
imgSplash = Image.createImage("/libraries/resources/splash.jpg");
} catch (java.io.IOException exception) {
exception.printStackTrace();
}
// Insert post-init code here
}
return imgSplash;
}
/** This method returns instance for lstInicial component and should be called
instead of accessing lstInicial field directly.
* @return Instance for lstInicial component
*/
public List get_lstInicial() {
if (lstInicial == null) {
// Insert pre-init code here
lstInicial = new List("Controle Residencial", Choice.IMPLICIT, new
String[] {
"Controlar",
"Configura\u00E7\u00F5es",
51
"Ajuda",
"Sobre"
}, new Image[] {
get_imgControlar(),
get_imgConfiguracoes(),
get_imgAjuda(),
get_imgSobre()
});
lstInicial.addCommand(get_exitInicial());
lstInicial.setCommandListener(this);
lstInicial.setSelectedFlags(new boolean[] {
false,
false,
false,
false
});
// Insert post-init code here
}
return lstInicial;
}
/** This method returns instance for frmControlar component and should be
called instead of accessing frmControlar field directly.
* @return Instance for frmControlar component
*/
public Form get_frmControlar() {
if (frmControlar == null) {
// Insert pre-init code here
frmControlar = new Form("Controlar", new Item[] {
get_chgrpPorta1(),
get_chgrpPorta2(),
get_chgrpPorta3()
});
frmControlar.addCommand(get_backControlar());
frmControlar.addCommand(get_okEnviar());
frmControlar.setCommandListener(this);
// Insert post-init code here
}
return frmControlar;
}
/** This method returns instance for frmConfiguracoes component and should be
called instead of accessing frmConfiguracoes field directly.
* @return Instance for frmConfiguracoes component
*/
public Form get_frmConfiguracoes() {
if (frmConfiguracoes == null) {
// Insert pre-init code here
frmConfiguracoes = new Form("Configura\u00E7\u00F5es", new Item[] {
get_txtTelefone(),
get_txtSenha(),
get_txtP1(),
get_txtP2(),
get_txtP3()
});
frmConfiguracoes.addCommand(get_okSalvar());
frmConfiguracoes.addCommand(get_backConfiguracoes());
frmConfiguracoes.setCommandListener(this);
// Insert post-init code here
}
return frmConfiguracoes;
}
/** This method returns instance for frmAjuda component and should be called
instead of accessing frmAjuda field directly.
* @return Instance for frmAjuda component
*/
52
public Form get_frmAjuda() {
if (frmAjuda == null) {
// Insert pre-init code here
frmAjuda = new Form("Ajuda", new Item[] {get_strAjuda()});
frmAjuda.addCommand(get_backAjuda());
frmAjuda.setCommandListener(this);
// Insert post-init code here
}
return frmAjuda;
}
/** This method returns instance for frmSobre component and should be called
instead of accessing frmSobre field directly.
* @return Instance for frmSobre component
*/
public Form get_frmSobre() {
if (frmSobre == null) {
// Insert pre-init code here
frmSobre = new Form("Sobre", new Item[] {get_strSobre()});
frmSobre.addCommand(get_backSobre());
frmSobre.setCommandListener(this);
// Insert post-init code here
}
return frmSobre;
}
/** This method returns instance for fntPequena component and should be called
instead of accessing fntPequena field directly.
* @return Instance for fntPequena component
*/
public Font get_fntPequena() {
if (fntPequena == null) {
// Insert pre-init code here
fntPequena = Font.getFont(Font.FACE_SYSTEM, 0x0, Font.SIZE_SMALL);
// Insert post-init code here
}
return fntPequena;
}
/** This method returns instance for txtTelefone component and should be called
instead of accessing txtTelefone field directly.
* @return Instance for txtTelefone component
*/
public TextField get_txtTelefone() {
if (txtTelefone == null) {
// Insert pre-init code here
txtTelefone = new TextField("Fone servidor:", null, 10,
TextField.PHONENUMBER);
txtTelefone.setInitialInputMode("null");
// Insert post-init code here
}
return txtTelefone;
}
/** This method returns instance for txtSenha component and should be called
instead of accessing txtSenha field directly.
* @return Instance for txtSenha component
*/
public TextField get_txtSenha() {
if (txtSenha == null) {
// Insert pre-init code here
txtSenha = new TextField("Senha:", null, 6, TextField.NUMERIC |
TextField.PASSWORD);
// Insert post-init code here
}
return txtSenha;
}
53
/** This method returns instance for txtP1 component and should be called
instead of accessing txtP1 field directly.
* @return Instance for txtP1 component
*/
public TextField get_txtP1() {
if (txtP1 == null) {
// Insert pre-init code here
txtP1 = new TextField("Descri\u00E7\u00E3o Porta1:", null, 20,
TextField.ANY);
// Insert post-init code here
}
return txtP1;
}
/** This method returns instance for txtP2 component and should be called
instead of accessing txtP2 field directly.
* @return Instance for txtP2 component
*/
public TextField get_txtP2() {
if (txtP2 == null) {
// Insert pre-init code here
txtP2 = new TextField("Descri\u00E7\u00E3o Porta2:", null, 20,
TextField.ANY);
// Insert post-init code here
}
return txtP2;
}
/** This method returns instance for txtP3 component and should be called
instead of accessing txtP3 field directly.
* @return Instance for txtP3 component
*/
public TextField get_txtP3() {
if (txtP3 == null) {
// Insert pre-init code here
txtP3 = new TextField("Descri\u00E7\u00E3o Porta3:", null, 20,
TextField.ANY);
// Insert post-init code here
}
return txtP3;
}
/** This method returns instance for okSalvar component and should be called
instead of accessing okSalvar field directly.
* @return Instance for okSalvar component
*/
public Command get_okSalvar() {
if (okSalvar == null) {
// Insert pre-init code here
okSalvar = new Command("Salvar", Command.OK, 1);
// Insert post-init code here
}
return okSalvar;
}
/** This method returns instance for waitConfiguracoes component and should be
called instead of accessing waitConfiguracoes field directly.
* @return Instance for waitConfiguracoes component
*/
public org.netbeans.microedition.lcdui.WaitScreen get_waitConfiguracoes() {
if (waitConfiguracoes == null) {
// Insert pre-init code here
waitConfiguracoes = new
org.netbeans.microedition.lcdui.WaitScreen(getDisplay());
waitConfiguracoes.setCommandListener(this);
waitConfiguracoes.setTitle("Salvar");
waitConfiguracoes.setFullScreenMode(true);
54
waitConfiguracoes.setText("Salvando configura\u00E7\u00F5es...");
waitConfiguracoes.setTask(get_taskSalvar());
// Insert post-init code here
}
return waitConfiguracoes;
}
/** This method returns instance for altFalhaSalvarConfiguracoes component and
should be called instead of accessing altFalhaSalvarConfiguracoes field directly.
* @return Instance for altFalhaSalvarConfiguracoes component
*/
public Alert get_altFalhaSalvarConfiguracoes() {
if (altFalhaSalvarConfiguracoes == null) {
// Insert pre-init code here
altFalhaSalvarConfiguracoes = new Alert("Erro", "Erro ao salvar
configura\u00E7\u00F5es!", null, AlertType.ERROR);
altFalhaSalvarConfiguracoes.setTimeout(3000);
// Insert post-init code here
}
return altFalhaSalvarConfiguracoes;
}
/** This method returns instance for altSucessoSalvarConfiguracoes component
and should be called instead of accessing altSucessoSalvarConfiguracoes field
directly.
* @return Instance for altSucessoSalvarConfiguracoes component
*/
public Alert get_altSucessoSalvarConfiguracoes() {
if (altSucessoSalvarConfiguracoes == null) {
// Insert pre-init code here
altSucessoSalvarConfiguracoes = new Alert("Sucesso",
"Configura\u00E7\u00F5es salvas com sucesso!", null, AlertType.CONFIRMATION);
altSucessoSalvarConfiguracoes.setTimeout(3000);
// Insert post-init code here
}
return altSucessoSalvarConfiguracoes;
}
/** This method returns instance for backSobre component and should be called
instead of accessing backSobre field directly.
* @return Instance for backSobre component
*/
public Command get_backSobre() {
if (backSobre == null) {
// Insert pre-init code here
backSobre = new Command("Voltar", Command.BACK, 1);
// Insert post-init code here
}
return backSobre;
}
/** This method returns instance for strAjuda component and should be called
instead of accessing strAjuda field directly.
* @return Instance for strAjuda component
*/
public StringItem get_strAjuda() {
if (strAjuda == null) {
// Insert pre-init code here
strAjuda = new StringItem(null, "Primeiramente, em
Configura\u00E7\u00F5es, defina o telefone onde o Dispositivo Servidor Local
est\u00E1 ligado, a senha de seguran\u00E7a, e, se desejar, tamb\u00E9m defina as
descri\u00E7\u00F5es dos elementos ligados \u00E0s portas. Salve as
configura\u00E7\u00F5es.\n\nPara alterar o estado das portas, em Controlar, escolha
para cada uma delas um estado: N\u00E3o alterar, Ligar ou Desligar. Ap\u00F3s isso
selecione ENVIAR para enviar o comando ao Dispositivo Servidor Local.");
strAjuda.setFont(get_fntPequena());
// Insert post-init code here
55
}
return strAjuda;
}
/** This method returns instance for backAjuda component and should be called
instead of accessing backAjuda field directly.
* @return Instance for backAjuda component
*/
public Command get_backAjuda() {
if (backAjuda == null) {
// Insert pre-init code here
backAjuda = new Command("Voltar", Command.BACK, 1);
// Insert post-init code here
}
return backAjuda;
}
/** This method returns instance for backConfiguracoes component and should be
called instead of accessing backConfiguracoes field directly.
* @return Instance for backConfiguracoes component
*/
public Command get_backConfiguracoes() {
if (backConfiguracoes == null) {
// Insert pre-init code here
backConfiguracoes = new Command("Voltar", Command.BACK, 1);
// Insert post-init code here
}
return backConfiguracoes;
}
/** This method returns instance for strSobre component and should be called
instead of accessing strSobre field directly.
* @return Instance for strSobre component
*/
public StringItem get_strSobre() {
if (strSobre == null) {
// Insert pre-init code here
strSobre = new StringItem(null, "Parte integrante da monografia
entitulada \"Automa\u00E7\u00E3o Residencial Remota utilizando
Sinaliza\u00E7\u00E3o DTMF\", desenvolvida por Luiz Fernando Castro da Cruz,
orientada por J\u00FAlio Carlos Balzano de Mattos, durante a disciplina de Trabalho
de Conclus\u00E3o de Curso em Inform\u00E1tica II, apresentada ao curso de
Ci\u00EAncia da Computa\u00E7\u00E3o, da Universidade Luterana do Brasil - ULBRA,
campus Gravata\u00ED, em julho de 2007, como pr\u00E9-requisito para
obten\u00E7\u00E3o do t\u00EDtulo de Bacharel em Ci\u00EAncia da
Computa\u00E7\u00E3o.");
strSobre.setFont(get_fntPequena());
// Insert post-init code here
}
return strSobre;
}
/** This method returns instance for backControlar component and should be
called instead of accessing backControlar field directly.
* @return Instance for backControlar component
*/
public Command get_backControlar() {
if (backControlar == null) {
// Insert pre-init code here
backControlar = new Command("Voltar", Command.BACK, 1);
// Insert post-init code here
}
return backControlar;
}
/** This method returns instance for taskSalvar component and should be called
instead of accessing taskSalvar field directly.
56
* @return Instance for taskSalvar component
*/
public org.netbeans.microedition.util.SimpleCancellableTask get_taskSalvar() {
if (taskSalvar == null) {
// Insert pre-init code here
taskSalvar = new
org.netbeans.microedition.util.SimpleCancellableTask();
taskSalvar.setExecutable(new
org.netbeans.microedition.util.Executable() {
public void execute() throws Exception {
rsp.open();
rsp.update(1, txtTelefone.getString());
rsp.update(2, txtSenha.getString());
rsp.update(3, txtP1.getString());
rsp.update(4, txtP2.getString());
rsp.update(5, txtP3.getString());
rsp.close();
}
});
// Insert post-init code here
}
return taskSalvar;
}
/** This method returns instance for exitInicial component and should be called
instead of accessing exitInicial field directly.
* @return Instance for exitInicial component
*/
public Command get_exitInicial() {
if (exitInicial == null) {
// Insert pre-init code here
exitInicial = new Command("Sair", Command.EXIT, 1);
// Insert post-init code here
}
return exitInicial;
}
/** This method returns instance for chgrpPorta1 component and should be called
instead of accessing chgrpPorta1 field directly.
* @return Instance for chgrpPorta1 component
*/
public ChoiceGroup get_chgrpPorta1() {
if (chgrpPorta1 == null) {
// Insert pre-init code here
chgrpPorta1 = new ChoiceGroup("Porta1", Choice.POPUP, new String[] {
"N\u00E3o alterar",
"Ligar",
"Desligar"
}, new Image[] {
get_imgNaoAlterar(),
get_imgLigar(),
get_imgDesligar()
});
chgrpPorta1.setSelectedFlags(new boolean[] {
true,
false,
false
});
// Insert post-init code here
}
return chgrpPorta1;
}
/** This method returns instance for chgrpPorta2 component and should be called
instead of accessing chgrpPorta2 field directly.
* @return Instance for chgrpPorta2 component
*/
57
public ChoiceGroup get_chgrpPorta2() {
if (chgrpPorta2 == null) {
// Insert pre-init code here
chgrpPorta2 = new ChoiceGroup("Porta2", Choice.POPUP, new String[] {
"N\u00E3o alterar",
"Ligar",
"Desligar"
}, new Image[] {
get_imgNaoAlterar(),
get_imgLigar(),
get_imgDesligar()
});
chgrpPorta2.setSelectedFlags(new boolean[] {
true,
false,
false
});
// Insert post-init code here
}
return chgrpPorta2;
}
/** This method returns instance for chgrpPorta3 component and should be called
instead of accessing chgrpPorta3 field directly.
* @return Instance for chgrpPorta3 component
*/
public ChoiceGroup get_chgrpPorta3() {
if (chgrpPorta3 == null) {
// Insert pre-init code here
chgrpPorta3 = new ChoiceGroup("Porta3", Choice.POPUP, new String[] {
"N\u00E3o alterar",
"Ligar",
"Desligar"
}, new Image[] {
get_imgNaoAlterar(),
get_imgLigar(),
get_imgDesligar()
});
chgrpPorta3.setSelectedFlags(new boolean[] {
true,
false,
false
});
// Insert post-init code here
}
return chgrpPorta3;
}
/** This method returns instance for okEnviar component and should be called
instead of accessing okEnviar field directly.
* @return Instance for okEnviar component
*/
public Command get_okEnviar() {
if (okEnviar == null) {
// Insert pre-init code here
okEnviar = new Command("ENVIAR", Command.OK, 1);
// Insert post-init code here
}
return okEnviar;
}
/** This method returns instance for taskEnviar component and should be called
instead of accessing taskEnviar field directly.
* @return Instance for taskEnviar component
*/
public org.netbeans.microedition.util.SimpleCancellableTask get_taskEnviar() {
if (taskEnviar == null) {
58
// Insert pre-init code here
taskEnviar = new
org.netbeans.microedition.util.SimpleCancellableTask();
taskEnviar.setExecutable(new
org.netbeans.microedition.util.Executable() {
public void execute() throws Exception {
final String CHR_BLOCO = "*";
final String CHR_CMD = "#";
final int VAL_CHR_CMD = 12;
final String CHR_LIGA = "1";
final int VAL_CHR_LIGA = 1;
final String CHR_DESL = "0";
final int VAL_CHR_DESL = 10;
final String CHR_ZERO = "#";
rsp.open();
pauseApp();
notifyPaused();
String s = "";
int i;
int dv = 0;
int m = 2;
s += CHR_BLOCO;
s += rsp.getRecord(2);
s += CHR_CMD;
if(chgrpPorta1.getSelectedIndex() != 0){
if(chgrpPorta1.getSelectedIndex() == 1){
s += "1" + CHR_LIGA;
}else{
s += "1" + CHR_DESL;
}
}
if(chgrpPorta2.getSelectedIndex() != 0){
if(chgrpPorta2.getSelectedIndex() == 1){
s += "2" + CHR_LIGA;
}else{
s += "2" + CHR_DESL;
}
}
if(chgrpPorta3.getSelectedIndex() != 0){
if(chgrpPorta3.getSelectedIndex() == 1){
s += "3" + CHR_LIGA;
}else{
s += "3" + CHR_DESL;
}
}
s += CHR_CMD;
for(i = s.toString().length(); i > 1; i--){
if(s.toString().substring(i - 1, i).compareTo(CHR_CMD) ==
0){
dv += m++ * VAL_CHR_CMD;
}else{
if(s.toString().substring(i - 1, i).compareTo(CHR_LIGA)
== 0){
dv += m++ * VAL_CHR_LIGA;
}else{
if(s.toString().substring(i - 1,
i).compareTo(CHR_DESL) == 0){
dv += m++ * VAL_CHR_DESL;
}else{
dv += m++ *
Integer.valueOf(s.toString().substring(i - 1, i)).intValue();
}
}
}
}
dv = dv * 10;
59
dv = dv % 11;
if(dv == 10){
s += "0";
}else{
if(dv == 0){
s += CHR_ZERO;
}else{
s += String.valueOf(dv);
}
}
s += CHR_BLOCO;
platformRequest("tel:" + rsp.getRecord(1) + "p" + s);
resumeRequest();
rsp.close();
}
});
// Insert post-init code here
}
return taskEnviar;
}
/** This method returns instance for imgControlar component and should be
called instead of accessing imgControlar field directly.
* @return Instance for imgControlar component
*/
public Image get_imgControlar() {
if (imgControlar == null) {
// Insert pre-init code here
try {
imgControlar =
Image.createImage("/libraries/resources/controlar.jpg");
} catch (java.io.IOException exception) {
exception.printStackTrace();
}
// Insert post-init code here
}
return imgControlar;
}
/** This method returns instance for imgConfiguracoes component and should be
called instead of accessing imgConfiguracoes field directly.
* @return Instance for imgConfiguracoes component
*/
public Image get_imgConfiguracoes() {
if (imgConfiguracoes == null) {
// Insert pre-init code here
try {
imgConfiguracoes =
Image.createImage("/libraries/resources/configuracoes.jpg");
} catch (java.io.IOException exception) {
exception.printStackTrace();
}
// Insert post-init code here
}
return imgConfiguracoes;
}
/** This method returns instance for imgAjuda component and should be called
instead of accessing imgAjuda field directly.
* @return Instance for imgAjuda component
*/
public Image get_imgAjuda() {
if (imgAjuda == null) {
// Insert pre-init code here
try {
imgAjuda = Image.createImage("/libraries/resources/ajuda.jpg");
60
} catch (java.io.IOException exception) {
exception.printStackTrace();
}
// Insert post-init code here
}
return imgAjuda;
}
/** This method returns instance for imgSobre component and should be called
instead of accessing imgSobre field directly.
* @return Instance for imgSobre component
*/
public Image get_imgSobre() {
if (imgSobre == null) {
// Insert pre-init code here
try {
imgSobre = Image.createImage("/libraries/resources/sobre.jpg");
} catch (java.io.IOException exception) {
exception.printStackTrace();
}
// Insert post-init code here
}
return imgSobre;
}
/** This method returns instance for imgLigar component and should be called
instead of accessing imgLigar field directly.
* @return Instance for imgLigar component
*/
public Image get_imgLigar() {
if (imgLigar == null) {
// Insert pre-init code here
try {
imgLigar = Image.createImage("/libraries/resources/ligar.jpg");
} catch (java.io.IOException exception) {
exception.printStackTrace();
}
// Insert post-init code here
}
return imgLigar;
}
/** This method returns instance for imgDesligar component and should be called
instead of accessing imgDesligar field directly.
* @return Instance for imgDesligar component
*/
public Image get_imgDesligar() {
if (imgDesligar == null) {
// Insert pre-init code here
try {
imgDesligar =
Image.createImage("/libraries/resources/desligar.jpg");
} catch (java.io.IOException exception) {
exception.printStackTrace();
}
// Insert post-init code here
}
return imgDesligar;
}
/** This method returns instance for imgNaoAlterar component and should be
called instead of accessing imgNaoAlterar field directly.
* @return Instance for imgNaoAlterar component
*/
public Image get_imgNaoAlterar() {
if (imgNaoAlterar == null) {
// Insert pre-init code here
61
try {
imgNaoAlterar =
Image.createImage("/libraries/resources/nao_alterar.jpg");
} catch (java.io.IOException exception) {
exception.printStackTrace();
}
// Insert post-init code here
}
return imgNaoAlterar;
}
/** This method returns instance for waitEnviar component and should be called
instead of accessing waitEnviar field directly.
* @return Instance for waitEnviar component
*/
public org.netbeans.microedition.lcdui.WaitScreen get_waitEnviar() {
if (waitEnviar == null) {
// Insert pre-init code here
waitEnviar = new
org.netbeans.microedition.lcdui.WaitScreen(getDisplay());
waitEnviar.setCommandListener(this);
waitEnviar.setTitle("Enviar");
waitEnviar.setFullScreenMode(true);
waitEnviar.setText("Enviando comando...");
waitEnviar.setTask(get_taskEnviar());
// Insert post-init code here
}
return waitEnviar;
}
/** This method returns instance for altFalhaEnviarComando component and should
be called instead of accessing altFalhaEnviarComando field directly.
* @return Instance for altFalhaEnviarComando component
*/
public Alert get_altFalhaEnviarComando() {
if (altFalhaEnviarComando == null) {
// Insert pre-init code here
altFalhaEnviarComando = new Alert("Erro", "Erro ao enviar comando!",
null, AlertType.ERROR);
altFalhaEnviarComando.setTimeout(3000);
// Insert post-init code here
}
return altFalhaEnviarComando;
}
/** This method returns instance for altSucessoEnviarComando component and
should be called instead of accessing altSucessoEnviarComando field directly.
* @return Instance for altSucessoEnviarComando component
*/
public Alert get_altSucessoEnviarComando() {
if (altSucessoEnviarComando == null) {
// Insert pre-init code here
altSucessoEnviarComando = new Alert("Sucesso", "Comando enviado com
sucesso!", null, AlertType.CONFIRMATION);
altSucessoEnviarComando.setTimeout(3000);
// Insert post-init code here
}
return altSucessoEnviarComando;
}
public void startApp() {
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
62
}
}
63
ANEXO B – CÓDIGO-FONTE DA CLASSE RECORD STORE
PERSONAL
package rms;
import java.io.*;
import javax.microedition.rms.*;
public class RecordStorePersonal {
private static String RS_NAME = "CONFIGS";
private RecordStore rs = null;
public void open() {
try {
//rs.deleteRecordStore(RS_NAME);
rs = RecordStore.openRecordStore(RS_NAME, true);
if (rs.getNumRecords() == 0){
for(int i = 0; i < 5; i++){
add("");
}
}
}
catch (RecordStoreNotFoundException e) {
System.out.println("-- RecordStore inexistente");
}
catch (RecordStoreException e) {
System.out.println("-- Outro erro");
}
}
public void close() {
try {
rs.closeRecordStore();
}
catch (RecordStoreNotOpenException e) {
System.out.println("-- O Record Store esta fechado");
}
catch (RecordStoreException e) {
System.out.println("-- Outro erro");
}
}
public void add(String nome) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeUTF(nome);
dos.flush();
byte[] data = baos.toByteArray();
int id = rs.addRecord(data, 0, data.length);
64
baos.close();
dos.close();
}
catch (IOException e) {
System.out.println("-- Erro de IO");
}
catch (RecordStoreFullException e) {
System.out.println("-- Não existe espaço disponível");
}
catch (RecordStoreNotOpenException e) {
System.out.println("-- O Record Store esta fechado");
}
catch (RecordStoreException e) {
System.out.println("-- Outro erro");
}
}
public String getRecord(int id) {
String toReturn = null;
try {
int recordSize = rs.getRecordSize(id);
byte[] data = new byte[recordSize];
ByteArrayInputStream bais = new ByteArrayInputStream(data);
DataInputStream dis = new DataInputStream(bais);
int numBytes = rs.getRecord(id, data, 0);
toReturn = dis.readUTF();
bais.reset();
bais.close();
dis.close();
}
catch (IOException e) {
System.out.println("-- Erro de IO");
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println("-- Registro muito grande");
}
catch (InvalidRecordIDException e) {
System.out.println("-- ID inexistente");
}
catch (RecordStoreNotOpenException e) {
System.out.println("-- O Record Store esta fechado");
}
catch (RecordStoreException e) {
System.out.println("-- Outro erro");
}
return toReturn;
}
public void update(int id, String nome) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeUTF(nome);
dos.flush();
byte[] data = baos.toByteArray();
rs.setRecord(id, data, 0, data.length);
}
catch (IOException e) {
System.out.println("-- Erro de IO");
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println("-- Registro muito grande");
}
catch (InvalidRecordIDException e) {
System.out.println("-- ID inexistente");
}
catch (RecordStoreNotOpenException e) {
65
System.out.println("-- O Record Store esta fechado");
}
catch (RecordStoreException e) {
System.out.println("-- Outro erro");
}
}
}
66
ANEXO C – CÓDIGO-FONTE DA PARTE CONTROLADORA
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define T_0 10
#define T_1 1
#define T_2 2
#define T_3 3
#define T_4 4
#define T_5 5
#define T_6 6
#define T_7 7
#define T_8 8
#define T_9 9
#define T_AST 11
#define T_SUS 12
#define T_A 13
#define T_B 14
#define T_C 15
#define T_D 0
#define CHR_BLOCO T_AST
#define CHR_CMD T_SUS
#define CHR_LIGA T_1
#define CHR_DESL T_0
#define CHR_ZERO T_SUS
#define TAM_SENHA 6
#define SENHA {1, 2, 3, 4, 5, 6}
#define OK 0xDF
#define ERRO 0x20
ISR(INT0_vect);
ISR(INT1_vect);
void reinicia();
uint8_t lerTom();
void mudaEstado(uint8_t tom);
uint8_t processaMudanca(uint8_t tom);
uint8_t verificaSenha();
uint8_t verificaIntegridade(uint8_t verificador);
void executa();
void defineStatus(uint8_t status);
uint8_t senha[6] = SENHA;
uint8_t bufSenha[6];
uint8_t pBufSenha;
uint8_t bufComandos[6];
uint8_t pBufComandos;
uint8_t estado;
int main(){
DDRB = 0x00;
67
DDRD = 0x00;
DDRE = 0xF0;
EIMSK |= _BV(INT0) | _BV(INT1);
EICRA |= _BV(ISC01) | _BV(ISC11);
sei();
reinicia();
}
ISR(INT0_vect){
defineStatus(OK);
reinicia();
}
ISR(INT1_vect){
uint8_t t;
t = lerTom();
mudaEstado(t);
if(processaMudanca(t) != 0){
defineStatus(ERRO);
reinicia();
}
}
void reinicia(){
pBufSenha = 0;
pBufComandos = 0;
estado = 0;
}
uint8_t lerTom(){
return 0x0F & (((PIND & 0x40) >> 6) | ((PINB & 0x20) >> 4) | ((PIND & 0x10)
>> 2) | ((PINB & 0x40) >> 3));
}
void mudaEstado(uint8_t tom){
if(tom == CHR_BLOCO && estado != 6){
reinicia();
}
switch(estado){
case 0:
if(tom == CHR_BLOCO){
estado = 1;
}
break;
case 1:
if((tom >= T_1) && (tom <= T_0)){
estado = 1;
}else{
if(tom == CHR_CMD){
estado = 2;
}else{
estado = 8;
}
}
break;
case 2:
if((tom >= T_1) && (tom <= T_3)){
estado = 3;
}else{
estado = 8;
}
break;
case 3:
if((tom == CHR_LIGA) || (tom == CHR_DESL)){
estado = 4;
}else{
estado = 8;
68
}
break;
case 4:
if((tom >= T_1) && (tom <= T_3)){
estado = 3;
}else{
if(tom == CHR_CMD){
estado = 5;
}else{
estado = 8;
}
}
break;
case 5:
if(tom == CHR_ZERO || ((tom >= T_1) && (tom <= T_0))){
estado = 6;
}else{
estado = 8;
}
break;
case 6:
if(tom == CHR_BLOCO){
estado = 7;
}else{
estado = 8;
}
}
}
uint8_t processaMudanca(uint8_t tom){
switch(estado){
case 1:
if(tom != CHR_BLOCO){
if(pBufSenha < 6){
bufSenha[pBufSenha] = tom;
pBufSenha++;
}else{
return 1;
}
}
break;
case 2:
if(verificaSenha() != 0){
return 2;
}
break;
case 3:
if(pBufComandos < 6){
bufComandos[pBufComandos] = tom;
pBufComandos++;
}else{
return 3;
}
break;
case 4:
bufComandos[pBufComandos] = tom;
pBufComandos++;
break;
case 6:
if(tom == CHR_ZERO){
tom = 0;
}
if(verificaIntegridade(tom) != 0){
return 4;
}
break;
case 7:
69
executa();
reinicia();
break;
case 8:
return 5;
}
defineStatus(OK);
return 0;
}
uint8_t verificaSenha(){
uint8_t i;
if(pBufSenha != TAM_SENHA){
return 1;
}
for(i = 0; i < TAM_SENHA; i++){
if(senha[i] != bufSenha[i]){
return 2;
}
}
return 0;
}
uint8_t verificaIntegridade(uint8_t verificador){
int resultado;
uint8_t i;
uint8_t multiplicador = 2;
resultado = CHR_CMD * multiplicador;
for(i = pBufComandos; i > 0; i--){
multiplicador++;
resultado += bufComandos[i - 1] * multiplicador;
}
multiplicador++;
resultado += CHR_CMD * multiplicador;
for(i = pBufSenha; i > 0; i--){
multiplicador++;
resultado += bufSenha[i - 1] * multiplicador;
}
resultado = (resultado * 10) % 11;
if(resultado == verificador){
return 0;
}else{
return 1;
}
}
void executa(){
uint8_t i;
for(i = 0; i < pBufComandos; i+=2){
switch(bufComandos[i]){
case 1:
if(bufComandos[i + 1] == CHR_LIGA){
PORTE |= 0x40;
}else{
PORTE &= 0xBF;
}
break;
case 2:
if(bufComandos[i + 1] == CHR_LIGA){
PORTE |= 0x10;
}else{
PORTE &= 0xEF;
}
break;
case 3:
if(bufComandos[i + 1] == CHR_LIGA){
PORTE |= 0x80;
70
}else{
PORTE &= 0x7F;
}
}
}
}
void defineStatus(uint8_t status){
if(status == OK){
PORTE &= status;
}else{
PORTE |= status;
}
}
REFERÊNCIAS
BOLZANI, Caio Augustus Morais. Residências Inteligentes. São Paulo: Editora Livraria da
Física, 2004. 332 p.
MUCHOW, John W. Core J2ME – Tecnologia & MIDP. São Paulo: Editora PEARSON
Makron Books, 2004. 588 p.
AHO, Alfred; SETHI, Ravi; ULLMAN, Jeffrey. Compiladores – Princípios, Técnicas e
Ferramentas. Rio de Janeiro: Editora Guanabara Koogan S.A., 1995. 344 p.
ARAUJO, Jair Jonko. Framework Orientado a Objetos para o Desenvolvimento de
Aplicações de Automação Predial e Residencial. Porto Alegre: DISS UFRGS, 2005.
PARMEGGIANI, André Antonio. LAR – Laboratório de Automação Residencial para
análise comparativa entre Jini e UPnP. Porto Alegre: DISS UFRGS, 2003.
AMORY, Alexandre; PETRINI, Juracy Júnior. Sistema Integrado e Multiplataforma para
Controle Remoto de Residências. Porto Alegre: TCC PUC/RS, 2001.
CORUJA, Eduardo de Jesus. Solução para Controle Unificado em um Projeto de
Automação Residencial. Porto Alegre: TCC ULBRA Gravataí, 2005.
SGT, Shouting Ground Technologies. DTMF also known as Touch Tone. Disponível em:
<http://www.shout.net/~wildixon/telecom/dtmf/dtmf.html>. Acesso em: 27 mai. 2007.
CARNIEL, Juliano; TEIXEIRA, Clóvis. Apostila de J2ME. Natal: UFRGN, 2005. 52 f.
Disponível em: <http://www.engcomp.ufrn.br/~evebat/tutorialj2me1.pdf>. Acesso em: 18
mai. 2007.
NOKIA. RFC2806. Disponível em: <http://www.ietf.org/rfc/rfc2806.txt?number=2806>.
Acesso em: 15 jun. 2007.
MITEL. MT8870D/MT8870D-1 Integrated DTMF Receiver. 1995. Disponível em:
<http://www.tranzistoare.ro/datasheets/228/268107_DS.pdf>. Acesso em: 17 jun. 2007.
ATMEL. 8-bit AVR Microcontroller with 64K Bytes In-System Programmable Flash.
2006. Disponível em: <http://www.atmel.com/dyn/resources/prod_documents/doc2490.pdf>.
Acesso em: 17 jun. 2007.
DIGILENT. Digilent Cerebot Board Reference Manual. 2005. Disponível em: <
http://www.digilentinc.com/Data/Products/CEREBOT/CEREBOT-rm.pdf>. Acesso em: 25
jun. 2007.
COMPARATEL. Comparar tarifas. Disponível em:
<http://www.comparatel.com.br/online/compare.asp>. Acesso em: 01 jul. 2007.
72
BURGOS, Eletrônica Burgos. Fotoacopladores. Disponível em:
<http://www.burgoseletronica.net/fotoacopladores.htm>. Acesso em: 01 jul. 2007.
WIKIPEDIA, a enciclopédia livre. Domótica. [S.I.]: [s.n.], 2007-a. Disponível em:
<http://pt.wikipedia.org/wiki/Dom%C3%B3tica>. Acesso em: 12 mai. 2007.
WIKIPEDIA, a enciclopédia livre. DTMF. [S.I.]: [s.n.], 2007-b. Disponível em:
<http://pt.wikipedia.org/wiki/Dtmf>. Acesso em: 12 mai. 2007.
WIKIPEDIA, a enciclopédia livre. QWERTY. [S.I.]: [s.n.], 2007-c. Disponível em:
<http://pt.wikipedia.org/wiki/QWERTY>. Acesso em: 18 jun. 2007.
WIKIPEDIA, a enciclopédia livre. Força contra-eletromotriz. [S.I.]: [s.n.], 2007-d.
Disponível em: <http://pt.wikipedia.org/wiki/For%C3%A7a_contra-eletromotriz>. Acesso
em: 01 jul. 2007.
WIKIPEDIA, a enciclopédia livre. Dígito verificador. [S.I.]: [s.n.], 2007-e. Disponível em:
<http://pt.wikipedia.org/wiki/D%C3%ADgito_verificador>. Acesso em: 22 jun. 2007.