乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      STM32 串口總線(xiàn)空閑檢測(cè)

       鹵煮小魚(yú) 2017-04-24

      主機(jī)環(huán)境:Windows XP  SP3

      開(kāi)發(fā)環(huán)境:MDK 5.20

      目標(biāo)芯片:STM32F030C8T6

      前兩天在群里看到有人在詢(xún)問(wèn)有關(guān)STM32 串口總線(xiàn)空閑檢測(cè)的事情,根據(jù)串口總線(xiàn)是否空閑來(lái)判斷一幀數(shù)據(jù)是否發(fā)送完成,之前使用串口一直沒(méi)怎么注意過(guò)這一串口特性,所以后來(lái)特意去看了下手冊(cè)中有關(guān)總線(xiàn)空閑檢測(cè)的指示,發(fā)現(xiàn)它的確是個(gè)好特性,之前都只是在串口中斷中接收數(shù)據(jù)在主循環(huán)中不斷的讀取數(shù)據(jù)然后檢測(cè)是否是一幀完整的數(shù)據(jù),之后再進(jìn)行后續(xù)處理。這樣處理有一個(gè)不是很好的問(wèn)題就是在主循環(huán)讀取串口數(shù)據(jù)時(shí)需要有個(gè)超時(shí)計(jì)數(shù)器來(lái)避免無(wú)串口數(shù)據(jù)時(shí)死等在那里,但如果使用串口總線(xiàn)空閑檢測(cè)的話(huà),我們就不需要超時(shí)計(jì)數(shù)器了,只需要在檢測(cè)到串口總線(xiàn)空閑時(shí)把收到的數(shù)據(jù)全部讀走,然后檢測(cè)是否滿(mǎn)足一定的格式進(jìn)而處理,這樣是的主循環(huán)的時(shí)間進(jìn)一步減少,加速了系統(tǒng)的處理速度。

      在STM32F030C8T6的參考手冊(cè)中串口中斷狀態(tài)寄存器USARTx_ISR中有一個(gè)IDLE位來(lái)表明是否檢測(cè)到總線(xiàn)空閑,如下圖所示:


      并且給出了如何清除該標(biāo)識(shí),STM32F1系列芯片清除該標(biāo)識(shí)的方法不同,可根據(jù)參考手冊(cè)來(lái)查詢(xún),且該標(biāo)識(shí)置位后就不再置位除非RXNE位再次置位,如果上位機(jī)一次性發(fā)送了1個(gè)字節(jié)數(shù)據(jù)則RXNE置位1次,IDLE置位1次,而如果上位機(jī)一次性發(fā)送了6個(gè)字節(jié)數(shù)據(jù),則RXNE置位6次,IDLE依然置位1次,只要在CR1寄存器中使能了串口總線(xiàn)空閑檢測(cè)就可以使用該特性了,使用標(biāo)準(zhǔn)庫(kù)編輯了一下測(cè)試代碼,uart頭文件如下

      1. #ifndef __UART_H__  
      2. #define __UART_H__  
      3. #include <stdint.h>  
      4. #include "stm32f0xx.h"  
      5. #include <stdio.h>  
      6.   
      7.   
      8. #define USARTx                          USART1  
      9. #define USARTx_GPIO_PORT                GPIOA  
      10. #define USARTx_GPIO_CLK                 RCC_AHBPeriph_GPIOA  
      11. #define USARTx_TX_PIN                   GPIO_Pin_9  
      12. #define USARTx_TX_SOURCE                GPIO_PinSource9  
      13. #define USARTx_TX_AF                    GPIO_AF_1  
      14. #define USARTx_RX_PIN                   GPIO_Pin_10  
      15. #define USARTx_RX_SOURCE                GPIO_PinSource10  
      16. #define USARTx_RX_AF                    GPIO_AF_1  
      17. #define USARTx_IRQn                     USART1_IRQn  
      18. #define USARTx_IRQHandler               USART1_IRQHandler  
      19. #define USARTx_CLK_ENABLE()             RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)  
      20.   
      21. void uart_init (uint32_t baud);  
      22.   
      23. #endif  

      uart的源碼文件如下

      1. #include "uart.h"  
      2. uint8_t buffer[100];  
      3. uint8_t cnt = 0,idle_detect = 0;  
      4.   
      5. void uart_init (uint32_t baud)  
      6. {  
      7.     USART_InitTypeDef USART_InitStructure;     
      8.     GPIO_InitTypeDef GPIO_InitStructure;       
      9.     NVIC_InitTypeDef NVIC_InitStructure;  
      10.   
      11.     //初始化串口時(shí)鐘以及串口端口時(shí)鐘  
      12.     RCC_AHBPeriphClockCmd(USARTx_GPIO_CLK, ENABLE);  
      13.     USARTx_CLK_ENABLE();  
      14.   
      15.     GPIO_PinAFConfig(USARTx_GPIO_PORT, USARTx_TX_SOURCE, USARTx_TX_AF);  
      16.     GPIO_PinAFConfig(USARTx_GPIO_PORT, USARTx_RX_SOURCE, USARTx_RX_AF);  
      17.   
      18.     GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN| USARTx_RX_PIN;                  
      19.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;         
      20.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      
      21.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;         
      22.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3;    
      23.     GPIO_Init(USARTx_GPIO_PORT, &GPIO_InitStructure);    
      24.   
      25.     USART_InitStructure.USART_BaudRate            = baud ;            //設(shè)置波特率  
      26.     USART_InitStructure.USART_WordLength          = USART_WordLength_8b;  //8位數(shù)據(jù)位  
      27.     USART_InitStructure.USART_StopBits            = USART_StopBits_1;     //1位停止位  
      28.     USART_InitStructure.USART_Parity              = USART_Parity_No;     //無(wú)校驗(yàn)位  
      29.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //無(wú)硬件控制  
      30.     USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;   //發(fā)送與接收兩種方式  
      31.     USART_Init(USARTx, &USART_InitStructure);         
      32.   
      33.     USART_ITConfig(USARTx,USART_IT_RXNE,ENABLE);    //使能接收中斷,在接收移位寄存器中有數(shù)據(jù)時(shí)產(chǎn)生  
      34.     USART_ITConfig(USARTx,USART_IT_PE,ENABLE);  
      35.     USART_ITConfig(USARTx,USART_IT_ERR,ENABLE);  
      36.     USART_ITConfig(USARTx,USART_IT_IDLE,ENABLE);    //使能總線(xiàn)空閑檢測(cè)中斷  
      37.       
      38.     /* 使能 USARTx 中斷 */  
      39.     NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;  
      40.     NVIC_InitStructure.NVIC_IRQChannelPriority=0;  
      41.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
      42.     NVIC_Init(&NVIC_InitStructure);   
      43.   
      44.     USART_Cmd(USARTx, ENABLE);   
      45. }  
      46.   
      47.   
      48. int fputc(int ch, FILE *f)  
      49. {  
      50.     USART_SendData(USARTx,(uint8_t)ch);  
      51.     while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) != SET);  
      52.     return ch;  
      53. }  
      54.   
      55. void USARTx_IRQHandler(void)  
      56. {  
      57.     uint8_t temp = 0;  
      58.       
      59.     if(USART_GetFlagStatus(USARTx,USART_FLAG_ORE) != RESET)  
      60.     {  
      61.         temp = USART_ReceiveData(USARTx);  
      62.         (void)temp;  
      63.         USART_ClearFlag(USARTx,USART_FLAG_ORE);  
      64.     }  
      65.     if(USART_GetFlagStatus(USARTx,USART_FLAG_NE) != RESET)  
      66.     {  
      67.         USART_ClearFlag(USARTx,USART_FLAG_NE);  
      68.     }  
      69.     if(USART_GetFlagStatus(USARTx,USART_FLAG_FE) != RESET)  
      70.     {  
      71.         USART_ClearFlag(USARTx,USART_FLAG_FE);  
      72.     }  
      73.     if(USART_GetFlagStatus(USARTx,USART_FLAG_PE) != RESET)  
      74.     {  
      75.         USART_ClearFlag(USARTx,USART_FLAG_PE);  
      76.     }  
      77.       
      78.     if(USART_GetITStatus(USARTx, USART_IT_RXNE) != RESET)//判斷寄存器中是否有數(shù)據(jù)  
      79.     {  
      80.         buffer[cnt++]=USART_ReceiveData(USARTx);  //讀取數(shù)據(jù),讀數(shù)據(jù)的同時(shí)清空了接收中斷標(biāo)志;  
      81.         if(cnt >= 100)  
      82.         {  
      83.             cnt = 0;  
      84.         }  
      85.         USART_ClearITPendingBit(USARTx, USART_IT_RXNE);  
      86.     }  
      87.     if(USART_GetITStatus(USARTx, USART_IT_IDLE) != RESET)  
      88.     {  
      89.         //清除總線(xiàn)空閑中斷標(biāo)志位  
      90.         USART_ClearITPendingBit(USARTx, USART_IT_IDLE);  
      91.         idle_detect = 1;  
      92.     }  
      93.     return;  
      94. }  

      這里檢測(cè)到IDLE標(biāo)識(shí)置位后置位idle_detect變量,cnt變量標(biāo)記了本次接收到的字節(jié)個(gè)數(shù),主函數(shù)測(cè)試代碼如下:

      1. #include "uart.h"                    
      2.   
      3. extern uint8_t idle_detect,cnt;  
      4. extern uint8_t buffer[100];  
      5. int main (void)  
      6. {  
      7.     uint8_t i = 0;  
      8.     uart_init(115200);  
      9.   
      10.     while(1)  
      11.     {  
      12.         if(1 == idle_detect)  
      13.         {  
      14.             idle_detect = 0;  
      15.             printf("\r\ncnt:%X,ctx:",cnt);  
      16.             for(i = 0; i < cnt; i++)  
      17.             {  
      18.                 printf("%02X ",buffer[i]);  
      19.             }  
      20.             cnt = 0;  
      21.         }  
      22.     }  
      23. }  
      代碼比較簡(jiǎn)單,這里使用printf來(lái)輸出本次接收到的字節(jié)數(shù)以及字節(jié)內(nèi)容,運(yùn)行結(jié)果如下:


      可以看到檢測(cè)結(jié)果是正常的,只是在開(kāi)機(jī)后有一次cnt為0的結(jié)果,應(yīng)該是上電之后總線(xiàn)默認(rèn)就是空閑的,的確也沒(méi)有收到數(shù)據(jù),因此就想把cnt為0的結(jié)果去掉,這里我遇到了一個(gè)很糾結(jié)的問(wèn)題,在判斷idle_detect變量的同時(shí)也檢測(cè)cnt是否大于0,測(cè)試代碼更改如下:

      1. #include "uart.h"                    
      2.   
      3. extern uint8_t idle_detect,cnt;  
      4. extern uint8_t buffer[100];  
      5. int main (void)  
      6. {  
      7.     uint8_t i = 0;  
      8.     uart_init(115200);  
      9.   
      10.     while(1)  
      11.     {  
      12.         if(1 == idle_detect && cnt > 0)  
      13.         {  
      14.             idle_detect = 0;  
      15.             printf("\r\ncnt:%X,ctx:",cnt);  
      16.             for(i = 0; i < cnt; i++)  
      17.             {  
      18.                 printf("%02X ",buffer[i]);  
      19.             }  
      20.             cnt = 0;  
      21.         }  
      22.     }  
      23. }  

      感覺(jué)邏輯是對(duì)的,再次運(yùn)行,結(jié)果如下:


      這個(gè)時(shí)候發(fā)現(xiàn)cnt變量的值輸出一直為1,但輸出的字節(jié)內(nèi)容卻是對(duì)的,一直想不通這是為啥?思來(lái)想去邏輯是沒(méi)啥問(wèn)題的,后來(lái)又把cnt是否為0的條件判斷不放在跟idle_detect變量檢測(cè)同一水平,而是放在它里面,更改測(cè)試代碼如下:

      1. #include "uart.h"                    
      2.   
      3. extern uint8_t idle_detect,cnt;  
      4. extern uint8_t buffer[100];  
      5. int main (void)  
      6. {  
      7.     uint8_t i = 0;  
      8.     uart_init(115200);  
      9.   
      10.     while(1)  
      11.     {  
      12.         if(1 == idle_detect)  
      13.         {  
      14.             idle_detect = 0;  
      15.             if(cnt == 0)  
      16.                 continue;  
      17.             printf("\r\ncnt:%X,ctx:",cnt);  
      18.             for(i = 0; i < cnt; i++)  
      19.             {  
      20.                 printf("%02X ",buffer[i]);  
      21.             }  
      22.             cnt = 0;  
      23.         }  
      24.     }  
      25. }  

      這個(gè)時(shí)候再次運(yùn)行代碼,結(jié)果如下:


      這個(gè)時(shí)候輸出的結(jié)果是正確的,難道兩個(gè)條件檢測(cè)放在一起會(huì)有問(wèn)題嗎?這個(gè)是不應(yīng)該的,因?yàn)閕dle_detect為0時(shí)CPU是不會(huì)再去檢測(cè)cnt變量的,只有idle_detect為1時(shí)才去檢測(cè)cnt變量,因此cnt的條件檢測(cè)放在里面和放在外面應(yīng)該是一樣的效果才對(duì)。后來(lái)想是否是printf引起的問(wèn)題,就把printf去掉改成了自己的輸出函數(shù),更改測(cè)試代碼如下:

      1. #include "uart.h"                    
      2.   
      3. extern uint8_t idle_detect,cnt;  
      4. extern uint8_t buffer[100];  
      5. int main (void)  
      6. {  
      7.     uint8_t i = 0;  
      8.     uart_init(115200);  
      9.   
      10.     while(1)  
      11.     {  
      12.         if(1 == idle_detect && cnt > 0)  
      13.         {  
      14.             idle_detect = 0;  
      15.             uart_puts("\r\ncnt:");  
      16.             uart_char(0x30+cnt);  
      17.             uart_puts(",ctx:");  
      18.             uart_write(buffer,cnt);  
      19.             cnt = 0;  
      20.         }  
      21.     }  
      22. }  

      這里cnt的輸出是有問(wèn)題的,但我測(cè)試時(shí)保證cnt不會(huì)大于10,因此不影響測(cè)試結(jié)果,在編譯時(shí)把微庫(kù)去掉,運(yùn)行結(jié)果如下:


      結(jié)果發(fā)現(xiàn)在數(shù)據(jù)小于等于6時(shí)結(jié)果是正確的,而當(dāng)數(shù)據(jù)大于6時(shí)cnt一直為6但字節(jié)內(nèi)容同樣是正確的,很是費(fèi)解,在后來(lái)我又測(cè)試過(guò)當(dāng)發(fā)送的字節(jié)為16時(shí),輸出的數(shù)據(jù)內(nèi)容會(huì)少幾個(gè)字節(jié),總而言之把cnt變量的判斷放在idle_detect變量檢測(cè)的后面就會(huì)導(dǎo)致結(jié)果不對(duì),而把cnt變量的判斷放在里面就不會(huì)有問(wèn)題,所以應(yīng)該不是printf引起的問(wèn)題,感覺(jué)像是if條件語(yǔ)句引起的問(wèn)題,嘗試過(guò)很多方法也沒(méi)搞定該問(wèn)題,雖然最后我們也能回避這個(gè)問(wèn)題,但沒(méi)找到原因真糾結(jié),如果有人知道是啥問(wèn)題的話(huà),麻煩告知一下。

      最后串口總線(xiàn)空閑檢測(cè)這一特性的確很有用,尤其是對(duì)收到的數(shù)據(jù)是不定長(zhǎng)時(shí)更有效果,大家以后可以嘗試使用一下該特性。

      PS:

      今天下午不死心又進(jìn)行了一些測(cè)試,還懷疑過(guò)是否是時(shí)序的問(wèn)題,對(duì)比了一下cnt判斷所在位置不同的匯編代碼,對(duì)比結(jié)果如下:


      左側(cè)是cnt判斷和idle_detect判斷在同一水平上,右側(cè)是cnt判斷放在了idle_detect條件檢測(cè)里面,兩者差別不大,再次證明我們的代碼邏輯是沒(méi)有問(wèn)題的,后來(lái)又想起使用printf和使用我們自己的輸出函數(shù)cnt的值會(huì)有變化,在使用printf時(shí)cnt一直為1,而使用我們自己的輸出函數(shù)時(shí)cnt在數(shù)據(jù)長(zhǎng)度小于等于6時(shí)正確,兩者的區(qū)別就是printf會(huì)使用微庫(kù),延遲不同,所以增加了一個(gè)延遲函數(shù),如下:

      1. void delay(void)  
      2. {  
      3.     uint32_t t = 5000;  
      4.     while(t)  
      5.     {  
      6.         __NOP();__NOP();__NOP();__NOP();__NOP();  
      7.         t-=1;  
      8.     }  
      9. }  

      更改主函數(shù)的測(cè)試代碼,delay()函數(shù)可以有兩處放置,如下:

      1. int main (void)  
      2. {  
      3.     uint8_t i = 0;  
      4.     uart_init(115200);  
      5.   
      6.     while(1)  
      7.     {  
      8.         delay();  
      9.         if(1 == idle_detect && cnt > 0)   
      10.         {  
      11.             idle_detect = 0;  
      12.             //delay();  
      13.             printf("\r\ncnt:%X,ctx:",cnt);  
      14.             for(i = 0; i < cnt; i++)  
      15.             {  
      16.                 printf("%02X ",buffer[i]);  
      17.             }  
      18.             cnt = 0;  
      19.         }  
      20.     }  
      21. }  

      加上delay()函數(shù)后代碼運(yùn)行的結(jié)果就正確了,區(qū)別是delay()函數(shù)如果放在if條件語(yǔ)句里面時(shí)當(dāng)上位機(jī)發(fā)送的數(shù)據(jù)量多時(shí)需要的延遲就會(huì)長(zhǎng)些才能保證結(jié)果的正確性,而delay()函數(shù)放在if條件語(yǔ)句的外面則不會(huì)這樣,總算找到問(wèn)題了,但還是推薦把cnt的判斷放在if條件的里面,這樣就不需要增加延遲函數(shù)了,就這樣吧。


        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶(hù) 評(píng)論公約

        類(lèi)似文章 更多