一. 开发背景
(1)模拟仿真仪表,连锁设备完布置完成后,外部铁路段,不一定同步完成,因此不能进行连锁设备的检测,这降低了,作业效率。因此有了模拟仿真器,它可以模拟铁路段上的设备,设备在程序中,体现为不同的寄存器,及寄存器上的不同位。这里程序编写虚拟寄存器,来达到仿真的效果。系统图为:
二. 仿真器部分程序
(1)写入寄存器操作,这里补充说明两个函数。
memcpy(void *dst, void *data, int count); //特点是可以使用于任何类型的数据
strcpy(char *dst, const char *data); //只能使用于字符串
程序如下:
int mbser_write_reg(struct mbserver *ms, uint8_t type, \
u16_t start, u16_t *data, u16_t size)
{
u16_t *tmp_pnt; //暂存寄存器地址
switch (type)
{
case REG_TYPE_INPUT:
if(ms->input_reg == NULL)
{
return -1;
}
tmp_pnt = ms->input_reg;
break;
case REG_TYPE_HOLD:
if(ms->hold_reg == NULL)
{
return -1;
}
tmp_pnt = ms->hold_reg;
break;
case REG_TYPE_COILS:
if(ms->coils_reg == NULL)
{
return -1;
}
tmp_pnt = ms->coils_reg;
break;
case REG_TYPE_DISCRETE:
if(ms->discr_reg == NULL)
{
return -1;
}
tmp_pnt = ms->discr_reg;
break;
default:
return -1;
break;
}
//数据写入寄存器
memcpy(tmp_pnt + start, data, size * 2);
return 1;
}
(2)寄存器读操作,程序如下:
int mbser_read_reg(struct mbserver *ms, u8_t type, \
u16_t start, u16_t *data, u16_t size)
{
u16_t *tmp_pnt; //暂时,存储寄存器地址
if(ms == NULL)
return -1;
//选择指定寄存器
switch (type)
{
case REG_TYPE_INPUT:
if(ms->input_reg == NULL)
{
return -1;
}
tmp_pnt = ms->input_reg;
break;
case REG_TYPE_HOLD:
if(ms->hold_reg == NULL)
{
return -1;
}
tmp_pnt = ms->hold_reg;
break;
case REG_TYPE_COILS:
if(ms->coils_reg == NULL)
{
return -1;
}
tmp_pnt = ms->coils_reg;
break;
case REG_TYPE_DISCRETE:
if(ms->discr_reg == NULL)
{
return -1;
}
tmp_pnt = ms->discr_reg;
break;
default:
return -1;
break;
}
//读取寄存器数据
memcpy(data, tmp_pnt + start, size * 2);
return 1;
}
(3)MODBUS功能回调函数,寄存器的实际读写操作,及其实现程序:
/*****************************************************************************
* MODBUS FUN CODE CALLBACK FUNCTIONS
****************************************************************************/
eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs)
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
#if 1
if( ( usAddress >= 0 )
&& ( usAddress + usNRegs <= 120 ) )
{
iRegIndex = ( int )( usAddress -1)*2;
while( usNRegs > 0 )
{
*pucRegBuffer++ = ( UCHAR )mbser->input_reg[iRegIndex] & 0x00FF;
*pucRegBuffer++ = ( UCHAR )(mbser->input_reg[iRegIndex++] >> 8) & 0xFF;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}
#endif
return eStatus;
}
/* 保持功能回调 */
eMBErrorCode eMBRegHoldingCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
#define REG_HOLDING_START 1
#define REG_HOLDING_NREGS 120
#if 1
if( ( usAddress >= REG_HOLDING_START ) &&
( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
{
iRegIndex = ( int )( usAddress - REG_HOLDING_START );
switch ( eMode )
{
/* Pass current register values to the protocol stack. */
case MB_REG_READ:
while( usNRegs > 0 )
{
*pucRegBuffer++ = ( UCHAR )mbser->hold_reg[iRegIndex] & 0x00FF;
*pucRegBuffer++ = ( UCHAR )(mbser->hold_reg[iRegIndex++] >> 8) & 0xFF;
usNRegs--;
}
break;
/* Update current register values with new values from the
* protocol stack. */
case MB_REG_WRITE:
while( usNRegs > 0 )
{
(mbser->hold_reg[iRegIndex]) = *pucRegBuffer++;
(mbser->hold_reg[iRegIndex++]) |= *pucRegBuffer++ << 8 ;
usNRegs--;
}
// hold_cb(REG_HOLDING_START, mbser->hold_size); //回调函数
}
}
else
{
eStatus = MB_ENOREG;
}
#endif
return eStatus;
}
三. 调试程序
(1)程序使用了 malloc( )函数,即需要开辟堆栈空间,IAR中需要进行一些配置。
操作顺序是:options -> Linker -> Edit… -> Stack/Heap Sizes 。如图:
(2)打开TCP_MODBUS软件测试工具,前面的文章中,有相关的文章,点MODBUS/TCP按钮,就会弹出右侧的窗口,蓝色数字,分别是地址,和数据。编辑框的数字根据程序的配置情况,进行编辑。这里可以进行数据的收发操作,对照IAR调试数据。最终完成程序的调试,定版。
四. 总结
(1)调试程序时,要先打开调试工具,配置好ip地址,串口等,点击自动连接,设置循环时间,不能为0。
(2)要善于观察,善于比对试验现象的前后不同,推测问题的原因,然后,根据原因进行调试。最终,确定推论。得到一个确定的想要的答案。