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.

[参考译文] 编译器/TM4C129CNCPDT:UART0 RX 中断问题

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/653140/compiler-tm4c129cncpdt-uart0-rx-interrupt-issue

器件型号:TM4C129CNCPDT
Thread 中讨论的其他器件:EK-TM4C129EXL

工具/软件:TI C/C++编译器

您好 Gurus、

我正在尝试实现 UART0 RX 中断、但尚未实现。 代码编译成功、没有任何错误。 但是、我面临两个奇怪的问题、

  1. 直到我发送第8个字符、它才会捕获任何中断。 当它接收到第8个字符时、它为中断处理程序 ISR 提供服务并成功返回
  2. 它只为中断提供一次服务、无论我发送多少宪章、它都不会再次中断。

我已经在 startup_css.c 文件中注册了中断处理程序并进行了声明。

//
//
//应用程序使用的中断处理程序的外部声明。
////
*****************
extern void xPortPendSVHandler (void);
extern void vPortSVCHandler (void);
extern void xPortSysTickHandler (void);

extern void UART0ISR (void);


//********* 

IntDefaultHandler、 // GPIO 端口 B
IntDefaultHandler、 // GPIO 端口 C
IntDefaultHandler、 // GPIO 端口 D
IntDefaultHandler、 // GPIO 端口 E
UART0ISR、 // UART0 Rx 和 Tx
IntDefaultHandler、 // UART1 Rx 和 Tx
IntDefaultHandler、 // SSI0 Rx 和 Tx
IntDefaultHandler、 // I2C0主机和从机 

mymain.c;

#include 
#include 
include "main.h"
#include "drivers/pinout.h"
#include "utils/uartstdio.h"


// TivaWare 包含
#include "driverlib/sysctl.h"
#include "driverlib/debug.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map#include



"driver.h"#defintrl.ude/task#include

"#include "driverlib.h"#include "#defintrabout.udpov.h"#include "#defintrab.trab.h #include "#tes#definu.tots.h #include "#include "driverlib/void #include "driverlib_rtos"#include "#def"#def"#def"#task.ipts"#include "#def"#def"#def"#def"#ts"#def"#ts"#def"#defintrl.ipts"#include "#include "#defintrab.ipts"#include "#def"#def"#ts.ts"#include "#ts"











void LED3Task (void *pvParameters);
void LED4Task (void *pvParameters);
void SerialTask1 (void *pvParameters);
void SerialTask2 (void *pvParameters);
void UART0ISR (void);

//主函数
int main (void)
{
//将系统时钟初始化为120 MHz
uint32_t output_clock_rate_Hz;
output_clock_rate _Hz = ROM_SysCtlClockFreqSet (
(SYSCTL_XTAL_25MHz | SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480)、
System_clock);
assert (output_clock_rate _Hz = system_clock);

//初始化 Launchpad 的 GPIO 引脚
PinoutSet (false、false);

//设置连接到虚拟 COM 端口的 UART
//UARTStdioInit(0);
//UARTStdioConfig (0、115200、system_clock);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

SysCtlPeripheralEnable (SYSCTL_Periph_UART0);

GPIOPinConfigure (GPIO_PA0_U0RX);
GPIOPinConfigure (GPIO_PA1_U0TX);
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);

//UARTConfigSetExpClk (UART0_BASE、OUTPUT_CLOCK_RATE、115200、(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));


UARTIntEnable (UART0_BASE、UART_INT_RX);//仅启用 RX 中断
//IntRegister (INT_UART0、UART0ISR);

IntEnable (INT_UART0);//启用 UART 中断
IntMasterEnable();//启用处理器中断

UARTStdioConfig (0、115200、system_clock);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//创建演示任务
xTaskCreate (LED1Task、(const portCHAR *)"LED1"、
configMINIMAL_STACK_SIZE、NULL、1、NULL);

//xTaskCreate (demLED2Task、(const portCHAR *)"LED2"、
//configMINIMAL_STACK_SIZE、NULL、1、NULL);

xTaskCreate (LED3Task、(const portCHAR *)"LED3"、
configMINIMAL_STACK_SIZE、NULL、1、NULL);

//xTaskCreate (LED4Task、(const portCHAR *)"LED4"、
//configMINIMAL_STACK_SIZE、NULL、1、NULL);

xTaskCreate (SerialTask1、(const portCHAR *)"SerialTask1"、
configMINIMAL_STACK_SIZE、NULL、1、NULL);

