原来的中断接收函数,实际使用时使能了接收中断,发送是采用租塞形式的发送方式,调试运行的时候,频繁的进入串口中断,尽管实际上没有数据接收,和发送,以至使得程序不能正常执行,在ai的帮组下,做了优化,优化的代码如下:
1. 增加了发送标志清零操作;
2. 接收中断,发送缓冲区空中断、发送传输完成中断,三者的顺序做了一个结构性的优化,3者并行,且发送传输完成中断放在发送缓冲区空中断前面;
3. 增加了溢出中断处理;
4.一次性的读出串口状态寄存器;
[C] 纯文本查看 复制代码 static void UartIRQ(UART_T *_pUart)
{
/* 处理接收中断 */
if (USART_GetITStatus(_pUart->uart, USART_IT_RXNE) != RESET)
{
/* 从串口接收数据寄存器读取数据存放到接收FIFO */
uint8_t ch;
ch = USART_ReceiveData(_pUart->uart);
_pUart->pRxBuf[_pUart->usRxWrite] = ch;
if (++_pUart->usRxWrite >= _pUart->usRxBufSize)//重新覆盖写
{
_pUart->usRxWrite = 0;
}
if (_pUart->usRxCount < _pUart->usRxBufSize)//
{
_pUart->usRxCount++;
}
/* 回调函数,通知应用程序收到新数据,一般是发送1个消息或者设置一个标记 */
//if (_pUart->usRxWrite == _pUart->usRxRead)
//if (_pUart->usRxCount == 1)
{
if (_pUart->ReciveNew)
{
// _pUart->ReciveNew(ch);//ReciveNew(ch) 会在Modbus协议里面要用到
}
}
}
/* 处理发送缓冲区空中断 */
if (USART_GetITStatus(_pUart->uart, USART_IT_TXE) != RESET)
{
//if (_pUart->usTxRead == _pUart->usTxWrite)
if (_pUart->usTxCount == 0)
{
/* 发送缓冲区的数据已取完时, 禁止发送缓冲区空中断 (注意:此时最后1个数据还未真正发送完毕)*/
USART_ITConfig(_pUart->uart, USART_IT_TXE, DISABLE);
/* 使能数据发送完毕中断 */
USART_ITConfig(_pUart->uart, USART_IT_TC, ENABLE);
}
else
{
/* 从发送FIFO取1个字节写入串口发送数据寄存器 */
USART_SendData(_pUart->uart, _pUart->pTxBuf[_pUart->usTxRead]);
if (++_pUart->usTxRead >= _pUart->usTxBufSize)
{
_pUart->usTxRead = 0;
}
_pUart->usTxCount--;
}
}
/* 数据bit位全部发送完毕的中断 */
else if (USART_GetITStatus(_pUart->uart, USART_IT_TC) != RESET)
{
//if (_pUart->usTxRead == _pUart->usTxWrite)
if (_pUart->usTxCount == 0)
{
/* 如果发送FIFO的数据全部发送完毕,禁止数据发送完毕中断 */
USART_ITConfig(_pUart->uart, USART_IT_TC, DISABLE);
/* 回调函数, 一般用来处理RS485通信,将RS485芯片设置为接收模式,避免抢占总线 */
if (_pUart->SendOver)
{
_pUart->SendOver();
}
}
else
{
/* 正常情况下,不会进入此分支 */
/* 如果发送FIFO的数据还未完毕,则从发送FIFO取1个数据写入发送数据寄存器 */
USART_SendData(_pUart->uart, _pUart->pTxBuf[_pUart->usTxRead]);
if (++_pUart->usTxRead >= _pUart->usTxBufSize)
{
_pUart->usTxRead = 0;
}
_pUart->usTxCount--;
}
}
}
优化后的代码:
[C] 纯文本查看 复制代码 void UartIRQ(UART_T *_pUart)
{
uint32_t sr = _pUart->huart->Instance->SR; // 读取一次状态寄存器
// 先检查ORE错误,并清除
/* 1. 处理ORE溢出错误 - 必须先处理 */
if(sr & USART_SR_ORE)
{
// 清除ORE标志的正确方法
volatile uint32_t tmp = _pUart->huart->Instance->SR; // 读SR
tmp = _pUart->huart->Instance->DR; // 读DR
(void)tmp;
// 重新读取SR,因为清除ORE后状态可能变化
sr = _pUart->huart->Instance->SR;
}
/* 处理接收中断 */
/* RXNE (Read Data Register Not Empty) - 接收数据寄存器非空 */
/* 2. 处理接收中断 */
if(sr & USART_SR_RXNE)
{
/* 从串口接收数据寄存器读取数据存放到接收FIFO */
uint8_t ch = (uint8_t)(_pUart->huart->Instance->DR & 0xFF);
_pUart->pRxBuf[_pUart->usRxWrite] = ch;
if (++_pUart->usRxWrite >= _pUart->usRxBufSize)//重新覆盖写
{
_pUart->usRxWrite = 0;
}
if (_pUart->usRxCount < _pUart->usRxBufSize)//
{
_pUart->usRxCount++;
}
/* 回调函数,通知应用程序收到新数据,一般是发送1个消息或者设置一个标记 */
//if (_pUart->usRxWrite == _pUart->usRxRead)
//if (_pUart->usRxCount == 1)
{
if (_pUart->ReciveNew)
{
// _pUart->ReciveNew(ch);//ReciveNew(ch) 会在Modbus协议里面要用到
}
}
}
/* 数据bit位全部发送完毕的中断 */
/* 处理传输完成中断 TC (Transmission Complete) - 传输完成标志 */
/* 3. 处理TC传输完成中断 - 必须放在TXE前面处理
在同时使能了TXE和TC中断的情况下,建议在中断处理函数中先处理TC中断,
再处理TXE中断。因为TC表示一次传输的结束,而TXE表示可以发送下一个数据。
如果先处理TXE,可能会在TC之前就写入新的数据,这样TC标志可能会被清除
(因为写入DR寄存器是清除TC的条件之一),导致TC中断无法正常触发。*/
if(sr & USART_SR_TC)
{
//if (_pUart->usTxRead == _pUart->usTxWrite)
if (_pUart->usTxCount == 0)
{
// 必须清除 TC 标志,只有当DR寄存器进行写操作,才会自动清零,否则手动清零
__HAL_UART_CLEAR_FLAG(_pUart->huart, UART_FLAG_TC); // 清除TC标志
/* 如果发送FIFO的数据全部发送完毕,禁止数据发送完毕中断 */
__HAL_UART_DISABLE_IT(_pUart->huart, UART_IT_TC);// 禁止TC中断
/* 回调函数, 一般用来处理RS485通信,将RS485芯片设置为接收模式,避免抢占总线 */
if (_pUart->SendOver)
{
_pUart->SendOver();
}
}
else
{
/* 正常情况下,不会进入此分支 */
/* 如果发送FIFO的数据还未完毕,则从发送FIFO取1个数据写入发送数据寄存器 */
_pUart->huart->Instance->DR = _pUart->pTxBuf[_pUart->usTxRead];
if (++_pUart->usTxRead >= _pUart->usTxBufSize)
{
_pUart->usTxRead = 0;
}
_pUart->usTxCount--;
}
}
/* 处理发送缓冲区空中断 */
/* TXE (Transmit Data Register Empty) - 发送数据寄存器空*/
/* 4. 处理TXE发送空中断 */
if(sr & USART_SR_TXE)
{
//if (_pUart->usTxRead == _pUart->usTxWrite)
if (_pUart->usTxCount == 0)
{
/* 发送缓冲区的数据已取完时, 禁止发送缓冲区空中断 (注意:此时最后1个数据还未真正发送完毕)*/
//禁止TXE中断、使能TC中断
__HAL_UART_DISABLE_IT(_pUart->huart, UART_IT_TXE);
/* 使能数据发送完毕中断 */
__HAL_UART_ENABLE_IT(_pUart->huart, UART_IT_TC);
}
else
{
/* 从发送FIFO取1个字节写入串口发送数据寄存器 */
/* 发送下一个字节 */
_pUart->huart->Instance->DR = _pUart->pTxBuf[_pUart->usTxRead];
if (++_pUart->usTxRead >= _pUart->usTxBufSize) {
_pUart->usTxRead = 0;
}
_pUart->usTxCount--;
}
}
}
|