今天学了个新的知识点 : 空闲中断
是接收不定长数据的大杀器
感觉比我上一篇文章的环形队列方便多了,有了这个工具,就不用每次接收一位数据都进入一次中断,而且不用判断数据是否接收完毕。
降低了cup算力的消耗。
本次主要介绍空闲中断。
1 空闲中断
空闲中断(IDLE),俗称帧中断,即第一帧数据接收完毕到第二帧数据开始接收期间存在一个空闲状态(每接收一帧数据后空闲标志位置1),检测到此空闲状态后即执行中断程序。空闲中断的优点在于省去了帧头帧尾的检测,进入中断程序即意味着已经接收到一组完整数据,仅需及时对数据处理或将数据转移出缓冲区即可。
串口空闲中断在串口无数据接收的情况下,是不会产生的,产生的条件是当清除空闲标志位后,必须有接收到第一个数据后,才开始触发,一旦接收的数据断流,没有接收到数据,即产生空闲中断。
当检测到总线空闲,即判断接收一个字节后的下一个字节时间内,是否继续接收数据,如果超出这个字节时间,并且判断CR1的第四位是否为1(是否使能空闲中断),如果是则会产生空闲中断。
2 题目要求
电脑给单片机发送不定长数据,单片机用串口通过DMA接收,保存到一个数组里,然后再发给电脑。
3 cubemx 配置
1 设置时钟频率 72mhz 使用外部晶振
2 使能串口1 设置串口中断以及优先级,接收和发送都使用DMA,接收DMA使用循环模式 ,发送DMA使用普通模式,收发DMA都是存储器增量模式。
4 程序框图
5 程序代码
main.c
uint16_t buf[20] = {0}; // 收发数组
uint8_t R_long = 0; // 接收长度
uint8_t buf_long = 0; // 收发数组的长度
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//使能空闲中断
buf_long = sizeof buf/sizeof buf[0]; //得到 buf 数组的长度
HAL_UART_Receive_DMA(&huart1,(uint8_t *)buf,buf_long); //使能串口DMA接收
while (1)
{
}
}
使能串口DMA接收和空闲中断后,此时只要接收数据停止时,就会触发空闲中断,进入串口1中断函数中
void USART1_IRQHandler(void)
{
if (__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) == SET) //判断是否时空闲中断
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清除空闲中断标志
HAL_UART_DMAStop(&huart1); //停止DMA
R_long = buf_long - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //接收了多长的数据
HAL_UART_Transmit_DMA(&huart1,(uint8_t *)buf,R_long); //使能DMA串口发送
}
HAL_UART_IRQHandler(&huart1);
}
串口发送完成之后会进入发送完成回调函数中
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
R_long = 0; // 清除发送长度
memset(buf,0,R_long); //清空收发数组
HAL_UART_Receive_DMA(&huart1,(uint8_t *)buf,buf_long); //使能接收
}
}
6 实验现象