A linguagem de Programação do Arduino

A Estrutura da Linguagem C do Arduino (excerto do livro digital Experimentos com o Arduino)

A estrutura básica da linguagem de programação do Arduino é bastante simples; ela é formada por dois blocos principais de funções, setup( ) e loop( ), que embutem comandos da linguagem e outros blocos de funções escritos em C/C++. Junto com esses dois blocos podem vir outras funções independentes criadas pelo programador, alem de declarações de variáveis e importações de bibliotecas externas e comentários.

Funções em linguagens de programação são como sub-rotinas ou procedimentos; são pequenos blocos de programas usados para montar o programa principal. Elas são escritas pelo programador para realizar tarefas repetitivas, ou podem ser importadas prontas para o programa principal em forma de bibliotecas.

Declaração da Função Toda função deve ser declarada antes de ser chamada atribuindo-lhe um tipo e um nome seguido de parenteses, onde serão colocados os parâmetros de passagem da função. Depois do nome são definidos entre as chaves '{' e '}' os procedimentos que a função vai executar.

setup( ): Esta é uma função de preparação, ela encapsula duas ou tres outras funções que ditam o comportamento dos pinos do Arduino e inicializam a porta serial. É a primeira função a ser chamada quando o programa inicia e é executada apenas nessa primeira vez.

loop( ): Essa é a função de execução, ela embute qualquer número de outras funções que são executadas repetidamente; é chamada logo depois da função setup( ) e fica lendo os pinos de entrada do Arduino e comandando os pinos de saída e a porta serial.

Exemplos:

Exemplo 1:

Nesse código a função setup( ) ativa a porta serial em 9600 bits/s e a função loop( ) fica transmitindo a frase "Hello World!" pela porta serial a cada 2 segundos:

                void setup( ){
                Serial.begin(9600);               //inicializa a porta serial
                }
                void loop( ){
                Serial.println(“Hello World!“);   //transmite frase pela serial
                delay(2000);                      //a cada 2000 mS
                }
                

Exemplo 2:

Neste programa uma função criada pelo programador, ledOn, aumenta e diminui repetida e gradativamente o brilho de um LED em série com um resistor de 1Kohm conectado no pino PWM 10 do Arduino:

    int i=0;          //declaração da variável global inteira i iniciada com 0
    void ledOn( );    //declaração da função criada 'ledOn' do tipo void
    void setup( ){
    pinMode(10,OUTPUT); //pino e seu modo de operação são passados à função pinMode()
    }
    void loop( ){
    for (i=0; i <= 255; i++) ledOn( );  //aumenta o brilho do led
    for (i=255; i >= 0; i--) ledOn( );  //diminui o brilho do led
    }
    void ledOn( ){       //função que acende/apaga o led
    analogWrite (10, i); //pino e o valor de i são passados à função analogWrite()
    delay (10);
    }
    

Símbolos Usados na Linguagem

Os Símbolos usados na construção de funções em C são os seguintes:

    { } - Dentro das chaves vão os procedimentos que a função deve executar;
                    
    ; - O ponto-e-vírgula é usado para marcar o final de um procedimento;
                    
    // - comentário de uma linha: tudo depois das duas barras é ignorado;
                    
    /*...*/ - comentário em várias linhas: tudo entre esses simbolos é ignorado.
    

Constantes

Constantes são valores predefinidos que nunca podem ser alterados. Na linguagem C do Arduino são 3 os grupos de constantes; os dois componentes de cada grupo sempre podem ser representados pelos números binários 1 e 0.

TRUE/FALSE são constantes booleanas (1 e 0) que definem estados lógicos. Verdadeiro é qualquer valor diferente de zero. Falso é sempre o valor zero.

HIGH/LOW essas constantes definem as tensões nos pinos digitais do Arduino. A constante High (alto) põe uma tensão de 5 volts no pino selecionado; a constante Low (baixo) põe terra (ou 0 volt) nesse pino.

INPUT/OUPUT são constantes programadas pela função pinMode( ) para os pinos do Arduino; eles podem ser programados como entradas (de sensores) ou podem ser programados como saídas (de controle).

Variáveis

Variáveis são posições na memória de programa do Arduino marcadas com um nome e o tipo de informação que irão guardar. Essas posições podem estar vazias ou podem receber um valor inicial. Os valores das variáveis podem ser alterados pelo programa.

Escopo da Variável é o limite ou abrangência da variável. Uma variável pode ser declarada em qualquer parte do programa. Se for declarada logo no início, antes da função setup( ), ela tem o escopo de Variável Global, e porisso ela pode ser vista e usada por qualquer função no programa. Se declarada dentro de uma função ela tem o escopo de Variável Local, e só pode ser usada por essa função.

Declaração da Variável como as funções, toda variável deve ser declarada antes de ser chamada. Essa declaração consiste em atribuir previamente um tipo e um nome à variável.

