Я передаю данные со своего микроконтроллера PIC24H через UART 460 Кбод на радиомодуль Bluetooth. В большинстве случаев этот поток работает нормально, и модуль Bluetooth использует линии CTS и RTS для управления потоком, когда его внутренние буферы данных заполнены. Однако в модуле bluetooth есть какая-то ошибка, которая сбрасывает его, когда данные постоянно отправляются на него без каких-либо перерывов, что происходит, если мои данные копируются в другом узком месте.
Было бы хорошо, если бы модуль работал правильно, но это вне моего контроля. Таким образом, кажется, что мой единственный вариант - выполнить некоторое регулирование скорости передачи данных на моем конце, чтобы убедиться, что я не превышаю лимиты пропускной способности (которые я знаю примерно экспериментально).
Мой вопрос - как реализовать регулирование скорости передачи данных?
Моя текущая реализация UART представляет собой кольцевой буфер FIFO RAM длиной 1024 байта, в который основной цикл записывает данные. Периферийное прерывание запускается PIC, когда последний байт был отправлен оборудованием UART, и мой ISR считывает следующий байт из буфера и отправляет его на оборудование UART.
Вот идея исходного кода:
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_methods.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];
}
}
Edit
Я вижу два способа реализации дросселирования:
Обеспечивает временную задержку между записываемым байтом UART, которая устанавливает верхний ограничение на пропускную способность данных.
Сохраняйте текущий счет байтов, переданных за определенный период времени, и если максимальное количество байтов превышено для этого промежутка времени, создайте немного более длительную задержку перед продолжением передачи.
Теоретически будет работать любой вариант, это реализация, которая меня интересует.