EASYCODE: Uma ferramenta de produtividade

EASYCODE

Introdução

Neste artigo vou apresentar uma ferramenta de software que utilizo há muitos anos, o EASYCODE. Garimpei essa ferramenta para melhorar minha produtividade no desenvolvimento de software embarcado para microcontroladores e DSPs. Eu sempre utilizei o método gráfico para planejamento e projeto de software conhecido como diagramas Nassi-Shneiderman e a abordagem Top-Down para o refinamento dos blocos do software. Essa ferramenta de software utiliza esses mesmos diagramas Nassi-Shneiderman para planejar e gerar o software.

Diagramas Nassi-Shneiderman

Os diagramas N-S, como são chamados na forma curta,  permitem  representar e desenvolver programas de computador ou algoritmos graficamente. Esses diagramas nos permitem visualizar melhor o sistema como um todo e facilitam o desenvolvimento do projeto e a detecção de eventuais falhas no nosso raciocínio. Na Figura 1 está ilustrado um exemplo de como realizar o cálculo de uma média de notas de um aluno. É muito simples, não? Bem mais fácil de ler ou entender do que o código de programação correspondente.

Media de notas
Figura 1: Diagrama N-S para cálculo da nota média de um aluno

Os diagramas N-S são associados diretamente aos comandos de programação, tais  como IF-THEN-ELSE, FOR, DO-WHILE, etc. A tradução é direta, quando o programa estiver totalmente detalhado. Para complementar a introdução, faltou explicar que a abordagem Top-Down é a maneira de se desenvolver um projeto, sistema, algoritmo, etc, partindo do plano mais geral (Top) e descendo aos poucos para os detalhes, (Down) até que esteja tudo definido nos mínimos detalhes. Para conhecer um pouco mais sobre a técnica Top-Down, sugiro que você leia o artigo técnico Técnicas: Top-Down, Mocks e TDD.

A ferramenta de desenvolvimento de software

Voltando ao tema da ferramenta de software, eu identifiquei uma que além de facilitar a geração dos diagramas N-S também traduz esses diagramas para uma linguagem de programação, no meu caso optei pela linguagem C/C++. Essa ferramenta também tem o recurso de realizar a engenharia reversa de programas. Você consegue montar os diagramas e escrever os comentários em cima do programa sem documentação. Os diagramas podem ser desenvolvidos de forma hierárquica. Essa ferramenta, originalmente desenvolvido pela Siemens da Áustria, chamava-se EASYCASE, depois foi rebatizada de EASYCODE.

Não é uma ferramenta gratuita. Ela custa caro, mas vale muito a pena. Se você possui uma empresa, ou trabalha numa instituição que pode investir nesse tipo de ferramenta, vale muito a pena adquirí-la. Você pode fazer um test drive gratuito, se quiser no link[1] abaixo. Se observarmos a Figura 2, podemos notar que a ferramenta vai muito além de facilitar a programação em diagramas estruturados. Ela permite planejar e desenvolver todo um projeto.

easycode
Figura 2: Módulos do EASYCODE

Exemplo

Para exemplificar a utilidade e o quanto essa ferramenta é poderosa, vou usar um programa pequeno, que foi apresentado no artigo técnico Sistemas Operacionais de Tempo Real – Teclados Matriciais, como um programa completo para a simulação da operação de timers, displays de 7 segmentos e um teclado matricial em ambientes de tempo real. Esse programa tem apenas em torno de 700 linhas de código. Se impresso em papel, seriam gastos mais de 12 páginas para essa impressão. Veja a seguir.

/* EasyCODE V6.8 03/03/2015 13:29:47 */
/* EasyCODE O
If=horizontal
LevelNumbers=no
LineNumbers=no
Colors=16777215,0,12582912,12632256,0,0,0,16711680,8388736,0,33023,32768,0,0,0,0,0,32768,12632256,255,65280,255,255,16711935
ScreenFont=System,,100,1,-13,0,700,0,0,0,0,0,0,1,2,1,34,96,96
PrinterFont=Courier New,,100,4,-83,0,400,0,0,0,0,0,0,3,2,1,49,600,600
LastLevelId=23 */
/* EasyCODE ( 1
   Exemplo de uso do EASYCODE */
//********************************************************************************************
//**                                                                                                                                    **
//**     ROTINA EXEMPLO PARA TESTE DO USO DO TIMER, DISPLAYS E TECLADO     **
//**         PARA SISTEMAS OPERACIONAIS DE TEMPO REAL                                          **
//**                   (Resp. Eng. Puhlmann)                                                                            **
//**                                                                                                                                    **
//**              (15/12/2014 - rev. 03/03/2015)                                                                      **
//**                                                                                                                                    **
//********************************************************************************************

#include <AT89S53.H>                   // AT89S8253

//----------------------------
/* EasyCODE ( 4
   Definicoes e inicializacoes referentes ao Timer */


