锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

FreeModbus移植经验分享

时间:2024-05-22 04:07:09

为什么要移植Freemodbus

为什么要移植Freemodbus,这个问题需要从两个方面来回答。第一,modbus是一个非常好的应用层协议,它很简洁也相对完善。对于还没有接触过modbus的朋友来说,我非常不建议直接移植freemodbus,应该耐心的从modbus文档入手,并充分把握身边的所有资源,例如PLC的中modbus部分。第二,其实嵌入式系统的通信协议可以自己制定,但是通过实践发现自己定制的协议漏洞百出,尤其是扩展极为困难。我始终认为借鉴他人的经验是很好的途径。借鉴他人成熟的代码,可以减少调试的时间,实现的功能也多了不少。

个人观点,仅供参考。

freemodbus小提示

freemodbus只能使用从机功能。freemodbus更适合嵌入式系统,虽然例子中也有WIN32的例子,如果想要做PC机程序并实现主机功能,推荐使用另一个modbus库——NMOUS,使用C#开发。同样WINFORM也可以通过自己编写串口代码实现modbus功能,但是这会花费很长的时间,可能是一周也可能是一个月,如果使用现成的代码库,那么开发时间可能只有10分钟。

freeemodbus中如何通过串口发送和接收数据

freemodbus通过串口中断的方式接收和发送数据。采用这种做法我想可以节省程序等待的时间,并且也短充分使用的资源。串口中断接收毋庸置疑,在中断服务函数中把数据保存在数组中,以便稍后处理。但是串口发送中断使用哪种形式?串口发送中断至少有两种方式,第一种,数据寄存器空中断,只要数据寄存器为空并且中断屏蔽位置位,那么中断就会发生;第二种,发送完成中断,若数据寄存器的数据发送完成并且中断屏蔽位置位,那么中断也会发送。我非常建议各位使用串口发送完成中断。freemodbus多使用RS485通信中,从机要么接收要么发送,多数情况下从机处于接收状态,要有数据发送时才进入发送状态。进入发送状态时,数据被一个一个字节发送出去,当最后一个字节被发送出去之后,从机再次进入接收状态。如果使用发送寄存器为空中断,还需要使用其他的方法才可以判断最后一个字节的数据是否发送完成。如果使用数据寄存器为空中断,那么将很有可能丢失最后一个字节。(马潮老师的图书中也推荐使用发送完成中断,交流性质的文章,就没有参考文献了。)

freemodbus中如何判断帧结束

大家应该清楚,modbus协议中没有明显的开始符和结束符,而是通过帧与帧之间的间隔时间来判断的。如果在指定的时间内,没有接收到新的字符数据,那么就认为收到了新的帧。接下来就可以处理数据了,首当其冲的就是判断帧的合法性。Modbus通过时间来判断帧是否接受完成,自然需要单片机中的定时器配合。

整体代码

下面给出一个M32平台上使用FREEMODBUS最简单的例子,操作保持寄存器,此时操作指令可以为030616

  • NT size=3>#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,0x4055,0x147b,0x408e};
  • int main(void)
  • {
  • //初始化 RTU模式 从机地址为1 U1 9600 无校验
  • eMBInit(MB_RTU, 0x01, 0x01, 9600, MB_PAR_NE);
  • //启动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 iRegIndex;
  • //判断寄存器是不是在范围内
  • 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--;
  • }
  • break;
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章