STM32移植FreeModbus实现ModBusRTU协议

首先将FreeModbus移植到自己工程中,如下图所示:在这里插入图片描述
然后修改portserial.c和porttimer.c文件:
portserial.c

/*
 * FreeModbus Libary: BARE Port
 * Copyright (C) 2006 Christian Walter <[email protected]>
 *
 * 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: portserial.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
 */

#include "port.h"
#include "stm32f10x.h"
#include "modbus.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.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(USART2, USART_IT_RXNE, ENABLE);
	}
	else
	{
		USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
	}
	
	if(xTxEnable == TRUE)
	{
		USART_ITConfig(USART2, USART_IT_TC, ENABLE);
	}
	else
	{
		USART_ITConfig(USART2, USART_IT_TC, DISABLE);
	}
}

BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
	modbus_uart_init((uint16_t)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(USART2, 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(USART2); 
	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(  );
}

/**
  * @brief  This function handles usart1 Handler.
  * @param  None
  * @retval None
  */
void USART2_IRQHandler(void)
{
	//发生接收中断
	if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
	{
		prvvUARTRxISR(); 
		//清除中断标志位    
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);   
	}

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

	//发生完成中断
	if(USART_GetITStatus(USART2, USART_IT_TC) == SET)
	{
		prvvUARTTxReadyISR();
		//清除中断标志
		USART_ClearITPendingBit(USART2, USART_IT_TC);
	}
}

porttimer.c