#define DESLIGA 0
#define LIGA    1

// Define-se aqui a freqüência de clock da CPU

#define FREQUENCIA_DO_CLOCK_DA_CPU         4.0e+6   // Hz ----> 4 MHz por exemplo

// Define o pre-scaler

#define FATOR_DE_ESCALA_CLOCK_TIMER    12.0f     // Divide o clock por 12

// Define a freqüência de interrupção do timer

#define FREQUENCIA_DE_INTERRUPCAO_TIMER_0 1.5e+3  // Hz ---- > 1,5 kHz

//--------------

// Definição de variáveis referentes aos timers

//------- Timer 0 ----------

#define MASCARA_CT_0                                    0xfb
<strong>Sistemas Operacionais de Tempo Real - Teclados Matriciais</strong>
// Definição utilizada apenas quando o timer estiver no modo 2 de operação
// se acaso nao for usado no modo 2, comentar a linha abaixo

// Define o Timer 0 como operando no modo 2
// A conta desse preset tem que dar um número de 0 a 255, senão não funciona... 
 
#define PRESET_TIMER_0_MODO_2          (255 - (unsigned char)((FREQUENCIA_DO_CLOCK_DA_CPU/(FATOR_DE_ESCALA_CLOCK_TIMER * FREQUENCIA_DE_INTERRUPCAO_TIMER_0))+ 0.5))


#define MASCARA_DO_MODO_DO_TIMER_0      0xfc
#define MODO_0_TIMER_0                  0x00
#define MODO_1_TIMER_0                  0x01
#define MODO_2_TIMER_0                  0x02
#define MODO_3_TIMER_0                  0x03


//=============== Fim da definicao dos parametros do Timer 0 ===========


#define PRESET_TIMER_DE_SOFTWARE        10        // Define o valor inicial do temporizador de software
int nTimerDeSoftware = PRESET_TIMER_DE_SOFTWARE;  // Inicializa o temporizador de software com 10
bit bFlagTimerDeSoftware = DESLIGA;               // Inicializa a sinalização de término de contagem


/* EasyCODE ) */
/* EasyCODE ( 5
   Definicoes e inicializacoes referentes ao teclado */
/* EasyCODE < */

//===============================================================================
//
//              ROTINA DE LEITURA DE MATRIZ DE CONTATOS II - Linhas de seleção separadas
//              (Cada linha de seleção corresponde a um bit da Porta)
//
//      Entradas : - bFlagDeTemporizacaoDaMatrizDeContatos - Sinaliza que pode realizar a leitura
//      Saídas   : - bFlagDeNovaLeituraDeMatrizDeContatos  - Sinaliza que foi realizada nova leitura da matriz
//                         - ucMatrizDeContatosDeEntrada[]                 - Leituras atualizadas no vetor
//=====                                                                     =====

//----------- Definições de parâmetros -------------------------

#define FREQ_DE_INTERRUP_TIMER_MATRIZ_DE_CONTATOS  10.0 // Hz, que corresponde à freqüencia de leitura da matriz/ teclado

// Inicializa o valor de preset do timer de software - Observe que FREQUENCIA_DE_INTERRUPCAO_TIMER_0 está
// definido no módulo do timer

#define PRESET_TEMPORIZADOR_DA_MATRIZ_DE_CONTATOS  (unsigned int)((FREQUENCIA_DE_INTERRUPCAO_TIMER_0/ FREQ_DE_INTERRUP_TIMER_MATRIZ_DE_CONTATOS)+ 0.5)

// Define o número de linhas da matriz (exemplo)

#define NUMERO_DE_LINHAS_DA_MATRIZ                 4            // Número de linhas de seleção

// Aqui define-se os ports onde estão conectadas a matriz e as linhas de selação

#define PORTA_DE_ENTRADA_DA_MATRIZ                 P2           // Define o Port onde está conectada a matriz
#define PORTA_DE_SAIDA_DA_SELECAO_DA_MATRIZ        P2           // Define o port onde estão conectadas as linhas de seleção

// As máscaras a seguir definem máscaras do tipo cheia de "uns", onde existem linhas ativas. Obrigatoriamente essas linhas
// têm que ser consecutivas e no máximo 8, ocupando o port inteiro

// Alguns exemplos ... 3 linhas a partir do bit 0 do port 2

#define MASCARA_DA_MATRIZ                                                  0x07         // Filtra os bits de entrada da matriz (3 nesse exemplo)

// Quatro linhas de selação ... bits 4 a 7 do port 2

#define MASCARA_DA_SELECAO                                                 0xf0         // Filtra os bits dos sinais de seleção

// Bit de seleção a ser shiftado, para gerar o sinal de seleção ...  bit 4 (define a primeira linha a ser lida)

#define SELETOR_DOS_SINAIS_DE_SELECAO                      0x10         // Define posição do primeiro bit do conjunto de seleção

