<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 關于STM32串口的理解

          關于STM32串口的理解

          作者: 時間:2016-11-18 來源:網絡 收藏

          總的來說,STM32單片機串口還是很好理解的,編程也不算復雜。當然我更愿意希望其中斷系統(tǒng)51單片機一樣的簡單。

          本文引用地址:http://www.ex-cimer.com/article/201611/315877.htm

          對于接收終端,就是RXNE了,這只在接收完成后才產生,在執(zhí)行USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)代碼時不會進入ISR。但麻煩的就是發(fā)送有關的中斷了:TXE或者TC,根據資料和測試的結果,TXE在復位后就是置1的,即在執(zhí)行USART_ITConfig(USART1, USART_IT_TXE, ENABLE)后會立即產生中斷請求。因此這造成一個麻煩的問題:如果沒有真正的發(fā)送數據,TXE中斷都會發(fā)生,而且沒有休止,這將占用很大部分的CPU時間,甚至影響其他程序的運行!

          因此建議的是在初始化時不好啟用TXE中斷,只在要發(fā)送數據(尤其是字符串、數組這樣的系列數據)時才啟用TXE。在發(fā)送完成后立即將其關閉,以免引起不必要的麻煩。

          對于發(fā)送,需要注意TXE和TC的差別——這里簡單描述一下,假設串口數據寄存器是DR、串口移位寄存器是SR以及TXD引腳TXDpin,其關系是DR->SR->TXDpin。當DR中的數據轉移到SR中時TXE置1,如果有數據寫入DR時就能將TXE置0;如果SR中的數據全部通過TXDpin移出并且沒有數據進入DR,則TC置1。并且需要注意TXE只能通過寫DR來置0,不能直接將其清零,而TC可以直接將其寫1清零。

          對于發(fā)送單個字符可以考慮不用中斷,直接以查詢方式完成。

          對于發(fā)送字符串/數組類的數據,唯一要考慮的是只在最后一個字符發(fā)送后關閉發(fā)送中斷,這里可以分為兩種情況:對于發(fā)送可顯示的字符串,其用0x00作為結尾的,因此在ISR中就用0x00作為關閉發(fā)送中斷(TXE或者TC)的條件;第二種情況就是發(fā)送二進制數據,那就是0x00~0xFF中間的任意數據,就不能用0x00來判斷結束了,這時必須知道數據的具體長度。

          這里簡單分析上面代碼的執(zhí)行過程:TXE中斷產生于前一個字符從DR送入SR,執(zhí)行效果是后一個字符送入DR。對于第一種情況,如果是可顯示字符,就執(zhí)行USART_SendData來寫DR(也就清零了TXE),當最后一個可顯示的字符從DR送入SR之后,產生的TXE中斷發(fā)現要送入DR的是字符是0x00——這當然不行——此時就關閉TXE中斷,字符串發(fā)送過程就算結束了。當然這時不能忽略一個隱含的結果:那就是最后一個可顯示字符從DR轉入SR后TXE是置1的,但關閉了TXE中斷,因此只要下次再開啟TXE中斷就會立即進入ISR。對于第二種情況,其結果和第一種的相同。

          對于第一種情況,其程序可以這么寫:其中TXS是保存了要發(fā)送數據的字符串,TxCounter1是索引值:

          extern __IO uint8_t TxCounter1;
          extern uint8_t *TXS;
          extern __IO uint8_t TxLen;

          void USART1_IRQHandler(void)
          {
          if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
          {
          if(TXS[TxCounter1]) //如果是可顯示字符
          { USART_SendData(USART1,TXS[TxCounter1++]);}
          else //發(fā)送完成后關閉TXE中斷,
          { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);}
          }
          }

          對于第二種情況,和上面的大同小異,其中TXLen表示要發(fā)送的二進制數據長度:

          void USART1_IRQHandler(void)
          {
          if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) //對USART_DR的寫操作,將該位清零。
          {
          if(TxCounter1{ USART_SendData(USART1,TXS[TxCounter1++]);}
          else //發(fā)送完成后關閉TXE中斷
          { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);}
          }
          }

          事實上第一種情況是第二種的特殊形式,就是說可以用第二種情況去發(fā)送可顯示的字符——當然沒人有閑心去數一句話里有多少個字母空格和標點符號!

          在使用時,只要將TXS指向要發(fā)送的字符串或者數組,設置TxLen為要發(fā)送的數據長度,然后執(zhí)行USART_ITConfig(USART1,USART_IT_TXE,ENABLE)就立即開始發(fā)送過程。用戶可以檢查TxCounter1來確定發(fā)送了多少字節(jié)。比如以第二種情況為例:

          uint32_t *TXS;
          uint8_t TxBuffer1[]="0123456789ABCDEF";
          uint8_t DST2[]="ASDFGHJKL";
          __IO uint8_t TxLen = 0x00;

          TxLen=8; //發(fā)送8個字符,最終發(fā)送的是01234567
          TXS=(uint32_t *)TxBuffer1; //將TXS指向字符串TxBuffer1
          TxCounter1=0; //復位索引值
          USART_ITConfig(USART1, USART_IT_TXE,ENABLE); //啟用TXE中斷,即開始發(fā)送過程
          while(TxCounter1!=TxLen); //等待發(fā)送完成

          TXS=(uint32_t *)TxBuffer2; //同上,最終發(fā)送的是ASDFGHJK
          TxCounter1=0;
          USART_ITConfig(USART1, USART_IT_TXE,ENABLE);
          while(TxCounter1!=TxLen);

          以上就是我認為的最佳方案,但串口中斷方式數據有多長就中斷多少次,我認為還是占用不少CPU時間,相比之下DMA方式就好多了,因為DMA發(fā)送字符串時最多中斷兩次(半傳輸完成,全傳輸完成),并且將串口變成類似16C550的器件。關于DMA方式的這里就不介紹了,有空再說。




          關鍵詞: STM32串

          評論


          技術專區(qū)

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();