stm32 Modbus-RTU Master 主机程序源码,modbus slave
ModbusRTU_Master.c ModbusRTU_Master.h 加入到工程中
初始化串口设备
调用函数接口
cpp
/*
* ModbusRTU_Master.c
*
*/
#include <ModbusRTU_Master.h>
#include "main.h"
extern UART_HandleTypeDef huart2;
uint8_t BytetoBit[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
funcState_t sendMessage(char *msg, uint16_t len)
{
uartState_t stateTx;
stateTx = HAL_UART_Transmit_IT(&huart2, (uint8_t *)msg, len);
if(stateTx == uartOkState)
{
return funcOk;
}
else
{
return funcErr;
}
}
funcState_t takeMessage(char *msg, uint16_t len, uint8_t SlaveID)
{
uartState_t stateRx;
crcState_t crcCheck;
uint16_t CRCVal, rxCRC;
stateRx = HAL_UART_Receive(&huart2, (uint8_t *)msg, len, 100);
rxCRC = (msg[len -1] << 8) | (msg[len - 2]);
CRCVal = MODBUS_CRC16(msg, len - 2);
if(CRCVal == rxCRC)
{
crcCheck = crcOk;
}
else
{
crcCheck = crcErr;
}
if(stateRx == uartOkState && crcCheck == crcOk && msg[0] == SLAVEID)
{
return funcOk;
}
else
{
return funcErr;
}
}
/*
* @brief Modbus_ReadHoldingRegister, Reads Holding Register #0x03
*
* @param SlaveID = Slave address to be read
*
* @param StartAddress = First address of the register to be read
*
* @param NumberOfReg = Number of register to be read
*
* @funcState_t returns funcOk if the received data CRC and SlaveID is true after the sent data
*/
funcState_t Modbus_ReadHoldingRegister(uint8_t SlaveID, uint16_t StartAddress, uint16_t NumberOfReg)
{
uint16_t CRCVal = 0;
funcState_t funcTxState, funcRxState;
uint8_t i, m = 0;
char ModbusRx[BUFFERSIZE];
char ModbusTx[8];
memset(ModbusTx, 0, 8);
ModbusTx[0] = SlaveID;
ModbusTx[1] = ReadHoldingRegister;
ModbusTx[2] = StartAddress >> 8;
ModbusTx[3] = (uint8_t)(StartAddress & 0x00FF);
ModbusTx[4] = NumberOfReg >> 8;
ModbusTx[5] = (uint8_t)(NumberOfReg & 0x00FF);
CRCVal = MODBUS_CRC16(ModbusTx, 6);
ModbusTx[6] = (uint8_t)(CRCVal & 0x00FF);
ModbusTx[7] = CRCVal >> 8;
funcTxState = sendMessage(&ModbusTx[0], 8);
if(funcTxState == funcOk)
{
funcRxState = takeMessage(ModbusRx, 5 + (NumberOfReg * 2), SlaveID);
}
if(funcRxState == funcOk)
{
for(i = 0; i < NumberOfReg; i++)
{
ModbusRegister[StartAddress + i] = (uint16_t)((ModbusRx[3 + m] << 8) | (ModbusRx[4 + m]));
m += 2;
}
}
return funcRxState;
}
/*
* @brief Modbus_ReadHoldingRegister, Reads Holding Register #0x03
*
* @param SlaveID = Slave address to be read
*
* @param RegAddress = Address of the register to be write
*
* @param RegValue = Value to be write to register
*
* @funcState_t returns funcOk if the received data CRC and SlaveID is true after the sent data
*/
funcState_t Modbus_WriteSingleRegister(uint8_t SlaveID, uint16_t RegAddress, uint16_t RegValue)
{
uint16_t CRCVal = 0;
funcState_t funcTxState, funcRxState;
char ModbusRx[BUFFERSIZE];
char ModbusTx[8];
memset(ModbusTx, 0, 8);
ModbusTx[0] = SlaveID;
ModbusTx[1] = WriteSingleRegister;
ModbusTx[2] = (uint8_t)(RegAddress >> 8);
ModbusTx[3] = (uint8_t)(RegAddress & 0x00FF);
ModbusTx[4] = (uint8_t)(RegValue >> 8);
ModbusTx[5] = (uint8_t)(RegValue & 0x00FF);
CRCVal = MODBUS_CRC16(ModbusTx, 6);
ModbusTx[6] = (uint8_t)(CRCVal & 0x00FF);
ModbusTx[7] = CRCVal >> 8;
funcTxState = sendMessage(&ModbusTx[0], 8);
if(funcTxState == funcOk)
{
funcRxState = takeMessage(ModbusRx, 8, SlaveID);
}
return funcRxState; //CRC and ID is true.
}
/*
* @brief Modbus_ReadCoil, Reads Coils #0x01
*
* @param SlaveID = Slave address to be read
*
* @param StartAddress = First address of the coil to be read
*
* @param NumberOfCoil = Number of coils to be read
*
* @funcState_t returns funcOk if the received data CRC and SlaveID is true after the sent data
*/
funcState_t Modbus_ReadCoil(uint8_t SlaveID, uint16_t StartAddress, int16_t NumberOfCoil)
{
uint16_t CRCVal = 0, Modbus_i, ByteCounter = 0, BitCounter = 0;
funcState_t funcTxState, funcRxState;
char ModbusRx[BUFFERSIZE];
char ModbusTx[8];
uint8_t NumberOfByte;
NumberOfByte = findByte(NumberOfCoil);
ModbusTx[0] = SlaveID;
ModbusTx[1] = ReadCoil;
ModbusTx[2] = (uint8_t)(StartAddress >> 8);
ModbusTx[3] = (uint8_t)(StartAddress & 0x00FF);
ModbusTx[4] = (uint8_t)(NumberOfCoil >> 8);
ModbusTx[5] = (uint8_t)(NumberOfCoil & 0x00FF);
CRCVal = MODBUS_CRC16(ModbusTx, 6);
ModbusTx[6] = (uint8_t)(CRCVal & 0x00FF);
ModbusTx[7] = CRCVal >> 8;
funcTxState = sendMessage(&ModbusTx[0], 8);
if(funcTxState == funcOk)
{
funcRxState = takeMessage(ModbusRx, 5 + NumberOfByte, SlaveID);
}
if(funcRxState == funcOk)
{
for(Modbus_i = 0; Modbus_i < NumberOfCoil; Modbus_i++)
{
ModbusCoil[StartAddress + Modbus_i] = (bool)(ModbusRx[3 + ByteCounter] & BytetoBit[BitCounter]);
BitCounter++;
if(Modbus_i % 8 == 7)
{
ByteCounter++;
BitCounter = 0;
}
}
}
return funcRxState;
}
/*
* @brief Modbus_WriteSingleCoil, Writes Holding Register #0x05
*
* @param SlaveID = Slave address to be read
*
* @param RegAddress = First address of the coil to be write
*
* @param CoilState = coilOn or coilOff @def group coilState_t
*
* @funcState_t returns funcOk if the received data CRC and SlaveID is true after the sent data
*/
funcState_t Modbus_WriteSingleCoil(uint8_t SlaveID, uint16_t RegAddress, coilState_t CoilState)
{
uint16_t CRCVal = 0;
funcState_t funcTxState, funcRxState;
char ModbusRx[BUFFERSIZE];
char ModbusTx[8];
ModbusTx[0] = SlaveID;
ModbusTx[1] = WriteSingleCoil;
ModbusTx[2] = (uint8_t)(RegAddress >> 8);
ModbusTx[3] = (uint8_t)(RegAddress & 0x00FF);
ModbusTx[4] = CoilState;
ModbusTx[5] = 0x00;
CRCVal = MODBUS_CRC16(ModbusTx, 6);
ModbusTx[6] = (uint8_t)(CRCVal & 0x00FF);
ModbusTx[7] = CRCVal >> 8;
funcTxState = sendMessage(&ModbusTx[0], 8);
if(funcTxState == funcOk)
{
funcRxState = takeMessage(ModbusRx, 8, SlaveID);
}
return funcRxState; //CRC and ID is true.
}
/*
* @brief Modbus_WriteSingleCoil, Writes Holding Register #0x15
*
* @param SlaveID = Slave address to be read
*
* @param StartAddress = First address of the coil to be read
*
* @param NumberOfCoils = Number of coils to be write
*
* @param coilValue = Array of values to write to coils
*
* @funcState_t returns funcOk if the received data CRC and SlaveID is true after the sent data
*/
funcState_t Modbus_WriteMultipleCoils(uint8_t SlaveID, uint16_t StartAddress, uint16_t NumberOfCoils, char *coilValue)
{
uint16_t CRCVal = 0;
uint8_t i, NumberOfByte;
funcState_t funcTxState, funcRxState;
char ModbusRx[BUFFERSIZE];
char ModbusTx[8];
ModbusTx[0] = SlaveID;
ModbusTx[1] = WriteMultipleCoils;
ModbusTx[2] = (uint8_t)(StartAddress >> 8);
ModbusTx[3] = (uint8_t)(StartAddress & 0x00FF);
ModbusTx[4] = (uint8_t)(NumberOfCoils >> 8);
ModbusTx[5] = (uint8_t)(NumberOfCoils & 0x00FF);
NumberOfByte = findByte(NumberOfCoils - 1);
ModbusTx[6] = NumberOfByte;
for(i = 0; i < NumberOfByte ; i++)
{
ModbusTx[7 + i] = coilValue[i];
}
CRCVal = MODBUS_CRC16(ModbusTx, 8 + i);
ModbusTx[8 + i] = (uint8_t)(CRCVal & 0x00FF);
ModbusTx[9 + i] = CRCVal >> 8;
funcTxState = sendMessage(&ModbusTx[0], 10 + i);
if(funcTxState == funcOk)
{
funcRxState = takeMessage(ModbusRx, 8, SlaveID);
}
return funcRxState; //CRC and ID is true.
}
/*
* @brief Modbus_WriteSingleCoil, Writes Holding Register #0x16
*
* @param SlaveID = Slave address to be read
*
* @param StartAddress = First address of the coil to be read
*
* @param NumberOfReg = Number of registers to be write
*
* @param regValue = Array of values to write to registers
*
* @funcState_t returns funcOk if the received data CRC and SlaveID is true after the sent data
*/
funcState_t Modbus_WriteMultipleRegisters(uint8_t SlaveID, uint16_t StartAddress, uint16_t NumberOfReg, uint16_t *regValue)
{
uint16_t CRCVal = 0;
uint8_t i, m = 0;
funcState_t funcTxState, funcRxState;
char ModbusRx[BUFFERSIZE];
char ModbusTx[8];
ModbusTx[0] = SlaveID;
ModbusTx[1] = WriteMultipleRegisters;
ModbusTx[2] = (uint8_t)(StartAddress >> 8);
ModbusTx[3] = (uint8_t)(StartAddress & 0x00FF);
ModbusTx[4] = (uint8_t)(NumberOfReg >> 8);
ModbusTx[5] = (uint8_t)(NumberOfReg & 0x00FF);
ModbusTx[6] = NumberOfReg * 2;
for(i = 0; i < NumberOfReg * 2 ; i += 2)
{
ModbusTx[7 + i] = (uint8_t)(regValue[m] >> 8);
ModbusTx[8 + i] = (uint8_t)(regValue[m] & 0x00FF);
m++;
}
CRCVal = MODBUS_CRC16(ModbusTx, 8 + i);
ModbusTx[8 + i] = (uint8_t)(CRCVal & 0x00FF);
ModbusTx[9 + i] = CRCVal >> 8;
funcTxState = sendMessage(&ModbusTx[0], 10 + i);
if(funcTxState == funcOk)
{
funcRxState = takeMessage(ModbusRx, 8, SlaveID);
}
return funcRxState; //CRC and ID is true.
}
uint8_t findByte(int16_t NumberOfCoil)
{
volatile uint8_t NumberOfByte = 0;
while(NumberOfCoil >= 0)
{
NumberOfCoil -= 8;
NumberOfByte++;
if(NumberOfCoil < 0)
{
break;
}
}
return NumberOfByte;
}
uint16_t MODBUS_CRC16(char *buf, uint8_t len )
{
static const uint16_t table[2] = { 0x0000, 0xA001 };
uint16_t crc = 0xFFFF;
unsigned int i = 0;
char bit = 0;
unsigned int xor = 0;
for( i = 0; i < len; i++ )
{
crc ^= buf[i];
for( bit = 0; bit < 8; bit++ )
{
xor = crc & 0x01;
crc >>= 1;
crc ^= table[xor];
}
}
return crc;
}
cpp
/*
* ModbusRTU_Master.h
*
*/
#ifndef INC_MODBUSRTU_MASTER_H_
#define INC_MODBUSRTU_MASTER_H_
#include "stdbool.h"
#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "stdbool.h"
#define SLAVEID 1
#define NUMBER_OF_REGISTER 10
#define NUMBER_OF_COIL 16
#define BUFFERSIZE (NUMBER_OF_REGISTER * 2 + 5)
uint16_t ModbusRegister[NUMBER_OF_REGISTER];
bool ModbusCoil[NUMBER_OF_COIL];
enum
{
ReadCoil = 0x01,
ReadHoldingRegister = 0x03,
WriteSingleCoil = 0x05,
WriteSingleRegister = 0x06,
WriteMultipleCoils = 0x0F,
WriteMultipleRegisters = 0x10,
};
typedef enum
{
uartOkState,
uartErrState,
}uartState_t;
typedef enum
{
crcOk,
crcErr,
}crcState_t;
typedef enum
{
funcOk,
funcErr,
}funcState_t;
typedef enum
{
coilOff = 0x00,
coilOn = 0xFF,
}coilState_t;
/*Data transmit and receive func*/
funcState_t sendMessage(char *msg, uint16_t len);
funcState_t takeMessage(char *msg, uint16_t len, uint8_t SlaveID);
/****************************************** MODBUS Command Function ******************************************************/
funcState_t Modbus_ReadHoldingRegister(uint8_t SlaveID, uint16_t StartAddress, uint16_t NumberOfReg);
funcState_t Modbus_WriteSingleRegister(uint8_t SlaveID, uint16_t RegAddress, uint16_t RegValue);
funcState_t Modbus_ReadCoil(uint8_t SlaveID, uint16_t StartAddress, int16_t NumberOfCoil);
funcState_t Modbus_WriteSingleCoil(uint8_t SlaveID, uint16_t RegAddress, coilState_t CoilState);
funcState_t Modbus_WriteMultipleCoils(uint8_t SlaveID, uint16_t StartAddress, uint16_t NumberOfCoils, char *coilValue);
funcState_t Modbus_WriteMultipleRegisters(uint8_t SlaveID, uint16_t StartAddress, uint16_t NumberOfReg, uint16_t *regValue);
/**************************************************************************************************************************/
uint8_t findByte(int16_t NumberOfCoil);
uint16_t MODBUS_CRC16(char *buf, uint8_t len );
#endif /* INC_MODBUSRTU_MASTER_H_ */
stm32 Modbus-RTU Master 主机程序源码,modbus-RTU slave,modbus slave