一、问题背景
单片机 重定向c库函数printf到串口 方便了很多调试工作! 但今天要用到一个重定向c库函数scanf到串口,于是就用了下面函数。开始用的也挺好!但遇到特殊场合就很难用,还有各种问题!发现百度也说了scanf 函数 的一些问题! 折腾了很久决定放弃!自己编写接收函数!
scanf 问题:scanf函数 点击链接…
/**
*******************************************************************************
* @brief 重定向c库函数scanf到串口
* @param
* @return
* @note
*******************************************************************************
*/
int fgetc(FILE *stream)
{
while( !(UART8->ISR & (1 << 5)) ); //等待数据接收完成
return UART8->RDR;
}
二、问题发现 清 溢出错误标志 错误方式
自己编写的串口接收函数 发现 死在里面出不去,发现是 检测到溢出错误标志 无法清除!
UART8->ISR &= ~(1<<3) //清ORE位. 实际无法清除
三、问题解决方法清 溢出错误标志 正确方式
UART8->ICR |= 1<<3; //清除溢出错误,否则可能会卡死. 向此位写入“1”时, ISR 寄存器中的 ORE 标志将清零.
四、解决问题后的代码实例串口 接收函数 替代 scanf函数
方法一:
/**
*******************************************************************************
* @brief 串口扫描接收 函数
* @param [in] char *pdata - 字符串 缓存 地址
* @param [in] u32 maxSize - 允许接收的最大字节数
* @return 实际接收的字节数
* @note 0x0D0A 结束符
*******************************************************************************
*/
u32 UartScanRx(char *pdata, u32 maxSize)
{
u8 rxOK;
u8 rxData;
u32 rxCnt = 0;
do
{
rxOK = 0;
if(rxCnt >= maxSize) rxCnt = 0; //超出最大接收缓存
if(UART8->ISR & (1<<3)) rxCnt = 0; //ORE==1,上溢错误
if( UART8->ISR & (1 << 5) ) //RXNE==1,读取数据寄存器不为空。表示接收到数据
{
rxData = UART8->RDR; //读取DR,同时也清了ISR中的标志。
pdata[rxCnt++] = rxData; //接收到的字符存起来
if(rxData == 0x0A) //0x0D0A 结束符判断
{
if(rxCnt >= 2)
{
if(pdata[rxCnt-2] == 0x0D) rxOK = 1;
}
}
}
UART8->ICR|=1<<3; //清除溢出错误,否则可能会卡死. 向此位写入“1”时, ISR 寄存器中的 ORE 标志将清零.
}while( !rxOK );
return rxCnt-2;
}
方法二: 比 方法一 更灵活, 接收 结束标志 自由定义
/**
*******************************************************************************
* @brief 串口扫描接收 函数
* @param [in] u16 endFlg - 接收结束标志(注意大小端,低字节先收,高字节在后收到)
* @param [in] char *pdata - 字符串 缓存 地址
* @param [in] u32 maxSize - 允许接收的最大字节数
* @return 实际接收的字节数
* @note
*******************************************************************************
*/
u32 UartScanRx(u16 endFlg, char *pdata, u32 maxSize)
{
u8 rxEnd = 0;
u32 rxCnt = 0;
do
{
if(rxCnt >= maxSize) rxCnt = 0; //超出最大接收缓存
if(UART8->ISR & (1<<3)) rxCnt = 0; //ORE==1,上溢错误
if(UART8->ISR & (1<<5)) //RXNE==1,读取数据寄存器不为空。表示接收到数据
{
u8 rxData = UART8->RDR; //读取DR,同时也清了ISR中的标志。
pdata[rxCnt++] = rxData; //接收到的字符存起来
if(rxCnt >= 2)
{
if(*(u16 *)&pdata[rxCnt-2] == endFlg) rxEnd = 1; //结束判断
}
}
UART8->ICR |= 1<<3; //清除溢出错误,否则可能会卡死. 向此位写入“1”时, ISR 寄存器中的 ORE 标志将清零.
}while(rxEnd);
return rxCnt-2;
}