FreeModbus——移植(三)

参考自:手把手教你移植FreeModbus到STM32【看评论区引导,领取全套资料包】_freemodbus移植_HQYJ520的博客-CSDN博客

1.准备源码

1.这里用到串口进行传输,所以我没拷贝一个正常的串口工程(我用的是正点原子f4库函数版本)

2.解压modbusV1.6的源码

FreeModbus——移植(三)_第1张图片

 2.复制源码到串口工程文件夹下

1.在串口实验目录下,新建一个MODBUS文件夹

2.然后将modbusV1.6解压,将文件里面的modbus复制到工程MODBUS文件夹下。

3.然后再将demo文件夹下的BARE复制到MODBUS文件夹下。

FreeModbus——移植(三)_第2张图片

 3.keil5中添加源码

1.新建一个MODBUS分组

2.添加文件:

        a.modbus文件夹下所有的.c文件以及BARE->port下的.c文件

        FreeModbus——移植(三)_第3张图片

     FreeModbus——移植(三)_第4张图片

3.添加后的所有文件 

 FreeModbus——移植(三)_第5张图片

 4.工程中添加modbus的头文件路径

FreeModbus——移植(三)_第6张图片

 (PS:今天先写到这,让我先理一下这位大神的思路,我也是边看边移植,然后做笔记)

5.在portserial.c中添加串口相关

void uart_init(unsigned int bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟 
    
    //串口1对应引脚复用映射
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);  //GPIOA9复用为USART1
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1
    
    //USART1端口配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;      //复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//速度50MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;   //上拉
    GPIO_Init(GPIOA,&GPIO_InitStructure);          //初始化PA9,PA10
    
    //USART1 初始化设置
    USART_InitStructure.USART_BaudRate = bound;//波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_InitStructure.USART_StopBits = USART_StopBits_1;  //一个停止位
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    USART_Init(USART1, &USART_InitStructure); //初始化串口1	
    USART_Cmd(USART1, ENABLE);  //使能串口1 

//    USART_ClearFlag(USART1, USART_FLAG_TC);

//    USART_ITConfig(USART1, USART_IT_RXNE | USART_IT_ORE | USART_IT_TC, ENABLE);         //开启相关中断
    
    //Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;      //串口1中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		   //子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			   //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	  //根据指定的参数初始化VIC寄存器、
}
/*
 * FreeModbus Libary: BARE Port
 * Copyright (C) 2006 Christian Walter 
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id$
 */

#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "./UART/uart.h"

/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR( void );
static void prvvUARTRxISR( void );

/* ----------------------- Start implementation -----------------------------*/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
    /* If xRXEnable enable serial receive interrupts. If xTxENable enable
     * transmitter empty interrupts.
     */
    if(xRxEnable == TRUE)
    {
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    }
    else
    {
        USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
    }

    if(xTxEnable == TRUE)
    {
        USART_ITConfig(USART1, USART_IT_TC, ENABLE);
    }
    else
    {
        USART_ITConfig(USART1, USART_IT_TC, DISABLE);
    }
}

BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
    uart_init(ulBaudRate);
    return TRUE;
}

BOOL
xMBPortSerialPutByte( CHAR ucByte )
{
    /* Put a byte in the UARTs transmit buffer. This function is called
     * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
     * called. */
    USART_SendData(USART1, ucByte);
    return TRUE;
}

BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
    /* Return the byte in the UARTs receive buffer. This function is called
     * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
     */
    *pucByte = USART_ReceiveData(USART1); 
    return TRUE;
}

/* Create an interrupt handler for the transmit buffer empty interrupt
 * (or an equivalent) for your target processor. This function should then
 * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
 * a new character can be sent. The protocol stack will then call 
 * xMBPortSerialPutByte( ) to send the character.
 */
static void prvvUARTTxReadyISR( void )
{
    pxMBFrameCBTransmitterEmpty(  );
}

/* Create an interrupt handler for the receive interrupt for your target
 * processor. This function should then call pxMBFrameCBByteReceived( ). The
 * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
 * character.
 */
static void prvvUARTRxISR( void )
{
    pxMBFrameCBByteReceived(  );
}
void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
    {
        prvvUARTRxISR(); 

        USART_ClearITPendingBit(USART1, USART_IT_RXNE);   
    }

    if(USART_GetITStatus(USART1, USART_IT_ORE) == SET)
    {  
        prvvUARTRxISR();   
        USART_ClearITPendingBit(USART1, USART_IT_ORE);
        
    }

    if(USART_GetITStatus(USART1, USART_IT_TC) == SET)
    {
        prvvUARTTxReadyISR();

        USART_ClearITPendingBit(USART1, USART_IT_TC);
    }
} 

6.在porttime.c中添加定时器相关 

/*
 * FreeModbus Libary: BARE Port
 * Copyright (C) 2006 Christian Walter 
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id$
 */

/* ----------------------- Platform includes --------------------------------*/
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "./TIMER/timer.h"
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR( void );

/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
//    (void)usTim1Timerout50us;
    TIM3_Int_Init(usTim1Timerout50us-1,4200 -1);//定时器时钟84M,分频系数4200 -1,一次中断50us
    return TRUE;
}


inline void
vMBPortTimersEnable(  )
{
    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
    TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
    TIM_SetCounter(TIM3,0); 
    TIM_Cmd(TIM3, ENABLE);
}

