407 lines
13 KiB
C
407 lines
13 KiB
C
/*
|
||
* @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]);
|
||
}
|