我们从2011年坚守至今,只想做存粹的技术论坛。  由于网站在外面,点击附件后要很长世间才弹出下载,请耐心等待,勿重复点击不要用Edge和IE浏览器下载,否则提示不安全下载不了

 找回密码
 立即注册
搜索
查看: 2981|回复: 10

基于STM8S单片机的FREEMODBUS总线协议栈的移植

[复制链接]

该用户从未签到

72

主题

232

回帖

387

积分

二级逆天

积分
387

终身成就奖社区居民社区劳模

QQ
发表于 2015-4-1 09:05:06 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区

您需要 登录 才可以下载或查看,没有账号?立即注册

×
     FreeMODBUS一个奥地利人写的Modbus协议。它是一个针对嵌入式应用的一个免费(自由)的通用MODBUS协议的移植。Modbus是一个工业制造环境中应用的一个通用协议.。
    FreeMODBUS最新版本V1.5。下载地址:http://www.freemodbus.org/index.php?idx=5
   下面进行的移植基于STM8S单片机的官方固件库
   1、物理层接口文件修改(具体应修改接口文件portserial.c及porttimer.c)
    portserial.c文件中:
    void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable)函数设置串口状态。当xRxEnable为真时,应使能串口接收及接收中断。在RS485通讯系统中,还要注意将RS485接口芯片设为接收使能状态;当xTxEnable为真时,应使能串口发送及发送中断。在RS485通讯系统中,还要注意将RS485接口芯片设为发送使能状态。voidvMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) //控制串口的收发中断
{
    if(TRUE==xRxEnable)
    {
        UART1_ITConfig(UART1_IT_RXNE, ENABLE);
    }
    else
    {
        UART1_ITConfig(UART1_IT_RXNE, DISABLE);   
    }

    if(TRUE==xTxEnable)
    {
        UART1_ITConfig(UART1_IT_TXE,ENABLE);
    }
    else
    {
       UART1_ITConfig(UART1_IT_TXE,  DISABLE);
    }
}
BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHARucDataBits, eMBParity eParity)函数初始化串行通讯端口。参数ucPORT可以忽略;参数ulBaudRate是通讯端口的波特率,应根据此数值设置所使用硬件端口的波特率;参数ucDataBits为通讯时所使用的数据位宽,注意,若使用RTU模式,则有ucDataBits=8,若使用ASCII模式,则有ucDataBits=7,应根据此参数设置所使用硬件端口的数据位宽;eParity为校验方式,eParity=MB_PAR_NONE为无校验,此时硬件端口应设置为无校验方式及两个停止位,eParity=MB_PAR_ODD为奇校验,此时硬件端口应设置为奇校验方式及一个停止位,eParity= MB_PAR_EVEN为偶校验,此时硬件端口应设置为偶校验方式及一个停止位。函数返回值务必为TRUE。
BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
      UART1_WordLength_TypeDef databit;
      UART1_Parity_TypeDef parity;
     UART1_DeInit();
        if(8==ucDataBits)
        {
            databit = UART1_WORDLENGTH_8D;
        }
        else
        {
            databit = UART1_WORDLENGTH_9D;        
        }
        if(MB_PAR_NONE == eParity)
        {
            parity = UART1_PARITY_NO;
        }
        else if(MB_PAR_ODD == eParity)
        {
                parity = UART1_PARITY_ODD;        
        }
        else
        {
                parity = UART1_PARITY_EVEN;        
        }
        UART1_Init((uint32_t)ulBaudRate,databit, UART1_STOPBITS_1, parity,
         UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);
    /* ENABLE the USARTx */
    UART1_ITConfig(UART1_IT_TXE, ENABLE);      
    return TRUE;
}
    BOOL xMBPortSerialPutByte( CHAR ucByte )通讯端口发送一字节数据函数。在此函数中编写发送一字节数据的函数。注意,由于使用的是中断发送,故只需将数据放到发送寄存器即可。函数返回值务必为TRUE。
