论坛风格切换切换到宽版
发帖 回复
返回列表  提醒:不能用迅雷等P2P下载,否则下载失败标(二级)的板块,需二级才能下载,没二级不要购买,下载不了
  • 2932阅读
  • 10回复

基于STM8S单片机的FREEMODBUS总线协议栈的移植 [复制链接]

上一主题 下一主题
离线yake
 

性别:
人妖
发帖
304
金币
475
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看楼主 倒序阅读 使用道具 0楼 发表于: 2015-04-01
关键词: 单片机源码
h%o%fH&F!  
     FreeMODBUS一个奥地利人写的Modbus协议。它是一个针对嵌入式应用的一个免费(自由)的通用MODBUS协议的移植。Modbus是一个工业制造环境中应用的一个通用协议.。 .GsV>H  
    FreeMODBUS最新版本V1.5。下载地址:http://www.freemodbus.org/index.php?idx=5 Gy9$wH@8  
   下面进行的移植基于STM8S单片机的官方固件库 8>trS=;n  
   1、物理层接口文件修改(具体应修改接口文件portserial.c及porttimer.c) K{x\4  
    portserial.c文件中: X}=n:Ql'YY  
    void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable)函数设置串口状态。当xRxEnable为真时,应使能串口接收及接收中断。在RS485通讯系统中,还要注意将RS485接口芯片设为接收使能状态;当xTxEnable为真时,应使能串口发送及发送中断。在RS485通讯系统中,还要注意将RS485接口芯片设为发送使能状态。voidvMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) //控制串口的收发中断 @G BxL*e  
{ -|J"s$yO4  
    if(TRUE==xRxEnable) m4TE5q%3  
    { ^WHE$4U`  
        UART1_ITConfig(UART1_IT_RXNE, ENABLE); @KWb+?_H{<  
    } p31NIf `  
    else *i\Qo  
    { i'a?kSy  
        UART1_ITConfig(UART1_IT_RXNE, DISABLE);     O- ew%@_  
    } OP~HdocB  
ge,H-8'Z  
    if(TRUE==xTxEnable) 9*2[B"5  
    { VeGL)  
        UART1_ITConfig(UART1_IT_TXE,ENABLE); "8c@sHk(w  
    } &qMPq->  
    else )jU)_To  
    { nc~F_i=  
       UART1_ITConfig(UART1_IT_TXE,  DISABLE); I CZ4 A{I  
    } f*!j[U/r_  
}  W,4QzcQR  
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。 bHPYp5UwN  
BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) = 6tHsN23  
{ kjW+QT?T&  
      UART1_WordLength_TypeDef databit; r#+d&.|  
      UART1_Parity_TypeDef parity; NV)!7~r}:  
     UART1_DeInit(); R%Qf7Q  
        if(8==ucDataBits) 2>|dF~"  
        { VCu{&Sh*  
            databit = UART1_WORDLENGTH_8D; ?i)f^O  
        } }E+!91't.^  
        else qHsUP;7  
        { Ager$uC  
            databit = UART1_WORDLENGTH_9D;         U1@IX4^2`  
        } pA`+hQNN  
        if(MB_PAR_NONE == eParity) 7Ilm{@ b=  
        { {kp-h2I,  
            parity = UART1_PARITY_NO; b_,|>U  
        } !$DIc  
        else if(MB_PAR_ODD == eParity) {p)",)td  
        { IYqBQnX}oM  
                parity = UART1_PARITY_ODD;         * "R|4"uy  
        } 4FEk5D  
        else g+DzscIT  
        { +~'865{  
                parity = UART1_PARITY_EVEN;         cmBB[pk\  
        } wi hH?~]  
        UART1_Init((uint32_t)ulBaudRate,databit, UART1_STOPBITS_1, parity, ~Cl){8o  
         UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE); 'Hc-~l>D  
    /* ENABLE the USARTx */ 2]I4M[|&z  
    UART1_ITConfig(UART1_IT_TXE, ENABLE);       Cnnh7`  
    return TRUE; 5 elw~u  
} bnm P{Ps  
    BOOL xMBPortSerialPutByte( CHAR ucByte )通讯端口发送一字节数据函数。在此函数中编写发送一字节数据的函数。注意,由于使用的是中断发送,故只需将数据放到发送寄存器即可。函数返回值务必为TRUE。 bIGHGd  
BOOLxMBPortSerialPutByte( CHAR ucByte ) @WJg WJm  
{ ^w(p8G_-w  
    UART1_SendData8(ucByte); W [Of|?  
    return TRUE; [!!o-9b  
} ;E@G`=0St  
BOOL xMBPortSerialGetByte( CHAR * pucByte )通讯端口接收一字节数据函数。在此函数中编写接收的函数。由于使用的是中断接收,只需将接收寄存器的值放到* pucByte即可。函数返回值务必为TRUE。 e .]KL('  
BOOL xMBPortSerialGetByte( CHAR * pucByte ) 0="%Y ^N  
{ r9X?PA0f  
    *pucByte = UART1_ReceiveData8(); nFE4qm  
    return TRUE; :Mb%A  
} L~_9_9c  
void prvvUARTRxISR( void )和void prvvUARTTxReadyISR( void )无需修改。 7Ok;Lt!x  
portserial.c文件修改 g1XZ5P} f  
BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )初始化超时定时器播函数。根据所使用的硬件初始化超时定时器,使之能产生中断时间为usTim1Timerout50us*50us的中断,本例移植采用单片机的TIM4定时器。函数返回值务必为TRUE。 &@%W29:  
BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )  =Qh\D  
{ 6^uq?  
  /* TIM4 configuration: 8*8Zc/{  
   - TIM4CLK is set to 16 MHz, the TIM4 Prescaler is equal to 128 so the TIM1 counter < XP9@t&  
   clock used is 16 MHz / 128 = 125 000 Hz @b"t]#V(E  
  - With 125 000 Hz we can generate time base: JXCCTUO  
      max time base is 2.048 ms if TIM4_PERIOD = 255 --> (255 + 1) / 125000 = 2.048 ms aD=a,  
      min time base is 0.016 ms if TIM4_PERIOD = 1   --> (  1 + 1) / 125000 = 0.016 ms S?RN?1  
                                                           --> 16us (EK"V';   
  - In this example we need to generate a time base equal to 50us *_R]*o!W'  
   so TIM4_PERIOD = (0.00005 * 125000 - 1) = 5 */ n,=VQ Ou  
    /* Time base configuration */ )_{dWf1  
  TIM4_TimeBaseInit(TIM4_PRESCALER_128, 5); RMd[Yr2e  
  /* Clear TIM4 update flag */ @.G[s)x  
  TIM4_ClearFlag(TIM4_FLAG_UPDATE); x;-. ZVF  
  /* Enable update interrupt */ s >e=?W  
  TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);   P/xKnm~  
  /* enable interrupts */ 9UKp?SIF  
// enableInterrupts(); '6Ay&A3N]  
  /* Enable TIM4 */ >wb 'QzF:  
  TIM4_Cmd(ENABLE); ktj]:rCkF  
    return TRUE;; D _/^+H]1  
} Qi_>Mg`x  
void vMBPortTimersEnable(  )使能超时定时器函数。需在此函数中清除中断标志位、清零定时器计数值,并重新使能定时器中断。 :/:.Kb  
void vMBPortTimersEnable(  ) //打开时钟 #k_HN}B  
{ !6s"]WvF  
    /* Clear TIM4 update flag */ =:DaS`~V  
  TIM4_ClearFlag(TIM4_FLAG_UPDATE); JAAI_gSR3  
     /* Enable update interrupt */ Q>/C*@  
  TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); Ynp{u`?  
    TIM4_SetCounter(0x00); _/Gczy4)#  
     /* Enable TIM4 */ `9)t[7  
  TIM4_Cmd(ENABLE); b8LoIY*  
} NG  
void vMBPortTimersDisable(  )关闭超时定时器函数。在此函数中清零定时器计数值,并关闭定时器中断。 hGd<<\  
void vMBPortTimersDisable(  ) //关闭时钟 70f Klp  
{ Y|8:;u'  
    TIM4_Cmd(DISABLE); >tO`r.5u9  
    TIM4_SetCounter(0x00); 5QPM t^  
    TIM4_ITConfig(TIM4_IT_UPDATE, DISABLE); <@}I0  
  TIM4_ClearFlag(TIM4_FLAG_UPDATE); Sp7ld7c  
} |;.o8}  
void prvvTIMERExpiredISR( void )函数不需修改。  Np'2}6P  
2、 应用层回函数的修改 *g y{]  
    在应用层,用户需要定义所需要使用的寄存器,并修改对应的回函数。 wNQ*t-K  
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNRegs)输入寄存器回函数。* pucRegBuffer为协议中所需的数据,usAddress为输入寄存器地址,usNRegs为访问寄存器的个数,eMode为访问类型(MB_REG_READ为读保持寄存器,MB_REG_WRITE为写保持寄存器)。用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的寄存器地址usAddress放到相应保持寄存器中。 w;k):; $  
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) 'd+N Vj{C  
{ ]xX$<@HR  
    eMBErrorCode  eStatus = MB_ENOERR; ?CC"Yij  
    int iRegIndex; 8<.C3m 6h  
    if( ( usAddress >= REG_INPUT_START )&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) ) WcHgBbNe  
    { G 16!eDMt  
        iRegIndex = ( int )( usAddress - usRegInputStart ); qw@puw@D  
        while( usNRegs > 0 ) p"l3e9&'j  
        { i/~1F_  
            *pucRegBuffer++ = `}BF${vF  
                ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 ); oI}kH=<,  
            *pucRegBuffer++ = U f|> (C  
                ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF ); jy giG&H  
            iRegIndex++; HPb]Zj  
            usNRegs--; }?z@rt^  
        } Ix(?fO#uNF  
    } Mk=mT3=#  
    else TjHwjRa  
    { A5i:x$ww  
        eStatus = MB_ENOREG; iCW*]U  
    } %^1cyk  
    return eStatus; ?t+5s]  
} ow0!%|fO  
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNRegs, eMBRegisterMode eMode)保持寄存器回函数。* pucRegBuffer为要协议中的数据,usAddress为输入寄存器地址,usNRegs为访问寄存器的个数,eMode为访问类型(MB_REG_READ为读保持寄存器,MB_REG_WRITE为写保持寄存器)。用户应根据要访问的寄存器地址usAddress将相应输入寄存器的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的寄存器地址usAddress放到相应保持寄存器中。 yaG= j  
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ) VH=S?_RY>  
{ U$ F{nZ1  
    eMBErrorCode    eStatus = MB_ENOERR; z I+\Oll#Q  
    int             iRegIndex; AX= 1b,s  
    u16 *PRT=(u16*)pucRegBuffer; 4O;OjUI0a  
    if( ( usAddress >= REG_HOLDING_START ) && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) ) mt5KbA>nU  
    { M/):e$S  
        iRegIndex = ( int )( usAddress - usRegHoldingStart ); ep=qf/vd<  
        switch ( eMode ) 1j:Wh  
        { wE@'ap#  
         case MB_REG_READ: \0mb 3Q'  
            while( usNRegs > 0 ) lY{FSGp  
            { G7)Fk%>  
              ////  *PRT++ = __REV16(usRegHoldingBuf[iRegIndex++]); //数据序转 REV16.W /v/C<]  
H|ER  
                       *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] >> 8 ); jS+AGE?5e  
              *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] & 0xFF ); 8}fu,$$5  
                      iRegIndex++; mcn 2Wt  
              usNRegs--; W -  
            } ++aL4:  
            break; -jn WZ5.  
