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;   
}
相关推荐
朱嘉鼎3 小时前
状态机的介绍
c语言·单片机
清风6666664 小时前
基于单片机的噪声波形检测与分贝测量仪设计
单片机·嵌入式硬件·毕业设计·课程设计
易享电子5 小时前
基于单片机车窗环境监测控制系统Proteus仿真(含全部资料)
单片机·嵌入式硬件·fpga开发·51单片机·proteus
三佛科技-134163842125 小时前
LED氛围灯方案开发MCU控制芯片
单片机·嵌入式硬件·智能家居·pcb工艺
小莞尔6 小时前
【51单片机】【protues仿真】基于51单片机主从串行通信系统
c语言·单片机·嵌入式硬件·物联网·51单片机
Hello_Embed6 小时前
STM32 环境监测项目笔记(一):DHT11 温湿度传感器原理与驱动实现
c语言·笔记·stm32·单片机·嵌入式软件
三佛科技-134163842127 小时前
便携式榨汁机方案开发,榨汁机果汁机MCU控制方案设计
单片机·嵌入式硬件·智能家居·pcb工艺
yongui478348 小时前
基于TMS320F28027实现光伏MPPT控制
单片机·嵌入式硬件
炸膛坦客10 小时前
Cortex-M3 内核 MCU-STM32F1 开发之路:(一)单片机 MCU 的构成,包括 FLASH 和 SRAM 的区别,以及引脚类型
stm32·单片机·嵌入式硬件
A9better10 小时前
嵌入式开发学习日志39——stm32之I2C总线物理层与常用术语
stm32·单片机·嵌入式硬件·学习