当前位置: 首页 > 工具软件 > Modbus-c# > 使用案例 >

Modbus通讯协议的C语言实现

刘阳荣
2023-12-01

刚写完一个modbus通讯协议,调试完,整理出来了,软件代码只能为大家提供一个思路,仅供参考。

//communication.h
#include "H01_Global\_Define.h"
#include "H01_Global\base_types.h"

#define SIZE_BUF_RECE 100
#define SIZE_BUF_TRAN 100
	 
#define TRANS_TIMER_DELAY_1MS    1
#define TRANS_TIMER_DELAY_10MS   10
#define TRANS_TIMER_DELAY_100MS  100
#define TRANS_TIMER_DELAY_1S   1000
	 
typedef union
{
	uint16_t word;
	struct 
	{
		uint8_t low;
		uint8_t high;
	}byte;
	struct
	{
		uint8_t bit0:1;
		uint8_t bit1:1;
		uint8_t bit2:1;
		uint8_t bit3:1;
		uint8_t bit4:1;
		uint8_t bit5:1;
		uint8_t bit6:1;
		uint8_t bit7:1;
		uint8_t bit8:1;
		uint8_t bit9:1;
		uint8_t bit10:1;
		uint8_t bit11:1;
		uint8_t bit12:1;
		uint8_t bit13:1;
		uint8_t bit14:1;
		uint8_t bit15:1;
	}BIT;
}WORD_BYTE;

typedef struct 
{
	uint32_t MODBUS_Reg_Set_Speed;
	uint32_t MODBUS_Reg_Set_Enable_VSP;
	uint32_t MODBUS_Reg_Set_Dir;
	uint32_t MODBUS_Reg_Force_Stop;
}MODBUS_HOLDING_REGISTORS;

typedef struct
{
	uint32_t MODBUS_Reg_Get_Motor_Type;
	uint32_t MODBUS_Reg_Get_Software_Version;
	uint32_t MODBUS_Reg_Get_Running_Status;
	uint32_t MODBUS_Reg_Get_Running_Speed;
	uint32_t MODBUS_Reg_Get_Phase_Current;
	uint32_t MODBUS_Reg_Get_IPM_Temperature;
	uint32_t MODBUS_Reg_Get_DC_Voltage;
	uint32_t MODBUS_Reg_Get_Running_Dir;
	uint32_t MODBUS_Reg_Get_Errors;
}MODBUS_INPUT_REGISTORS;

typedef struct
{
	uint32_t dev_comm;
	uint32_t delay_tran;
	uint32_t Function_Code;
	uint32_t flag_state;
	uint32_t addr_dev;
	uint32_t pt_tran;
	uint32_t pt_rece;
	uint32_t len_tran;
	uint32_t len_rece;
	uint32_t xorsum_rece;
	uint32_t addsum_rece;
	uint32_t xorsum_tran;
	uint32_t addsum_tran;
	uint32_t flag_trans_start;
	uint32_t flag_trans_end;
	uint32_t flag_trans_timer_ON;
	uint32_t count_trans_timer_1ms;
	uint32_t count_trans_timer_10ms;
	uint32_t count_trans_timer_100ms;
	uint32_t count_trans_timer_1s;
	WORD_BYTE address_reg;
	WORD_BYTE num_reg;
	uint32_t buf_rece[SIZE_BUF_RECE];
	uint32_t buf_tran[SIZE_BUF_TRAN];
	MODBUS_HOLDING_REGISTORS Modbus_Holding_Reg ;
	MODBUS_INPUT_REGISTORS Modbus_Input_Reg;
}MODBUS_COMM;


extern void Uart_Trans(void);
extern void Uart_Receive(void);
extern void Init_Modbus(void);
extern void Timer_Task(void);
extern void Proc_Modbus_Data(void);
extern uint32_t Read_Reg_Modbus(MODBUS_COMM *modbus);
void Set_Reg_Modbus(MODBUS_COMM *modbus, WORD_BYTE data);
extern void CRC_Rece_Check(void);
extern uint32_t Flag_Trans_End;
extern uint32_t Timer_Count;
extern uint32_t Timer_1s;
// communication.c
#include "H05_User\AllInOne.h"
/*****************************************************************************/
/* Local pre-processor symbols/macros ('#define')                            */
/*****************************************************************************/
#define MAX_DEV_COMM 4
#define DELAY_SENT 20
/*****************************************************************************/
/* Global variable definitions (declared in header file with 'extern')       */
/*****************************************************************************/

