串口的緩存發送以及緩存接收機制

#創作靈感#

在我們實際使用MCU進行多串口任務分配的時候,我們會碰到這樣一種情況,即串口需要短間隔周期性發送數據,且相鄰兩幀之間需要間隔一段時間,防止連幀。我們常常需要在軟件層面對串口的發送和接受做一個緩存的處理方式。

針對發送,我們使用以下策略:

即1、上層應用在發送數據的時候其實是先將數據送入我們自己設定的發送緩存內(一個數組);

2、真正的發送是主循環在判斷出緩存內有數據的時候,自行啟動的發送;

所以我們的發送函數其實有兩個,一個用于上層應用將數據寫入緩存,一個用于串口自啟動發送過程。串口自啟動發送連續字節的時候? 我給大家提供了有三種發送方式:堵塞型發送、輪詢式發送、中斷式發送

對于MCU主頻不高的情況,通常跑完一整個while(1)循環 需要的時間相對而言比較長,而串口連續數據的發送是常常要滿足一定超時時間范圍的,比如你的串口連的是某個可以通信的電機,一幀的完整性需要得到保證,超出這個超時時間,電機可能會識別不出來這一幀指令。當然,現在大部分的MCU主控選用高速晶振的時候 都是可以滿足要求的。

堵塞型發送

