刚写完一个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通讯协议,所以在定义寄存器的时候会定义电机运行期间的变量,仅供参考,不要来问我为什么移植到某平台上运行不了这样的问题,这仅仅是项目软件的很小的一个部分,仅提供思路而已。