Files
testtools/Modbus/Modbus_Function.c
T
2025-09-16 14:44:50 +08:00

429 lines
9.3 KiB
C

#include "Modbus_Function.h"
#include "Modbus_Registers.h"
#include "stm32f1xx_hal.h"
#include "usart.h"
#include "bsp.h"
#include "string.h"
uint8_t MODBUS_SLAVE_ID = 0x01;
/*
帧结构 = 地址 + 功能码+ 数据 + 校验
|--ADDR--|--CMD--|--DAT--|--CRC--|
|--Byte--|--Byte-|-nByte-|-2Byte-|
线圈(Coils)
离散量输入(Discrete Input)
输入寄存器(Input registers)
保持寄存器(Holding registers)
功能码 解释翻译 作用
0x01 Read Coils 读线圈状态 读取远程设备中1到2000个连续的线圈的状态
0x02 Read Discrete Inputs 读离散输入状态 读取远程设备中1到2000个连续的离散输入的状态
0x03 Read Holding Registers 读保持寄存器内容 读取远程设备中1到125个连续的保持寄存器的内容
0x04 Read Input Registers 读输入寄存器内容 读取远程设备中1到125个连续的输入寄存器的内容
0x05 Write Single Coil 写单个线圈 在远程设备中把单个线圈状态改变为打开或关闭的状态
0x06 Write Single Register 写单个保持寄存器 在远程设备中写入单个保持寄存器
0x07 Read Exception Status (Serial Line only) 读取异常状态(仅限串行线路) 读取远程设备中八个异常状态输出的内容
0x08 Diagnostics (Serial Line only) 通信系统诊断(仅限串行线路)
0x0B Get Comm Event Counter (Serial Line only) 获取通讯事件计数器(仅限串行线路) 从远程设备的通信事件计数器获取状态字和事件计数
0x0C Get Comm Event Log (Serial Line only) 获取通讯事件日志(仅限串行线路) 从远程设备获取状态字、事件计数、消息计数和事件字节字段
0x0F Write Multiple Coils 写多个线圈 强制远程设备中线圈序列中的每个线圈接通或断开
0x10 Write Multiple registers 写多个保持寄存器 在远程设备中写入连续寄存器块
0x11 Report Slave ID (Serial Line only) 报导从机信息(仅限串行线路) 读取远程设备特有的类型、当前状态和其他信息的说明。数据内容特定于每种类型的设备
0x14 Read File Record 读取文件记录
0x15 Write File Record 写文件记录
0x16 Mask Write Register 带屏蔽字写入寄存器
0x17 Read/Write Multiple registers 读、写多个寄存器 执行一次连续写和连续读,写入操作在读取之前执行
0x18 Read FIFO Queue 读取先进先出队列
0x2B Encapsulated Interface Transport 封装接口传输
*/
MODEBUS_t modbus;
typedef enum {
ReadCoils = 0x01,
ReadDiscreteInputs = 0x02,
ReadHoldingRegisters = 0x03,
ReadInputRegisters = 0x04,
WriteSingleCoil = 0x05,
WriteSingleRegister = 0x06,
ReadExceptionStatus = 0x07,
Diagnostics = 0x08,
GetCommEventCounter = 0x0B,
GetCommEventLog = 0x0C,
WriteMultipleCoils = 0x0F,
WriteMultipleRegisters = 0x10,
ReportSlaveID = 0x11,
ReadFileRecord = 0x14,
WriteFileRecord = 0x15,
MaskWriteRegister = 0x16,
Read_WriteMultipleregisters = 0x17,
ReadFIFOQueue = 0x18,
EncapsulatedInterfaceTransport = 0x2B
}modbus_cmd_e;
static uint16_t Modbus_CRC16(uint8_t* data, uint16_t length)
{
uint16_t crc = 0xFFFF;
for (int i = 0; i < length; i++) {
crc ^= data[i];
for (int j = 0; j < 8; j++) {
if ((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
void Modbus_Init(void)
{
//串口初始化
//选择485通讯
COMM_setSel(COMM_TYPE_485);
COMM_setDir(COMM_DIR_RX);
SERIAL_Init(&serial3,"UART3",&huart3,50, 50);
serial3.setDir = COMM_setDir;
//设备硬件初始化
SERIAL_StartRecv(&serial3);
//modbus寄存器初始化
memset(&modbus,0,sizeof(modbus));
//函数绑定
Modbus_Write("asdfghjkl",9);
}
uint8_t serial3_buff[50];
void Modbus_Poll(void)
{
//收到主机信息, 绿灯闪
size_t len = SERIAL_Read(&serial3, serial3_buff, 50);
if(len > 4)//这个长度不出意外的话是一包的长度
{
if(serial3_buff[0] == MODBUS_SLAVE_ID)
{
uint16_t crc = serial3_buff[len - 2] | (serial3_buff[len - 1] << 8);
if(crc == Modbus_CRC16(serial3_buff,len-2))
{
//通讯成功,红灯闪烁
LED_setToggle(LED_RED);
/*
0x03 read
0x06 write
0x10 write multi
*/
//赋值给modbus结构体
modbus.addr = serial3_buff[0];
modbus.cmd = serial3_buff[1];
modbus.crc = crc;
memcpy(modbus.payload,&serial3_buff[2],len - 4);
switch(modbus.cmd)
{
case ReadCoils:
{
}break;
case ReadDiscreteInputs:
{
uint16_t regis = modbus.payload[0] | (modbus.payload[1] << 8);
uint16_t value = modbus.payload[2] | (modbus.payload[3] << 8);
}break;
case ReadHoldingRegisters:
{
// 0x03
/*
reg value
0xFF 0xFFFFFFFF
0x00 Di
*/
uint16_t addr = modbus.payload[1] << 0 |
modbus.payload[0] << 8;
uint16_t cmd = modbus.payload[3] << 0 |
modbus.payload[2] << 8;
switch(addr)
{
case 0x00:
{//DI
uint16_t regis = 0x0000;
uint16_t value = SYS_getDi();
uint8_t sendbuff[50] = {0};
size_t send_len = 0;
sendbuff[send_len++] = modbus.addr;
sendbuff[send_len++] = modbus.cmd;
sendbuff[send_len++] = regis;
sendbuff[send_len++] = regis >> 8;
sendbuff[send_len++] = value;
sendbuff[send_len++] = value >> 8;
uint16_t crc_f = Modbus_CRC16(sendbuff,send_len);
sendbuff[send_len++] = crc_f;
sendbuff[send_len++] = crc_f >> 8;
Modbus_Write(sendbuff,send_len);
}break;
case 0x01:
{//ADC
uint16_t regis = 0x0001;
uint16_t value = SYS_getReg();
uint8_t sendbuff[50] = {0};
size_t send_len = 0;
sendbuff[send_len++] = modbus.addr;
sendbuff[send_len++] = modbus.cmd;
sendbuff[send_len++] = regis;
sendbuff[send_len++] = regis >> 8;
sendbuff[send_len++] = value;
sendbuff[send_len++] = value >> 8;
uint16_t crc_f = Modbus_CRC16(sendbuff,send_len);
sendbuff[send_len++] = crc_f;
sendbuff[send_len++] = crc_f >> 8;
Modbus_Write(sendbuff,send_len);
}break;
case 0x02:
{//当前位置
}break;
}
}break;
case ReadInputRegisters:
{
//Modbus_Write(buff,len);
}break;
case WriteSingleCoil:
{
}break;
case WriteSingleRegister:
{//0x06
uint16_t addr = modbus.payload[1] << 0 |
modbus.payload[0] << 8;
uint16_t cmd = modbus.payload[3] << 0 |
modbus.payload[2] << 8;
switch(addr)
{
case 0x00://设置DO输出
{
SYS_setDo(1,(cmd & 0x01));
SYS_setDo(2,(cmd & 0x02));
}break;
case 0x01://设置电机使能
{
MOTOR_setEn((cmd & 0x01)?(MOTOR_ENABLE):(MOTOR_DISABLE));
}break;
case 0x02://设置电机方向
{
MOTOR_setDir((cmd & 0x8000)?(MOTOR_DIR_CW):(MOTOR_DIR_CCW));
}break;
case 0x03://设置电机细分
{
MOTOR_setMS(MOTOR_MS_1);
}break;
case 0x04://设置电机步数
{
MOTOR_setStep(cmd & 0x7fff);
}break;
case 0x05://设置电机步数,同时启动
{
MOTOR_setDir((cmd & 0x8000)?(MOTOR_DIR_CW):(MOTOR_DIR_CCW));
MOTOR_setStep(cmd & 0x7fff);//最大32767步
MOTOR_setEn(MOTOR_ENABLE);
}break;
case 0x06://获取原点
{
MOTOR_setGetFlag(MOTOR_GET_MIN);
MOTOR_setDir(MOTOR_DIR_CCW);
MOTOR_setStep(MOTOR_MAX_STEP);
MOTOR_setEn(MOTOR_ENABLE);
}break;
case 0x07://获取最大值
{
MOTOR_setLenght(0);
MOTOR_setGetFlag(MOTOR_GET_MAX);
MOTOR_setDir(MOTOR_DIR_CW);
MOTOR_setStep(MOTOR_MAX_STEP);
MOTOR_setEn(MOTOR_ENABLE);
}break;
case 0x08://
{
}break;
}
}break;
case ReadExceptionStatus:
{
//Modbus_Write(buff,len);
}break;
case Diagnostics:
{
//Modbus_Write(buff,len);
}break;
case GetCommEventCounter:
{
//Modbus_Write(buff,len);
}break;
case GetCommEventLog:
{
//Modbus_Write(buff,len);
}break;
case WriteMultipleCoils:
{
//Modbus_Write(buff,len);
}break;
case WriteMultipleRegisters:
{
//0x10
//用来写配置数据
}break;
case ReportSlaveID:
{
uint16_t regis = modbus.cmd;
uint16_t value = modbus.addr;
uint8_t sendbuff[50] = {0};
size_t send_len = 0;
sendbuff[send_len++] = modbus.addr;
sendbuff[send_len++] = modbus.cmd;
sendbuff[send_len++] = regis;
sendbuff[send_len++] = regis >> 8;
sendbuff[send_len++] = value;
sendbuff[send_len++] = value >> 8;
uint16_t crc_f = Modbus_CRC16(sendbuff,send_len);
sendbuff[send_len++] = crc_f;
sendbuff[send_len++] = crc_f >> 8;
Modbus_Write(sendbuff,send_len);
}break;
case ReadFileRecord:
{
//Modbus_Write(buff,len);
}break;
case WriteFileRecord:
{
//Modbus_Write(buff,len);
}break;
case MaskWriteRegister:
{
//Modbus_Write(buff,len);
}break;
case Read_WriteMultipleregisters:
{
//Modbus_Write(buff,len);
}break;
case ReadFIFOQueue:
{
//Modbus_Write(buff,len);
}break;
case EncapsulatedInterfaceTransport:
{
//Modbus_Write(buff,len);
}break;
}
}
}
}
}
void Modbus_Write(uint8_t *data, size_t len)
{
//只能一包一包发,不允许一次发很多包
SERIAL_Write(&serial3,data,len);
}