pile_com_stm32/main/stm32/flow.c

316 lines
8.9 KiB
C
Raw Normal View History

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;
#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);
}