Linguagem de Comandos Elétricos - LCE 2.1  
 
 
 
Web Site: www.andrebarbosa.eti.br

Previous  Top  Next



Por acreditar e esperar que versões adequadas dos controladores lógicos programáveis virão a ser, como já o são no setor industrial, amplamente utilizados nos setores comercial e doméstico, em automação maleável de edifícios, residências, escritórios, consultórios, equipamentos profissionais, brinquedos, veículos, eletrodomésticos, e outros, pelas maravilhas de conforto, confiabilidade, economia, racionalidade e qualidade que podem agregar ao padrão de nossas vidas, ao substituir os controles manuais repetitivos que somos obrigados a fazer (quando conseguimos e quando não esquecemos - imagine a programação de um videocassete!) por ações programáveis flexíveis, criei o SimuPLC e a LCE. (Obs.: como acontece com toda tecnologia, tudo será em vão se o foco não for a felicidade humana.)

A Linguagem de Comandos Elétricos - LCE
, é uma linguagem de alto nível (em oposição à linguagem de baixo nível Lista de Instruções - IL) desenvolvida com a finalidade de agilizar, facilitar e tornar a programação de PLCs mais natural e compreensível para os não-especialistas, e mais produtiva para os especialistas, tornando os programas de controle melhor estruturados, semanticamente mais significativos e naturalmente documentarizados, além de potencialmente independentes de equipamento. Exemplo de um programa de controle muito simples escrito em LCE:

clp Liga_Desliga_Lâmpada // Controle mais simples que imaginei: acende e apaga uma lâmpada

var
   I0.0   Interruptor,
      
Q0.0
   Lâmpada;

rede
1 // Verifica se interruptor está ligado para acionar a lâmpada

se
( Interruptor ) {
aciona
Lâmpada;
}

fim

Muito embora este controle tenha sido o mais simples que imaginei, com ele já é possível verificar pontos interessantes e expor vários aspectos da
linguagem LCE:

·No início, o programa deve apresentar, após a cláusula obrigatória clp, um nome ou denominação, o qual poderá descrever, de modo sintético, mas significativo, do que se trata o controle. E o fim do programa-fonte é sinalizado com a cláusula fim.  
 
·Com a cláusula var torna-se possível (mas não obrigatório) a associação de nomes significativos a variáveis do programa, os quais podem ser referenciados posteriormente, no corpo da lógica do programa, tornando mais clara sua compreensão.  
 
·A cláusula rede segmenta o programa em partes, onde cada parte inicializa a utilização da pilha (stack), tornando sua gerência mais racional, pois se garante que a mesma não crescerá ilimitadamente durante o funcionamento do programa. Além disso, quando acrescidos comentários esclarecedores da função de cada segmento, o programa de controle fica mais bem documentarizado, facilitando sua compreensão e manutenção.  
 
·A sintaxe da LCE é similar à das linguagens de programação de uso geral, como C, C++, Pascal, Basic, mas é infinitamente menor e mais simples que estas, aproximando-se de comandos imperativos em linguagem natural (em português, inglês, ou bilíngüe, indiferentemente) e do Texto Estruturado (Structured Text - ST) o que minimiza em muito a curva de aprendizagem da LCE, mesmo para os leigos em programação, pois ela oculta do usuário a complexidade inerente às linguagens de controle baseadas em listas de instruções.  
 
·Os modos alternativos de programação de PLCs, o desenho direto do diagrama ladder ou do diagrama de blocos de função, são apropriados, em programas de menor porte, para engenheiros e técnicos eletricistas ou eletrônicos, respectivamente, os quais detêm os conhecimentos especializados requeridos.  
 
·Ressalte-se que em programas de maior porte tal técnica, mesmo para os especialistas da área, sofre no aspecto da documentarização do controle implementado, que constitui um extenso trabalho suplementar a ser feito, decorrente da ausência de significado e semântica textual do programa obtido, características naturalmente inerentes às linguagens de alto nível, onde o próprio texto do programa escrito compõe sua melhor documentarização.  
 
