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;   
}
相关推荐
智商偏低2 小时前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen3 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森5 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白5 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D5 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术8 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt9 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘9 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang9 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n12 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件