freemodbus 1.5 移植modbusRTU到stm32f429igt6,使用串口232

对modbus中的包含下的mbconfig.h进行编辑,把Ascii码配置为0我们只用用RTU

1.可以新建一个STM32工程,我这里是用的是例程串口232收发的例程,用的是串口2

2.主要先将freemodbus 1.5源码中的modbus文件夹和演示文件夹里的BARE文件复制到工程,然后添加文件到工程

3.配置串口使能函数vMBPortSerialEnable(BOOL xRxEnable,BOOL xTxEnable)

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

	if(TRUE==xTxEnable)
	{
		USART_ITConfig(RS232_USART, USART_IT_TXE, ENABLE);
	}
	else
	{
	   USART_ITConfig(RS232_USART, USART_IT_TXE, DISABLE);
	}
}

串口初始化函数xMBPortSerialInit(UCHAR ucPORT,ULONG ulBaudRate,UCHAR ucDataBits,eMBParity eParity)

可以将232串口初始化的例程复制到这个函数

BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
	(void)ucPORT; //不修改串口
	(void)ucDataBits; //不修改数据长度
	(void)eParity; //不修改格式
	
	//////////////////////////////////////////////////////////////////////////////////////////////
	GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
		
  RCC_AHB1PeriphClockCmd( RS232_USART_RX_GPIO_CLK|RS232_USART_TX_GPIO_CLK, ENABLE);

  /*使用UART时钟*/
  RCC_APB1PeriphClockCmd(RS232_USART_CLK, ENABLE);
  
   /*连接PXx到USARTx_Tx*/
  GPIO_PinAFConfig(RS232_USART_RX_GPIO_PORT,RS232_USART_RX_SOURCE, RS232_USART_RX_AF);

   /*连接PXx到USARTx_Rx*/
  GPIO_PinAFConfig(RS232_USART_TX_GPIO_PORT,RS232_USART_TX_SOURCE,RS232_USART_TX_AF);

    /*配置Tx引脚为复用功能*/
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Pin = RS232_USART_TX_PIN  ;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(RS232_USART_TX_GPIO_PORT, &GPIO_InitStructure);

   /*配置Rx引脚为复用功能*/
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = RS232_USART_RX_PIN;
  GPIO_Init(RS232_USART_RX_GPIO_PORT, &GPIO_InitStructure);
			
  /* 配置串口RS232_USART模式*/
  USART_InitStructure.USART_BaudRate = RS232_USART_BAUDRATE;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  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(RS232_USART, &USART_InitStructure); 
  USART_ITConfig(RS232_USART, USART_IT_RXNE, ENABLE);
  USART_Cmd(RS232_USART, ENABLE);
  ////////////////////////////////////////////////////////////////////////////////////////////////
	NVIC_InitTypeDef NVIC_InitStructure;
  
  /* Configure one bit for preemption priority */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  /*中断初始化 */
  //设置NVIC优先级分组为Group2:0-3抢占优先级,0-3的响应优先级
  NVIC_InitStructure.NVIC_IRQChannel = RS232_USART_IRQ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);


    return TRUE;
}

 注意:

          1- 我这里用的例程串口的.H文件的波特率RS232_USART_BAUDRATE,不是MODBUS初始化函数  

             eMBInit(MB_RTU,1,1,9600,MB_PAR_NONE);里的波特率9600,而且最后返回TRUE

           2- 当波特率大于19200时,usTimerT35_50us固定为35us;否则 

                usTimerT35_50us =(7UL * 220000UL)/(2UL * ulBaudRate);

4.xMBPortSerialPutByte的作用是将字节数据送到串口。把正常用的串口发送拿过来就可以了

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);  
    while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET){};
	
    return TRUE;
}

5.xMBPortSerialGetByte的作用是从串口接收数据并且把数据传给指定内存。

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(RS232_USART);
    return TRUE;
}

6.配置中断函数

void RS232_USART_IRQHandler(void)
{
	if(USART_GetITStatus(RS232_USART, USART_IT_RXNE) == SET)
	{		
		prvvUARTRxISR();
		USART_ClearITPendingBit(RS232_USART, USART_IT_RXNE);
	}

	if(USART_GetITStatus(RS232_USART, USART_IT_TXE) == SET)
	{
		prvvUARTTxReadyISR();

	}
}

