USART之空闲中断(IDLE)

纵然是瞬间 提交于 2019-11-27 16:40:14

                                     USART - 空闲中断接收

STM32 的 USART 收发,  以前只知道用RENE(非空中断)处理接收, 自从发现IDLE(空闲中断) 这词后, 眼前一亮, 老司机自然明白能省多少中断工夫!!

使用时,注意以下两点,很重要:

1. IDLE的中断清理方式.

  • 开始以为住SR写0就能清理中断, 调试时寄存器确实清0了, 但程序上却不断进中断! (你用IDLE就会发现这问题了) 
  • 这个费了一个白天,直至网上发现前人的留言:
  • "因为IDLE被搞成了一个帧,而不是一个事件,这个帧不读掉是清除不了中断标志的,这个真的很坑啊。" 
  • 方法如下:
  • u32 temp;
  • temp=USART1->SR;
  • temp=USART1->DR;
  • 就是这样, 这两句顺序还不能错, 前人不说, 撞墙也想不出来这前因后果!!

2. DMA 设置

  • 平时用DMA一般就:PtoM,  MtoP,  就是数据长度是已知道的;  而用IDLE(空闲中断), 最方便的就是接收不定长数据.
  • 所以NDTR(传输数量)要设得比实际数量要大(注意单位:你的字长),如200. 大多少没关系.
  • 中断中, 要重新设置NDTR. 切记,切记,切记. 另外: DMA是在关闭时方能修改!!

代码如下, 主要三个函数, DMA初始化USART初始化中断函数,   


// DMA初始化
//******************************************************************************
void DMA_Init(void)
{  
    RCC->AHB1ENR |= 0x1<<22 ;                      // 使能DMA2时钟  
    DMA2_Stream1 ->CR   = 0;                       // EN    [0]     禁止数据流 ,才能写寄存器 
    DMA2_Stream1 ->PAR  = (u32)USART1 +0x04;       // 外设地址      ADC1->DR
    DMA2_Stream1 ->M0AR = (u32)&RxBuf;             // 存储器地址    内部SDRAM的变量
    DMA2_Stream1 ->NDTR = 60;                      // 一次传输数量      
    DMA2_Stream1 ->FCR  = 0x21;                    // 复位值        FIFO所有配置失效 
   
      DMA2_Stream1 ->CR |= 0<< 6;                  // DIR   [7:6]   传输方向       0_PtM, 1_Mtp, 2_MtM
      DMA2_Stream1 ->CR |= 1<< 8;                  // CIRC  [8]     循环模式       0_禁止 1_使能
      DMA2_Stream1 ->CR |= 0<< 9;                  // PINC  [9]     外设递增       0_外设地址指针固定  1_递增
      DMA2_Stream1 ->CR |= 1<<10;                  // MINC  [10]    存储器递增     0_存储器指针固定    1_递增
      DMA2_Stream1 ->CR |= 0<<11;                  // PSIZE [12:11] 外设数据大小   0_8位  1_16位  10_32位
      DMA2_Stream1 ->CR |= 0<<13;                  // MSIZE [14:13] 存储器数据大小 0_8位  1_16位  10_32位
      DMA2_Stream1 ->CR |= 1<<16;                  // PL    [17:16] 优先级         0_低 1_中 2_高 3_最高
      DMA2_Stream1 ->CR |= 5<<25;                  // CHSEL [27:25] 通道选择
      DMA2_Stream1 ->CR |= 1<<0;                   // EN    [0]     使能数据流, 使能后DMA大部份寄存器都不能写        
}



// USART初始化
//******************************************************************************     
void USART_Init()
{
    float T;
    u16 M,F;    	
	
    RCC->APB2ENR |= (u32)1<<4;         // 使能 USART时钟
    RCC->AHB1ENR |= (u32)1<<0;         // 使能 GPIOA时钟

    vSys_GPIOSet (DEBUG_TX_GPIOx, DEBUG_TX_PINx, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_OSPEED_50M , GPIO_PUPD_UP , DEBUG_USART_AFx);  // TX, GPIO
    vSys_GPIOSet (DEBUG_RX_GPIOx, DEBUG_RX_PINx, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_OSPEED_50M , GPIO_PUPD_UP , DEBUG_USART_AFx);  // RX, GPIO         

    T=(float)(DEBUG_USART_CLK *1000000)/(DEBUG_USART_BRR *16); // 得到USARTDIV,OVER8设置为0
    M=T;			       // 得到整数部分
    F=(T-M)*16; 	               // 得到小数部分,OVER8设置为0	 
    M<<=4;
    M=M+F;  
    USART1 ->BRR = M;                  // 设置波特率因子
    
    USART1 ->CR1  = 0;                 // 清0     
    USART1 ->CR1 |= 1<<2;              // 接收                    
    USART1 ->CR1 |= 1<<3;              // 发送
    USART1 ->CR1 |= 1<<4;              // 使能接收缓冲区非空中断
    USART1 ->CR1 |= 0<<10;             // 校验
    USART1 ->CR1 |= 0<<12;             // 字长
    USART1 ->CR1 |= 0<<15;             // 过采样 0=16           
    USART1 ->CR1 |= 1<<13;             // 使能    
         
    vSys_NVICSet(DEBUG_USART_IRQN,9);  // 我自己的NVIC设置函数, 改成你自己需要的 
    
    DMA_Init ();
    USART1 ->CR3  = 1<<6;              // 使能DMA接收      
} 



// 中断函数 
//****************************************************************************** 
void USART1_IRQHandler(void)           
{        
    static u32 temp;      
    temp =USART1->SR ;
    
    if((temp&0x10))                    // 检查IDLE中断标志
    {   
        vDelay_ms (20);                // 等一会, 速度匹配问题, 暂未能解决
        p(RxBuf );  
        
        temp=USART1 ->SR;              // !!! 这两句很重要, 作用是清理IDLE中断, 顺序不参错!!
        temp=USART1->DR;               // !!!
            
        DMA2_Stream1 -> CR &=~(1<<0);  // 失能 DMA, 关闭方能修改参数
        DMA2_Stream1 ->NDTR = 60;      // 重新设置DMA的传输数目, 必须大于要传输的数目,否则超出部分会履盖开始部份
        DMA2_Stream1 -> CR |= 1<<0;    // 使能 DMA                
     }         
}  

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!