| 本帖最后由 固桐 于 2013-5-27 22:27 编辑 
 这几天,研究了freemodbus通信协议,然后在stm32上移植。关于freemodbus通信原理,以及通信过程(状态机转换),这里就不说了。       freemodbus使用的库是最新版本freemodbus-v1.5.0,把相应的库文件加载在STM32工程中。移植时,需要用户改写的文件有两个,一个是porttimer.c文件,一个是portserial.c文件。porttimer.c文件主要用于超时判断,本例使用的是定时器2,portserial.c主要使用串口通信的实现,本例使用的是RS485.porttimer.c修改如下
 
 portserial.c文件修改如下/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "..\..\include\nvic.h"
#include "..\..\include\stm32f10x_reg.h"
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us ) //配置50us时钟
{
        uint16_t PrescalerValue = 0;
        
        /* TIM2 clock enable */
        
        RCC->CFGR.B.PPRE1 = 4;  //APB1预分频系数
                          //100:HCLK 2分频
                                //APB1 不超过36MHz
        RCC->APB1ENR.B.TIM2EN = 1;
        /* Compute the prescaler value */
        PrescalerValue = (uint16_t) (36000000 / 20000) - 1; // 1/20000=50us 
        /* Time base configuration */
        TIM2->ARR=(uint16_t) usTim1Timerout50us;
        TIM2->PSC= PrescalerValue;
        TIM2->CR1.B.URS = 1; 
   MY_NVIC_Init(3,3,28,2);         
                
        /* TIM IT DISABLE */
        TIM2->SR.B.UIF = 0;
        TIM2->DIER.B.UIE = 0;
        TIM2->CR1.B.CEN = 0;
        /* TIM2 DISABLE counter */
        return TRUE;;
}
void vMBPortTimersEnable(  ) //打开时钟
{
         TIM2->SR.B.UIF = 0;
        TIM2->DIER.B.UIE = 1;
        TIM2->CNT= 0;
        TIM2->CR1.B.CEN = 1; 
        
}
void vMBPortTimersDisable(  ) //关闭时钟
{
        TIM2->CR1.B.CEN = 0;
        TIM2->CNT= 0;
        TIM2->DIER.B.TIE = 0;
        TIM2->DIER.B.UIE = 0;
        }
/* Create an ISR which is called whenever the timer has expired. This function
 * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
 * the timer has expired.
 */
void prvvTIMERExpiredISR( void ) //在时钟中断内调用
{
    ( void )pxMBPortCBTimerExpired(  );
}
void TIM2_IRQHandler(void)
{
    /* Clear TIM4 Capture Compare1 interrupt pending bit*/
   
        TIM2->SR.B.UIF = 0;
        TIM2->SR.B.TIF = 0;
        prvvTIMERExpiredISR( );
}
 
 另外在主函数中,加入测试函数如下
 
 #include "mb.h" 
#include "..\..\include\adc.h" 
#include "..\..\include\lm75.h" 
#include "..\..\include\timer.h" 
#include "..\..\include\simulate.h" 
#include "..\..\include\encode.h" 
#include "..\..\include\hardware.h"
#include "..\..\include\systick.h"
unsigned short int  usRegInputBuf[10]={0x0000,0xfe02,0x1203,0x1304,0x1405,0x1506,0x1607,0x1708,0x1809};
unsigned short int *usRegHoldingBuf=usRegInputBuf;        //一个测试用的 寄存器数组 地址0-7
unsigned char REG_INPUT_START=0,REG_HOLDING_START=0;
unsigned char REG_INPUT_NREGS=8,REG_HOLDING_NREGS=8;
unsigned char usRegInputStart=0,usRegHoldingStart=0;
//读数字寄存器 功能码0x04
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;
}
// 寄存器的读写函数 支持的命令为读 0x03 和写0x06
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    int             iRegIndex;
 
    if( ( usAddress >= REG_HOLDING_START ) && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegHoldingStart );
        switch ( eMode )
        {
                                        
        case MB_REG_READ:
        if(usAddress==1)
                            {
                                    *pucRegBuffer++ = ( unsigned char )( adc.read(1) >> 8 );
             
                                    *pucRegBuffer++ = ( unsigned char )( adc.read(1) & 0xFF );
                                  }
                                if(usAddress==2)
                                  {
                                    *pucRegBuffer++ = ( unsigned char )( adc.read(0) >> 8 );
             
                                    *pucRegBuffer++ = ( unsigned char )( adc.read(0) & 0xFF );
                                  }
                                        if(usAddress==3)
                                  {
                                    *pucRegBuffer++ = ( unsigned char )( adc.read(7) >> 8 );
             
                                    *pucRegBuffer++ = ( unsigned char )( adc.read(7) & 0xFF );
                                  }
                                        if(usAddress==4)
                                  {
                                    *pucRegBuffer++ = ( unsigned char )( lm75.read() >> 8 );
             
                                    *pucRegBuffer++ = ( unsigned char )( lm75.read() & 0xFF );
                                  }
        
         if(usAddress==5)
                                  {
                                                                
                                timer.refresh();
                                *pucRegBuffer++ = ( unsigned char )( tim_parameter.Position_relative >> 8 );
                *pucRegBuffer++ = ( unsigned char )( tim_parameter.Position_relative &0xFF );
                                                
                
        }
                if(usAddress==6)
                                  {
                                                                
                                timer.refresh();
                                *pucRegBuffer++ = ( unsigned char )(  TIM1->CCR2>> 8 );
                *pucRegBuffer++ = ( unsigned char )(  TIM1->CCR2&0xFF );
                                                
                
        }
                                  
            break;
        case MB_REG_WRITE:
            while( usNRegs > 0 )
            {
          
                                usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
             usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
             iRegIndex++;
                usNRegs--;
            }
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}
//读/写开关寄存器  0x01  x05
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
    ( void )pucRegBuffer;
    ( void )usAddress;
    ( void )usNCoils;
    ( void )eMode;
    return MB_ENOREG;
}
//读开关寄存器 0x02
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    ( void )pucRegBuffer;
    ( void )usAddress;
    ( void )usNDiscrete;
    return MB_ENOREG;
}
经过,测试,本次移植可以读取节点的温度,AD转换值,等参数,实现了预期的效果。
 
 
 
 |