diff --git a/protocol.c b/protocol.c index 86283ed..dbe80c6 100644 --- a/protocol.c +++ b/protocol.c @@ -117,56 +117,13 @@ void InitDeviceStatus() { updateInitStatus(INIT_SUCCESS); } -// 定时1s更新设备状态 -// 活度计通过网口获取 -// 下挂设备通过485获取 -void UpdateDeviceStatus() { - // 更新设备状态 -} - - - - -// 状态查询处理 -static uint8_t HandleStatusQuery(uint8_t *txBuf) { - // 填充并返回数据 - memcpy(txBuf, &deviceStatus, sizeof(DeviceStatus)); - return sizeof(DeviceStatus); -} //modBUS RTU 写命令 void writeCMD(uint8_t *txBuf, uint16_t *txLen) { } -// 三通阀控制处理 -static uint8_t HandleValveControl(uint8_t index, ValveAngle_t angle) { - // 实现三通阀控制逻辑 - updateValveStatus(index, angle); - return 1; -} - -// 泵时长控制处理 -static uint8_t HandlePumpTimeControl(uint8_t *rxBuf, uint8_t *txBuf, uint16_t *txLen) { - // 实现泵时长控制逻辑 - *txLen = 1; - return 1; -} - -// 泵速度设置处理 -static uint8_t HandlePumpSpeedControl(uint8_t *rxBuf, uint8_t *txBuf, uint16_t *txLen) { - // 实现泵速度设置逻辑 - *txLen = 1; - return 1; -} - -// 软急停功能处理 -static uint8_t HandleSoftStop(uint8_t *rxBuf, uint8_t *txBuf, uint16_t *txLen) { - // 实现软急停功能逻辑 - *txLen = 1; - return 1; -} // 判断系统大端序还是小端序 static uint8_t IsBigEndian() { @@ -200,7 +157,7 @@ static void FillBigEndian16(uint8_t *data, uint16_t value) { } // 泵加速、减速处理 -static uint8_t HandlePumpAccDec(uint8_t index, uint8_t acc, uint8_t dec) { +static uint8_t WritePumpAccDec(uint8_t index, uint8_t acc, uint8_t dec) { // 实现泵加速、减速逻辑 RTU_Frame frame; @@ -225,7 +182,7 @@ static uint8_t HandlePumpAccDec(uint8_t index, uint8_t acc, uint8_t dec) { } // 泵速度设置处理 -static uint8_t HandlePumpSpeed(uint8_t index, uint8_t speed) { +static uint8_t WritePumpSpeed(uint8_t index, uint8_t speed) { // 实现泵速度设置逻辑 RTU_Frame frame; @@ -247,7 +204,7 @@ static uint8_t HandlePumpSpeed(uint8_t index, uint8_t speed) { } // 泵步进设置处理 -static uint8_t HandlePumpStep(uint8_t index, int32_t step) { +static uint8_t WritePumpStep(uint8_t index, int32_t step) { // 实现泵步进设置逻辑 RTU_Frame frame; @@ -279,48 +236,274 @@ static uint8_t HandlePumpStep(uint8_t index, int32_t step) { return 1; } -// 初始化处理 -static uint8_t HandleInit(uint8_t *rxBuf, uint8_t *txBuf, uint16_t *txLen) { - // 实现初始化逻辑 - *txLen = 1; +// pump 读寄存器 +uint16_t ReadPump1Reg(uint8_t index, uint16_t reg) { + + // 读取保存寄存器不能直接使用RTU_Frame,因为无数据位 + uint8_t data[8] = {0}; + data[0] = index; + data[1] = RTU_PUMP_FUNC_READ_REG; + FillBigEndian16(&data[2], reg); + FillBigEndian16(&data[4], 1); + + uint16_t crc = CalculateCRC16(data, 6); + // 大端序填充 + FillBigEndian16(&data[6], crc); + + writeCMD(data, 8); +} + +// 获取泵状态 +void ReadPumpStatus(uint8_t index) { + ReadPump1Reg(index, RTU_PUMP_CMD_SC); +} + +// 获取泵告警信息 +void ReadPumpAlarm(uint8_t index) { + ReadPump1Reg(index, RTU_PUMP_CMD_AL); +} + +// 解码告警信息 +void DecodePumpAlarmMsg(uint16_t reg4001) { + static AlarmCode_t alarmCode = {0}; + // 与上次告警信息相同,则不更新,仅打印一次 + if (alarmCode.all == reg4001) + { + return 0; + } + alarmCode.all = reg4001; + + if(alarmCode.all == 0) { + //暂时屏蔽,避免刷屏 + // printf("\r\n%s无报警信息\r\n", pumpName[index]); + return 0; + } + + // 打印表格头部 + printf("\r\n+--------+------------------+\r\n"); + printf("| 告警位 | 告警信息 |\r\n"); + printf("+--------+------------------+\r\n"); + + for(uint16_t i = 0; i < 16; i++) { + if(alarmCode.all & (1 << i)) { + printf("| %6d | %-14s |\r\n", i, alarmInfo[i]); + printf("+--------+------------------+\r\n"); + } + } return 1; } -// 主命令处理函数 -uint8_t ProcessCommand(uint8_t *rxBuf, uint16_t rxLen, uint8_t *txBuf, uint16_t *txLen) { - uint16_t cmdCode = (rxBuf[0] << 8) | rxBuf[1]; - uint8_t dataLen = rxBuf[2]; - uint8_t *data = &rxBuf[3]; - uint8_t result = 0; +// 解码状态信息 +void DecodePumpStatusMsg(uint16_t reg4002) { + static StatusCode_t statusCode = {0}; + // 与上次状态信息相同,则不更新,仅打印一次 + if (statusCode.all == reg4002) + { + return 1; + } + statusCode.all = reg4002; + + printf("\r\n+--------+------------------+\r\n"); + printf("| 状态位 | 状态信息 |\r\n"); + printf("+--------+------------------+\r\n"); + + for(uint16_t i = 0; i < 16; i++) { + if(statusCode.all & (1 << i)) { + printf("| %6d | %-14s |\r\n", i, statusInfo[i]); + printf("+--------+------------------+\r\n"); + } + } + return 0; +} + + + + +// 定时1s更新设备状态 +// 活度计通过网口获取 +// 下挂设备通过485获取 +void UpdatePumpStatus() { + // 更新设备状态 + ReadPumpStatus(0); + ReadPumpStatus(1); + ReadPumpAlarm(0); + ReadPumpAlarm(1); +} + + +// 初始化处理 +static uint8_t HandleInit(uint8_t *rxBuf, uint8_t *txBuf, uint16_t *txLen) { + // 实现初始化逻辑 + InitDeviceStatus(); + return 1; +} + + +// 状态查询处理 +static uint8_t HandleStatusQuery(uint8_t *txBuf) { + // 填充并返回数据 + memcpy(txBuf, &deviceStatus, sizeof(DeviceStatus)); + return sizeof(DeviceStatus); +} + +// 三通阀控制处理 +static uint8_t HandleValveControl(uint8_t *Buff, uint8_t len) { + // 实现三通阀控制逻辑 + + if(len != 8) { + printf("三通阀控制错误\r\n"); + return 0; + } + uint8_t index = Buff[0]; + uint8_t direction = Buff[1]; + uint16_t angle = (Buff[2]<<8) | Buff[3]; + if(angle > 360) { + printf("三通阀控制错误\r\n"); + return 1; + } + if (angle != VALVE_ANGLE_120 && angle != VALVE_ANGLE_210) { + printf("三通阀控制错误\r\n"); + return 1; + } + + // 具体实现 + + + // 更新三通阀状态 + updateValveStatus(index, angle); + return 0; +} + +// 泵时长控制处理 +static uint8_t HandlePumpTimeControl(uint8_t *Buff, uint8_t len) { + // 实现泵时长控制逻辑 + + // 暂未知控制方法,是直接设置泵运行时间,还是设置泵运行步数 + + return 1; +} + +// 泵速度设置处理 +static uint8_t HandlePumpSpeedControl(uint8_t *Buff, uint8_t len) { + // 实现泵速度设置逻辑 + if(len != 4) { + printf("泵速度设置错误\r\n"); + return 0; + } + uint8_t index = Buff[0]; + uint8_t speed = Buff[1]; + if (speed > 100) { + printf("泵速度设置错误\r\n"); + return 0; + } + WritePumpSpeed(index, speed); + + index = Buff[2]; + speed = Buff[3]; + if (speed > 100) { + printf("泵速度设置错误\r\n"); + return 0; + } + WritePumpSpeed(index, speed); + + return 1; +} + +static uint8_t HandlePumpStepControl(uint8_t *Buff, uint8_t len) { + if(len != 10) { + printf("泵步进设置错误\r\n"); + return 0; + } + uint8_t index = Buff[0]; + int32_t step = (Buff[1]<<24) | (Buff[2]<<16) | (Buff[3]<<8) | Buff[4]; + WritePumpStep(index, step); + + index = Buff[5]; + step = (Buff[6]<<24) | (Buff[7]<<16) | (Buff[8]<<8) | Buff[9]; + WritePumpStep(index, step); + + return 1; +} + +// 软急停功能处理 +static uint8_t HandleSoftStop(uint8_t *rxBuf, uint16_t rxLen) { + if(rxLen != 1) { + printf("软急停设置错误\r\n"); + return 1; + } + // 实现软急停功能逻辑 + if(rxBuf[0] == 0) { +// 正常状态 + updateEmergencyStop(ESTOP_NORMAL); + } + else { +// 急停状态 + updateEmergencyStop(ESTOP_PRESSED); + } + return 0; +} + + +CmdFrameError_t checkHostCmd(uint8_t *rxBuf, uint16_t rxLen) { + // 检查命令是否正确 + if (memcmp(rxBuf, FRAME_HEADER, 4) != 0) + { + return CMD_FRAME_HEADER_ERROR; + } + if (memcmp(rxBuf + rxLen - 4, FRAME_TAIL, 4) != 0) + { + return CMD_FRAME_TAIL_ERROR; + } + uint16_t crc = CalculateCRC16(rxBuf+4, rxLen - 8);// 计算crc,不包含帧头和帧尾 + if (memcmp(rxBuf + rxLen - 4, &crc, 2) != 0) + { + return CMD_FRAME_CHECK_ERROR; + } + return CMD_FRAME_OK; +} + + +// 上位机命令处理函数,采用的自定协议,非modbus协议 +// rxBuf: 接收到的数据 +// rxLen: 接收到的数据长度 +CmdFrameError_t ProcessHostCommand(uint8_t *rxBuf, uint16_t rxLen) { + + CmdFrameError_t error = checkHostCmd(rxBuf, rxLen); + if (error != CMD_FRAME_OK) + { + return error; + } + + uint16_t cmdCode = (rxBuf[sizeof(FRAME_HEADER)] << 8) | rxBuf[sizeof(FRAME_HEADER)+1];//提取命令码 + uint8_t dataLen = rxBuf[sizeof(FRAME_HEADER)+2];//提取数据长度 + uint8_t *data = &rxBuf[sizeof(FRAME_HEADER)+3];//提取数据 switch(cmdCode) { case CMD_STATUS_QUERY: - result = HandleStatusQuery(data, txBuf, txLen); + error = HandleStatusQuery(data, dataLen); break; case CMD_VALVE_CTRL: - result = HandleValveControl(data, txBuf, txLen); + error = HandleValveControl(data, dataLen); break; case CMD_PUMP_RUN_TIME: - result = HandlePumpTimeControl(data, txBuf, txLen); + error = HandlePumpTimeControl(data, dataLen); break; case CMD_PUMP_RUN_SPEED: - result = HandlePumpSpeedControl(data, txBuf, txLen); + error = HandlePumpSpeedControl(data, dataLen); break; case CMD_SOFT_STOP: - result = HandleSoftStop(data, txBuf, txLen); + error = HandleSoftStop(data, dataLen); break; case CMD_PUMP_RUN_STEP: - result = HandlePumpStep(data, txBuf, txLen); + error = HandlePumpStep(data, dataLen); break; case CMD_SYSTEM_INIT: - result = HandleInit(data, txBuf, txLen); + error = HandleInit(data, dataLen); break; default: - *txLen = 1; - txBuf[0] = 0; - result = 0; + error = CMD_FRAME_CMD_ERROR; break; } - return result; + return error; } \ No newline at end of file diff --git a/protocol.h b/protocol.h index 42b789d..8631e5b 100644 --- a/protocol.h +++ b/protocol.h @@ -15,6 +15,15 @@ #define CMD_SOFT_STOP 0x0005 // 软急停功能 #define CMD_PUMP_RUN_STEP 0x0006 // 泵步进设置 #define CMD_SYSTEM_INIT 0x0007 // 系统初始化 +// 命令帧错误码定义 +typedef enum { + CMD_FRAME_OK = 0, + CMD_FRAME_HEADER_ERROR = -1, + CMD_FRAME_TAIL_ERROR = -2, + CMD_FRAME_CHECK_ERROR = -3, + CMD_FRAME_CMD_ERROR = -4, +} CmdFrameError_t; + // MOONS’驱动器支持的Modbus功能码如下: @@ -46,26 +55,33 @@ 14 调用的Q程序段为空 15 存储器错误 */ +// 使用联合体表示 -typedef enum { - ALARM_POSITION_ERROR = 0, - ALARM_CCW_LIMIT = 1, - ALARM_CW_LIMIT = 2, - ALARM_OVER_TEMP = 3, - ALARM_INTERNAL_VOLTAGE_ERROR = 4, - ALARM_OVER_VOLTAGE = 5, - ALARM_UNDER_VOLTAGE = 6, - ALARM_OVER_CURRENT = 7, - ALARM_MOTOR_WINDING_SWITCH = 8, - ALARM_MOTOR_ENCODER_ERROR = 9, - ALARM_COMMUNICATION_ERROR = 10, - ALARM_PARAMETER_SAVE_FAILED = 11, - ALARM_MOTOR_UNDER_LOAD = 13, - ALARM_EMPTY_Q_PROGRAM = 14, - ALARM_MEMORY_ERROR = 15, -} AlarmCode_t; +// 告警寄存器联合体定义 +typedef union { + struct { + uint16_t position_error:1; // 位0: 位置误差超限 + uint16_t ccw_limit:1; // 位1: CCW方向禁止限位 + uint16_t cw_limit:1; // 位2: CW方向禁止限位 + uint16_t over_temp:1; // 位3: 驱动器过温 + uint16_t voltage_error:1; // 位4: 驱动器内部电压错误 + uint16_t over_voltage:1; // 位5: 驱动器过压 + uint16_t under_voltage:1; // 位6: 驱动器欠压 + uint16_t over_current:1; // 位7: 驱动器过流 + uint16_t winding_switch:1; // 位8: 电机绕组开关 + uint16_t encoder_error:1; // 位9: 电机编码器信号错误 + uint16_t comm_error:1; // 位10: 通讯异常 + uint16_t param_save_failed:1; // 位11: 参数保存失败 + uint16_t motor_disabled:1; // 位12: 在电机未使能时命令其运转 + uint16_t motor_overload:1; // 位13: 电机重载状态 + uint16_t empty_q_program:1; // 位14: 调用的Q程序段为空 + uint16_t memory_error:1; // 位15: 存储器错误 + } bits; + uint16_t all; // 访问完整的16位寄存器 +}AlarmCode_t; -const uint8_t armInfo[16][32]={ +// 用于输出具体的告警信息字符串 +const uint8_t alarmInfo[16][32]={ "位置误差超限", "CCW方向禁止限位", "CW方向禁止限位", @@ -109,22 +125,25 @@ const uint8_t armInfo[16][32]={ 15 初始化(步进系),伺服准备好(伺服系) */ -typedef enum { - STATUS_ENABLE = 0, - STATUS_SAMPLE = 1, - STATUS_FAULT = 2, - STATUS_POSITION_REACHED = 3, - STATUS_MOVING = 4, - STATUS_POINT_MOVE = 5, - STATUS_DECELERATING = 6, - STATUS_WAIT_INPUT = 7, - STATUS_PARAMETER_SAVE = 8, - STATUS_ALARM = 9, - STATUS_RETURN_HOME = 10, - STATUS_WAIT_TIME = 11, - STATUS_ENCODER_CHECK = 13, - STATUS_Q_PROGRAM_RUN = 14, - STATUS_INIT = 15, +typedef union { + struct { + uint16_t enable:1; // 位0: 使能 + uint16_t sample:1; // 位1: 采样中(软件示波器功能开启) + uint16_t fault:1; // 位2: 驱动器报故障 + uint16_t position_reached:1; // 位3: 运动到位 + uint16_t moving:1; // 位4: 运动中 + uint16_t point_move:1; // 位5: 点动运行中 + uint16_t decelerating:1; // 位6: 减速中 + uint16_t wait_input:1; // 位7: 等待输入信号(例如执行WI指令) + uint16_t parameter_save:1; // 位8: 参数保存中 + uint16_t alarm:1; // 位9: 驱动器报警告 + uint16_t return_home:1; // 位10: 回原点中 + uint16_t wait_time:1; // 位11: 等待时间(例如执行WT、WD指令) + uint16_t encoder_check:1; // 位12: 编码器检测中 + uint16_t q_program_run:1; // 位13: Q程序运行中 + uint16_t init:1; // 位14: 初始化(步进系),伺服准备好(伺服系) + } bits; + uint16_t all; } StatusCode_t; const uint8_t statusInfo[16][32]={ "使能", @@ -170,6 +189,8 @@ const uint8_t statusInfo[16][32]={ #define RTU_PUMP_CMD_VE 0x001D // 速度 #define RTU_PUMP_CMD_DI 0x001E // 目标位置 +#define RTU_PUMP_CMD_SC 0x4002 // 状态寄存器 +#define RTU_PUMP_CMD_AL 0x4001 // 告警寄存器 // 错误码定义 typedef enum { @@ -249,6 +270,11 @@ typedef struct { } DeviceStatus; +static uint8_t pumpName[2][10] = { + "Pump1", + "Pump2" +}; + // 定义协议消息结构 typedef struct { uint8_t device_id; @@ -256,13 +282,16 @@ typedef struct { uint8_t reg_addr[2]; uint8_t reg_cnt[2]; uint8_t data_cnt; - uint8_t data[0];//柔性数组,大小由data_cnt决定 - uint8_t crc[2]; + uint8_t data[];//柔性数组,大小由data_cnt决定 + // uint8_t crc[2]; } RTU_Frame; // 函数声明 -uint8_t ProcessCommand(uint8_t *rxBuf, uint16_t rxLen, uint8_t *txBuf, uint16_t *txLen); -uint16_t CalculateCRC16(uint8_t *data, uint16_t length); - +CmdFrameError_t ProcessHostCommand(uint8_t *rxBuf, uint16_t rxLen); +// uint16_t CalculateCRC16(uint8_t *data, uint16_t length); +void InitDeviceStatus(); +void DecodePumpAlarmMsg(uint16_t reg4001); +void DecodePumpStatusMsg(uint16_t reg4002); +void UpdatePumpStatus(); #endif // PROTOCOL_H \ No newline at end of file