如何控制中断驱动的UART传输PIC24H?
我正在通过460Kbaud UART将数据从PIC24H微控制器传输到蓝牙无线电模块。在大多数情况下,此流量工作正常,蓝牙模块在其内部数据缓冲区已满时使用CTS和RTS线路来管理流量控制。但是,蓝牙模块中存在某种缺陷,当数据连续无中断地发送到蓝牙模块时会重置蓝牙模块,如果我的数据在另一个瓶颈中备份,就会发生这种情况 如果模块工作正常就好了,但这超出了我的控制范围。因此,我唯一的选择似乎是在我的终端上进行一些数据节流,以确保我不会超过数据吞吐量限制(我通过实验大致知道) 我的问题是如何实现数据速率限制? 我当前的UART实现是一个RAM循环FIFO缓冲区,长度为1024字节,主循环将数据写入其中。当UART硬件发出最后一个字节,并且我的ISR从缓冲区读取下一个字节并将其发送到UART硬件时,PIC触发外围中断 下面是源代码的一个想法: uart_isr.c如何控制中断驱动的UART传输PIC24H?,c,embedded,microcontroller,interrupt,C,Embedded,Microcontroller,Interrupt,我正在通过460Kbaud UART将数据从PIC24H微控制器传输到蓝牙无线电模块。在大多数情况下,此流量工作正常,蓝牙模块在其内部数据缓冲区已满时使用CTS和RTS线路来管理流量控制。但是,蓝牙模块中存在某种缺陷,当数据连续无中断地发送到蓝牙模块时会重置蓝牙模块,如果我的数据在另一个瓶颈中备份,就会发生这种情况 如果模块工作正常就好了,但这超出了我的控制范围。因此,我唯一的选择似乎是在我的终端上进行一些数据节流,以确保我不会超过数据吞吐量限制(我通过实验大致知道) 我的问题是如何实现数据速率
//*************** 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];
}
}
编辑在我看来,有两种方法可以实现节流:
这两种方法在理论上都是可行的,这就是我想知道的实现。如果你有一个空闲计时器,或者如果你可以使用现有的计时器,你可以对发送的字节进行某种“去抖动” 假设你有一个全局变量,
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;
}
}
很抱歉,我没有仔细研究你的代码,所以我可以更具体一些。
这只是一个想法,我不知道是否适合你 首先,常用的串行流控制有两种类型
- (“硬件流控制”)
- (“软件流控制”)
如果可以配置,另一种方法就是使用较低的波特率。这显然取决于您可以在链路的另一端配置什么,但当设备无法处理更高速度的传输时,这通常是解决问题的最简单方法。也许配额方法正是您想要的。 使用相关时间刻度的周期性中断,将“要传输的字节”配额添加到全局变量,使其不超过针对相关洪水调整的某个级别。 然后在发送字节之前检查是否有配额。对于新的传输,最初会出现洪水,但稍后配额将限制传输速率
~~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。这不是忙等待延迟,因此不会影响系统其余部分的计时
- 调整计时器的周期,以适当的间隔增加延迟