BOOLxMBPortSerialPutByte( CHAR ucByte )
{
    UART1_SendData8(ucByte);
    return TRUE;
}
BOOL xMBPortSerialGetByte( CHAR * pucByte )通讯端口接收一字节数据函数。在此函数中编写接收的函数。由于使用的是中断接收,只需将接收寄存器的值放到* pucByte即可。函数返回值务必为TRUE。
BOOL xMBPortSerialGetByte( CHAR * pucByte )
{
    *pucByte = UART1_ReceiveData8();
    return TRUE;
}
void prvvUARTRxISR( void )和void prvvUARTTxReadyISR( void )无需修改。
portserial.c文件修改
BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )初始化超时定时器播函数。根据所使用的硬件初始化超时定时器,使之能产生中断时间为usTim1Timerout50us*50us的中断,本例移植采用单片机的TIM4定时器。函数返回值务必为TRUE。
BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )
{
  /* TIM4 configuration:
   - TIM4CLK is set to 16 MHz, the TIM4 Prescaler is equal to 128 so the TIM1 counter
   clock used is 16 MHz / 128 = 125 000 Hz
  - With 125 000 Hz we can generate time base:
      max time base is 2.048 ms if TIM4_PERIOD = 255 --> (255 + 1) / 125000 = 2.048 ms
      min time base is 0.016 ms if TIM4_PERIOD = 1   --> (  1 + 1) / 125000 = 0.016 ms
                                                           --> 16us
  - In this example we need to generate a time base equal to 50us
   so TIM4_PERIOD = (0.00005 * 125000 - 1) = 5 */
    /* Time base configuration */
  TIM4_TimeBaseInit(TIM4_PRESCALER_128, 5);
  /* Clear TIM4 update flag */
  TIM4_ClearFlag(TIM4_FLAG_UPDATE);
  /* Enable update interrupt */
  TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);  
  /* enable interrupts */
// enableInterrupts();
  /* Enable TIM4 */
  TIM4_Cmd(ENABLE);
    return TRUE;;
}
void vMBPortTimersEnable(  )使能超时定时器函数。需在此函数中清除中断标志位、清零定时器计数值,并重新使能定时器中断。
void vMBPortTimersEnable(  ) //打开时钟
{
    /* Clear TIM4 update flag */
  TIM4_ClearFlag(TIM4_FLAG_UPDATE);
     /* Enable update interrupt */
  TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
    TIM4_SetCounter(0x00);
     /* Enable TIM4 */
  TIM4_Cmd(ENABLE);
}
void vMBPortTimersDisable(  )关闭超时定时器函数。在此函数中清零定时器计数值,并关闭定时器中断。
void vMBPortTimersDisable(  ) //关闭时钟
{
    TIM4_Cmd(DISABLE);
    TIM4_SetCounter(0x00);
    TIM4_ITConfig(TIM4_IT_UPDATE, DISABLE);
  TIM4_ClearFlag(TIM4_FLAG_UPDATE);
}
void prvvTIMERExpiredISR( void )函数不需修改。
2、 应用层回函数的修改
    在应用层,用户需要定义所需要使用的寄存器,并修改对应的回函数。
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNRegs)输入寄存器回函数。* pucRegBuffer为协议中所需的数据,usAddress为输入寄存器地址,usNRegs为访问寄存器的个数,eMode为访问类型(MB_REG_READ为读保持寄存器,MB_REG_WRITE为写保持寄存器)。用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的寄存器地址usAddress放到相应保持寄存器中。
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    eMBErrorCode  eStatus = MB_ENOERR;
    int iRegIndex;
    if( ( usAddress >= REG_INPUT_START )&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegInputStart );
        while( usNRegs > 0 )
        {
            *pucRegBuffer++ =
                ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
            *pucRegBuffer++ =
                ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNRegs, eMBRegisterMode eMode)保持寄存器回函数。* pucRegBuffer为要协议中的数据,usAddress为输入寄存器地址,usNRegs为访问寄存器的个数,eMode为访问类型(MB_REG_READ为读保持寄存器,MB_REG_WRITE为写保持寄存器)。用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的寄存器地址usAddress放到相应保持寄存器中。
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    int             iRegIndex;
    u16 *PRT=(u16*)pucRegBuffer;
    if( ( usAddress >= REG_HOLDING_START ) && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegHoldingStart );
        switch ( eMode )
        {
         case MB_REG_READ:
            while( usNRegs > 0 )
            {
              ////  *PRT++ = __REV16(usRegHoldingBuf[iRegIndex++]); //数据序转 REV16.W

                       *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] >> 8 );
              *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] & 0xFF );
                      iRegIndex++;
              usNRegs--;
            }
            break;

        case MB_REG_WRITE:
            while( usNRegs > 0 )
            {
              ////  usRegHoldingBuf[iRegIndex++] = __REV16(*PRT++); //数据序转 REV16.W
                    usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
              usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
              iRegIndex++;
              usNRegs--;
            }
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNCoils, eMBRegisterMode eMode )读/写开关寄存器函数。* pucRegBuffer为要添加到协议中的数据,usAddress为地址,usNCoils为要访问的个数,eMode为访问类型(MB_REG_READ为读状态,MB_REG_WRITE为写)。用户应根据要访问的地址usAddress将相应的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的地址usAddress放到相应地址中。
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
    ( void )pucRegBuffer;
    ( void )usAddress;
    ( void )usNCoils;
    ( void )eMode;
    return MB_ENOREG;
}
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )读开关寄存器函数。
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    ( void )pucRegBuffer;
    ( void )usAddress;
    ( void )usNDiscrete;
    return MB_ENOREG;
}
官方网站下载出问题,为了方便大家,附上FreeMODBUS源码 freemodbus-v1.5.0.zip (5.9 MB, 下载次数: 0)
回复

