如何控制中断驱动的UART传输PIC24H?

如何控制中断驱动的UART传输PIC24H?,c,embedded,microcontroller,interrupt,C,Embedded,Microcontroller,Interrupt,我正在通过460Kbaud UART将数据从PIC24H微控制器传输到蓝牙无线电模块。在大多数情况下,此流量工作正常,蓝牙模块在其内部数据缓冲区已满时使用CTS和RTS线路来管理流量控制。但是,蓝牙模块中存在某种缺陷,当数据连续无中断地发送到蓝牙模块时会重置蓝牙模块,如果我的数据在另一个瓶颈中备份,就会发生这种情况 如果模块工作正常就好了,但这超出了我的控制范围。因此,我唯一的选择似乎是在我的终端上进行一些数据节流,以确保我不会超过数据吞吐量限制(我通过实验大致知道) 我的问题是如何实现数据速率

我正在通过460Kbaud UART将数据从PIC24H微控制器传输到蓝牙无线电模块。在大多数情况下,此流量工作正常,蓝牙模块在其内部数据缓冲区已满时使用CTS和RTS线路来管理流量控制。但是,蓝牙模块中存在某种缺陷,当数据连续无中断地发送到蓝牙模块时会重置蓝牙模块,如果我的数据在另一个瓶颈中备份,就会发生这种情况

如果模块工作正常就好了,但这超出了我的控制范围。因此,我唯一的选择似乎是在我的终端上进行一些数据节流,以确保我不会超过数据吞吐量限制(我通过实验大致知道)

我的问题是如何实现数据速率限制?

我当前的UART实现是一个RAM循环FIFO缓冲区,长度为1024字节,主循环将数据写入其中。当UART硬件发出最后一个字节,并且我的ISR从缓冲区读取下一个字节并将其发送到UART硬件时,PIC触发外围中断

下面是源代码的一个想法:

uart_isr.c

//*************** Interrupt Service routine for UART2 Transmission  
void __attribute__ ((interrupt,no_auto_psv)) _U2TXInterrupt(void)
{       
//the UART2 Tx Buffer is empty (!UART_TX_BUF_FULL()), fill it
//Only if data exists in data buffer (!isTxBufEmpty())
while(!isTxBufEmpty()&& !UART_TX_BUF_FULL())    {
    if(BT_CONNECTED)
    {   //Transmit next byte of data
        U2TXREG = 0xFF & (unsigned int)txbuf[txReadPtr];
        txReadPtr = (txReadPtr + 1) % TX_BUFFER_SIZE;
    }else{
        break;
    }
}
IFS1bits.U2TXIF = 0;
}
uart_方法.c

//return false if buffer overrun
BOOL writeStrUART(WORD length, BYTE* writePtr)
{
    BOOL overrun = TRUE;
    while(length)
    {
        txbuf[txWritePtr] = *(writePtr);
        //increment writePtr
        txWritePtr = (txWritePtr + 1) % TX_BUFFER_SIZE;
        if(txWritePtr == txReadPtr)
        {
            //write pointer has caught up to read, increment read ptr
            txReadPtr = (txReadPtr + 1) % TX_BUFFER_SIZE;
            //Set overrun flag to FALSE
            overrun = FALSE;
        }

        writePtr++;
        length--;
    }

    //Make sure that Data is being transmitted
    ensureTxCycleStarted();

    return overrun;
}


