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.

[参考译文] TM4C1292NCPDT:在 UART1的 ISR 上接收数据时出现问题

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1130188/tm4c1292ncpdt-problems-with-receiving-data-on-the-isr-of-uart1

器件型号:TM4C1292NCPDT
您好! 从 UART1接收 ISR 数据时遇到问题。 我从主程序的 main 发送一个响应 
外部器件的请求。 设备在500毫秒内回复我、到达的数据是
由 ISR 接收、但由于来自外部器件的响应字符串已定义、因此数据到达顺序不一致
结构。 如果可能我配置了错误的中断、您能指导我吗?

int main(void)
{
   //configurar el reloj del microcontrolador
    g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN |SYSCTL_USE_PLL |SYSCTL_CFG_VCO_240), 120000000);//120 MHz

    INIT_UART();
    CONFIG_UART();



    while(1)
   {
        SysCtlDelay(10000);
        sendStringUART1(S_P1);//?V913
        SysCtlDelay(19000000);//569ms
        GUARDA_ARREGLO();
     //   SysCtlDelay(22000000);//659ms
     //   sendStringUART1(S_P2);//?V914
      //  SysCtlDelay(22000000);//659ms
      //  GUARDA_ARREGLO();
      //  SysCtlDelay(22000000);//659ms
       // cabecera(UART0_BASE,0x50);
     /* SysCtlDelay(50000);
        sendStringUART1(S_P2);//?V914
        SysCtlDelay(500);
        GUARDA_ARREGLO();
        SysCtlDelay(500);
        cabecera(UART0_BASE,0x50); */
   }
}


