This repository has been archived on 2025-01-02. You can view files and clone it, but cannot push or open issues or pull requests.
torsion/User/board/flowmeter.c

407 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: shenghao.xu
* @Date: 2023-04-19 22:29:52
* @LastEditors: shenghao.xu
* @LastEditTime: 2023-05-12 15:19:58
* @Description:流量计-modbus主机模块
* email:545403892@qq.com
* Copyright (c) 2023 by shenghao.xu, All Rights Reserved.
*/
#include "flowmeter.h"
extern uart_t *uarts[UART_NUM_MAX];
static flowmeter_t handle;
static uint8_t current_uart_index; // 当前正在操作的485正在执行过程中不允许切换
static flowmeter_process_status_e current_status; // 当前流程的状态
static void flowmeter_send(uart_num_e id, uint8_t *data, uint8_t length)
{
handle.send_data_cb(id, data, length);
}
// 打开写保护寄存器
static void flowmeter_open_write_protect(uart_num_e id)
{
uint16_t _send_len = 0;
agile_modbus_t *ctx = &handle.ctx_rtu._ctx;
if (id == FLOWMETER_RS485_PORT_1)
{
agile_modbus_set_slave(ctx, FLOWMETER_SLAVER_ADDR);
_send_len = agile_modbus_serialize_write_register(ctx, 0x14, 0xAA55);
}
else if (id == FLOWMETER_RS485_PORT_2)
{
agile_modbus_set_slave(ctx, FLOWMETER_SLAVER_ADDR + 1);
_send_len = agile_modbus_serialize_write_register(ctx, 0xFF, 0xAA55);
}
flowmeter_send(id, ctx->send_buf, _send_len);
}
// 测试流量计校准气体流量为0时参数累计总量、气体修正系数、响应时间、自动教零、下限报警、上限报警
static void flowmeter_calibrate(uart_num_e id, flowmeter_calibrate_t data)
{
current_status = PROCESS_WRITE_REGISTERS;
uint16_t _send_len = 0;
agile_modbus_t *ctx = &handle.ctx_rtu._ctx;
uint16_t buf[FLOWMETER1_REGISTERS_LEN]; // 用于存放需要写入的数据
uint16_t *ptr = buf;
uart_t *h;
h = uarts[id];
DBG_ASSERT(h != NULL __DBG_LINE);
h->rx_sta |= 0x8000;
delay_ms(50);
if (id == FLOWMETER_RS485_PORT_1)
{
agile_modbus_set_slave(ctx, FLOWMETER_SLAVER_ADDR);
// 遍历data.registers_write_enable.bits将使能的寄存器写入ctx->send_buf
if (data.registers_write_enable.bits.total_flow)
{
// 寄存器地址从4开始
osel_memset((uint8_t *)buf, 0, sizeof(buf));
osel_memcpy((uint8_t *)ptr, (uint8_t *)&data.total_flow, sizeof(data.total_flow));
_send_len = agile_modbus_serialize_write_registers(ctx, 0x04, 3, ptr);
flowmeter_send(id, ctx->send_buf, _send_len);
delay_ms(100);
}
if (data.registers_write_enable.bits.gas_correct)
{
// 寄存器地址从0x16开始
flowmeter_open_write_protect(id);
delay_ms(100);
_send_len = agile_modbus_serialize_write_register(ctx, 0x16, data.gas_correct);
flowmeter_send(id, ctx->send_buf, _send_len);
delay_ms(100);
}
if (data.registers_write_enable.bits.response_time)
{
// 寄存器地址从0x17开始
flowmeter_open_write_protect(id);
delay_ms(100);
_send_len = agile_modbus_serialize_write_register(ctx, 0x17, data.response_time);
flowmeter_send(id, ctx->send_buf, _send_len);
delay_ms(100);
}
if (data.registers_write_enable.bits.auto_zero)
{
// 寄存器地址从0x27开始
_send_len = agile_modbus_serialize_write_register(ctx, 0x27, data.auto_zero);
flowmeter_send(id, ctx->send_buf, _send_len);
delay_ms(100);
}
if (data.registers_write_enable.bits.lower_limit)
{
// 寄存器地址从0x31开始
flowmeter_open_write_protect(id);
delay_ms(100);
_send_len = agile_modbus_serialize_write_register(ctx, 0x31, data.lower_limit);
flowmeter_send(id, ctx->send_buf, _send_len);
delay_ms(100);
}
if (data.registers_write_enable.bits.upper_limit)
{
// 寄存器地址从0x33开始
flowmeter_open_write_protect(id);
delay_ms(100);
_send_len = agile_modbus_serialize_write_register(ctx, 0x33, data.upper_limit);
flowmeter_send(id, ctx->send_buf, _send_len);
delay_ms(100);
}
}
else if (id == FLOWMETER_RS485_PORT_2)
{
agile_modbus_set_slave(ctx, FLOWMETER_SLAVER_ADDR + 1);
// 气体修正因子
if (data.registers_write_enable.bits.gas_correct)
{
// 寄存器地址从0x8B开始
flowmeter_open_write_protect(id);
delay_ms(100);
_send_len = agile_modbus_serialize_write_register(ctx, 0x8B, data.gas_correct);
flowmeter_send(id, ctx->send_buf, _send_len);
delay_ms(100);
}
// 自动校零
if (data.registers_write_enable.bits.auto_zero)
{
// 寄存器地址从0xF0开始
flowmeter_open_write_protect(id);
delay_ms(100);
_send_len = agile_modbus_serialize_write_register(ctx, 0xF0, data.auto_zero);
flowmeter_send(id, ctx->send_buf, _send_len);
delay_ms(100);
}
// 清除总量
if (data.registers_write_enable.bits.total_flow)
{
// 寄存器地址从0xF2开始
flowmeter_open_write_protect(id);
delay_ms(100);
_send_len = agile_modbus_serialize_write_register(ctx, 0xF2, 0x0001);
flowmeter_send(id, ctx->send_buf, _send_len);
delay_ms(100);
}
}
h->rx_sta = 0;
current_status = PROCESS_END;
}
// 流量计校准
void flowmeter_calibrate_simulate(uint8_t index)
{
uart_t *h;
flowmeter_calibrate_t d;
d.registers_write_enable.bits.total_flow = 1;
d.registers_write_enable.bits.gas_correct = 0;
d.registers_write_enable.bits.response_time = 1;
d.registers_write_enable.bits.auto_zero = 1;
d.registers_write_enable.bits.lower_limit = 0;
d.registers_write_enable.bits.upper_limit = 0;
d.total_flow.data1 = 0;
if (!handle.idel_flag)
{
d.total_flow.data2 = 0;
}
else
{
d.total_flow.data2 = 0;
}
d.total_flow.data3 = 0;
d.gas_correct = 1000;
d.response_time = 100;
d.auto_zero = 0xAA55;
d.lower_limit = 0;
d.upper_limit = 100;
h = handle.huart[index];
flowmeter_calibrate((uart_num_e)h->uart_index, d);
}
static void calibration_sensor_flowmeter(uint8_t bits) // 流量传感器校准
{
for (uint8_t i = 0; i < 8; i++)
{
uint8_t bit = bits & (1 << i);
switch (bit)
{
case 1:
flowmeter_calibrate_simulate(i);
break;
case 2:
flowmeter_calibrate_simulate(i);
break;
}
}
}
/**
* @description: 流程处理完后,是否需要休眠
* @return {*}
*/
flowmeter_process_sleep_e flowmeter_process_need_sleep(void)
{
if (current_uart_index == FLOWMETER_MAX)
{
return FLOWMETER_PROCESS_SLEEP_1s;
}
else
{
if (current_status == PROCESS_RECEIVE_REGISTERS_DATA)
{
return FLOWMETER_PROCESS_SLEEP_RECVTM;
}
else if (current_status == PROCESS_END || current_status == PROCESS_WAIT)
{
return FLOWMETER_PROCESS_SLEEP_100ms;
}
else if (current_status == PROCESS_IDEL)
{
return FLOWMETER_PROCESS_SLEEP_3s;
}
else
{
return FLOWMETER_PROCESS_NO_SLEEP;
}
}
}
/**
* @description: 进程处理:读取从机寄存器数据
* @return {*}
*/
void flowmeter_process(void)
{
uart_t *h;
int32_t rc;
agile_modbus_t *ctx = &handle.ctx_rtu._ctx;
uint16_t _send_len = 0;
uint16_t _hold_register[FLOWMETER1_REGISTERS_LEN];
if (handle.calibration_flag != 0 && PROCESS_IDEL != current_status)
{
calibration_sensor_flowmeter(handle.calibration_flag);
handle.calibration_flag = 0;
}
if (current_uart_index == FLOWMETER_MAX)
{
current_uart_index = 0;
}
// if (current_uart_index == 0 && handle.idel_flag == true)
// { // 测试单个设备
// current_status = PROCESS_END;
// }
h = handle.huart[current_uart_index];
if (h == NULL)
{
return;
}
DBG_ASSERT(h != NULL __DBG_LINE);
switch (current_status)
{
case PROCESS_READ_REGISTERS:
h->rx_sta = 0; // 开启串口缓冲区接收数据
osel_memset(ctx->send_buf, 0, FLOWMETER_MODBUS_SEND_LENGTH);
osel_memset(ctx->read_buf, 0, FLOWMETER_MODBUS_RECV_LENGTH);
if (h->uart_index == FLOWMETER_RS485_PORT_1)
{
agile_modbus_set_slave(ctx, FLOWMETER_SLAVER_ADDR);
_send_len = agile_modbus_serialize_read_registers(ctx, FLOWMETER1_START_REGISTERS_ADDR, FLOWMETER1_REGISTERS_LEN);
flowmeter_send((uart_num_e)h->uart_index, ctx->send_buf, _send_len);
current_status = PROCESS_RECEIVE_REGISTERS_DATA;
}
else if (h->uart_index == FLOWMETER_RS485_PORT_2)
{
agile_modbus_set_slave(ctx, FLOWMETER_SLAVER_ADDR + 1);
_send_len = agile_modbus_serialize_read_registers(ctx, FLOWMETER2_START_REGISTERS_ADDR, FLOWMETER2_REGISTERS_LEN);
flowmeter_send((uart_num_e)h->uart_index, ctx->send_buf, _send_len);
current_status = PROCESS_RECEIVE_REGISTERS_DATA;
}
else
{
current_status = PROCESS_END;
}
break;
case PROCESS_RECEIVE_REGISTERS_DATA:
if (h->rx_sta == 0)
{
current_status = PROCESS_END;
return; // 未收到数据切换到下一个设备
}
h->rx_sta |= 0x8000; // 暂停串口接收数据20ms预留了充足的接收时间
current_status = PROCESS_DESERIALIZE_DATA;
break;
case PROCESS_DESERIALIZE_DATA:
osel_memset((uint8_t *)_hold_register, 0, FLOWMETER1_REGISTERS_LEN * sizeof(uint16_t));
rc = agile_modbus_deserialize_read_registers(ctx, (h->rx_sta & 0X3FFF), _hold_register);
if (rc >= 0)
{
handle.flow[current_uart_index].f = (_hold_register[0] * 65535 + _hold_register[1]) / 1000.0;
}
current_status = PROCESS_END;
break;
case PROCESS_WAIT:
break;
case PROCESS_WRITE_REGISTERS:
break;
case PROCESS_IDEL:
if (handle.idel_flag)
{
current_status = PROCESS_READ_REGISTERS;
return;
}
agile_modbus_rtu_init(&handle.ctx_rtu, handle.ctx_send_buf, FLOWMETER_MODBUS_SEND_LENGTH,
handle.ctx_recv_buf, FLOWMETER_MODBUS_RECV_LENGTH);
current_status = PROCESS_READ_REGISTERS;
for (uint8_t i = 0; i < FLOWMETER_MAX; i++)
{
flowmeter_calibrate_simulate(i);
delay_ms(50);
}
handle.idel_flag = true;
handle.calibration_flag = 0;
break;
default:
current_status = PROCESS_READ_REGISTERS;
current_uart_index++; // 切换到下一个485
break;
}
}
// 获取顺时流量值
float32 flowmeter_get_flow(uint8_t index)
{
return handle.flow[index].f;
}
// 串口接收中断回调函数,流量
static void flowmeter_rx_cb(uint8_t uart_index, uint8_t *data, uint16_t len)
{
uart_t *h, *h1;
// 公用一个485需要复制数据
h1 = handle.huart[0];
h = handle.huart[current_uart_index];
if ((h->rx_sta & 0x8000) == 0) // 接收未完成
{
handle.ctx_recv_buf[h->rx_sta & 0X3FFF] = h1->rxbuf[0];
h->rx_sta++;
if (h->rx_sta > (FLOWMETER_MODBUS_RECV_LENGTH - 1))
h->rx_sta = 0; // 接收数据错误,重新开始接收
}
}
void flowmeter_set_calibration_flag(uint8_t bits)
{
handle.calibration_flag = bits;
}
static void flowmeter_uart_init(void)
{
if (uarts[FLOWMETER_RS485_PORT_1] == NULL)
{
uarts[FLOWMETER_RS485_PORT_1] = uart_create(USART2, FALSE, 1, flowmeter_rx_cb, FALSE, 0, NULL);
uarts[FLOWMETER_RS485_PORT_1]->uart_index = FLOWMETER_RS485_PORT_1;
}
if (uarts[FLOWMETER_RS485_PORT_2] == NULL)
{
uarts[FLOWMETER_RS485_PORT_2] = uart_create(USART2, FALSE, 1, flowmeter_rx_cb, FALSE, 0, NULL);
uarts[FLOWMETER_RS485_PORT_2]->uart_index = FLOWMETER_RS485_PORT_2;
}
}
/**
* @description: 初始化流量计
* @return {*}
*/
void flowmeter_init(send_data_cb_t cb)
{
handle.send_data_cb = cb;
flowmeter_uart_init();
handle.huart[0] = uarts[FLOWMETER_RS485_PORT_1]; // MF4700
handle.huart[1] = uarts[FLOWMETER_RS485_PORT_2]; // MF5600
DBG_ASSERT(handle.huart[0] != NULL __DBG_LINE);
DBG_ASSERT(handle.huart[1] != NULL __DBG_LINE);
GPIO_RESET(RS485_EN1_GPIO_Port, RS485_EN1_Pin);
current_uart_index = 0; // 默认从第一个485开始执行
handle.idel_flag = FALSE;
handle.flow[0].f = 0;
handle.flow[1].f = 0;
uart_recv_en(uarts[FLOWMETER_RS485_PORT_1]);
uart_recv_en(uarts[FLOWMETER_RS485_PORT_2]);
}