stm32--free modbus 1.5.0移植(作为从机)

添加文件

  1. 获取原始free modbus library(官网
  2. 将...\freemodbus-v1.5.0\demo\BARE中的所有文件复制到...\freemodbus-v1.5.0\modbus中,修改demo.c文件名为user_mb_app.c
  3. 将...\freemodbus-v1.5.0\modbus中的所有.c文件全部添加到项目中
  4. 在项目路径中添加所有.c、.h文件路径

添加完成后项目结构图:

移植修改

需要修改的文件:

  1. port.h:补全开关总中断的宏定义、宏定义串口和定时器
    #define ENTER_CRITICAL_SECTION( )   __set_PRIMASK(1); //关闭中断
    #define EXIT_CRITICAL_SECTION( )    __set_PRIMASK(0); //开启中断
  2. portserial.c:补全串口相关函数(串口中断使能选择、串口初始化、发送1字节、接收1字节、串口中断服务函数)
    • 注意事项:
      1. 使能中断:发送中断应使用TC而非TXE,否则可能会出现最后一个字节不能成功发送的情况。此外由于是用485发送,所以在使能中断时,应同时转换485收发转换引脚。使能中断前,应判断对应的标志位是否为1,为1则清除该标志位。
      2. 串口初始化:初始化前用USART_DeInit重置寄存器;引脚初始化(GPIO)->串口初始化(USART)->中断初始化(NVIC);参数中的ucPORT和eParity都应该忽略。
      3. 发送1字节:不用循环等待发送完成,因为已经有发送完成中断了
      4. 串口中断服务函数:在stm32f0xx_it.c中添加USART3_4_IRQHandler函数,跳转到本文件中的prvvModbusUARTISR函数。
    •   1 /*
        2  * FreeModbus Libary: BARE Port
        3  * Copyright (C) 2006 Christian Walter <wolti@sil.at>
        4  *
        5  * This library is free software; you can redistribute it and/or
        6  * modify it under the terms of the GNU Lesser General Public
        7  * License as published by the Free Software Foundation; either
        8  * version 2.1 of the License, or (at your option) any later version.
        9  *
       10  * This library is distributed in the hope that it will be useful,
       11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       13  * Lesser General Public License for more details.
       14  *
       15  * You should have received a copy of the GNU Lesser General Public
       16  * License along with this library; if not, write to the Free Software
       17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       18  *
       19  * File: $Id: portserial.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
       20  */
       21 
       22 #include "port.h"
       23 
       24 /* ----------------------- Modbus includes ----------------------------------*/
       25 #include "mb.h"
       26 #include "mbport.h"
       27 
       28 /* ----------------------- static functions ---------------------------------*/
       29 static void prvvUARTTxReadyISR( void );
       30 static void prvvUARTRxISR( void );
       31 
       32 #define MODBUS_SEND()     (GPIO_SetBits(MODBUS_USART_CTRL_PORT, MODBUS_USART_CTRL_PIN))
       33 #define MODBUS_RECIEVE()  (GPIO_ResetBits(MODBUS_USART_CTRL_PORT, MODBUS_USART_CTRL_PIN))
       34 
       35 /* ----------------------- Start implementation -----------------------------*/
       36 void
       37 vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
       38 {
       39   /* If xRXEnable enable serial receive interrupts. If xTxENable enable
       40    * transmitter empty interrupts.
       41    */
       42   if(xRxEnable==TRUE) {
       43     MODBUS_RECIEVE();
       44     if(USART_GetFlagStatus(MODBUS_USART, USART_FLAG_RXNE) == SET) {
       45       USART_ClearFlag(MODBUS_USART, USART_FLAG_RXNE);
       46     }
       47     USART_ITConfig(MODBUS_USART, USART_IT_RXNE, ENABLE);
       48   } else if(xRxEnable == FALSE) {
       49     MODBUS_SEND();
       50     USART_ITConfig(MODBUS_USART, USART_IT_RXNE, DISABLE);
       51   }
       52   
       53   if(xTxEnable==TRUE) {
       54     MODBUS_SEND();
       55     if(USART_GetFlagStatus(MODBUS_USART, USART_FLAG_TC) == SET) {
       56       USART_ClearFlag(MODBUS_USART, USART_FLAG_TC);
       57     }
       58     USART_ITConfig(MODBUS_USART, USART_IT_TC, ENABLE);
       59   } else if(xTxEnable == FALSE) {
       60     MODBUS_RECIEVE();
       61     USART_ITConfig(MODBUS_USART, USART_IT_TC, DISABLE);
       62   }
       63 }
       64 
       65 BOOL
       66 xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
       67 {
       68   /*****************************引脚初始化*************************************/
       69   GPIO_InitTypeDef  GPIO_InitStructure;
       70   
       71   //时钟使能
       72   RCC_AHBPeriphClockCmd(MODBUS_USART_TX_CLK | MODBUS_USART_RX_CLK | MODBUS_USART_CTRL_CLK, ENABLE);
       73   MODBUS_USART_CLK_INIT(MODBUS_USART_CLK, ENABLE);
       74   
       75   //复用功能定义
       76   GPIO_PinAFConfig(MODBUS_USART_TX_PORT, MODBUS_USART_TX_SOURCE, MODBUS_USART_TX_AF);
       77   GPIO_PinAFConfig(MODBUS_USART_RX_PORT, MODBUS_USART_RX_SOURCE, MODBUS_USART_RX_AF);
       78   
       79   //引脚功能定义
       80   GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
       81   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
       82   GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;
       83   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3; //50MHz
       84   
       85   //TX
       86   GPIO_InitStructure.GPIO_Pin = MODBUS_USART_TX_PIN;
       87   GPIO_Init(MODBUS_USART_TX_PORT, &GPIO_InitStructure);
       88   
       89   //RX
       90   GPIO_InitStructure.GPIO_Pin = MODBUS_USART_RX_PIN;
       91   GPIO_Init(MODBUS_USART_RX_PORT, &GPIO_InitStructure);
       92   
       93   //CTRL
       94   GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
       95   GPIO_InitStructure.GPIO_Pin   = MODBUS_USART_CTRL_PIN;
       96   GPIO_Init(MODBUS_USART_CTRL_PORT, &GPIO_InitStructure);
       97   MODBUS_RECIEVE(); //接收模式
       98   
       99   /*****************************串口初始化*************************************/
      100   USART_InitTypeDef USART_InitStructure;
      101   
      102   USART_InitStructure.USART_BaudRate    = ulBaudRate;
      103   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
      104   USART_InitStructure.USART_Mode        = USART_Mode_Rx|USART_Mode_Tx;
      105   USART_InitStructure.USART_Parity      = USART_Parity_No;
      106   USART_InitStructure.USART_StopBits    = USART_StopBits_1;
      107   USART_InitStructure.USART_WordLength  = USART_WordLength_8b;
      108   
      109   USART_Init(MODBUS_USART, &USART_InitStructure);
      110   USART_Cmd(MODBUS_USART, ENABLE);
      111   vMBPortSerialEnable(FALSE, FALSE);
      112   
      113   /*****************************中断初始化*************************************/
      114   NVIC_InitTypeDef  NVIC_InitStructure;
      115   
      116   NVIC_InitStructure.NVIC_IRQChannel          = USART3_4_IRQn;
      117   NVIC_InitStructure.NVIC_IRQChannelCmd       = ENABLE;
      118   NVIC_InitStructure.NVIC_IRQChannelPriority  = 1;
      119   
      120   NVIC_Init(&NVIC_InitStructure);
      121   
      122   return TRUE;
      123 }
      124 
      125 BOOL
      126 xMBPortSerialPutByte( CHAR ucByte )
      127 {
      128   /* Put a byte in the UARTs transmit buffer. This function is called
      129    * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
      130    * called. */
      131   MODBUS_USART->TDR = ucByte; //此处不用等待发送完毕(TC),因为有发送完成中断
      132   return TRUE;
      133 }
      134 
      135 BOOL
      136 xMBPortSerialGetByte( CHAR * pucByte )
      137 {
      138   /* Return the byte in the UARTs receive buffer. This function is called
      139    * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
      140    */
      141   *pucByte = MODBUS_USART->RDR;
      142   return TRUE;
      143 }
      144 
      145 /* Create an interrupt handler for the transmit buffer empty interrupt
      146  * (or an equivalent) for your target processor. This function should then
      147  * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
      148  * a new character can be sent. The protocol stack will then call 
      149  * xMBPortSerialPutByte( ) to send the character.
      150  */
      151 static void prvvUARTTxReadyISR( void )
      152 {
      153     pxMBFrameCBTransmitterEmpty(  );
      154 }
      155 
      156 /* Create an interrupt handler for the receive interrupt for your target
      157  * processor. This function should then call pxMBFrameCBByteReceived( ). The
      158  * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
      159  * character.
      160  */
      161 static void prvvUARTRxISR( void )
      162 {
      163     pxMBFrameCBByteReceived(  );
      164 }
      165 
      166 void  prvvModbusUARTISR( void )
      167 {
      168   if(USART_GetITStatus(MODBUS_USART, USART_IT_TC) == SET) {
      169     prvvUARTTxReadyISR();
      170     USART_ClearITPendingBit(MODBUS_USART, USART_IT_TC);
      171   }
      172 
      173   if(USART_GetITStatus(MODBUS_USART, USART_IT_RXNE) == SET) {
      174     prvvUARTRxISR();
      175     USART_ClearITPendingBit(MODBUS_USART, USART_IT_RXNE);
      176   }
      177 }
      portserial.c
  3. porttimer.c:补全定时器相关函数(定时器初始化、定时器使能、定时器关闭使能、定时器中断服务函数)
    • 注意事项:
      1. 初始化:初始化前应用TIM_DeInit函数重置寄存器值;初始化后要清标志位
      2. 定时器使能:要先关中断、关定时器,然后清标志位、重置计数器,最后开中断、开定时器
      3. 中断服务函数:要先判断中断标志位,再清标志位、进入操作部分。
    •   1 /*
        2  * FreeModbus Libary: BARE Port
        3  * Copyright (C) 2006 Christian Walter <wolti@sil.at>
        4  *
        5  * This library is free software; you can redistribute it and/or
        6  * modify it under the terms of the GNU Lesser General Public
        7  * License as published by the Free Software Foundation; either
        8  * version 2.1 of the License, or (at your option) any later version.
        9  *
       10  * This library is distributed in the hope that it will be useful,
       11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       13  * Lesser General Public License for more details.
       14  *
       15  * You should have received a copy of the GNU Lesser General Public
       16  * License along with this library; if not, write to the Free Software
       17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       18  *
       19  * File: $Id: porttimer.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
       20  */
       21 
       22 /* ----------------------- Platform includes --------------------------------*/
       23 #include "port.h"
       24 
       25 /* ----------------------- Modbus includes ----------------------------------*/
       26 #include "mb.h"
       27 #include "mbport.h"
       28 
       29 /* ----------------------- static functions ---------------------------------*/
       30 static void prvvTIMERExpiredISR( void );
       31 
       32 /* ----------------------- Start implementation -----------------------------*/
       33 BOOL
       34 xMBPortTimersInit( USHORT usTim1Timerout50us )
       35 {
       36   /***************************定时器初始化*************************************/
       37   TIM_TimeBaseInitTypeDef  TIM_InitStructure;
       38   
       39   TIM_DeInit(MODBUS_TIM);
       40   MODBUS_TIM_CLK_INIT(MODBUS_TIM_CLK, ENABLE);
       41   TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
       42   TIM_InitStructure.TIM_CounterMode   = TIM_CounterMode_Up;
       43   TIM_InitStructure.TIM_Period        = usTim1Timerout50us - 1;
       44   TIM_InitStructure.TIM_Prescaler     = 2400 - 1; //48MHz/20kHz=2400
       45   TIM_InitStructure.TIM_RepetitionCounter = 0;
       46   
       47   TIM_TimeBaseInit(MODBUS_TIM, &TIM_InitStructure);
       48   TIM_ClearFlag(MODBUS_TIM, TIM_FLAG_Update);
       49   TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, ENABLE);
       50   TIM_Cmd(MODBUS_TIM, DISABLE);
       51   
       52   /*****************************中断初始化*************************************/
       53   NVIC_InitTypeDef  NVIC_InitStructure;
       54   
       55   NVIC_InitStructure.NVIC_IRQChannel          = TIM2_IRQn;
       56   NVIC_InitStructure.NVIC_IRQChannelCmd       = ENABLE;
       57   NVIC_InitStructure.NVIC_IRQChannelPriority  = 0;
       58   
       59   NVIC_Init(&NVIC_InitStructure);
       60   
       61   return TRUE;
       62 }
       63 
       64 
       65 inline void
       66 vMBPortTimersEnable(  )
       67 {
       68   /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
       69   TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, DISABLE);
       70   TIM_Cmd(MODBUS_TIM, DISABLE);
       71   TIM_ClearITPendingBit(MODBUS_TIM, TIM_IT_Update);
       72   TIM_ClearFlag(MODBUS_TIM, TIM_FLAG_Update);
       73   TIM_SetCounter(MODBUS_TIM, 0);
       74   TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, ENABLE);
       75   TIM_Cmd(MODBUS_TIM, ENABLE);
       76 }
       77 
       78 inline void
       79 vMBPortTimersDisable(  )
       80 {
       81   /* Disable any pending timers. */
       82   TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, DISABLE);
       83   TIM_Cmd(MODBUS_TIM, DISABLE);
       84 }
       85 
       86 /* Create an ISR which is called whenever the timer has expired. This function
       87  * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
       88  * the timer has expired.
       89  */
       90 static void prvvTIMERExpiredISR( void )
       91 {
       92     ( void )pxMBPortCBTimerExpired(  );
       93 }
       94 
       95 void  prvvModbusTIMISR( void )
       96 {
       97   if(TIM_GetITStatus(MODBUS_TIM, TIM_IT_Update) == SET) {
       98     TIM_ClearITPendingBit(MODBUS_TIM, TIM_IT_Update);
       99     prvvTIMERExpiredISR();
      100   }
      101 }
      porttimer.c
  4. user_mb_app.h:定义各模拟寄存器地址
    • 注意事项:
      1. 每个寄存器固定长度16位(2字节)
      2. 寄存器地址:从机内部定义的寄存器地址,要对寻址用的寄存器地址+1【Modbus标准协议规定】。即:从机内部定义的寄存器地址,必须大于1;对于寄存器1-16,寻址时通过0-15来寻址(如:查询寄存器1的值时,指令中的寄存器地址为00 00)。
      3. 换句话说,就是:从机程序中定义寄存器地址为1-16时,文档中的寄存器地址要写成0-15。
  5. user_mb_app.c:补全输入寄存器操作函数、保持寄存器操作函数(操作方式可参见...\freemodbus-v1.5.0\demo\ATSAM3S\demo.c),将main分解为modbus初始化函数和modbus进程函数,添加结构体与模拟寄存器之间的数据交互函数。
    • 注意事项:
      1. eMBInit初始化:仅需更改地址和波特率。
      2. user_mb_app函数中不要用循环(本身就会被应用到主程序中的while(1)中)
    •   1 /* ----------------------- Modbus includes ----------------------------------*/
        2 #include "mb.h"
        3 #include "mbport.h"
        4 #include "user_mb_app.h"
        5 
        6 /* ----------------------- Defines ------------------------------------------*/
        7 #define REG_INPUT_START ((uint16_t)0x0000)
        8 #define REG_INPUT_NREGS 25
        9 #define REG_HOLD_START  ((uint16_t)0x0000)
       10 #define REG_HOLD_NREGS  30
       11 
       12 /* ----------------------- Static variables ---------------------------------*/
       13 static USHORT   usRegInputStart = REG_INPUT_START;
       14 static USHORT   usRegInputBuf[REG_INPUT_NREGS];
       15 static USHORT   usRegHoldStart  = REG_HOLD_START;
       16 static USHORT   usRegHoldBuf[REG_HOLD_NREGS];
       17 extern uint8_t  g_Meter_Data[];
       18 extern uint8_t  g_Check_Data[];
       19 /* ----------------------- Start implementation -----------------------------*/
       20 /******************************************************************************
       21 ** 函数名称: mb_Modbus_Init
       22 ** 功能描述: modbus初始化
       23 ** 入口参数: 无
       24 ** 返 回 值: 无
       25 **
       26 ** 作 者: Cage
       27 ** 日 期: 2018年3月9日
       28 **-----------------------------------------------------------------------------
       29 ******************************************************************************/
       30 void  mb_Modbus_Init(void) {
       31     
       32     uint8_t address = dio_Get_DIP_Value();  //获取拨码开关信息,获得本机地址
       33     ( void )eMBInit( MB_RTU, address, 0, 9600, MB_PAR_NONE );
       34 
       35     /* Enable the Modbus Protocol Stack. */
       36     ( void )eMBEnable(  );
       37 }
       38 
       39 
       40 /******************************************************************************
       41 ** 函数名称: user_mb_app
       42 ** 功能描述: modbus进程函数
       43 ** 入口参数: 无
       44 ** 返 回 值: 无
       45 **
       46 ** 作 者: Cage
       47 ** 日 期: 2018年3月13日
       48 **-----------------------------------------------------------------------------
       49 ******************************************************************************/
       50 void  user_mb_app( void )
       51 {
       52 
       53   ( void )eMBPoll(  );
       54 
       55 }
       56 
       57 
       58 /******************************************************************************
       59 ** 函数名称: _mb_Fresh_Input_Reg
       60 ** 功能描述: 将计量数据结构体中的数据刷新到Modbus模拟寄存器中
       61 ** 入口参数: 无
       62 ** 返 回 值: 无
       63 **
       64 ** 作 者: Cage
       65 ** 日 期: 2018年3月13日
       66 **-----------------------------------------------------------------------------
       67 ******************************************************************************/
       68 static  void  _mb_Fresh_Input_Reg(void) {
       69   uint8_t i;
       70   USHORT  *pmeter_data = (USHORT*)g_Meter_Data;
       71   for(i = 0; i<REG_INPUT_NREGS; i++) {
       72     usRegInputBuf[i] = *pmeter_data++;
       73   }
       74 }
       75 
       76 
       77 /******************************************************************************
       78 ** 函数名称: _mb_Fresh_Check_Struct
       79 ** 功能描述: 将Modbus模拟寄存器中的数据刷新到校表数据结构体
       80 ** 入口参数: 无
       81 ** 返 回 值: 无
       82 **
       83 ** 作 者: Cage
       84 ** 日 期: 2018年3月13日
       85 **-----------------------------------------------------------------------------
       86 ******************************************************************************/
       87 static  void  _mb_Fresh_Check_Struct(void) {
       88   uint8_t i;
       89   USHORT  *pcheck_data = (USHORT*)g_Check_Data;
       90   for(i = 0; i<REG_HOLD_NREGS; i++) {
       91     *pcheck_data++ = usRegHoldBuf[i];
       92   }
       93 }
       94 
       95 
       96 //读输入寄存器
       97 eMBErrorCode
       98 eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
       99 {
      100     eMBErrorCode    eStatus = MB_ENOERR;
      101     int             iRegIndex;
      102 
      103     if( ( usAddress >= REG_INPUT_START )
      104         && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
      105     {
      106         _mb_Fresh_Input_Reg();  //将计量数据结构体中的数据刷新到Modbus模拟寄存器中
      107         iRegIndex = ( int )( usAddress - usRegInputStart );
      108         while( usNRegs > 0 )
      109         {
      110             *pucRegBuffer++ =
      111                 ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
      112             *pucRegBuffer++ =
      113                 ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
      114             iRegIndex++;
      115             usNRegs--;
      116         }
      117     }
      118     else
      119     {
      120         eStatus = MB_ENOREG;
      121     }
      122 
      123     return eStatus;
      124 }
      125 
      126 //写保持寄存器--未定义
      127 eMBErrorCode
      128 eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
      129                  eMBRegisterMode eMode )
      130 {
      131     eMBErrorCode    eStatus = MB_ENOERR;
      132     int             iRegIndex;
      133 
      134     if( ( usAddress >= REG_HOLD_START )
      135         && ( usAddress + usNRegs <= REG_HOLD_START + REG_HOLD_NREGS ) )
      136     {
      137         iRegIndex = ( int )( usAddress - usRegHoldStart );
      138         if(eMode == MB_REG_WRITE) {
      139             while( usNRegs > 0 )
      140             {
      141                 usRegHoldBuf[iRegIndex] = *pucRegBuffer++ << 8;
      142                 usRegHoldBuf[iRegIndex] |= *pucRegBuffer++;
      143                 iRegIndex++;
      144                 usNRegs--;
      145             }
      146         }
      147         _mb_Fresh_Check_Struct(); //将Modbus模拟寄存器中的数据刷新到校表数据结构体
      148     }
      149     else
      150     {
      151         eStatus = MB_ENOREG;
      152     }
      153 
      154     return eStatus;
      155 }
      156 
      157 /*********************************不使用的功能*********************************/
      158 eMBErrorCode
      159 eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
      160                eMBRegisterMode eMode )
      161 {
      162     return MB_ENOREG;
      163 }
      164 
      165 eMBErrorCode
      166 eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
      167 {
      168     return MB_ENOREG;
      169 }
      user_mb_app.c
  6. mb.c:在eMBPoll函数中,EV_EXECUTE状态下,准备好发送后,手动发送第一个字节,启动发送
    •  1         case EV_EXECUTE:
       2             ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
       3             eException = MB_EX_ILLEGAL_FUNCTION;
       4             for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
       5             {
       6                 /* No more function handlers registered. Abort. */
       7                 if( xFuncHandlers[i].ucFunctionCode == 0 )
       8                 {
       9                     break;
      10                 }
      11                 else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
      12                 {
      13                     eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
      14                     break;
      15                 }
      16             }
      17 
      18             /* If the request was not sent to the broadcast address we
      19              * return a reply. */
      20             if( ucRcvAddress != MB_ADDRESS_BROADCAST )
      21             {
      22                 if( eException != MB_EX_NONE )
      23                 {
      24                     /* An exception occured. Build an error frame. */
      25                     usLength = 0;
      26                     ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
      27                     ucMBFrame[usLength++] = eException;
      28                 }
      29                 if( ( eMBCurrentMode == MB_ASCII ) && MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS )
      30                 {
      31                     vMBPortTimersDelay( MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS );
      32                 }                
      33                 eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
      34                 /*发送数组准备完毕,串口切换到了发送状态,但TC标志位为0,不能自动开始发送*/
      35                 if( eStatus == MB_ENOERR )
      36                 {
      37                   xMBRTUTransmitFSM();  //发送第一个字节,启动发送
      38                 }
      39               }
      40             break;
      mb.c节选

       

