娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

歷史上的今天

今天是:2025年06月08日(星期日)

2018年06月08日 | STM32 串口總線空閑檢測

發布者:TranquilMind 來源: eefocus關鍵字:STM32  串口總線  空閑檢測 手機看文章 掃描二維碼
隨時隨地手機看文章

主機環境:Windows XP  SP3

開發環境:MDK 5.20

目標芯片:STM32F030C8T6

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

在STM32F030C8T6的參考手冊中串口中斷狀態寄存器USARTx_ISR中有一個IDLE位來表明是否檢測到總線空閑,如下圖所示:


并且給出了如何清除該標識,STM32F1系列芯片清除該標識的方法不同,可根據參考手冊來查詢,且該標識置位后就不再置位除非RXNE位再次置位,如果上位機一次性發送了1個字節數據則RXNE置位1次,IDLE置位1次,而如果上位機一次性發送了6個字節數據,則RXNE置位6次,IDLE依然置位1次,只要在CR1寄存器中使能了串口總線空閑檢測就可以使用該特性了,使用標準庫編輯了一下測試代碼,uart頭文件如下

  1. #ifndef __UART_H__  

  2. #define __UART_H__  

  3. #include   

  4. #include "stm32f0xx.h"  

  5. #include   

  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.     //初始化串口時鐘以及串口端口時鐘  

  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 ;            //設置波特率  

  26.     USART_InitStructure.USART_WordLength          = USART_WordLength_8b;  //8位數據位  

  27.     USART_InitStructure.USART_StopBits            = USART_StopBits_1;     //1位停止位  

  28.     USART_InitStructure.USART_Parity              = USART_Parity_No;     //無校驗位  

  29.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //無硬件控制  

  30.     USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;   //發送與接收兩種方式  

  31.     USART_Init(USARTx, &USART_InitStructure);         

  32.   

  33.     USART_ITConfig(USARTx,USART_IT_RXNE,ENABLE);    //使能接收中斷,在接收移位寄存器中有數據時產生  

  34.     USART_ITConfig(USARTx,USART_IT_PE,ENABLE);  

  35.     USART_ITConfig(USARTx,USART_IT_ERR,ENABLE);  

  36.     USART_ITConfig(USARTx,USART_IT_IDLE,ENABLE);    //使能總線空閑檢測中斷  

  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)//判斷寄存器中是否有數據  

  79.     {  

  80.         buffer[cnt++]=USART_ReceiveData(USARTx);  //讀取數據,讀數據的同時清空了接收中斷標志;  

  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.         //清除總線空閑中斷標志位  

  90.         USART_ClearITPendingBit(USARTx, USART_IT_IDLE);  

  91.         idle_detect = 1;  

  92.     }  

  93.     return;  

  94. }  


這里檢測到IDLE標識置位后置位idle_detect變量,cnt變量標記了本次接收到的字節個數,主函數測試代碼如下:


  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. }  

代碼比較簡單,這里使用printf來輸出本次接收到的字節數以及字節內容,運行結果如下:



可以看到檢測結果是正常的,只是在開機后有一次cnt為0的結果,應該是上電之后總線默認就是空閑的,的確也沒有收到數據,因此就想把cnt為0的結果去掉,這里我遇到了一個很糾結的問題,在判斷idle_detect變量的同時也檢測cnt是否大于0,測試代碼更改如下:

  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. }  


感覺邏輯是對的,再次運行,結果如下:



這個時候發現cnt變量的值輸出一直為1,但輸出的字節內容卻是對的,一直想不通這是為啥?思來想去邏輯是沒啥問題的,后來又把cnt是否為0的條件判斷不放在跟idle_detect變量檢測同一水平,而是放在它里面,更改測試代碼如下:

  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. }  


這個時候再次運行代碼,結果如下:



這個時候輸出的結果是正確的,難道兩個條件檢測放在一起會有問題嗎?這個是不應該的,因為idle_detect為0時CPU是不會再去檢測cnt變量的,只有idle_detect為1時才去檢測cnt變量,因此cnt的條件檢測放在里面和放在外面應該是一樣的效果才對。后來想是否是printf引起的問題,就把printf去掉改成了自己的輸出函數,更改測試代碼如下:

  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的輸出是有問題的,但我測試時保證cnt不會大于10,因此不影響測試結果,在編譯時把微庫去掉,運行結果如下:



結果發現在數據小于等于6時結果是正確的,而當數據大于6時cnt一直為6但字節內容同樣是正確的,很是費解,在后來我又測試過當發送的字節為16時,輸出的數據內容會少幾個字節,總而言之把cnt變量的判斷放在idle_detect變量檢測的后面就會導致結果不對,而把cnt變量的判斷放在里面就不會有問題,所以應該不是printf引起的問題,感覺像是if條件語句引起的問題,嘗試過很多方法也沒搞定該問題,雖然最后我們也能回避這個問題,但沒找到原因真糾結,如果有人知道是啥問題的話,麻煩告知一下。

最后串口總線空閑檢測這一特性的確很有用,尤其是對收到的數據是不定長時更有效果,大家以后可以嘗試使用一下該特性。

PS:

今天下午不死心又進行了一些測試,還懷疑過是否是時序的問題,對比了一下cnt判斷所在位置不同的匯編代碼,對比結果如下:


左側是cnt判斷和idle_detect判斷在同一水平上,右側是cnt判斷放在了idle_detect條件檢測里面,兩者差別不大,再次證明我們的代碼邏輯是沒有問題的,后來又想起使用printf和使用我們自己的輸出函數cnt的值會有變化,在使用printf時cnt一直為1,而使用我們自己的輸出函數時cnt在數據長度小于等于6時正確,兩者的區別就是printf會使用微庫,延遲不同,所以增加了一個延遲函數,如下:

  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. }  


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

  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()函數后代碼運行的結果就正確了,區別是delay()函數如果放在if條件語句里面時當上位機發送的數據量多時需要的延遲就會長些才能保證結果的正確性,而delay()函數放在if條件語句的外面則不會這樣,總算找到問題了,但還是推薦把cnt的判斷放在if條件的里面,這樣就不需要增加延遲函數了,就這樣吧。


關鍵字:STM32  串口總線  空閑檢測 引用地址:STM32 串口總線空閑檢測

上一篇:STM32CubeMX:UART(DMA空閑方式)
下一篇:STM32:DMA方式接收SPI總線數據,并按照協議進行處理

推薦閱讀

  近日,無人駕駛行業再掀波瀾,先是通用Cruise接受軟銀22.5億美元的投資,接著Waymo斥資向菲亞特-克萊斯勒(FCA)一次性訂購6.2萬臺Pacific,一舉將其無人駕駛車隊擴大一百倍。無人駕駛全球競逐 中國力量能否脫穎而出  如此一來,補齊資金短板的Cruise和彌補了造車劣勢的Waymo可謂勢不可擋。相較于這兩家無人駕駛行業的Top2,中國無人駕駛企業的技術...
6月的莫斯科,藍天白云,風和日麗。在第23屆圣彼得堡國際經濟論壇即將舉辦之際,應邀參加此次論壇的創新工場董事長兼CEO李開復博士在莫斯科就人工智能、創新工場在中國市場及全球投資趨勢等話題接受了科技日報記者的專訪。記者:作為一名應邀參會的中國商界領袖代表,您將在圣彼得堡經濟論壇上主要與哪些人士進行對話?李開復:我是應俄羅斯主權基金邀請參...
連接器產品在我們的生活中無處不在,比如家中常見的插座、筆記本電腦充電插頭或者是智能手機的USB線。此外,在眾多工業設備和系統中,連接器也是必不可少的器件,用于實現電流、信號和數據的傳遞。這些設備應用于航空航天器、軍用坦克、海上鉆井平臺、軌道交通系統、電動汽車以及醫療等行業。 工業連接器雖然在龐大系統中并不起眼,但卻必須經得起惡劣環境...
安森美半導體在APEC 2021發布新的用于電動車充電的完整碳化硅MOSFET模塊方案全面的寬禁帶器件組合實現高性能充電方案2021年6月8日—推動高能效創新的安森美半導體 (ON Semiconductor),發布一對1200 V完整的碳化硅 (SiC) MOSFET 2-PACK模塊,進一步增強其用于充滿挑戰的電動車 (EV) 市場的產品系列。隨著電動車銷售不斷增長,必須推出滿足駕駛員...

史海拾趣

小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 成安县| 渝北区| 吉安市| 英超| 临西县| 博爱县| 溧阳市| 双峰县| 子长县| 台南市| 奈曼旗| 海宁市| 郯城县| 汉川市| 江门市| 乐至县| 梓潼县| 安龙县| 乐山市| 岳池县| 普安县| 莱芜市| 安福县| 承德市| 涞源县| 迁西县| 神木县| 石渠县| 武鸣县| 临澧县| 峡江县| 天祝| 大化| 大竹县| 庐江县| 九台市| 新建县| 郎溪县| 馆陶县| 沅江市| 中西区|