程序代碼篇---多循環串口程序切換

上位機版(Python)

要實現根據串口接收結果高效切換四個 while 循環函數,我們可以采用狀態機模式,配合非阻塞串口讀取來設計程序結構。這種方式可以實現快速切換,避免不必要的資源消耗。

下面是一個高效的實現方案,使用狀態變量控制當前執行的循環,并通過非阻塞方式檢查串口數據:

import serial
import time
import threading
from enum import Enum# 定義狀態枚舉,清晰表示四個不同狀態
class State(Enum):STATE_1 = 1STATE_2 = 2STATE_3 = 3STATE_4 = 4class SerialStateMachine:def __init__(self, port='COM3', baudrate=9600, timeout=0.1):# 初始化串口self.ser = serial.Serial(port, baudrate, timeout=timeout)self.current_state = State.STATE_1  # 默認初始狀態self.running = True  # 程序運行標志self.lock = threading.Lock()  # 線程鎖,確保狀態切換安全# 啟動串口監聽線程self.serial_thread = threading.Thread(target=self._serial_listener, daemon=True)self.serial_thread.start()def _serial_listener(self):"""串口監聽線程,非阻塞讀取指令"""while self.running:if self.ser.in_waiting > 0:# 讀取并處理串口數據command = self.ser.readline().decode().strip()self._process_command(command)time.sleep(0.01)  # 短暫休眠,降低CPU占用def _process_command(self, command):"""處理接收到的命令,切換狀態"""command_map = {'1': State.STATE_1,'2': State.STATE_2,'3': State.STATE_3,'4': State.STATE_4,'exit': None  # 退出程序}new_state = command_map.get(command)if new_state is None and command == 'exit':self.running = Falseprint("收到退出指令,程序將終止")elif new_state:with self.lock:self.current_state = new_stateprint(f"切換到狀態: {new_state}")def state_1_loop(self):"""第一個循環函數"""start_time = time.time()while True:# 檢查是否需要切換狀態with self.lock:if self.current_state != State.STATE_1:return# 狀態1的業務邏輯elapsed = time.time() - start_timeprint(f"狀態1運行中 - {elapsed:.2f}秒", end='\r')# 控制循環頻率,避免CPU占用過高time.sleep(0.1)def state_2_loop(self):"""第二個循環函數"""start_time = time.time()while True:with self.lock:if self.current_state != State.STATE_2:return# 狀態2的業務邏輯elapsed = time.time() - start_timeprint(f"狀態2運行中 - {elapsed:.2f}秒", end='\r')time.sleep(0.1)def state_3_loop(self):"""第三個循環函數"""start_time = time.time()while True:with self.lock:if self.current_state != State.STATE_3:return# 狀態3的業務邏輯elapsed = time.time() - start_timeprint(f"狀態3運行中 - {elapsed:.2f}秒", end='\r')time.sleep(0.1)def state_4_loop(self):"""第四個循環函數"""start_time = time.time()while True:with self.lock:if self.current_state != State.STATE_4:return# 狀態4的業務邏輯elapsed = time.time() - start_timeprint(f"狀態4運行中 - {elapsed:.2f}秒", end='\r')time.sleep(0.1)def run(self):"""主運行函數,根據當前狀態執行相應循環"""state_mapping = {State.STATE_1: self.state_1_loop,State.STATE_2: self.state_2_loop,State.STATE_3: self.state_3_loop,State.STATE_4: self.state_4_loop}print("程序啟動,等待串口指令...")print("發送 1-4 切換狀態,發送 exit 退出程序")while self.running:# 獲取當前狀態對應的函數并執行current_func = state_mapping.get(self.current_state)if current_func:current_func()time.sleep(0.05)# 清理資源self.ser.close()print("\n程序已退出")if __name__ == "__main__":try:# 根據實際情況修改串口參數machine = SerialStateMachine(port='COM3', baudrate=9600)machine.run()except serial.SerialException as e:print(f"串口錯誤: {e}")except KeyboardInterrupt:print("\n用戶中斷程序")

