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;   
}
相关推荐
极客 - L U2 小时前
卡尔曼滤波从零到精通
c语言·数据结构·单片机·嵌入式硬件·mcu
AMASENSYS艾马斯3 小时前
变频器滤波器选型与EMC合规建议
驱动开发·单片机·其他·硬件工程·精益工程
码小文4 小时前
CAM350使用笔记(6)---Gerber文件铺铜间距检查
嵌入式硬件·cam350软件·cam350使用笔记
Zw-awa5 小时前
编译器工具链:GCC、Clang、MSVC、ICC、armclang
stm32
Yiran_G5 小时前
双频 Wi-Fi 6 + 蓝牙 5.4:无声讯通 WS8712 模组的开发与集成要点
网络·嵌入式硬件·物联网·智能家居
凯基迪科技6 小时前
STM32G系列(G0/G4)芯片解密程序提取RDP读保护解析
网络·stm32·安全
光子物联单片机6 小时前
ESP32传感器模块编程实践(一)DIY智能WIFI视频控制小车
嵌入式硬件·esp32·智能硬件·硬件
2501_922639586 小时前
率能半导体 SS6628E直流双向马达驱动芯片:20V/7A,覆盖电子锁、玩具、无线充电、机器人四大应用场景
单片机·嵌入式硬件·硬件工程
硅基造物主6 小时前
STM32 从 0 到 1 做智能家居(五):工程结构与代码骨架
stm32·单片机·嵌入式硬件·智能家居
深圳老胡7 小时前
STM32F103 硬件 SPI 与软件 IO 模拟 SPI 最高速度差异详解
笔记·stm32·单片机·代码规范·1024程序员节