模拟寄存器开发实例总结

本文介绍了一种用于模拟铁路段上设备行为的仿真器开发过程。该仿真器通过编写虚拟寄存器来模拟真实设备,并提供了读写寄存器的操作函数。此外,还详细介绍了MODBUS功能回调函数的实现,用于寄存器的实际读写操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 开发背景
(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)要善于观察,善于比对试验现象的前后不同,推测问题的原因,然后,根据原因进行调试。最终,确定推论。得到一个确定的想要的答案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值