這個程序結構的高效性體現在以下幾個方面:

  1. 獨立串口監聽線程:使用單獨的線程處理串口數據接收,避免阻塞主循環,確保指令能被及時處理。

  2. 狀態機設計:通過枚舉類型明確定義四個狀態,使狀態切換邏輯清晰,易于維護和擴展。

  3. 非阻塞檢查:每個循環函數內部定期檢查狀態是否變化,一旦收到切換指令能立即退出當前循環,切換到新狀態。

  4. 線程安全:使用線程鎖保證狀態變量的線程安全訪問,避免多線程操作導致的狀態不一致。

  5. 資源控制:每個循環都有適當的休眠時間,避免 CPU 占用過高。

使用時,只需通過串口發送 "1"、"2"、"3"、"4" 即可切換到相應的循環,發送 "exit" 則退出程序。你可以根據實際需求,在四個狀態循環函數中實現具體的業務邏輯。

Openmv版(MincroPython)

在 OpenMV 上提升代碼邏輯的運行反應速度,需要結合其硬件特性(基于 MicroPython,資源有限,主打機器視覺)和應用場景(狀態切換、串口通信、實時處理)進行針對性優化。以下是具體的優化方向和實現方法:

一、代碼結構優化:減少冗余與阻塞

OpenMV 的 CPU 性能有限(如 H7 型號為 480MHz,但 MicroPython 解釋執行效率低于原生 C),需避免冗余計算和長時間阻塞。

1.?簡化狀態切換邏輯,減少檢查開銷
  • 原狀態機中若使用threading.Lock等線程同步機制,會引入額外開銷。OpenMV 的線程支持較弱(無真正多線程,僅為分時調度),可改用輕量狀態變量 + 非阻塞檢查
  • 示例:用全局變量直接存儲狀態(無需鎖),在循環中快速檢查狀態是否變化(避免復雜的上下文切換)。
import time
from pyb import UART# 狀態定義(用整數代替Enum,減少屬性查找開銷)
STATE_1 = 1
STATE_2 = 2
STATE_3 = 3
STATE_4 = 4
current_state = STATE_1# 串口初始化(非阻塞模式)
uart = UART(3, 115200)  # 根據實際引腳配置
uart.init(115200, timeout_char=10)  # 縮短超時時間,快速返回def check_serial():"""非阻塞讀取串口指令,直接修改全局狀態"""global current_stateif uart.any():  # 檢查是否有數據(比in_waiting更高效)cmd = uart.readline().strip().decode()if cmd == '1':current_state = STATE_1elif cmd == '2':current_state = STATE_2# ... 其他狀態def state_1():while current_state == STATE_1:# 業務邏輯(避免復雜計算)check_serial()  # 循環內快速檢查串口time.sleep_ms(10)  # 短延遲,平衡響應速度與CPU占用# 主循環
while True:if current_state == STATE_1:state_1()elif current_state == STATE_2:state_2()# ... 其他狀態
2.?避免嵌套循環與深層調用
  • 嵌套循環會增加棧開銷和條件判斷時間,盡量將邏輯扁平化。
  • 減少函數調用層級:OpenMV 的函數調用開銷較高,核心邏輯可適當 “內聯”(避免頻繁調用小函數)。

二、硬件資源優化:利用 OpenMV 專屬特性

1.?優化串口通信效率
  • 降低波特率:若無需高速通信,可將波特率從 115200 降至 9600(減少誤碼率和處理時間)。
  • 固定指令格式:用單字節指令(如b'1'代替字符串'1'),避免復雜的字符串解析(decode()strip()耗時)。
# 優化:直接處理字節,避免字符串轉換
def check_serial_fast():global current_stateif uart.any():cmd = uart.read(1)  # 讀取1字節指令if cmd == b'1':current_state = STATE_1elif cmd == b'2':current_state = STATE_2

  • 使用中斷接收:OpenMV 的 UART 支持中斷(uart.irq()),可在數據到達時立即觸發處理,避免循環中輪詢的開銷。
