STM32F103 USART1 IDLE旗标进中断ISR后, 会自动清除

目前在接收不定长度的 Modbus Frame上, 还是以 RXNE为基础

想改用STM32 DMA + USART IDLE试试, 看能不能降低中断次数/CPU使用率.

数据发送频率低, 长度<16

USART1 RX 以 DMA Normal mode 驱动 ( Buffer & CNDTR = 80)

接收 不定个字符后, 等USART1触发 IDLE 中断 (其他 RXNEIE, TXEIE, TCIE关闭),

网上 + CSDN 搜了 STM32 DMA + USART IDLE的文章, 概念上都建议在中断 ISR中判断 IDLEF

开始实作

(a) DMA1 -> RX Buffer 数据接收正确

(b) USART1 触发 IDLE中断, 程序进入ISR正常

cpp 复制代码
void USART1_IRQHandler(void)
{
	int  iRXLen =0;  
    if( RESET != USART_GetITStatus( USART1, USART_IT_IDLE )) 
     {
        iRXLen = USART_BUFFER_SIZE - (uint16_t)(DMA1_Channel5->CNDTR);
        if( iRXLen > 3)  
          {
			    // DMA_Cmd( DMA1_Channel4, DISABLE );    
			    DMA1_Channel4->CCR &= ~DMA_CCR4_EN;     
	            flagMessgaeIn=1; ; 
         }
     }  
     USART1->SR=0; 
}     

问题发生了:
当我判断 USART_FLAG_IDLE 时, IDLE旗标, 它自己清除了!

实验发现, 似乎进了中断USART1_IRQHandler后就会清除.

断点 设在进入后第一个点, SR=0x000000D0

执行第一个指令时, 就变成 SR=0x000000C0

嗯! USART_FLAG_IDLE = 0x00000010 ( SR bit4 )

<答案>

ST RM0008文件上, 说的是IDLEF要软件清除.它漏说了: IDLEF 进ISR会被自动清除!

意思是, 开了 IDLEIE, 你是摸不到IDLEF的!

使用上: 不开中断的状况下, 可以轮询 IDLEF, 再软件清除!

我就想知道那些说 STM32F103可以在 ISR里面判断 IDLEF的,

你们真的试过吗, 还是搬来搬去忽悠呢?

cpp 复制代码
void DMA1_Init(void)
{
	    DMA_InitTypeDef  DMA_InitStruct;
	    // Enable DMA1 Clock    
	    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE);  
	    
	    // TX Config    
	    DMA_DeInit( DMA1_Channel4 );
	    DMA_InitStruct.DMA_BufferSize       = 0;
	    DMA_InitStruct.DMA_DIR              = DMA_DIR_PeripheralDST;
	    DMA_InitStruct.DMA_M2M              = DMA_M2M_Disable;
	    DMA_InitStruct.DMA_MemoryBaseAddr   = (uint32_t)USART_TX_Buffer;
	    DMA_InitStruct.DMA_MemoryDataSize   = DMA_MemoryDataSize_Byte;
	    DMA_InitStruct.DMA_MemoryInc        = DMA_MemoryInc_Enable;
	    DMA_InitStruct.DMA_Mode             = DMA_Mode_Normal;
	    DMA_InitStruct.DMA_PeripheralBaseAddr = USART1_BASE +0x0004;
	    DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	    DMA_InitStruct.DMA_PeripheralInc    = DMA_PeripheralInc_Disable;
	    DMA_InitStruct.DMA_Priority         = DMA_Priority_High;  
	    DMA_Init( DMA1_Channel4, &DMA_InitStruct);
	    DMA_Cmd( DMA1_Channel4, DISABLE );
	    
	   
	    // RX Config
	    DMA_DeInit( DMA1_Channel5);
	    DMA_InitStruct.DMA_BufferSize       = USART_BUFFER_SIZE;
	    DMA_InitStruct.DMA_DIR              = DMA_DIR_PeripheralSRC;
	    DMA_InitStruct.DMA_M2M              = DMA_M2M_Disable;
	    DMA_InitStruct.DMA_MemoryBaseAddr   = (uint32_t)USART_RX_Buffer;
	    DMA_InitStruct.DMA_MemoryDataSize   = DMA_MemoryDataSize_Byte;
	    DMA_InitStruct.DMA_MemoryInc        = DMA_MemoryInc_Enable;
	    DMA_InitStruct.DMA_Mode             = DMA_Mode_Normal;
	    DMA_InitStruct.DMA_PeripheralBaseAddr= USART1_BASE +0x0004;
	    DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	    DMA_InitStruct.DMA_PeripheralInc    = DMA_PeripheralInc_Disable;
	    DMA_InitStruct.DMA_Priority         = DMA_Priority_High;      
	    DMA_Init( DMA1_Channel5, &DMA_InitStruct);
	    DMA_Cmd( DMA1_Channel5, ENABLE);
    }

