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.
工具/软件:Code Composer Studio
大家好、
我正在尝试使用 FreeMODBUS 堆栈在 TM4C123G 上实现 Modbus 协议。 但问题似乎发生在硬件设置上、这里是我使用的代码
对于 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$ */ #ifndef _port_H #define _port_H #include #include #include #include #include "inc/tm4c123gh6m.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/hw_sysctl.h" #include "driverlib/sysctl.h" #include "driverlib/interrupt.h" #include "driverlib/driverlib.gpio" #define #define 内联 #define PR_BEGIN_EXTERN extern "C"{ #definePR_END_extern _C} define enter_critical section() IntMasterDisable(); #define EXIT_CRITICAL_SECTION () IntMasterEnable(); typedef uint8_t BOOL; typedef unsigned char UCHAR; typedef char char; typedef uint16_t USHORT; typedef Int16_t short; tyedef Uint32_t long; typedef int32_t long; #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif #endif
portserial.h
/*
* FreeModbus Libary:裸端口
* Copyright (C) 2006 Christian Walter
*
*此库是免费软件;您可以重新分发和/或
*根据 GNU Lesser General Public 的条款对其进行修改
*由免费软件基金会发布的许可证;或者
*许可证2.1版,或(您可以选择)任何更高版本。
*
*发布此库的目的是希望它有用、
*但不提供任何保证;甚至没有的暗示保证
*适销性或特定用途的适用性。 请参阅 GNU
*较宽松通用公共许可证,了解更多详细信息。
*
*您应该已经收到 GNU Lesser General Public 的副本
*随此库一起提供许可证;如果没有、请写入免费软件
* Foundation、Inc.、51 Franklin St、Fifth Floor、Boston、 MA 02110-1301美国
*
*文件:$ID$
*
#include
#include
#include "inc/tm4c123gh6m.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/pin_map.h"
#include "driverlib/uart.h"
#include "port.h"
/*---------------- Modbus 包括------------------ *
#include "mB.h"
#include "mbport.h"
/*---------------- 静态函数------------------------------------------------------- *
static void prvUARTTxReadyISR( void );
static void prvUARTRxISR( void );
/*---------------- 开始执行--- *
无效
vMBPortSerialEnable( BOOL xRxEnable,BOOL xTxEnable )
{
/*如果 xRXEnable 启用串行接收中断。 如果启用了 xTxENable
*发送器为空中断。
*
if (xRxEnable)
{
UARTIntEnable (UART0_BASE、UART_INT_RX|UART_INT_RT);
UARTIntRegister (UART0_BASE、&prvUARTRxISR);
}
其他
UARTIntDisable (UART0_BASE、UART_INT_RX);
if (xTxEnable)
{
UARTIntEnable (UART0_BASE、UART_INT_TX);
UARTIntRegister (UART0_BASE、&prvUARTTxReadyISR);
}
其他
UARTIntDisable (UART0_BASE、UART_INT_TX);
}
布尔
xMBPortSerialInit( UCHAR ucPORT、Ulong ulBaudRate、UCHAR ucDataBits、eMBParity eParity )
{
(空) ucPORT;
uint32_t 奇偶校验、位、秒位;
//
//启用 UART 使用的 GPIO 外设。
//
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
//
//启用 UART0
//
SysCtlPeripheralEnable (SYSCTL_Periph_UART0);
//
//为 UART 模式配置 GPIO 引脚。
//
GPIOPinConfigure (GPIO_PA0_U0RX);
GPIOPinConfigure (GPIO_PA1_U0TX);
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);
//
//选择 UART 的长度和奇偶校验
//
switch (eParity)
{
案例 MB_PAR_LEVen:
奇偶校验= UART_CONFIG_PAR_LEVen;
stopbits = UART_CONFIG_STOP_ONE;
中断;
案例 MB_PAR_ODD:
奇偶校验= UART_CONFIG_PAR_ODD;
stopbits = UART_CONFIG_STOP_ONE;
中断;
案例 MB_PAR_NONE:
奇偶校验= UART_CONFIG_PAR_NONE;
stopbits = UART_CONFIG_STOP_Two;//确保11位 RTU 字符格式
中断;
}
Switch( ucDataBits )
{
案例8:
位= UART_CONFIG_WLEN_8;
中断;
案例7:
位= UART_CONFIG_WLEN_7;
中断;
}
//
//初始化控制台 I/O 的 UART
//
UARTConfigSetExpClk (UART0_BASE、SysCtlClockGet ()、ulBaudRate、(位|秒位|奇偶校验));
//禁用 FIFO,以确保中断仅用于 RX 的更改
UARTFIFODisable (UART0_BASE);
//
//启用 UART 和中断
//
UARTIntEnable (UART0_BASE、UART_INT_RX|UART_INT_RT);
UARTIntRegister (UART0_BASE、&prvUARTRxISR);
UARTEnable (UART0_BASE);
返回 false;
}
布尔
xMBPortSerialPutByte (char ucByte)
{
/*在 UART 发送缓冲区中放入一个字节。 此函数被调用
*如果 pxMBFrameCBTransmitterEmpty()已经存在,则按协议栈
*被调用。 *
UARTCharPut (UART0_BASE、ucByte);
if (UARTCharsAvail (UART0_BASE))
{
UARTCharPut (UART0_BASE、UARTCharGet (UART0_BASE));
}
返回 true;
}
布尔
xMBPortSerialGetByte (char * pucByte)
{
/*返回 UART 接收缓冲区中的字节。 此函数被调用
*在调用 pxMBFrameCBByteRecepto()后由协议栈提供。
*
UARTIntClear (UART0_BASE、UARTIntStatus (UART0_BASE、TRUE));
while (UARTCharsAvail (UART0_BASE))
{
* pucByte = UARTCharGetNonBlocking (UART0_BASE);
}
返回 true;
}
/*为发送缓冲区空中断创建中断处理程序
*(或等效项)。 此函数应如此
*调用 pxMBFrameCBTransmitterEmpty(),它告诉协议栈
*可以发送新字符。 然后、协议栈将调用
* xMBPortSerialPutByte()发送字符。
*
静态空 prvUARTTxReadyISR(空)
{
pxMBFrameCBTransmitterEmpty();
}
/*为目标的接收中断创建中断处理程序
*处理器。 然后,此函数应调用 pxMBFrameCBByteRecepthat()。 。
然后,协议栈将调用 xMBPortSerialGetByte()来检索
*字符。
*
静态 void prvUARTRxISR( void )
{
pxMBFrameCBByteRecept接收 器();
}
porttimer.h
/*
* FreeModbus Libary:裸端口
* Copyright (C) 2006 Christian Walter
*
*此库是免费软件;您可以重新分发和/或
*根据 GNU Lesser General Public 的条款对其进行修改
*由免费软件基金会发布的许可证;或者
*许可证2.1版,或(您可以选择)任何更高版本。
*
*发布此库的目的是希望它有用、
*但不提供任何保证;甚至没有的暗示保证
*适销性或特定用途的适用性。 请参阅 GNU
*较宽松通用公共许可证,了解更多详细信息。
*
*您应该已经收到 GNU Lesser General Public 的副本
*随此库一起提供许可证;如果没有、请写入免费软件
* Foundation、Inc.、51 Franklin St、Fifth Floor、Boston、 MA 02110-1301美国
*
*文件:$ID$
*
#include
#include
#include "inc/tm4c123gh6m.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
/*---------------- 平台包括: *
#include "port.h"
/*---------------- Modbus 包括------------------ *
#include "mB.h"
#include "mbport.h"
/*---------------- 静态函数------------------------------------------------------- *
static void prvTIMERExpiredISR( void );
/*---------------- 开始执行--- *
布尔
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
uint32_t a;
SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0);
TimerConfigure (TIMER0_BASE、TIMER_CFG_ONE_SHOT);
a = usTim1Timerout50us*SysCtlClockGet ()/2000-1;
TimerLoadSet (TIMER0_BASE、TIMER_A、A);
TimerIntRegister (TIMER0_BASE、TIMER_A、&prvTIMERExpiredISR);
IntEnable (INT_TIMER0A);
TimerIntEnable (TIMER0_BASE、TIMER_TINA_TIMEOUT);
IntMasterEnable();
GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_2、4);
返回 false;
}
内联空
vMBPortTimersEnable()
{
/*启用超时传递给 xMBPortTimersInit()*/的计时器
TimerEnable (TIMER0_BASE、TIMER_A);
}
内联空
vMBPortTimersDisable()
{
/*禁用任何挂起的计时器。 *
TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT);
GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_2、0);
}
/*创建一个 ISR,该 ISR 在计时器过期时调用。 此函数
*然后必须调用 pxMBPortCBTimerExpired ()通知协议栈
*计时器已过期。
*
静态 void prvTIMERExpiredISR( void )
{
( void )pxMBPortCBTimerExpired ();
}
用于 main.c
/* FreeModbus Libary:Bare Demo Application *版权所有(C) 2006 Christian Walter * *此程序是免费软件;您可以根据 *免费软件基金会发布的 GNU 通用公共许可证条款重新分发和/或修改*它;许可证的第2版或 *(您可以选择)任何后续版本。 * **本计划的发布目的是希望其有用 、*但没有任何保证;甚至没有* 适销性或特定用途适用性的暗示保证。 有关 更多详细信息、请参阅* GNU 通用公共许可证。 * *您应该已经收到 GNU 通用公共许可证*的副本 以及此程序;如果没有,请写信至 Free Software * Foundation、Inc.,51 Franklin St,Fifth Floor,Boston, MA 02110-1301 USA * *文件:$ID$ */ /*--- Modbus 包括------------------ // #include "mb.h" #include "mbport.h" #include #include #include "inc/tm4c123gh6m.h" #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "driverlib/sysctl.h" #include "driverlib/interrupt.h" #include "driverlib/gpio.h" #include "driverlib/timer.h" --- 定义了------------------------------------------------------- */ #define REG_INPUT_START 3000 #define REG_INPUT_NREGS 4 /*-------------- 静态变量------------------------------------------------------- */ static USHORT usRegInputStart = REG_INPUT_START; static USHORT usRegInputBuf[REG_INPUT_NREGS]; /*------------ 开始执行--- */ void Configuration() { SysCtlClockSet (SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHz);// 16MHz 时钟 SysCtlPeripheralEnable (SYSCTL_Periph_GPIOF); GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_3 | GPIO_PIN_2); SysCtlDelay (100000); GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_3 | GPIO_PIN_2、0); } int main (void) { eMBErrorCode EStatus; 配置(); EStatus = eMBInit( MB_RTU、0x0A、0、9600、MB_PAR_EVLETE ); /*启用 Modbus 协议栈。 * EStatus = eMBEnable(); // eMBClose (); for (;;) { ( void )eMBPoll(); /*在这里、我们只计算轮询周期数。 * usRegInputBuf[0]++; usRegInputBuf[1]= 5; usRegInputBuf[2]= 6; usRegInputBuf[3]= 33; } } eMBErrorCode eMBRegInputCB( UCHAR * puRegBuffer、USHORT usAddress、USHORT usRegs ) { 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; }
测试后、我发现微控制器仍然接收数据、但不会处理。 这可能是由于计时器设置、但我不确定、因为没有要观察的输出。 我尝试使用 GPIO LED 来跟踪数据过程、但当涉及到计时器时、中断条件可能会阻止它。
请帮我解决这个问题。 我确实在 TM4C 上查找了 Modbus 实现、但没有任何解决方案可以提供帮助、因此我不知道下一步要做什么。
感谢你的答复。
我将断点放入中断 ISR 中、但看不到发生计时器中断。 起初、我以为可能是因为我没有正确重新启动计时器。 我尝试使用它来实现它
bool xMBPortTimersInit( USHORT usTim1Timerout50us ) { SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0); TimerConfigure (TIMER0_BASE、TIMER_CFG_ONE_SHOT); A =(((usTim1Timerout50us*SysCtlClockGet ())/20000)-1; TimerLoadSet (TIMER0_BASE、TIMER_A、A); TimerIntRegister (TIMER0_BASE、TIMER_A、&prvTIMERExpiredISR); IntEnable (INT_TIMER0A); TimerIntEnable (TIMER0_BASE、TIMER_TINA_TIMEOUT); TimerEnable (TIMER0_BASE、TIMER_A); 返回 false; } 内联 void vMBPortTimersEnable() { /*启用超时传递给 xMBPortTimersInit()*/的计时器 TimerLoadSet (TIMER0_BASE、TIMER_A、A); TimerIntEnable (TIMER0_BASE、TIMER_TINA_TIMEOUT); TimerEnable (TIMER0_BASE、TIMER_A); } 内联 void vMBPortTimersDisable() { /*禁用任何挂起的计时器。 * TimerDisable (TIMER0_BASE、TIMER_A); TimerIntDisable (TIMER0_BASE、TIMER_TINA_TIMEOUT); TimerIntClear (TIMER0_BASE、TIMER_TIMA_TIMEOUT); } //创建一个 ISR,该 ISR 在计时器过期时调用。 然后,此函数*必须调用 pxMBPortCBTimerExpired (),以通知协议栈 *计时器已过期。 */ static void prvTIMERExpiredISR( void ) { TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT); ( void )pxMBPortCBTimerExpired (); }
但它仍然不起作用。 我不知道为什么在我运行一个单独的程序时中断仍然会发生(我是指一个用于定时器中断的程序、而不是上面的程序)。 请帮我解决这个问题。 谢谢!
关于断点、当我将断点放在 vMBPortTimersEnable 中时、该过程在 TimerEnable 函数处停止。 但是、当我在计时器中断函数中放置断点时、该过程并未停止。 因此、我的假设是该过程中未调用该函数。
关于检查状态寄存器、我以前没有做过类似的事情。 因此、我将尽快尝试并回复您。
感谢您的建议。
尊敬的 Charles:
我发现、由于某些不适用的函数、未调用中断。 所以我决定自己重写所有内容、该计划按预期工作(感谢您的建议)。
但目前、我在线圈、寄存器等的地址方面遇到了一些问题 Modbus 协议要求读取或读取/写入某些寄存器。
例如:
我发现数据的地址可以使用 HWREG 或直接使用指针来分配。 但我不确定如果我这么做、程序是否会发生冲突。 我已经读出该范围中的数据是针对闪存 ROM 的、但我找不到更具体的存储器映射。 我担心 TM4C123GH6PM 是否使用相同类型的存储器映射;因为首先、当我调试程序时、我发现分立式输入(只读、由于标准 Modbus 指南、在0x10000处)全部为1。 (下图)
我尝试查找其他 MCU 的存储器设置、发现对于 STM32和 Arduino、它们有寄存器组可将数据放入所需的地址、但我在 TM4C123GH6PM 中找不到任何类似的功能。 可以帮我解决这个问题吗? 谢谢你。
此致、