429 lines
9.3 KiB
C
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);
|
|
}
|
|
|
|
|
|
|
|
|
|
|