inline void
vMBPortTimersDisable(  )
{
    /* Disable any pending timers. */
    TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
    TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
    TIM_SetCounter(TIM3,0); 
    TIM_Cmd(TIM3, DISABLE);
}

/* 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.
 */
static void prvvTIMERExpiredISR( void )
{
    ( void )pxMBPortCBTimerExpired(  );
}
void TIM3_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    {
        prvvTIMERExpiredISR();
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
    }
}

7.完善四个回调函数

FreeModbus——移植(三)_第7张图片

 a.首先解决第一个assert

        在assert.h文件中, 注释掉assert.

FreeModbus——移植(三)_第8张图片

 b.补充四个回调函数

在工程中新建mbusr.c和mbusr.h, 在这个文件中补充全四个回调函数

#include "mbusr.h"

eMBErrorCode    eStatus;

static USHORT   usRegInputStart = REG_INPUT_START;
USHORT   usRegInputBuf[REG_INPUT_NREGS] = {11,12,13,14,0x1004,15,16,17};


static USHORT   usRegHoldingStart = REG_HOLDING_START;
static USHORT   usRegHoldingBuf[REG_HOLDING_NREGS] = {21,22,23,24,25,26,27,28};

//线圈状态
uint8_t ucRegCoilsBuf[REG_COILS_SIZE / 8] = {0x01,0x02};
//开关输入状态
uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE / 8] = {0x01,0x02};

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++ = ( UCHAR )( usRegInputBuf[iRegIndex] >> 8 );
            *pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] & 0xFF );
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}


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:
        while(usNRegs > 0)
        {
          *pucRegBuffer++ = (UCHAR)(usRegHoldingBuf[iRegIndex] >> 8);            
          *pucRegBuffer++ = (UCHAR)(usRegHoldingBuf[iRegIndex] & 0xFF); 
          iRegIndex++;
          usNRegs--;          
        }                            
        break;
      case MB_REG_WRITE:
        while(usNRegs > 0)
        {         
          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 )
{
  eMBErrorCode    eStatus = MB_ENOERR;
  int             iRegIndex;

  if((usAddress >= REG_HOLDING_START)&&
    ((usAddress+usNCoils) <= (REG_HOLDING_START + REG_HOLDING_NREGS)))
  {
    iRegIndex = (int)(usAddress - usRegHoldingStart);
    switch(eMode)
    {                                       
      case MB_REG_READ:
        while(usNCoils > 0)
        {


          iRegIndex++;
          usNCoils--;          
        }                            
        break;
      case MB_REG_WRITE:
        while(usNCoils > 0)
        {         


          iRegIndex++;
          usNCoils--;
        }        
      }
  }
  else
  {
    eStatus = MB_ENOREG;
  }  
  
  return eStatus;
}

eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    ( void )pucRegBuffer;
    ( void )usAddress;
    ( void )usNDiscrete;
    return MB_ENOREG;
}




#ifndef MBUSR_H
#define MBUSR_H
#include "mb.h"
#include "stm32f4xx.h"
#include "./UART/uart.h"

#define REG_INPUT_START 0x0001
#define REG_INPUT_NREGS 8

#define REG_HOLDING_START 0x0001
#define REG_HOLDING_NREGS 8

#define REG_COILS_START 0x0001
#define REG_COILS_SIZE 16

#define REG_DISCRETE_START 0x0001
#define REG_DISCRETE_SIZE 16

eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs );

eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode );

eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode );

eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode );

#endif

8.修改mbrtu.c中的eMBRTUSend()函数 

eMBErrorCode
eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    USHORT          usCRC16;

    ENTER_CRITICAL_SECTION(  );

    /* Check if the receiver is still in idle state. If not we where to
     * slow with processing the received frame and the master sent another
     * frame on the network. We have to abort sending the frame.
     */
    if( eRcvState == STATE_RX_IDLE )
    {
        /* First byte before the Modbus-PDU is the slave address. */
        pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
        usSndBufferCount = 1;

        /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
        pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
        usSndBufferCount += usLength;

        /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
        usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
        ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF );
        ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 );

        /* Activate the transmitter. */
        eSndState = STATE_TX_XMIT;

        //启动第一次发送,这样才可以进入发送完成中断
        xMBPortSerialPutByte( ( CHAR )*pucSndBufferCur );
        pucSndBufferCur++;  /* next byte in sendbuffer. */
        usSndBufferCount--;

        //使能发送状态,禁止接收状态
        vMBPortSerialEnable( FALSE, TRUE );
    }
    else
    {
        eStatus = MB_EIO;
    }
    EXIT_CRITICAL_SECTION(  );
    return eStatus;
}

9.在主函数中添加测试程序 

#include "mb.h"
#include "mbusr.h"


extern eMBErrorCode    eStatus;
extern USHORT   usRegInputBuf[REG_INPUT_NREGS];
    
int main(void)
{ 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    eStatus = eMBInit( MB_RTU, 0x01, 0x01, 115200, MB_PAR_EVEN );
    eStatus = eMBEnable();
    
    while(1)
    {
        eMBPoll();
    }
}

 



10.效果展示

FreeModbus——移植(三)_第9张图片

你可能感兴趣的:(嵌入式第三方库,freemodbus)