void USART1_Init(uint32_t baud)
{
	    USART_InitTypeDef USART_InitStructure;
	    GPIO_InitTypeDef GPIO_InitStructure;
	    NVIC_InitTypeDef NVIC_InitStrue;    
		
	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
		  
		  // Set GPIO PA9 as USART1 TX 
	    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; 
	    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//USART1_TX PA.9
	    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	    GPIO_Init(GPIOA, &GPIO_InitStructure);  
	
		  // Set GPIO PA10 as USART1 RX 
	    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; 
	    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//USART1_RX PA.10
	    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	    GPIO_Init(GPIOA, &GPIO_InitStructure);  	
		
		  // Init USART1	
	    USART_DeInit(USART1); 
	    USART_InitStructure.USART_BaudRate = baud; 
	    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	    USART_InitStructure.USART_StopBits = USART_StopBits_1;  
	    USART_InitStructure.USART_Parity = USART_Parity_No;  
	    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
	    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  
	    USART_Init(USART1, &USART_InitStructure);  
	
	    // Enable USART1 Interrupt
	    USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); 
	    USART_ITConfig(USART1, USART_IT_TC, DISABLE);
		USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
	    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); 
	    
	    // Set NVIC Interrupt
	    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_0 ); 
	    NVIC_InitStrue.NVIC_IRQChannel = USART1_IRQn;
	    NVIC_InitStrue.NVIC_IRQChannelCmd = ENABLE; 
	    NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority = 0; 
	    NVIC_InitStrue.NVIC_IRQChannelSubPriority = 13; 
	    NVIC_Init(&NVIC_InitStrue); 
	    
	    DMA1_Init(); 
	    // USART1 TX Channle4
	    USART_DMACmd( USART1, USART_DMAReq_Tx, ENABLE);
	    // USART1 RX Channel5   
	    USART_DMACmd( USART1, USART_DMAReq_Rx, ENABLE);    
	    USART_Cmd(USART1,ENABLE); 
	    DelayXms(2);        
	    (void)USART1->SR;        
	    (void)USART1->DR;   
}
相关推荐
星辰pid2 小时前
STM32实现四自由度机械臂(SG90舵机)多功能控制(软件篇freertos)
stm32·单片机·嵌入式硬件·机械臂
森焱森7 小时前
水下航行器外形分类详解
c语言·单片机·算法·架构·无人机
小殷学长9 小时前
【单片机毕业设计17-基于stm32c8t6的智能倒车监测系统】
stm32·单片机·课程设计
TESmart碲视11 小时前
HKS201-M24 大师版 8K60Hz USB 3.0 适用于 2 台 PC 1台显示器 无缝切换 KVM 切换器
单片机·嵌入式硬件·物联网·游戏·计算机外设·电脑·智能硬件
small_wh1te_coder11 小时前
硬件嵌入式学习路线大总结(一):C语言与linux。内功心法——从入门到精通,彻底打通你的任督二脉!
linux·c语言·汇编·嵌入式硬件·算法·c
花落已飘12 小时前
STM32中实现shell控制台(shell窗口输入实现)
stm32·单片机·嵌入式硬件
花落已飘12 小时前
STM32中实现shell控制台(命令解析实现)
stm32·shell
没有钱的钱仔12 小时前
STM32低功耗模式全面指南
css·stm32·css3
牵牛老人14 小时前
Qt处理USB摄像头开发说明与QtMultimedia与V4L2融合应用
stm32·单片机·qt
宇钶宇夕15 小时前
针对工业触摸屏维修的系统指南和资源获取途径
单片机·嵌入式硬件·自动化