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

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 關(guān)于STM32串口的理解

          關(guān)于STM32串口的理解

          作者: 時間:2016-11-18 來源:網(wǎng)絡(luò) 收藏

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

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

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

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

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

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

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

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

          對于第一種情況,其程序可以這么寫:其中TXS是保存了要發(fā)送數(shù)據(jù)的字符串,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ā)送完成后關(guān)閉TXE中斷,
          { USART_ITConfig(USART1,USART_IT_TXE,DISABLE);}
          }
          }

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

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

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

          在使用時,只要將TXS指向要發(fā)送的字符串或者數(shù)組,設(shè)置TxLen為要發(fā)送的數(shù)據(jù)長度,然后執(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; //復(fù)位索引值
          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);

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




          關(guān)鍵詞: STM32串

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁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); })();