Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
Guia do programador de NQC
Versão 2.5 a4 Por Dave Baum
Traduzido por Ricardo Ortins
ÍNDICE
1. Introdução..............................................................................................................1
2. Linguagem NQC....................................................................................................2
2.1 Regra léxica............................................................................................................2
2.1.1. Comentários......................................................................................................2
2.1.2. Espaço em branco.............................................................................................2
2.1.3. Constantes numéricas.......................................................................................3
2.1.4. Identificadores e palavras reservadas...............................................................3
2.2. Estrutura do programa...........................................................................................4
2.2.1. Tarefas..............................................................................................................4
2.2.2. Funções.............................................................................................................4
2.2.3. Sub-rotinas........................................................................................................7
2.2.4. Variáveis...........................................................................................................8
2.2.5. Matrizes..........................................................................................................10
2.3. Instruções............................................................................................................10
2.3.1. Declaração de variáveis..................................................................................10
2.3.2. Atribuição.......................................................................................................11
2.3.3. Estruturas de controle.....................................................................................11
2.3.4. Controle de acesso e eventos..........................................................................15
2.3.5. Outras instruções............................................................................................17
2.4. Expressões...........................................................................................................17
2.4.1. Condicionais...................................................................................................19
2.5. O pré-processador................................................................................................20
2.5.1. # include.........................................................................................................20
2.5.2. # define...........................................................................................................20
2.5.3. Compilação condicional.................................................................................21
2.5.4. Iniciação do programa....................................................................................21
2.5.5. Armazenamento de reserva............................................................................21
3. NQC API..............................................................................................................22
3.1. Sensores...............................................................................................................22
3.1.1. Tipos e modos RCX, CyberMaster................................................................22
3.1.2. Informação do sensor.....................................................................................25
3.1.3. Sensor de luz do Scout ..................................................................................26
3.1.4. Sensor de luz do Spybotics Spy.....................................................................27
3.2. Saídas.................................................................................................................27
3.2.1. Funções básicas.............................................................................................27
3.2.2. Outras funções...............................................................................................28
3.2.3. Controle Global RCX2, Scout.......................................................................30
3.2.4. Saídas de Spybotics.......................................................................................31
3.3. Som.....................................................................................................................31
3.4. Display LCD RCX............................................................................................32
3.5. Comunicação......................................................................................................33
3.5.1. Mensagens RCX, Scout.................................................................................33
3.5.2. Série RCX2, Scout.........................................................................................34
3.5.3. VLL (Link de luz visível), Scout...................................................................36
3.6. Temporizadores..................................................................................................36
3.7. Contadores RCX2, Scout, Spy...........................................................................37
3.8. Controle de acesso RCX2, Scout, Spy...............................................................38
3.9. Evento RCX2, Scout..........................................................................................38
3.9.1. Eventos do RCX, spy....................................................................................39
3.9.2. Eventos do Scout...........................................................................................43
3.10. Registro de dados RCX....................................................................................45
3.11. Características gerais........................................................................................46
3.12. Características específicas do RCX..................................................................47
3.13. Características específicas do Scout.................................................................48
3.14. Características específicas do Cybermaster......................................................48
4. Detalhes técnicos.................................................................................................50
4.1. A instrução ASN.................................................................................................50
4.2. Fontes de dados..................................................................................................52
5. Nota do tradutor...................................................................................................54
____________________Guia do programador de NQC________________________
1
1. Introdução
NQC significa Not Quite C (Não completamente C) e, é uma linguagem simples
para programar vários produtos LEGO MINDSTORMS. Algumas das características de
NQC dependem do produto MINDSTORMS que se utilize. NQC se refere aos
diferentes blocos inteligentes como os modelos. Atualmente NQC suporta quatro
diferentes modelos: RCX, RCX2 (Um RCX que executa um firmware versão 2.0),
CyberMaster, Scout e Spybotics.
Todos os modelos têm um intérprete de bytes (proporcionado por Lego) que pode
ser utilizado para executar programas. O compilador NQC converte um programa fonte
em LEGO Bytecode, o qual pode ser executado no próprio modelo. Ainda que as
estruturas de processamento e de controle sejam muito similares a C, NQC não é uma
linguagem de propósito geral
há muitas restrições que são produtos das limitações do
intérprete de código de bytes Lego.
Logicamente o NQC se define em duas partes diferentes.
A linguagem NQC descreve a sintaxe utilizada ao escrever programas. O NQC
API descreve as funções dos sistemas, constantes e macros que se podem usar nos
programas. Esta API define-se em um arquivo especial incluído no compilador.
Por definição, esse arquivo sempre se processa antes de compilar o programa.
Esse documento descreve ambos: a linguagem NQC e o NQC API. Em resumo,
proporciona a informação necessária para escrever programas em NQC. Dado que há
várias interfaces para NQC, esse documento não descreve como usar nenhuma
implementação de NQC específica. Consulte a documentação oferecida com a
ferramenta NQC, assim como o manual de usuário de NQC para informações
específicas para essa implementação.
Se deseja informação em documentação atualizada de NQC, visite o site web de
NQC na seguinte direção:
http:// www.baumfamily.org/nqc
____________________Guia do programador de NQC________________________
2
2. Linguagem NQC
Esta sessão descreve a própria linguagem NQC. Inclui as regras léxicas usadas
pelo compilador, a estrutura dos programas, sentenças e expressões e, o funcionamento
do processador.
2.1. Regras Léxicas
As regras léxicas descrevem como o NQC divide um arquivo fonte em sinais
individuais. Inclui como estão escritos os comentários, o manejo dos espaços em branco
e os caracteres válidos para identificadores.
2.1.1. Comentários
NQC suporta dois tipos de comentários. O primeiro tipo (comentário C
tradicional) começa com /* e termina com */ . Podem conter várias linhas, mas não
podem adicionar.
/* isto é um comentário*/
/* isto é um comentário
de duas linhas */
/* outro comentário...
/* tentando adicionar...
finalizando o comentário de dentro... */
Esse texto já não é um comentário! */
A segunda classe de comentário começa com // e termina com uma nova linha
(conhecido às vezes como comentário estilo c++).
// um comentário de uma linha simples
O compilador ignora os comentários. Seu único propósito é permitir ao
programador documentar o código fonte.
2.1.2. Espaços em branco
O espaço em branco (espaços, tabulações e saltos de linha) usa-se para separar
sinais e para fazer os programas mais legíveis. Contanto que se distingam, os sinais, não
tem efeito no programa adicionar ou suprimir espaços em branco. Por exemplo, as
seguintes linhas de código têm o mesmo significado:
____________________Guia do programador de NQC________________________
3
x=2;
x = 2 ;
Alguns dos operadores de c++ estão formados por múltiplos caracteres. Para
preservar esses sinais não se deve inserir espaços em branco entre eles. No exemplo
seguinte, a primeira linha usa um operador de avanço para direita ( >> ), mas na
segunda linha o espaço adicionado faz com que os símbolos > se interpretem como
dois elementos separados e em conseqüência se gera um erro.
x = 1 >> 4; // dá a X o valor de 1 deslocado para direita 4 bits
x = 1 > > 4; // errado
2.1.3. Constantes Numéricas
As constantes numéricas podem se escrever tanto em formato decimal como
hexadecimal. As constantes decimais consistem em um ou mais dígitos decimais. As
constantes hexadecimais começam com 0x ou 0X seguidos de um ou mais dígitos
hexadecimais.
x = 10; // dá a x o valor 10
x = 0x10; // dá a x o valor 16 (10 hex)
2.1.4. Identificadores e palavras reservadas
Usam-se os identificadores para nomes de tarefas, variáveis e funções. O primeiro
caractere de um identificador deve ser uma letra maiúscula ou minúscula ou sublinhado
( _ ). Os caracteres restantes podem ser letras números e sublinhado.
Se reserva um número potencial de identificadores para uso da própria linguagem
de NQC. Essas palavras se denominam palavras reservadas e não se podem usar como
identificadores. Abaixo se oferece uma lista completa de palavras reservadas:
__event_src __res __tasked abs
__nolist __sensor __type acquire
asm do int sub
break else monitor switch
case false repeat task
catch for return true
const goto sign void
continue if start while
default inline stop
____________________Guia do programador de NQC________________________
4
2.2. Estrutura do programa
Um programa NQC compõe-se de blocos de código e variáveis globais. Existem
três tipos de blocos de código: tarefas, funções em linha e sub-rotinas. Cada tipo de
blocos de código tem suas próprias características e restrições particulares, mas todos
compartilham uma estrutura comum.
2.2.1.Tarefas
O RCX suporta multitarefas, de modo que uma tarefa em NQC corresponde a uma
tarefa RCX. As tarefas definem-se por meios da palavra reservada task utilizando a
seguinte sintaxe:
task nome()
{
// o código da tarefa se escreve aqui
}
O nome da tarefa pode ser qualquer identificador legal. Um programa deve ter ao
menos uma tarefa chamada main
que se inicia cada vez que se executa o programa. O
número máximo de tarefas depende do modelo
RCX suporta 10 tarefas, cybermaster 4
e, scout 6.
O corpo de uma tarefa consiste em uma lista de instruções. As tarefas podem
iniciar-se e parar utilizando as instruções start e stop (descritas na sessão intitulada
instruções). Existe também um comando RCX API stopalltasks, que pára todas as
tarefas em funcionamento neste momento.
2.2.2. Funções
Às vezes é útil agrupar um conjunto de instruções em uma só função, que pode ser
chamada quando seja necessário. NQC suporta funções com argumentos, mas não
valores de retorno. As funções se definem com as seguintes sintaxes:
void nome(lista_de_argumentos)
{
// corpo da função
}
A palavra reservada void é conseqüência da herança de NQC
em C as funções
se especificam com o tipo de dados que devolvem. As funções que não devolvem dados
devolvem void. A devolução de dados não tem suporte em NQC, de modo que todas as
funções se declaram usando a palavra reservada void.
____________________Guia do programador de NQC________________________
5
A lista de argumentos pode estar vazia ou pode conter uma ou mais definições de
argumento. Um argumento define-se por seu tipo, seguido de seu nome. Os argumentos
múltiplos separam-se por vírgulas. Todos os valores em RCX representam-se como
inteiros de 16 bits consígnos. No entanto, NQC suporta quatro tipos diferentes de
argumentos que correspondem a diferentes restrições e modos de passo do argumento.
Tipo Significado Restrição
Int Passa Valor Nenhuma
Const Int Passa Valor Só se pode usar constantes
Int& Passa Referência Só se pode usar variáveis
Const Int& Passa Referência A função não pode modificar argumentos
Os argumentos de tipo int passam-se por valores da função que chama para
função iniciada. Isto quer dizer, que o compilador deve definir uma variável temporal
que armazene o argumento. Não existem restrições para o tipo de valor que se pode
usar. No entanto, já que a função trabalha com a cópia do argumento em si, qualquer
mudança que sofra o valor não se vê na função que se chama. No exemplo abaixo a
função foo tenta estabelecer o valor de seu argumento em 2. Isto é perfeitamente legal,
mas dado que foo funciona como uma cópia do argumento original a variável Y da
tarefa principal não sofrerá mudanças.
void foo(int x)
{
x = 2;
}
task main()
{
int y = 1; // y é agora igual a 1
foo (y); // y continua igual a 1!
}
O segundo tipo de argumento, const int, também passa-se por valor, mas com a
restrição de só poder usar valores constantes (quer dizer, números). Isso é muito
importante já que existem várias funções RCX que só funcionam com argumentos
constantes:
void foo(const int x)
{
PlaySound (x); // ok
____________________Guia do programador de NQC________________________
6
x = 1; // erro não pode modificar um argumento
}
task main()
{
foo (2); // ok
foo (4*5 ); // ok expressão constante
foo (x); // erro - x não é uma constante
}
O terceiro tipo, int &, passa argumentos ou referências em vez de passar valor.
Isto permite que a função chamada modifique o valor e, faça visíveis as mudanças na
função que chama. No entanto, só se podem usar variáveis quando se chama uma
função usando argumento int &:
void foo(int &x)
{
x = 2;
}
task main()
{
int y = 1; // y é igual a 1
foo (y); // y é agora igual a 2
foo (2); // erro só se permitem variáveis
}
O último tipo, const int &, é muito pouco freqüente. Também se passa por
referência, mas com a restrição de que a função chamada não lhe permite modificar o
valor. A causa dessa restrição: o compilador pode passar qualquer coisa (não só
variáveis) à função usando esse tipo de argumento. Em geral esta é a forma mais
eficiente de passar argumentos em NQC.
Existe uma diferença importante entre argumentos int e argumentos const int & .
Um argumento int passa-se por valor, de modo que no caso de uma expressão dinâmica
(como a leitura de um sensor) o valor lê uma vez e se armazena. Com os argumentos
const int & , a expressão lê cada vez que é usada na função:
void foo(int x)
{
if (x == x) // isto sempre é verdade
PlaySound(SOUND_CLICK);
}
void bar(const int &x)
{
____________________Guia do programador de NQC________________________
7
if (x == x) //pode não ser verdade..
// o valor poderia mudar
PlaySound(SOUND_CLICK);
}
task main()
{
foo(SENSOR_1); // reproduz som
bar(2); // reproduz som
bar(SENSOR_1); // poderia não reproduzir som
}
As funções devem chamar com o número (e tipo) correto de argumentos.
O exemplo seguinte mostra diferentes chamadas legais e ilegais da função foo:
void foo(int bar, const int baz)
{
// faz algo aqui...
}
task main()
{
int x; // declarar variável x
foo (1,2); // ok
foo (x,2); // ok
foo (2,x); // erro segundo argumento não constante!
foo (2); // erro número equivocado de argumentos!
}
As funções NQC sempre se expandem como funções em linha. Isto significa que
cada chamada a uma função faz com que se inclua no programa outra cópia do código
da função. Se não se usar com sensatez, as funções em linha fazem com que o tamanho
do código seja excessivo.
2.2.3. Sub-rotinas
A diferença das funções em linha é que as sub-rotinas permitem que se
compartilhem uma única cópia do fragmento de código entre diferentes funções
chamadoras. Isto faz com que seja muito mais eficaz no uso do espaço que nas funções
em linha, mas devido a algumas limitações do interpretador de códigos de bytes Lego as
sub-rotinas possuem algumas restrições significativas. Em primeiro lugar, as sub-rotinas
não podem utilizar nenhum argumento. Segundo, uma sub-rotina não pode chamar a
outra sub-rotina. Por último, o número máximo de sub-rotinas se limita a 8 para o RCX,
____________________Guia do programador de NQC________________________
8
4 para cybermaster, 3 para scout e 32 para spybotics. No mais, quando se utiliza o RCX
1.0 ou o cybermaster, se uma sub-rotina é chamada, desde múltiplas tarefas, não podem
ter variáveis locais ou realizar cálculos que necessitem variáveis temporárias. Estas
importantes restrições fazem com que as sub-rotinas sejam menos atrativas que as
funções. Portanto, seu uso deveria limitar-se a situações onde seja absolutamente
necessário economizar no tamanho do código. Segue abaixo a sintaxe de uma sub-
rotina:
Nome_da_sub-rotina()
{
// corpo da sub-rotina
}
2.2.4. Variáveis
Todas as variáveis em NQC são do mesmo tipo inteiros consígnos de 16 bits.
As variáveis se declaram usando a palavra reservada int seguido de uma lista de
nomes de variáveis separadas por vírgulas e terminadas por um ponto e vírgula ( ; ).
Opcionalmente pode-se especificar um valor inicial para cada variável usando o
símbolo ( = ) depois do nome da variável. Seguem abaixo alguns exemplos:
int x; // declara x
int t,z; // declara t e z
int a=1,b; // declara a e b, inicia a com o valor 1
As variáveis globais se declaram no âmbito do programa (fora de qualquer bloco
de código). Uma vez declaradas podem ser utilizadas dentro de qualquer tarefa, função
e sub-rotina. Seu âmbito começa com a declaração e termina ao final do programa.
As variáveis locais podem declarar-se dentro das tarefas, funções e às vezes dentro
das sub-rotinas. Essas variáveis somente são acessíveis dentro do bloco de código em
que são definidas. Concretamente, seu âmbito começa com a declaração, e termina ao
final do bloco de código. No caso das variáveis locais se considera um bloco uma
instrução composta (um grupo de instruções incluídas entre duas chaves { y } ):
int x; // x é global
task main()
{
int y; // y é local da tarefa main
x = y; // ok
{ // começa a instrução composta
int z; // z declaração local
____________________Guia do programador de NQC________________________
9
y = z; // ok
}
y = z; // erro aqui não está definida z
}
task foo ()
{
x = 1; // ok
y = 2; // erro - y não é global
}
Em muitos casos, NQC deve reservar uma ou mais variáveis temporais para o seu
próprio uso. Em alguns casos utiliza-se uma variável temporal para alocar um valor
intermediário durante um cálculo. Em outros casos utiliza-se para guardar um valor a
ser passado à função. Estas variáveis temporais reduzem a reserva de variáveis
disponíveis para o resto do programa. O NQC tentará ser o mais eficiente possível com
as variáveis temporais (inclusive reutilizando-as sempre que seja possível).
O RCX (e outros modelos) proporcionam várias posições de armazenamento e
podem ser usadas para alocar variáveis em um programa NQC. Existem dois tipos de
posições de armazenamento: globais e locais. Quando compilam um programa, NQC
reserva cada variável a um lugar específico de armazenamento. Os programadores
geralmente podem ignorar os detalhes desta reserva seguindo duas regras básicas:
Se uma variável necessitar estar em posição global declara-se como
variável global.
Se uma variável não necessitar ser global, faz com que seja o mais local
possível.
Isto dá ao compilador a máxima flexibilidade ao reservar uma posição de
armazenamento correta.
O número de variáveis locais e globais variam segundo o modelo:
Modelo Global Local
RCX 32 0
Cyber Master 32 0
Scout 10 8
RCX2 32 16
Spybotics 32 4
____________________Guia do programador de NQC________________________
10
2.2.5. Matrizes
Os modelos RCX2 e spybotics suportam matrizes (os outros modelos não têm
suporte apropriado para matrizes em seu firmware). As matrizes declaram-se da mesma
forma que as variáveis normais, mas com o tamanho das matrizes fechadas entre
colchetes. O tamanho deve ser uma constante.
int minha_matriz[3]; // declarar uma matriz de três elementos
Os elementos de uma matriz identificam-se por sua posição dentro da matriz
(chamada índice). O primeiro elemento possui um índice 0, o segundo 1, etc. Por
exemplo:
minha_matriz[0]=123; // estabelece o primeiro elemento em 123
minha_matriz[1]= minha_matriz[2];// cópia o terceiro no segundo
Atualmente existe uma série de limitações no uso de matrizes. É provável que
essas limitações acabem nas futuras versões de NQC:
Uma matriz não pode ser argumento de uma função. Todavia pode-se
passar a uma função um elemento individual da matriz.
Nem as matrizes nem seus elementos podem utilizar-se com os operadores
de aumento (++) ou diminuição (--).
Somente é permitida a utilização normal (=) para os elementos da matriz.
Não se permitem as utilizações matemáticas (+=).
Os valores iniciais dos elementos de uma matriz não se podem especificar.
Necessita de uma reserva explícita dentro do mesmo programa que
estabeleça o valor de um elemento.
2.3. Instruções
O corpo de um bloco de código (tarefa, função ou sub-rotina) compõe-se de
instruções. As instruções terminam com um ponto e vírgula ( ; ).
2.3.1. Declaração de variáveis
A declaração de variáveis, como descrito na sessão anterior, é um tipo de
instrução. Uma variável declara-se como local (com indicação opcional) quando
utilizada dentro de um bloco de código. A sintaxe para uma declaração de variável
é:
____________________Guia do programador de NQC________________________
11
Int variáveis;
Onde variáveis é uma lista de nomes separados por vírgulas com valores iniciais
opcionais.
Nome [=expressão]
As matrizes de variáveis também podem declarar (só para RCX2):
Int matriz [tamanho]
2.3.2. Atribuição
Uma vez declaradas as variáveis pode-se reservar o valor de uma expressão:
Variável operador_de_atribuição expressão
Há novos operadores de reserva. O operador mais básico, = , simplesmente
reserva o valor da expressão para a variável. Os outros operadores modificam de
alguma forma o valor da variável em um dos modos como se mostra na tabela
seguinte:
Operador Ação
= Atribui a uma variável uma expressão
+= Adiciona a uma variável uma expressão
-= Resta a uma variável uma expressão
*= Multiplica uma variável por uma expressão
/= Divide uma variável por uma expressão
&= AND bit a bit da expressão e da variável
|= OR bit a bit da expressão e da variável
||= Atribui a uma variável o valor absoluto de uma expressão
+-= Atribui uma variável o sinal (-1, +1, 0) de uma expressão
>>= Desloca para a direita a variável em uma quantidade constante
____________________Guia do programador de NQC________________________
12
{
x = 1;
y = 2;
}
Ainda pode não parecer muito significativo, exerce um papel crucial ao construir
estruturas de controle mais complicadas. Muitas estruturas de controle requerem uma
instrução simples como corpo. Usando uma instrução composta, a mesma estrutura de
controle pode ser usada para controlar múltiplas instruções.
A instrução if demonstra uma condição. Se a condição é verdadeira, executa uma
instrução (a conseqüência). Uma segunda instrução opcional (a alternativa) é executada
se a condição é falsa. Continuando, mostram-se as sintaxes possíveis para uma instrução
if.
if (condição) conseqüência
if (condição) conseqüência else alternativa
Observe que a condição vai ser colocada entre parênteses. Veja os exemplos a
seguir. No último exemplo utiliza-se uma instrução composta para permitir que se
executem duas instruções como conseqüências da condição.
if (x==1) y = 2;
if (x==1) y = 3; else y = 4;
if (x==1) {y = 1; z = 2;}
A instrução while é usada para construir um laço condicional. Avalia-se a
condição. Se, é verdadeira, executa-se o corpo do laço, a continuação comprova de novo
a condição. O processo continua até que a condição se torne falsa (o que executa a
instrução break). A continuação aparece na sintaxe para o laço while:
while (condição) corpo
É normal utilizar uma instrução composta como corpo do laço.
while (x < 10)
{
x = x+1;
y = y*2;
}
Uma variante do laço while é o laço do-while. Sua sintaxe é :
do corpo while (condição)
____________________Guia do programador de NQC________________________
13
A diferença entre o laço while e o do-while é que o do-while sempre executa ao
menos uma vez, enquanto que o laço while pode não executá-lo nunca.
Outro tipo de laço é o laço for:
for(instr1 ; condição ; instr2 ;) corpo
Um laço for sempre executa instr1 logo, checa repetidamente a condição e,
enquanto é verdadeira, executa o corpo seguido de instr2. O laço for é equivalente a:
instr1;
while (condição)
{
corpo
instr2;
}
A instrução repeat executa um laço de um número determinado de vezes:
repeat (expressão) corpo
A expressão determina quantas vezes se executará o corpo. Observa-se que a
expressão só se avalia uma vez e o corpo se repete esse número de vezes. Isto é
diferente nas estruturas while e do-while que avalia a condição em cada laço.
Uma instrução switch pode utilizar-se para executar um de vários blocos de
código dependendo do valor de uma expressão. Cada bloco de código vem precedido
por uma ou mais etiquetas case. Cada case deve ser uma constante única dentro da
instrução switch. A instrução switch avalia a expressão e a continuação busca uma
etiqueta case que cumpra a condição. Então executará qualquer instrução que diga case
até que se encontre uma instrução break ou até que chegue ao final do switch. Também
pode-se usar uma única etiqueta default que se associará a qualquer valor que não
apareça na etiqueta case. Tecnicamente uma instrução switch tem a seguinte sintaxe:
switch (expressão) corpo
As etiquetas case e default não são instruções em si mesmas, sendo que são
etiquetas que precedem as instruções. Múltiplas etiquetas podem preceder à mesma
instrução. Estas etiquetas têm a seguinte sintaxe:
case expressão_constante:
default :
____________________Guia do programador de NQC________________________
14
Uma típica instrução switch teria este aspecto:
switch (x)
{
case 1 : // faz algo quando x é 1
break;
case 2 :
case 3 : // faz outra coisa quando x é 2 ou 3
break;
default : // faz isto quando x não é 1,2 nem 3
break;
}
A instrução goto força o programa a saltar a uma posição determinada. As
instruções de um programa podem ser marcadas precedendo-as de um identificador e
dos pontos. Uma instrução goto especifica a etiqueta a que o programa há de saltar. Por
exemplo, vejamos como implementar um laço que incrementa o valor de uma variável
utilizando goto:
Meu_ laço:
x++;
goto Meu_ laço;
A instrução goto deve ser usada com moderação e precaução. Na maioria dos
casos as estruturas de controle tales como if , while e switch fazem os programas mais
fáceis de ler e modificar. Têm a precaução de não utilizar nunca uma instrução goto
para saltar a uma instrução monitor ou acquire ou para sair dela. Isto é assim porque
monitor e acquire têm um código especial que normalmente é executado na entrada e
saída, e um goto evitaria este código
provavelmente provocando um comportamento
não desejado.
NQC também define o macro until que supõe uma alternativa prática ao laço
while. A definição real de until é:
#define until (c ) while (!( c ))
Em outras palavras, until continuará fazendo laços até que a condição seja
verdadeira. Com muita freqüência utiliza-se como uma instrução de corpo vazio:
until (SENSOR_1 = 1); // espera que se pressione o sensor
____________________Guia do programador de NQC________________________
15
2.3.4. Controle de acesso e eventos
O Scout, RCX2 e Spybotics suportam a monitoração de eventos e o controle de
acesso. O controle de acesso permite que uma tarefa solicite a posição de um ou mais
recursos. No NQC o controle de acesso proporciona a instrução acquire, que pode
apresentar duas formas:
acquire (recursos) corpo
acquire (recursos) corpo catch handler
onde recursos é uma constante que especifica os recursos que há que obter e corpo e
handler, são instruções. O NQC API define as constantes para os recursos individuais
que se podem somar para solicitar múltiplos recursos por vez. O comportamento da
instrução acquire é o seguinte: solicitará a posição dos recursos especificados. Se outra
tarefa de prioridade superior já possui os recursos, então a solução não será aceita e a
execução saltará a handler (se existir). Caso contrário o pedido será aceito e o corpo
começará a ser executado. Enquanto executa-se o corpo, se uma tarefa de prioridade
igual ou superior solicita alguns dos recursos, a tarefa original perderá sua posição.
Quando se perde a posição, a execução salta para handler (se existir). Uma vez que o
corpo está completo devolvem-se os recursos ao sistema (para que possam adquirir
tarefas de prioridade mais baixa). Se não se especifica um handler, tanto o pedido não é
aceito como pode sê-lo (com sua conseqüência perdida uma vez executado o corpo) o
controle passa a instrução que segue a instrução acquire. Por exemplo, o seguinte
código adquire um recurso 10 segundos, fazendo soar um som não se completa com
êxito:
acquire (ACQUIRE_OUT_A)
{
Wait (1000);
}
catch
{
PlaySound (SOUND_UP);
}
A monitoração de eventos implementa-se com a instrução monitor, que tem uma
sintaxe muito similar a instrução acquire:
monitor (eventos) corpo
monitor (eventos) corpo handler_list
____________________Guia do programador de NQC________________________
16
onde handler_list é um ou mais handlers do tipo:
catch (catch_events) handler
O último handler em uma lista de handlers pode omitir a especificação do
evento:
catch handler
Evento é uma constante que determina que eventos devem ser monitorados. Para
o Scout os eventos estão pré-definidos, de modo que há constantes como
EVENT_1_PRESSED que podem ser utilizadas como especificação de evento. Com
RCX2 o significado de cada evento é configurado pelo programador. Existem 16
eventos (números do 0 ao 15). Para especificar um evento em uma instrução de monitor,
o número de evento deve converter-se em uma máscara de evento, utilizando a macro
EVENT_MASK(). As constantes de evento do Scout, as máscaras de evento podem
somar-se para especificar múltiplos eventos. Podem combinar-se múltiplas máscaras
por meio do OR bit a bit.
A instrução monitor executa o corpo enquanto monitoriza os eventos
especificados. Sucede-se qualquer dos eventos, a execução salta o primeiro handler para
esse evento (um handler sem nenhuma especificação maneja qualquer evento). Se não
existe nenhum handler de evento para esse evento, então o controle continua na
instrução que segue a instrução monitor. O seguinte exemplo espera 10 segundos
enquanto monitora os eventos 2, 3 e 4 para RCX2:
monitor (EVENT_MASK (2)| EVENT_MASK (3)| EVENT_MASK (4))
{
Wait (1000);
}
catch (EVENT_MASK (4))
{
PlaySound (SOUND_DOWN); // sucede o evento 4
}
catch
{
PlaySound (SOUND_UP); // sucede o evento 2 ou 3
}
Observe que as instruções acquire e monitor só são suportadas por modelos que
implementem o controle de acesso e a monitoração de eventos, quer dizer, o Scout e o
RCX2.
____________________Guia do programador de NQC________________________
17
2.3.5. Outras instruções
Uma chamada da função (ou sub-rotina) é uma instrução como a seguinte:
Nome(argumentos);
A lista de argumentos é uma lista de expressões separadas por vírgulas. O
número e o tipo de argumento que se proporciona, deve coincidir com a definição da
mesma função.
As tarefas devem iniciar-se e terminar com as seguintes instruções:
start nome_de_tarefa;
stop nome_de_tarefa;
Dentro dos laços (por exemplo, em um laço while) a instrução break pode ser
utilizada para sair do laço e a instrução continue pode ser utilizada para saltar a parte
superior da seguinte interação do laço. A instrução break também pode ser utilizada
para sair da instrução switch.
break;
continue;
É possível fazer com que uma função finalize antes de chegar ao fimde seu
código usando a instrução return.
return;
Qualquer expressão é também uma instrução legal quando termina em ponto e
vírgula. É pouco freqüente usar esse tipo de instrução já que então se descartaria no
valor da expressão. A única exceção mencionada refere-se às expressões que implicam
nos operadores de acréscimo (++) ou decréscimo (--).
X++;
A instrução vazia (só o ponto e vírgula) é também uma instrução legal.
2.4. Expressões
As primeiras versões de NQC faziam uma distinção entre expressões e
condições. Esta diferença elimina-se a partir da versão 2.3: tudo é uma expressão e
agora operadores condicionais para as expressões. Isto é parecido como utiliza-se em
C/C++, as operações condicionais.
Os valores são do tipo mais primitivo de expressões. Formam-se expressões
mais complicadas a partir de valores, usando vários operadores. A linguagem NQC só
____________________Guia do programador de NQC________________________
18
tem incorporado duas classes de valores: constantes numéricas e variáveis. O RCX API
define outros valores que correspondem a várias características do RCX tais como
sensores e temporizadores (timers).
As constantes numéricas no RCX representam-se como inteiros com signo de 16
bits. Internamente NQC usa matemáticas com signo de 32 bits para a avaliação de
expressões constantes, logo o reduz a 16 bits quando generaliza o código RCX. As
constantes numéricas podem ser escritas como decimais (123) ou hexadecimais
(0xABC). Atualmente, existe muito pouco controle da faixa de valor das constantes, de
modo que usar um valor maior do que esperado pode ter efeitos não usuais.
Se predefinem dos valores especiais: true e false. O valor de false é zero,
enquanto que só se garante que o valor de true não é zero. São válidos os mesmos
valores para operadores relacionais (
____________________Guia do programador de NQC________________________
19
Operador Descrição Associação Restrição Exemplo
abs () sing ()
Valor absoluto Sinal de operando
n/a abs (x) sing (x)
++ , -- Incremento, Diminuição Esquerda Só variáveis x++ ou ++x
- ~ !
unário menor negação bitwise (unário) negação lógica
Direita Direita Direita
Só constantes
-x ~123 !x
* / %
Multiplicação Divisão Modulo
Esquerda Esquerda Esquerda
x * y
+ -
Soma Subtração
Esquerda Esquerda
x + y x - y
>> 4
< , > =
Operadores Relacionais Esquerda x < y x > y
== !=
Igual a Diferente de
Esquerda x == 1 x != 1
& AND bit a bit Esquerda x & y
^ XOR bit a bit Esquerda x ^ y
| OR bit a bit Esquerda x | y
&& AND lógico Esquerda x && y
|| OR lógico Esquerda x || y
?: Valor condicional n/a x ==1 ?Y : z
Pode se usar parêntesis onde seja necessário, para mudar a ordem da avaliação.
x = 2+3; 4 // atribuir a x o valor 14
y = (2+3)*4 // atribuir a y o valor 20
2.4.1. Condicionais
As condições formam-se, geralmente, comparando duas expressões. Existem
também duas expressões constantes
true e false
que sempre dão como valor de
avaliação verdadeiro ou falso, respectivamente. Pode-se negar uma condição com o
operador de negação, ou combinar duas condições com os operadores AND ou OR. A
tabela seguinte resume os diferentes tipos de condicionais:
____________________Guia do programador de NQC________________________
20
Condição Significado
True Sempre verdadeiro
False Sempre falso
Expr Verdade se a expressão não é igual a 0
Expr1 == Expre2 Verdade se expr1 for igual a expr2
Expr1 != Expre2 Verdade se expr1 for diferente a expr2
Expr1 < Expre2 Verdade se expr1 for menor a expr2
Expr1 Expre2 Verdade se expr1 for maior a expr2
Expr1 >= Expre2 Verdade se expr1 for maior ou igual a expr2
! Condição Negação lógica de uma condição Verdadeiro se a condição for falsa
Cond1 && Cond2
AND lógico de duas condições - Verdadeiro se e somente se ambas as condições forem verdadeiras
Cond1 || Cond2 OR lógico de duas condições - Verdadeiro se e somente se uma condição for verdadeira
2.5. O pré-processador
O pré-processador implementa as seguintes diretrizes: #include, #define,
#ifdef, #ifndef, #if, #elif, #else, #endif, #undef. Sua implementação
está muito próxima a um pré-processador C standar, de modo que a maior parte das
coisas que funcionam em um pré-processador C genérico, deveriam ter o efeito
esperado em NQC. Abaixo aparece uma lista de desvios significativos.
2.5.1. #include
O comando #include funciona como era de se esperar, com a ressalva de que o
nome do arquivo deve ir colocado entre aspas. Não existe noção no sistema de uma rota
de inclusão, de modo que, fechar um arquivo entre parêntesis angular, está proibido.
#include foo.nqh // ok
#include // erro!
2.5.2. #define
O comando #define usa-se para uma substituição de macro simples. A
redefinição de macro é um erro (ao invés que em C onde é um aviso). Os macros
terminam normalmente pelo final da linha, porém pode escrever a nova linha com ( \ )
para permitir macros multilinhas.
#define foo (x) do { bar (x);\
baz (x); } while (false)
A diretiva #undef pode-se usar para retirar uma definição de macro.
____________________Guia do programador de NQC________________________
21
2.5.3. Compilação condicional
A compilação condicional funciona de forma parecida ao pré-processador C.
Podem-se usar as seguintes diretivas de pré-processador.
#if condição
#ifdef symbol
#ifndef symbol
#else
#elif condição
#endif
As condições nas diretivas #if usam os mesmos operadores e prioridades que em
C. Suporta-se no operador defined( ).
2.5.4. Iniciação do programa
Ao início do programa o pré-processador insere uma chamada a uma função de
inicialização especial, _init. Esta função, de fato, é parte do RCX API e põe as três
saídas a plena potência em direção para frente (todavia desconectadas). A função de
iniciação pode desativar-se usando a diretiva #pragma noinit:
#pragma noinit //não faz nenhuma iniciação do programa
A função de iniciação, de fato, pode-se substituir por uma função diferente
usando a diretiva #pragma init:
#pragma init função //usar iniciação de usuário
2.5.5. Armazenamento de reserva
O compilador NQC atribui, automaticamente, variáveis a posições de
armazenamento. No entanto, às vezes é necessário impedir que o compilador use certas
posições de armazenamento. Isto pode-se fazer por meio da diretiva:
#pragma reserve:
#pragma reserve início
#pragma reserve início fim
Esta diretiva faz com que o compilador ignore uma ou mais posições de
armazenamento, durante a atribuição de variáveis. Início e fim devem ser números que
se refiram as posições de armazenamento válidas. Só se proporciona um início, então se
reserva uma única posição. Se especificam ambos, início e fim então, se reserva a escala
de posições de principio a fim (inclusive). O uso mais comum desta diretiva é para
reservar as posições 0, 1 e/ou 2 ao usar contadores para RCX2. Isto é porque os
____________________Guia do programador de NQC________________________
22
contadores de RCX2 se sobrepõem com as posições de armazenamento 0, 1 e 2. Por
exemplo, se fossem utilizar os três contadores:
#pragma reserve 0 1 2
3. NQC API
O NQC API define um grupo de constantes, funções, valores e macros que
proporcionam acesso a várias capacidades do modelo como sensores, saídas,
temporizadores e comunicações. Algumas características só se encontram em certos
modelos. Sempre que seja necessário, o título da seção indica a que o modelo se aplica.
O RCX2 reúne todas as características do RCX, de modo que se faz referência ao RCX,
então essa característica funciona com o firmware original e com o firmware 2.0. Se faz
referência ao RCX2 a característica que só se aplica ao firmware 2.0. CyberMaster,
Scout e Spybotics se indicam como CM, Scout e Spy, respectivamente.
O API consiste em funções, valores e constantes. Uma função é algo que pode
ser também denominada instrução. Tipicamente, empreende alguma ação ou configura
algum argumento. Os valores representam algum argumento ou quantidade, e podem ser
usados em expressões. As constantes são nomes simbólicos para valores que têm
significado especial para o modelo. A princípio, usa-se um grupo de constantes junto
com uma função. Por exemplo, a função PlaySound utiliza um simples argumento que
determina que som tocará. As constantes, tais como SOUND_UP, definem-se para cada
som.
3.1. Sensores
Existem três sensores, que se enumeram internamente 0, 1 e 2. Isto poderia dar
confusão já que no RCX está etiquetado externamente como 1, 2 e 3. Para minimizar
esta confusão, foi definido os nomes dos sensores SENSOR_1, SENSOR_2 e
SENSOR_3. Esses nomes de sensores podem ser usados em qualquer função, que
requeira um sensor como argumento. No mais, podem-se usar os nomes sempre que um
programa deseje ler o valor atual de um sensor:
x = SENSOR_1; // lê o sensor y armazena o valor em x
3.1.1. Tipos e modos RCX, CyberMaster
As portas de sensores no RCX têm capacidade de suportar uma grande variedade
de sensores (outros modelos não suportam tipos de sensor configuráveis). É função do
programa dizer ao RCX que classe de sensor está conectada em cada porta. Se pode
____________________Guia do programador de NQC________________________
23
configurar o tipo do sensor por meio de SetSensorType. Existem quatro tipos de
sensores e cada qual corresponde a um sensor específico de LEGO. Pode-se usar um
quinto tipo (SENSOR_TYPE_NONE) para ler os valores puros dos sensores genéricos
passivos. Em geral, um programa deveria configurar o tipo para que encaixe com o
sensor real. Se uma porta de sensor se configurar com o tipo incorreto, o RCX pode não
ser capaz de ler corretamente.
Tipo de Sensor Significado
SENSOR_TYPE_NONE Sensor passivo - Genérico
SENSOR_TYPE_TOUCH Sensor de toque
SENSOR_TYPE_TEMPERATURE Sensor de temperatura
SENSOR_TYPE_LIGHT Sensor de luz
SENSOR_TYPE_ROTATION Sensor de rotação
O RCX, CyberMaster e Spybotics permitem que se configure um sensor em
modos diferentes. O modo de sensor determina como se processa o valor puro de um
sensor. Alguns modos só têm sentido para certos tipos de sensores, por exemplo
SENSOR_MODE_ROTATION só é útil com sensores de rotação. O modo de sensor
pode estabelecer por meio de SetSensorMode. A continuação mostra os possíveis
modos. Adverte-se que, já que CyberMaster não suporta sensores de rotação ou de
temperatura, os últimos três modos se restringem somente ao RCX. Spybotics é todavia
mais restrito e, somente permite os modos raw, booleano e porcentual.
Modo do Sensor Significado
SENSOR_MODE_RAW Valor puro de 0 a 1023
SENSOR_MODE_BOOL Valor booleano (0 ou 1)
SENSOR_MODE_EDGE Conta números de transições booleanas
SENSOR_MODE_PULSE Conta números de períodos booleanos
SENSOR_MODE_PERCENT Valor de 0 a 100
SENSOR_MODE_FAHRENHEIT Graus F - Somente RCX
SENSOR_MODE_CELSIUS Graus C - Somente RCX
SENSOR_MODE_ROTATION Rotação (16 ticks por revolução) - Somente RCX
Ao usar o RCX é normal pôr o tipo e o modo ao mesmo tempo. A função
SetSensor faz este processo um pouco mais fácil ao proporcionar uma única função
que chama e estabelece um conjunto de combinações tipo/modo padrão.
____________________Guia do programador de NQC________________________
24
Configuração do Sensor Tipo Modo
SENSOR_TOUCH SENSOR_TYPE_TOUCH SENSOR_MODE_BOOL
SENSOR_LIGHT SENSOR_TYPE_LIGHT SENSOR_MODE_PERCENT
SENSOR_ROTATION SENSOR_TYPE_ROTATION SENSOR_MODE_ROTATION
SENSOR_CELSIUS SENSOR_TYPE_TEMPERATURE SENSOR_MODE_CELSIUS
SENSOR_FAHRENHEIT SENSOR_TYPE_TEMPERATURE SENSOR_MODE_FAHRENHEIT
SENSOR_PULSE SENSOR_TYPE_TOUCH SENSOR_MODE_PULSE
SENSOR_EDGE SENSOR_TYPE_TOUCH SENSOR_MODE_EDGE
O RCX proporciona uma conversão booleana para todos os sensores
não só
para os sensores de contato. Esta conversão booleana baseia-se, normalmente, em
entradas préestablecidos para o valor puro. Um valor baixo (menor de 460) é um
valor booleano de 1. Um valor alto (maior de 562) é um valor booleano de 0. Esta
conversão pode modificar: ao chamar SetSensorMode pode adicionar um valor de
entrada entre 0 e 31. Se o valor do sensor mudar mais que o valor de entrada durante
certo tempo (3 milisegundos), então troca o estado booleano do sensor. Isto permite que
o estado booleano reflita mudanças rápidas no valor puro. Um aumento rápido ocasiona
um valor booleano de 0, uma descida rápida em um valor booleano de 1. Inclusive
quando um sensor se configura para outro modo (por exemplo
SENSOR_MODE_PERCENT), se leva a cabo a conversão booleana.
SetSensor (sensor, configuração) Função RCX
Estabelece o tipo e modo de um sensor dado em uma configuração específica,
que deve ser uma constante especial contendo o tipo e o modo da informação.
SetSensor (SENSOR_1, SENSOR_TOUCH);
SetSensorType (sensor, tipo) Função RCX
Estabelece um tipo de sensor, que deve ser uma das constantes de tipo de sensor
pré-definidos.
SetSensorType(SENSOR_1, SENSOR_TYPE_TOUCH);
SetSensorMode (sensor, modo) Função - RCX, CM, Spy
Estabelece um modo de sensor, que deve ser uma das constantes de modo de
sensor pré-definidos. Pode-se adicionar, se desejar, (somente ao modo RCX ) um
argumento de entrada para converção booleana.
SetSensorMode(SENSOR_1, SENSOR_MODE_RAW); // modo puro
SetSensorMode(SENSOR_1, SENSOR_MODE_RAW+10); // entrada 10
____________________Guia do programador de NQC________________________
25
ClearSensor(sensor) Função Todas
Apaga o valor de um sensor
só afeta aos sensores que se configuram para
medir uma quantidade acumulativa, tal como a rotação uma recontagem de pulso.
ClearSensor(SENSOR_1);
3.1.2. Informação do sensor
Existe um número de valores que se pode inspecionar para cada sensor. Para
todos esses valores deve-se especificar o sensor por seu número de sensor (0, 1 ou 2), e
não com a constante correspondente (ex. SENSOR_1).
SensorValue(n) Valor Todos
Devolve a leitura processada do sensor para o sensor n, onde n é 0, 1 ou 2. Este é
o mesmo valor que devolve os nomes de sensor (ex. SENSOR_1).
x = SensorValue(0); // lê o sensor 1
SensorType(n) Valor RCX, CM, Scout
Devolve o tipo configurado do sensor n, que deve ser 0, 1 ou 2. Somente tem
tipos configuráveis de sensor RCX, outros suportes devolvem o tipo pré-configurado de
sensor.
x = SensorType(0);
SensorMode(n) Valor RCX, CyberMaster, Spy
Devolve o modo de sensor em uso para o sensor n, que deve ser 0, 1 ou 2.
x = SensorMode(0);
SensorValueBool(n) Valor RCX
Devolve o valor booleano do sensor n, que deve ser 0, 1 ou 2. A conversão
booleano se faz baseando-se, ou bem em limites preestabelecidos, ou em um argumento
slope especificado por meio de SetSensorMode.
x = SensorValueBool(0);
SensorValueRaw(n) Valor RCX, Scout, Spy
Devolve o valor puro do sensor n, que deve ser 0, 1 ou 2. Os valores puros
variam entre 0 e 1023.
x = SensorValueRaw(0);
____________________Guia do programador de NQC________________________
26
3.1.3. Sensor de luz do Scout Scout
No Scout, SENSOR_3 refere-se ao sensor de luz que vem incorporado. A leitura
do valor do sensor de luz (com SENSOR_3) devolve um dos três níveis: 0 (escuro), 1
(normal) o 2 (brilhante). Pode-se ler o valor puro do sensor com
SensorValueRaw(SENSOR_3), mas tem que levar em conta que uma luz mais brilhante,
ocasiona um valor puro mais baixo. A conversão do valor puro do sensor (entre 0 e
1023) a um dos três níveis depende de três argumentos: limite superior, limite inferior e
delay. O limite inferior é o valor puro menor (mais brilhante) que ainda se considera
normal. Os valores abaixo do limite mais baixo se consideram brilhantes. O limite
superior é o maior valor puro (mais escuro) que se considera normal. Os valores perto
deste limite se consideram escuros.
Pode-se usar o delay para impedir que mude o nível, quando o valor puro chegue
perto de um dos limites. Isto se consegue, fazendo com que seja um pouco mais difícil
abandonar os estados escuros e brilhantes que entram neles. Especificamente, o limite
para mover-se de normal a brilhante é um pouco mais baixo que o limite para voltar de
brilhante a normal. A diferença entre estes dois limites é a margem do delay. O mesmo
acontece para a transição entre normal e escuro.
SetSensorLowerLimit (valor) Função Scout
Estabelece o valor inferior da luz do sensor. O valor pode ser uma expressão.
SetSensorLowerLimit (100);
SetSensorUpperLimit (valor) Função Scout
Estabelece o valor superior da luz do sensor. O valor pode ser uma expressão.
SetSensorUpperLimit (900);
SetSensorHysteresis (valor) Função Scout
Estabelece o delay do sensor de luz. O valor pode ser uma expressão.
SetSensorHysteresis (20);
CalibrateSensor ( ) Função - Scout
Lê o valor do sensor de luz, depois estabelece os limites superior e inferior em
12,5% por cima o por baixo da leitura atual, e estabelece um delay de 3.12% do valor da
leitura.
CalibrateSensor();
____________________Guia do programador de NQC________________________
27
3.1.4. Sensores do Spybotics Spy
Spybotics utiliza sensores embutidos, em lugar de sensores conectados
externamente. O sensor de contato que se encontra na parte frontal do tijolo Spybotics é
o SENSOR_1. Está normalmente configurado no modo percentual, seu valor é 0 quando
não está pressionado e 100 quando está. SENSOR_2 é o sensor de luz (o conector na
parte traseira do tijolo que se usa para se comunicar com o computador). Está
normalmente configurado no modo percentual, valores altos indicam luz brilhante.
3.2. Saídas
3.2.1. Funções básicas
Todas as funções que utilizam saídas, estabelecem, como primeiro argumento
um conjunto de saídas. Este valor tem que ser uma constante. Os nomes OUT_A,
OUT_B, e OUT_C usam-se para identificar as três saídas. Várias saídas podem ser
combinadas encadeando saídas individuais. Por exemplo, usa-se OUT_A+OUT_B para
especificar as saídas A e B, em uma só instrução. O valor das saídas tem que ser sempre
uma constante (não pode ser uma variável).
Cada saída tem três atributos: modo, direção e potência. Modo, pode ser
configurado por meio de SetOutput(saída, modo). O argumento modo deve ser uma das
seguintes constantes:
Modo Significado
OUT_OFF A saída está desligada (O motor não pode girar)
OUT_ON A saída está ligada (O motor pode girar)
OUT_FLOAT O motor seguirá girando até parar por si só
Os outros dois atributos, direção e potência, podem ser configurados em
qualquer momento, mas só têm efeito se a saída está ligada. A direção é configurada
mediante o comando SetDirection(saída,direção). O argumento direção deve ser uma
das seguintes constantes:
Direção Significado
OUT_FWD O motor gira para frente
OUT_REV O motor gira para trás
OUT_TOGGLE O motor inverte o sentido de giro
A potência pode ser configurada entre 0 (mínima) e 7 (máxima). Os valores
OUT_LOW, OUT_HALF e OUT_FULL estão definidos para serem utilizados na
configuração do argumento potência. A potência pode ser estabelecida mediante a
____________________Guia do programador de NQC________________________
28
função SetPower(saída,potencia). Por padrão, os três motores estão configurados a
máxima potência e giro para frente quando o programa inicia. Contudo, o RCX neste
momento está parado.
SetOutput(saídas, modo) Função Todos
Estabelece a saída no modo especificado. Saída é um ou mais dos valores
OUT_A, OUT_B, e OUT_C. O modo tem que ser OUT_ON, OUT_OFF, ou OUT_FLOAT.
SetOutput(OUT_A + OUT_B, OUT_ON); // Estabelece A e B ligado
SetDirection(saídas, direção) Função - Todos
Estabelece a saída na direção especificada. Saída é um ou mais dos valores
OUT_A, OUT_B, e OUT_C. A direção tem que ser OUT_FWD, OUT_REV, ou
OUT_TOGGLE.
SetDirection(OUT_A, OUT_REV); // Faz girar A para trás
SetPower(saídas , potência) Função - Todos
Estabelece a potência do motor especificado. A potência pode ser uma
expressão, cujo resultado deve ser um valor entre 0 e 7. As constantes OUT_LOW,
OUT_HALF, ou OUT_FULL também podem ser usadas.
SetPower(OUT_A, OUT_FULL); // A a máxima potência
SetPower(OUT_B, x);
OutputStatus(n) Valor - Todos
Devolve o estado do motor n. Tendo em conta que n deve ser 0, 1 ou 2
não
OUT_A, OUT_B, ou OUT_C.
x = OutputStatus(0); // Estado de OUT_A
3.2.2. Outras funções
Dado que o controle das saídas é uma característica de uso freqüênte dentro do
programa, se dispõe de outras funções que fazem com que se trabalhar com saídas seja
mais fácil. Deve levar-se em conta que estes comandos não adicionam nenhuma nova
funcionalidade aos comandos SetOutput e SetDirection. Só são interessantes para fazer
o programa mais conciso.
____________________Guia do programador de NQC________________________
29
On(saídas) Função - Todos
Estabelece as saídas especificadas como ligadas. Saída é um ou mais dos valores
OUT_A, OUT_B, e OUT_C.
On(OUT_A + OUT_C); // Liga as saídas A e C
Off(saídas) Função - Todos
Estabelece as saídas especificadas como apagadas. Saída é um ou mais dos
valores OUT_A, OUT_B, e OUT_C.
Off(OUT_A); // Apaga a saída A
Float(saídas) Função - Todos
Estabelece as saídas especificadas como float. Saída é um ou mais dos valores
OUT_A, OUT_B, e OUT_C.
Float(OUT_A); // Detém a saída A sem freá-la
Fwd(saídas) Função Todos
Estabelece o sentido de giro das saídas especificadas como para frente. Saída é
um ou mais dos valores OUT_A, OUT_B, e OUT_C.
Fwd(OUT_A);
Rev(saídas) Função - Todos
Estabelece o sentido de giro das saídas especificadas como retrocesso. Saída é
um ou mais dos valores OUT_A, OUT_B, e OUT_C.
Rev(OUT_A);
Toggle(saídas) Função - Todos
Inverte o sentido de giro das saídas especificadas. Saída é um ou mais dos
valores OUT_A, OUT_B, e OUT_C.
Toggle(OUT_A);
OnFwd(saídas) Função - Todos
Estabelece o sentido de giro das saídas especificadas como para frente e as põe
em marcha. Saída é um ou mais dos valores OUT_A, OUT_B, e OUT_C.
OnFwd(OUT_A);
____________________Guia do programador de NQC________________________
30
OnRev(saídas) Função - Todos
Estabelece o sentido de giro das saídas especificadas como retrocesso e as põe
em marcha. Saída é um ou mais dos valores OUT_A, OUT_B, e OUT_C.
OnRev(OUT_A);
OnFor(saídas, tempo) Função - Todos
Põe em marcha as saídas especificadas por um determinado tempo e a
continuação as detém. Saída é um ou mais dos valores OUT_A, OUT_B, e OUT_C.
Tempo se mede em incrementos de 10ms (one second = 100) e pode ser uma
expressão.
OnFor(OUT_A, x);
3.2.3. Controle Global RCX2, Scout
SetGlobalOutput(saídas, modo) Função - RCX2, Scout, Spy
Desativa ou volta a ativar as saídas dependendo do argumento modo. Se modo é
OUT_OFF, então as saídas se apagaram e se desativaram. Enquanto estão desativadas
qualquer chamada SetOutput() (incluindo funções tais como On()) será ignorada. Se, se
utiliza o modo OUT_FLOAT, às saídas estarão estabelecidas no modo float antes de
desativá-las. As saídas podem voltar a ser ativadas chamando SetGlobalOutput() e
modo OUT_ON. Deve levar-se em conta que ativar uma saída não a liga
imediatamente, só permite posteriores chamadas a SetOutput().
SetGlobalOutput(OUT_A, OUT_OFF); //desativa a saída A
SetGlobalOutput(OUT_A, OUT_ON); //ativa a saída A
SetGlobalDirection(saídas, direção) Função - RCX2, Scout, Spy
Inverte ou reestabelece a direção das saídas. O argumento direção deve ser
OUT_FWD, OUT_REV ou OUT_TOGGLE. Se SetGlobalDirection é OUT_FWD o
comportamento da saída é o normal. Se SetGlobalDirection é OUT_REV o
valor de saída de direção será o oposto do que se atribui pelas funções básicas. Se
SetGlobalDirection é OUT_TOGGLE este mudará entre o comportamento
normal e o comportamento oposto.
SetGlobalDirection(OUT_A, OUT_REV); //direção oposta
SetGlobalDirection(OUT_A, OUT_FWD); //direção normal
____________________Guia do programador de NQC________________________
31
SetMaxPower(saídas, potência) Função - RCX2, Scout, Spy
Estabelece o valor máximo de potência permitida para as saídas. Potência pode
ser uma variável, mas deve ter um valor entre OUT_LOW e OUT_FULL.
SetMaxPower(OUT_A, OUT_HALF);
GlobalOutputStatus(n) Função RCX2, Scout, Spy
Devolve a configuração global da saída do motor n. Deve levar-se em conta que
n tem que ser 0, 1 ou 2 não OUT_A, OUT_B ou OUT_C.
X = GlobalOutputStatus(0); //Estado global de OUT_A
3.2.4. Saídas de Spybotics
Spybotics tem dois motores internos. OUT_A refere-se ao motor direito e
OUT_B ao esquerdo. OUT_C enviará ordens VLL por meio do LED traseiro (o que se
utiliza para as comunicações com o ordenador). Isto permite a um dispositivo VLL,
como o Micro_Scout, ser utilizado como terceiro motor do Spybotics. O mesmo LED
pode ser controlado utilizando as funções SendVLL() e SetLight().
3.3. Som
PlaySound(som) Função - Todos
Executa um dos 6 sons pré-determinados do RCX. O argumento som tem que
ser uma constante (exceto em Spybotics, que permite utilizar uma variável).
As seguintes constantes estão pré-definidas para serem usadas com a função
PlaySound(): SOUND_CLICK, SOUND_DOUBLE_BEEP, SOUND_DOWN, SOUND_UP,
SOUND_LOW_BEEP, SOUND_FAST_UP.
PlaySound(SOUND_CLICK);
PlayTone(freqüência, duração) Função - Todos
Executa um só tom da freqüência e duração específica. O valor de freqüência é
em hertz e pode ser uma variável para RCX2, Scout e Spybotics, mas tem que ser uma
constante para RCX e CyberMaster. O valor duração é em centésimos de segundo e tem
que ser constante.
PlayTone(440,50); //Executa um La de meio segundo
____________________Guia do programador de NQC________________________
32
MuteSound() Função - RCX2, Scout, Spy
Faz com que se deixe de executar todos os sons e tons.
MuteSound();
UnmuteSound() Função - RCX2, Scout, Spy
Devolve o comportamento normal de sons e tons.
UnmuteSound();
ClearSound() Função - RCX2, Spy
Elimina todos os sons pendentes de serem executados no buffer.
ClearSound();
SelectSounds(grupo) Função - Scout
Seleciona que grupo de sons do sistema devem ser usados. O grupo deve ser
uma constante.
SelectSound();
3.4. Display LCD RCX
O RCX tem 7 modos diferentes de display como se mostra abaixo. O pré-
determinado do RCX é DYSPLAY_WATCH.
Modo Conteúdo do LCD
DISPLAY_WATCH Mostra o relógio do sistema
DISPLAY_SENSOR_1 Mostra o valor do sensor 1
DISPLAY_SENSOR_2 Mostra o valor do sensor 2
DISPLAY_SENSOR_3 Mostra o valor do sensor 3
DISPLAY_OUT_A Mostra a configuração da saída A
DISPLAY_OUT_B Mostra a configuração da saída B
DISPLAY_OUT_C Mostra a configuração da saída C
O RCX2 atribui um oitavo modo: DISPLAY_USER. Este modo lê,
continuamente, um valor fonte e o mostra no visor. Pode mostrar um ponto decimal em
qualquer posição entre os valores. Isto permite emular o trabalho, com frações, ainda
que todos os valores estejam armazenados como inteiros. Por exemplo, a seguinte
função irá mostrar o valor 1234, mostrando duas cifras depois do ponto decimal,
fazendo com que apareça 12.34 no LCD.
SetUserDisplay(1234,2);
O seguinte programa ilustra a atualização do display:
____________________Guia do programador de NQC________________________
33
task main()
{
ClearTimer(0);
SetUserDisplay(Timer(0),0);
Until(false);
}
Dado que o modo SetUserDysplay atualiza constantemente o LCD, existem
algumas restrições no código fonte. Se, se usa uma variável, esta deve ser atribuída a
uma variável global. A melhor maneira para assegurar que é assim, é declará-la como
variável global. Também podem produzir-se outros efeitos estranhos. Por exemplo, se
está mostrando uma variável e se executa um cálculo em que o resultado é a variável, é
possível que o display mostre alguns resultados intermediários:
int x;
task main()
{
SetUserDisplay(x,0);
while(true)
{
// O display pode mostrar durante um instante 1
x = 1 + Timer(0);
}
}
SelectDisplay(modo) Função - RCX
Seleciona um modo de display.
SelectDisplay(DISPLAY_SENSOR_1); // mostra o sensor 1
SetUserDisplay(valor,precisão) Função - RCX2
Estabelece que o display LCD mostre continuamente um valor especificado.
Precisão específica o número de dígitos à direita do ponto decimal. Uma
precisão de 0 não mostra ponto decimal.
SetUserDisplay(Timer(0),0); // mostra o temporizador 0
3.5. Comunicações
3.5.1. Mensagens RCX, Scout
O RCX e o Scout podem enviar e receber mensagens, simples, utilizando os
infravermelhos. Uma mensagem pode ter um valor desde 0 até 255, mas não se
____________________Guia do programador de NQC________________________
34
recomenda utilizar a mensagem 0. A última mensagem recebida é guardada e, pode-se
acessá-la mediante Message(). Se não foi recebida nenhuma mensagem, Message()
devolverá o valor 0. Deve-se levar em conta, que devido a natureza da comunicação
mediante infravermelhos, não poderão receber mensagens enquanto uma mensagem
estiver sendo transmitida.
ClearMessage(valor, precisão) Função - RCX, Scout
Apaga o buffer de mensagens. Isto facilita a detecção de uma mensagem
recebida, já que então o programa pode esperar que a Message() não seja zero:
ClearMessage(); // Apaga as mensagens recebidas
until(Message() > 0); //Espera a mensagem seguinte
SendMessage(mensagem) Função - RCX, Scout
Envia uma mensagem por infravermelhos. Mensagem pode ser uma expressão,
mas o RCX só pode enviar mensagens com um valor entre 0 e 255, portanto só os 8 bits
menores do argumento serão usados.
SendMessage(3); // envia mensagem 3
SendMessage(259); // outra maneira de enviar a mensagem 3
SetTxPower(potência) Função RCX, Scout
Estabelece a potência para a transmissão por infravermelhos. Potência tem que
ser uma destas constantes: TX_POWER_LO ou TX_POWER_HI
3.5.2. Série RCX2, Scout
O RCX2 pode transmitir dados série, pela porta de infravermelhos. Antes de
enviar dados, a configuração da comunicação e dos pacotes têm que ser especificada.
Então, para cada transmissão, os dados devem ser colocados no buffer de transmissão e
então, usar a função SendSerial() para enviá-los. A configuração da comunicação é
establecida mediante SetSerialComm()e, determina como são enviados os bits mediante
a porta de infravermelho. Os valores possíveis se mostram abaixo:
Opção Efeito
SERIAL_COMM_DEFAULT Configuração prédeterminada
SERIAL_COMM_4800 4800 Baud
SERIAL_COMM_DUTY25 25% Duty cycle
SERIAL_COMM_76KHZ 76 khz carrier
____________________Guia do programador de NQC________________________
35
Por definição, está configurado enviar dados a 2400 baud usando um duty cycle
de 50% em um carrier de 38 kHz. Para especificar opções múltiplas (como a 4800 baud
com um duty cycle de 25%), combinam-se as opções individuais utilizando OR bit a bit
(SERIAL_COMM_4800 | SERIAL_COMM_DUTY25). A configuração dos pacotes
estabelecem-se com SetSerialPacket e controla a maneira como se monta os bytes em
pacotes. Os valores possíveis se mostram abaixo:
Opção Efeito
SERIAL_PACKET_DEFAULT Sem formato de pacotes , somente os bits de dados
SERIAL_PACKET_PREAMBLE Envia um preâmbulo do pacote
SERIAL_PACKET_NEGATED Envia cada byte com seu complemento
SERIAL_PACKET_CHECKSUM Inclui um checksum para cada pacote
SERIAL_PACKET_RCX Formato padrão do RCX (preâmbulo dados negados e checksum)
Deve-se levar em conta que os pacotes negados sempre incluem um checksum,
por tanto a opção SERIAL_PACKET_CHECKSUM só tem significado quando
SERIAL_PACKET_NEGATED não tiver sido especificado. Igualmente, o preâmbulo
negados e checksum estão implícitos no SERIAL_PACKET_RCX. O buffer de
transmissão pode guardar até 16 bytes de dados. Por exemplo, o seguinte código envia
dois bytes (0x12 y 0x34) à porta série:
SetSerialComm(SERIAL_COMM_DEFAULT);
SetSerialPacket(SERIAL_PACKET_DEFAULT);
SetSerialData(0,0x12);
SetSerialData(1,0x34);
SendSerial(0,2);
SetSerialComm(configuração) Função - RCX2
Estabelece a configuração da comunicação que determinando que modos são
enviados os bits pelos infravermelhos.
SetSerialComm(SERIAL_COMM_DEFAULT);
SetSerialPacket(configuração) Funcão - RCX2
Estabelece a configuração dos pacotes que determinando de que modos os bytes
são montados em pacotes.
SetSerialPacket(SERIAL_PACKET_DEFAULT);
SetSerialData(n,valor) Função - RCX2
____________________Guia do programador de NQC________________________
36
Coloca um byte de dados no buffer de transmissão. n é o índice do byte a
establecer (0-15), e o valor pode ser uma expressão
SetSerialData(3,x); // estabelece o byte 3 em x
SerialData(n) Funcão - RCX2
Devolve o valor do byte do buffer de transmissão (não os dados recebidos). N
tem que ser uma constante entre 0 e 15.
X = SerialData(7);// lê o byte #7
SendSerial(começo, contador) Função - RCX2
Utiliza conteúdo do buffer de transmissão para construir um pacote e enviá-lo
por infravermelhos (de acordo com a configuração atual de pacotes e comunicação).
Começo e contador são constantes que especificam o primeiro byte e o número de bytes
dentro do buffer que se devem enviar
SendSerial(0,2);// envia os dois primeiros bytes do buffer
3.5.3. VLL (Link de luz visível) Scout
SendVLL(valor) Função Scout, Spy
Envia um comando VLL que pode ser usado para comunicar-se com o
MicroScout ou o CodePilot. Os comandos específicos VLL estão descritos no SDK do
Scout.
SendVLL(4); // Envia o comando VLL #4
3.6. Temporizadores
Os diferentes modelos oferecem temporizadores, independentes, com uma
resolução de 100 ms (10 ticks por segundo). O Scout dispõe de 3 temporizadores,
enquanto o RCX, o Cybermaster e o Spybotics de 4. Os temporizadores vão desde o tic
0 até o tic 32767 (ao redor de 55 minutos). O valor do temporizador pode ser lido
usando Timer(n), onde n é uma constante que determina que temporizador usar (0-2
para o Scout, 0-3 para o resto). O RCX2 e o Spybotics possuem a característica de ler o
mesmo temporizador com maior resolução usando FastTimer(n), que devolve o valor
do temporizador com uma resolução de 10 ms (100 ticks por segundo).
____________________Guia do programador de NQC________________________
37
ClearTimer(n) Função - Todos
Põe a zero o temporizador especificado.
ClearTimer(0);
Timer(n) Função - Todos
Devolve o valor atual do temporizador especificado (com uma resolução de 100
ms).
x = Timer(0);
SetTimer(n,valor) Função RCX2, Spy
Configura o temporizador com um valor especificado (que pode ser uma
expressão).
SetTimer(0,x);
FastTimer(n) Função - RCX2, Spy
Devolve o valor atual do temporizador especificado com uma resolução de 10
ms.
x = FastTimer(0);
3.7. Contadores RCX2, Scout, Spy
Os contadores são como variáveis simples que podem ser incrementadas,
decrescidas, e apagadas. O Scout dispõe de dois contadores (0 e 1), enquanto que o
RCX2 e Spybotics dispõem de três (0, 1, 2). No caso do RCX2, estes contadores se
sobrepõem com direções de armazenagem global 0-2, portanto, vão ser usadas como
contadores haverá de ser reservadas com #pragma para evitar que NQC as utilize como
uma variável comum. Por exemplo, se se deseja utilizar o contador 1:
#pragma reserve 1
ClearCounter(n) Função - RCX2, Scout, Spy
Põe a zero o contador n. n tem que ser 0 ou 1 para o Scout, 0-2 para o RCX2 e
Spybotics.
Clear Counter(1);
IncCounter(n) Função - RCX2, Scout, Spy
Incrementa o contador n em 1. n tem que ser 0 ou 1 para o Scout, 0-2 para o
RCX2 e Spybotics.
____________________Guia do programador de NQC________________________
38
IncCounter(1);
DecCounter(n) Função - RCX2, Scout, Spy
Decrescida o contador n em 1. n tem que ser 0 ou 1 para o Scout, 0-2 para o
RCX2 e Spybotics.
DecCounter(1);
Counter(n) Função - RCX2, Scout, Spy
Devolve o valor do contador n. n tem que ser 0 ou 1 para o Scout, 0-2 para o
RCX2 e Spybotics.
x = Counter(1);
3.8. Controle de Acesso RCX2, Scout, Spy
O controle de acesso é implementado, principalmente, por meio das declarações
acquire. A função SetPriority pode ser usada para estabelecer a prioridade de uma
função, e as seguintes constantes podem ser usadas para especificar os recursos em uma
declaração acquire. Deve levar-se em conta que a definição dos recursos só está
disponível no RCX2.
Constante Recurso
ACQUIRE_OUT_A
ACQUIRE_OUT_B
ACQUIRE_OUT_C
Saídas
ACQUIRE_OUT_SOUND Som
ACQUIRE_LED LEDs (Somente spybotics)
ACQUIRE_USER_1
ACQUIRE_USER_2
ACQUIRE_USER_3
ACQUIRE_USER_4
Definidas pelo usuário ( Somente em RCX2)
SetPriority(p) Função - RCX2, Scout, Spy
Estabelece a prioridade de uma função a p, que deve ser constante. RCX2
suporta prioridades 0-255, enquanto o Scout suporta prioridades 0-7. Deve levar-se em
conta que para números menores, prioridade maior.
SetPriority(1);
3.9. Eventos RCX2, Scout
Ainda que o RCX2, Scout e Spybotics comportem um mecanismo comum de
eventos, o RCX2 e Spybotics dispõem de 16 eventos, completamente, configuráveis,
____________________Guia do programador de NQC________________________
39
enquanto que o Scout dispõe de 15 eventos pré-definidos. As únicas funções comuns
nestes modelos são os comandos para inspecionar e forçar eventos.
ActiveEvents(tarefa) Valor - RCX2, Scout, Spy
Devolve os eventos que foram produzidos em uma tarefa dada.
x = ActiveEvents(0);
CurrentEvents() Valor - RCX2, Scout, Spy
Devolve os eventos que foram produzidos na tarefa atual.
x = CurrentEvents();
Event(eventos) Valor - RCX2, Scout, Spy
Ativa, manualmente, um evento. Isto pode ser útil para provar o tratamento de
eventos de um programa ou, em outros casos, para simular um evento baseado em
outros argumentos. Deve-se levar em conta que a especificação de eventos difere, um
pouco, entre o RCX2 e o Scout. RCX2 usa a macro EVENT_MASK para computar uma
máscara de evento, enquanto que o Scout as tem pré-definidas.
Event(EVENT_MASK(3)); // Ativa um evento no RCX2
Event(EVENT_1_PRESSED)); // Ativa um evento no Scout
3.9.1. Eventos do RCX2 RCX2, Spy
Nota: Spybotics events appear to be very similar to RCX2 events, although very
little testing has been done for the NQC API y Spybotics. A informação seguinte foi
escrita sobre a perspectiva do RCX2, e não tem sido todavia atualizada para Spybotics.
O RCX2 e Spybotics oferecem um sistema de eventos, extremamente, flexível.
Existem 16 eventos, cada um deles se relaciona com uma das diferentes fontes de
eventos (o estímulo que pode fazer disparar o evento) e o tipo de evento (o critério para
que se dispare).
Outros argumentos podem ser especificados dependendo do tipo de evento. Para
todas as chamadas desde uma função, um evento se identifica por seu número de evento
uma constante entre 0 e 15. Fontes de eventos são os sensores, temporizadores,
contadores ou o buffer de mensagens. Um evento é configurado chamando a
SetEvent(evento, fonte, tipo), onde evento é um número constante (0-15), fonte é a fonte
do evento, e tipo é um dos tipos que se mostram a continuação (algumas combinações
de fontes e tipos não são possíveis).
____________________Guia do programador de NQC________________________
40
Tipo de Evento Condição Fonte do Evento
EVENT_TYPE_PRESSED Valor muda para on Somente Sensores
EVENT_TYPE_RELESASED Valor muda para off Somente Sensores
EVENT_TYPE_PULSE Valor muda de off a on e outra vez a off Somente Sensores
EVENT_TYPE_EDGE Valor muda de on para off e vice-versa Somente Sensores
EVENT_TYPE_FASTCHANGE Valor varia rapidamente Somente Sensores
EVENT_TYPE_LOW Valor muda para low Todos
EVENT_TYPE_NORMAL Valor muda para normal Todos
EVENT_TYPE_HIGHT Valor muda para hight Todos
EVENT_TYPE_CLICK Valor muda de low para hight e outra vez a low
Todos
EVENT_TYPE_DUOBLECLICK
Dois clicks durante um determinado tempo Todos
EVENT_TYPE_MESSAGE Nova mensagem recebida Somente mensagem
Os primeiros quatro eventos baseiam-se no valor booleano de um sensor, assim
que são mais úteis com sensores de contato. Por exemplo, para configurar o evento #2
que se dispare quando o sensor de contato da porta 1 é pressionado, pode ser assim:
SetEvent(2,SENSOR_1,EVENT_TYPE_PRESSED);
Quando se queria usar EVENT_TYPE_PULSE o EVENT_TYPE_EDGE, o sensor
tem que estar configurado como SENSOR_MODE_PULSE o SENSOR_MODE_EDGE
respectivamente.
EVENT_TYPE_FASTCHANGE deve ser usado com sensores que tenham sido
configurados com um argumento slope. Quando o valor raw troca mais rápido que o
argumento slope um evento EVENT_TYPE_FASTCHANGE se disparará.
Os seguintes três tipos (EVENT_TYPE_LOW, EVENT_TYPE_NORMAL e
EVENT_TYPE_HIGH) convertem o valor fonte do evento em uma das três escalas (low
[baixa], normal ou high[alta]), e o evento disparará quando o valor passar de uma
escala a outra. As escalas são definidas por lower limit (limite inferior) e upper limit
(limite superior) para o evento. Quando o valor fonte é menor que o limite inferior, a
fonte será considerada baixa. Quando o valor fonte seja maior que o limite superior, a
fonte será considerada alta. A fonte será normal, quando estiver entre os dois limites.
O seguinte evento configura o evento #3 para que dispare quando o valor do
sensor na porta 2 estiver na escala alta. O limite superior está estabelecido em 80 e o
limite inferior em 50. Esta configuração é um exemplo de como um evento pode
disparar quando o sensor de luz detecta luz clara.
SetEvent(3,SENSOR_2,EVENT_TYPE_HIGH);
SetLowerLimit(3,50);
____________________Guia do programador de NQC________________________
41
SetUpperLimit(3,80);
O argumento hysteresis pode ser usado para fazer com que as transições sejam
mais estáveis, nos casos em que o valor varia. O delay funciona fazendo com que a
transição de baixa a normal seja um pouco mais ampla que a transição de normal a
baixa.
Assim, faz com que seja mais fácil entrar na escala baixa que sair dela.