#include "stdlib.h" #include "utils.h" #include "config.h" #include "ads1220.h" #include "fram.h" #include "modbuss.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "freertos/semphr.h" #include "esp_err.h" #include "esp_log.h" #include "esp_check.h" #include "soc/rtc.h" #include "driver/mcpwm.h" int zero_totalflow_req = 0; const static char *TAG = "flow"; typedef struct capture_event { int ch; uint32_t val; } capture_event_t; #define FLOW1_PIN_ECHO GPIO_NUM_39 // 捕获GPIO端口 #define FLOW2_PIN_ECHO GPIO_NUM_38 // 捕获GPIO端口 #define TRIGGER_THREAD_PRIORITY 5 extern int abs_sub(uint32_t enc_update_time, uint32_t _enc_update_time); typedef struct { uint32_t capture_signal; mcpwm_capture_signal_t sel_cap_signal; } capture; // static uint32_t cap_val_begin_of_flow1 = 0; // static uint32_t cap_val_end_of_flow1 = 0; // static uint32_t cap_val_begin_of_flow2 = 0; // static uint32_t cap_val_end_of_flow2 = 0; //static xQueueHandle cap_queue; extern uint32_t rtc_clk_apb_freq; uint32_t volatile t15_ccr[2]; uint16_t volatile t15_ccr_times[2]; cal_4_20ma_t *cal_4_20ma = (cal_4_20ma_t *)&gWordVar[CAL_4_20MA_ADDR]; flow_config_t *flow_config = (flow_config_t *)&gWordVar[FLOW_CONFIG_ADDR]; flow_t *pflow = (flow_t *)&gWordVar[FLOW_REG_ADDR]; void capture_flow1_init(); void capture_flow2_init(); extern void ADS1220_Init(void); uint32_t volatile last_ccr[2] = {0}; extern int ad_value[4]; extern int ad_update_time[4]; extern uint8_t ad_watchdog_cnt; extern int ad_values[4]; extern int ad_update_time[4]; uint32_t flow_update_time[2]; uint8_t timeout[2] = {0}; int flow_rem[2] = {0}; static bool flow1_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata, void *arg) { // calculate the interval in the ISR, // so that the interval will be always correct even when cap_queue is not handled in time and overflow. BaseType_t high_task_wakeup = pdFALSE; t15_ccr[0] = edata->cap_value; t15_ccr_times[0]++; return high_task_wakeup == pdFALSE; } void capture_flow1_init() { ESP_ERROR_CHECK(mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_1, FLOW1_PIN_ECHO)); // enable pull down CAP0, to reduce noise ESP_ERROR_CHECK(gpio_pulldown_en(FLOW1_PIN_ECHO)); // enable both edge capture on CAP0 mcpwm_capture_config_t conf = { .cap_edge = MCPWM_NEG_EDGE, .cap_prescale = 1, .capture_cb = flow1_isr_handler, // 绑定流量捕获中断处理函数 .user_data = NULL}; ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_1, MCPWM_SELECT_CAP1, &conf)); ESP_LOGI(TAG, "capture_flow_init"); } static bool flow2_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata, void *arg) { // calculate the interval in the ISR, // so that the interval will be always correct even when cap_queue is not handled in time and overflow. BaseType_t high_task_wakeup = pdFALSE; t15_ccr[1] = edata->cap_value; // t15_ccr_times[1] = cap_event.val * (1000000.0 / rtc_clk_apb_freq); t15_ccr_times[1]++; // send measurement back though queue // xQueueSendFromISR(cap_queue, &cap_event, &high_task_wakeup); return high_task_wakeup == pdFALSE; } void capture_flow2_init() { ESP_ERROR_CHECK(mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_2, FLOW2_PIN_ECHO)); // enable pull down CAP0, to reduce noise ESP_ERROR_CHECK(gpio_pulldown_en(FLOW2_PIN_ECHO)); // enable both edge capture on CAP0 mcpwm_capture_config_t conf = { .cap_edge = MCPWM_NEG_EDGE, .cap_prescale = 1, .capture_cb = flow2_isr_handler, // 绑定流量捕获中断处理函数 .user_data = NULL}; ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_1, MCPWM_SELECT_CAP2, &conf)); ESP_LOGI(TAG, "capture_flow_init"); } // void capture_task(void) // { // while (true) { // capture_event_t cap_event = {.val = 0, .ch = 1}; // uint32_t pulse_width_us = 0; // // block and wait for new measurement // // ESP_LOGI(TAG, "xQueueReceive started"); // xQueueReceive(cap_queue, &cap_event, portMAX_DELAY); // // ESP_LOGI(TAG, "xQueueReceive after"); // // ESP_LOGI(TAG, " cap_event.val: %d, cap_event.ch : %d", cap_event.val, cap_event.ch); // switch (cap_event.ch) // { // case 1: //flow1 capture // pulse_width_us = cap_event.val * (1000000.0 / rtc_clk_apb_freq); // ESP_LOGI(TAG, " (flow1 capture) Pulse width: %uus", pulse_width_us); // break; // case 2: //flow2 capture // pulse_width_us = cap_event.val * (1000000.0 / rtc_clk_apb_freq); // ESP_LOGI(TAG, "(flow2 capture) Pulse width: %uus", pulse_width_us); // break; // default: ESP_LOGI(TAG, " default\n"); // break; // } // } // } void flow_init(void) { // 流量 初始化捕获定时器 // capture_flow2_init(); // MX_TIM15_Init(); // HAL_TIM_Base_Start_IT(&htim15); if (flow_config->input_type == 1) { // 4~20ma // ADS1220_Init(); } else if (flow_config->input_type == 2) { // freq // HAL_TIM_IC_Start_IT(&htim15, TIM_CHANNEL_1); // HAL_TIM_IC_Start_IT(&htim15, TIM_CHANNEL_2); capture_flow1_init(); capture_flow2_init(); } } extern void zero_totalflow(int ch); void flow_task(void *arg) { static uint32_t cp_flow_tick = 0; static uint32_t ad_flow_tick = 100; //int lock_time_out = 0; while (1) { vTaskDelay(50); if (flow_config->input_type == 2 && TickDiff(cp_flow_tick) > 100) { int ch; cp_flow_tick = xTaskGetTickCount(); for (ch = 0; ch < 2; ch++) { if (t15_ccr_times[ch] > 0) { int ccr_times; int time_diff; uint32_t ccr; // __disable_irq(); ccr_times = t15_ccr_times[ch]; t15_ccr_times[ch] = 0; ccr = t15_ccr[ch]; ccr = ccr / (rtc_clk_apb_freq / 1000000); // __enable_irq(); time_diff = ccr - last_ccr[ch]; ESP_LOGI(TAG, "(type2) t15_ccr_times[%d]: %lu %d time_diff: %d", ch, ccr, ccr_times, time_diff); ESP_LOGI(TAG,"rtc_clk_apb_freq : %lu\n", rtc_clk_apb_freq); if (time_diff != 0) { int t_flow; pflow[ch].flow_ = flow_config->pulse_coef[ch] * 600 * (int64_t)ccr_times / time_diff; if (pflow[ch].flow_ < flow_config->min_flow[ch]) { pflow[ch].flow = 0; } else { pflow[ch].flow = pflow[ch].flow_; } t_flow = pflow[ch].flow * time_diff / (5 * 60); flow_rem[ch] += t_flow; pflow[ch].total_flow += flow_rem[ch] / 10000; flow_rem[ch] = flow_rem[ch] % 10000; pflow[ch].update_time = ccr; last_ccr[ch] = ccr; timeout[ch] = 0; // ESP_LOGI(TAG, "(type2) pflow[%d].flow: %u", ch ,pflow[ch].flow); } } if (++timeout[ch] > 5) { timeout[ch] = 0; pflow[ch].flow = 0; pflow[ch].flow_ = 0; } } } if (flow_config->input_type == 1 && TickDiff(ad_flow_tick) > 200) { int i; ad_flow_cal_t *cal = flow_config->ad_cal; ad_flow_tick = xTaskGetTickCount(); for (i = 0; i < 2; i++) { int ad_ch = i * 2 + 1; int time_diff = abs_sub(ad_update_time[ad_ch], pflow[i].update_time); if (time_diff != 0) { int t_flow; // time_diff时间段总流量 pflow[i].flow_ = scale(ad_value[ad_ch], cal_4_20ma->ch[i].ad_4ma, cal_4_20ma->ch[i].ad_20ma, cal[i].flow_min, cal[i].flow_max); if (pflow[i].flow_ < flow_config->min_flow[i]) { pflow[i].flow = 0; } else { pflow[i].flow = pflow[i].flow_; } // 累计流量计算 pflow[i].flow 单位为0.01L/分钟 time_diff 单位为20uS // flow = pflow[i].flow / 60.0 * 10000; 将流量换算成uL/s // t_diff = time_diff / 50000 将时间差换算成秒 // t_flow = flow * t_diff 计算t_diff时间段的流量 单位uL // 取出0.01L的整数部分累加,余数部分和下次值累加 // t_flow = pflow[i].flow * 1000 * time_diff / 500000 / 60; int time_diff_us = time_diff / (APB_CLK_FREQ / 1000000); t_flow = pflow[i].flow * time_diff_us / 60 / 100; flow_rem[i] += t_flow; pflow[i].total_flow += flow_rem[i] / 10000; flow_rem[i] = flow_rem[i] % 10000; pflow[i].update_time = ad_update_time[ad_ch]; timeout[i] = 0; ESP_LOGI(TAG, "(type1) flow_rem[%d].flow: %u", i, pflow[i].flow); } if (++timeout[i] > 10) { timeout[i] = 0; pflow[i].flow = 0; pflow[i].flow_ = 0; } } } if(zero_totalflow_req){ zero_totalflow_req = 0; zero_totalflow(0); zero_totalflow(1); } } } // 获取给定时刻累计流量 int get_total_flow_by_time(int ch, uint32_t time) { int delta_t; int delta_flow; if (ch > 1) { return 0; } delta_t = abs_sub(time, pflow[ch].update_time) / (APB_CLK_FREQ / 1000000); // 换算成us delta_flow = pflow[ch].flow * delta_t / 60 / 100; return pflow[ch].total_flow + delta_flow; } void zero_totalflow(int ch) { if (ch > 1) { return; } pflow[ch].total_flow = 0; flow_rem[ch] = 0; } void FLOW_init() { flow_init(); xTaskCreate(flow_task, "flow_task", 4096, NULL, 10, NULL); }