/*****************************************************************************/
/* Local type definitions ('typedef')                                        */
/*****************************************************************************/
typedef enum
{
	Reg_Set_Speed = 100,  //100
	Reg_Set_Enable_VSP,   //101
	Reg_Set_Dir,         //102
	Reg_Force_Stop
}Modbus_Holding_Registors;

typedef enum
{
	Reg_Get_Motor_Type = 200, //200
	Reg_Get_Software_Version, //201
	Reg_Get_Running_Status,   //202
	Reg_Get_Running_Speed,    //203
	Reg_Get_Phase_Current,    //204
	Reg_Get_IPM_Temperature,  //205
	Reg_Get_DC_Voltage,       //206
	Reg_Get_Running_Dir,      //207
	Reg_Get_Errors            //208
}Modbus_Input_Registors;

enum
{
	MODBUS_State_Idle = 0,
	MODBUS_State_Receive,
	MODBUS_State_Transmit
};
/*****************************************************************************/
/* Local variable definitions ('static')                                     */
/*****************************************************************************/
uint32_t Timer_Count;
uint32_t Timer_1s;
uint32_t Flag_Trans_End;
extern uint32_t Software_Version;
extern MODBUS_COMM modbus_comm;
extern MODBUS_COMM *modbus;


void Init_Modbus()
{
	uint32_t temp = 0;
	
	modbus = &modbus_comm;
	modbus->addr_dev = 1;
	modbus->dev_comm = 0;
	modbus->delay_tran = 0;
	modbus->Function_Code = 0;
	modbus->flag_state = MODBUS_State_Idle;
	modbus->pt_tran = 0;
	modbus->pt_rece = 0;
	modbus->len_tran = 0;
	modbus->len_rece = 0;
	modbus->xorsum_rece = 0;
	modbus->xorsum_tran = 0;
	modbus->addsum_rece = 0;
	modbus->addsum_tran = 0;
	modbus->flag_trans_start = 0;
	modbus->flag_trans_end = 1;
	modbus->flag_trans_timer_ON = 0;
	modbus->count_trans_timer_1ms = 0;
	modbus->count_trans_timer_10ms = 0;
	modbus->count_trans_timer_100ms = 0;
	modbus->count_trans_timer_1s = 0;
	modbus->address_reg.word = 0;
	modbus->num_reg.word = 0;
	for(temp = 0; temp<SIZE_BUF_RECE; temp++)
	{
		modbus->buf_rece[temp] = 0;
	}
	for(temp=0; temp<SIZE_BUF_TRAN; temp++)
	{
		modbus->buf_tran[temp] = 0;
	}
	modbus->Modbus_Input_Reg.MODBUS_Reg_Get_DC_Voltage = 0;
	modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Errors = 0;
	modbus->Modbus_Input_Reg.MODBUS_Reg_Get_IPM_Temperature = 0;
	modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Motor_Type = 0;
	modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Phase_Current = 0;
	modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Running_Dir = 0;
	modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Running_Speed = 0;
	modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Running_Status = 0;
	modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Software_Version = Software_Version;
}

void Uart_Trans()
{
	uint32_t data_trans;
	if(modbus->flag_trans_start)
	{
		if(modbus->pt_tran < modbus->len_tran)
		{
			if(UART_SpiUartGetTxBufferSize() == 0)
			{
				data_trans = modbus->buf_tran[modbus->pt_tran];
				UART_UartPutChar(data_trans);
				modbus->pt_tran++;
				modbus->flag_trans_end = 0;
			}
		}
		else
		{
			modbus->pt_tran = 0;
			modbus->pt_rece = 0;
			modbus->flag_trans_start = 0;
			modbus->flag_trans_end = 1;
			modbus->flag_state = MODBUS_State_Idle;
		}
	}
	else
	{
		modbus->pt_tran = 0;
	}
}