void ISR_UART1(void)
{
  ui32Status = UARTIntStatus(UART1_BASE,true);
   UARTIntClear(UART1_BASE, ui32Status);        //limpia las banderas de interrupción?

   if (UARTCharsAvail(UART1_BASE))
     {
       char rxData = UARTCharGetNonBlocking(UART1_BASE); //recibe el dato UART entrante
           if(i_rx < 26) //si el contador es menor a 26
             {
               BUFFER_UART[i_rx]=rxData;// Guarda el dato recibido en un arreglo
               i_rx++;  //aumenta el contador en uno
             }
           impedimenta=1; //breakpoint
      }//cierra if(charsAvail)
   lumos=1; //breakpoint
}

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

    Mayra、您好!

    在我假设它是全局变量时、I_Rx 是否声明为易失性变量? 否则、它可能无法准确存储您的计数器点、这可能导致数据被覆盖。

    如果计数器被声明为易失性、 那么我想了解数组实际上是如何从错误数据与实际正确数据之间的关系来看待的。 这可能会为可能发生的情况提供一些线索。

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好! 非常感谢您的回答。
    
    我的变量声明为"int"、如下所示:"int i_rx=0"。
    
    要查看数据、请使用"Expressions"窗口。 正确的数据帧 
    从外部器件开始、标头"=V913"、然后跟随压力数据
    和最终数据。 我想将"="符号存储在 buffer_UART 阵列的位置0、
    阵列位置1处的"V"字符、依此类推、如"示例1"和所示
    "示例1_2"图像、但在我的案例中、数据会按图像"示例2"和"示例3"中的那样保存在混乱状态中。 我希望我已经正确地解释了自己,我再次表示感谢。 梅拉
     example 1
    示例1.



    示例1_2




    示例2.




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

    您好、Marya、

    好的、所以它不是易失性的。 这可能是您的问题、就好像您没有将全局变量声明为易失性变量、那么它在 ISR 中的修改可能不会持续。

    请将 INDEX 变量的声明更改为:

    volatile int i_rx=0

    查看是否解决了该问题。

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!
    感谢您的建议、我已经尝试将变量声明为易失性、但它不起作用、 
    数据仍然混乱(图像“示例4”):( Mayra


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

    Mayra、您好!

    嗯。 因此、数据以"=913"开头、然后数据后跟。 您提到发送了"最终数据"。 是否有结束字符来指定发送的数据已完成?

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!
    
    是的、响应字符串的最后一个字符是回车符。
    
    梅拉 
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Mayra、

    好的、我认为要使数据按正确的顺序排序、需要做的是在 UART ISR 中添加一些更智能的内容、以便它查找起始字符和结束字符。

    我对以下代码所做的操作将添加到布尔标志中、以跟踪您是否应该接收传感器数据。

    如果标志为 false 并且 UART 接收到一个'='字符、则标志变为 true、索引复位为0、字符存储在数组中。 如果该标志为 false 并且接收到任何其他字符、则不会对其执行任何操作、而会有效地将其丢弃。

    如果标志为 true、UART 返回除回车符以外的任何字符、则会将其存储在缓冲区中并递增计数。 当收到回车字符时、标志设置为 false、因此回车后接收的下一个字符现在需要为'='才能覆盖阵列数据。

    这应允许阵列按您的需要运行。

    现在、由于26个字符的限制已被删除、我不确定您需要多少数据、 因此、您可能需要延长阵列以确保仅接收26个字节、否则、如果没有保留足够的阵列空间并且阵列存储溢出、则程序可能会由于堆栈溢出而崩溃。


    volatile int i_rx=0;
    volatile bool flag_rx=false;
    
    void ISR_UART1(void)
    {
        ui32Status = UARTIntStatus(UART1_BASE,true);
        UARTIntClear(UART1_BASE, ui32Status);        //limpia las banderas de interrupción?
    
        if (UARTCharsAvail(UART1_BASE))
        {
            char rxData = UARTCharGetNonBlocking(UART1_BASE); //recibe el dato UART entrante
            
            if (flag_rx)
            {
                if (rxData == 0x0D)
                {
                    flag_rx = false;
                }
                BUFFER_UART[i_rx]=rxData;// Guarda el dato recibido en un arreglo
                i_rx++;  //aumenta el contador en uno
            }
            else
            {
                if (rxData == '=')
                {
                    flag_rx = true;
                    i_rx = 0;
                    BUFFER_UART[i_rx]=rxData;// Guarda el dato recibido en un arreglo
                }
            }
            impedimenta=1; //breakpoint
        }//cierra if(charsAvail)
        lumos=1; //breakpoint
    }

    最后需要注意的一点是、如果程序无法识别 bool 声明、则可能需要添加以下行。

    #include <stdbool.h>

    请告诉我这是如何为您工作的。

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    你好!
    我已经尝试了建议的代码、添加了布尔值的库、 
    为 buffer_UART 数组声明了27个空格、因为这是的长度
    来自外部器件的响应字符串、现在是标头中的"V"字符
    位于阵列的位置0 (示例5)、回车存储在阵列的位置25中、
    除了"I_Rx"计数器的值保持为19 (示例6)。


    示例5



    示例6.

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

    您好、Mayra、

    啊、这是我自己无法轻松测试代码的问题、哈哈。

    初始数据存储后、I_Rx 计数器不会递增、因此当接收到下一个字符时、计数器的值为0。

    至少容易修复:

                if (rxData == '=')
                {
                    flag_rx = true;
                    i_rx = 0;
                    BUFFER_UART[i_rx]=rxData;// Guarda el dato recibido en un arreglo
                    i_rx++;  //aumenta el contador en uno
                }

    其余数据现在是否正确传入?

    顺便说一下、如果您想让代码更干净一点、您可以在获取如下数据的同时递增索引:

    BUFFER_UART[i_rx++]=rxData;// Guarda el dato recibido en un arreglo

    这相当于:

    BUFFER_UART[i_rx]=rxData;// Guarda el dato recibido en un arreglo
    i_rx++;  //aumenta el contador en uno

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    你好!
    我修改了代码、它保存了一次完整数据、"I_Rx"计数器的值从0到20不等、 
    当在需要来自外部器件响应的所有数据的函数中进行调试时
    如果条件允许对其进行处理、则传入的数据必须为"I_Rx=26"
    (我放置此项是为了确保输入的响应字符串的26个字符)、buffer_UART 具有
    数据从位置0存储到位置19、然后从此处切断(示例8)



    即使 buffer_UART 保存了所有数据、它也不会进入我需要的条件、因为 
    计数器"I_Rx"的值保持为20:(
    
    
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Mayra、您好!

    我看到 您在 Guarda_arreglo 函数中再次清除索引。 您是否已停止 UART 通信并且此时无法接收到数据?

    如果在  Guarda_arreglo 执行期间从传感器接收到任何 UART 数据 、则可以在传输过程中重置索引位置、这会 损坏数据并阻止索引达到值26。

    我不会将该索引用作标记、而是添加一个全局标志、指示数据已满并使用该全局标志、以便您可以避免对索引进行任何操作。 这也避免了索引比处理数据更快重置的情况。

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    你好!
    
    当我在主程序中发送响应请求时、外部器件仅回答我的问题、 
    我通过"sendStringUART1"函数发送响应请求、并等待514毫秒
    在处理 Guarda_arreglo 函数中的数据之前应答我的外部设备。
    我将尝试全局标志建议:)
    
    
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Mayra、您好!

    我会谨慎地使用这样的拖延来作出决定。 UART 传输速度不快、您可能无法准确预测所需的时间、除非您使用示波器来确定数据包之间的时间、然后在此基础上增加一些保护时间。 通常、建议使用更具确定性的方法、例如监控终止字符和相应地设置标志、以实现更可靠的操作。

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!
    
    非常感谢您的建议、如果不是太多问题、 
    您能否详细解释一下如何避免 ISR 堆栈溢出?

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

    您好、Mayra、

    遗憾的是、我有太多的支持请求需要在我的结尾编写一份摘要、但本文是一个很好的起点: https://www.microcontrollertips.com/faq-avoiding-stack-overflow-embedded-processors/

    它侧重于一些其他方面、但溢出和破坏程序的另一种方法是在栈末尾附近或靠近关键变量的位置设置缓冲区、例如20字节、 但是、软件会尝试写入24个字节、因此处理器会转到下一个存储器位置、并破坏它们、从而"溢出"缓冲器/堆栈、从而使程序崩溃。

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    你好!
    
    非常感谢您为我的代码提供的建议、现在数据已按顺序到达、 
    但链到达时被切断、幸运的是、我需要的数据属于的一部分
    缓冲区 UART 中存储的链、我感觉它是由堆栈溢出引起的。 非常感谢您的这篇文章、我将阅读它。 梅拉。
    
    
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Myra、

    最好检查 ui32RxIntStatus 是否存在 RX 错误并处理溢出、奇偶校验、帧等错误。 例如、如果波特率在两端的时钟频率几乎不相同、则可能会发生意外错误。 这往往表明两端的波特率设置得越高、RS232的电缆长度限制为150英尺、RS423的电缆长度限制为1000英尺。

    当发生 RX 错误时、清空缓冲区、无论如何数据都不好。

       
           uint32_t ui32RxErrorStatus;
           
        /* Load the RX error status bits */
        ui32RxErrorStatus = (UART_RXERROR_FRAMING|UART_RXERROR_PARITY
        						|UART_RXERROR_BREAK|UART_RXERROR_OVERRUN);
        						
            /* Durring interrupt check the RSR/ECR register for
             * RX errors: OE, BE, PE, FE  */
            if(ui32RxErrorStatus &= MAP_UARTRxErrorGet(UART3_BASE))
            {
                /* Clear all ECR error bits and return */
                MAP_UARTRxErrorClear(UART3_BASE);
                //
    #if DEBUG
                /* Print the error event message */
                UARTprintf("\n RxError: %x\n\n", ui32RxErrorStatus);
    #endif
            	/* Flush the RX buffer */
                for(i=0; i <= 32; i++)
                {
                	CcRxBuff[i] = 0;
                }
                //
    #if DEBUG
                UARTprintf("\n>> RxBuffFlush: \n");
    #endif
                //
                return;
            }    						

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

    BTW:即使是使用 bool 标志、也会在中出现更大的问题、用于使索引++循环读取16字 FIFO、超过16字。 当在 FIFO 中接收到16个字后 READY 位未被置位时、循环需要检查 FE 位的状态或者溢出错误将发生。 只需检查条件并暂停一段周期、UART 逻辑就可以捕捉到大于16的 RX 字的缓冲。 TM4C 150DMIPS CPU 读取 C 代码的速度似乎快于 UART 硬件处理的速度。   

    			/* Check RX FIFO is empty or timeout Interrupt.
    			 * The RX timeout interrupt is asserted when
    			 * the RX FIFO is not empty, and no further data
    			 * is received over a 32-bit period when the HSE bit is
    			 * clear or over a 64-bit period when the HSE bit is set.
    			 * Note:The receive timeout interrupt is cleared
    			 * either when the FIFO becomes empty through reading
    			 * all the data (or by reading the holding register) */
    			if(i >= 15 || (HWREG(UART3_BASE + UART_O_FR) & UART_FR_RXFE))
    			{
    				/* Pause here to wait for FIFO loading */
    				/* System clock 8.33ns, 1000=1.0ms, 1200=833us delay */
    				SysCtlDelay(SYSTEM_CLOCK / 1200);
    			}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!
    非常感谢您的建议、我将测试奇偶校验和帧错误、 
    我还将尝试提供中断时间、以便正确读取数据。
    抱歉、是否可以将提供的代码添加到我的代码中而不会出现问题? 梅拉。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="475151" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum 1130188/tm4c1292ncpdt-problems-with -receiving-data-on-the -isr of -uart1/4199041#4199041"]是否可以将提供的代码毫无问题地添加到我的代码中?

    您需要更改 UART#并使用 Buffer[]名称。 在 RX 中断的顶部添加代码 snip、请参阅(return)语句? 每当 RX 错误清除时、缓冲器就会退出中断。 for 循环 FE 位延迟假定 SYSCLK 为120MHz、并将等待用下一个字恢复填充缓冲区。 FIFO 深度是缓冲器满之前的字计数循环 INT 指针。 您可以使用3x 0xFF Ralph 来填充 TX 数据蒸汽的末尾、并在 RX 中断循环中检查3x 0xFF、以将缓冲区字计数重置回16。  

     我的缓冲区在32个字深时总是被清除。 您可能需要修改 FE 位延迟检查>32个字。 添加一个静态 INT 变量 count 16、然后使 variable ++递增、并在 RX 传输结束时重置回16个字深。 您可以使用该方法填充非常大的缓冲区。 当 RX 传输结束时、针对3x 0xFF 的 RX 中断环路测试将字计数重置回16。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    非常感谢您的建议、 
    我会尝试它们! :) 梅拉