def uart_irq_handler(uart):global current_statecmd = uart.read(1)if cmd == b'1':current_state = STATE_1# ...# 注冊中斷
uart.irq(handler=uart_irq_handler, trigger=UART.IRQ_RXNE)  # 接收非空時觸發
2.?控制循環延遲,平衡響應與性能
  • 原代碼中time.sleep(0.1)(100ms)可能導致響應滯后,可縮短至time.sleep_ms(10)(10ms),但需避免過度縮短(導致 CPU 占用過高,反而卡頓)。
  • pyb.millis()(毫秒級定時器)替代time.time(),減少時間獲取的開銷(time.time()返回浮點數,計算耗時)。
# 優化:用毫秒計時,減少計算開銷
def state_1():start_ms = pyb.millis()while current_state == STATE_1:elapsed = pyb.millis() - start_ms# ... 業務邏輯time.sleep_ms(10)  # 10ms延遲,響應更快

三、內存管理:減少 GC(垃圾回收)干擾

OpenMV 的內存較小(如 H7 為 32MB),頻繁的內存分配會觸發 GC,導致卡頓。

1.?預分配內存,避免動態創建對象
  • 循環中避免頻繁創建列表、字符串等對象,提前定義并復用。
# 優化前:每次循環創建新字符串
while True:print(f"狀態1運行中: {elapsed}ms")  # f-string會動態創建字符串# 優化后:復用緩沖區
buf = bytearray(32)  # 預分配緩沖區
while True:# 用sprintf格式化到緩沖區(C風格,更快)buf[:] = b''  # 清空pyb.uart_write_str(uart, "狀態1: %dms\n" % elapsed)  # 避免字符串拼接
2.?禁用自動 GC,手動觸發
  • 自動 GC 會在內存不足時突然執行,導致卡頓。可禁用自動 GC,在空閑時手動觸發。
import gcgc.disable()  # 禁用自動垃圾回收def state_1():while current_state == STATE_1:# ... 業務邏輯if pyb.millis() % 1000 == 0:  # 每1秒手動回收一次gc.collect()

四、固件與工具鏈優化

1.?使用最新固件

OpenMV 官方會持續優化固件(如提升 MicroPython 執行效率、修復硬件驅動 bug),最新固件通常比舊版本運行更快。

  • 燒錄方法:通過 OpenMV IDE 的「Tools → Install Firmware」直接升級(確保型號匹配)。
2.?開啟代碼編譯優化
  • OpenMV IDE 支持將 Python 代碼編譯為字節碼(.mpy),執行速度比純腳本(.py)快 30% 以上。
  • 操作:「Tools → Save as .mpy」將main.py編譯為main.mpy,放入 SD 卡(OpenMV 會優先執行.mpy)。

五、避免耗時操作阻塞主循環

1.?減少打印輸出

print()會通過 USB 串口傳輸數據,速度慢且阻塞執行。調試完成后應刪除冗余打印,或用條件編譯關閉。

DEBUG = False  # 發布時設為Falseif DEBUG:print("調試信息")  # 僅調試時輸出
2.?分離耗時任務(如圖像處理)
  • 若涉及攝像頭圖像處理,盡量使用 OpenMV 內置的 C 實現函數(如img.find_blobs()),避免用純 Python 處理像素(速度極慢)。
  • 將圖像處理與狀態切換分離:在單獨的短周期內處理圖像,結果存入全局變量,狀態循環僅讀取結果(不直接處理)。

總結:關鍵優化點

  1. 簡化狀態邏輯:用全局變量 + 輕量檢查替代線程和鎖。
  2. 優化串口:用中斷接收 + 字節指令,減少解析開銷。
  3. 控制延遲:縮短sleep時間至 10-50ms,平衡響應與性能。
  4. 內存管理:預分配對象 + 手動 GC,避免卡頓。
  5. 利用硬件特性:用內置函數(C 實現)、編譯.mpy文件。

通過以上方法,可顯著提升 OpenMV 代碼的響應速度,尤其適合需要快速切換狀態的串口控制場景。

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

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

相關文章

rk3568上,實現ota,計算hash,驗證簽名,判斷激活分區,并通過dd命令,寫入對應AB分區