void Uart_Receive()
{
	uint32_t data_rece;
	data_rece = UART_UartGetChar();
	
	if(modbus->flag_state)
	{
		modbus->pt_rece = 0;
	}
	else
	{
		if((modbus->pt_rece)&&(modbus->addr_dev == modbus->buf_rece[0]))
		{
			if(modbus->dev_comm > MAX_DEV_COMM)
			{
				modbus->pt_rece = 0;
			}
			modbus->buf_rece[modbus->pt_rece] = data_rece;
			modbus->pt_rece++;
			if(modbus->pt_rece < 8)
			{
				if(modbus->pt_rece == 7)
				{
					if(modbus->buf_rece[1] >= 0x0F)
					{
						modbus->len_rece = modbus->buf_rece[6]+9;
					}
					else
					{
						modbus->len_rece = 8;
					}
				}
			}
			else if(modbus->pt_rece >= modbus->len_rece)
			{
				modbus->pt_rece = 0;
				modbus->flag_state = MODBUS_State_Receive;
				if(modbus->buf_rece[0])
				{
					modbus->delay_tran = DELAY_SENT;
				}
			}
		}
		else
		{
			if((modbus->addr_dev == data_rece) || (data_rece == 0))
			{
				modbus->buf_rece[0] = data_rece;
				modbus->pt_rece = 1;
			}
		}
	}
	modbus->dev_comm = 0;
}

void Timer_Task()
{
	Timer_Count++;
	if(Timer_Count >= 5000)
	{
		Timer_Count = 0;
		Timer_1s++;
	}
	if(modbus->flag_trans_timer_ON)
	{
		modbus->count_trans_timer_100ms++;
		if(modbus->count_trans_timer_100ms >= TRANS_TIMER_DELAY_100MS)
		{
			modbus->count_trans_timer_100ms = 0;
			modbus->flag_trans_timer_ON = 0;
			modbus->flag_trans_start = 1;
		}
	}
}

uint32_t Read_Reg_Modbus(MODBUS_COMM *modbus)
{
	WORD_BYTE dat;
	uint32_t addr;
	addr = modbus->address_reg.word;
	dat.word = 0;
	if(modbus->Function_Code == 3)
	{
		switch(addr)
		{
		case Reg_Set_Speed:
			dat.word = modbus->Modbus_Holding_Reg.MODBUS_Reg_Set_Speed;
			break;
		case Reg_Set_Enable_VSP:
			dat.word = modbus->Modbus_Holding_Reg.MODBUS_Reg_Set_Enable_VSP;
			break;
		case Reg_Set_Dir:
			dat.word = modbus->Modbus_Holding_Reg.MODBUS_Reg_Set_Dir;
			break;
		case Reg_Force_Stop:
			dat.word = modbus->Modbus_Holding_Reg.MODBUS_Reg_Force_Stop;
			break;
		default:
			break;
		}
	}
	else if(modbus->Function_Code == 4)
	{
		switch(addr)
		{
		case Reg_Get_Motor_Type:
			dat.word = modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Motor_Type;
			break;
		case Reg_Get_Software_Version:
			dat.word = modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Software_Version;
			break;
		case Reg_Get_Running_Status:
			dat.word = modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Running_Status;
			break;
		case Reg_Get_Running_Speed:
			dat.word = modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Running_Speed;
			break;
		case Reg_Get_Phase_Current:
			dat.word = modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Phase_Current;
			break;
		case Reg_Get_IPM_Temperature:
			dat.word = modbus->Modbus_Input_Reg.MODBUS_Reg_Get_IPM_Temperature;
			break;
		case Reg_Get_DC_Voltage:
			dat.word = modbus->Modbus_Input_Reg.MODBUS_Reg_Get_DC_Voltage;
			break;
		case Reg_Get_Running_Dir:
			dat.word = modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Running_Dir;
			break;
		case Reg_Get_Errors:
			dat.word = modbus->Modbus_Input_Reg.MODBUS_Reg_Get_Errors;
			break;
		default:
			break;
		}
	}
	else if((modbus->Function_Code == 6)||(modbus->Function_Code == 16))
	{
	
	}
	
	return (dat.word);
}

