/* * @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]); }