freemodbus移植

freemodbus下载地址:GitHub - cwalter-at/freemodbus: BSD licensed MODBUS RTU/ASCII and TCP slave

freemodbus仅支持从机模式

配置cubeide

1、配置sys

2、配置RCC

3、配置系统时钟

4、配置串口,出口参数可任意填写,会在程序中重新进行初始化

  串口中断使能

5、配置定时器,定时器参数可任意配置,在系统初始化中会重新配置

     定时器中断使能

6、全局中断配置

中断代码生成配置

 7、生成代码配置

8、生成代码

9、在\Core\Src文件夹中建立mb文件夹,用于存放freemodbus文件

10、添加文件

  •  \freemodbus-v1.6\demo\BARE\port 中文件复制到第9步文件夹mb中
  • \freemodbus-v1.6\modbus\functions中文件复制到第9步文件夹mb中
  •  \freemodbus-v1.6\modbus\include中文件复制到第9步文件夹mb中
  • \freemodbus-v1.6\modbus\rtu中文件复制到第9步文件夹mb中
  •  \freemodbus-v1.6\modbus中mb.c文件复制到第9步文件夹mb中
  • mb文件夹中新建port.c文件中

 11、修改modbus定时器初始化源代码porttimer.c文件 ,注意定时器选择正确,定时器的Prescaler 根据cpu频率计算,配置50us出现一次计数;HAL的time6中断方法是

void TIM6_DAC_IRQHandler(void),和其他tim的中断方法名称不一样,会导致移植失败

/*
 * 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"
#include "tim.h"
#include <stdio.h>

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

/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR( void );

/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
	HAL_TIM_Base_DeInit(&htim6);

	TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM6_Init 1 */

  /* USER CODE END TIM6_Init 1 */
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 3600-1;//50us分频,这里使用的timer PCLK频率是72Mhz
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;


  htim6.Init.Period = usTim1Timerout50us-1;//modbus 规定的TIMEOUT时间


  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
     return FALSE;
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
     return FALSE;
  }
	 return TRUE;

}

inline void
vMBPortTimersEnable(  )
{
    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
	__HAL_TIM_CLEAR_IT(&htim6,TIM_IT_UPDATE);
	__HAL_TIM_SetCounter(&htim6,0);//这里一定要清零计数器
	HAL_TIM_Base_Start_IT(&htim6);

}

inline void
vMBPortTimersDisable(  )
{
    /* Disable any pending timers. */
	HAL_TIM_Base_Stop_IT(&htim6);

	__HAL_TIM_SetCounter(&htim6,0);
	__HAL_TIM_CLEAR_IT(&htim6,TIM_IT_UPDATE);

}


/* 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(  );
}



/**
  * @brief This function handles TIM6 global interrupt, DAC1 and DAC2 underrun error interrupts.
  */
void TIM6_DAC_IRQHandler(void)
{
  /* USER CODE BEGIN TIM6_DAC_IRQn 0 */

  /* USER CODE END TIM6_DAC_IRQn 0 */
  HAL_TIM_IRQHandler(&htim6);
  /* USER CODE BEGIN TIM6_DAC_IRQn 1 */
	prvvTIMERExpiredISR();
  /* USER CODE END TIM6_DAC_IRQn 1 */
}

11、修改modbus串口初始化源代码portserial.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$
 */

#include "port.h"
#include "usart.h"

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

/* ----------------------- static functions ---------------------------------*/
 void prvvUARTTxReadyISR( void );
 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)
 		 __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
 	else
 		 __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);

 	if(xTxEnable == TRUE)
 		 __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);
 	else
 		 __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);
 }




 BOOL
 xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
 {
 	HAL_UART_DeInit(&huart1);//DEINIT cubeMX中的初始化配置
 	(void)ucPORT;
 	huart1.Instance = USART1;
     huart1.Init.BaudRate = ulBaudRate;


     huart1.Init.StopBits = UART_STOPBITS_1;
 	switch (eParity)//使用校验位,就需要将uart的数据位配置为9位
   {
   	case MB_PAR_ODD:
 			huart1.Init.WordLength = UART_WORDLENGTH_9B;
 			huart1.Init.Parity = UART_PARITY_ODD;
   		break;
   	case MB_PAR_EVEN:
 			huart1.Init.WordLength = UART_WORDLENGTH_9B;
 			huart1.Init.Parity = UART_PARITY_EVEN;
   		break;
   	default:
 			huart1.Init.WordLength = UART_WORDLENGTH_8B;
 			huart1.Init.Parity = UART_PARITY_NONE;
   		break;
   }

   huart1.Init.Mode = UART_MODE_TX_RX;
   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
   if (HAL_UART_Init(&huart1) != HAL_OK)
   {
     return FALSE;
   }

 		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. */

 		if(HAL_UART_Transmit(&huart1,(uint8_t*)&ucByte,1,1) == HAL_OK)
 			return TRUE;
 		else
 			return FALSE;
 }

 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.
      */

 	if(HAL_UART_Receive(&huart1,(uint8_t*)pucByte,1,1) == HAL_OK)
     	return TRUE;
 	else
 		return FALSE;
 }


 /* 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.
  */
 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.
  */
 void prvvUARTRxISR( void )
 {
     pxMBFrameCBByteReceived(  );
 }




 void USART1_IRQHandler(void)
 {
   /* USER CODE BEGIN USART1_IRQn 0 */
 	uint8_t tmp;
 	if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_PE))//奇偶校验位判断
 	{
 		HAL_UART_Receive(&huart1,&tmp,1,1);
 	}

 	else if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE)&&__HAL_UART_GET_IT_SOURCE(&huart1,UART_IT_RXNE))
 	{
 		prvvUARTRxISR();

 	}
 	if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TXE)&&__HAL_UART_GET_IT_SOURCE(&huart1,UART_IT_TXE))
 	{
 		prvvUARTTxReadyISR();

 	}

   /* USER CODE END USART1_IRQn 0 */
   HAL_UART_IRQHandler(&huart1);
   /* USER CODE BEGIN USART1_IRQn 1 */

   /* USER CODE END USART1_IRQn 1 */
 }

 12、编写modbus命令处理回调函数port.c文件

