FreeModbusFreeModbusFreeModbusFreeModbus移植于STM32STM32STM32STM32实现ModbusModbusModbusModbusRTURTURTURTU通信毕业设计自己要做个基于STM32的PLC能直接跑语句表的,现在看来好像没有什么创新的地方,不过实现的方式绝对够创新的了...呵呵。自己写的开题报告中说了要有高级的通信功能。现在做以太网有点来不及了,CAN又感觉不搭调,硬件上也没准备。串口上跑Modbus感觉不错。本来西门子的S7-200就能跑Modbus,STM32-PLC当然也要支持Modbus什么组态软件,触摸屏都可以连上,不过FreeModbus只支持从机有点可惜,当然本来协议也不难而且也必要实现全协议栈。Modbus中文协议.PDFSTM32移植FreeModbus的步骤:首先去下载文件一定要是官方可靠的才行,我起先为了图方便网上随便下载了一个,结果白白浪费了一下午的时间不知道是哪里被改动了。目前最新的版本是1.5。这是官方的可靠版本。Demo文件夹下都是官方移植好的其他芯片的版本。选BARE文件下的“赤裸”文件加入工程同时添加全部的库文件,可参考下图需要移植修改的在port目录下porttimer.c中xMBPortTimersInit(USHORTusTim1Timerout50us)负责配置一个时基,vMBPortTimersEnable()启用这个时基。比如执行xMBPortTimersInit(10000);vMBPortTimersEnable();for(;;);定时器按中断内便会每500MS调用一次pxMBPortCBTimerExpired();同时你也要检测vMBPortTimersDisable()是否可以可靠的关闭定时器。用仿真器用LED灯都行的.portother.c//负责一个串口的配置为了省事我只支持了波特率的修改xMBPortSerialInit(UCHARucPORT,ULONGulBaudRate,UCHARucDataBits,eMBParityeParity)vMBPortSerialEnable(BOOLxRxEnable,BOOLxTxEnable)负责控制串口【收/发】中断的禁止与使能pxMBFrameCBByteReceived();//在串口接收中断内调用用于通讯侦测pxMBFrameCBTransmitterEmpty();//在串口发送中断内调用用于告知完成了发送发送缓冲为空xMBPortSerialGetByte(CHAR*pucByte)xMBPortSerialPutByte(CHARucByte)两个为串口字节的收发port.h中定义了全局中断的开关#defineENTER_CRITICAL_SECTION()__set_PRIMASK(1)/*关中中断*/#defineEXIT_CRITICAL_SECTION()__set_PRIMASK(0)/*开总中断*/__set_PRIMASK()来源于core_cm3.c这个头文件中添加了#includeassert.hassert()断言宏freeModbus的作者有点意思,为此不可以定义NDEBUG。#includestm32f10x.h似乎要添加到#includeassert.h的后边不然编译会有问题。port.Cport.Cport.Cport.C添加了些Modbus协议栈与寄存器的接口函数这个也要自己写。FreeModbus通过eMBRegInputCBeMBRegHoldingCBeMBRegCoilsCBeMBRegDiscreteCB四个接口函数完成数据的读写操作其中最常用的是这个eMBRegHoldingCB为了方便测试可以构造usRegHoldingBuf[]这样的一个数组进行读写调试。上位机可以用诸如Modbus调试精灵这样的软件。//寄存器的读写函数支持的命令为读0x03和写0x06eMBErrorCodeeMBRegHoldingCB(UCHAR*pucRegBuffer,USHORTusAddress,USHORTusNRegs,eMBRegisterModeeMode){eMBErrorCodeeStatus=MB_ENOERR;intiRegIndex;u16*PRT=(u16*)pucRegBuffer;if((usAddress=REG_HOLDING_START)&&(usAddress+usNRegs=REG_HOLDING_START+REG_HOLDING_NREGS)){iRegIndex=(int)(usAddress-usRegHoldingStart);switch(eMode){caseMB_REG_READ:while(usNRegs0){*PRT++=__REV16(usRegHoldingBuf[iRegIndex++]);//数据序转REV16.W//*pucRegBuffer++=(unsignedchar)(usRegHoldingBuf[iRegIndex]8);//*pucRegBuffer++=(unsignedchar)(usRegHoldingBuf[iRegIndex]&0xFF);//iRegIndex++;usNRegs--;}break;caseMB_REG_WRITE:while(usNRegs0){usRegHoldingBuf[iRegIndex++]=__REV16(*PRT++);//数据序转REV16.W//usRegHoldingBuf[iRegIndex]=*pucRegBuffer++8;//usRegHoldingBuf[iRegIndex]|=*pucRegBuffer++;//iRegIndex++;usNRegs--;}}}else{eStatus=MB_ENOREG;}returneStatus;}受到freeModbus作者使用“assert()”的影响在这个里我用了__REV16()__REV16()__REV16()__REV16()这个函数*PRT++=__REV16__REV16__REV16__REV16(usRegHoldingBuf[iRegIndex++]);这是Cortex—M3中的一个汇编指令REV16功能是交换一个字的高位和地位位的两个字节,若0x1234==__REV16(0x3412)__REV16(0x3412)__REV16(0x3412)__REV16(0x3412)。字节在*pucRegBuffer中的顺序与串口发送的顺序是一致的所以要有这么个转换,当然用代码中注释掉的部分也能实现同样的功能。这是用__REV16()__REV16()__REV16()__REV16()看起来更“酷”一些。当然这样编译后的结果是大约减少4条指令,效率提升有限。序转指令不少功能非常强大~!__REV16()来源于core_cm3.c后边只要想法将STM32_PLC输出的地址映射这个寄存器上边可以了整个移植没有什么难度只是看官方的英文API文档生词太多,其实意思非常简单。而且刚开始又用了来路不明的FreeModbus库文件,不伦怎样都不工作,浪费不少时间。全部工作前后总共花了两天的时间。我移植好的demo注释很全应该可以轻易看懂。