调试

  1. 串口收到数据后,无限进入中断
    1. 现象:仿真时,一直进入中断服务函数,不作任何处理后跳出;如此反复进入中断服务函数。
    2. 判断:ORE标志位未清除。RXNEIE中断使能包括RXNE标志位和ORE标志位,中断服务函数中只判断、处理了RXNE标志位。
    3. 处理:在portserial.c的中断服务函数prvvModbusUARTISR中,加入USART_IT_ORE标志位的判断与处理【注:stm32f072库函数中的USART_IT_ORE标志位定义错误,需要修改】
    4. 结果:问题解决
  2. Modbus收到数据后不响应
    1. 现象:跟踪发现,Modbus协议一直进行到“串口发送”之前都是正常的,可是之后却没有发送
    2. 原因:上一次发送最后一个字节时,发送中断中清除了TC标志位;切换到发送状态、使能TCIE后,TC标志位为0,无法启动发送。
    3. 解决方案:
      1. TXE+TC发送:
        1. 中断使能函数:切换为发送状态时,使能TXE中断而非TC中断(由TXE启动发送,TXE永不手动清零)
        2. 中断服务函数:TXE启动发送后,将中断使能由TXE改为TC,之后由TC判断发送完成、清TC标志位
      2. 手动启动:切换为发送状态后,手动启动发送(发送第一个字节)
    4. 处理:选择了方案2,问题解决。

