welcom ! Handel home

2014年6月30日 星期一

ST32 USART about the TXE and TC 測試說明!

為了解決 USART 重複觸發問題查詢很多網上資料 一直未有可靠的斬獲
直到找到 "amoBBS 阿莫电子论坛"  有下面的討論 才引發我去驗證的決心, 分享給諸君參考!
結論如下:
1: Flag 說明:
     USART_IT_TC:   Transmission complete interrupt .  
     USART_IT_TXE:  Tansmit Data Register empty interrupt
     USART_IT_RXNE: Receive Data register not empty interrupt.
2: 根據說明驗證
     於 USART1_IRQHandler(void) 內宣告 變數 u16  srreg  作為回讀確認 USART->SR Flag 讀值buffer 
3 確認事項
 **  drreg = USARTDR  讀取 USARTDR , TXE  Flag 狀態不變!
            與網路上有的說明 回讀USARTDR  TXE清為 0 不符
 **  將 USARTSR = 0x0000 強制寫入 0 TXE Flag 無法歸零 
 ** darareg = USARTDR R/W data buffer TXE Flag 會歸零
 ** 寫入 USARTSR = 0x0000 then  TC and RXEN Flag 可以 歸零     


4: 由此 可以確認
USART_ITConfig(USART1, USART_IT_TXE, ENABLE); 會引發產生接收中斷
 USART_ITConfig(USART1, USART_IT_TC, ENABLE); 使用傳送結束中斷較理想!



在void USART_Config(void)串口初始化函数中设置了USART_ITConfig(USART1, USART_IT_TXE, ENABLE);,
对“发送数据寄存器空”中断进行了使能。
其中TXE中断的描述是如下(STM32F10x微控制器参考手册(2008年12月第7版).pdf,P494)
______________________________________________________________________________
|  TXE:发送数据寄存器空 
|     TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。
|      如果USART_CR1 寄存器中的TXEIE1,则产生中断。对USART_DR的写操作,将该位清零。 
|     0:数据还没有被转移到移位寄存器; 
|     1:数据已经被转移到移位寄存器。 
|  注意:单缓冲器传输中使用该位。
|_____________________________________________________________________________
其中提到该位的清零只能由对对USART_DR的写操作来完成。而我在原来的程序里面使用了
USART_ClearITPendingBit(USART1 ,USART_IT_TXE);
这句话,本意是想在ISR中清除 发送数据寄存器空 中断,实际上只是一厢情愿,并不能达到清中断标志的目的。
跟踪USART_ClearITPendingBit();函数,发现在函数说明中,这个函数并不能对USART_IT_TXE进行操作,原来的写法有误。
/*******************************************************************************
* Function Name  : USART_ClearITPendingBit
* Description    : Clears the USARTx interrupt pending bits.
* Input          : - USARTx: Select the USART or the UART peripheral. 
*                    This parameter can be one of the following values:
*                     - USART1, USART2, USART3, UART4 or UART5.
*                  - USART_IT: specifies the interrupt pending bit to clear.
*                    This parameter can be one of the following values:
*                       - USART_IT_CTS:  CTS change interrupt (not available for 
*                                        UART4 and UART5)
*                       - USART_IT_LBD:  LIN Break detection interrupt
*                       - USART_IT_TC:   Transmission complete interrupt. 
*                       - USART_IT_RXNE: Receive Data register not empty interrupt.
*                       - USART_IT_IDLE: Idle line detection interrupt.
*                       - USART_IT_ORE:  OverRun Error interrupt.
*                       - USART_IT_NE:   Noise Error interrupt.
*                       - USART_IT_FE:   Framing Error interrupt.
*                       - USART_IT_PE:   Parity Error interrupt.
*  可以看到,USART_IT_TXE并不能作为该函数的参数。
*                    Note: - For IDLE, ORE, NE, FE and PE pending bits user has to 
*                            read the USART DR register after calling this function.
*                          - TXE pending bit can't be cleared by this function, it's
*                            cleared only by a write to the USART DR register.
* Output         : None
* Return         : None
*******************************************************************************/
这就导致了上面提到的出现永无止尽的中断,因为 USART_DR 一直都是空的。
这样看来,我在 4 楼提到的 NVIC_Init()函数中 
“NVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] = (u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F);//这里触发了一次中断
这样的描述是不对的,并不是触发软中断,只是这句话刚打开中断,CPU发现 USART_DR 是空的,于是就进入响应中断了。

解决办法:

1. 因为发送的数据量不是很大,只是打印几个字符信息而已,所以干脆就把发送空中断关了
2. 将原来发送一个字符的函数
    void putch(u8 c)
    {
        if(c=='\n')
        {
            USART_SendData(USART1, 0x0D);
            while(!USART_GetITStatus(USART1, USART_IT_TXE)); //将要改这里
            USART_SendData(USART1, 0x0A);
            while(!USART_GetITStatus(USART1, USART_IT_TXE));
        }
        else
        {
            USART_SendData(USART1, (unsigned char)c);
            while(!USART_GetITStatus(USART1, USART_IT_TXE)); 
        }
    }//end of void putch(u8 c)
改为
    void putch(u8 c)
    {
        if(c=='\n')
        {
            USART_SendData(USART1, 0x0D);
            while (!(USART1->SR & USART_FLAG_TXE)); //这里改动
            USART_SendData(USART1, 0x0A);
            while (!(USART1->SR & USART_FLAG_TXE));
        }
        else
        {
            USART_SendData(USART1, (unsigned char)c);
            while (!(USART1->SR & USART_FLAG_TXE)); 

        }

沒有留言: