在 ISR() 中使用 UART2 中继 UART1(PIC24H)

Relaying UART1 with UART2 within an ISR() (PIC24H)

我正在对 PIC24H 系列的微控制器进行编程并使用 xc16 编译器。

我在 main() 内将 U1RX 数据中继到 U2TX,但是当我在 ISR 中尝试时它不起作用。

我正在向 U1RX 发送命令,ISR() 在下方。在 U2RX,不断有数据字节进来,我想用 U1TX 中继其中的 500 个。结果是 U1TX 从 U2RX 中继前 4 个数据字节,然后一遍又一遍地重新发送第 4 个字节。

当我将下面的 for 循环复制到我的 main() 时,一切正常。在 ISR() 中,U2RX 的相应 FIFO 缓冲区在读取时未清除,因此缓冲区溢出并停止将进一步的传入数据读取到 U2RX。如果有人能告诉我如何解决这里的问题,我将不胜感激。变量 tmpcommand 是全局声明的。

void __attribute__((__interrupt__, auto_psv, shadow)) _U1RXInterrupt(void)
{
    command = U1RXREG;
    if(command=='d'){
        for(i=0;i<500;i++){
            while(U2STAbits.URXDA==0);
            tmp=U2RXREG;
            while(U1STAbits.UTXBF==1); //
            U1TXREG=tmp;
           }
    }
}

编辑:我在 ISR() 中添加了第一行。

ISR 的 必须 保持精简和平均,如果有任何希望跟上 UART 上的缓冲区,代码将变得非常高效。试验波特率只是为了找到您的代码可以跟上的点,以帮助发现正确的启发式并查看您距离实现目标还有多远。

成功还可能取决于您的微控制器的速度,以及它 运行 正在执行的任务数量。如果微控制器有一个内置的 UART,理论上你应该能够管理防止 FIFO 溢出。另一方面,如果您将 UART 与功率不足的微控制器配对,您可能无法优化解决问题的方法。

除了建议将低优先级的工作卸载到主线程并保持 ISR 快速(有人在评论中提出)之外,您还需要仔细查看所有代码行的时间和尝试书中的每一个技巧,让他们更快地 运行。一项昂贵的指导可能会毁了你一整天,所以要真正发挥创意,寻找节省时间的方法。

编辑:另一件需要考虑的事情——看看你的 C 编译器创建的汇编语言。一个好的编译器应该允许您内联汇编语言指令,以允许您针对您的特定情况进行超级优化。通常在 ISR 中,它只是您必须查找和执行的少量指令。

编辑 2:如果您正确编码,PIC 24 系列应该足够快并且 select 快速振荡器或 crystal 和 运行 芯片具有良好的时钟速率。还要考虑 UART 可能用来实现其速率与 PIC 时钟速率的除数。可以想象(对我来说)可以通过移位在内部完成的均匀除法比需要数学的更好。

试图从各种评论中得出答案。

如果 main() 无事可做,并且没有其他中断,您可以 "get away with" 在中断下将所有 500 个字符从一个 UART 修补到另一个,一旦第一个中断已经发生,也许这将是一个有用的练习来让它工作。

但这不是您使用中断的方式。如果您在 main() 中有其他任务,并且优先级相同或较低的中断,则此中断将花费相对较长的时间(9600 波特时 500 个字符 = 半秒)将使处理器成为所谓的 "interrupt-bound",也就是其他进程都被冻结了。

随着您的项目变得越来越复杂,在设置 UART 和 IRQ 之后,您不会希望将 main() 限制在这个任务上,并且根本不需要涉及它。之后,如果需要,它可以无限计算 π

我对你的操作顺序有点困惑。从 U1 收到命令 'd',它告诉您将 500 个字符从 U2 修补到 U1。

鉴于您真的想使用中断,我建议解决这个问题的一种方法(有很多)是等到从 U1 收到命令 - 在 main() 中。然后为 U2 上的 RXD 配置并启用中断。

那么 ISR 的工作就是从 U2 接收数据并通过 U1 传输数据。如果两个 UART 具有相同的时钟和相同的波特率,则不应该存在同步问题,因为 UART 通常在内部进行缓冲:一旦它开始传输,TXD 寄存器可用于保存另一个字符,因此 UART 中的任何停滞ISR 应该是最小的。

我无法为您编写实际代码,因为它应该可以工作,但这里有一些非常伪代码,而且我没有 PIC方便(或希望研究其操作细节)。

ISR
    has been invoked because U2 has a char RXD
    you *might* need to check RXD status as a required sequence to clear the interrupt
    read the RXD register, which also might clear the interrupt status
    if not, specifically clear the interrupt status
    while (U1 TXD busy);
    write char to U1
    if (chars received == 500)
        disable U2 RXD interrupt
    return from interrupt