// Aqui define-se se as saídas são normais ou invertidas, complemento de 1. Se forem invertidas, realiza-se
// um ou exclusivo da máscara de seleção com elas, invertendo a todos os bits.. 

//#define SAIDAS_INVERTIDAS                                                     1               // Define se as saidas de selecao sao invertidas ou nao

#ifdef SAIDAS_INVERTIDAS
        #define MASCARA_DE_INVERSAO                                             MASCARA_DA_SELECAO
#else
        #define MASCARA_DE_INVERSAO                                             0x00
#endif

//*** Aqui definem-se as variáveis globais desse trecho da rotina (fora do bloco principal - main)***

volatile bit  bFlagDeTemporizacaoDaMatrizDeContatos = DESLIGA;                  // Sinaliza que pode realizar nova leitura
unsigned int unTimerDaMatrizDeContatos  = PRESET_TEMPORIZADOR_DA_MATRIZ_DE_CONTATOS;
unsigned char ucMatrizDeContatosDeEntrada[NUMERO_DE_LINHAS_DA_MATRIZ] = { 0, 0, 0, 0};
volatile bit  bFlagDeNovaLeituraDeMatrizDeContatos = DESLIGA;                   // Sinaliza que foi realizada nova leitura


//===============================================================================
//
//              ROTINA QUE REALIZA O "DEBOUNCE" DA MATRIZ DE CONTATOS
//
//          uma vez lidos os contatos, pode-se inserir essa rotina para realizar o debounce, se necessário
//
//      Entradas : - bFlagDeNovaLeituraDeMatrizDeContatos  - Sinaliza que há leitura nova da matriz de entrada
//                         - ucMatrizDeContatosDeEntrada[]             - Vetor contendo as leituras atualizadas da matriz
//             - ucMatrizDeContatosDeEntradaAnterior[] - Vetor contendo as leituras anteriores da matriz
//  Saídas   : - ucMatrizDeContatosDeEntradaAnterior[] - Vetor contendo as leituras anteriores da matriz atualizadas
//                         - bFlagDeTerminoDeDebounce                      - Sinalização de término de debounce, permissão para análise
//
//=====                                                                     =====

#define PRESET_CONTADOR_DEBOUNCE                        3                       // Número de dados novos com a leitura estável ( 0 - 255)

unsigned char ucMatrizDeContatosDeEntradaAnterior[NUMERO_DE_LINHAS_DA_MATRIZ] = { 0, 0, 0, 0};
unsigned char ucContadorDeDebounce = PRESET_CONTADOR_DEBOUNCE;
volatile bit  bFlagDeTerminoDeDebounce = DESLIGA;
volatile bit  bFlagNovosDados = DESLIGA;

//===============================================================================
//
//              ROTINA QUE REALIZA A IDENTIFICAÇ+O DOS CONTATOS FECHADOS
//
//              Após a realização da leitura, ou após o debounce, pode-se identificar os 
//              contatos que foram acionados, se houver. Ela numero os contatos sequencialmente
//              a partir do primeiro. 
//
//      Entradas : - bFlagDeTerminoDeDebounce             - Sinaliza que há leitura estável da matriz de entrada
//                         - ucMatrizDeContatosDeEntrada[]        - Vetor contendo as leituras atualizadas da matriz
//                         - ucMatrizDeContatosDeReferencia[] - Vetor contendo as máscaras de referência para identificar
//                                                                                                      os contatos acionados
//  Saídas   : - bFlagResultadosMatrizDeContatos  - Sinaliza que há contatos acionados
//                         - ucContadorDeContatosFechados     - Número de contatos acionados
//                         - ucVetorDeResultados[]                        - Vetor contendo a posição relativa do contato acionado
//
//=====                                                                     =====

// Define o número de colunas da matriz.. (quantos bits tem em cada leitura)

#define NUMERO_DE_COLUNAS_DA_MATRIZ             03

// Identifica a posição do primeiro bit a ser identificado, e utilizado para comparação (com operação AND
// com a máscara) e deslocamento da máscara para leitura dos bits subseqüentes

#define MASCARA_DE_SELECAO_DE_COLUNA_INICIAL 0x01

// Define um número máximo de resultados para o vetor de resultados

#define TAMANHO_MAXIMO_DO_VETOR_DE_RESULTADOS 5

// define e inicializa um vetor de referência, onde os bits = 1, sinalizam que o contato fechado = 1, e
// bits = 0, quando está em zero... Abrange apenas os bits conectados da matriz... Aqui no exemplo, bits 
// de 0 a 2

unsigned char ucMatrizDeContatosDeReferencia[NUMERO_DE_LINHAS_DA_MATRIZ] = {0x07, 0x07, 0x07, 0x07};

unsigned char ucVetorDeResultados[TAMANHO_MAXIMO_DO_VETOR_DE_RESULTADOS] = {0, 0, 0, 0, 0};