```c
/*
 * FreeModbus Libary: BARE Port
 * Copyright (C) 2006 Christian Walter <[email protected]>
 *
 * 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: porttimer.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
 */

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

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

/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
	modbus_timer_init(usTim1Timerout50us);

	return TRUE;
}


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,0x0000); 
	TIM_Cmd(TIM3, ENABLE);
}

void
vMBPortTimersDisable(  )
{
    /* Disable any pending timers. */
  TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
  TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
  TIM_SetCounter(TIM3,0x0000); 
  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);
	}
}


然后主函数中调用


 int main(void)
 {		
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);
	eMBInit(MB_RTU, 0x01, 0x01, 9600, MB_PAR_NONE);
	eMBEnable();  
 	while(1)
	{
		(void)eMBPoll();
		delay_ms(5);
		
	}	 
 }

其次还要实现读线圈、写线圈、读离散输入、写保持寄存器、读保持寄存器、读输入寄存器等功能,如下:

#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			//开关寄存器数量
//输入寄存器内容
uint16_t usRegInputBuf[REG_INPUT_NREGS] = {0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007};
//保持寄存器内容		
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] = {0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007};					
//线圈状态
uint8_t ucRegCoilsBuf[REG_COILS_SIZE] = {0x01,0x01,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00};
//离散寄存器内容
uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE] = {0x01,0x01,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x01}; 

/****************************************************************************
* 名	  称:eMBRegInputCB 
* 功    能:读取输入寄存器,对应功能码是 04 eMBFuncReadInputRegister
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
*						usAddress: 寄存器地址
*						usNRegs: 要读取的寄存器个数
* 出口参数:
* 注	  意:上位机发来的 帧格式是: SlaveAddr(1 Byte)+FuncCode(1 Byte)
*								+StartAddrHiByte(1 Byte)+StartAddrLoByte(1 Byte)
*								+LenAddrHiByte(1 Byte)+LenAddrLoByte(1 Byte)+
*								+CRCAddrHiByte(1 Byte)+CRCAddrLoByte(1 Byte)
*							3 区
****************************************************************************/
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 - REG_INPUT_START );
        while( usNRegs > 0 )
        {
            *pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] >> 8 );
            *pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] & 0xFF );
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}

/****************************************************************************
* 名	  称:eMBRegHoldingCB 
* 功    能:对应功能码有:06 写保持寄存器 eMBFuncWriteHoldingRegister 
*													16 写多个保持寄存器 eMBFuncWriteMultipleHoldingRegister
*													03 读保持寄存器 eMBFuncReadHoldingRegister
*													23 读写多个保持寄存器 eMBFuncReadWriteMultipleHoldingRegister
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
*						usAddress: 寄存器地址
*						usNRegs: 要读写的寄存器个数
*						eMode: 功能码
* 出口参数:
* 注	  意:4 区
****************************************************************************/
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 - REG_HOLDING_START);
		switch(eMode)
		{                                       
			case MB_REG_READ://读 MB_REG_READ = 0
				while(usNRegs > 0)
				{
					*pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] >> 8);            
					*pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] & 0xFF); 
					iRegIndex++;
					usNRegs--;					
				}                            
			break;
			case MB_REG_WRITE://写 MB_REG_WRITE = 0
				while(usNRegs > 0)
				{         
					usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
					usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
					iRegIndex++;
					usNRegs--;
				}
			break;				
		}
	}
	else//错误
	{
		eStatus = MB_ENOREG;
	}	
	
	return eStatus;
}

/****************************************************************************
* 名	  称:eMBRegCoilsCB 
* 功    能:对应功能码有:01 读线圈 eMBFuncReadCoils
*						  05 写线圈 eMBFuncWriteCoil
*						  15 写多个线圈 eMBFuncWriteMultipleCoils
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
*						usAddress: 线圈地址
*						usNCoils: 要读写的线圈个数
*						eMode: 功能码
* 出口参数:
* 注	  意:如继电器 
*						0 区
****************************************************************************/
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
	eMBErrorCode    eStatus = MB_ENOERR;
	int             iRegIndex;
	u8 i;
	USHORT readNumber=usNCoils;
	USHORT coilValue=0x0000;
	if((usAddress >= REG_COILS_START)&&\
	((usAddress+usNCoils) <= (REG_COILS_START + REG_COILS_SIZE)))
	{
		iRegIndex = (int)(usAddress + usNCoils-REG_COILS_START);
		switch(eMode)
		{                                       
			case MB_REG_READ://读 MB_REG_READ = 0
				for(i=0;i<usNCoils;i++)
				{
					readNumber--;
					iRegIndex--;
					coilValue|=ucRegCoilsBuf[iRegIndex]<<readNumber;
				}
				if(usNCoils<=8)
				{
					* pucRegBuffer=coilValue;
				}
				else
				{
					* pucRegBuffer++ = (coilValue)&0x00ff;
					* pucRegBuffer++ = (coilValue>>8)&0x00ff;
				}
			break;                            
			case MB_REG_WRITE://写 MB_REG_WRITE = 1
				while(usNCoils > 0)
				{         
					// 			usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
					//           usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
						iRegIndex++;
						usNCoils--;
				}
			break;
		}
	}
	else//错误
	{
		eStatus = MB_ENOREG;
	}	

	return eStatus;
}
/****************************************************************************
* 名	  称:eMBRegDiscreteCB 
* 功    能:读取离散寄存器,对应功能码有:02 读离散寄存器 eMBFuncReadDiscreteInputs
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
*						usAddress: 寄存器地址
*						usNDiscrete: 要读取的寄存器个数
* 出口参数:
* 注	  意:1 区
****************************************************************************/
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
	eMBErrorCode    eStatus = MB_ENOERR;
	int             iRegIndex;
	u8 i;
	USHORT readNumber=usNDiscrete;
	USHORT coilValue=0x0000;
	iRegIndex = (int)(usAddress + usNDiscrete-REG_DISCRETE_START);
	if((usAddress >= REG_DISCRETE_START)&&\
	((usAddress+usNDiscrete) <= (REG_DISCRETE_START + REG_DISCRETE_SIZE)))
	{
		for(i=0;i<usNDiscrete;i++)
		{
			readNumber--;
			iRegIndex--;
			coilValue|=ucRegDiscreteBuf[iRegIndex]<<readNumber;
		}
		if(usNDiscrete<=8)
		{
			* pucRegBuffer=coilValue;
		}
		else
		{
			* pucRegBuffer++ = (coilValue)&0x00ff;
			* pucRegBuffer++ = (coilValue>>8)&0x00ff;
		}
	}
	else
	{
		eStatus = MB_ENOREG;
	}
    return eStatus;
}


给出完整代码供大家下载。https://download.csdn.net/download/qq_15181569/12264170

原创文章 81 获赞 48 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_15181569/article/details/105043406