RuiViana

Arduino_FreqMeter_0.38.0.ino

Jul 21st, 2020
1,217
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //Arduino_FreqMeter_0.38.0.ino
  2.  
  3. #define LCD_OFF                                                           // Define LCD_ON, para usar LCD, se não, defina LCD_OFF
  4. #define LCD_I2C_ON                                                        // Define LCD_I2C_ON, para usar LCD I2C, se não, defina LCD_I2C_OFF
  5.  
  6. #include <stdio.h>                                                        // Bibliotecas ESP32
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/portmacro.h"
  9. #include "freertos/task.h"
  10. #include "freertos/queue.h"
  11. #include "driver/periph_ctrl.h"
  12. #include "driver/ledc.h"
  13. #include "driver/gpio.h"
  14. #include "driver/pcnt.h"
  15. #include "driver/ledc.h"
  16. #include "esp_attr.h"
  17. #include "esp_log.h"
  18. #include "esp_timer.h"
  19. #include "sdkconfig.h"
  20. #include "math.h"
  21.  
  22. #ifdef LCD_I2C_ON                                                         // Se tem LCD I2C
  23.  
  24. #define I2C_SDA 16                                                        // LCD I2C GPIO SDA
  25. #define I2C_SCL 17                                                        // LCD I2C GPIO SCL
  26. #include <Wire.h>                                                         // Biblioteca para I2C
  27. #include <LiquidCrystal_PCF8574.h>                                        // Biblioteca para PCF8574
  28. LiquidCrystal_PCF8574 lcd(0x39);                                          // Instacia LCD i2c com endereco
  29.  
  30. #endif                                                                    // LCD I2C
  31.  
  32. #ifdef LCD_ON                                                             // Se tem LCD
  33.  
  34. #include <LiquidCrystal.h>                                                // Inclue a bibliotea do LCD
  35. LiquidCrystal lcd(5, 18, 19, 21, 22, 23);                                 // Instancia e define port
  36.  
  37. #endif                                                                    // LCD
  38.  
  39. #define PCNT_COUNT_UNIT       PCNT_UNIT_0                                 // Unidade 0 do pcnt
  40. #define PCNT_COUNT_CHANNEL    PCNT_CHANNEL_0                              // Canal 0 do pcnt
  41.  
  42. //                 Para usar teste jumper GPIO 25 com GPIO 34
  43. //                 Port de entrada do frequencimetro  GPIO 34
  44. #define PCNT_INPUT_SIG_IO     GPIO_NUM_34                                 // Freq Meter Input GPIO 34
  45. #define LEDC_HS_CH0_GPIO      GPIO_NUM_25                                 // Saida do ledc gerador de pulsos
  46.  
  47. //                  Necessario jumper entre GPIO 32 e GPIO 35
  48. #define PCNT_INPUT_CTRL_IO    GPIO_NUM_35                                 // Count Control GPIO HIGH = count up, LOW = count down
  49. #define OUTPUT_CONTROL_GPIO   GPIO_NUM_32                                 // Saida do timer GPIO 32 Controla a contagem
  50.  
  51. #define IN_BOARD_LED          (gpio_num_t)2                               // LED nativo ESP32 GPIO 2
  52.  
  53. #define LEDC_HS_CH0_CHANNEL   LEDC_CHANNEL_0                              // LEDC no canal 0
  54. #define LEDC_HS_MODE          LEDC_HIGH_SPEED_MODE                        // LEDC em high speed
  55. #define LEDC_HS_TIMER         LEDC_TIMER_0                                // Usar timer0 do ledc
  56.  
  57. uint32_t         overflow  =  20000;                                      // Valor maximo para overflow de pcnt
  58. #define PCNT_H_LIM_VAL        overflow                                    // Limite superior de contagem
  59.  
  60. esp_timer_create_args_t create_args;                                      // Argumentos do esp-timer
  61. esp_timer_handle_t timer_handle;                                          // Instancia de esp-timer
  62.  
  63. //  Calculo do ajustes para cada faixa de frequencia
  64. //  Resolucao = log2(Clock(80MHz)/f) + 1   ex: 50.000 HZ = 80.0000/50.000 = 1.600 log2(1600) = 10 + 1 = 11
  65. //  Duty 50%  = (2**Resolucao)/2       ex: 2**11 = 2048   2048/2 = 1024
  66.  
  67. bool            flag          = true;                                     // Indicador de fim de contagem libera impressao
  68. int16_t         pulses        = 0;                                        // Contador de pulsos de entrada
  69. uint32_t        multPulses    = 0;                                        // Contador de overflows de pcnt
  70. uint32_t        janela        = 1000000;                                  // Janela de 1 segundo para a contagem de pulsos
  71. uint32_t        oscilator     = 2;                                        // Frequencia em Hz
  72. uint32_t        mDuty         = 0;                                        // Valor calculado do duty
  73. uint32_t        resolucao         = 0;                                    // Valor calculado da resolucao
  74.  
  75. portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;                     // variavel tipo portMUX_TYPE para sincronismo
  76.  
  77. //----------------------------------------------------------------------------------------
  78. // Sem comentarios originais  https://arduino.stackexchange.com/questions/28603/the-most-effective-way-to-format-numbers-on-arduino
  79. char *ultos_recursive(unsigned long val, char *s, unsigned radix, int pos)
  80. {
  81.   int c;
  82.   if (val >= radix)
  83.     s = ultos_recursive(val / radix, s, radix, pos + 1);
  84.   c = val % radix;
  85.   c += (c < 10 ? '0' : 'a' - 10);
  86.   *s++ = c;
  87.   if (pos % 3 == 0) *s++ = '.';
  88.   return s;
  89. }
  90. //----------------------------------------------------------------------------------------
  91. // Sem comentarios originais  https://arduino.stackexchange.com/questions/28603/the-most-effective-way-to-format-numbers-on-arduino
  92. char *ltos(long val, char *s, int radix)
  93. {
  94.   if (radix < 2 || radix > 36) {
  95.     s[0] = 0;
  96.   } else {
  97.     char *p = s;
  98.     if (radix == 10 && val < 0) {
  99.       val = -val;
  100.       *p++ = '-';
  101.     }
  102.     p = ultos_recursive(val, p, radix, 0) - 1;
  103.     *p = 0;
  104.   }
  105.   return s;
  106. }
  107. //----------------------------------------------------------------------------
  108. void ledcInit ()
  109. {
  110.   resolucao = log((80000000 / oscilator) + 1) / log(2);                   // Calculo da resolucao para ledc
  111.   if (resolucao > 15) resolucao = 15;                                     // Maxima resolucao 15
  112.   //  Serial.println(resolucao);                                          // Print
  113.   mDuty = (pow(2, resolucao)) / 2;                                        // Calculo do duty para ledc
  114.   //  Serial.println(mDuty);                                              // Print
  115.  
  116.   ledc_timer_config_t ledc_timer = {};                                    // Instancia a configuracao do timer do ledc
  117.  
  118.   ledc_timer.duty_resolution =  ledc_timer_bit_t(resolucao);              // Configura resolucao
  119.   //ledc_timer.duty_resolution = (ledc_timer_bit_t) + resolucao;          // Configura resolucao
  120.   ledc_timer.freq_hz    = oscilator;                                      // Frequencia de oscilacao
  121.   ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;                           // Mode de operacao em high speed
  122.   ledc_timer.timer_num = LEDC_TIMER_0;                                    // Usar timer0 do ledc
  123.   ledc_timer_config(&ledc_timer);                                         // Configurar o timer do ledc
  124.  
  125.   ledc_channel_config_t ledc_channel = {};                                // Instancia a configuracao canal do ledc
  126.  
  127.   ledc_channel.channel    = LEDC_HS_CH0_CHANNEL;                          // Configura canal0
  128.   ledc_channel.duty       = mDuty;                                        // Valor calculado do duty em %
  129.   ledc_channel.gpio_num   = LEDC_HS_CH0_GPIO;                             // Saida no GPIO defino no inicio
  130.   ledc_channel.intr_type  = LEDC_INTR_DISABLE;                            // Desabilita interrupt de ledc
  131.   ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;                         // Mode de operacao do canal em high speed
  132.   ledc_channel.timer_sel  = LEDC_TIMER_0;                                 // Usar timer0 do ledc
  133.  
  134.   ledc_channel_config(&ledc_channel);                                     // Configurar o canal do ledc
  135. }
  136. //----------------------------------------------------------------------------------
  137. void tempo_controle(void *p)                                              // Fim de tempo de leitura de pulsos
  138. {
  139.   gpio_set_level(OUTPUT_CONTROL_GPIO, 0);                                 // Controle do PCount - stop count
  140.   pcnt_get_counter_value(PCNT_COUNT_UNIT, &pulses);                       // Obtem o valor contado
  141.   flag = true;                                                            // Informa que ocorreu interrupt de controle
  142. }
  143. //----------------------------------------------------------------------------------
  144. static void IRAM_ATTR pcnt_intr_handler(void *arg)                        // Overflow de contagem de pulsos
  145. {
  146.   portENTER_CRITICAL_ISR(&timerMux);                                      // Desabilita interrupção ?
  147.   multPulses++;                                                           // Incrementa contador de overflow
  148.   PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT);                                // Limpa indicador de interrupt
  149.   portEXIT_CRITICAL_ISR(&timerMux);                                       // Libera novo interrupt
  150. }
  151. //----------------------------------------------------------------------------------
  152. void pcnt_init(void)                                                      // Rotina de inicializacao do pulse count
  153. {
  154.   pcnt_config_t pcnt_config = { };                                        // Instancia pulse config
  155.  
  156.   pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_IO;                         // Port de entrada dos pulsos
  157.   pcnt_config.ctrl_gpio_num = PCNT_INPUT_CTRL_IO;                         // Controle da contagem
  158.   pcnt_config.unit = PCNT_COUNT_UNIT;                                     // Unidade de contagem
  159.   pcnt_config.channel = PCNT_COUNT_CHANNEL;                               // Canal de contagem
  160.   pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;                             // Limite maximo de contagem
  161.   pcnt_config.pos_mode = PCNT_COUNT_INC;                                  // Conta na subida do pulso
  162.   pcnt_config.neg_mode = PCNT_COUNT_INC;                                  // Conta na descida do pulso
  163.   pcnt_config.lctrl_mode = PCNT_MODE_DISABLE;                             // Nao usado
  164.   pcnt_config.hctrl_mode = PCNT_MODE_KEEP;                                // Se HIGH conta incrementando
  165.   pcnt_unit_config(&pcnt_config);                                         // Inicializa PCNT
  166.  
  167.   pcnt_counter_pause(PCNT_COUNT_UNIT);                                    // Inicializa o contador PCNT
  168.   pcnt_counter_clear(PCNT_COUNT_UNIT);                                    // Zera o contador PCNT
  169.  
  170.   pcnt_event_enable(PCNT_COUNT_UNIT, PCNT_EVT_H_LIM);                     // Limite superior de contagem
  171.   pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL);                    // Rotina de Interrupt de pcnt
  172.   pcnt_intr_enable(PCNT_COUNT_UNIT);                                      // Habilita interrup de pcnt
  173.  
  174.   pcnt_counter_resume(PCNT_COUNT_UNIT);                                   // inicia a contagem
  175. }
  176. //----------------------------------------------------------------------------------
  177. void myInit()
  178. {
  179. #ifdef LCD_I2C_ON                                                         // Se tem LCD I2C
  180.  
  181.   Wire.begin(I2C_SDA, I2C_SCL);                                           // GPIOs de SDA e SCL
  182.  
  183. #endif
  184.  
  185. #if defined LCD_ON || defined LCD_I2C_ON                                  // LCD                                                
  186.  
  187.   lcd.begin(16, 2);                                                       // Inicializa lcd
  188.   lcd.print("  Frequencia:");                                             // Print
  189.  
  190. #endif                                                                    // LCD I2C
  191.  
  192.   ledcInit();                                                             // Inicializa o ledc
  193.   pcnt_init();                                                            // Inicializa o pulse count
  194.   gpio_pad_select_gpio(OUTPUT_CONTROL_GPIO);                              // Define o port decontrole
  195.   gpio_set_direction(OUTPUT_CONTROL_GPIO, GPIO_MODE_OUTPUT);              // Define o port de controle como saida
  196.  
  197.   create_args.callback = tempo_controle;                                  // Instancia o tempo de controle
  198.   esp_timer_create(&create_args, &timer_handle);                          // Cria parametros do timer
  199.  
  200.   gpio_set_direction(IN_BOARD_LED, GPIO_MODE_OUTPUT);                     // Port LED como saida
  201.  
  202.   gpio_matrix_in(PCNT_INPUT_SIG_IO, SIG_IN_FUNC226_IDX, false);           // Direciona a entrada de pulsos
  203.   gpio_matrix_out(IN_BOARD_LED, SIG_IN_FUNC226_IDX, false, false);        // Para o LED do ESP32
  204. }
  205. //---------------------------------------------------------------------------------
  206. void app_main(void)
  207. {
  208. #ifndef ARDUINO                                                           // IDF
  209.  
  210.   myInit();                                                               // IDF
  211.   while (1)                                                               // IDF
  212.   {
  213.  
  214. #endif                                                                    // IDF
  215.  
  216.     if (flag == true)                                                     // Se a contagem tiver terminado
  217.     {
  218.       flag = false;                                                       // Impede nova impresao
  219.       float frequencia = 0;                                               // Variavel para calculo de frequencia
  220.       frequencia = (pulses + (multPulses * overflow)) / 2  ;              // Calcula qtos pulsos ocorreram
  221.       char buf[32];                                                       // Buffer para guardar a pontuacao
  222.       printf("Frequencia: %s", (ltos(frequencia, buf, 10)));              // Imprime pontuado
  223.       printf(" Hz \n");                                                   // Sufixo
  224.  
  225. #if defined LCD_ON || defined LCD_I2C_ON                                  // LCD
  226.  
  227.       lcd.setCursor(2, 1);                                                // Posiciona cusros na posicao 3 da linha 2
  228.       lcd.print((ltos(frequencia, buf, 10)));                             // Print
  229.       lcd.print(" Hz              ");                                     // Sufixo
  230.  
  231. #endif
  232.  
  233.       multPulses = 0;                                                     // Zera contador de overflow
  234.       // Aqui pode rodar qq funcao                                        // Espaco para qualquer função
  235.       vTaskDelay(100);                                                    // Delay qq
  236.       // Aqui pode rodar qq funcao                                        // Espaco para qualquer função
  237.       pcnt_counter_clear(PCNT_COUNT_UNIT);                                // Zera o contador PCNT
  238.       esp_timer_start_once(timer_handle, janela);                         // Inicia contador de tempo de 1 segundo
  239.       gpio_set_level(OUTPUT_CONTROL_GPIO, 1);                             // Porta de controle habilita contagem dos pulsos
  240.     }
  241. #ifndef ARDUINO                                                           // IDF
  242.  
  243.   }                                                                       // IDF
  244.  
  245. #endif                                                                    // IDF
  246.  
  247. }
  248. //---------------------------------------------------------------------------------
  249. #ifdef ARDUINO                                                            // Arduino
  250.  
  251. void setup()                                                              // Arduino
  252. {
  253.   Serial.begin(115200);                                                   // Inicializa a serial
  254.   myInit();                                                               // Chaama inicializacao
  255. }                                                                         // Arduino
  256. //---------------------------------------------------------------------------------
  257. void loop()                                                               // Arduino
  258. {
  259.   app_main();                                                             // Roda rotina principal
  260.   String inputString = "";                                                // Temporaria transformar o valor da frequencia
  261.   oscilator = 0;                                                          // Limpa valor original
  262.   while (Serial.available())                                              // Enquanto tiver dados na serial
  263.   { //
  264.     char inChar = (char)Serial.read();                                    // Le um byte:
  265.     inputString += inChar;                                                // Adicione na string:
  266.     if (inChar == '\n')                                                   // Se new line:
  267.     {
  268.       oscilator = inputString.toInt();                                    // Transforma a string em inteiro
  269.       inputString = "";                                                   // Limpa a string
  270.     }
  271.   }
  272.   if (oscilator != 0)                                                     // Se foi digitado algum valor
  273.   {
  274.     ledcInit();                                                           // Reconfigura ledc
  275.   }
  276. }
  277.  
  278. #endif                                                                    // Arduino
RAW Paste Data