// Contador que indica o número de contatos fechados no vetor

unsigned char ucContadorDeContatosFechados;

// bit de sinalização de que encontrou contatos "fechados"

bit bFlagResultadosMatrizDeContatos = DESLIGA;


//*************************************************************************



/* EasyCODE > */
/* EasyCODE ) */
/* EasyCODE ( 8
   Definicoes e inicializacoes referntes aos Displays */
/* EasyCODE < */

//===============================================================================
//
//        DEFINIÇiES DOS D-GITOS UTILIZADOS NA ROTINA DOS DISPLAYS DE 7 SEGMENTOS II
//                             Linhas de seleção separadas
//            (Cada linha de seleção corresponde a um bit da Porta)
//
//    Entradas : -
//    Saídas   : - ucFilaDeSaidaDosDisplays[]               - Vetor de saídas para os displays
//               - ucIndiceDisplayAtivo                     - ìndica o display que está ativo
//
//        Deve-se definir um port dedicado a isso, configurado da seguinte maneira:
//
//        PORT.Bit    - Segmento do Display
//
//            Px.0    - a
//            Px.1    - b
//            Px.2    - c
//            Px.3    - d
//            Px.4    - e
//            Px.5    - f
//            Px.6    - g
//            Px.7    - DP
//
//            Composição dos números decimais utilizando a especificação acima:
//
//                                                                    a
//                                                                --------
//                                                                |        |
//                                                              f |        | b
//                                                                |    g  |
//                                                                ---------
//                                                                |        |
//                                                             e |        | c
//                                                                |    d  |
//                                                                 -------
//
// SEGMENTOS:                                   g f e | d c b a    Código Hexadecimal
//-----------------------------------------
// Dígito:       apagado             0 0 0 | 0 0 0 0         = 0x00
//                              0               0 1 1 | 1 1 1 1         = 0x3f
//                              1               0 0 0 | 0 1 1 0         = 0x06
//                              2               1 0 1 | 1 0 1 1         = 0x5b
//                              3               1 0 0 | 1 1 1 1         = 0x4f
//                              4               1 1 0 | 0 1 1 0         = 0x66
//                              5               1 1 0 | 1 1 0 1         = 0x6d
//                              6               1 1 1 | 1 1 0 0         = 0x7c
//                              7               0 0 0 | 0 1 1 1         = 0x07
//                              8               1 1 1 | 1 1 1 1         = 0x7f
//                              9               1 1 0 | 0 1 1 1         = 0x67
//
//                              P               1 1 1 | 0 0 1 1         = 0x73
//                              r               1 0 1 | 0 0 0 0         = 0x50
//                              E               1 1 1 | 1 0 0 1         = 0x79
//                              F               1 1 1 | 0 0 0 1         = 0x71
//                              i               0 0 0 | 0 1 0 0         = 0x04
//
//=====                                        =====
 
//#define DISPLAY_INVERTIDO                               1
#define TEM_PONTO_DECIMAL                                1
 
#ifdef DISPLAY_INVERTIDO
    #ifdef TEM_PONTO_DECIMAL
        #define MASCARA_INV_DISPLAY                       0xff
        #define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
       #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
    #else
        #define MASCARA_INV_DISPLAY              0x7f
        #define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD   MASCARA_INV_DISPLAY
       #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD      0x00
    #endif
#else
    #define MASCARA_INV_DISPLAY                            0x00
 
    #ifdef TEM_PONTO_DECIMAL
        #define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
        #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0xff
    #else
        #define DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD    MASCARA_INV_DISPLAY
        #define LIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD       0x7f
    #endif
#endif
 
 
#define DISPLAY_7_SEG_APAGADO                 0x00 ^ MASCARA_INV_DISPLAY
 
#define DISPLAY_7_SEG_ZERO                    0x3f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_UM                      0x06 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_DOIS                    0x5b ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_TRES                    0x4f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_QUATRO                  0x66 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_CINCO                   0x6d ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SEIS                    0x7c ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_SETE                    0x07 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_OITO                    0x7f ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_NOVE                    0x67 ^ MASCARA_INV_DISPLAY
 
#define DISPLAY_7_SEG_PE                      0x73 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_ERRE                    0x50 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_E                       0x79 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_EFE                     0x71 ^ MASCARA_INV_DISPLAY
#define DISPLAY_7_SEG_I                       0x04 ^ MASCARA_INV_DISPLAY
 
#define NUMERO_DE_DISPLAYS                    0x03
 
#define FREQ_DE_INTERRUP_TIMER_DISPLAYS      90.0    // Hz
 
// ************* Precisa revisar essas linhas !!!!! *****
 
