This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TM4C123GH6PM:FreeModbus 实现

Guru**** 2331900 points
Other Parts Discussed in Thread: TM4C123GH6PM
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/598083/tm4c123gh6pm-freemodbus-implementation

器件型号:TM4C123GH6PM

大家好!  

我正在尝试在我的 TM4C123GH6PM 中实现 Freemodbus 堆栈 、 我已经进行了一些测试、但没有成功。

希望能得到一些帮助或建议非常感谢、以下是我已经完成的步骤

1.首先,我下载了 freemodbus-v 1.4.0文件夹,并在相应的端口文件夹中进行“更改”,  

port.h


 

/*
FreeModbus Libary:Bare Port
* Copyright (C) 2006 Christian Walter 
*
*此库是免费软件;您可以根据

免费软件基金会发布的 GNU Lesser General Public *许可证的条款重新分发和/或*修改它;
*许可证2.1版或(您可以选择)任何更高版本。
*
*发布本库的目的是希望其有用
、*但不作任何保证;甚至没有*
适销性或特定用途适用性的暗示保证。 有关
详细信息、请参阅 GNU * Lesser General Public License。
*
*您应该已经收到 GNU Lesser General Public
*许可证以及此库的副本;如果没有,请写信至 Free Software
* Foundation、Inc.,51 Franklin St,Fifth Floor,Boston, ma 02110-1301 USA
*
*文件:$ID:port.h、v 1.1 2006/08/221:35:13 wolti Exp$
*/

#ifndef _port_H
#define _port_H
/*------ 平台包括: */
#include "incTM4c123.h"
#include 
#define内联 内联
#define PR_BEGIN_EXTERN extern "C"{
#definePR_END_extern _C}

#define enter_critical SECTION () ROM_IntMasterDisable ()
#define EXIT_CRITICAL_SECTION () ROM_IntMasterEnable ()

typedef uint8_t BOOL;

typedef unsigned char UCHAR;
typedef char char;

typedef uint16_t USHORT;
tyf Int16_t short;

tyINT32_t Ulong
typedef int32_t long;

#ifndef true
#define true 1
#endif

#ifndef false
#define false 0
#endif

#endif

因此、.h 文件 IncTm4c123.h 只是一个头文件、我在其中放置相应的头文件以使用外设函数、我忘记了提到我正在使用 TivaWare 2.1.4.178、IDE 是 IAR 8.0

根据  我的理解、使用或需要使用常量:ENTER_CRITICAL_SECTION 和 EXIT_CRITIC_SECTION 来禁用器件对象上的中断、以便禁用所有处理器中断  


在 portation.dox 文件之后、下一个要更改的文件是  

porttimer.c

/*---------------- 平台包括: */
#include "port.h"
#include "IncTM4C123.h"


/*---------------- Modbus 包括------------------ */
#include "mb.h"
#include "mbport.h"

/*-------------- 静态函数------------------------------------------------------- ///static
void prvTIMER ExpiredISR( void );

/*-------------- 我的函数------------------------------------------- */
USHORT usMBMulDiv (USHORT A、USHORT b、USHORT c);

/*-------------- 持久性变量------------------------------------------------------- */
USHORT usDelta;
/*-------------- 开始执行--- //
USHORT usMBMulDiv (USHORT A、USHORT b、USHORT c){
Ulong x;
x = a;
x *= b;
x /= c;
return (USHORT) x;
}

//时间参数 usTim1Timerout50us 是50us 的倍数
//因此,为了计算计时器节拍,请使用函数 usMBMMulDiv
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{

ROM_SysCtlPeripheralEnable (sysctl_Periph_TIMER0);
ROM_TIMERConfigure (TIMER0_BASE、TIMER_CFG_ONE_SHOT);//全宽32位和针对 freemodmus 要求计时器需要是一次性
//定义要加载到寄存器
中的数字 usDelta = usMBMulDiv (usTim1Timerout50us、800、100);
ROM_IntMasterIMA ();//启用 TIMER0A/ENABLE_TIMER

TOOT/ END/ TOOTTIMER 0/ TOVERT 超时(/inc/hw_ints.h);启用 TIMER0_INT_INTERRUPT




返回 true;
}


void
vMBPortTimersEnable()//仅启动计时
器{
/*在超时传递给 xMBPortTimersInit()时启用定时器*/
ROM_TimerLoadSet (TIMER0_BASE、TIMER_A、usDelta);
ROM_TimerEnable (TIMER0_BASE、TIMER_A);//启用定时器
ROM_TimerIntEnable (TIMER0_BASE、 Timer_TINA_TIMEOUT);
ROM_TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT);
}

void
vMBPortTimersDisable()
{
/*禁用任何挂起的计时器。 /
ROM_TIMERDisable (TIMER0_BASE、TIMER_A);
ROM_TIMERIntDisable (TIMER0_BASE、TIMER_TINA_TIMEOUT);
ROM_TIMERIntClear (TIMER0_BASE、TIMER_TIMA_TIMEOUT);

}

/*创建一个 ISR,该 ISR 在计时器过期时调用。
然后,此函数*必须调用 pxMBPortCBTimerExpired (),以通知协议栈
*计时器已过期。
*/
void Timer0IntHandler( void ){


ROM_TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT);
ROM_TimerIntDisable (TIMER0_BASE、TIMER_TINA_TIMEOUT);
( void )pxMBPortCBTimerExpired ();
}

我已经使用以下所述的代码来测试此部件:

xMBPortTimersInit(20);
vMBPortTimersEnable(); 

似乎可以正常工作、只需打开 Timer0 ISR (Timer0IntHandler (void))中的 LED


下一个...

portserial.c

#include "port.h"

/*---------------------- Modbus 包括------------------ */
#include "mb.h"
#include "mbport.h"

/*-------------- 静态函数------------------------------------------------------- /*static
void prvUARTTxReadyISR( void );
static void prvUARTRxISR( void );
*/
/*--- 开始执行--- //
void
vMBPortSerialEnable( BOOL xRxEnable,BOOL xTxEnable )
{//
If xRXEnable 启用串行接收中断。 如果启用了 xTxENable
*发送器为空中断。
//
if (xRxEnable)
{
UARTIntEnable (UART0_BASE、UART_INT_RX);

}否则 UARTIntDisable (UART0_BASE、UART_INT_RX);

if (xTxEnable)
{
UARTIntEnable (UART0_BASE、UART_INT_TX);
}否则 UARTIntDisable (UART0_BASE、UART_INT_TX);

}

BOOL
xMBPortSerialInit( UCHAR ucPORT、Ulong ulBaudRate、UCHAR ucDataBits、eMBParity eParity)
{
(空) ucPORT;
uint32_t 奇偶校验、位、秒位;
//
//启用 UART 使用的 GPIO 外设。
//
ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);

//
//启用 UART0
//
ROM_SysCtlPeripheralEnable (SYSCTL_Periph_UART0);

//
//为 UART 模式配置 GPIO 引脚。
//
ROM_GPIOPinConfigure (GPIO_PA0_U0RX);
ROM_GPIOPinConfigure (GPIO_PA1_U0TX);
ROM_GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);

//
//选择 UART 的长度和奇偶校验
//

switch (eParity)
{
case MB_PAR_EVEN:
奇偶校验= UART_CONFIG_PAR_EVEN;
stopbits = UART_CONFIG_STOP_ONE;
break;
case MB_PAR_ODD:
奇偶校验= UART_CONFIG_PAR_ODD;
stopbits = UART_CONFIG_ST_NOT_11



;stop_bits = UART_UART_CONFIG = UART_11字符格式/确保 UART_CONFIG

break;
}

switch( ucDataBits )
{
案例8:
bits = UART_CONFIG_WLEN_8;
break;
案例7:
bits = UART_CONFIG_WLEN_7;
break;
}

//
//初始化控制台 I/O 的 UART
//
ROM_UARTConfigSetExpClk (UART0_BASE、ROM_SysCtlClockGet ()、ulBaudRate、
(BITS | stopbits |
奇偶校验);
//禁用 FIFO,以确保中断仅用于 RX 的更改
UARTFIFODisable (UART0_BASE);
//
//启用 UART 和中断
//
ROM_IntEnable (INT_UART0);
// vMBPortSerialEnable (true、true);
返回 true;
}

BOOL
xMBPortSerialPutByte (char ucByte)
{
/*在 UART 发送缓冲区中放入一个字节。 此函数被调用
*如果 pxMBFrameCBTransmitterEmpty()已经存在,则按协议栈
*被调用。 */
UARTCharPut( UART0_BASE,ucByte );
返回 true;
}

