modbus通讯协议格式协议中响应的bytecount怎么得来的

后使用快捷导航没有帐号?
查看: 11201|回复: 19
STM32 移植FreeModbus 详细过程
在线时间10 小时
威望605 分
芯币427 枚
TA的帖子TA的资源
纯净的硅(初级), 积分 605, 距离下一级还需 195 积分
纯净的硅(初级), 积分 605, 距离下一级还需 195 积分
FreeModbus移植 经验分享
一& &为什么要移植Freemodbus
& && && &为什么要移植Freemodbus,这个问题需要从两个方面来回答。第一,modbus是一个非常好的应用层协议,它很简洁也相对完善。对于还没有接触过modbus的朋友来说,我非常不建议直接移植freemodbus,应该耐心的从modbus文档入手,并充分把握身边的所有资源,例如PLC的中modbus部分。第二,其实嵌入式系统的通信协议可以自己制定,但是通过实践发现自己定制的协议漏洞百出,尤其是扩展极为困难。我始终认为借鉴他人的经验是很好的途径。借鉴他人成熟的代码,可以减少调试的时间,实现的功能也多了不少。
& && && &个人观点,仅供参考。
& && && &freemodbus小提示
& && && &freemodbus只能使用从机功能。freemodbus更适合嵌入式系统,虽然例子中也有WIN32的例子,如果想要做PC机程序并实现主机功能,推荐使用另一个modbus库——NMODBUS,使用C#开发。同样WINFORM也可以通过自己编写串口代码实现modbus功能,但是这会花费很长的时间,可能是一周也可能是一个月,如果使用现成的代码库,那么开发时间可能只有10分钟。
自己整理的modbus协议:&&代码参考了这个帖子:
二&&freeemodbus中如何通过串口发送和接收数据
& && && &freemodbus通过串口中断的方式接收和发送数据。采用这种做法我想可以节省程序等待的时间,并且也短充分使用CPU的资源。串口中断接收毋庸置疑,在中断服务函数中把数据保存在数组中,以便稍后处理。但是串口发送中断使用哪种形式?串口发送中断至少有两种方式,第一种,数据寄存器空中断,只要数据寄存器为空并且中断屏蔽位置位,那么中断就会发生;第二种,发送完成中断,若数据寄存器的数据发送完成并且中断屏蔽位置位,那么中断也会发送。我非常建议各位使用串口发送完成中断。freemodbus多使用RS485通信中,从机要么接收要么发送,多数情况下从机处于接收状态,要有数据发送时才进入发送状态。进入发送状态时,数据被一个一个字节发送出去,当最后一个字节被发送出去之后,从机再次进入接收状态。如果使用发送寄存器为空中断,还需要使用其他的方法才可以判断最后一个字节的数据是否发送完成。如果使用数据寄存器为空中断,那么将很有可能丢失最后一个字节。(马潮老师的AVR图书中也推荐使用发送完成中断,交流性质的文章,就没有参考文献了。)
二&&freemodbus中如何判断帧结束
& && && &大家应该清楚,modbus协议中没有明显的开始符和结束符,而是通过帧与帧之间的间隔时间来判断的。如果在指定的时间内,没有接收到新的字符数据,那么就认为收到了新的帧。接下来就可以处理数据了,首当其冲的就是判断帧的合法性。Modbus通过时间来判断帧是否接受完成,自然需要单片机中的定时器配合。
三& &整体代码
下面给出一个STM32平台上使用FREEMODBUS最简单的例子,操作保持寄存器,此时操作指令可以为03,06和16;#include "stm32f10x.h"
#include
#include "mb.h"
#include "mbutils.h"
//保持寄存器起始地址
#define REG_HOLDING_START 0x0000
//保持寄存器数量
#define REG_HOLDING_NREGS 8
//保持寄存器内容
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS]
= {0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0xb,0x408e};
int main(void)
{
//初始化 RTU模式 从机地址为1 USART1 9600 无校验
eMBInit(MB_RTU, 0x01, 0x01, 9600, MB_PAR_NONE);
//启动FreeModbus
eMBEnable();
while (1)
{
//FreeMODBUS不断查询
eMBPoll();
/**
* @brief 保持寄存器处理函数,保持寄存器可读,可读可写
* @param pucRegBuffer 读操作时--返回数据指针,写操作时--输入数据指针
* usAddress 寄存器起始地址
* usNRegs 寄存器长度
* eMode 操作方式,读或者写
* @retval eStatus 寄存器状态
*/
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
eMBRegisterMode eMode )
{
//错误状态
eMBErrorCode eStatus = MB_ENOERR;
//偏移量
int16_t iRegI
//判断寄存器是不是在范围内
if( ( (int16_t)usAddress >= REG_HOLDING_START ) \
&& ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
{
//计算偏移量
iRegIndex = ( int16_t )( usAddress - REG_HOLDING_START);
switch ( eMode )
{
//读处理函数
case MB_REG_READ:
while( usNRegs > 0 )
{
*pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] >> 8 );
*pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
//写处理函数
case MB_REG_WRITE:
while( usNRegs > 0 )
{
usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
}
}
else
{
//返回错误状态
eStatus = MB_ENOREG;
}
return eS
}
复制代码先给大家一个整体的印象,先让大家会使用FREEMODBUS,再详细描述细节
//保持寄存器起始地址
#define REG_HOLDING_START& &&&0x0000
//保持寄存器数量
#define REG_HOLDING_NREGS& &&&8
这两个宏定义,决定了保持寄存器的起始地址和总个数。需要强调的是,modbus寄存器的地址有两套规则,一套称为PLC地址,为5位十进制数,例如40001。另一套是协议地址,PLC地址40001意味着该参数类型为保持寄存器,协议地址为0x0000,这里面有对应关系,去掉PLC地址的最高位,然后剩下的减1即可。这会存在一个问题,PLC地址30002和PLC地址40002的协议地址同为0x0001,此时访问时是不是会冲突呢。亲们,当然不会了,30001为输入寄存器,需要使用04指令访问,而40001为保持寄存器,可以使用03、06和16指令访问。所以,用好modbus还是要熟悉协议本生,切不可着急。
//保持寄存器内容
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS]
= {0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0xb,0x408e};
接下来定义了保持寄存器的内容,在这里请大家注意了,保持寄存器为无符号16位数据。在测试的情况下,我随便找了一些数据进行测试。看数据的本质似乎看不出说明规律,但是usRegHoldingBuf却是以16进制保存了浮点数。int main(void)
{
//初始化 RTU模式 从机地址为1 USART1 9600 无校验
eMBInit(MB_RTU, 0x01, 0x01, 9600, MB_PAR_NONE);
//启动FreeModbus
eMBEnable();
while (1)
{
//FreeMODBUS不断查询
eMBPoll();
}
}
复制代码接下来就进入主函数部分。有三个FREEMODBUS提供的函数,eMBInit,eMBEnable和eMBPoll。eMBInit为modbus的初始化函数,eMBEnable为modbus的使能函数,而eMBPoll为modbus的查询函数,eMBPoll也是非常单纯的函数,查询是否有数据帧到达,如果有数据到达,便进行相依的处理。再次观察这几个函数,只有eMBInit有很多的参数,这些参数和位于系统底层的硬件有关,这个应该引起移植过程的更多关注。下面几个章节再议。eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
eMBRegisterMode eMode )
{
//错误状态
eMBErrorCode eStatus = MB_ENOERR;
//偏移量
int16_t iRegI
//判断寄存器是不是在范围内
if( ( (int16_t)usAddress >= REG_HOLDING_START ) \
&& ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
{
//计算偏移量
iRegIndex = ( int16_t )( usAddress - REG_HOLDING_START);
switch ( eMode )
{
//读处理函数
case MB_REG_READ:
while( usNRegs > 0 )
{
*pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] >> 8 );
*pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
//写处理函数
case MB_REG_WRITE:
while( usNRegs > 0 )
{
usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
}
}
else
{
//返回错误状态
eStatus = MB_ENOREG;
}
return eS
}
复制代码最后,如果收到一个有效的数据帧,那么就可以开始处理了。
第一步,判断寄存器的地址是否在合法的范围内。
&&if( ( (int16_t)usAddress &= REG_HOLDING_START ) \
& &&&&& ( usAddress + usNRegs &= REG_HOLDING_START + REG_HOLDING_NREGS ) )
第二步,判断需要操作寄存器的偏移地址。
& && && &给个例子可以迅速的说明问题,例如访问寄存器的起始地址为0x0002,保持寄存器的起始地址为0x0000,那么这个访问的偏移量为2,程序就从保持寄存器数组的第2个(从0开始)开始操作。
第三步,读写操作分开处理
& && &case MB_REG_READ:
& && &&&while( usNRegs & 0 )
& && && & *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] && 8 );
& && && & *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] & 0xFF );
& && && & iRegIndex++;
& && && & usNRegs--;
& && && &以读操作为例,代码不多说了,请大家注意操作的顺序。保持寄存器以16位形式保存,但是modbus通信时以字节为单位,高位字节数据在前,低位数据字节在后。
四& &串口相关部分代码编写
& && && &串口部分的代码编写比较常规,主要有三个函数,串口初始化,串口数据发送和串口数据接收。除了以上三个函数之外,还有串口中断服务函数。/**
* @brief 串口初始化
* @param ucPORT 串口号
* ulBaudRate 波特率
* ucDataBits 数据位
* eParity 校验位
* @retval None
*/
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
(void)ucPORT; //不修改串口
(void)ucDataB //不修改数据位长度
(void)eP //不修改校验格式
GPIO_InitTypeDef GPIO_InitS
USART_InitTypeDef USART_InitS
//使能USART1,GPIOA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
RCC_APB2Periph_USART1, ENABLE);
//GPIOA9 USART1_Tx
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//GPIOA.10 USART1_Rx
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮动输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = ulBaudR //只修改波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_N
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
//串口初始化
USART_Init(USART1, &USART_InitStructure);
//使能USART1
USART_Cmd(USART1, ENABLE);
NVIC_InitTypeDef NVIC_InitS
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//设定USART1 中断优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//最后配置485发送和接收模式
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
//GPIOD.8
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
return TRUE;
}复制代码传入的参数有端口号,波特率,数据位和校验位,可以根据实际的情况修改代码。在这里我并没有修改其他参数,至于传入的波特率是有效的。除了配置串口的相关参数之外,还需要配置串口的中断优先级。最后,由于使用485模式,还需要一个发送接收控制端,该IO配置为推挽输出模式。/**
* @brief 控制接收和发送状态
* @param xRxEnable 接收使能、
* xTxEnable 发送使能
* @retval None
*/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
if(xRxEnable)
{
//使能接收和接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//MAX485操作 低电平为接收模式
GPIO_ResetBits(GPIOD,GPIO_Pin_8);
}
else
{
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
//MAX485操作 高电平为发送模式
GPIO_SetBits(GPIOD,GPIO_Pin_8);
}
if(xTxEnable)
{
//使能发送完成中断
USART_ITConfig(USART1, USART_IT_TC, ENABLE);
}
else
{
//禁止发送完成中断
USART_ITConfig(USART1, USART_IT_TC, DISABLE);
}
}
复制代码由于485使用半双工模式,从机一般处于接收状态,有数据发送时才会进入发送模式。在FreeModbus中有专门的控制接收和发送状态的函数,在这里不但可以打开或关闭接收和发送中断,还可以控制485收发芯片的发送接收端口。代码非常简单,但是还是建议各位使用发送完成中断。BOOL
xMBPortSerialPutByte( CHAR ucByte )
{
//发送数据
USART_SendData(USART1, ucByte);
return TRUE;
}
BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
//接收数据
*pucByte = USART_ReceiveData(USART1);
return TRUE;
}
xMBPortSerialPutByte和xMBPortSerialGetByte两个函数用于串口发送和接收数据,在这里只要调用STM32的库函数即可。
static void prvvUARTTxReadyISR( void )
{
//mb.c eMBInit函数中
//pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM
//发送状态机
pxMBFrameCBTransmitterEmpty();
}
static void prvvUARTRxISR( void )
{
//mb.c eMBInit函数中
//pxMBFrameCBByteReceived = xMBRTUReceiveFSM
//接收状态机
pxMBFrameCBByteReceived();
}
void USART1_IRQHandler(void)
{
//发生接收中断
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
prvvUARTRxISR();
//清除中断标志位
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
//发生完成中断
if(USART_GetITStatus(USART1, USART_IT_TC) == SET)
{
prvvUARTTxReadyISR();
//清除中断标志
USART_ClearITPendingBit(USART1, USART_IT_TC);
}
}
复制代码若进入串口中断服务函数,则要调用FreeModbus中响应的函数,串口接收中断服务函数对应prvvUARTRxISR(),其代码如下static void prvvUARTRxISR( void )
{
//mb.c eMBInit函数中
//pxMBFrameCBByteReceived = xMBRTUReceiveFSM
//接收状态机
pxMBFrameCBByteReceived();
}
复制代码在prvvUARTRxISR中又调用了pxMBFrameCBByteReceived(),其实pxMBFrameCBTransmitterEmpty()并不是一个函数,而是一个函数指针。其定义如下,请注意函数指针的声明和函数声明的区别。
BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
在mb.c文件的eMBInit函数完成赋值。一般情况下都会选择RTU模式,那么pxMBFrameCBByteReceived就和xMBRTUReceiveFSM等价了,
pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
同理,若发生串口发送完成中断,该中断服务函数对应prvvUARTTxReadyISR,其代码如下static void prvvUARTTxReadyISR( void )
{
//mb.c eMBInit函数中
//pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM
//发送状态机
pxMBFrameCBTransmitterEmpty();
}
复制代码在prvvUARTTxReadyISR中又调用了pxMBFrameCBTransmitterEmpty(),pxMBFrameCBTransmitterEmpty也是函数指针,在eMBInit函数完成赋值,它等价于xMBRTUTransmitFSM。
& && && &特别提醒,由于我使用的是串口发送完成中断,想要进入该中断服务函数,需要发送一个字节的数据并启动串口发送中断,代码还需要少许修改。在mbRTU.c的eMBRTUSend中稍作修改,代码如下。
复制代码/* First byte before the Modbus-PDU is the slave address. */
pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
usSndBufferCount = 1;
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveA
usSndBufferCount += usL
/* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF );
ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 );
/* Activate the transmitter. */
//发送状态转换,在中断中不断发送
eSndState = STATE_TX_XMIT;
//插入代码 启动第一次发送,这样才可以进入发送完成中断
xMBPortSerialPutByte( ( CHAR )*pucSndBufferCur );
pucSndBufferCur++;
usSndBufferCount--;
//使能发送状态,禁止接收状态
vMBPortSerialEnable( FALSE, TRUE );
复制代码
本帖子中包含更多资源
才可以下载或查看,没有帐号?
<p id="rate_09" onmouseover="showTip(this)" tip="很给力!&芯币 + 1 枚
" class="mtn mbn">
在线时间10 小时
威望605 分
芯币427 枚
TA的帖子TA的资源
纯净的硅(初级), 积分 605, 距离下一级还需 195 积分
纯净的硅(初级), 积分 605, 距离下一级还需 195 积分
工程代码,IAR 5.5&&V3.4库函数
请配合MODBUS POLL工具使用,会有更好的效果!
本帖子中包含更多资源
才可以下载或查看,没有帐号?
在线时间7 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
赶紧下载,观看观看
在线时间97 小时
芯币226 枚
TA的帖子TA的资源
一粒金砂(中级), 积分 74, 距离下一级还需 126 积分
一粒金砂(中级), 积分 74, 距离下一级还需 126 积分
步骤很详细啊!
在线时间5 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
真的是很详细,像我这样的菜鸟都能看懂一点的
在线时间139 小时
威望898 分
芯币797 枚
TA的帖子TA的资源
纯净的硅(中级), 积分 898, 距离下一级还需 302 积分
纯净的硅(中级), 积分 898, 距离下一级还需 302 积分
谢谢共享!
在线时间21 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 86, 距离下一级还需 114 积分
一粒金砂(中级), 积分 86, 距离下一级还需 114 积分
刚好要用这个&&只能现学现卖
在线时间5 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 10, 距离下一级还需 -5 积分
一粒金砂(初级), 积分 10, 距离下一级还需 -5 积分
刚好要用这个,谢谢分享!
在线时间7 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 12, 距离下一级还需 -7 积分
一粒金砂(初级), 积分 12, 距离下一级还需 -7 积分
在线时间1 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
谢谢!正因有你们的奉献,才有我们菜鸟的一步一步成长
在线时间17 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
在线时间1 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
在线时间7 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
在线时间7 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
正在,看代码,很有启发
在线时间2 小时
TA的帖子TA的资源
宇宙尘埃, 积分 -2, 距离下一级还需 2 积分
宇宙尘埃, 积分 -2, 距离下一级还需 2 积分
...............
在线时间42 小时
芯币116 枚
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
在线时间12 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 4, 距离下一级还需 1 积分
一粒金砂(初级), 积分 4, 距离下一级还需 1 积分
mark&&l留着明天看
在线时间0 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
非常感谢!!!!!
在线时间9 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 10, 距离下一级还需 190 积分
一粒金砂(中级), 积分 10, 距离下一级还需 190 积分
标记一下。正好可以学习一下
请修改签名 ^_^
在线时间1 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
正在学习,谢谢
资源大师勋章
在下载中心贡献超过4000份资料
Powered by
逛了这许久,何不进去瞧瞧?modbus协议中响应的bytecount怎么得来的
[问题点数:40分,结帖人u]
modbus协议中响应的bytecount怎么得来的
[问题点数:40分,结帖人u]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2014年7月 硬件/嵌入开发大版内专家分月排行榜第二
2013年10月 硬件/嵌入开发大版内专家分月排行榜第三2013年6月 硬件/嵌入开发大版内专家分月排行榜第三2013年3月 硬件/嵌入开发大版内专家分月排行榜第三
2015年3月 Linux/Unix社区大版内专家分月排行榜第二2014年12月 Linux/Unix社区大版内专家分月排行榜第二2014年11月 Linux/Unix社区大版内专家分月排行榜第二2014年9月 Linux/Unix社区大版内专家分月排行榜第二2014年8月 Linux/Unix社区大版内专家分月排行榜第二2014年7月 Linux/Unix社区大版内专家分月排行榜第二2014年5月 Linux/Unix社区大版内专家分月排行榜第二2014年4月 Linux/Unix社区大版内专家分月排行榜第二
2014年3月 Linux/Unix社区大版内专家分月排行榜第三
2015年3月 Linux/Unix社区大版内专家分月排行榜第二2014年12月 Linux/Unix社区大版内专家分月排行榜第二2014年11月 Linux/Unix社区大版内专家分月排行榜第二2014年9月 Linux/Unix社区大版内专家分月排行榜第二2014年8月 Linux/Unix社区大版内专家分月排行榜第二2014年7月 Linux/Unix社区大版内专家分月排行榜第二2014年5月 Linux/Unix社区大版内专家分月排行榜第二2014年4月 Linux/Unix社区大版内专家分月排行榜第二
2014年3月 Linux/Unix社区大版内专家分月排行榜第三
2015年3月 Linux/Unix社区大版内专家分月排行榜第二2014年12月 Linux/Unix社区大版内专家分月排行榜第二2014年11月 Linux/Unix社区大版内专家分月排行榜第二2014年9月 Linux/Unix社区大版内专家分月排行榜第二2014年8月 Linux/Unix社区大版内专家分月排行榜第二2014年7月 Linux/Unix社区大版内专家分月排行榜第二2014年5月 Linux/Unix社区大版内专家分月排行榜第二2014年4月 Linux/Unix社区大版内专家分月排行榜第二
2014年3月 Linux/Unix社区大版内专家分月排行榜第三
2015年3月 Linux/Unix社区大版内专家分月排行榜第二2014年12月 Linux/Unix社区大版内专家分月排行榜第二2014年11月 Linux/Unix社区大版内专家分月排行榜第二2014年9月 Linux/Unix社区大版内专家分月排行榜第二2014年8月 Linux/Unix社区大版内专家分月排行榜第二2014年7月 Linux/Unix社区大版内专家分月排行榜第二2014年5月 Linux/Unix社区大版内专家分月排行榜第二2014年4月 Linux/Unix社区大版内专家分月排行榜第二
2014年3月 Linux/Unix社区大版内专家分月排行榜第三
2011年1月 VB大版内专家分月排行榜第二2010年10月 VB大版内专家分月排行榜第二
2013年1月 VB大版内专家分月排行榜第三2012年12月 VB大版内专家分月排行榜第三2011年6月 VB大版内专家分月排行榜第三2011年2月 VB大版内专家分月排行榜第三2010年12月 VB大版内专家分月排行榜第三2010年11月 VB大版内专家分月排行榜第三2009年7月 VB大版内专家分月排行榜第三
2014年7月 硬件/嵌入开发大版内专家分月排行榜第二
2013年10月 硬件/嵌入开发大版内专家分月排行榜第三2013年6月 硬件/嵌入开发大版内专家分月排行榜第三2013年3月 硬件/嵌入开发大版内专家分月排行榜第三
2014年7月 硬件/嵌入开发大版内专家分月排行榜第二
2013年10月 硬件/嵌入开发大版内专家分月排行榜第三2013年6月 硬件/嵌入开发大版内专家分月排行榜第三2013年3月 硬件/嵌入开发大版内专家分月排行榜第三
2011年1月 VB大版内专家分月排行榜第二2010年10月 VB大版内专家分月排行榜第二
2013年1月 VB大版内专家分月排行榜第三2012年12月 VB大版内专家分月排行榜第三2011年6月 VB大版内专家分月排行榜第三2011年2月 VB大版内专家分月排行榜第三2010年12月 VB大版内专家分月排行榜第三2010年11月 VB大版内专家分月排行榜第三2009年7月 VB大版内专家分月排行榜第三
2015年3月 Linux/Unix社区大版内专家分月排行榜第二2014年12月 Linux/Unix社区大版内专家分月排行榜第二2014年11月 Linux/Unix社区大版内专家分月排行榜第二2014年9月 Linux/Unix社区大版内专家分月排行榜第二2014年8月 Linux/Unix社区大版内专家分月排行榜第二2014年7月 Linux/Unix社区大版内专家分月排行榜第二2014年5月 Linux/Unix社区大版内专家分月排行榜第二2014年4月 Linux/Unix社区大版内专家分月排行榜第二
2014年3月 Linux/Unix社区大版内专家分月排行榜第三
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。}

我要回帖

更多关于 modbus协议 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信