//#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 * NUMERO_DE_DISPLAYS)/ FREQ_DE_INTERRUP_TIMER_DISPLAYS)+ 0.5) // Original, mas acho que está errado
#define PRESET_TEMPORIZADOR_DOS_DISPLAYS  (unsigned int)(((FREQUENCIA_DE_INTERRUPCAO_TIMER_0 )/ (FREQ_DE_INTERRUP_TIMER_DISPLAYS * NUMERO_DE_DISPLAYS))+ 0.5)
 
//********************************************************

#define NUMERO_DE_LINHAS_DO_DISPLAY                 3         // Número de linhas de seleção
#define PORTA_DE_SAIDA_DOS_DISPLAYS                 P3        /https://embarcados.com.br/sistemas-operacionais-de-tempo-real-teclados-matriciais// Define o Port onde estão conectados os displays
#define PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS      P1        // Define o port onde estão conectadas as linhas de seleção
 
 
#ifdef TEM_PONTO_DECIMAL
    #define MASCARA_DOS_DISPLAYS                   0xff        // Filtra os bits de saída do port dos Displays    incluindo o do Ponto decimal
    #define FIM_DO_TESTE_DISPLAY                   0x08
#else
    #define MASCARA_DOS_DISPLAYS                   0x7f        // Filtra os bits de saída do port dos Displays, sem o ponto decimal
    #define FIM_DO_TESTE_DISPLAY                   0x07
#endif
 
#define LIGA_PONTO_DECIMAL                         0x80
#define MASCARA_DA_SELECAO_DE_DISPLAY              0xE0        // Filtra os bits dos sinais de seleção dos displays
 
// Bit de seleção a ser shiftado, para gerar o sinal de seleção ...  bit 1 (define a primeira linha a ser lida)
 
#define SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY      0x20        // Define posição do primeiro bit do conjunto de seleção
 
 
//#define SAIDAS_INVERTIDAS_SEL_DISP                 1         // Define se as saidas de selecao sao invertidas ou nao
 
#ifdef SAIDAS_INVERTIDAS_SEL_DISP
    #define MASCARA_DE_INVERSAO_SEL_DISP            MASCARA_DA_SELECAO_DE_DISPLAY
#else
    #define MASCARA_DE_INVERSAO_SEL_DISP            0x00
#endif
 
 
volatile int unTimerDosDisplays  = PRESET_TEMPORIZADOR_DOS_DISPLAYS;
unsigned char ucFilaDeSaidaDosDisplays[NUMERO_DE_DISPLAYS] = { DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD,
                                                               DESLIGA_TODOS_SEGMENTOS_DISP_7_SEG_E_PD};
 
unsigned char ucIndiceDisplayAtivo = 0;
unsigned char ucContadorDeSelecaoDisplay = 0;
 
//-------- Definição das variáveis globais ---------------
 
code unsigned char ucTabelaDeDisplayDeSeteSegmentos[10] = { DISPLAY_7_SEG_ZERO,
                                                            DISPLAY_7_SEG_UM,
                                                            DISPLAY_7_SEG_DOIS,
                                                            DISPLAY_7_SEG_TRES,
                                                            DISPLAY_7_SEG_QUATRO,
                                                            DISPLAY_7_SEG_CINCO,
                                                            DISPLAY_7_SEG_SEIS,
                                                            DISPLAY_7_SEG_SETE,
                                                            DISPLAY_7_SEG_OITO,
                                                            DISPLAY_7_SEG_NOVE};
/* EasyCODE > */
/* EasyCODE ) */
/* EasyCODE ( 2
   vInterrupcaoTimer0 */
/* EasyCODE F */
//----------------- Fim dos parâmetros e variáveis dos displays  do tipo II ---------

//*******************************************************************************
//                                                               TIMER 0        
//                                                      rotina de interrupção
//