使用道具 举报

该用户从未签到

24

主题

2224

回帖

3257

积分

二级逆天

积分
3257

社区居民忠实会员社区劳模最爱沙发优秀斑竹奖终身成就奖

QQ
发表于 2015-4-1 09:10:13 | 显示全部楼层
不错,可以做来一些类似内容
广告位出租,价格可以商量。
回复

使用道具 举报

该用户从未签到

39

主题

2842

回帖

2077

积分

二级逆天

积分
2077

终身成就奖社区居民忠实会员社区劳模最爱沙发原创达人优秀斑竹奖

QQ
发表于 2015-4-1 11:49:04 | 显示全部楼层
回复

使用道具 举报

该用户从未签到

2

主题

2995

回帖

1284

积分

游客

积分
1284

社区居民忠实会员社区劳模最爱沙发终身成就奖优秀斑竹奖

QQ
发表于 2015-4-2 12:58:53 | 显示全部楼层
谢谢分享   学习一下
困……
回复

使用道具 举报

该用户从未签到

0

主题

12

回帖

3

积分

一级逆天

积分
3

社区居民终身成就奖

QQ
发表于 2015-7-4 19:07:59 | 显示全部楼层
回复

使用道具 举报

该用户从未签到

363

主题

615

回帖

0

积分

二级逆天

积分
0

终身成就奖

QQ
发表于 2016-8-11 15:00:38 | 显示全部楼层
回复

使用道具 举报

该用户从未签到

0

主题

3

回帖

0

积分

一级逆天

积分
0

终身成就奖

QQ
发表于 2017-4-18 17:26:46 | 显示全部楼层
回复

使用道具 举报

  • TA的每日心情
    开心
    4 小时前
  • 签到天数: 55 天

    [LV.5]常住居民I

    2

    主题

    1万

    回帖

    2万

    积分

    三级逆天

    积分
    20564

    终身成就奖特殊贡献奖原创先锋奖优秀斑竹奖

    QQ
    发表于 2018-10-28 09:23:40 | 显示全部楼层
    回复

    使用道具 举报

    该用户从未签到

    5

    主题

    147

    回帖

    0

    积分

    1元学习PADS(5期)

    积分
    0

    终身成就奖

    QQ
    发表于 2018-10-28 17:05:06 | 显示全部楼层
    回复

    使用道具 举报

    该用户从未签到

    5

    主题

    1480

    回帖

    897

    积分

    1元学习Allegro(1期)

    积分
    897

    终身成就奖优秀斑竹奖

    QQ
    发表于 2018-10-28 19:36:02 | 显示全部楼层
    谢谢分享谢谢分享学习下
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    每日签到,有金币领取。


    Copyright ©2011-2024 NTpcb.com All Right Reserved.  Powered by Discuz! (NTpcb)

    本站信息均由会员发表,不代表NTpcb立场,如侵犯了您的权利请发帖投诉

    ( 闽ICP备2024076463号-1 ) 论坛技术支持QQ群171867948 ,论坛问题,充值问题请联系QQ1308068381

    平平安安
    TOP
    快速回复 返回顶部 返回列表