·Para fins da visualização da simulação, a partir da Lista de Instruções, é gerado automaticamente o diagrama ladder correspondente, o qual funcionará como se percorrido por ciclos de varredura (scan cycles) reais, reiteradamente lendo os pontos de entrada virtuais e atualizando as variáveis internas correspondentes (simulação da memória-imagem do processo de E/S (I/O)), processando as instruções do início ao fim do programa de controle, ou de acordo com a lógica de desvios utilizada, atendendo, se habilitadas, as ocorrências de eventos de interrupções virtuais, e, ao final, colocando os resultados nos pontos de saída virtuais. Obs.: a forma de atualização das entradas e atuação das saídas pode ser alterada pelo item de menu I/O.  
 
·Tal ciclo é repetido indefinidamente, até que o Simulador seja posto no Modo Stop.  

Como resultado da compilação do programa
Liga_Desliga_Lâmpada acima, o SimuPLC 4.1.0 gerou, exatamente, o seguinte código, na linguagem Lista de Instruções - IL:

// CLP    Liga_Desliga_Lâmpada
// Controle mais simples que imaginei: acende e apaga uma lâmpada

//
=VAR
   I0.0   Interruptor
//
=VAR
   Q0.0   Lâmpada

NETWORK
   1 // Verifica se interruptor está ligado para acionar a lâmpada

LD
   I0.0
=
   Q0.0

Exemplos mais complexos:    

A estrutura gramatical livre de contexto simplificada da linguagem LCE 2.1
, na Forma de Backus-Naur (BNF), é a seguinte:

Gramática da Linguagem de Comandos Elétricos - LCE 2.1


programa -> clp id variáveis circuito fim

variáveis ->   var
listvar | e
listvar   ->    id idVar
maisvar ;
maisvar    -> ,
id idVar maisvar | e

circuito   -> rede
id comandos mais_circ
mais_circ   -> rede
id comandos mais_circ | e

comandos   -> se
(cond) { listacão } else mais_coman |

           enquanto
(cond) { comandos } mais_coman |

           repete
{ comandos } enquanto (cond); mais_coman |

quando (cond) temporiza idVar id tempo; mais_coman |  
 
quando_não (cond) temporiza idVar id tempo; mais_coman |  
 
quando (cond) temporiza_acumula idVar id tempo; mais_coman |  
 
quando_não (cond) temporiza_acumula idVar id tempo; mais_coman |  
 
conta (cond) reset_quando (cond) em idVar referencia id;  
mais_coman |  
 
conta_decrescente (cond) quando (cond) faz idVar receber id;  
mais_coman |  

conta_crescente (cond) conta_decrescente (cond)  
reset_quando (cond) em idVar referencia id; mais_coman |  
 
label id: mais_coman |  
 
seqüência idVar circuito fim_cto_seq rede id se (cond) { mais_ação  
transfere_seqüência id; } else_seq mais_transfere rede id fim_seq; |  
 
IL comando_il carriage_return new_line mais_coman |  
 
          sub_rotina id (param1 param2) comandos mais_circ fim_sub mais_sub mais_interrupção
|  

          tratador_interrupção id( )
comandos mais_circ fim_tratador_interrupção mais_interrupção |

          watchdog_reset;
mais_coman

param1   -> idVar1
| e
param2   -> , idVar2 | e

else      -> senão {
listacão } | e

else_seq   -> senão {
ação_else_seq } | e

ação_else_seq -> se (cond) { mais_ação transfere_seqüência id; } |
          transfere_seqüência
id;

mais_coman-> comandos |
e

mais_transfere -> se
(cond) { mais_ação transfere_seqüência id; } else_seq mais_transfere | e

tempo      -> ms
| s | min | h

mais_sub   -> rede
id sub_rotina id param1 param2 circuito fim_sub mais_sub | e

mais_interrupção -> rede
id interrupção id comandos mais_circ fim_interrupção mais_interrupção | e

cond      -> PPm
Pm      -> ou
PPm | e
P         -> FFm
Fm      -> e
FFm | e
F      -> tipo_ação idVar | id_cmp tipop Rel id | não tipo_ação idVar | (cond) | sem_erro | overflow | pulso_desliga (cond) | pulso_liga (cond) | nega (cond)  

Rel      -> =
| <> | > | < | >= | <=
tipop      -> B
| W | D | R | e

listação   -> liga
tipo_ação idVar; mais_ação |
desliga tipo_ação idVar; mais_ação |  
aciona tipo_ação idVar; mais_ação |  
se (cond) { listacão } mais_ação |  
           transfere_sequencia id; mais_ação |