void vInterrupcaoTimer0() interrupt 1
   {
   /* EasyCODE ( 9
      Verifica Temporizador virtual para demosntracao do Timer */
   nTimerDeSoftware--;                            // Decrementa o temporizador de software
   if (nTimerDeSoftware == 0)
      {
      bFlagTimerDeSoftware = LIGA;                 // Sinaliza que terminou a temporização de software
      nTimerDeSoftware = PRESET_TIMER_DE_SOFTWARE; // Reinicializa o temporizador
      }
   /* EasyCODE ) */
   /* EasyCODE ( 10
      Testa temporizador de software referente aos displays */
   //********************************************************************************
   //****** Trecho a ser inserido na rotina de interrupção do timer - DISPLAYS II ***
   //******                                                                       ***
   if (--unTimerDosDisplays == 0)
      {
      unsigned char ucAux;
       
      unTimerDosDisplays = PRESET_TEMPORIZADOR_DOS_DISPLAYS;       // Reinicializa temporizador
       
      ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS; // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
      ucAux |= DISPLAY_7_SEG_APAGADO;                              // Apaga o display
      PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;                         // Atualiza a saída
      if (ucIndiceDisplayAtivo == NUMERO_DE_DISPLAYS                // Testa se atualizou o último display
         )
         {
         ucIndiceDisplayAtivo = 0;                                    // Reinicializa o Indice do display
         ucContadorDeSelecaoDisplay = 0;                              // Reinicializa o contador de seleção
         }
      ucAux = ~MASCARA_DA_SELECAO_DE_DISPLAY;                     // Inverte os bits da mascara
      ucAux &= PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS;            // Filtra os bits de seleção
       
       
      ucAux |= ((SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY << ucIndiceDisplayAtivo) ^ MASCARA_DE_INVERSAO_SEL_DISP);
      PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS = ucAux;
       
      ucAux = PORTA_DE_SAIDA_DOS_DISPLAYS & ~MASCARA_DOS_DISPLAYS; // Lê o conteúdo do port, para salvar o bit do Ponto decinal, se for o caso
      ucAux |= ucFilaDeSaidaDosDisplays[ucIndiceDisplayAtivo++];   // Lê o valor a ser apresentado no display
      PORTA_DE_SAIDA_DOS_DISPLAYS = ucAux;                        // Atualiza a saída
      
      //************** Fim da Rotina Displays II ************************************
      }
   /* EasyCODE ) */
   /* EasyCODE ( 11
      Testa temporizador de siftware referente ao teclado matricial */
   
   
   //****** Trecho a ser inserido na rotina de interrupção do timer - Matriz de Contatos - Timer de software***
   if (--unTimerDaMatrizDeContatos == 0)
      {
      unTimerDaMatrizDeContatos = PRESET_TEMPORIZADOR_DA_MATRIZ_DE_CONTATOS; // Reinicializa temporizador
          bFlagDeTemporizacaoDaMatrizDeContatos = LIGA;                                              // Sinaliza que terminou a contagem
      /* EasyCODE - */
      //************** Fim da Rotina **************************************************
      }
   /* EasyCODE ) */
   }
/* EasyCODE ) */
/* EasyCODE ( 3
   main */
/* EasyCODE F */
//================================================================================
//
//                   PROGRAMA PRINCIPAL