注意:需要将这两个函数void prvvUARTTxReadyISR(void);和void prvvUARTRxISR(void); 的静态去掉,并在port.h里声明

          才能在中断文件里引用

7.设置定时器初始化,使用的是TIM2

BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  
        TIM_DeInit(TIM2);

        TIM_TimeBaseStructure.TIM_Period = usTim1Timerout50us-1;
        TIM_TimeBaseStructure.TIM_Prescaler = (9000 - 1);	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	TIM_ARRPreloadConfig(TIM2, ENABLE);
 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);	
 
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
	TIM_Cmd(TIM2, DISABLE);
	return TRUE;
}

8.vMBPortTimersEnable()使能定时器函数

void
vMBPortTimersEnable(  )
{	
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	TIM_SetCounter(TIM2, 0);
	TIM_Cmd(TIM2, ENABLE);

}

9.vMBPortTimersDisable()定时器失能(关闭)函数

void
vMBPortTimersDisable(  )
{
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
	TIM_SetCounter(TIM2, 0);
	//TIM_Cmd(TIM2, DISABLE);

}

10.配置定时器中断函数

void TIM2_IRQHandler(void)
{
	prvvTIMERExpiredISR();
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	
}

注意:需要把static void prvvTIMERExpiredISR(void)函数的静去掉,并且声明在port.h里才能在中断文件里引用

11.新建port.c文件,主要是定义开启/关闭全局中断函数

​
port.c

#include "stm32f4xx.h"
#include "port.h"

void EnterCriticalSection(void)
{
	//看看这个函数的使用位置就知道他们是反过来的,Enter本来意思是进入,但他的位置表明其实应该关闭
    //开启全局中断
	__disable_irq();
}

void ExitCriticalSection(void)
{
	//开启全局中断
	__enable_irq();
}

​

注意:在mbrtu.c文件里

看看这两个函数的位置就知道,按照一般逻辑来说:

     一,都是先关闭中断,然后处理数据,再打开终端,

     湾并且输入是使能/打开的意思,EXIT是失能/关闭的意思

所以我觉得这两个函数的位置是弄反的,所以我直接在两个函数的具体实现里调换过来。

12.新建一个modbus.c文件,复制demo.c里的四个函数(的的的Modbus通信中,总共有四类的寄存器,开关输入寄存器,线圈寄存器,保持寄存器和输入寄存器)过来,然后自己实现

//这是.h文件的内容
#include "mb.h"
#include "stm32f4xx.h"
#include "bsp_led.h" 
#include "relay.h"
#include "modbus.h"
#include "Timer5.h"
#include "mbrtu.h"
#include "main.h"
#include "bsp_SysTick.h"
#include "new.h"

/* -----------------------Slave Defines -------------------------------------*/
#define S_DISCRETE_INPUT_START        1
#define S_DISCRETE_INPUT_NDISCRETES   16
#define S_COIL_START                  1
#define S_COIL_NCOILS                 104
#define S_REG_INPUT_START             1
#define S_REG_INPUT_NREGS             100
#define S_REG_HOLDING_START           1
#define S_REG_HOLDING_NREGS           100
//从机模式:在保持寄存器中,各个地址对应得功能定义
#define          S_HD_RESERVE                     0		  //保留
#define          S_HD_CPU_USAGE_MAJOR             1         //当前CPU利用率的整数位
#define          S_HD_CPU_USAGE_MINOR             2         //当前CPU利用率的小数位
//从机模式:在输入寄存器中,各个地址对应的功能定义
#define          S_IN_RESERVE                     0		  //保留

//从机模式:在线圈中,各个地址对应的功能定义
#define          S_CO_RESERVE                     2		  //保留

//从机模式:在离散输入中,各个地址对应的功能定义
#define          S_DI_RESERVE                     1		  //保留
/*------------------------Slave mode use these variables----------------------*/
//////Slave mode:DiscreteInputs variables
USHORT   usSDiscInStart                               = S_DISCRETE_INPUT_START;
#if S_DISCRETE_INPUT_NDISCRETES%8
UCHAR    ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR    ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8]  ;
#endif
//Slave mode:Coils variables
USHORT   usSCoilStart                                 = S_COIL_START;
#if S_COIL_NCOILS%8
UCHAR    ucSCoilBuf[S_COIL_NCOILS/8+1]                ;
#else
 UCHAR    ucSCoilBuf[14]                  ;
