我有一个GSM模块通过硬件UART与我的微控制器通信。
当我收到少量数据时,一切正常。当我尝试获取存储在SIM卡中的所有SMS消息的列表时,出现UART缓冲区溢出错误。
我有一个动态字符串函数,它将每个接收到的字符追加到使用malloc的缓冲区中。这就是我收到的方式。我注释掉导致问题的线。
while( uart_available() > 0 )
{
/*
* There are characters in the buffer so
* keep receiving until buffer in empty.
*/
unsigned int c = uart_getc();
if ( c & UART_NO_DATA )
{
/*
* No data available from UART. This is not an error.
*/
error( AT, "No error but - No uart data" );// TODO: Delete it. It is not an error actually.
}
else if ( c & UART_FRAME_ERROR )
{
/* Framing Error detected, i.e no stop bit detected */
errorOccured( ER_UART_FRAME_ERROR );
error( AT, "Frame error" );
}
else if ( c & UART_OVERRUN_ERROR )
{
/*
* Overrun, a character already present in the UART UDR register was
* not read by the interrupt handler before the next character arrived,
* one or more received characters have been dropped.
*/
errorOccured( ER_UART_OVERRUN_ERROR );
error( AT, "Overrun error" );
}
else if ( c & UART_BUFFER_OVERFLOW )
{
/*
* We are not reading the receive buffer fast enough,
* one or more received characters have been dropped.
*/
errorOccured( ER_UART_BUFFER_OVERFLOW );
error( AT, "Buffer overflow error" );
}
else
{
/*
* There are data available add them to cString.
*/
appendChar( data, (const char)c );// This line is slow and causes UART overflow.
if ( *data == 0 )
{
/*
* Report bad pointer.
*/
errorOccured( ER_SIM900_BAD_POINTER );
error( AT, "Bad pointer" );
}
/*
* We received something so change the flag
* even if an error occurs in the next loop.
*/
isReceivedData = true;
}
}
我想问你们是否有关于malloc变慢的线索,或者您知道UART被UART接收中断中断是一个问题。
如何在不降低UART比特率而又不提高时钟速度的情况下解决这个问题?
更新:
调试后,我确定malloc正常工作(如果malloc失败,我会得到一个断言),所以我的下一个猜测是appendChar很慢。尽管仅阅读SMS,但我会尝试Mateo建议一次使用固定字符数组的SMS一条消息(每个SMS最多160个字符+发送者信息)
更新2-新代码
我成功了,但是我靠运气做到了。代码中有一行我无法理解为什么需要它。我有8Mhz和19200 UART比特率。我猜时间安排有问题。
这是如果我删除该功能不起作用的行:
_delay_us(150); // TODO: WEIRD KNOWN BUG!!!
这里是整个功能:
/**
* @brief Receives raw data from SIM900.
*
* @param data Get SIM900's raw data on exit.
*
* @return True if at least one character received.
*/
bool SIM900_receive( cString* data )
{
/*
* Because we append chars we need to init it.
*/
#define SIM900_MAX_RECEIVE_CHARACTERS 300
char temp[SIM900_MAX_RECEIVE_CHARACTERS+1];
strcpy_P( temp, PSTR("") );
int32_t i = 0;
/*
* There are no received data so far.
*/
bool isReceivedData = false;
/*
* Check UART buffer
*/
while( uart_available() > 0 )
{
/*
* There are characters in the buffer so
* keep receiving until buffer in empty.
*/
unsigned int c = uart_getc();
_delay_us(150); // TODO: WEIRD KNOWN BUG!!!
if ( c & UART_NO_DATA )
{
/*
* No data available from UART. This is not an error.
*/
error( AT, "No error but - No uart data" );// TODO: Delete it. It is not an error actually.
}
else if ( c & UART_FRAME_ERROR )
{
/* Framing Error detected, i.e no stop bit detected */
errorOccured( ER_UART_FRAME_ERROR );
error( AT, "Frame error" );
}
else if ( c & UART_OVERRUN_ERROR )
{
/*
* Overrun, a character already present in the UART UDR register was
* not read by the interrupt handler before the next character arrived,
* one or more received characters have been dropped.
*/
errorOccured( ER_UART_OVERRUN_ERROR );
error( AT, "Overrun error" );
}
else if ( c & UART_BUFFER_OVERFLOW )
{
/*
* We are not reading the receive buffer fast enough,
* one or more received characters have been dropped.
*/
errorOccured( ER_UART_BUFFER_OVERFLOW );
error( AT, "Buffer overflow error" );
}
else
{
/*
* There are data available add them to cString.
*/
if( i<SIM900_MAX_RECEIVE_CHARACTERS )
{
temp[i] = (char) c;
temp[i+1] = '\0';
i++;
}
/*
* We received something so change the flag
* even if an error occurs in the next loop.
*/
isReceivedData = true;
}
}
copyString( data, temp );
/*
* Exit.
*/
return isReceivedData;
}
最佳答案
阅读基于堆的动态内存分配如何工作;这太宽泛了,无法解释。请注意,它的运行时是不确定的,可能会导致堆碎片,因此一段时间后您最终将不会得到任何块。
此外,您正在打印我认为的内容。这也可能是一个问题。综上所述:不要使用运行时间(可能)比实时情况下可接受的功能长的功能(UART接收器强加了处理时间的上限。
使用足够长的缓冲区以获取最大值。数据包的大小。如果您坚持使用线性处理序列,则无论如何都要为这种情况做好准备。
更好的方法是使用中断来接收数据。这样,您可以使用两个交替的缓冲区(每个缓冲区的最大大小)并在常规代码中处理一个缓冲区,同时通过中断处理程序接收下一个缓冲区。
注意:除非您确实必须并且已经考虑了所有含义,否则请不要进行强制转换。通常,强制转换是界面设计不良的信号。
关于c - 修复UART溢出,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32649762/