xTaskCreate (SerialTask2、(const portCHAR *)"SerialTask2"、
configMINIMAL_STACK_SIZE、NULL、1、NULL);

vTaskStartScheduler();

///调度程序永远不应到达此处///
while (1)
{
//UARTprintf ("调度程序错误!!\n\n"\});
GPIOPinWrite (CLP_D1_PORT、CLP_D1_PIN、CLP_D1_PIN);
GPIOPinWrite (CLP_D2_PORT、CLP_D2_PIN、CLP_D2_PIN);
GPIOPinWrite (CLP_D3_PORT、CLP_D3_PIN、CLP_D3_PIN);
GPIOPinWrite (CLP_D4_PORT、CLP_D4_PIN、CLP_D4_PIN);
返回0;
}



}

和 UART0处理程序定义;

空 UART0ISR (空)
{
UARTIntClear (UART0_BASE、UART_INT_RX);
UARTprintf ("UART0ISR 被调用..!\n\n");
}

我卡住了、无法识别问题。

任何帮助/提示都是值得注意的。

谢谢大家。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    请注意、前两个代码来自 startup_css.c、最后两个代码来自 main.c
    我使用的是 EK-TM4C129EXL launchpad 和 CCS 版本7.4
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用 USER="Sahil)]直到我发送第8个字符后,才会捕获任何中断。 当它接收到第8个字符时,它为中断处理程序 ISR 提供服务,并在 UARTStdioConfig()函数内返回 sucessFully,此时有以下条件编译代码:

    #ifdef UART_buffered
    //
    //将 UART 设置为在 TX FIFO 几乎为空或时中断
    //接收到任何字符时。
    //
    MAP_UARTFIFOLevelSet (g_ui32Base、UART_FIFO_TX1_8、UART_FIFO_RX1_8);
    
    //
    //刷新两个缓冲区。
    //
    UARTFlushRx();
    UARTFlushTx (真);
    
    //
    //记住我们要处理的中断。
    //
    G_ui32PortNum = ui32PortNum;
    
    //
    //我们配置为缓冲输出,因此启用主中断
    //对于该 UART 和接收中断。 我们实际上不会启用
    //在 UART 本身发送中断,直到放置了一些数据
    //在发送缓冲区中。
    //
    MAP_UARTIntDisable (g_ui32Base、0xFFFFFFFF);
    MAP_UARTIntEnable (g_ui32Base、UART_INT_RX | UART_INT_RT);
    MAP_IntEnable (g_ui32UARTInt[ui32PortNum]);
    #endif 

    在主函数中 ,注释掉对 UARTConfigSetExpClk()的调用,而 是调用 UARTStdioConfig()来配置 UART0。 如果  在编译包含 UARTConfigSetExpClk () 的 Tivaware uartstudio.c 实用程序时定义了 UART_buffered,则 UARTConfigSetExpClk ()将使 UART FIFO 只在收到8个字符后中断,这可能会解释您的第一个问题。 不确定这是否也是第二个问题的原因。

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

    问题是我注释掉 UARTStudioConfig (),而使用 UARTConfigSetExpClk()。 由于 UARTprintf()挂起,我再也不能使用它了。 所以我不得不使用它、除非你能提出替代方案?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用 user="Chester Gillon">在主函数中 ,对 UARTConfigSetExpClk()的调用被注释掉,而 是调用 UARTStdioConfig()来配置 UART0。 如果  在编译包含 UARTConfigSetExpClk () 的 Tivaware uartstudio.c 实用程序时定义了 UART_buffed,则 UARTConfigSetExpClk ()将使 UART FIFO 只在收到8个字符后中断Oops,我没有正确读取 UARTConfigSetExpClk ()函数中的代码,这意味着我先前的建议是错误的。 进一步检查时:

    a)在编译 UART_buffered 定义时、UARTConfigSetExpClk ()启用 RX/TX FIFO (通过调用 MAP_UARTEnable)并将 UART 设置为在接收到任何字符时中断(通过调用 MAP_UARTFIFOLevelSet)。

    b)在编译 UART_buffered  时未定义、UARTConfigSetExpClk ()启用 RX/TX FIFO (通过调用 MAP_UARTEnable) 但将  UART 中断 FIFO 深度选择寄存器(UARTIFLS)的 RXIFLSEL 位域保留为默认值、这意味着只有在 RX FIFO 大于等于1/2满时(即在接收到8个字符后)才会产生接收中断。

    [引用 user="Sahil]但是我遇到了两个奇怪的问题,例如:

    1. 直到我发送第8个字符、它才会捕获任何中断。 当它接收到第8个字符时、它为中断处理程序 ISR 提供服务并成功返回
    2. 它只为中断提供一次服务、无论我发送多少宪章、它都不会再次中断。

    [/引述]我认为第一个问题是在上面的 b)中解释的。 在这种情况下,请尝试在调用 UARTConfigSetExpClk()之前向主函数中添加以下内容:

    //
    //将 UART 设置为在 TX FIFO 几乎为空或时中断
    //接收到任何字符时。
    //
    MAP_UARTFIFOLevelSet (g_ui32Base、UART_FIFO_TX1_8、UART_FIFO_RX1_8); 

    我认为第二个问题是因为 UART0ISR()中断处理程序不会读取任何接收字符。  UARTIFLS 寄存器的数据表说明包含:

    [引用]中断是根据电平转换而不是基于电平生成的。 也就是说、当填充级别通过触发级别时、会生成中断。 例如、如果接收触发级别设置为半向标志、则在模块接收到第9个字符时触发中断。[/QUERT]因此、如果从接收 FIFO 中未读取任何接收字符、则不会认为接收中断会被重新引发。

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

    [引用用户="Chester Gillon"]

    中断是根据电平转换而不是基于电平生成的。 也就是说、当填充级别通过触发级别时、会生成中断。 例如、如果接收触发级别被设定为半向标志、中断在模块接收到第9个字符时被触发。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!

    刚才通过在 UARTStdioConfig()之前添加一行来尝试您提到的内容,如下所示;
    发生的情况是、它在我发送两个字符后调用处理程序、并且不再调用任何其他字符。

    SysCtlPeripheralEnable (SYSCTL_Periph_UART0);

    GPIOPinConfigure (GPIO_PA0_U0RX);
    GPIOPinConfigure (GPIO_PA1_U0TX);
    GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);

    //UARTConfigSetExpClk (UART0_BASE、OUTPUT_CLOCK_RATE、115200、(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
    UARTEnable (UART0_BASE);

    UARTIntEnable (UART0_BASE、UART_INT_RX);//仅启用 RX 中断
    //IntRegister (INT_UART0、UART0ISR);

    IntEnable (INT_UART0);//启用 UART 中断
    IntMasterEnable();//启用处理器中断

    MAP_UARTFIFOLevelSet (UART0_BASE、UART_FIFO_TX1_8、UART_FIFO_RX1_8);

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

    [引用 user="Sahil)]发生的情况是,在我发送两个字符后,它会调用处理程序,而不再再调用。 如前所述、处理程序是否从 UART 读取任何接收字符?

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

    您好!

    处理程序会清除中断标志、但不会读取缓冲区本身。

    您认为它应该读取缓冲区、即将其复制到另一个缓冲区、还是请告诉我如何完成?

    谢谢

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

    void UART0_ISR (void) { UARTprintf ("UART0_ISR 被调用!!\n\n"); //UARTCharPut (UART0_BASE、"t"); delay_clocks (20000); UARTIntClear (UART0_BASE、UART_INT_RX); }

    请说明您对缓冲区的读取意味着什么、因为我不知道它将如何清除中断、或者请分享如何完成中断。

    谢谢

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您是否已经阅读过微处理器或 TIVAWare 用户手册? 我建议至少对这两个章节的有关部分进行快速审查。

    您还可以检查 #bookshelf 标签。 我相信这里有一本关于串行通信的书。

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

    您好、Robert、

    感谢您的建议。

    我更改了处理程序、使其读取缓冲区并正常工作。

    现在、每次 发送字符时都会调用处理程序、但唯一的问题是启动时、当我复位处理器时、第一次必须发送两个字符才能调用处理程序。

    空 UART0ISR (空)
    {
    
    UARTCharGetNonBlocking (UART0_BASE);
    UARTIntClear (UART0_BASE、UART_INT_RX);
    UARTprintf ("UART0ISR 被调用!!\n\n");
    delay_clocks (900000);
    
    //UARTsendString ("UART0ISR 已调用!!\n\n");
    } 

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

    因此我尝试查看哪个字符触发了处理程序、结果发现处理程序在前一个字符上被调用。  

    代码是:

    空 UART0ISR (空)
    {
    
    UARTprintf ("\n%c\n"、UARTCharGetNonBlocking (UART0_BASE));
    UARTIntClear (UART0_BASE、UART_INT_RX);
    UARTprintf ("UART0ISR 被调用!!\n\n");
    delay_clocks (900000);
    
    //UARTsendString ("UART0ISR 已调用!!\n\n");
    } 

    例如、如果我按"A"、然后按"b"、再按"c"  

    按下"b"时、处理程序(上面)将打印前一个字符"A"、按下"c"、打印前一个字符"b"、依此类推...

     

    请记住、我在初始化时读取缓冲区、以便删除是否存在任何字符等 如下所示;

    UARTEnable (UART0_BASE);
    
    UARTIntEnable (UART0_BASE、UART_INT_RX);//仅启用 RX 中断
    内部寄存器(INT_UART0、UART0ISR);
    
    IntEnable (INT_UART0);//启用 UART 中断
    IntMasterEnable();//启用处理器中断
    
    MAP_UARTFIFOLevelSet (UART0_BASE、UART_FIFO_TX1_8、UART_FIFO_RX1_8);
    
    UARTStdioConfig (0、115200、system_clock);
    DELAY_Cocks (2);
    UARTCharGetNonBlocking (UART0_BASE); 

    看起来它确认缓冲区是流动的,并且仅在下次调用时才为 ISR 提供服务??

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

    [引用用户="Sahil"]

    因此我尝试查看哪个字符触发了处理程序、结果发现处理程序在前一个字符上被调用。  

    代码是:

    空 UART0ISR (空)
    {
    
    UARTprintf ("\n%c\n"、UARTCharGetNonBlocking (UART0_BASE));
    UARTIntClear (UART0_BASE、UART_INT_RX);
    UARTprintf ("UART0ISR 被调用!!\n\n");
    delay_clocks (900000);
    
    //UARTsendString ("UART0ISR 已调用!!\n\n");
    } 

    例如、如果我按"A"、然后按"b"、再按"c"  

    按下"b"时、处理程序(上面)将打印前一个字符"A"、按下"c"、打印前一个字符"b"、依此类推...

    [/报价]

    您正在误解您看到的内容。

     当超过 FIFO 阈值时、中断发生。 在您的情况下、当 b 被按下时。  此时、FIFO 中有两个要读取的字符(您应该在 FIFO 为空时读取)。

    您可能也不会同时监控两个接收中断。 您正在响应 FIFO 中断。 此外、您应该打开接收超时中断(我认为是 RTI)。 当 FIFO 中接收到一个字符、但 FIFO 未填充超过阈值、并且在一段时间内未接收到任何其他字符时、这将提供一个中断。 应以完全相同的方式处理两个源:读取 FIFO、直到其为空。

    Robert

    最后要注意的一点是、ISR 中的这些打印和延迟是一个非常糟糕的主意。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    同意您的最终注释、延迟和打印仅在代码开发时才有效... 稍后、我希望仅使用处理程序捕获接收到的字节并将其存储在我自己定义的字符串数组缓冲区中、以便进一步操作。 但是、我只能在使代码工作后执行此操作。

    我在接收一个字节时不能获得中断。 我宁愿避免这种超时的想法,除非这是使它发挥作用的唯一方法?

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

    您好、Robert、

    UARTIntEnable (UART0_BASE、UART_INT_RX | UART_INT_RT);//仅启用 RX FIFO 和 RX 超时中断 

    已按照您的建议添加上述修改。 现在工作正常。 您也可以忽略先前的愚蠢问题:P

    感谢你的帮助。

    感谢大家的参与和帮助。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    上一个问题并不愚蠢、只是缺少了关于 FIFO 的一点。 如果您禁用 FIFO、则没有缓冲、并且每个接收到的字符都会生成一个中断。

    添加 FIFO 的原因有两个方面、一个是减少中断数量(以及相关的开销)、另一个是如果不响应中断、则增加字符溢出之前的 CPU 时间。

    Robert
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    是的、这是一项非常有用的功能、因此可以通过这种方式降低 CPU 中断频率。 我可能会在稍后实施以利用它。
    谢谢、祝您一年愉快...
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    可以注意到、"2:49今天"的"Robert 的帖子""解决了您的问题"的帖子?

    他的写稿-现在引述:"您可能也不会同时监控接收中断、"这显然 让您成功了!    唉,罗伯特的指导文章“没有奖” ,而你的文章— —只是遵循罗伯特的指示——是一个获奖的文章,“这个帖子已经解决了。”   (它显然-没有-它充其量是"衍生品...")

    您可以很容易地将(正确的)"此帖子已解决"授予 Robert 的帖子-如本文所述。   (您的"自我奖励"将保留-一旦"授予"-这些"奖励"不能被否定...)