FreeModbus——移植(三)

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

1.准备源码

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

2.解压modbusV1.6的源码

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

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

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

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

 3.keil5中添加源码

1.新建一个MODBUS分组

2.添加文件:

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

        

     

3.添加后的所有文件 

 

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

 (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 <wolti@sil.at>
 *
 * 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 <wolti@sil.at>
 *
 * 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.完善四个回调函数

 a.首先解决第一个assert

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

 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.效果展示

### 回答1: Freemodbus HAL移植是将Freemodbus层与底层硬件之间的接口适配到不同的硬件平台或操作系统上的一个过程。 在进行Freemodbus HAL移植前,我们首先需要理解Freemodbus的原理和结构。Freemodbus是一款开源的Modbus通信协议栈,它主要由Modbus协议的核心功能、硬件抽象层(HAL)和物理层(PHY)组成。其中,HAL层主要负责与底层硬件的交互,包括GPIO控制、串口通信、定时器等。 进行Freemodbus HAL移植的具体步骤如下: 1. 确定目标硬件平台或操作系统。 2. 查阅目标平台的文档或参考资料,了解其硬件架构、IO口、串口、定时器等相关信息。 3. 根据目标平台的特点,对Freemodbus HAL层进行修改和适配。主要包括GPIO控制、串口通信和定时器等功能的实现。 4. 在目标平台上移植和编译Freemodbus源代码,并与应用程序进行集成。 5. 进行功能测试和兼容性测试,确保移植后的Freemodbus可以正常运行和与其他设备进行Modbus通信。 在进行Freemodbus HAL移植时,需要注意以下几点: 1. 理解目标平台的硬件特性和限制,合理利用硬件资源。 2. 根据目标平台的不同,可能需要修改一些底层驱动程序或库函数的实现,以适配不同的硬件接口和操作系统调用。 3. 注意调试和测试过程,定位并修复可能出现的问题和Bug。 4. 充分了解Freemodbus的应用场景和功能需求,确保移植后的系统可以满足实际应用需求。 总之,Freemodbus HAL移植是将Freemodbus与不同的硬件平台或操作系统进行适配的过程,需要掌握目标平台的相关知识和技术,并进行充分的测试和调试工作,以确保移植后的系统能够正常工作并实现预期的功能。 ### 回答2: freemodbus hal 移植指的是将freemodbus(自由的 Modbus 通信库)的硬件抽象层(HAL)移植到其他硬件平台上。 首先,进行freemodbus hal 移植前,我们需要了解目标硬件平台和所需要的功能。根据硬件平台的不同,移植的步骤可能有所差异,但下面是一般的移植步骤: 1. 硬件初始化:根据硬件平台的要求,初始化与Modbus通信相关的硬件资源,如串口、GPIO等。 2. HAL 接口实现:根据freemodbus HAL的接口定义,实现与目标硬件平台相关的 HAL 接口函数。这些接口函数包括初始化串口、发送和接收数据等。 3. 中断处理:如果硬件平台支持中断,我们需要实现相应的中断处理函数,并在适当的时候调用freemodbus HAL提供的中断相关接口。 4. 调试与测试:进行移植后,需要对移植freemodbus HAL进行调试和测试。可以使用Modbus调试工具,如Modbus Slave,来验证Modbus通信的正确性。 总结来说,freemodbus hal 移植的关键在于实现与目标硬件平台相关的 HAL 接口函数,并根据硬件平台的特性进行适配。移植完成后,可以使用freemodbus库的功能来实现Modbus通信,并对其进行调试和测试,确保功能正常。 需要注意的是,由于具体硬件平台和要求的不同,移植的详细步骤可能会有所变化。因此,在进行具体的freemodbus hal 移植前,应该仔细阅读相关的文档和参考资料,并根据硬件平台的要求进行适当的调整和修改。 ### 回答3: Freemodbus HAL(硬件抽象层)移植是将Freemodbus协议栈适配到特定硬件平台或操作系统的过程。在进行移植之前,首先需要了解目标平台的硬件特性和操作系统支持情况。 移植的第一步是针对目标平台和操作系统编写HAL层驱动程序。这些驱动程序负责与硬件进行通信,并提供必要的接口供协议栈使用。HAL层驱动程序通常包括串口或以太网接口驱动,用于与Modbus设备进行通信。 其次,需要根据目标平台的字节序,调整协议栈的字节序设置。Modbus协议使用大端字节序,因此移植时需要设置正确的字节序,以确保数据的正确传输和解析。 接下来,需要根据目标平台的内存和处理能力,进行协议栈的调整。可能需要进行内存优化或适配以满足硬件资源限制。例如,可以选择禁用一些不必要的功能或减小数据包缓冲区的大小。 最后,在移植过程中需要对协议栈进行验证和测试,以确保其在目标平台上的正常运行。可以使用一些模拟器或硬件测试设备来进行测试,并检查通信的准确性和稳定性。如果发现问题,则需要进行调试和修复。 总的来说,Freemodbus HAL移植需要根据目标平台的硬件和操作系统特性进行适配和调整。这样才能确保协议栈在新平台上能够正常运行,并与Modbus设备进行通信。移植过程需要耐心和仔细的调试和测试,以确保移植成功。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

入门->放弃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值