这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » freemodbus教程之freemodbus移植应用串口中断接收和数据解析

共1条 1/1 1 跳转至

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

工程师
2021-02-20 23:45:43     打赏
本篇主要讲解从机数据的接收流程。接收流程分为两个阶段:串口中断接收和数据解析。第一阶段:中断接收函数prvvUARTRxISR(xMBRTUReceiveFSM)和定时器中断回调函数xMBRTUTImerT35Expired(),第二阶段:数据解析eMBPoll()。一、串口中断接收从机正常状态下,串口设置为接收中断模式,也不启动定时器。当检测到有数据时,中断函数调用xMBRTUReceiveFSM()函数,通过该函数中的ucRTUBuf数组存储接收帧,用usRcvBufferPos存储数据帧长度。具体函数:1、中断接收函数。voidUART1_IRQ(void){IF(USART_GeTITStatus(USART1,USART_IT_TXE)){pxMBFrameCBTransmitterEmpty();}elseif(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(接收所有数据,常用)。注意:接收数据时,只要接收到数据,定时器就会清零,重新计数。BOOLxMBRTUReceiveFSM(void){BOOLxTaskNeedSwitch=FALSE;UCHARucByte;assert(eSndState==STATE_TX_IDLE);/*Alwaysreadthecharacter.*/(void)xMBPortSerialGetByte((CHAR*)&ucByte);switch(eRcvState){/*Ifwehavereceivedacharacterintheinitstatewehaveto*waitunTIltheframeisfinished.*/caseSTATE_RX_INIT:vMBPortTimersEnable();break;/*Intheerrorstatewewaituntilallcharactersinthe*damagedframearetransmitted.*/caseSTATE_RX_ERROR:vMBPortTimersEnable();break;/*Intheidlestatewewaitforanewcharacter.Ifacharacter*isreceivedthet1.5andt3.5timersarestartedandthe*receiverisinthestateSTATE_RX_RECEIVCE.*/caseSTATE_RX_IDLE:usRcvBufferPos=0;ucRTUBuf[usRcvBufferPos++]=ucByte;eRcvState=STATE_RX_RCV;/*Enablet3.5timers.*/vMBPortTimersEnable();break;/*Wearecurrentlyreceivingaframe.Resetthetimerafter*everycharacterreceived.Ifmorethanthemaximumpossible*numberofbytesinamodbusframeisreceivedtheframeis*ignored.*/caseSTATE_RX_RCV:if(usRcvBufferPos<MB_SER_PDU_SIZE_MAX){ucRTUBuf[usRcvBufferPos++]=ucByte;}else{eRcvState=STATE_RX_ERROR;}vMBPortTimersEnable();break;}returnxTaskNeedSwitch;}二、数据解析涉及到的函数eMBPoll、eMBRTUReceive和xFuncHandlers[i]是结构体数组。1、eMBPoll函数。eMBPoll函数调用eMBRTUReceive和xFuncHandlers[i]结构体数组。eMBErrorCodeeMBPoll(void){staticUCHAR*ucMBFrame;staticUCHARucRcvAddress;staticUCHARucFunctionCode;staticUSHORTusLength;staticeMBExceptioneException;inti;eMBErrorCodeeStatus=MB_ENOERR;eMBEventTypeeEvent;/*Checkiftheprotocolstackisready.*/if(eMBState!=STATE_ENABLED){returnMB_EILLSTATE;}/*Checkifthereisaeventavailable.Ifnotreturncontroltocaller.*Otherwisewewillhandletheevent.*/if(xMBPortEventGet(&eEvent)==TRUE){switch(eEvent){caseEV_READY:break;caseEV_FRAME_RECEIVED:eStatus=peMBFrameReceiveCur(&ucRcvAddress,&ucMBFrame,&usLength);if(eStatus==MB_ENOERR){/*Checkiftheframeisforus.Ifnotignoretheframe.*/if((ucRcvAddress==ucMBAddress)||(ucRcvAddress==MB_ADDRESS_BROADCAST)){(void)xMBPortEventPost(EV_EXECUTE);}}break;caseEV_EXECUTE:ucFunctionCode=ucMBFrame[MB_PDU_FUNC_OFF];//把接收的数据传递给ucFunctionCodeeException=MB_EX_ILLEGAL_FUNCTION;for(i=0;i<MB_FUNC_HANDLERS_MAX;i++){/*Nomorefunctionhandlersregistered.Abort.*/if(xFuncHandlers[i].ucFunctionCode==0){break;}elseif(xFuncHandlers[i].ucFunctionCode==ucFunctionCode)//查询匹配的功能码,{eException=xFuncHandlers[i].pxHandler(ucMBFrame,&usLength);//调用相应的功能函数break;}}/*Iftherequestwasnotsenttothebroadcastaddresswe*returnareply.*/if(ucRcvAddress!=MB_ADDRESS_BROADCAST){if(eException!=MB_EX_NONE)//如果接收有问题{/*Anexceptionoccured.Buildanerrorframe.*/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;caseEV_FRAME_SENT:break;}}returnMB_ENOERR;}2、peMBFrameReceiveCur()//数据帧接收函数指针3、主要讲一下xFuncHandlers[i],它是结构体数组,存放的是功能码以及对应的报文解析函数。typedefstruct{UCHARucFunctionCode;pxMBFunctionHandlerpxHandler;}xMBFunctionHandler;staticxMBFunctionHandlerxFuncHandlers[MB_FUNC_HANDLERS_MAX]={#ifMB_FUNC_OTHER_REP_SLAVEID_ENABLED>0{MB_FUNC_OTHER_REPORT_SLAVEID,eMBFuncReportSlaveID},#endif#ifMB_FUNC_READ_INPUT_ENABLED>0{MB_FUNC_READ_INPUT_REGISTER,eMBFuncReadInputRegister},#endif#ifMB_FUNC_READ_HOLDING_ENABLED>0{MB_FUNC_READ_HOLDING_REGISTER,eMBFuncReadHoldingRegister},#endif#ifMB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED>0{MB_FUNC_WRITE_MULTIPLE_REGISTERS,eMBFuncWriteMultipleHoldingRegister},#endif#ifMB_FUNC_WRITE_HOLDING_ENABLED>0{MB_FUNC_WRITE_REGISTER,eMBFuncWriteHoldingRegister},#endif#ifMB_FUNC_READWRITE_HOLDING_ENABLED>0{MB_FUNC_READWRITE_MULTIPLE_REGISTERS,eMBFuncReadWriteMultipleHoldingRegister},#endif#ifMB_FUNC_READ_COILS_ENABLED>0{MB_FUNC_READ_COILS,eMBFuncReadCoils},#endif#ifMB_FUNC_WRITE_COIL_ENABLED>0{MB_FUNC_WRITE_SINGLE_COIL,eMBFuncWriteCoil},#endif#ifMB_FUNC_WRITE_MULTIPLE_COILS_ENABLED>0{MB_FUNC_WRITE_MULTIPLE_COILS,eMBFuncWriteMultipleCoils},#endif#ifMB_FUNC_READ_DISCRETE_INPUTS_ENABLED>0{MB_FUNC_READ_DISCRETE_INPUTS,eMBFuncReadDiscreteInputs},#endif};以功能码04为例,读取输入寄存器。eMBExceptioneMBFuncReadInputRegister(UCHAR*pucFrame,USHORT*usLen){USHORTusRegAddress;USHORTusRegCount;UCHAR*pucFrameCur;eMBExceptioneStatus=MB_EX_NONE;eMBErrorCodeeRegStatus;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]);/*Checkifthenumberofregisterstoreadisvalid.Ifnot*returnModbusillegaldatavalueexception.*/if((usRegCount>=1)&&(usRegCount<MB_PDU_FUNC_READ_REGCNT_MAX))//读取寄存器的长度不越界{/*SetthecurrentPDUdatapointertothebeginning.*/pucFrameCur=&pucFrame[MB_PDU_FUNC_OFF];//把数据帧赋值给pucFrameCur*usLen=MB_PDU_FUNC_OFF;/*Firstbytecontainsthefunctioncode.*/*pucFrameCur++=MB_FUNC_READ_INPUT_REGISTER;//*usLen+=1;/*Secondbyteintheresponsecontainthenumberofbytes.*/*pucFrameCur++=(UCHAR)(usRegCount*2);*usLen+=1;eRegStatus=eMBRegInputCB(pucFrameCur,usRegAddress,usRegCount);/*IfanerroroccuredconvertitintoaModbusexception.*/if(eRegStatus!=MB_ENOERR){eStatus=prveMBError2Exception(eRegStatus);}else{*usLen+=usRegCount*2;}}else{eStatus=MB_EX_ILLEGAL_DATA_VALUE;}}else{/*Can'tbeavalidreadinputregisterrequestbecausethelength*isincorrect.*/eStatus=MB_EX_ILLEGAL_DATA_VALUE;}returneStatus;}eMBErrorCodeeMBRegInputCB(UCHAR*pucRegBuffer,USHORTusAddress,USHORTusNRegs){eMBErrorCodeeStatus=MB_ENOERR;intiRegIndex;if((usAddress>=REG_INPUT_START)&&(usAddress+usNRegs<=REG_INPUT_START+REG_INPUT_NREGS)){iRegIndex=(int)(usAddress-REG_INPUT_START);while(usNRegs>0){*pucRegBuffer++=(unsignedchar)(usRegInputBuf[iRegIndex]>>8);*pucRegBuffer++=(unsignedchar)(usRegInputBuf[iRegIndex]&0xFF);iRegIndex++;usNRegs--;}}else{eStatus=MB_ENOREG;}returneStatus;}以上就是整个接收数据、解析数据的过程。




共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]