void main(void)
   {
   /* EasyCODE ( 15
      Inicializacoes referentes aos Displays */
         int nContadorSemFuncao = 0;
         
         //********************* Inicializações *************
   
         //************************ TIMER 0      ********************************************
         // Inicializa os bits do timer 0
   
         TR0   = DESLIGA;
         TMOD &= MASCARA_CT_0;                                   // Seleciona função de "timer"
   
         T2CON = 0x00;
         TR2   = DESLIGA;
         T2MOD &= 0x0f;                                                  // Seleciona função de "timer"
   
   
         TH0       = PRESET_TIMER_0_MODO_2;                      // Inicializa o preset do contador
         TL0   = PRESET_TIMER_0_MODO_2;
   
         TMOD &= MASCARA_DO_MODO_DO_TIMER_0;             // Seta M1 e M0 para timer 0 - modo 2
         TMOD |= MODO_2_TIMER_0;
     
         //******
         
   //********************* Inicializa Displays para demostração ******
         
         ucFilaDeSaidaDosDisplays[0] = DISPLAY_7_SEG_UM;
         ucFilaDeSaidaDosDisplays[1] = DISPLAY_7_SEG_DOIS;
         ucFilaDeSaidaDosDisplays[2] = DISPLAY_7_SEG_TRES;
   /* EasyCODE : */
      {
      unsigned char ucAux1;
      
      ucAux1 = ~MASCARA_DA_SELECAO_DE_DISPLAY;                        // Inverte os bits da mascara
      ucAux1 &= PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS;               // Filtra os bits de seleção
      PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS = ucAux1;               // Inicializa bits de selecao
      }
         //******
   
   
         //********** Fim das Inicializações ******************
   

   /* EasyCODE ) */
   /* EasyCODE ( 16
      Inicializacao do TIMER 0 */
                
         //********************************************************************************
   //
   //                                               TIMER 0
   //
   // Este bloco deve ser colocado no programa principal, para iniciar a operação do timer
   
   
   TR0 = LIGA;                                                           // Liga o timer
   ET0 = LIGA;                                                           // Libera a interrupção do timer
   EA  = LIGA;                                                           // Habilita as interrupções
   
   //****
   /* EasyCODE ) */
   for (;;                               // Loop principal
       )
      {
      /* EasyCODE ( 17
         Trata a sinalizacao de termino de temporizacao do timer virtual */
      nContadorSemFuncao++;              // Soma um no contador. Essa instrução foi inserida aqui apenas para não dar a impressão que a simulação está parada
      if (bFlagTimerDeSoftware == LIGA    // Verifica se terminou a temporização por software (10 vezes a interrupção do Timer 0)
         )
         {
         P1_1 = ~P1_1;                                              // Inverte o bit 1 da porta 1 - ;
         bFlagTimerDeSoftware = DESLIGA;  // Desliga a sinalização de término
         }
      //********************************************************************************
      //****** Trecho a ser inserido no programa principal - Matriz de Contatos - II ***
      //******                                                                       ***
      /* EasyCODE ) */
      /* EasyCODE ( 18
         Trata teclado matricial */
      /* EasyCODE ( 19
         Rotina de nova leitura de teclado */
      if (bFlagDeTemporizacaoDaMatrizDeContatos == LIGA         // Testa se pode realizar a leitura da matriz
         )
         {
         unsigned char ucIndice;
                     bFlagDeTemporizacaoDaMatrizDeContatos = DESLIGA;       // Desliga o Flag
         PORTA_DE_ENTRADA_DA_MATRIZ |= MASCARA_DA_MATRIZ;       // Prepara a porta para leitura
         
         //*** Início da rotina para realizar a leitura da matriz de contatos ***
         for (ucIndice = 0; ucIndice < NUMERO_DE_LINHAS_DA_MATRIZ ; ucIndice++)
            {
            unsigned char ucAux;
            
            ucAux = ~MASCARA_DA_SELECAO;                           // Inverte os bits da mascara
            ucAux &= PORTA_DE_SAIDA_DA_SELECAO_DA_MATRIZ;          // Filtra os bits de seleção
            
            ucAux |= ((SELETOR_DOS_SINAIS_DE_SELECAO << ucIndice) ^ MASCARA_DE_INVERSAO);
            PORTA_DE_SAIDA_DA_SELECAO_DA_MATRIZ = ucAux;
            
            // Le a linha de contatos, e filtra, deixando só o que interessa
            
            ucMatrizDeContatosDeEntrada[ucIndice] = PORTA_DE_ENTRADA_DA_MATRIZ & MASCARA_DA_MATRIZ;
            }
         // Desliga as linhas de seleção
         
         ucIndice = ~MASCARA_DA_SELECAO;                          // Inverte os bits da mascara
         ucIndice &= PORTA_DE_SAIDA_DA_SELECAO_DA_MATRIZ;         // Filtra os bits de seleção
         PORTA_DE_SAIDA_DA_SELECAO_DA_MATRIZ = (ucIndice ^ MASCARA_DE_INVERSAO);
         
         // Inserir essa instrução apenas se necessitar de "debounce"
         
         bFlagDeNovaLeituraDeMatrizDeContatos = LIGA;            // Sinaliza que foi realizada nova leitura
         }
      //******** Término da rotina Matriz de Contatos - II ********

      /* EasyCODE ) */
      /* EasyCODE ( 20
         Rotina de debounce do teclado */
      
      //******************************************
      //******** Rotina de "Debounce " ********
      //*******                                        ********
      
                  // Testa se há leitura nova
      if (bFlagDeNovaLeituraDeMatrizDeContatos == LIGA)
         {
         bit bFlagOk = LIGA;
               unsigned char ucIndice;
               
                           // Reseta o flag de sinalização
         bFlagDeNovaLeituraDeMatrizDeContatos = DESLIGA;  // Sinaliza que foi realizada nova leitura
               
                           // Se o contador for diferente de zero, decrementa o contador
         if (ucContadorDeDebounce != 0)
            {
            ucContadorDeDebounce--;
            }
         for (ucIndice = 0; ucIndice < NUMERO_DE_LINHAS_DA_MATRIZ ; ucIndice++)
            {
            // Compara a matriz de entrada com a matriz anterior
            if (ucMatrizDeContatosDeEntrada[ucIndice] != ucMatrizDeContatosDeEntradaAnterior[ucIndice])
               {
               // Se diferentes, sinaliza
                           bFlagNovosDados = LIGA; 
               bFlagOk = DESLIGA;
               }
                              // Transfere a matriz para a área da matriz anterior
            ucMatrizDeContatosDeEntradaAnterior[ucIndice] = ucMatrizDeContatosDeEntrada[ucIndice];
            }
         // Testa se houve alteração das entradas
         if (bFlagOk == DESLIGA)
            {
            // Se houve alteração, reinicializa o contador
            ucContadorDeDebounce = PRESET_CONTADOR_DEBOUNCE;
            }
         // Testa se estabilizou as leituras
         if ((ucContadorDeDebounce == 0) && (bFlagNovosDados == LIGA))
            {
            // Sinaliza que estabilizou a leitura
            bFlagDeTerminoDeDebounce = LIGA;
            }
         //************* Término da rotina de debounce ***************

         }
      /* EasyCODE ) */
      /* EasyCODE ( 21
         Identifica as teclas acionadas */
                  
      //******************************************************************
      //************* Rotina que identifica os contatos acionados ****
      //*************                                                                          ****
      
                  // Verifica se terminou o "debounce"
      if (bFlagDeTerminoDeDebounce ==LIGA)
         {
         unsigned char ucIndice, ucContadorAux;
         bFlagDeTerminoDeDebounce = DESLIGA;
         bFlagNovosDados = DESLIGA;
         
                           // Inicializa o contador de contatos
         ucContadorDeContatosFechados = 0;  // Inicializa contador de contatos fechados
         ucContadorAux = 0;                         // Inicializa o contador Auxiliar, que indicará o índice do contato
         for (ucIndice = 0; ucIndice < NUMERO_DE_LINHAS_DA_MATRIZ ; ucIndice++)
            {
                  unsigned char ucContatoAux;
                  
                                    // Verifica se nesssa linha há contatos fechados
            ucContatoAux = (ucMatrizDeContatosDeEntrada[ucIndice] ^ ucMatrizDeContatosDeReferencia[ucIndice]);
            if (ucContatoAux != 0)
               {
               unsigned char ucAux, ucRegistroDeDeslocamento;
                     ucRegistroDeDeslocamento = MASCARA_DE_SELECAO_DE_COLUNA_INICIAL;
               for (ucAux = 0; ucAux < NUMERO_DE_COLUNAS_DA_MATRIZ; ucAux++)
                  {
                  if ((ucRegistroDeDeslocamento & ucContatoAux) != 0)
                     {
                     ucVetorDeResultados[ucContadorDeContatosFechados++] = ucContadorAux;  // Transfere a posição do contato
                     bFlagResultadosMatrizDeContatos = LIGA;                                          // Sinaliza que encontrou contatos acionados
                     }
                  ucRegistroDeDeslocamento = ucRegistroDeDeslocamento << 1;                  // Desloca a máscara de um
                  ucContadorAux++;                                                                       // Incrementa o contador
                  }
               }
            }
         }
      //************** Fim da rotina e identificação dos contatos acionados ***
      

      /* EasyCODE ) */
      /* EasyCODE ( 22
         Desvia para a rotina de tratamento */
      //**********************************************************************************
      //************** Inicio da rotina de execução de ações em função dos contatos ******
      //**************                                                                                                                       ******
      
            // Testa se há contatos acionados
      if (bFlagResultadosMatrizDeContatos == LIGA)
         {
         unsigned char ucIndice;
         
               // Verifica todos os contatos localizados
         for (ucIndice = 0; ucIndice < ucContadorDeContatosFechados; ucIndice++)
            {
            // Aqui verifica qual é o contato acionado e realiza alguma ação dependendo de qual for...
            switch (ucVetorDeResultados[ucIndice])
               {
               case 0:
                  /* EasyCODE : */
                     {
                     break;
                     }
               case 1:
                  /* EasyCODE : */
                     {
                     break;
                     }
               default:
                  /* EasyCODE : */
                     {
                     }
               }
            }
         }
      /* EasyCODE ) */
      /* EasyCODE ) */
      }
   }
