1. 程式人生 > >freemodbus 1.5 移植modbusRTU到stm32f429igt6,使用串列埠232

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