void ensureTxCycleStarted()
{
    WORD oldPtr = 0;
    if(IS_UART_TX_IDLE() && !isTxBufEmpty())
    {
        //write one byte to start UART transmit cycle
        oldPtr = txReadPtr;
        txReadPtr = (txReadPtr + 1) % TX_BUFFER_SIZE;//Preincrement pointer
        //Note: if pointer is incremented after U2TXREG write,
        //      the interrupt will trigger before the increment
        //      and the first piece of data will be retransmitted.
        U2TXREG = 0xFF & (unsigned int)txbuf[oldPtr];
    }
}
编辑
在我看来,有两种方法可以实现节流:

  • 在要写入的UART字节之间强制执行一个时间延迟,从而对数据吞吐量设置一个上限

  • 保持在特定时间段内传输的字节的运行计数,如果超过该时间段的最大字节数,则在继续传输之前创建稍长的延迟


  • 这两种方法在理论上都是可行的,这就是我想知道的实现。

    如果你有一个空闲计时器,或者如果你可以使用现有的计时器,你可以对发送的字节进行某种“去抖动”

    假设你有一个全局变量,
    byte\u interval
    ,你有一个定时器每微秒溢出一次(并触发ISR)。然后它可能看起来像这样:

    timer_usec_isr() {
        // other stuff
        if (byte_interval)
            byte_interval--;
    }
    
    然后在“putchar”函数中,可以有如下内容:

    uart_send_byte(unsigned char b) {
        if (!byte_interval) { // this could be a while too, 
                              // depends on how you want to structure the code
            //code to send the byte
            byte_interval = AMOUNT_OF_USECS;
        }
    
    }
    
    很抱歉,我没有仔细研究你的代码,所以我可以更具体一些。
    这只是一个想法,我不知道是否适合你

    首先,常用的串行流控制有两种类型

    • (“硬件流控制”)
    • (“软件流控制”)
    您说CTS是打开的,但您可能想看看是否可以以某种方式启用XON/XOFF


    如果可以配置,另一种方法就是使用较低的波特率。这显然取决于您可以在链路的另一端配置什么,但当设备无法处理更高速度的传输时,这通常是解决问题的最简单方法。

    也许配额方法正是您想要的。 使用相关时间刻度的周期性中断,将“要传输的字节”配额添加到全局变量,使其不超过针对相关洪水调整的某个级别。 然后在发送字节之前检查是否有配额。对于新的传输,最初会出现洪水,但稍后配额将限制传输速率

    ~~some periodic interrupt
    if(bytes_to_send < MAX_LEVEL){
      bytes_to_send = bytes_to_send + BYTES_PER_PERIOD;
      }
    ~~in uart_send_byte
    if(bytes_to_send){
      bytes_to_send = bytes_to_send - 1;
      //then send the byte
    
    ~~一些周期性的中断
    if(字节到发送<最大级别){
    字节发送=字节发送+每个周期字节发送;
    }
    ~~在uart\u发送\u字节中
    如果(字节到发送){
    字节发送=字节发送-1;
    //然后发送字节
    
    在特定时间增加发送延迟的计时器方法:

    • 以适当的周期速率配置自由运行计时器
    • 在计时器ISR中,在全局状态变量(delayBit)中切换一位
    • 在UART ISR中,如果delayBit为高而delayPostedBit为低,则在不清除TX中断标志的情况下退出TX ISR,并在全局状态变量(delayPostedBit)中设置一位。如果delayBit较低,则清除delayPostedBit。结果是导致延迟等于一个ISR计划延迟,因为将再次输入ISR。这不是忙等待延迟,因此不会影响系统其余部分的计时
    • 调整计时器的周期,以适当的间隔增加延迟

    描述什么样的“中断”该模块需要工作…@Ben Jackson如果我知道就好了。这是一个bug,不是一个功能,所以没有文档记录。基本上,它会在大约3秒的恒定吞吐量后重置,即使它是流量控制的。我平均可以获得约25kbps的吞吐量。我不想在每个字节之间设置延迟,因为这需要e频繁重新启动tx循环。是否有办法调整此方法以检测x数量(太多)时字节已在上一个y usecs中传输,并触发计时器延迟?这将更好地适合我的代码结构。即使在没有实际字符的情况下,您是否可以让UART设置txdone?如果可以,则如果它不传输实际数据,则应发送停止位。然后,您可以每1024个(例如)取消2或3个TXINT在这2或3个字符的时间过去后,我将再次读取字符。如果你能使用它,我将首先尝试。@Pete Wilson我无法在不启动传输循环的情况下设置txdone,该传输循环将输出空白数据。我必须执行计时器延迟或其他操作来触发中断。@CodeFusionMobile--好的,那么当你进入dr时带传输请求的iver(在主流级别,对吗?)我会计算输入的字符数,如果超过1024,则启动一个短超时,如1或2毫秒,这将以您看到的比特率为您提供大量字符时间。当超时触发时:(1)如果处于中断级别,则启动UART,就像您从txdone输入一样;(2)如果在主流级别,请在清除chars sent计数器后重新发出传输。这对您合理吗?让我知道。我喜欢UART/USART的东西:它就像我的家一样:-)硬件流量控制已启用,由蓝牙模块驱动。我尝试过实现较低的波特率设置