/* EasyCODE ) */
/* EasyCODE ) */

Ficou enorme, não? Já pensou o trabalho que vai dar, se for necessário realizar alterações ou manutenção nesse programa? E se esse programa tivesse mais de 9.000 linhas, como um que desenvolvi para outro projeto?  Dá para notar a dificuldade claramente. Agora veja a Figura 3, onde podemos observar o mesmo programa organizado no EASYCODE.

Principal
Figura 3: Programa exemplo organizado no EASYCODE

A diferença é gritante!!! Pode-se observar claramente as diversas partes do programa, agora organizado em blocos. Esses diagramas têm estrutura hierárquica, que nos permite avançar para o interior do bloco, apenas “clickando” em cima dele. Veja no Figura 4 os detalhes da rotina de interrupção do Timer 0.

Interrupcao
Figura 4: Detalhes do bloco do Timer 0

Na Figura 5, descendo mais um estágio dentro dessa rotina, podemos ver o detalhamento do bloco referente aos displays de 7 segmentos.

Interrupcao_1
Figura 5: Trecho de código ref. aos displays de 7 segmentos inserido na interrupção do Timer 0

Para finalizar, veja na Figura 6 o detalhe do programa principal.

Main
Figura 6: Detalhes do bloco do programa principal

O software EASYCODE também permite copiar, arrastar, mover e deletar um bloco inteiro, se você quiser. Pode-se fazer engenharia reversa de algum código, especialmente naqueles mais antigos, em que você não se lembra mais o que foi feito. Recomendo que você baixe o programa de avaliação e dê uma “voltinha” nele. Você vai ficar com água na boca.

Resumo

Neste artigo técnico foi apresentada uma ferramenta comercial para desenvolvimento de software e mostradas algumas características e vantagens de se utilizá-la.

Referências

https://www.easycode.de/en/home.html

Técnicas: Top-Down, Mocks e TDD

Sistemas Operacionais de Tempo Real – Teclados Matriciais

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
0 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Home » Hardware » Ferramentas de Desenvolvimento » EASYCODE: Uma ferramenta de produtividade

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: