RuiViana

Frequence_Meter_0.0.22.ino

Jul 9th, 2020
1,203
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.   ESP32 Frequence_Meter_0.0.21
  3.   Desenvolvedores: Rui Viana e Gustavo Murta   08/jul/2020
  4.  
  5.   Para desenvolver este projeto, foram aproveitadas partes de códigos dos seguintes desenvolvedores.
  6.  
  7.   author=krzychb https://github.com/espressif/esp-idf/tree/master/examples/peripherals/pcnt
  8.   resposta by Deouss » Thu May 17, 2018 3:07 pm no tópico https://esp32.com/viewtopic.php?t=5734
  9.   Gerador de sinais Gustavo https://github.com/Gustavomurta/ESP32_frequenceMeter/blob/master/ESP32OscilatorV03.ino
  10.  
  11.   O Projeto:
  12.   Um frequencímetro usando ESP32, sem necessidade de escalas e mostrando até 7 dígitos,
  13.   atingindo com precisão até 20MHz ou mais.
  14.  
  15.   Definições:
  16.   PORT de entrada do frequencímetro PCNT_INPUT_SIG_IO (GPIO 34)
  17.   PORT de entrada de controle PCNT_INPUT_CTRL_IO (GPIO 35)
  18.   PORT de saída do timer OUTPUT_CONTROL_GPIO (GPIO 32)
  19.   O PORT de entrada de controle (GPIO 35) deve ser ligado ao PORT de saída do timer (GPIO 32).
  20.   Estes são os ports usados no projeto, mas podem ser modificados para sua melhor conveniência.
  21.  
  22.   O frequencímetro é dividido em 5 partes:
  23.     1. Contador de pulsos;
  24.     2. Controle de tempo de contagem;
  25.     3. Impressão do resultado;
  26.     4. Espaço para outras funções.
  27.     5. Gerador de sinais programado para 10 KHz
  28.  
  29.   1. O contador de pulso usa o pcnt do ESP32.
  30.     O pcnt tem os seguintes parâmetros:
  31.       a. port de entrada;
  32.       b. canal de entrada;
  33.       c. port de controle;
  34.       d. contagem na subida do pulso;
  35.       e. contagem na descida do pulso;
  36.       f. contagem só com o controle em nível elevado;
  37.       g. limite máximo de contagem.
  38.  
  39.   2. O Controle de tempo de contagem usa o esp-timer.
  40.     O esp-timer tem o seguinte parâmetro:
  41.       a. controle do tempo;
  42.  
  43.   Funcionamento:
  44.     O port de controle de contagem em nível alto, libera o contador para contar os pulsos que chegam no port de entrada de pulsos.
  45.   Os pulsos são contado tanto na subida quanto na descida do pulso, para melhorar a media de contagem.
  46.   O tempo de contagem é definido pelo esp-timer, e esta' definido em 1 segundo, na variável janela.
  47.   Se a contagem for maior que 20000 pulsos durante o tempo de contagem, ocorra overflow e a cada overflow que ocorre
  48.   e' contabilizado na variável multPulses, e o contador de pulso retorna a zero continuando a contar.
  49.     Quando o port de controle contagem for para o nível baixo, ocorre um interrupt.
  50.   Neste interrupt o valor do no contador de pulsos e' lido e salvo, um flag e' ligado um flag indicando que terminou
  51.   a leitura dos pulsos.
  52.     No loop, ao verificar que 0 flag indica que terminou a leitura dos pulsos, o valor é calculado multiplicando
  53.   o numero de overflow por 20000 e somando ao numero de pulsos restantes e dividindo por 2, pois contou 2 vezes.
  54.   Como o pulsos são contados na subida e na descida, a contagem e´ o dobro da frequência.
  55.     A frequência é impressa no serial monitor.
  56.   Os registradores são resetados e o port de controle de entrada é novamente elevado para nível alto e a contagem de
  57.   pulsos se inicia.
  58.  
  59.   Tem também um gerador de sinais que gera 10 KHz, e pode ser usado para testes.
  60.   Este gerador pode ser alterado para gerar frequencias até 40 MHz.
  61.   O Port de saida dest gerador é definido na linha #define LEDC_GPIO.
  62.   Atualmente está definido como GPIO 25.
  63.  
  64.   Para o uso da Serial e de um LCD, existem 2 definições que pode ser usadas juntas ou bloqueadas.
  65.   Este uso e bolqueio pode ser comitantemente ou individualmente.
  66.            
  67.   Referências:
  68.   https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_timer.html
  69.   https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html
  70.  
  71. */
  72.  
  73. #define LCD_ON                                                          // Se tem LCD defina LCD_ON, se não tem LCD, defina LCD_OFF
  74. #define Ser_ON                                                          // Se quer imprimir resultados na serial defina Ser_ON, se não, defina  Ser_OFF
  75. unsigned long overflow = 20000;                                           // Valor maximo para overun de pcnt
  76. #include "driver/pcnt.h"                                                  // Pulse count library
  77.  
  78. #ifdef LCD_ON                                                             // Se tem LCD
  79. #include <LiquidCrystal.h>                                                // Inclue a bibliotea do LCD
  80. LiquidCrystal lcd(5, 18, 19, 21, 22, 23);                                 // Instancia e define port
  81. #endif
  82.  
  83. #define PCNT_COUNT_UNIT       PCNT_UNIT_0                                 // Unidade de pcnt
  84. #define PCNT_COUNT_CHANNEL    PCNT_CHANNEL_0                              // Canal pcnt
  85. #define PCNT_INPUT_SIG_GPIO   34                                          // Pulse Input GPIO
  86. #define PCNT_INPUT_CTRL_GPIO  35                                          // Control GPIO HIGH=count up, LOW=count down
  87. #define OUTPUT_CONTROL_GPIO   GPIO_NUM_32                                 // Saida de controle
  88. #define LEDC_GPIO             25                                          // Saida da frequencia gerada pelo LEDc
  89.  
  90. #define PCNT_H_LIM_VAL        overflow                                    // Limite superior de contagem
  91.  
  92. esp_timer_create_args_t create_args;                                      // Argumentos do timer
  93. esp_timer_handle_t timer_handle;                                          // Instancia de timer
  94.  
  95. bool flag = true;                                                         // Indicador de fim de contagem libera impressao
  96. int16_t pulses = 0;                                                       // Contador de pulsos de entrada
  97. unsigned long multPulses = 0;                                             // Contador de overflows de pcnt
  98. unsigned long  janela = 1000000;                                          // Janela de contagem de pulsos
  99. uint32_t dig[8];
  100.  
  101. portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
  102.  
  103. // Parametro do ledc
  104. long  freque = 10000;                                                     // Frequencia em Hz
  105. long  canal = 1;                                                          // Canal gerador de sinal
  106. long  resolBits = 1;                                                      // Bits de resolucao
  107. float dutyCycle = 1;                                                      // Valor divisor de Duty Cycle
  108. //----------------------------------------------------------------------------
  109. void freqAdjust ()
  110. {
  111.   pinMode(LEDC_GPIO, OUTPUT);                                             // GPIO_ as Output
  112.   ledcAttachPin(LEDC_GPIO, canal);                                        // GPIO_ attached to PWM Channel
  113.   ledcSetup(canal, freque, resolBits);                                    // Channel  , freq  ,  bit resolution
  114.   ledcWrite(canal, dutyCycle);                                            // Enable frequency with dutty cycle
  115. }
  116. //----------------------------------------------------------------------------------
  117. void tempo_controle(void *p)                                              // Fim de tempo de leitura de puslos
  118. {
  119.   gpio_set_level(OUTPUT_CONTROL_GPIO, 0);                                 // Desliga o controle do pcnt
  120. }
  121. //----------------------------------------------------------------------------------
  122. static void IRAM_ATTR pcnt_intr_handler(void *arg)                        // Overflow de contagem de pulsos
  123. {
  124.   PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT);                                // Limpa indicador de interrupt
  125.   portENTER_CRITICAL_ISR(&timerMux);                                      // Bloqueia novo interrupt
  126.   multPulses++;                                                           // Incrementa contador de overflow
  127.   portEXIT_CRITICAL_ISR(&timerMux);                                       // Libera novo interrupt
  128. }
  129. //----------------------------------------------------------------------------------
  130. void IRAM_ATTR detectsCount()                                             // Interrupt de fim de tempo contagem
  131. {
  132.   pcnt_get_counter_value(PCNT_COUNT_UNIT, &pulses);                       // Obtem o valor contado
  133.   flag = true;                                                            // Informa que ocorreu interrupt de controle
  134. }
  135. //----------------------------------------------------------------------------------
  136. void pcnt_init(void)                                                      // Rotina de inicializacao do pulse count
  137. {
  138.   pcnt_config_t pcnt_config = { };                                        // Instancia pulse config
  139.   pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_GPIO;                       // Port de entrada dos pulsos
  140.   pcnt_config.ctrl_gpio_num = PCNT_INPUT_CTRL_GPIO;                       // Controle da contagem
  141.   pcnt_config.unit = PCNT_COUNT_UNIT;                                     // Unidade de contagem
  142.   pcnt_config.channel = PCNT_COUNT_CHANNEL;                               // Canal de contagem
  143.   pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;                             // Limite maximo de contagem
  144.   pcnt_config.pos_mode = PCNT_COUNT_INC;                                  // Conta na subida do pulso
  145.   pcnt_config.neg_mode = PCNT_COUNT_INC;                                  // Conta na descida do pulso
  146.   pcnt_config.lctrl_mode = PCNT_MODE_DISABLE;                             // Nao usado
  147.   pcnt_config.hctrl_mode = PCNT_MODE_KEEP;                                // Se HIGH conta incrementando
  148.   pcnt_unit_config(&pcnt_config);                                         // Inicializa PCNT
  149.  
  150.   pcnt_counter_pause(PCNT_COUNT_UNIT);                                    // Inicializa o contador PCNT
  151.   pcnt_counter_clear(PCNT_COUNT_UNIT);                                    // Zera o contador PCNT
  152.   pcnt_counter_resume(PCNT_COUNT_UNIT);                                   // inicia a contagem
  153.  
  154.   pcnt_event_enable(PCNT_COUNT_UNIT, PCNT_EVT_H_LIM);                     // Limite superior de contagem
  155.   pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL);                    // Rotina de Interrupt de pcnt
  156.   pcnt_intr_enable(PCNT_COUNT_UNIT);                                      // Habilita interrup de pcnt
  157. }
  158. //---------------------------------------------------------------------------------
  159. void inserePt(uint32_t frequencia)                                        // Separação da frequencia em digitos
  160. {
  161.   uint32_t cTemp;                                                         // Temporaria para calculo
  162.   cTemp = (uint32_t)(frequencia / 2);                                     // Obtem o valor da frequencia
  163.   for (int i = 0 ; i < 8; i++)                                            // Separa 8 digitos
  164.   {
  165.     dig[i] = (cTemp % 10);                                                // Salva digito separado na mattriz
  166.     cTemp /= 10;                                                          // Divide por 10 para separar o proximo digito
  167.   }
  168. }
  169. //---------------------------------------------------------------------------------
  170. void rotinaSerial()                                                       // Imprime na serial com ponto milhar
  171. {
  172. #ifdef Ser_ON                                                             // Se está definido para imprimir na serial
  173.   bool nTemp = false;                                                     // Temporario para limpeza de zeros a esquerda
  174.   for (int i = 7 ; i > -1 ; i--)                                          // Identifica o digito
  175.   {
  176.     if (nTemp == false)                                                   // Se não encontrou digito significativo ainda
  177.     {
  178.       if (dig[i] == 0)                                                    // Testa se o digito é zero
  179.       {
  180.         Serial.print  ("" );                                              // Se for Print nullo
  181.       }
  182.       else                                                                // Se não for
  183.       {
  184.         Serial.print  (dig[i]);                                           // Print o digito
  185.         nTemp = true;                                                     // Informa que tem numero significativo
  186.       }
  187.     }
  188.     else                                                                  // Se tem numero significativo
  189.     {
  190.       Serial.print  (dig[i] );                                            // Imprime o digito
  191.       if (i == 6)                                                         // Se for a 6a posição
  192.       {
  193.         Serial.print  (".");                                              // Print imprime ponto
  194.       }
  195.       if (i == 3)                                                         // Se for a 3a posição
  196.       {
  197.         Serial.print  (".");                                              // Imprime ponto
  198.       }
  199.     }
  200.   }
  201.   Serial.println  (" Hz" );                                               // Print
  202. #endif
  203. }
  204. //---------------------------------------------------------------------------------
  205. void rotinaLCD()                                                          // Imprime LCD com ponto milhar
  206. {
  207. #ifdef LCD_ON                                                             // Se está definido para imprimir no LCD
  208.   bool nTemp = false;                                                     // Temporario para limpeza de zeros a esquerda
  209.   lcd.setCursor(2, 1);                                                    //´Vai para posicao 3 Linha 1
  210.   for (int i = 7 ; i > -1 ; i--)                                          // Identifica o digito
  211.   {
  212.     if (nTemp == false)                                                   // Se não encontrou digito significativo ainda
  213.     {
  214.       if (dig[i] == 0)                                                    // Testa se o digito é zero
  215.       {
  216.         lcd.print("");                                                    // Se for Print nullo
  217.       }
  218.       else                                                                // Se não for
  219.       {
  220.         lcd.print(dig[i]);                                                // Print o digito
  221.         nTemp = true;                                                     // Informa que tem numero significativo
  222.       }
  223.     }
  224.     else                                                                  // Se tem numero significativo
  225.     {
  226.       lcd.print(dig[i]);                                                  // Imprime o digito
  227.       if (i == 6)                                                         // Se for a 6a posição
  228.       {
  229.         lcd.print(".");                                                   // Print imprime ponto
  230.       }
  231.       if (i == 3)                                                         // Se for a 3a posição
  232.       {
  233.         lcd.print(".");                                                   // Imprime ponto
  234.       }
  235.     }
  236.   }
  237.   lcd.print(" Hz         ");                                              // Print
  238. #endif
  239. }
  240. //----------------------------------------------------------------------------------
  241. void setup()
  242. {
  243.   Serial.begin(115200);                                                   // Inicializa serial
  244. #ifdef LCD_ON                                                             // Se tem LCD
  245.   lcd.begin(16, 2);                                                       // Inicializa lcd
  246.   lcd.print("Frequencimetro");                                            // Print
  247. #endif
  248.   freqAdjust();
  249.   pcnt_init();                                                            // Inicializa o pulse count
  250.   gpio_pad_select_gpio(OUTPUT_CONTROL_GPIO);                              // Define o port decontrole
  251.   gpio_set_direction(OUTPUT_CONTROL_GPIO, GPIO_MODE_OUTPUT);              // Define como saida
  252.  
  253.   create_args.callback = tempo_controle;                                  // Instancia o tempo de controel
  254.   esp_timer_create(&create_args, &timer_handle);                          // Cria parametros do timer
  255.  
  256.   attachInterrupt(digitalPinToInterrupt(PCNT_INPUT_CTRL_GPIO), detectsCount, FALLING);  // Habilita interrupt de fim de contagem
  257. }
  258. //---------------------------------------------------------------------------------
  259. void loop()
  260. {
  261.   if (flag == true)                                                       // Se impressa estiver liberada
  262.   {
  263.     flag = false;                                                         // Impede nova impresao
  264.     float frequencia = 0;                                                 // Variavel para calculo de frequencia
  265.     frequencia = (pulses + (multPulses * overflow))  ;                    // Calcula qtos pulsos ocorram
  266.     inserePt((uint32_t) frequencia);
  267.     rotinaSerial();
  268.     rotinaLCD();
  269.     multPulses = 0;                                                       // Zera contador de overflow
  270. //    ajuste_ledc();
  271.     // Aqui pode rodar qq funcao                                          // Espaco para qualquer função
  272.     delay(50);                                                            // Espaco para qualquer função
  273.     // Aqui pode rodar qq funcao                                          // Espaco para qualquer função
  274.  
  275.     pcnt_counter_clear(PCNT_COUNT_UNIT);                                  // Zera o contador PCNT
  276.     esp_timer_start_once(timer_handle, janela);                           // Disparo unico de tempo de finido na variavel Janela
  277.     gpio_set_level(OUTPUT_CONTROL_GPIO, 1);                               // Libera port de contagem
  278.   }
  279. }
RAW Paste Data