vai_para id; |  
para idVar de id a id comandos fim_para |  
idVar tipopop:= expressão; mais_ação |  
permuta_bytes de idVar; mais_ação |  
incrementa tipop idVar; mais_ação |  
decrementa tipop idVar; mais_ação |  
desloca para direção tipop idVar id posições; mais_ação |  
rotaciona para direção tipop idVar id posições; mais_ação |  
encode id em idVar; mais_ação |  
decode idVar de id; mais_ação |  
display7seg id em idVar; mais_ação |  
pid id, SP = id, Kc = id, Ti = id, Td = id,  
MX = id, PV = id, Mn = id; |  
id_sbr (id1, id2); mais_ação |  
converte tipop id para tipop idVar; mais_ação |  
BCD_para_inteiro em idVar; mais_ação |  
inteiro_para_BCD em idVar; mais_ação |  
extrai_raiz_quadrada de id em idVar; mais_ação |  
extrai_seno de id em idVar; mais_ação |  
extrai_cosseno de id em idVar; mais_ação |  
extrai_tangente de id em idVar; mais_ação |  
extrai_logaritmo_natural de id em idVar; mais_ação |  
randomize id em idVar; mais_ação |  
arredonda id em idVar; mais_ação |  
trunca id em idVar; mais_ação |  
inverte tipop idVar; mais_ação |  
retorna; |  
stop; |  
finaliza_scan; |  
habilita_interrupções; mais_ação |  
desabilita_interrupções; mais_ação |  
vincula id à interrupção evento; mais_ação |  
desvincula evento; mais_ação |  
recebe_byte em id vindo_do port; mais_ação |  
transmite_byte id no port; mais_ação  

expressão   -> parcela mais_parcela
parcela   -> fator mais_fator
mais_parcela-> tipop+
parcela mais_parcela | tipop- parcela mais_parcela | tipop| parcela                     mais_parcela | tipop^ parcela mais_parcela | e
mais_fator   -> tipop*
fator mais_fator | tipop/ fator mais_fator | tipop& fator mais_fator | e
fator      -> id
| idVar | (expressão)

port      -> Port0
| Port1

evento   -> borda_subida_I0.0
| borda_descida_I0.0 | borda_subida_I0.1 |
          borda_descida_I0.1
| borda_subida_I0.2 | borda_descida_I0.2 |
          borda_subida_I0.3
| borda_descida_I0.3 | recepção_Port0 |
          recepção_port1
| transmissão_port0 | transmissão_port1 |
          temporização_T32
| temporização_T96

mais_ação      -> listação | ou (cond_OuSe) { listacão } mais_ação_OuSe | e  

mais_ação_OuSe    -> ou (
cond_OuSe) { listacão } mais_ação_OuSe | e

cond_OuSe       -> tipo_ação idVar
| id_cmp tipop Rel id | não tipo_ação idVar

op         -> +
| - | * | / | & | | | ^ | e

tipo_ação   -> imediato | e

direção   -> esq
| dir


onde idVar (identificador variável variant) é um nome que começa com uma letra, e pode ter até 255 caracteres; id (identificador) pode ser, além de um nome como o anterior, também uma constante, formada por dígitos numéricos, onde o símbolo de decimal é o ponto, e cmd_stl é qualquer linha de comando válida em IL.

Obs. 1
: as variáveis e instruções no SimuPLC são sensíveis ao caso (case sensitive), ou seja, são consideradas diferentes as formas minúscula e maiúscula da mesma letra. Geralmente, as instruções em IL são escritas em maiúsculas, e em LCE o são em minúsculas.

Obs. 2
: na gramática acima, os símbolos em azul são não-terminais e os em preto são terminais.

Obs. 3
: os operadores aritméticos devem ser separados por espaços dos respectivos operandos na construção das expressões, à exceção dos operadores unários - e +. Exemplo:

Sinal_Correção
:= (-3*Corrente+100)/(Velocidade+Pressão); // Errado. sempre mantenha espaço entre operador e operando e nunca entre tipo da operação e operador

Sinal_Correção
:= (-3 * Corrente + 100) / (Velocidade + Pressão); // Certo