Tipos de variáveis

                byte - esse tipo armazena 8 bits (0-255);
                    
                int - armazena números inteiros de até 16 bits;
                    
                long - armazena números inteiros de até 32 bits;
                    
                float - variáveis deste tipo podem armazenar números fracionários de até 32 bits.
                

Matrizes

Matrizes são coleções de variáveis de um mesmo tipo, portanto são posições na memória de programa; cada uma com um endereço, um identificador, chamado de índice. A primeira posição de uma matriz é sempre a de índice 0.

Declaração de uma Matriz - I As matrizes, como as variáveis e as funções, devem ser declaradas com um tipo e um nome seguido de colchetes; e podem também ser inicializadas com os valores entre as chaves. Exemplo:

int nomeMatriz [ ] = {16,32,64,128,...};

Declaração de uma Matriz - II Pode-se tambem declarar somente o tipo, o nome e o tamanho da matriz, deixando para o programa o armazenamento de variáveis nas posições, ou índices, da matriz. Exemplo:

int nomeMatriz [ 10 ] ; //nomeMatriz com dez 10 posições para variáveis inteiras

Escrever/Ler uma Matriz:

Para guardar o inteiro 16 na 4ª posição da matriz nomeMatriz, usa-se:

nomeMatriz [3] = 16;

Para atribuir o valor armazenado na 5ª posição de nomeMatriz à variável x:

int x = nomeMatriz[4];

Operações Aritméticas e lógicas

As 4 operações aritméticas, divisão, adição, multiplicação e subtração, são representadas pelos símbolos: /, +, *, e -, respectivamente, separando os operandos:

                x = x + 1       [= x++ ] 
                x = x - 1       [= x-- ]
                x = x + y       [= x+=y] 
                x = x - y       [= x-=y] 
                x = x * y       [= x*=y] 
                x = x / y       [= x/=y] 
            

E são 3 os operadores lógicos na linguagem do Arduino que são usados para comparar duas expressões e retornar 1 ou 0 (TRUE/FALSE):

                &&	AND	porta lógica ‘E’
                ||	OR	porta lógica ‘OU’
                !	NOT	porta lógica NÃO
            

Os símbolos compostos combinam os símbolos aritméticos com o sinal de atribuição e comparam uma variável com uma constante, ou variáveis entre si, para testar uma condição:

                x == y	 //  x é igual a y?
                x != y	 //  x não é igual a y?
                x < y	 //  x é menor que y?
                x > y	 //  x é maior que y?
                x <= y	 //  x é menor ou igual a y?
                x >= y   //  x é maior ou igual a y?
            

Funções de Matemática e Tempo

delay(ms) Essa função pausa o programa por um período em milissegundos indicado pelo parâmetro entre parênteses. Exemplo: delay(1000); Com esse parâmetro o programa vai pausar durante 1 segundo (1000 ms). Nota: Durante o período em que essa função está ativa qualquer outra função no programa é suspensa; é equivalente ao HALT em Assembly. Somente as interrupções de hardware podem parar essa função.

delayMicroseconds(us) Essa função pausa o programa por um período em microssegundos indicado pelo parâmetro entre parênteses. Exemplo: delayMicroseconds(1000); Com esse parâmetro o programa vai pausar durante 1 ms (1000 us).

millis( ) Retorna o número de milissegundos desde que o Arduino começou a executar o programa corrente. Exemplo: long total = millis( ); Aqui a variável inteira longa (de 32 bits) ‘total’ vai guardar o tempo em ms desde que o Arduino foi inicializado.

random(min,max) Gera números pseudo-aleatórios entre os limites min e max especificados como parâmetros. Exemplo: int valor = random(100,400); A variável inteira ‘valor’ vai assumir um valor aleatório entre 100 e 400. Nota: O parâmetro min é opcional e se excluído o limite mínimo é 0.

abs(x) Retorna o módulo ou valor absoluto do número real passado como parâmetro. Exemplo: float valor = abs(-3.14); À variável ‘valor’ vai ser atribuído o número em ponto flutuante (e sem sinal) 3.14.

map(valor,min1,max1,min2,max2) A função map( ) converte uma faixa de valores para outra faixa. O primeiro parâmetro ‘valor’ é a variável que será convertida; o segundo e o terceiro parâmetros são os valores mínimo e máximo dessa variável; o quarto e o quinto são os novos valores mínimo e máximo da variavel ‘valor’. Exemplo: int valor = map(analog Read(A0),0,1023,0,255)); A variável ‘valor’ vai guardar a leitura do nível analógico no pino A0 convertida da faixa de 0-1023 para a faixa 0-255. Com essa função é possível reverter uma faixa de valores, exemplo: int valor = map(x,1,100,100,1);

Controles de Fluxo

O comando if

if é um controle de fluxo usado para selecionar uma ou mais instruções baseado no resultado de um teste de comparação. Todas as instruções entre as chaves '{' e '}' são executadas somente se o resultado desse teste for verdadeiro; se não, essas instruções não são executadas. Verdadeiro é qualquer resultado, mesmo negativo, diferente de zero. Falso é um resultado zero.

Sintaxe:

    if (expressão) {
    bloco de instruções;
    }
    //se ‘expressão’ for verdadeira, ‘bloco de instruções’ é executado.



O comando if...else

Ao se acrescentar mais um bloco de instruções no loop do comando 'if' pode-se criar o comando if...else, para fazer um teste novo quando o resultado da expressão for falsa.

Sintaxe:

    if (expressão){
    bloco de instruções1;	
    }
    //se ‘expressão’ for verdadeira, ‘bloco de instruções1’ é executado
    else {
    bloco de instruções2;	
    }
    //se ‘expressão’ for falsa, ‘bloco de instruções2’ é executado
        
    

O comando if...else...if

E de novo ao se acrescentar agora o comando 'if...else' no loop do comando 'if' pode-se criar mais um outro comando, o if...else...if. No exemplo abaixo se ‘expressão1’ for verdadeira o ‘bloco de instruções1’ é executado; se ‘expressão1’ for falsa mas expressão2 for verdadeira ‘bloco de instruções2’ é executado; e se ‘expressão1’ e ‘expressão2’ forem falsas o ‘bloco de instruções3’ é executado.

Sintaxe:

    if (expressão1) {
    bloco de comandos1;	
    }
    else if (expressão2) {
    bloco de instruções2;
    }
    else {
    bloco de comandos3;	
    }
    



O comando switch...case

É possível ir inserindo comandos 'if...else' na posição do segundo bloco de instruções de outro comando 'if...else' e assim criar uma cadeia de comandos para testar dezenas de expressões até encontrar uma que retorne um resultado verdadeiro e executar um dos blocos de instruções. Mas existe um comando próprio que simplifica bastante essa seleção, é o comando switch...case. Esse comando permite comparar uma mesma variável inteira, ou uma expressão que retorne um inteiro, com vários valores possíveis pré-definidos.

Sintaxe:

    if (expressão1) {
    switch (expressão) {
    case 1: bloco de instruções1; 
    break;
    case 2: bloco de instruções2;
    break;
    case 3: bloco de instruções3;
    break;
    default: bloco de instruções4;
    }
    



O comando while

Uma das operações mais frequentes que os programas executam é repetir um bloco de instruções até que uma condição inicialmente verdadeira se torne falsa. É para isso que serve o comando while.

Sintaxe:

    if (expressão1) {
    while (expressão) {
    bloco de instruções;	
    }
    //O bloco de instruções será executado
    //enquanto o parâmetro expressão for verdadeiro. 



O comando do...while

Para que o bloco de instruções seja executado ao menos uma vez, ele é deslocado para a entrada da caixa de decisões, antes do teste de validade, cria-se o comando do...while:

Sintaxe:

    
    do {
    bloco de instruções;
    }
    while (expressão);
    
    //Aqui o ‘bloco de instruções’ será executado primeiro
    //e só então o parâmetro ‘expressão’ é avaliado. 

O comando for

Inserindo-se no loop do comando 'while' um contador que registre cada execução do bloco de instruções cria-se o comando for. Esse contador deve conter uma variável de controle que deve ser previamente inicializada com um tipo e um valor.

Sintaxe:

     
    for (variável; expressão;incremento) {
    bloco de instruções;
    }
           
    

A variável de controle é inicializada normalmente com 0 ou 1; o parâmetro expressão deve conter o valor máximo (ou mínimo) que o contador deve alcançar; e incremento é o valor que será incrementado (ou decrementado) da variável cada vez que o bloco de instruções é executado. Observe que cada parâmetro entre parênteses é separado por ponto e vírgula.





O operador ternário '?'

É possível simplificar códigos com comandos if...else em C/C++ com o operador condicional ‘?’, tambem chamado de operador ternário '?'. Esse operador avalia uma expressão e se esta for vardadeira uma instrução é executada, se a expressão for falsa uma outra expressão é executada. A sua sintaxe é a seguinte:

Sintaxe:

     
    (expressão) ? instrução1 : instrução2;
        
    

Exemplo:

     
    int x = 8;
    y = (x > 10) ? 15 : 20;
        
    

Aqui o valor de y vai depender da avaliação da expressão do operador ternário; como o valor de x vale 8, a expressão (x>10) é falsa, porisso o inteiro 20 será atribuido a y; se o valor atribuido a x fosse maior que 10, y seria 15. Essa mesma expressão com o comando 'if...else' ficaria assim:

     
    int x = 8;
    if (x > 10) {
    y = 15;
    }
    else 
    y = 20;