BOOL
xMBPortSerialGetByte (char * pucByte)//提供@以放置新的 char
{
/*返回 UART 接收缓冲区中的字节。 此函数被调用
*在调用 pxMBFrameCBByteRecepto()后由协议栈提供。
*

//
//无 FIFO。
//
操作
{
* pucByte = ROM_UARTCharGet (UART0_BASE);

} while (ROM_UARTCharsAvail (UART0_BASE));

返回 true;
}


void UARTIntHandler (void)
{
uint32_t ui32status;

ui32status = ROM_UARTIntStatus (UART0_BASE,TRUE);
//为目标
*处理器的接收中断创建中断处理程序。 然后,此函数应调用 pxMBFrameCBByteRecepthat()。
然后,*协议栈将调用 xMBPortSerialGetByte()以检索
*字符。
//
if (ui32status == UART_INT_RX)
{
pxMBFrameCBByteReceived();
ROM_UARTIntClear ( UART0_BASE,ui32status );

}

/*为
目标处理器创建发送缓冲区空中断*(或等效中断)的中断处理程序。 然后,此函数
应*调用 pxMBFrameCBTransmitterEmpty(),它告知协议栈
*可以发送新字符。 然后,协议栈将调用
* xMBPortSerialPutByte()发送字符。
//
if (ui32status =UART_INT_TX)
{
pxMBFrameCBTransmitterEmpty ();
ROM_UARTIntClear (UART0_BASE、ui32status);
}

在这里、我不确定是否可以禁用 UART 的 FIFO、但我只想确保只有在引脚发生变化时才会发生中断

我只尝试使用这部分从 PC 发送字符的代码、并打开 UART ISR 中的 LED、它工作正常。


最后、主要内容:

main.c

#include "incTM4c123.h"
#include 
#include "mb.h"
#include "mbport.h"
/*------------------ 定义了------------------------------------------------------- //
#define REG_INPUT_START 1000
#define REG_INPUT_NREGS 4
static unsigned usRegInputStart = REG_INPUT_START;
static unsigned usRegInputBuf[REG_INPUT_NREGS];
void configure (void);

eMBErrorCode
eMBRegInputCB (UCHAR * pucRegBuffer、USHORT)

eMBErrorCode EStatus = MB_ENOERR;
内部 iRegIndex;

if ((usAddress >= REG_INPUT_START)
&&(usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS)
{
iRegIndex =( int )( usAddress - usRegInputStart );
while (usNRegs >0)
{
*puRegBuffer++=
(unsigned char)(usRegInputBuf[iRegIndex]>> 8);
*puRegBuffer++=
(unsigned char)(usRegInputBuf[iRegIndex]& 0xFF);
iRegIndex++;
usNRegs--;
}
}
其他
{
EStatus = MB_ENOREG;
}

返回 EStatus;
}
eMBErrorCode
eMBRegHoldingCB (UCHAR * puRegBuffer、USHORT usAddress、USHORT usNRegs、
eMBRegisterMode eMode)
{
返回 MB_ENOREG;
}


eMBErrorCode
eMBRegCoilsCB (UCHAR * puRegBuffer、USHORT usAddress、USHORT usNils、
eMBRegisterMode eMode)
{
返回 MB_ENOREG;
}

eMBErrorCode
eMBRegDisconteCB( UCHAR * puRegBuffer、USHORT usAddress、USHORT us离散)
{
返回 MB_ENOREG;
}
//----------------- main
int main()
{
configureMBIN(MB_RTU

,0x01,0,9600, mb_par_none);
//启用 Modbus 协议栈。 */
eMBEnable();

for (;;)
{
( void )eMBPoll();


/*在这里、我们只计算轮询周期数。 *
usRegInputBuf[0]++;
}
}


void 配置(void){


ROM_SysCtlClockSet (SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHz);// 16MHz clk ROM_SysTL_SysT1_GPIO
PeripheralEnable (SYSCTL_Periph_GPIOF);ROM_GPIOPINTypeGP2_BASE



(GPIO_IN_GPIOPTF);GPIO_PIN_IN_IN_INP0_GPIO_IN_IN_GPIO_IN_IN_GPIOPTF);GPIO_IN_IN_IN_IN_GPIO_IN_IN_IN_IN_IN_IN_IN_IN_INP0_GPIO_IN_IN_IN_ 

我只想使用 RTU 模式、因此在 mbconfig.h 中、我在 ASCII 和 TCP 宏中放置了0、我在 Linux 中使用了 Modpoll Modbus Master Simulator、参数为:  

:$./modpoll -m RTU -a 1 -r 1000 -c 4 -t 3 -b 9600 -d 8 -p 无/dev/ttyACM0 

对从属方没有答案:/我真的很难,我会尝试在 FIFO 上做一些更改,也许这会有帮助,但我只是想知道有人是否处理过这个问题, 并告诉我是否正在正确修改文件

谢谢、致以最诚挚的问候!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Miguel -在这里发表"第一次"的帖子-你做了一个"很棒"的工作!   体贴、以小巧易消化的小块介绍、细节充分。   这种情况很罕见-比一般情况更好地解释、"不起作用!"    (正如我们的故障、海报出现故障...)

    我们可以从您帖子的"结束"开始吗?

    [引用 user="Miguel Miranda "]没有从站的答案:/我真的很难回答[/quot]

    怀疑您的意思是"从奴"-我们不应该从那里开始吗?    BTW -我"知道"-但从未使用- Free ModBus。

    是否最好"确认"您的从设备(4C123 MCU)是否(真正)能够"与"Modpoll Modbus Master Simulator"(Modpoll Modbus 主模拟器)进行"通话"(使用更简单的实现方式)?

    公司/我取得了(部分)成功-这主要是由于"亲吻"-我们始终尝试将设计的"复杂且冗长"部分分解为更小、更基本的部分-并逐一测试!

    在您的案例中、有(非常)大量工作在进行、因此您的诊断能力(正如您发现的那样)非常困难。    我们无法判断您是否已(成功)从4C123发送到 Modbus 仿真器。   我认为、这是一项重要的测试、应该通过供应商的 API 以最快、最简单的方式完成。   (有多个 UART 示例: "Examples/Peripherals/UART...")

    一旦您成功地在 MCU 和 Modbus 之间传输数据-使"Modbus 命令"运行应该更容易。

    我建议您(暂时)在 Modbus 上保持挂起、而是在 Modbus 仿真器和4C123板之间通过同一 UART 建立双向通信。   请注意、您使用的 UART0是(单独使用)使用 MCU 板的第二个 MCU 作为 UART 转 USB 串行转换器。   所有其他 UART 通道均为3V3信号电平-仅限!   (请勿连接到 RS232或任何高于3V3的电压或低于接地!)

    您是否知道这种在 Windows 下运行的仿真器(理想情况下是 Win7 -我们使用的是 Win7)?   这将使(许多)在这里重复您的测试- Linux 在这里不受欢迎-因此将限制能够提供帮助的人员/组的数量。   (包括我的小组)

    祝你好运——再说一次——干得不错……

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用 USER="CB1_MOBILE "]

    Miguel -在这里发表"第一次"的帖子-你做了一个"很棒"的工作!   体贴、以小巧易消化的小块介绍、细节充分。   这种情况很罕见-比一般情况更好地解释、"不起作用!"    (正如我们的故障、海报出现故障...)

    [/报价]

    -感谢您的回复,并感谢您的祝贺。

    [引用 USER="CB1_MOBILE "]

    怀疑您是指" 从器件"

    [/报价]

    是的,我的意思是:p

    [引用 USER="CB1_MOBILE "]

    是否最好"确认"您的从设备(4C123 MCU)是否(真正)能够"与"Modpoll Modbus Master Simulator"(Modpoll Modbus 主模拟器)进行"通话"(使用更简单的实现方式)?

    [/报价]

    我进行了一些基本测试、只需确认计时器和 UART 的正确初始化、它正常工作、也是根据中断情况进行的、在 UART 中只尝试 RX 中断。 但我所做的所有测试都是在不启用 Modbus 堆栈的情况下进行的、我的意思是... 使用这样的东西:

    xMBPortSerialInit (9600UL, 0, 8, MB_PAR_NON);
    vMBPortSerialEnable (true , false );
    xMBPortTimersInit( 200);
    vMBPortTimersEnable(); 

    但我同意您的观点、我认为首先我需要确保当第一个帧从主器件到达并且计时器开始计数时发生中断...

    谢谢!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    确实、请考虑"亲吻"-总是那些"尝试一切-一切都被打乱"的人会发现他们的结果缺失-他们的测试/故障排除不必要地扩展和复杂!

    回想一下宇航员 Armstrong 的话、"这是一个小的"测试"步骤(由 Miguel 完成)-一个朝着项目成功迈出的巨大一步!