全球最实用的IT互联网信息网站!

AI人工智能P2P分享&下载搜索网页发布信息网站地图

当前位置:诺佳网 > 电子/半导体 > 接口/总线/驱动 >

freemodbus教程之freemodbus移植应用串口中断接收和数

时间:2021-02-18 16:56

人气:

作者:admin

标签: 函数  数据  定时器  串口 

导读:freemodbus教程之freemodbus移植应用串口中断接收和数据解析-div style=overflow-wrap: break-word; color: rgb(0, 0, 0); font-family: Tahoma, quot;Microsoft Yaheiquot;, Simsun; font-size: 14px;本篇主要讲解从机数据的接收...
本篇主要讲解从机数据的接收流程。接收流程分为两个阶段:串口中断接收和数据解析。 第一阶段:中断接收函数prvvUARTRxISR(xMBRTUReceiveFSM)和定时器中断回调函数xMBRTUtimerT35Expired(), 第二阶段:数据解析eMBPoll(  )。   一、串口中断接收     从机正常状态下,串口设置为接收中断模式,也不启动定时器。当检测到有数据时,中断函数调用xMBRTUReceiveFSM()函数,通过该函数中的ucRTUBuf数组存储接收帧,用usRcvBufferPos存储数据帧长度。具体函数:   1、中断接收函数。 void UART1_IRQ(void) {     IF(USART_GetITStatus(USART1,USART_IT_TXE))     {         pxMBFrameCBTransmitterEmpty(  );     }     else if(USART_GetITStatus(USART1,USART_IT_RXNE))//接收中断     {         pxMBFrameCBByteReceived(  );//pxMBFrameCBByteReceived = xMBRTUReceiveFSM;     } }   2、xMBRTUReceiveFSM()函数。RTU接收状态函数。只要进人该函数,就会启动定时器中断。   从机的接收状态:      (1)STATE_RX_INIT(协议栈初始化); (2)STATE_RX_ERROR(接收错误);  (3)STATE_RX_IDLE(接收空闲,接收帧头,常用); (4)STATE_RX_RCV(接收所有数据,常用)。   注意:接收数据时,只要接收到数据,定时器就会清零,重新计数。   BOOL xMBRTUReceiveFSM( void ) {     BOOL            xTaskNeedSwitch = FALSE;     UCHAR           ucByte;       assert( eSndState == STATE_TX_IDLE );       /* Always read the character. */     ( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );       switch ( eRcvState )     {         /* If we have received a character in the init state we have to          * wait until the frame is finished.          */     case STATE_RX_INIT:         vMBPortTimersEnable(  );         break;           /* In the error state we wait until all characters in the          * damaged frame are transmitted.          */     case STATE_RX_ERROR:         vMBPortTimersEnable(  );         break;           /* In the idle state we wait for a new character. If a character          * is received the t1.5 and t3.5 timers are started and the          * receiver is in the state STATE_RX_RECEIVCE.          */     case STATE_RX_IDLE:         usRcvBufferPos = 0;         ucRTUBuf[usRcvBufferPos++] = ucByte;         eRcvState = STATE_RX_RCV;           /* Enable t3.5 timers. */         vMBPortTimersEnable(  );         break;           /* We are currently receiving a frame. Reset the timer after          * every character received. If more than the maximum possible          * number of bytes in a modbus frame is received the frame is          * ignored.          */     case STATE_RX_RCV:         if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )         {             ucRTUBuf[usRcvBufferPos++] = ucByte;         }         else         {             eRcvState = STATE_RX_ERROR;         }         vMBPortTimersEnable(  );         break;     }     return xTaskNeedSwitch; }   二、数据解析 涉及到的函数 eMBPoll、eMBRTUReceive和xFuncHandlers[i]是结构体数组。   1、eMBPoll函数。eMBPoll函数调用eMBRTUReceive和xFuncHandlers[i]结构体数组。   eMBErrorCode eMBPoll( void ) {     static UCHAR   *ucMBFrame;     static UCHAR    ucRcvAddress;     static UCHAR    ucFunctionCode;     static USHORT   usLength;     static eMBException eException;       int             i;     eMBErrorCode    eStatus = MB_ENOERR;     eMBEventType    eEvent;       /* Check if the protocol stack is ready. */     if( eMBState != STATE_ENABLED )     {         return MB_EILLSTATE;     }       /* Check if there is a event available. If not return control to caller.      * Otherwise we will handle the event. */     if( xMBPortEventGet( &eEvent ) == TRUE )     {         switch ( eEvent )         {         case EV_READY:             break;           case EV_FRAME_RECEIVED:             eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );             if( eStatus == MB_ENOERR )             {                 /* Check if the frame is for us. If not ignore the frame. */                 if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )                 {                     ( void )xMBPortEventPost( EV_EXECUTE );                 }             }             break;           case EV_EXECUTE:             ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];//把接收的数据传递给ucFunctionCode             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 );//功能码与0x80或之后的为                                                                                                                                                         //异常码                     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 );//发送数据             }             break;           case EV_FRAME_SENT:             break;         }     }     return MB_ENOERR; }       2、peMBFrameReceiveCur() //数据帧接收函数指针   3、主要讲一下xFuncHandlers[i],它是结构体数组,存放的是功能码以及对应的报文解析函数。   typedef struct { UCHAR ucFunctionCode; pxMBFunctionHandler pxHandler; } xMBFunctionHandler;   static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX] = { #if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0     {MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID}, #endif #if MB_FUNC_READ_INPUT_ENABLED > 0     {MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister}, #endif #if MB_FUNC_READ_HOLDING_ENABLED > 0     {MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister}, #endif #if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0     {MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister}, #endif #if MB_FUNC_WRITE_HOLDING_ENABLED > 0     {MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister}, #endif #if MB_FUNC_READWRITE_HOLDING_ENABLED > 0     {MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister}, #endif #if MB_FUNC_READ_COILS_ENABLED > 0     {MB_FUNC_READ_COILS, eMBFuncReadCoils}, #endif #if MB_FUNC_WRITE_COIL_ENABLED > 0     {MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil}, #endif #if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0     {MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils}, #endif #if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0     {MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs}, #endif };    以功能码04为例,读取输入寄存器。   eMBException eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen ) {     USHORT          usRegAddress;     USHORT          usRegCount;     UCHAR          *pucFrameCur;       eMBException    eStatus = MB_EX_NONE;     eMBErrorCode    eRegStatus;       if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )//计算帧长度,除了地址位和两位的crc校验位     {         usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );//读取寄存器的首地址         usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );         usRegAddress++;           usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );//计算读取寄存器的长度         usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );           /* Check if the number of registers to read is valid. If not          * return Modbus illegal data value exception.           */         if( ( usRegCount >= 1 )             && ( usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX ) )//读取寄存器的长度不越界         {             /* Set the current PDU data pointer to the beginning. */             pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];//把数据帧赋值给pucFrameCur             *usLen = MB_PDU_FUNC_OFF;               /* First byte contains the function code. */             *pucFrameCur++ = MB_FUNC_READ_INPUT_REGISTER;//             *usLen += 1;               /* Second byte in the response contain the number of bytes. */             *pucFrameCur++ = ( UCHAR )( usRegCount * 2 );             *usLen += 1;               eRegStatus =                 eMBRegInputCB( pucFrameCur, usRegAddress, usRegCount );               /* If an error occured convert it into a Modbus exception. */             if( eRegStatus != MB_ENOERR )             {                 eStatus = prveMBError2Exception( eRegStatus );             }             else             {                 *usLen += usRegCount * 2;             }         }         else         {             eStatus = MB_EX_ILLEGAL_DATA_VALUE;         }     }     else     {         /* Can't be a valid read input register request because the length          * is incorrect. */         eStatus = MB_EX_ILLEGAL_DATA_VALUE;     }     return eStatus; }       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 ) )     {         iRegIndex = ( int )( usAddress - REG_INPUT_START );         while( usNRegs > 0 )         {             *pucRegBuffer++ =                 ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );             *pucRegBuffer++ =                 ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );             iRegIndex++;             usNRegs--;         }     }     else     {         eStatus = MB_ENOREG;     }       return eStatus; }    以上就是整个接收数据、解析数据的过程。 

来源:csdn博客 萧年已逝;在此特别鸣谢!
温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信