通常一幀會包含很多字節數據,堵塞型發送其實就是程序在原地等待發送緩沖區空的標志位 或者發送完成標志位 ,一般發送完成肯定是比發送緩沖區空的時間晚。

 u8 i = 0;if (USARTx == USART1) 
{for (; i < len; i++) { if ((USART1->STATR & USART_STATR_TXE)) {  USART1->DATAR = Data[i];}while (!(USART1->STATR & USART_STATR_TXE));  // 檢查發送緩沖區空標志}}

我們會使用while循環在這里等待發送緩沖區空 ,當然也會容易導致系統在此堵塞,從而對于其他控制響應很慢,如果你的系統并沒有短時間的連續發送幀的要求,響應也沒有要求很高,使用這種方式也是可以的。

輪詢型發送

輪詢的核心思想其實就是利用最外層的while(1)循環,每次都只用if來判斷條件是否成立,這樣就不會導致系統的堵塞,但是這對你的整個系統大循環一次的時間有要求,現在基本高主頻都是可以滿足要求的,也不需占用中斷資源,是個不錯的方法。在使用狀態機理論的時候,其實也是在輪詢,這樣的思想在很多產品中都會出現。

具體的實現代碼見上述堵塞型發送,只不過不再有while循環原地等待,同時要記錄下當前發送字節的位置,這樣下次循環進來可以根據位置直接發掉下個對應的字節數據。

中斷型發送

核心思想其實是先發一個字節觸發發送完成中斷,而后在中斷里將下一個需要發送的數據塞入串口的數據寄存器內,等待下一次觸發中斷,直到緩存內的幀數據全部被發送完,期間如果有多幀,那么需要延后一段時間Ts來避免連幀。

對此我常常會定義這么兩個結構體

typedef struct
{u8  length;        //幀長  寫入數據的時候需要更新u8  DataBuff[20];   //幀的內容  這里的最大幀長就是20u8  ProcessLoc;    //當前幀處理的字節位置 如果不是一次性發完所有字節 建議都保留使用
}Frame;
struct
{UartFrame FBuff[20];  //幀的內容u8 UsartFrameNum;     //幀的數量 每次寫入這個數據就會加一 到20末尾的話回環到0u8 UsartFinishLoc;    //當前處理幀的位置 每次發送完一幀 就加一 同樣也需要回環到0u8 UsartBusyFlag : 1;  //幀處理間隔 就設置這個標志位 表示繁忙 20ms以后自動解封u16 UsartTimeNap;     //放在定時器中斷內用來累加
}UsartSendStorage;

第一個是幀的結構體,用來保存與單幀有關系的各項數據;

第二個是串口的發送存儲,如果有很多串口需要使用,可以單獨設置;

下面是關于串口的初始化設置,每種MCU可能都不太一樣,但是建議大家使用宏定義來選擇當前的工作方式,比較方便。

void UsartInit (void) {USART_InitTypeDef USART_InitStructure = {0};NVIC_InitTypeDef NVIC_InitStructure = {0};USART_InitStructure.USART_BaudRate = 115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;USART_Init (USART2, &USART_InitStructure);USART_Init (USART3, &USART_InitStructure);USART_Init (USART1, &USART_InitStructure);#define USART_Interrupt_Mode  // 中斷發送模式#ifdef USART_Interrupt_ModeUSART_ITConfig (USART2, USART_IT_RXNE, ENABLE);  // 接收寄存器非空中斷USART_ITConfig (USART2, USART_IT_TC, ENABLE);    // 發送寄存空中斷USART_ITConfig (USART3, USART_IT_RXNE, ENABLE);  // 接收寄存器非空中斷USART_ITConfig (USART3, USART_IT_TC, ENABLE);    // 發送寄存空中斷NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //搶占優先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;       //響應優先級NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init (&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init (&NVIC_InitStructure);
#endifUSART_Cmd (USART3, ENABLE);USART_Cmd (USART2, ENABLE);USART_Cmd (USART1, ENABLE);
}

搶占優先級要設置一樣,這樣兩個串口不會互相打斷,響應優先級可以設置不一樣。

下面是幾個函數用于添加幀到發送緩存以及自啟動發送過程。?

void UsartSetFrame(USART_TypeDef *USARTx, unsigned char *Data, unsigned char len)
{if(USARTx== USART1){memcpy(UsartSendStoorage.FBuff[UsartSendStoorage.UsartFrameNum].DataBuff,Data,len)UsartSendStoorage.FBuff[UsartSendStoorage.UsartFrameNum].length = len;UsartSendStoorage.UsartFrameNum++;if(UsartSendStoorage.UsartFrameNum >=10)UsartSendStoorage.UsartFrameNum = 0;}
}

注意我們這里能緩存的幀最長只有10幀,超出這個范圍以后,num的值就回頭覆蓋掉第一項了,你可以認為它就是一個會回環的寫指針,用來指示當前可以存儲幀的第一個位置。

?這里是把我們要發送的幀送到發送緩存里,

void UsartSendFrameTask(USART_TypeDef *USARTx)
{if (USARTx == USART1)                                                                                   {if(UsartSendStorage.UsartFrameNum != UsartSendStorage.UsartFinishLoc && !UsartSendStorage.UsartBusyFlag ) //有數據需要發 且不繁忙#ifdef USART_Interrupt_ModeUSART1->DATAR =  UsartSendStorage.FBuff[UsartSendStorage.UsartFinishLoc];#elseUsartSendData(UsartSendStorage.FBuff[UsartSendStorage.UsartFinishLoc]);UsartSendStorage.UsartFinishLoc++;UsartSendStorage.UsartFrameNum--;  //可選if(UsartSendStorage.UsartFinishLoc>=20)UsartSendStorage.UsartFinishLoc = 0;#endif}    
}

每次發送完一幀,記得需要把finishLoc加一,這樣只要加入幀的位置和最后處理完幀的位置是一致的,說明此時就沒有幀要發送,相反,如果此時有幀需要發送,num的值和finishLoc的值是不一致的。當然,這個num我的本意是將它作為寫入幀的位置,如果你要將它理解為幀的數量,當你處理完一幀的時候,可以將它減一,只用于記錄幀的個數,是個標量。這樣的話你判斷是否有幀的標準就是num的值是不是為0,就不是兩者是否相等。

void USART_IRQHandler (void)  
{u8 i;if (USART_GetITStatus (USART2, USART_IT_TC))  //  發送完成標志  表示上一次數據已經發送{if (USARTST.USART2SendBUFF[USARTST.USART1SendFrameFinishLoc].FrameProcessLoc < USARTST.USART2SendBUFF[USARTST.USART1SendFrameFinishLoc].FrameLength) {// 當前幀處理字節的位置還沒到末尾 繼續發送i = USARTST.USART2SendBUFF[USARTST.USART1SendFrameFinishLoc].FrameProcessLoc;  // 當前需要處理數據的位置USART1->DATAR = USARTST.USART1SendBUFF[USARTST.USART1SendFrameFinishLoc].FrameBuff[i];USARTST.USART2SendBUFF[USARTST.USART1SendFrameFinishLoc].FrameProcessLoc++;}     //else  // 幀處理完畢了  可以調用busyflag 來產生間隔    {USARTST.USART1BusyFlag = 1;USARTST.USART1SendFrameFinishLoc++;          // 這一幀發送完畢if (USARTST.USART1SendFrameFinishLoc >= 10)  // 回環處理USARTST.USART1SendFrameFinishLoc = 0;}}
}

大家可能對結構體內的TimeNap感到疑惑,其實它就是用來進行累加,這個累加函數會被調用在滴答定時器中斷內,當busyflag? = 1 的時候可以將TimeNap清0,而后在SendFrameTask()函數內部給一個if判斷,當TimeNap >= 200的時候,自動將busyflag = 0,就完成了幀間隔的設置,因為發送幀的時候是需要判斷幀是否繁忙的,不繁忙才會啟動幀的發送。

以上僅供大家參考使用,如有錯誤之處,還請多多體諒。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78382.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78382.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78382.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

時間交織(TIADC)的失配誤差校正處理(以4片1GSPS采樣率的12bitADC交織為例講解)

待寫…有空再寫&#xff0c;有需要的留言。 存在失配誤差的4GSPS交織 校正完成后的4GSPS交織

Linux進程間通信(二)之管道1【匿名管道】

文章目錄 管道什么是管道匿名管道用fork來共享管道原理站在文件描述符角度-深度理解管道站在內核角度-管道本質 接口實例代碼管道特點管道的4種情況管道讀寫規則應用場景 管道 什么是管道 管道是Unix中最古老的進程間通信的形式。 我們把從一個進程連接到另一個進程的一個數…

Xilinx FPGA | 管腳約束 / 時序約束 / 問題解析

注&#xff1a;本文為 “Xilinx FPGA | 管腳約束 / 時序約束 / 問題解析” 相關文章合輯。 略作重排&#xff0c;未整理去重。 如有內容異常&#xff0c;請看原文。 Xilinx FPGA 管腳 XDC 約束之&#xff1a;物理約束 FPGA技術實戰 于 2020-02-04 17:14:53 發布 說明&#x…

家用服務器 Ubuntu 服務器配置與 Cloudflare Tunnel 部署指南

Ubuntu 服務器配置與 Cloudflare Tunnel 部署指南 本文檔總結了我們討論的所有內容&#xff0c;包括 Ubuntu 服務器配置、硬盤擴容、靜態 IP 設置以及 Cloudflare Tunnel 的部署步驟。 目錄 硬盤分區與擴容設置靜態 IPCloudflare Tunnel 部署SSH 通過 Cloudflare Tunnel常見…

分享5款開源、美觀的 WinForm UI 控件庫

前言 今天大姚給大家分享5款開源、美觀的 WinForm UI 控件庫&#xff0c;助力讓我們的 WinForm 應用更好看。 WinForm WinForm是一個傳統的桌面應用程序框架&#xff0c;它基于 Windows 操作系統的原生控件和窗體。通過簡單易用的 API&#xff0c;開發者可以快速構建基于窗體…

PHP盲盒商城系統源碼從零搭建部署:專業級開發與優化實踐

【導語&#xff1a;技術驅動商業創新】 在2025年社交電商全面升級的浪潮下&#xff0c;基于PHP的盲盒系統憑借其高開發效率與低成本優勢&#xff0c;成為中小企業的首選方案。本文將深度拆解盲盒源碼從開發到部署的全流程技術細節&#xff0c;涵蓋架構設計、性能優化與安全防護…

(33)VTK C++開發示例 ---圖片轉3D

文章目錄 1. 概述2. CMake鏈接VTK3. main.cpp文件4. 演示效果 更多精彩內容&#x1f449;內容導航 &#x1f448;&#x1f449;VTK開發 &#x1f448; 1. 概述 這是 VTK 測試 clipArt.tcl 的改編版本。 提供帶有 2D 剪貼畫的 jpg 文件&#xff0c;該示例將創建 3D 多邊形數據模…

2025東三省B題深圳杯B題數學建模挑戰賽數模思路代碼文章教學

完整內容請看文章最下面的推廣群 已經完成全部問題的代碼和建模 一、問題一的模型構建與優化&#xff08;RGB顏色空間轉換模型&#xff09; 基礎模型&#xff08;線性映射模型&#xff09;/高斯過程回歸模型&#xff08;GPR&#xff09;&#xff1a; 針對高清視頻源&#xff0…

linux netlink實現用戶態和內核態數據交互

1&#xff0c;內核態代碼 #include <linux/module.h> #include <linux/netlink.h> #include <net/sock.h> #define NETLINK_TEST 31 struct sock *nl_sk NULL; static void nl_recv_msg(struct sk_buff *skb) { struct nlmsghdr *nlh; int pid; …

LeetCode:DP-多狀態問題

簡單 面試題 17.16. 按摩師 一個有名的按摩師會收到源源不斷的預約請求&#xff0c;每個預約都可以選擇接或不接。在每次預約服務之間要有休息時間&#xff0c;因此她不能接受相鄰的預約。給定一個預約請求序列&#xff0c;替按摩師找到最優的預約集合&#xff08;總預約時間最…

Spring AOP---面向切面編程由認識到使用

1. AOP AOP(Aspect-Oriented Programming), 是一種思想, 面向切面編程。 在前文統一異常處理&#xff0c;統一結果返回就是使用了這一思想&#xff08;都是在集中處理某一類事情, 但又不影響原有代碼的正常運行&#xff09;&#xff0c;但他們不是AOP&#xff0c;只是應用了這…

專題二十四:虛擬專用網絡

一、VPN簡介 VPN&#xff08;Virtual Personal Network&#xff09;即虛擬專用網&#xff0c;泛指通過VPN技術在公用網絡上構建的虛擬專用網絡。VPN用戶在此虛擬網絡中傳輸私網流量&#xff0c;在不改變網絡現狀的情況下實現安全、可靠的連接。其主要功能是在公用網絡上建立專…

Milvus(12):分析器

1 分析器概述 在文本處理中&#xff0c;分析器是將原始文本轉換為結構化可搜索格式的關鍵組件。每個分析器通常由兩個核心部件組成&#xff1a;標記器和過濾器。它們共同將輸入文本轉換為標記&#xff0c;完善這些標記&#xff0c;并為高效索引和檢索做好準備。 在 Milvus 中&a…

Power Query精通指南1:查詢結構設計、數據類型、數據導入與遷移(平面文件、Excel、Web)

文章目錄 零、Power Query簡介0.1 Power Query 主要功能0.2 Power Query 的優勢0.3 Power Query 組件 一、Power Query數據處理基本流程1.1 前期準備1.2 提取1.3 轉換1.3.1 Power Query 編輯器界面1.3.2 默認轉換1.3.3 自定義轉換 1.4 加載1.4.1 自動檢測數據類型1.4.2 重命名查…

WebRTC 服務器之Janus概述和環境搭建

1 概述 Janus 是由 Meetecho 開發的通用 WebRTC 服務器&#xff0c;它為構建 WebRTC 應用程序提供了一個模塊化框架。服務器目標&#xff1a;Janus WebRTC 網關被設計為輕量級、通用的 WebRTC 服務器&#xff0c;除了實現以下方法外&#xff0c;它本身不提供任何功能&#xff1…

19:常見的Halcon數據格式

遍歷文件夾與文件選擇 1&#xff09;遍歷文件夾&#xff1a; list_files( : : Directory, Options : Files) Directory&#xff1a;目錄&#xff08;文件夾路徑&#xff09; Options&#xff1a;選項 files 指定搜索的格式為文件 directories 指定搜索的格式為文件夾 re…

QML圖像提供器 (Image Provider)

QML 中的圖像提供器是一種自定義圖像加載機制&#xff0c;允許你從非文件源&#xff08;如數據庫、網絡或程序生成的內容&#xff09;提供圖像數據。 主要類型 QQuickImageProvider - 基礎圖像提供器 QPixmapImageProvider - 提供 QPixmap 圖像 QImageImageProvider - 提供 …

計算機視覺與深度學習 | 雙目立體匹配算法理論+Opencv實踐+matlab實踐

雙目立體匹配 一、雙目立體匹配算法理論與OpenCV、matlab實踐一、雙目立體匹配理論二、OpenCV實踐三、優化建議四、算法對比與適用場景二、雙目立體匹配算法理論及Matlab實踐指南一、雙目立體匹配理論二、Matlab實踐步驟三、算法對比與優化建議四、完整流程示例五、常見問題與解…

AI國學智慧語錄視頻,條條視頻10W+播放量

家人們&#xff01;圖書類帶貨玩法真的非常多&#xff0c;之前也分享過蠻多&#xff0c;例如情感語錄、育兒教育、爆款圖書金句類、AI歷史人物解說類等等。 本期繼續來分享一個對于普通人來說&#xff0c;上手相當簡單&#xff0c;容易起號&#xff0c;可作為長線深耕的AI帶貨…

echart圖表使用

2、接口編寫 該部分代碼定義了UserController控制器類&#xff0c;用于處理與用戶相關的請求。包含一個用于跳轉頁面的方法和一個返回用戶詳細數據&#xff08;以 JSON 格式呈現&#xff09;的接口。前者負責將用戶導航至指定頁面&#xff0c;后者通過構建ChartVO對象并填充數…