毕业设计自己要做个根据STM32的PLC能直接跑句子表的,现在看来如同没有什么立异的当地,不过完结的方法肯定够立异的了…呵呵。自己写的开题陈述中说了要有高档的通讯功用。现在做以太网有点来不及了,CAN又感觉不搭调,硬件上也没预备。串口上跑Modbus感觉不错。原本西门子的S7-200就能跑Modbus,STM32-PLC当然也要支撑Modbus 什么 组态软件,触摸屏都能够连上,不过FreeModbus只支撑从机有点惋惜,当然原本协议也不难并且也必要完结全协议栈。
Modbus中文协议.PDF
STM32移植FreeModbus的过程:
首先去http://www.freemodbus.org下载文件 必定要是官方牢靠的才行,我起先为了图便利网上随意下载了一个,成果白白糟蹋了一下午的时刻
不知道是哪里被改动了。现在最新的版别是1.5。
http://115.com/file/bee0jrth#freemodbus-v1.5.0.zip这是官方的牢靠版别。
Demo 文件夹下都是官方移植好的其他芯片的版别。选BARE文件下的“赤裸”文件参加工程 一起增加悉数的库文件,可参阅下图
需求移植修正的在 port 目录下
porttimer.c
中 xMBPortTimersInit( USHORT usTim1Timerout50us ) 担任装备一个 时基 ,vMBPortTimersEnable( ) 启用这个时基。
比方履行
xMBPortTimersInit( 10000 );
vMBPortTimersEnable( );
for( ;; );
定时器按中止内 便会每500MS调用一次pxMBPortCBTimerExpired( );一起你也要检测vMBPortTimersDisable( ) 是否能够牢靠的封闭定时器。用仿真器 用LED灯都行的.
portother.c
//担任一个串口的装备 为了省劲我只支撑了波特率的修正
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )担任操控串口【收/发】中止的制止与使能
pxMBFrameCBByteReceived( ); //在串口接纳中止内调用 用于通讯侦测
pxMBFrameCBTransmitterEmpty( ); //在串口发送中止内调用 用于奉告完结了发送 发送缓冲为空
xMBPortSerialGetByte( CHAR * pucByte ) xMBPortSerialPutByte( CHAR ucByte ) 两个为 串口字节的收发
port.h
中界说了 大局中止的开关
#define ENTER_CRITICAL_SECTION( ) __set_PRIMASK(1) /*关中中止*/
#define EXIT_CRITICAL_SECTION( ) __set_PRIMASK(0) /*开总中止*/
__set_PRIMASK() 来源于 core_cm3.c
这个头文件中增加了#include assert() 断语宏 freeModbus的作者有点意思,为此不能够界说NDEBUG 。#include "stm32f10x.h" 好像要增加到#include 的后边 否则编译会有问题。
port.C
增加了些Modbus协议栈与寄存器的接口函数 这个也要自己写。
FreeModbus 经过 eMBRegInputCB eMBRegHoldingCB eMBRegCoilsCBeMBRegDiscreteCB 四个接口函数完结数据的读写操作
其间最常用的是这个 eMBRegHoldingCB 为了便利测验能够结构usRegHoldingBuf[]这样的一个数组进行读写调试。
上位机能够用比如Modbus调试精灵这样的软件。
// 寄存器的读写函数 支撑的指令为读 0x03 和写0x06
eMBErrorCodeeMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ){ eMBErrorCode eStatus = MB_ENOERR; int iRegIndex;u16 *PRT=(u16*)pucRegBuffer;
if( ( usAddress >= REG_HOLDING_START ) && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) ) { iRegIndex = ( int )( usAddress - usRegHoldingStart ); switch ( eMode ) { case MB_REG_READ: while( usNRegs > 0 ) { *PRT++ = __REV16(usRegHoldingBuf[iRegIndex++]); //数据序转 REV16.W
// *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] >> 8 );// *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] & 0xFF );// iRegIndex++; usNRegs--; } break;
case MB_REG_WRITE: while( usNRegs > 0 ) { usRegHoldingBuf[iRegIndex++] = __REV16(*PRT++); //数据序转 REV16.W
// usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;// usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;// iRegIndex++; usNRegs--; } } } else { eStatus = MB_ENOREG; } return eStatus;}
遭到freeModbus作者运用“assert()”的影响在这个里我用了__REV16()这个函数
*PRT++ = __REV16(usRegHoldingBuf[iRegIndex++]);
这是Cortex—M3中的一个汇编指令REV16 功用是交流一个字的高位和位置位的两个字节,若0x1234==__REV16(0x3412)。字节在*pucRegBuffer中的次序与串口发送的次序是共同的所以要有这么个转化,当然用代码中注释掉的部分也能完结相同的功用。这是用__REV16()看起来更“酷”一些。当然这样编译后的成果是大约削减4条指令,功率提高有限。