RuiViana

NovoTeste03

Jul 13th, 2020
974
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 desenvolvedores
  6.   abaixo referenciados.
  7.  
  8.   O Projeto:
  9.   Um frequencímetro usando ESP32, sem necessidade de escalas e mostrando até 7 dígitos,
  10.   atingindo com precisão até 20MHz ou mais.
  11.  
  12.   Definições:
  13.   PORT de entrada do frequencímetro PCNT_INPUT_SIG_IO (GPIO 34)
  14.   PORT de entrada de controle PCNT_INPUT_CTRL_IO (GPIO 35)
  15.   PORT de saída do timer OUTPUT_CONTROL_GPIO (GPIO 32)
  16.   O PORT de entrada de controle (GPIO 35) deve ser ligado ao PORT de saída do timer (GPIO 32).
  17.   Estes são os ports usados no projeto, mas podem ser modificados para sua melhor conveniência.
  18.  
  19.   O frequencímetro é dividido em 5 partes:
  20.     1. Contador de pulsos;
  21.     2. Controle de tempo de contagem;
  22.     3. Impressão do resultado;
  23.     4. Espaço para outras funções.
  24.     5. Gerador de sinais programado para 10 KHz
  25.  
  26.   1. O contador de pulso usa o pcnt do ESP32.
  27.     O pcnt tem os seguintes parâmetros:
  28.       a. port de entrada;
  29.       b. canal de entrada;
  30.       c. port de controle;
  31.       d. contagem na subida do pulso;
  32.       e. contagem na descida do pulso;
  33.       f. contagem só com o controle em nível elevado;
  34.       g. limite máximo de contagem.
  35.  
  36.   2. O Controle de tempo de contagem usa o esp-timer.
  37.     O esp-timer tem o seguinte parâmetro:
  38.       a. controle do tempo;
  39.  
  40.   Funcionamento:
  41.     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.
  42.   Os pulsos são contado tanto na subida quanto na descida do pulso, para melhorar a media de contagem.
  43.   O tempo de contagem é definido pelo esp-timer, e esta' definido em 1 segundo, na variável janela.
  44.   Se a contagem for maior que 20000 pulsos durante o tempo de contagem, ocorra overflow e a cada overflow que ocorre
  45.   e' contabilizado na variável multPulses, e o contador de pulso retorna a zero continuando a contar.
  46.     Quando o tempo de leitura termina, uma rotina é chamada e o valor do no contador de pulsos e' lido e salvo,
  47.     um flag e' ligado indicando que terminou a leitura dos pulsos
  48.  
  49.     No loop, ao verificar que o flag indica que terminou a leitura dos pulsos, o valor é calculado multiplicando
  50.   o numero de overflow por 20000 e somando ao numero de pulsos restantes e dividindo por 2, pois contou 2 vezes.
  51.   Como o pulsos são contados na subida e na descida, a contagem e´ o dobro da frequência.
  52.     A frequência é impressa no serial monitor.
  53.   Os registradores são resetados e o port de controle de entrada é novamente elevado para nível alto e a contagem de
  54.   pulsos se inicia.
  55.  
  56.   Tem também um gerador de sinais que gera 10 KHz, e pode ser usado para testes.
  57.   Este gerador pode ser alterado para gerar frequencias até 40 MHz.
  58.   O Port de saida deste gerador é definido na linha #define LEDC_GPIO.
  59.   Atualmente está definido como GPIO 25.
  60.  
  61.   Para o uso da Serial e de um LCD, existem 2 definições que pode ser usadas juntas ou bloqueadas.
  62.   Este uso e bolqueio pode ser comitantemente ou individualmente.
  63.  
  64.   Referências:
  65.   author=krzychb https://github.com/espressif/esp-idf/tree/master/examples/peripherals/pcnt
  66.   resposta by Deouss » Thu May 17, 2018 3:07 pm no tópico https://esp32.com/viewtopic.php?t=5734
  67.   Gerador de sinais Gustavo https://github.com/Gustavomurta/ESP32_frequenceMeter/blob/master/ESP32OscilatorV03.ino
  68.   Formatação de numero https://arduino.stackexchange.com/questions/28603/the-most-effective-way-to-format-numbers-on-arduino
  69.   https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/esp_timer.html
  70.   https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html
  71.  
  72. */
  73.  
  74. #include <stdio.h>
  75. #include "freertos/FreeRTOS.h"
  76. #include "freertos/portmacro.h"
  77. #include "freertos/task.h"
  78. #include "freertos/queue.h"
  79. #include "driver/periph_ctrl.h"
  80. #include "driver/gpio.h"
  81. #include "driver/pcnt.h"
  82. #include "driver/ledc.h"
  83. #include "soc/ledc_struct.h"
  84.  
  85. #include "esp_attr.h"
  86. #include "esp_log.h"
  87. #include "esp_timer.h"
  88. #include "sdkconfig.h"
  89.  
  90. #define IDF_ON                                                           // Seleciona IDF_ON = IDF  IDF_OFF = Arduino
  91. #define LCD_OFF                                                            // Se tem LCD defina LCD_ON, se não tem LCD, defina LCD_OFF
  92. #define Ser_ON                                                            // Se quer imprimir resultados na serial defina Ser_ON, se não, defina  Ser_OFF
  93.  
  94. #ifdef LCD_ON                                                             // Se tem LCD
  95. #include <LiquidCrystal.h>                                                // Inclue a bibliotea do LCD
  96. LiquidCrystal lcd(5, 18, 19, 21, 22, 23);                                 // Instancia e define port
  97. #endif
  98.  
  99. #define PCNT_COUNT_UNIT        PCNT_UNIT_0                                // Unidade 0 do pcnt
  100. #define PCNT_COUNT_CHANNEL     PCNT_CHANNEL_0                             // Canal 0 do pcnt
  101.  
  102. #define PCNT_INPUT_CTRL_IO     GPIO_NUM_35                                // Count Control GPIO HIGH=count up, LOW=count down GPIO 25
  103. #define OUTPUT_CONTROL_GPIO    GPIO_NUM_32                                // Saida do timer GPIO 2
  104.  
  105. #define PCNT_INPUT_SIG_IO      GPIO_NUM_34                                // Freq Meter Input GPIO 34
  106. #define LEDC_HS_CH0_GPIO       GPIO_NUM_25                                // GPIO de saida do ledc
  107.  
  108. #define PCNT_OVERFLOW              20000                                  // Limite superior de contagem para overflow de pcnt
  109. #define PCNT_H_LIM_VAL        PCNT_OVERFLOW                               // Limite superior de contagem
  110.  
  111. //  Calculo do ajustes para cada faixa de frequencia
  112. //  Resolucao = log2(Clock(80MHz)/f)   ex: 50.000 HZ = 80.0000/50.000 = 1.600 log2(1600) = 10
  113. //  Duty 50%  = (2**Resolucao)/2       ex: 2**10 = 1024   1024/2 = 512
  114.  
  115. #define LEDC_TIMER(g,t) LEDC.timer_group[(g)].timer[(t)]
  116.  
  117.  
  118. uint32_t  oscilator = 50000;                                                     // Frequencia em Hz
  119. //#define OSCILADOR             115000                                      // Frequncia a ser gerada
  120. #define RESOLUCAO             LEDC_TIMER_7_BIT                            // Resolucao do ledc
  121. //#define M_DUTY              64                                          // Duty do ledc
  122.  
  123. esp_timer_create_args_t create_args;                                      // Argumentos do timer
  124. esp_timer_handle_t timer_handle;                                          // Instancia de timer
  125.  
  126. bool flag = true;                                                         // Indicador de fim de contagem libera impressao
  127. int16_t pulses = 0;                                                       // Contador de pulsos de entrada
  128. unsigned long multPulses = 0;                                             // Contador de overflows de pcnt
  129. unsigned long janela = 1000000;                                           // Janela de 1 segundo para a contagem de pulsos
  130.  
  131. portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
  132. //----------------------------------------------------------------------------------------
  133. char *ultos_recursive(unsigned long val, char *s, unsigned radix, int pos)
  134. {
  135.   int c;
  136.  
  137.   if (val >= radix)
  138.     s = ultos_recursive(val / radix, s, radix, pos + 1);
  139.   c = val % radix;
  140.   c += (c < 10 ? '0' : 'a' - 10);
  141.   *s++ = c;
  142.   if (pos % 3 == 0) *s++ = '.';
  143.   return s;
  144. }
  145. //----------------------------------------------------------------------------------------
  146. char *ltos(long val, char *s, int radix)
  147. {
  148.   if (radix < 2 || radix > 36) {
  149.     s[0] = 0;
  150.   } else {
  151.     char *p = s;
  152.     if (radix == 10 && val < 0) {
  153.       val = -val;
  154.       *p++ = '-';
  155.     }
  156.     p = ultos_recursive(val, p, radix, 0) - 1;
  157.     *p = 0;
  158.   }
  159.   return s;
  160. }
  161. //----------------------------------------------------------------------------------
  162. void tempo_controle(void *p)                                              // Fim de tempo de leitura de pulsos
  163. {
  164.   gpio_set_level(OUTPUT_CONTROL_GPIO, 0);                                 // Controle do PCount - stop count
  165.   pcnt_get_counter_value(PCNT_COUNT_UNIT, &pulses);                       // Obtem o valor contado
  166.   flag = true;                                                            // Informa que ocorreu interrupt de controle
  167. }
  168. //----------------------------------------------------------------------------------
  169. static void IRAM_ATTR pcnt_intr_handler(void *arg)                        // Overflow de contagem de pulsos
  170. {
  171.   portENTER_CRITICAL_ISR(&timerMux);                                      // Desabilita interrupção ?
  172.   multPulses++;                                                           // Incrementa contador de overflow
  173.   PCNT.int_clr.val = BIT(PCNT_COUNT_UNIT);                                // Limpa indicador de interrupt
  174.   portEXIT_CRITICAL_ISR(&timerMux);                                       // Libera novo interrupt
  175. }
  176. //----------------------------------------------------------------------------------
  177. void pcnt_init(void)                                                      // Rotina de inicializacao do pulse count
  178. {
  179.   pcnt_config_t pcnt_config = { };                                        // Instancia pulse config
  180.   pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_IO;                         // Port de entrada dos pulsos
  181.   pcnt_config.ctrl_gpio_num = PCNT_INPUT_CTRL_IO;                         // Controle da contagem
  182.   pcnt_config.unit = PCNT_COUNT_UNIT;                                     // Unidade de contagem
  183.   pcnt_config.channel = PCNT_COUNT_CHANNEL;                               // Canal de contagem
  184.   pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;                             // Limite maximo de contagem
  185.   pcnt_config.pos_mode = PCNT_COUNT_INC;                                  // Conta na subida do pulso
  186.   pcnt_config.neg_mode = PCNT_COUNT_INC;                                  // Conta na descida do pulso
  187.   pcnt_config.lctrl_mode = PCNT_MODE_DISABLE;                             // Nao usado
  188.   pcnt_config.hctrl_mode = PCNT_MODE_KEEP;                                // Se HIGH conta incrementando
  189.   pcnt_unit_config(&pcnt_config);                                         // Inicializa PCNT
  190.  
  191.   pcnt_counter_pause(PCNT_COUNT_UNIT);                                    // Inicializa o contador PCNT
  192.   pcnt_counter_clear(PCNT_COUNT_UNIT);                                    // Zera o contador PCNT
  193.  
  194.   pcnt_event_enable(PCNT_COUNT_UNIT, PCNT_EVT_H_LIM);                     // Limite superior de contagem
  195.   pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL);                    // Rotina de Interrupt de pcnt
  196.   pcnt_intr_enable(PCNT_COUNT_UNIT);                                      // Habilita interrup de pcnt
  197.  
  198.   pcnt_counter_resume(PCNT_COUNT_UNIT);                                   // inicia a contagem
  199. }
  200. //----------------------------------------------------------------------------
  201. void ledcInit ()
  202. {
  203.  // byte resol = log((80000000 / OSCILADOR));
  204. //   Serial.println(resol);
  205. //  uint32_t mDuty = (pow(2, resol)) / 2;
  206. //   Serial.println(mDuty);
  207. //  uint32_t mDuty = 64;
  208. //  uint8_t bit_num = 1;
  209. //  uint8_t chan = 0;
  210. //  uint8_t group = (chan / 8), timer = ((chan / 2) % 4);
  211. //   Serial.println(group);
  212.  
  213.   ledc_timer_config_t ledc_timer{};
  214. //  LEDC_TIMER(group, timer).conf.duty_resolution = 7;
  215. //  ledc_timer.duty_resolution = RESOLUCAO;
  216.   ledc_timer.duty_resolution = LEDC_TIMER_7_BIT;      // resolution of PWM duty
  217. //  ledc_timer.freq_hz = OSCILADOR;
  218.   ledc_timer.freq_hz = oscilator;
  219.   ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE;
  220.   ledc_timer.timer_num = LEDC_TIMER_0;
  221.   ledc_timer_config(&ledc_timer);
  222.  
  223.   ledc_channel_config_t ledc_channel{};
  224.   ledc_channel.channel = LEDC_CHANNEL_0;
  225.   ledc_channel.duty = mDuty;
  226.   ledc_channel.gpio_num = LEDC_HS_CH0_GPIO;
  227.   ledc_channel.intr_type = LEDC_INTR_DISABLE;
  228.   ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
  229.   ledc_channel.timer_sel = LEDC_TIMER_0;
  230.   ledc_channel_config(&ledc_channel);
  231. }
  232. //----------------------------------------------------------------------------------
  233. void myInit()
  234. {
  235. #ifdef LCD_ON                                                             // Se tem LCD
  236.   lcd.begin(16, 2);                                                       // Inicializa lcd
  237.   lcd.print("Frequencimetro");                                            // Print
  238. #endif
  239.   ledcInit();                                                             // Inicializa o ledc
  240.   pcnt_init();                                                            // Inicializa o pulse count
  241.   gpio_pad_select_gpio(OUTPUT_CONTROL_GPIO);                              // Define o port decontrole
  242.   gpio_set_direction(OUTPUT_CONTROL_GPIO, GPIO_MODE_OUTPUT);              // Define o port de controle como saida
  243.  
  244.   create_args.callback = tempo_controle;                                  // Instancia o tempo de controle
  245.   esp_timer_create(&create_args, &timer_handle);                          // Cria parametros do timer
  246. }
  247. //---------------------------------------------------------------------------------
  248. void app_main(void)
  249. {
  250. #ifdef IDF_ON                                                             // IDF
  251.   myInit();                                                               // IDF
  252.   while (1)                                                               // IDF
  253.   {
  254. #endif
  255.     if (flag == true)                                                     // Se a contagem tiver terminado
  256.     {
  257.       flag = false;                                                       // Impede nova impresao
  258.       float frequencia = 0;                                               // Variavel para calculo de frequencia
  259.       frequencia = (pulses + (multPulses * PCNT_OVERFLOW)) / 2  ;              // Calcula qtos pulsos ocorreram
  260.       char buf[32];
  261.       printf("frequencia: %s", (ltos(frequencia, buf, 10)));
  262.       printf(" Hz \n");
  263. #ifdef LCD_ON                                                             // LCD
  264.       lcd.setCursor(2, 1);                                                // Posiciona cusros na posicao 3 da linha 2
  265.       lcd.print(ltos(frequencia, buf, 10));                               // Print
  266.       lcd.print(" Hz           ");
  267. #endif
  268.       multPulses = 0;                                                     // Zera contador de overflow
  269.       // Aqui pode rodar qq funcao                                        // Espaco para qualquer função
  270.       vTaskDelay(1);                                                      // Delay (desnecessário)
  271.       // Aqui pode rodar qq funcao                                        // Espaco para qualquer função
  272.       pcnt_counter_clear(PCNT_COUNT_UNIT);                                // Zera o contador PCNT
  273.       esp_timer_start_once(timer_handle, janela);                         // Inicia contador de tempo de 1 segundo
  274.       gpio_set_level(OUTPUT_CONTROL_GPIO, 1);                             // Porta de controle habilita contagem dos pulsos
  275.     }
  276. #ifdef IDF_ON                                                             // IDF
  277.   }                                                                       // IDF
  278. #endif
  279. }
  280. //---------------------------------------------------------------------------------
  281. #ifdef IDF_OFF                                                            // Arduino
  282. void setup()
  283. {
  284.   Serial.begin(115200);                                                   // Inicializa a serial
  285.   myInit();                                                               // Chaama inicializacao
  286. }
  287. //---------------------------------------------------------------------------------
  288. void loop()
  289. {
  290.   app_main();                                                             // Chama rotina principal
  291. }
  292. #endif
RAW Paste Data