仿真跟踪--Modbus数据处理流程(RTU)

  1. modbus poll主进程(eMBPoll)获取消息状态,执行指令
  2. 数据接收:串口中断接收数据(数据存入ucRTUBuf数组)->超过3.5us没有收到数据->判断一串数据接收完毕->将“接收完毕”消息添加到消息队列
  3. 数据处理:
    1. eMBPoll获取到“接收完毕”消息,令ucMBFrame指针指向ucRTUBuf数组的第1位(命令字),获取地址位和数据长度(不含地址位和校验位的长度),将“执行”消息添加到消息队列
    2. eMBPoll获取到“执行”消息,通过ucMBFrame中的命令字,进行对应的操作(比如:04--读输入寄存器),将要发回的数据存入ucMBFrame(不含地址位和校验位)
    3. 将ucMBFrame中的数据加上地址位后计算校验位,将地址位和校验位存入ucRTUBuf数组,将发送状态标志由空闲转为发送,串口状态转为发送
      • --至此发送数组(ucRTUBuf)和串口状态都已经准备完毕,但没有发送指令
    4. 【添加】手动发送发送数组的第一个字节,启动发送
  4. 数据发送:通过串口将发送数组逐字节发送。
posted @ 2018-03-13 16:36  花火·  阅读(12712)  评论(0编辑  收藏  举报