通過自定義升級程序&#xff0c;更直觀的理解ota升級原理。 一、模擬計算hash&#xff0c;驗證簽名&#xff0c;判斷激活分區&#xff0c;并通過dd命令&#xff0c;寫入對應分區 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <u…

數據分析—numpy庫

numpy庫NumPy 庫全面指南NumPy (Numerical Python) 是 Python 科學計算的基礎庫&#xff0c;提供了高性能的多維數組對象和工具。以下是 NumPy 的核心功能和使用方法。一、安裝與基礎1. 安裝 NumPypip install numpy2. 導入 NumPyimport numpy as np # 標準導入方式二、數組創建…

Vue3 setup、ref和reactive函數

一、setup函數1.理解&#xff1a;Vue3.0中一個新的配置項&#xff0c;值為一個函數。2.setup是所有Composition API(組合API)的“表演舞臺”。3.組件中用到的&#xff1a;數據、方法等等&#xff0c;均要配置在setup中。4.setup函數的兩種返回值&#xff1a;(1).若返回一個對象…

python中appium 的NoSuchElementException錯誤 原因以及解決辦法

錯誤收集D:\Program\Util\python.exe "D:/Program/myUtil/PyCharm 2024.3.5/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --target demo.py::TestAppium Testing started at 15:57 ... Launching pytest with arguments demo.py::TestAppium --no-hea…

mybatis-plus從入門到入土(四):持久層接口之BaseMapper和選裝件

大家好&#xff0c;今天繼續更新MybatisPlus從入門到入土系列&#xff0c;上一次的持久層接口還沒講完&#xff0c;只講了IService接口&#xff0c;今天我們繼續來講一下。 BaseMapper BaseMapper中的方法也比較簡單&#xff0c;都是增刪改查的基礎API&#xff0c;不知道大家還…

數組和指針的關系

在 C 語言中&#xff0c;?指針和數組有著非常緊密的聯系&#xff0c;但它們本質上是 ?不同的概念。理解它們的關系是掌握 C 語言內存操作的關鍵。下面我會從多個角度幫你梳理 ?指針和數組的直接聯系&#xff0c;并解釋它們的異同點。1. 數組和指針的本質區別?概念本質存儲方…

AI大模型探索之路-實戰篇:智能化IT領域搜索引擎之github網站在線搜索

系列篇章?? No. 文章 1 AI大模型探索之路-實戰篇:智能化IT領域搜索引擎的構建與初步實踐 2 AI大模型探索之路-實戰篇:智能化IT領域搜索引擎之GLM-4大模型技術的實踐探索 3 AI大模型探索之路-實戰篇:智能化IT領域搜索引擎之知乎網站數據獲取(初步實踐) 4 AI大模型探索之路…

從0到1學PHP(十二):PHP 框架入門與項目實戰

目錄一、主流 PHP 框架介紹1.1 Laravel1.2 ThinkPHP1.3 Yii1.4 框架的優勢二、框架基本使用&#xff08;以 Laravel 為例&#xff09;2.1 框架的安裝與配置2.2 路由定義、控制器創建、視圖渲染2.3 數據庫操作&#xff08;ORM 的使用&#xff09;三、小型項目實戰3.1 項目需求分…

MPLS LSP

一、概述上一章我們已經介紹過,LSP是MPLS報文在MPLS網絡中轉發時經過的路徑,可以看作是由報文傳輸方向節點為對應FEC分配的MPLS入標簽組成的,因為每臺設備上為每個FEC分配的入標簽是唯一 的&#xff0c;并與由下游節點為本地節點上該FEC分配的出標簽建立映射關系&#xff0c; 所…

圖像、視頻、音頻多模態大模型中長上下文token壓縮方法綜述

多模態大模型MLLMs 能夠處理高分辨率圖像、長視頻序列和冗長音頻輸入等復雜上下文&#xff0c;但自注意力機制的二次復雜度使得大量輸入 token 帶來了巨大的計算和內存需求。 如下圖&#xff0c;上&#xff1a;圖像、視頻和音頻數據類型可以在其表示維度上進行擴展&#xff0c;…

