2023-07-20 10:17:11 +08:00
|
|
|
#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;
|
|
|
|
|
2023-07-20 10:50:39 +08:00
|
|
|
#define FLOW1_PIN_ECHO GPIO_NUM_39 // 捕获GPIO端口
|
|
|
|
#define FLOW2_PIN_ECHO GPIO_NUM_38 // 捕获GPIO端口
|
2023-07-20 10:17:11 +08:00
|
|
|
|
|
|
|
#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)
|
|
|
|
{
|
|
|
|
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]: %u %u time_diff: %u", ch, ccr, ccr_times, time_diff);
|
|
|
|
printf("rtc_clk_apb_freq : %u\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);
|
|
|
|
}
|