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

本文详细介绍了如何在STM32上移植FreeModbus 1.5.0库作为Modbus RTU从机,包括配置串口、定时器、中断,以及模拟寄存器的初始化和操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

stm32–free modbus 1.5.0移植(作为从机)
此文仅最为一个记录,原文地址:stm32–free modbus 1.5.0移植(作为从机)https://www.cnblogs.com/cage666/p/8529885.html

添加文件

  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文件路径
    添加完成后项目结构图:
    在这里插入图片描述
    移植修改
    需要修改的文件:
  5. port.h:补全开关总中断的宏定义、宏定义串口和定时器
	#define ENTER_CRITICAL_SECTION( )   __set_PRIMASK(1); //关闭中断
	#define EXIT_CRITICAL_SECTION( )    __set_PRIMASK(0); //开启中断
  1. portserial.c:补全串口相关函数(串口中断使能选择、串口初始化、发送1字节、接收1字节、串口中断服务函数)
    注意事项:
    使能中断:发送中断应使用TC而非TXE,否则可能会出现最后一个字节不能成功发送的情况。此外由于是用485发送,所以在使能中断时,应同时转换485收发转换引脚。使能中断前,应判断对应的标志位是否为1,为1则清除该标志位。
    串口初始化:初始化前用USART_DeInit重置寄存器;引脚初始化(GPIO)->串口初始化(USART)->中断初始化(NVIC);参数中的ucPORT和eParity都应该忽略。
    发送1字节:不用循环等待发送完成,因为已经有发送完成中断了
    串口中断服务函数:在stm32f0xx_it.c中添加USART3_4_IRQHandler函数,跳转到本文件中的prvvModbusUARTISR函数。
/*
 * FreeModbus Libary: BARE Port
 * Copyright (C) 2006 Christian Walter <wolti@sil.at>
 *
 * 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"

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

/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR( void );
static void prvvUARTRxISR( void );

#define MODBUS_SEND()     (GPIO_SetBits(MODBUS_USART_CTRL_PORT, MODBUS_USART_CTRL_PIN))
#define MODBUS_RECIEVE()  (GPIO_ResetBits(MODBUS_USART_CTRL_PORT, MODBUS_USART_CTRL_PIN))

/* ----------------------- Start implementation -----------------------------*/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
  /* If xRXEnable enable serial receive interrupts. If xTxENable enable
   * transmitter empty interrupts.
   */
  if(xRxEnable==TRUE) {
    MODBUS_RECIEVE();
    if(USART_GetFlagStatus(MODBUS_USART, USART_FLAG_RXNE) == SET) {
      USART_ClearFlag(MODBUS_USART, USART_FLAG_RXNE);
    }
    USART_ITConfig(MODBUS_USART, USART_IT_RXNE, ENABLE);
  } else if(xRxEnable == FALSE) {
    MODBUS_SEND();
    USART_ITConfig(MODBUS_USART, USART_IT_RXNE, DISABLE);
  }
  
  if(xTxEnable==TRUE) {
    MODBUS_SEND();
    if(USART_GetFlagStatus(MODBUS_USART, USART_FLAG_TC) == SET) {
      USART_ClearFlag(MODBUS_USART, USART_FLAG_TC);
    }
    USART_ITConfig(MODBUS_USART, USART_IT_TC, ENABLE);
  } else if(xTxEnable == FALSE) {
    MODBUS_RECIEVE();
    USART_ITConfig(MODBUS_USART, USART_IT_TC, DISABLE);
  }
}

BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
  /*****************************引脚初始化*************************************/
  GPIO_InitTypeDef  GPIO_InitStructure;
  
  //时钟使能
  RCC_AHBPeriphClockCmd(MODBUS_USART_TX_CLK | MODBUS_USART_RX_CLK | MODBUS_USART_CTRL_CLK, ENABLE);
  MODBUS_USART_CLK_INIT(MODBUS_USART_CLK, ENABLE);
  
  //复用功能定义
  GPIO_PinAFConfig(MODBUS_USART_TX_PORT, MODBUS_USART_TX_SOURCE, MODBUS_USART_TX_AF);
  GPIO_PinAFConfig(MODBUS_USART_RX_PORT, MODBUS_USART_RX_SOURCE, MODBUS_USART_RX_AF);
  
  //引脚功能定义
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3; //50MHz
  
  //TX
  GPIO_InitStructure.GPIO_Pin = MODBUS_USART_TX_PIN;
  GPIO_Init(MODBUS_USART_TX_PORT, &GPIO_InitStructure);
  
  //RX
  GPIO_InitStructure.GPIO_Pin = MODBUS_USART_RX_PIN;
  GPIO_Init(MODBUS_USART_RX_PORT, &GPIO_InitStructure);
  
  //CTRL
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_Pin   = MODBUS_USART_CTRL_PIN;
  GPIO_Init(MODBUS_USART_CTRL_PORT, &GPIO_InitStructure);
  MODBUS_RECIEVE(); //接收模式
  
  /*****************************串口初始化*************************************/
  USART_InitTypeDef USART_InitStructure;
  
  USART_InitStructure.USART_BaudRate    = ulBaudRate;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode        = USART_Mode_Rx|USART_Mode_Tx;
  USART_InitStructure.USART_Parity      = USART_Parity_No;
  USART_InitStructure.USART_StopBits    = USART_StopBits_1;
  USART_InitStructure.USART_WordLength  = USART_WordLength_8b;
  
  USART_Init(MODBUS_USART, &USART_InitStructure);
  USART_Cmd(MODBUS_USART, ENABLE);
  vMBPortSerialEnable(FALSE, FALSE);
  
  /*****************************中断初始化*************************************/
  NVIC_InitTypeDef  NVIC_InitStructure;
  
  NVIC_InitStructure.NVIC_IRQChannel          = USART3_4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelCmd       = ENABLE;
  NVIC_InitStructure.NVIC_IRQChannelPriority  = 1;
  
  NVIC_Init(&NVIC_InitStructure);
  
  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. */
  MODBUS_USART->TDR = ucByte; //此处不用等待发送完毕(TC),因为有发送完成中断
  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 = MODBUS_USART->RDR;
  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(  );
}

void  prvvModbusUARTISR( void )
{
  if(USART_GetITStatus(MODBUS_USART, USART_IT_TC) == SET) {
    prvvUARTTxReadyISR();
    USART_ClearITPendingBit(MODBUS_USART, USART_IT_TC);
  }

  if(USART_GetITStatus(MODBUS_USART, USART_IT_RXNE) == SET) {
    prvvUARTRxISR();
    USART_ClearITPendingBit(MODBUS_USART, USART_IT_RXNE);
  }
}

portserial.c
  1. porttimer.c:补全定时器相关函数(定时器初始化、定时器使能、定时器关闭使能、定时器中断服务函数)
    注意事项:
    初始化:初始化前应用TIM_DeInit函数重置寄存器值;初始化后要清标志位
    定时器使能:要先关中断、关定时器,然后清标志位、重置计数器,最后开中断、开定时器
    中断服务函数:要先判断中断标志位,再清标志位、进入操作部分。
/*
 * FreeModbus Libary: BARE Port
 * Copyright (C) 2006 Christian Walter <wolti@sil.at>
 *
 * 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"

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

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

/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
  /***************************定时器初始化*************************************/
  TIM_TimeBaseInitTypeDef  TIM_InitStructure;
  
  TIM_DeInit(MODBUS_TIM);
  MODBUS_TIM_CLK_INIT(MODBUS_TIM_CLK, ENABLE);
  TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_InitStructure.TIM_CounterMode   = TIM_CounterMode_Up;
  TIM_InitStructure.TIM_Period        = usTim1Timerout50us - 1;
  TIM_InitStructure.TIM_Prescaler     = 2400 - 1; //48MHz/20kHz=2400
  TIM_InitStructure.TIM_RepetitionCounter = 0;
  
  TIM_TimeBaseInit(MODBUS_TIM, &TIM_InitStructure);
  TIM_ClearFlag(MODBUS_TIM, TIM_FLAG_Update);
  TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, ENABLE);
  TIM_Cmd(MODBUS_TIM, DISABLE);
  
  /*****************************中断初始化*************************************/
  NVIC_InitTypeDef  NVIC_InitStructure;
  
  NVIC_InitStructure.NVIC_IRQChannel          = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelCmd       = ENABLE;
  NVIC_InitStructure.NVIC_IRQChannelPriority  = 0;
  
  NVIC_Init(&NVIC_InitStructure);
  
  return TRUE;
}


inline void
vMBPortTimersEnable(  )
{
  /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
  TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, DISABLE);
  TIM_Cmd(MODBUS_TIM, DISABLE);
  TIM_ClearITPendingBit(MODBUS_TIM, TIM_IT_Update);
  TIM_ClearFlag(MODBUS_TIM, TIM_FLAG_Update);
  TIM_SetCounter(MODBUS_TIM, 0);
  TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, ENABLE);
  TIM_Cmd(MODBUS_TIM, ENABLE);
}