Spring MVC 九大組件源碼深度剖析(一):MultipartResolver - 文件上傳的幕后指揮官

文章目錄一、為什么從 MultipartResolver 開始&#xff1f;二、核心接口&#xff1a;定義文件上傳的契約三、實現解析&#xff1a;兩種策略的源碼較量1. StandardServletMultipartResolver&#xff08;Servlet 3.0 首選&#xff09;2. CommonsMultipartResolver&#xff08;兼容…

stm32是如何實現電源控制的?

STM32的電源控制主要通過內置的電源管理模塊&#xff08;PWR&#xff09;實現&#xff0c;涵蓋電壓調節、功耗模式切換和電源監控等功能。以下是其核心機制及實現方式&#xff1a;??1. 電源架構與供電區域??STM32的電源系統分為多個供電區域&#xff0c;各司其職&#xff1…

《R for Data Science (2e)》免費中文翻譯 (第3章) --- Data transformation(1)

寫在前面 本系列推文為《R for Data Science (2)》的中文翻譯版本。所有內容都通過開源免費的方式上傳至Github&#xff0c;歡迎大家參與貢獻&#xff0c;詳細信息見&#xff1a; Books-zh-cn 項目介紹&#xff1a; Books-zh-cn&#xff1a;開源免費的中文書籍社區 r4ds-zh-cn …

rclone、rsync、scp使用總結

數據同步工具使用總結【rclone、rsync、scp】一、數據處理背景二、數據處理方法對比1、數據關系梳理2、不同工具處理方法3、經驗總結三、工具擴展知識1、rclone工具介紹&#xff08;1&#xff09;、rclone概述&#xff08;2&#xff09;、安裝工具及配置本地文件遷移到云上服務…

用latex+vscode+ctex寫畢業論文

文章目錄前言一、安裝latex二、安裝ctex包三、更新ctex包四、使用ctex文檔類前言 用latexvscodectex寫畢業論文。&#xff08;英文論文不用安裝ctex&#xff09; CTEX 宏集是面向中文排版的通用 LATEX 排版框架&#xff0c;為中文 LATEX 文檔提供了漢字輸出支持、標點壓縮、字…

深度學習·mmsegmentation基礎教程

mmsegmentation的使用教程 mmsegmentation微調方法總結 自定義自己的數據集&#xff1a;mmsegmentation\configs\_base_\datasets\ZihaoDataset_pipeline.py注冊&#xff1a;mmsegmentation\configs\_base_\datasets\__init__.py定義訓練和測試的pipeline&#xff1a;mmsegme…

InfluxDB 與 Node.js 框架:Express 集成方案(二)

四、優化與注意事項 &#xff08;一&#xff09;性能優化技巧 連接池管理&#xff1a;使用連接池可以有效減少創建和銷毀數據庫連接的開銷。在 Node.js 中&#xff0c;可以借助influx模塊結合第三方連接池庫&#xff0c;如generic-pool來實現連接池的管理 。通過設置連接池的…

單位長度上的RC參數

1inch1000mil25.4mm2.54cm 使用SI9000計算導線上電容電感參數并使用Q2D進行仿真驗證。使用SI9000建立一個阻抗為50歐的微帶線模型&#xff0c;后對該模型進行1GHz頻域計算 通過計算得到結果&#xff0c;可知1GHz頻率下單位傳輸線上的RLGC參數使用SI9000計算好單位長度上的RLGC參…

基于Dockerfile 部署一個 Flask 應用

Docker 與 Python&#xff1a;容器化部署應用&#xff0c;實現快速發布與彈性伸縮 以下是一個簡單的 Flask 應用 # app.py - 一個簡單的Flask應用 from flask import Flask import osapp Flask(__name__)app.route("/") def hello():env os.environ.get(FLASK_ENV,…

DFT設計中的不同階段介紹

在DFT&#xff08;Design for Test&#xff0c;可測試性設計&#xff09;軟件開發中&#xff0c;針對設計檢測的完整流程通常包含Setup&#xff08;設置&#xff09;、Analysis&#xff08;分析&#xff09;、Insertion&#xff08;插入&#xff09;和Verification&#xff08;…