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
这个头文件中添加了#includeassert() 断言宏 freeModbus的作者有点意思,为此不可以定义NDEBUG 。#include "stm32f10x.h" 似乎要添加到#include 的后边 不然编译会有问题。
port.C
添加了些Modbus协议栈与寄存器的接口函数 这个也要自己写。
FreeModbus 通过 eMBRegInputCB eMBRegHoldingCB eMBRegCoilsCB eMBRegDiscreteCB 四个接口函数完成数据的读写操作
其中最常用的是这个 eMBRegHoldingCB 为了方便测试可以构造usRegHoldingBuf[]这样的一个数组进行读写调试。
上位机可以用诸如Modbus调试精灵这样的软件。
// 寄存器的读写函数 支持的命令为读 0x03 和写0x06
eMBErrorCode eMBRegHoldingCB( 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条指令,效率提升有限。
上一篇:STM32 的看门狗
下一篇:STM32 _I _0 _IO volatile const
推荐阅读最新更新时间:2024-03-16 15:13