inline void
vMBPortTimersDisable(  )
{
  /* Disable any pending timers. */
  TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, DISABLE);
  TIM_Cmd(MODBUS_TIM, 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  prvvModbusTIMISR( void )
{
  if(TIM_GetITStatus(MODBUS_TIM, TIM_IT_Update) == SET) {
    TIM_ClearITPendingBit(MODBUS_TIM, TIM_IT_Update);
    prvvTIMERExpiredISR();
  }
}

porttimer.c
  1. user_mb_app.h:定义各模拟寄存器地址
    注意事项:
    每个寄存器固定长度16位(2字节)
    寄存器地址:从机内部定义的寄存器地址,要对寻址用的寄存器地址+1【Modbus标准协议规定】。即:从机内部定义的寄存器地址,必须大于1;对于寄存器1-16,寻址时通过0-15来寻址(如:查询寄存器1的值时,指令中的寄存器地址为00 00)。
    换句话说,就是:从机程序中定义寄存器地址为1-16时,文档中的寄存器地址要写成0-15。
  2. user_mb_app.c:补全输入寄存器操作函数、保持寄存器操作函数(操作方式可参见…\freemodbus-v1.5.0\demo\ATSAM3S\demo.c),将main分解为modbus初始化函数和modbus进程函数,添加结构体与模拟寄存器之间的数据交互函数。
    注意事项:
    eMBInit初始化:仅需更改地址和波特率。
    user_mb_app函数中不要用循环(本身就会被应用到主程序中的while(1)中)
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "user_mb_app.h"

/* ----------------------- Defines ------------------------------------------*/
#define REG_INPUT_START ((uint16_t)0x0000)
#define REG_INPUT_NREGS 25
#define REG_HOLD_START  ((uint16_t)0x0000)
#define REG_HOLD_NREGS  30

/* ----------------------- Static variables ---------------------------------*/
static USHORT   usRegInputStart = REG_INPUT_START;
static USHORT   usRegInputBuf[REG_INPUT_NREGS];
static USHORT   usRegHoldStart  = REG_HOLD_START;
static USHORT   usRegHoldBuf[REG_HOLD_NREGS];
extern uint8_t  g_Meter_Data[];
extern uint8_t  g_Check_Data[];
/* ----------------------- Start implementation -----------------------------*/
/******************************************************************************
** 函数名称: mb_Modbus_Init
** 功能描述: modbus初始化
** 入口参数: 无
** 返 回 值: 无
**
** 作 者: Cage
** 日 期: 2018年3月9日
**-----------------------------------------------------------------------------
******************************************************************************/
void  mb_Modbus_Init(void) {
    
    uint8_t address = dio_Get_DIP_Value();  //获取拨码开关信息,获得本机地址
    ( void )eMBInit( MB_RTU, address, 0, 9600, MB_PAR_NONE );

    /* Enable the Modbus Protocol Stack. */
    ( void )eMBEnable(  );
}


/******************************************************************************
** 函数名称: user_mb_app
** 功能描述: modbus进程函数
** 入口参数: 无
** 返 回 值: 无
**
** 作 者: Cage
** 日 期: 2018年3月13日
**-----------------------------------------------------------------------------
******************************************************************************/
void  user_mb_app( void )
{

  ( void )eMBPoll(  );

}


/******************************************************************************
** 函数名称: _mb_Fresh_Input_Reg
** 功能描述: 将计量数据结构体中的数据刷新到Modbus模拟寄存器中
** 入口参数: 无
** 返 回 值: 无
**
** 作 者: Cage
** 日 期: 2018年3月13日
**-----------------------------------------------------------------------------
******************************************************************************/
static  void  _mb_Fresh_Input_Reg(void) {
  uint8_t i;
  USHORT  *pmeter_data = (USHORT*)g_Meter_Data;
  for(i = 0; i<REG_INPUT_NREGS; i++) {
    usRegInputBuf[i] = *pmeter_data++;
  }
}


/******************************************************************************
** 函数名称: _mb_Fresh_Check_Struct
** 功能描述: 将Modbus模拟寄存器中的数据刷新到校表数据结构体
** 入口参数: 无
** 返 回 值: 无
**
** 作 者: Cage
** 日 期: 2018年3月13日
**-----------------------------------------------------------------------------
******************************************************************************/
static  void  _mb_Fresh_Check_Struct(void) {
  uint8_t i;
  USHORT  *pcheck_data = (USHORT*)g_Check_Data;
  for(i = 0; i<REG_HOLD_NREGS; i++) {
    *pcheck_data++ = usRegHoldBuf[i];
  }
}


//读输入寄存器
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 ) )
    {
        _mb_Fresh_Input_Reg();  //将计量数据结构体中的数据刷新到Modbus模拟寄存器中
        iRegIndex = ( int )( usAddress - usRegInputStart );
        while( usNRegs > 0 )
        {
            *pucRegBuffer++ =
                ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
            *pucRegBuffer++ =
                ( unsigned char )( usRegInputBuf[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;

    if( ( usAddress >= REG_HOLD_START )
        && ( usAddress + usNRegs <= REG_HOLD_START + REG_HOLD_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegHoldStart );
        if(eMode == MB_REG_WRITE) {
            while( usNRegs > 0 )
            {
                usRegHoldBuf[iRegIndex] = *pucRegBuffer++ << 8;
                usRegHoldBuf[iRegIndex] |= *pucRegBuffer++;
                iRegIndex++;
                usNRegs--;
            }
        }
        _mb_Fresh_Check_Struct(); //将Modbus模拟寄存器中的数据刷新到校表数据结构体
    }
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}

/*********************************不使用的功能*********************************/
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
               eMBRegisterMode eMode )
{
    return MB_ENOREG;
}

eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    return MB_ENOREG;
}

user_mb_app.c
  1. mb.c:在eMBPoll函数中,EV_EXECUTE状态下,准备好发送后,手动发送第一个字节,启动发送
case EV_EXECUTE:
            ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
            eException = MB_EX_ILLEGAL_FUNCTION;
            for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
            {
                /* No more function handlers registered. Abort. */
                if( xFuncHandlers[i].ucFunctionCode == 0 )
                {
                    break;
                }
                else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
                {
                    eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
                    break;
                }
            }

            /* If the request was not sent to the broadcast address we
             * return a reply. */
            if( ucRcvAddress != MB_ADDRESS_BROADCAST )
            {
                if( eException != MB_EX_NONE )
                {
                    /* An exception occured. Build an error frame. */
                    usLength = 0;
                    ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
                    ucMBFrame[usLength++] = eException;
                }
                if( ( eMBCurrentMode == MB_ASCII ) && MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS )
                {
                    vMBPortTimersDelay( MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS );
                }                
                eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
                /*发送数组准备完毕,串口切换到了发送状态,但TC标志位为0,不能自动开始发送*/
                if( eStatus == MB_ENOERR )
                {
                  xMBRTUTransmitFSM();  //发送第一个字节,启动发送
                }
              }
            break;

mb.c节选

调试

  1. 串口收到数据后,无限进入中断
    现象:仿真时,一直进入中断服务函数,不作任何处理后跳出;如此反复进入中断服务函数。
    判断:ORE标志位未清除。RXNEIE中断使能包括RXNE标志位和ORE标志位,中断服务函数中只判断、处理了RXNE标志位。
    处理:在portserial.c的中断服务函数prvvModbusUARTISR中,加入USART_IT_ORE标志位的判断与处理【注:stm32f072库函数中的USART_IT_ORE标志位定义错误,需要修改】
    结果:问题解决
  2. Modbus收到数据后不响应
    现象:跟踪发现,Modbus协议一直进行到“串口发送”之前都是正常的,可是之后却没有发送
    原因:上一次发送最后一个字节时,发送中断中清除了TC标志位;切换到发送状态、使能TCIE后,TC标志位为0,无法启动发送。
    解决方案:
    TXE+TC发送:
    中断使能函数:切换为发送状态时,使能TXE中断而非TC中断(由TXE启动发送,TXE永不手动清零)
    中断服务函数:TXE启动发送后,将中断使能由TXE改为TC,之后由TC判断发送完成、清TC标志位
    手动启动:切换为发送状态后,手动启动发送(发送第一个字节)
    处理:选择了方案2,问题解决。
  3. 仿真跟踪–Modbus数据处理流程(RTU)
    modbus poll主进程(eMBPoll)获取消息状态,执行指令
    数据接收:串口中断接收数据(数据存入ucRTUBuf数组)->超过3.5us没有收到数据->判断一串数据接收完毕->将“接收完毕”消息添加到消息队列
    数据处理:
    eMBPoll获取到“接收完毕”消息,令ucMBFrame指针指向ucRTUBuf数组的第1位(命令字),获取地址位和数据长度(不含地址位和校验位的长度),将“执行”消息添加到消息队列
    eMBPoll获取到“执行”消息,通过ucMBFrame中的命令字,进行对应的操作(比如:04–读输入寄存器),将要发回的数据存入ucMBFrame(不含地址位和校验位)
    将ucMBFrame中的数据加上地址位后计算校验位,将地址位和校验位存入ucRTUBuf数组,将发送状态标志由空闲转为发送,串口状态转为发送
    –至此发送数组(ucRTUBuf)和串口状态都已经准备完毕,但没有发送指令
    【添加】手动发送发送数组的第一个字节,启动发送
    数据发送:通过串口将发送数组逐字节发送。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值