OM|Fwr$  
        case MB_REG_WRITE: F29v a  
            while( usNRegs > 0 ) 'yV?*a  
            { -0_d/'d  
              ////  usRegHoldingBuf[iRegIndex++] = __REV16(*PRT++); //数据序转 REV16.W 59zENUYl  
                    usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8; qwK2WE%T  
              usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++; 6gT5O]]#o  
              iRegIndex++; <JV"@H=  
              usNRegs--; rQEyD  
            } RPIyO  
        } C=s1R;"H  
    } aB]m*~  
    else $b<6y/"  
    { k51Eyy50(  
        eStatus = MB_ENOREG; {@<J_ A  
    } u$D*tqxG  
    return eStatus; t\RF=BbJJ  
} bu=?N  
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNCoils, eMBRegisterMode eMode )读/写开关寄存器函数。* pucRegBuffer为要添加到协议中的数据,usAddress为地址,usNCoils为要访问的个数,eMode为访问类型(MB_REG_READ为读状态,MB_REG_WRITE为写)。用户应根据要访问的地址usAddress将相应的值按顺序添加到pucRegBuffer中,或将协议中的数据根据要访问的地址usAddress放到相应地址中。 f8SL3+v  
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) etoo #h"]1  
{ Q2A7mGN  
    ( void )pucRegBuffer; Up:<=Kgci  
    ( void )usAddress; @h*fFiY&{  
    ( void )usNCoils; } g3+{\x8  
    ( void )eMode; *loOiM\5a  
    return MB_ENOREG; j S;J:$>^  
} U,+[5sbo  
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )读开关寄存器函数。 ,^gyH \  
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) P7 PB t  
{ `60gFVu  
    ( void )pucRegBuffer; y!5$/`AF  
    ( void )usAddress; R(-<BtM!-  
    ( void )usNDiscrete; w~#nYM=fP!  
    return MB_ENOREG; _DrJVC~6@  
} ->h6j  
官方网站下载出问题,为了方便大家,附上FreeMODBUS源码
附件设置隐藏,需要回复后才能看到!


评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

一般

差劲
离线shuobing

性别:
帅哥
发帖
2254
金币
644
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 1楼 发表于: 2015-04-01
不错,可以做来一些类似内容


广告位出租,价格可以商量。
离线aabb888

性别:
人妖
发帖
2883
金币
1885
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 2楼 发表于: 2015-04-01


离线ycy

性别:
帅哥
发帖
2998
金币
389
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 3楼 发表于: 2015-04-02
谢谢分享   学习一下 -$4kBYC l+  

内容来自Android手机客户端



困……
离线llab123

性别:
人妖
发帖
12
金币
4
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 4楼 发表于: 2015-07-04
谢谢分享


离线3395587186

性别:
人妖
发帖
978
金币
157
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 5楼 发表于: 2016-08-11
  


离线aninstone

性别:
人妖
发帖
3
金币
5
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 6楼 发表于: 2017-04-18
good 效果咋样?


离线lqsgg

性别:
人妖
发帖
10201
金币
19088
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 7楼 发表于: 2018-10-28
  


离线君夕

性别:
人妖
发帖
152
金币
32
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 8楼 发表于: 2018-10-28
6b1 Uj<  


离线fxliuqq

性别:
帅哥
发帖
1489
金币
518
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 9楼 发表于: 2018-10-28
谢谢分享谢谢分享学习下


离线lichuanfa

性别:
帅哥
发帖
497
金币
1258
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 10楼 发表于: 2018-10-30
搞控制的好东西


快速回复
限150 字节
 
上一个 下一个