void Set_Reg_Modbus(MODBUS_COMM *modbus, WORD_BYTE data)
{
	if(modbus->Function_Code == 3)
	{
	
	}
	else if(modbus->Function_Code == 4)
	{
	
	}
	else if((modbus->Function_Code == 6)||(modbus->Function_Code == 16))
	{
		switch(modbus->address_reg.word)
		{
		case Reg_Set_Speed:
			modbus->Modbus_Holding_Reg.MODBUS_Reg_Set_Speed = data.word;
			break;
		case Reg_Set_Enable_VSP:
			modbus->Modbus_Holding_Reg.MODBUS_Reg_Set_Enable_VSP = data.word;
			break;
		case Reg_Set_Dir:
			modbus->Modbus_Holding_Reg.MODBUS_Reg_Set_Dir = data.word;
			break;
		case Reg_Force_Stop:
			modbus->Modbus_Holding_Reg.MODBUS_Reg_Force_Stop = data.word;
			break;
		default:
			break;
		}
	}
}

void Proc_Modbus_Data()
{
	uint32_t index_modbus;
	uint32_t index;
	WORD_BYTE data;
	
	if(modbus->flag_state == MODBUS_State_Receive)
	{
		modbus->len_tran = 0;
		if(crc16_str_rece(modbus->buf_rece, modbus->len_rece-2))
		{
			modbus->addr_dev = modbus->buf_rece[0];
			modbus->Function_Code = modbus->buf_rece[1];
			modbus->buf_tran[0] = modbus->addr_dev;
			if((modbus->Function_Code&&(modbus->Function_Code<7)) || (modbus->Function_Code == 15) || (modbus->Function_Code == 16))
			{
				modbus->address_reg.byte.high = modbus->buf_rece[2];
				modbus->address_reg.byte.low = modbus->buf_rece[3];
				modbus->num_reg.byte.high = modbus->buf_rece[4];
				modbus->num_reg.byte.low = modbus->buf_rece[5];
				modbus->address_reg.word++;
				if((modbus->Function_Code == 3)||(modbus->Function_Code==4)||(modbus->Function_Code==6)||(modbus->Function_Code==16))
				{
					if((modbus->Function_Code==3)||(modbus->Function_Code==4))
					{
						modbus->buf_tran[1] = modbus->Function_Code;
						modbus->buf_tran[2] = (modbus->num_reg.byte.low<<1);
						modbus->len_tran = modbus->buf_tran[2] + 5;
						index_modbus = 3;
						for(index=0; index<modbus->num_reg.byte.low; index++, modbus->address_reg.word++)
						{
							data.word = Read_Reg_Modbus(modbus);
							modbus->buf_tran[index_modbus++] = data.byte.high;
							modbus->buf_tran[index_modbus++] = data.byte.low;
						}
					}
					else if(modbus->Function_Code == 6)
					{
						for(index=1; index<6; index++)
						{
							modbus->buf_tran[index] = modbus->buf_rece[index];
						}
						modbus->len_tran = 8;
						data.byte.high = modbus->buf_rece[4];
						data.byte.low = modbus->buf_rece[5];
						Set_Reg_Modbus(modbus, data);
					}
					else
					{
						for(index=1; index<6; index++)
						{
							modbus->buf_tran[index] = modbus->buf_rece[index];
						}
						modbus->len_tran = 8;
						index_modbus = 7;
						for(index=0; index<modbus->num_reg.byte.low; index++, modbus->address_reg.word++)
						{
							data.byte.high = modbus->buf_rece[index_modbus++];
							data.byte.low = modbus->buf_rece[index_modbus++];
							Set_Reg_Modbus(modbus, data);
						}
					}
				}
			}
			if(modbus->len_tran)
			{
				crc16_str_sent(modbus->buf_tran, (modbus->len_tran - 2));
				modbus->flag_state = MODBUS_State_Transmit;
				modbus->flag_trans_timer_ON = 1;
				modbus->count_trans_timer_100ms = 0;
			}
			else
			{
				modbus->flag_state = MODBUS_State_Idle;
			}
			
		}
		else
		{
			modbus->flag_state = MODBUS_State_Idle;
		}
	}
}

另外针对CRC校验的代码实现,请移步我的另一篇博客:
链接: CRC校验查表法原理及实现(CRC-16).

以上的代码仅仅是一demo例程,面向电机控制系统的modbus通讯协议,所以在定义寄存器的时候会定义电机运行期间的变量,仅供参考,不要来问我为什么移植到某平台上运行不了这样的问题,这仅仅是项目软件的很小的一个部分,仅提供思路而已。

 类似资料: