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

本篇主要讲解从机数据的接收流程。接收流程分为两个阶段:串口中断接收和数据解析。
第一阶段:中断接收函数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 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] <= 1 )
&& ( usregcount = reg_input_start )
&& ( usaddress + usnregs 0 )
{
*pucregbuffer++ =
( unsigned char )( usreginputbuf[iregindex] >> 8 );
*pucregbuffer++ =
( unsigned char )( usreginputbuf[iregindex] & 0xff );
iregindex++;
usnregs--;
}
}
else
{
estatus = mb_enoreg;
}
return estatus;
}
以上就是整个接收数据、解析数据的过程。
来源:csdn博客 萧年已逝;在此特别鸣谢!

大联大世平集团基于NXP和TI的ZigBee和NFC无线通讯解决方案
针对下一代高带宽通信系统优化的 IDT 模拟可变增益放大器
如何采用STM32单片机来产生PWM输出
Maxim推出DirectDrive耳机放大器
rs485集线器使用说明书详解
freemodbus教程之freemodbus移植应用串口中断接收和数据解析
MCU助力物联网快速发展
基于DA14531 BLE SoC的低功耗蓝牙信标系统
基于STC12C5A60S2单片机中的AD采样实时采样用于检测电路是否正常的设计
HONEYWELL霍尼韦尔传感器芯片推出了一种新的自诊断传感器
高通宣布将提供一款可以加速人工智能处理速度的新型数据中心芯片
餐饮油烟整治不停,在线油烟监测仪让餐饮店不再偷漏排
嵌入式工控机在智能仓储中的应用
边缘智能化如何为自主工厂提供动力
小批量PCB组装:设计的试验场
低功耗应用中µC外围设备的选择
振动对连接器影响大?选对锁扣连接器很重要
吴忠供电投运110千伏周闸站4回线路
关于全球照明市场需求分析的报告
开源模型OpenCLIP达成ImageNet里程碑成就!