#include "mb.h"
#include "mbport.h"


// 十路输入寄存器
#define REG_INPUT_SIZE  10
uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];


// 十路保持寄存器
#define REG_HOLD_SIZE   10
uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];


// 十路线圈
#define REG_COILS_SIZE 10
uint8_t REG_COILS_BUF[REG_COILS_SIZE] = {1, 1, 1, 1, 0, 0, 0, 0, 1, 1};


// 十路离散量
#define REG_DISC_SIZE  10
uint8_t REG_DISC_BUF[REG_DISC_SIZE] = {1,1,1,1,0,0,0,0,1,1};


/// CMD4命令处理回调函数
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    USHORT usRegIndex = usAddress - 1;

    // 非法检测
    if((usRegIndex + usNRegs) > REG_INPUT_SIZE)
    {
        return MB_ENOREG;
    }

    // 循环读取
    while( usNRegs > 0 )
    {
        *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );
        *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );
        usRegIndex++;
        usNRegs--;
    }

    // 模拟输入寄存器被改变
    for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)
    {
        REG_INPUT_BUF[usRegIndex]++;
    }

    return MB_ENOERR;
}

/// CMD6、3、16命令处理回调函数
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
    USHORT usRegIndex = usAddress - 1;

    // 非法检测
    if((usRegIndex + usNRegs) > REG_HOLD_SIZE)
    {
        return MB_ENOREG;
    }

    // 写寄存器
    if(eMode == MB_REG_WRITE)
    {
        while( usNRegs > 0 )
        {
            REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
            pucRegBuffer += 2;
            usRegIndex++;
            usNRegs--;
        }
    }

    // 读寄存器
    else
    {
        while( usNRegs > 0 )
        {
            *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
            *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
            usRegIndex++;
            usNRegs--;
        }
    }

    return MB_ENOERR;
}

/// CMD1、5、15命令处理回调函数
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
    USHORT usRegIndex   = usAddress - 1;
    UCHAR  ucBits       = 0;
    UCHAR  ucState      = 0;
    UCHAR  ucLoops      = 0;

    // 非法检测
    if((usRegIndex + usNCoils) > REG_COILS_SIZE)
    {
        return MB_ENOREG;
    }

    if(eMode == MB_REG_WRITE)
    {
        ucLoops = (usNCoils - 1) / 8 + 1;
        while(ucLoops != 0)
        {
            ucState = *pucRegBuffer++;
            ucBits  = 0;
            while(usNCoils != 0 && ucBits < 8)
            {
                REG_COILS_BUF[usRegIndex++] = (ucState >> ucBits) & 0X01;
                usNCoils--;
                ucBits++;
            }
            ucLoops--;
        }
    }
    else
    {
        ucLoops = (usNCoils - 1) / 8 + 1;
        while(ucLoops != 0)
        {
            ucState = 0;
            ucBits  = 0;
            while(usNCoils != 0 && ucBits < 8)
            {
                if(REG_COILS_BUF[usRegIndex])
                {
                    ucState |= (1 << ucBits);
                }
                usNCoils--;
                usRegIndex++;
                ucBits++;
            }
            *pucRegBuffer++ = ucState;
            ucLoops--;
        }
    }

    return MB_ENOERR;
}

/// CMD2命令处理回调函数
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    USHORT usRegIndex   = usAddress - 1;
    UCHAR  ucBits       = 0;
    UCHAR  ucState      = 0;
    UCHAR  ucLoops      = 0;

    // 非法检测
    if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)
    {
        return MB_ENOREG;
    }

    ucLoops = (usNDiscrete - 1) / 8 + 1;
    while(ucLoops != 0)
    {
        ucState = 0;
        ucBits  = 0;
        while(usNDiscrete != 0 && ucBits < 8)
        {
            if(REG_DISC_BUF[usRegIndex])
            {
                ucState |= (1 << ucBits);
            }
            usNDiscrete--;
            usRegIndex++;
            ucBits++;
        }
        *pucRegBuffer++ = ucState;
        ucLoops--;
    }

    // 模拟离散量输入被改变
    for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)
    {
        REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
    }

    return MB_ENOERR;
}

13、main文件处理

添加头文件

/* USER CODE BEGIN Includes */
//#include "port.h"
#include "mb.h"
#include "mbport.h"
/* USER CODE END Includes */

main函数添加

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    eMBInit(MB_RTU, 0x01, 0, 9600, MB_PAR_ODD);		// 初始化modbus为RTU方式,波特率9600,奇校验
    eMBEnable();									// 使能modbus协议栈

    for( ;; )
    {
        eMBPoll();									// 轮训查询
    }
}

14、mbconfig.h文件配置 

/*! \brief If Modbus ASCII support is enabled. */
#define MB_ASCII_ENABLED                        (  0 )

/*! \brief If Modbus RTU support is enabled. */
#define MB_RTU_ENABLED                          (  1 )

/*! \brief If Modbus TCP support is enabled. */
#define MB_TCP_ENABLED                          (  0 )

宏定义值设置为0,不启用ascii和TCP模式

15、头文件路径设置

菜单project->properties,打开项目属性配置选项框

添加mb文件夹,点击确认

16、步骤完成,编译下载测试 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值