zoukankan      html  css  js  c++  java
  • stm32--free modbus 1.5.0移植(作为从机)

    添加文件

    1. 获取原始free modbus library(官网
    2. 将...freemodbus-v1.5.0demoBARE中的所有文件复制到...freemodbus-v1.5.0modbus中,修改demo.c文件名为user_mb_app.c
    3. 将...freemodbus-v1.5.0modbus中的所有.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.0demoATSAM3Sdemo.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. 数据发送:通过串口将发送数组逐字节发送。
  • 相关阅读:
    Python 2.7出现但Python 3.5不出现“ImportError: No module named xxx”的解决方案
    Flask REST API サンプル(エラー処理部分を参照)
    vue:vuex store里面的数据更新后,如何在页面同步更新
    vue+VeeValidate 校验范围实例分析(部分校验,全部校验)
    postgresql时区设置,系统主机与数据库时间不一致
    执行Docker命令,提示没有权限的对应方法
    Linux Mint安装Docker注意事项
    JS过滤器(filter)的用法
    NUXT中使用自带axios
    如何通过一个网卡访问两个网段
  • 原文地址:https://www.cnblogs.com/cage666/p/8529885.html
Copyright © 2011-2022 走看看