123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "freertos/queue.h"
- #include "driver/ledc.h"
- #include "driver/pcnt.h"
- #include "esp_attr.h"
- #include "esp_log.h"
- #include "config.h"
- #include "pcnt_functions.h"
- #include "soc/dport_reg.h"
- #ifdef CCFG_PCNT
- /** Electric meter:
- * 10000 impulses per kWh
- * Some normal max number could be 120 kWh/24h = 5 kWh/hour = 50000 pulses/hour = 833 pulses/min = 14 pulses/sec
- *
- * Counter is 16 bit signed = Max 32768 pulses = Will NOT work for one hour !!!!!
- * So we need some other way of counting higher numbers that will last for one h
- * Probably we need to use interrupts !
- */
- // Example-code: https://github.com/espressif/esp-idf/blob/master/examples/peripherals/pcnt/pulse_count_event/main/pcnt_event_example_main.c
- // Counts interrupts that occus every 32K Pulses
- // The counter register is 16 bit signed so we count to 32K before doing an interrupt
- // This equals to 32kWH consumed energy (at 1000 pulses per kWh)
- static uint32_t Counter_32K_Pulses = 0;
- static const int pcntUnit = PCNT_UNIT_0;
- static void pCntMonitorTask(void *pvParameters);
- static double getkWh(uint32_t *bigCnt, int32_t *cnt) {
- pcnt_intr_disable(pcntUnit);
- volatile int32_t count = DPORT_REG_READ(0x3FF57060);
- volatile uint32_t bigCounter = Counter_32K_Pulses;
- pcnt_intr_enable(pcntUnit);
- *bigCnt = bigCounter;
- *cnt = count;
- const double retVal = ((double)bigCounter*32)+((double)count / PULSES_PER_KWH);
- return retVal;
- }
- static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
- {
- Counter_32K_Pulses++;
- }
- void init_pcnt_unit()
- {
- /* Prepare configuration for the PCNT unit */
- pcnt_config_t pcnt_config = {
- // Set PCNT input signal and control GPIOs
- .pulse_gpio_num = PCNT_INPUT_SIG_IO,
- .ctrl_gpio_num = PCNT_PIN_NOT_USED;
- .channel = PCNT_CHANNEL_0,
- .unit = pcntUnit,
- // What to do on the positive / negative edge of pulse input?
- .pos_mode = PCNT_COUNT_INC, // Count up on the positive edge
- .neg_mode = PCNT_COUNT_DIS, // Keep the counter value on the negative edge
- // What to do when control input is low or high?
- .lctrl_mode = PCNT_MODE_REVERSE, // Reverse counting direction if low
- .hctrl_mode = PCNT_MODE_KEEP, // Keep the primary counter mode if high
- // Set the maximum and minimum limit values to watch
- .counter_h_lim = 32000,
- .counter_l_lim = 0,
- };
- /* Initialize PCNT unit */
- pcnt_unit_config(&pcnt_config);
- // How to read a periphial-register:
- //uint32_t c = p_pcnt_obj->hal.dev.hw.conf_unit[unit];
- //printf("Reg: %08x\n",(uint32_t)DPORT_REG_READ(0x3FF57000));
- //The length of ignored pulses is provided in APB_CLK clock cycles by calling pcnt_set_filter_value().
- //The current filter setting may be checked with pcnt_get_filter_value().
- //The APB_CLK clock is running at 80 MHz.
- /* Configure and enable the input filter */
- pcnt_set_filter_value(pcntUnit, 1023); // APB_CLK=80MHz * 1023 is filtered out = 0,0127875mS (????)
- pcnt_filter_enable(pcntUnit);
- /* Enable int on high count limit */
- pcnt_event_enable(pcntUnit, PCNT_EVT_H_LIM);
- /* Initialize PCNT's counter */
- pcnt_counter_pause(pcntUnit);
- pcnt_counter_clear(pcntUnit);
- /* Install interrupt service and add isr callback handler */
- pcnt_isr_service_install(0);
- pcnt_isr_handler_add(pcntUnit, pcnt_example_intr_handler, (void *)pcntUnit);
- /* Everything is set up, now go to counting */
- pcnt_counter_resume(pcntUnit);
- }
- static void pCntMonitorTask(void *pvParameters) {
- ESP_LOGI("PCNT", "pCntMonitorTask starting");
- /*
- char dataStr[100];
- double kWh = 0.0;
- uint32_t bigCnt = 0;
- int32_t cnt = 0;
- kWh = getkWh(&bigCnt, &cnt);
- sprintf(dataStr,"%.5f",kWh);
- // @TODO This is changed for testing
- #ifdef MQTT_ENABLED
- sendMQTTMessage("/sensors/TEST/energy/electricalTotal", dataStr);
- #endif
- ESP_LOGI("MAIN", "%.4f %u %d",kWh,bigCnt,cnt);
- */
- }
- void initPCNT() {
- init_pcnt_unit();
- ledc_init();
- xTaskCreate(pCntMonitorTask, "pCntMonitorTask", 1024*10, NULL, 2, NULL);
- }
- #endif
|