#endif
//Slave mode:InputRegister variables
USHORT   usSRegInStart                                = S_REG_INPUT_START;
USHORT   usSRegInBuf[100];  
//float   usSRegInBuf[S_REG_INPUT_NREGS];


//Slave mode:HoldingRegister variables
USHORT   usSRegHoldStart                              = S_REG_HOLDING_START;
USHORT   usSRegHoldBuf[250]           ;



下面是modbus.c的内容

/*------------------------Slave mode use these variables----------------------*/
//////Slave mode:DiscreteInputs variables
USHORT   usSDiscInStart                               = S_DISCRETE_INPUT_START;
#if S_DISCRETE_INPUT_NDISCRETES%8
UCHAR    ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR    ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8]  ;
#endif
//Slave mode:Coils variables
USHORT   usSCoilStart                                 = S_COIL_START;
#if S_COIL_NCOILS%8
UCHAR    ucSCoilBuf[S_COIL_NCOILS/8+1]                ;
#else
 UCHAR    ucSCoilBuf[14]                  ;
#endif
//Slave mode:InputRegister variables
USHORT   usSRegInStart                                = S_REG_INPUT_START;
USHORT   usSRegInBuf[100];  
//float   usSRegInBuf[S_REG_INPUT_NREGS];


//Slave mode:HoldingRegister variables
USHORT   usSRegHoldStart                              = S_REG_HOLDING_START;
USHORT   usSRegHoldBuf[250]           ;

eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    int             iRegIndex;
    USHORT *        pusRegInputBuf;
    UCHAR           REG_INPUT_START;
    UCHAR           REG_INPUT_NREGS;
    UCHAR           usRegInStart;
	  
	      	pusRegInputBuf = usSRegInBuf;
    	REG_INPUT_START = S_REG_INPUT_START;
    	REG_INPUT_NREGS = S_REG_INPUT_NREGS;
    	usRegInStart = usSRegInStart;

    if( ( usAddress >= REG_INPUT_START )
        && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegInStart );
        while( usNRegs > 0 )
        {

				*pucRegBuffer++ = ( unsigned char )( pusRegInputBuf[iRegIndex] >> 8 );
				*pucRegBuffer++ = ( unsigned char )( pusRegInputBuf[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;
    USHORT *        pusRegHoldingBuf;
    UCHAR           REG_HOLDING_START;
    UCHAR           REG_HOLDING_NREGS;
    UCHAR           usRegHoldStart;
      
	
	    	pusRegHoldingBuf = usSRegHoldBuf;
    	REG_HOLDING_START = S_REG_HOLDING_START;
    	REG_HOLDING_NREGS = S_REG_HOLDING_NREGS;
    	usRegHoldStart = usSRegHoldStart;
	



    if( ( usAddress >= REG_HOLDING_START ) &&
        ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegHoldStart );
        switch ( eMode )
        {
            /* Pass current register values to the protocol stack. */
        case MB_REG_READ:
            while( usNRegs > 0 )
            {
				*pucRegBuffer++ = ( unsigned char )( pusRegHoldingBuf[iRegIndex] >> 8 );
				*pucRegBuffer++ = ( unsigned char )( pusRegHoldingBuf[iRegIndex] & 0xFF );
                iRegIndex++;
                usNRegs--;
            }
            break;

            /* Update current register values with new values from the
             * protocol stack. */
        case MB_REG_WRITE:
            while( usNRegs > 0 )
            {
                pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
                pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
                iRegIndex++;
                usNRegs--;
            }
            break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    int             iRegIndex , iRegBitIndex , iNReg;

    iNReg =  usNCoils / 8 + 1;        //Õ¼ÓüĴæÆ÷ÊýÁ¿

  

    if( ( usAddress >= S_COIL_START ) &&
        ( usAddress + usNCoils <= S_COIL_START + S_COIL_NCOILS ) )
    {
        iRegIndex    = ( int )( usAddress - S_COIL_START ) / 8 ;    //ÿ¸ö¼Ä´æÆ÷´æ8¸ö
		iRegBitIndex = ( int )( usAddress - usSCoilStart ) % 8 ;	   //Ïà¶ÔÓڼĴæÆ÷ÄÚ²¿µÄλµØÖ·
        switch ( eMode )
        {
            /* Pass current coil values to the protocol stack. */
        case MB_REG_READ:
            while( iNReg > 0 )
            {
								*pucRegBuffer++ = xMBUtilGetBits(&ucSCoilBuf[iRegIndex++] , iRegBitIndex , 8);
                iNReg --;
            }
						pucRegBuffer --;
						usNCoils = usNCoils % 8;                        //ÓàϵÄÏßȦÊý	
						*pucRegBuffer = *pucRegBuffer <<(8 - usNCoils); //¸ßλ²¹Áã
						*pucRegBuffer = *pucRegBuffer >>(8 - usNCoils);
            break;

            /* Update current coil values with new values from the
             * protocol stack. */
        case MB_REG_WRITE:
            while(iNReg > 1)									 //×îºóÃæÓàÏÂÀ´µÄÊýµ¥¶ÀËã
            {
				xMBUtilSetBits(&ucSCoilBuf[iRegIndex++] , iRegBitIndex  , 8 , *pucRegBuffer++);
                iNReg--;
            }
			usNCoils = usNCoils % 8;                            //ÓàϵÄÏßȦÊý
			if (usNCoils != 0)                                  //xMBUtilSetBits·½·¨ ÔÚ²Ù×÷λÊýÁ¿Îª0ʱ´æÔÚbug
			{
				xMBUtilSetBits(&ucSCoilBuf[iRegIndex++], iRegBitIndex, usNCoils,
						*pucRegBuffer++);
			}
			break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    eMBErrorCode    eStatus = MB_ENOERR;
	int             iRegIndex , iRegBitIndex , iNReg;
	UCHAR *         pucDiscreteInputBuf;
    UCHAR           DISCRETE_INPUT_START;
    UCHAR           DISCRETE_INPUT_NDISCRETES;
    UCHAR           usDiscreteInputStart;
	iNReg =  usNDiscrete / 8 + 1;        //Õ¼ÓüĴæÆ÷ÊýÁ¿
    
	
	    	pucDiscreteInputBuf = ucSDiscInBuf;
    	DISCRETE_INPUT_START = S_DISCRETE_INPUT_START;
    	DISCRETE_INPUT_NDISCRETES = S_DISCRETE_INPUT_NDISCRETES;
    	usDiscreteInputStart = usSDiscInStart;

      pucDiscreteInputBuf[0]=0x07;
    if( ( usAddress >= DISCRETE_INPUT_START )
        && ( usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES ) )
    {
				iRegIndex    = ( int )( usAddress - usDiscreteInputStart ) / 8 ;    //ÿ¸ö¼Ä´æÆ÷´æ8¸ö
				iRegBitIndex = ( int )( usAddress - usDiscreteInputStart ) % 8 ;	   //Ïà¶ÔÓڼĴæÆ÷ÄÚ²¿µÄλµØÖ·


					while( iNReg > 0 )
					{
						*pucRegBuffer++ = xMBUtilGetBits(&pucDiscreteInputBuf[iRegIndex++] , iRegBitIndex , 8);
						iNReg --;
					}
					pucRegBuffer --;
					usNDiscrete = usNDiscrete % 8;                     //ÓàϵÄÏßȦÊý
					*pucRegBuffer = *pucRegBuffer <<(8 - usNDiscrete); //¸ßλ²¹Áã
					*pucRegBuffer = *pucRegBuffer >>(8 - usNDiscrete);
	  }
    
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}

13.在主函数里初始化,然后使用输入寄存器第一和第二个寄存器来测试

int main(void)
{

	eMBInit(MB_RTU, 1, 1, 9600, MB_PAR_NONE);

	eMBEnable();
	
	
	test_data1.d=11;
  while(1)
	{	
       ( void)eMBPoll(); 
			  	test_data1.d =test_data1.d +0.001;
					usSRegInBuf[0]=test_data1.value[3];
					usSRegInBuf[0]=(usSRegInBuf[0]<<8)+test_data1.value[2];
					usSRegInBuf[1]=test_data1.value[1];
					usSRegInBuf[1]=(usSRegInBuf[1]<<8)+test_data1.value[0];

	}	


}

注意:TEST_DATA1是联体数,不懂得可以百度


移植好的代码链接:https//download.csdn.net/download/qq_22079023/10840362

我不知道怎么直接把代码放到这里点击就可以下载,有会的希望能告知一下!

如果对于freemodbus不了解的可以看看这个https://blog.csdn.net/liukais/article/details/73385328

猜你喜欢

转载自blog.csdn.net/qq_22079023/article/details/84934983